diff -Nru linux-6.6.0/debian/changelog linux-6.6.0/debian/changelog --- linux-6.6.0/debian/changelog 2025-01-17 14:59:51.000000000 +0800 +++ linux-6.6.0/debian/changelog 2025-01-24 11:03:02.000000000 +0800 @@ -1,32 +1,8 @@ -linux (6.6.0-15.0ok12) nile; urgency=medium +linux (6.6.0-15.0ok13) nile; urgency=medium - [ Yongzhen Zhang ] - * Revert "update fs/erofs/super.c." + * 回退ok10到ok12的改动 - -- XieWei <xiewei@kylinos.cn> Fri, 17 Jan 2025 14:59:51 +0800 - -linux (6.6.0-15.0ok11) nile; urgency=medium - - [ wangdicheng ] - * ALSA: hda: Resolving the issue of the ALC662 sound card failing to load. - - [ Xianglai Li ] - * LoongArch: fix compile error when enable CONFIG_PARAVIRT - * LoongArch: KVM: enable ptw for kvm - - [ Kanglong Wang ] - * LoongArch: Fix the problem that the touchpad couldn't work - - [ Jiajia Liu ] - * Fix build error for IEE_SELINUX_P - - -- XieWei <xiewei@kylinos.cn> Thu, 16 Jan 2025 17:54:55 +0800 - -linux (6.6.0-15.0ok10) nile; urgency=medium - - * rebase linux-6.6-next, build ok10 - - -- XieWei <xiewei@kylinos.cn> Thu, 16 Jan 2025 10:30:06 +0800 + -- XieWei <xiewei@kylinos.cn> Fri, 24 Jan 2025 11:03:02 +0800 linux (6.6.0-15.0ok9) nile; urgency=medium diff -Nru linux-6.6.0/debian/patches/0020-rebase-linux-6.6-next-build-ok10.patch linux-6.6.0/debian/patches/0020-rebase-linux-6.6-next-build-ok10.patch --- linux-6.6.0/debian/patches/0020-rebase-linux-6.6-next-build-ok10.patch 2025-01-17 14:59:51.000000000 +0800 +++ linux-6.6.0/debian/patches/0020-rebase-linux-6.6-next-build-ok10.patch 1970-01-01 08:00:00.000000000 +0800 @@ -1,38001 +0,0 @@ -From: root <root@localhost> -Date: Thu, 16 Jan 2025 10:34:02 +0800 -Subject: rebase linux-6.6-next, build ok10 - ---- - Documentation/arch/loongarch/irq-chip-model.rst | 32 + - .../devicetree/bindings/hwmon/phytium,tacho.yaml | 81 + - .../bindings/misc/phytium,lpc-snoop.yaml | 53 - - .../devicetree/bindings/mmc/phytium,mci.yaml | 67 + - .../devicetree/bindings/mmc/phytium,sdci.yaml | 58 + - .../devicetree/bindings/pwm/phytium,pwm.yaml | 60 + - .../devicetree/bindings/rng/phytium,rng.yaml | 30 + - .../bindings/security/loongson_se/se.yaml | 32 + - .../zh_CN/arch/loongarch/irq-chip-model.rst | 32 + - MAINTAINERS | 11 + - arch/arm64/configs/defconfig | 8 + - arch/arm64/configs/openkylin_generic_defconfig | 11 +- - arch/loongarch/Kconfig | 6 +- - arch/loongarch/Kconfig.debug | 1 + - arch/loongarch/configs/loongson3_defconfig | 2 +- - arch/loongarch/configs/openkylin_generic_defconfig | 18 +- - arch/loongarch/include/asm/Kbuild | 1 - - arch/loongarch/include/asm/addrspace.h | 4 + - arch/loongarch/include/asm/atomic.h | 2 + - arch/loongarch/include/asm/cpu-features.h | 1 + - arch/loongarch/include/asm/cpu.h | 2 + - arch/loongarch/include/asm/hardirq.h | 3 +- - arch/loongarch/include/asm/hugetlb.h | 4 +- - arch/loongarch/include/asm/hw_irq.h | 2 + - arch/loongarch/include/asm/io.h | 10 +- - arch/loongarch/include/asm/irq.h | 33 +- - arch/loongarch/include/asm/kfence.h | 6 +- - arch/loongarch/include/asm/kvm_csr.h | 7 +- - arch/loongarch/include/asm/kvm_extioi.h | 96 + - arch/loongarch/include/asm/kvm_host.h | 61 +- - arch/loongarch/include/asm/kvm_ipi.h | 52 + - arch/loongarch/include/asm/kvm_para.h | 6 +- - arch/loongarch/include/asm/kvm_pch_pic.h | 61 + - arch/loongarch/include/asm/kvm_vcpu.h | 12 +- - arch/loongarch/include/asm/loongarch.h | 38 +- - arch/loongarch/include/asm/mmu_context.h | 35 +- - arch/loongarch/include/asm/paravirt.h | 6 + - arch/loongarch/include/asm/pgalloc.h | 11 + - arch/loongarch/include/asm/pgtable.h | 83 +- - arch/loongarch/include/asm/qspinlock.h | 41 + - arch/loongarch/include/asm/se.h | 147 ++ - arch/loongarch/include/asm/setup.h | 1 + - arch/loongarch/include/asm/shmparam.h | 11 + - arch/loongarch/include/asm/smp.h | 5 + - arch/loongarch/include/asm/stackframe.h | 11 + - arch/loongarch/include/uapi/asm/bitsperlong.h | 9 + - arch/loongarch/include/uapi/asm/kvm.h | 32 + - arch/loongarch/include/uapi/asm/kvm_para.h | 21 + - arch/loongarch/kernel/acpi.c | 24 +- - arch/loongarch/kernel/cpu-probe.c | 3 +- - arch/loongarch/kernel/fpu.S | 4 + - arch/loongarch/kernel/head.S | 14 +- - arch/loongarch/kernel/irq.c | 16 +- - arch/loongarch/kernel/legacy_boot.h | 11 + - arch/loongarch/kernel/paravirt.c | 25 +- - arch/loongarch/kernel/relocate.c | 10 +- - arch/loongarch/kernel/setup.c | 80 +- - arch/loongarch/kernel/smp.c | 20 +- - arch/loongarch/kvm/Kconfig | 4 + - arch/loongarch/kvm/Makefile | 4 + - arch/loongarch/kvm/exit.c | 93 +- - arch/loongarch/kvm/intc/extioi.c | 804 ++++++++ - arch/loongarch/kvm/intc/ipi.c | 538 +++++ - arch/loongarch/kvm/intc/pch_pic.c | 540 +++++ - arch/loongarch/kvm/irqfd.c | 87 + - arch/loongarch/kvm/main.c | 19 +- - arch/loongarch/kvm/mmu.c | 2 +- - arch/loongarch/kvm/switch.S | 4 + - arch/loongarch/kvm/timer.c | 7 - - arch/loongarch/kvm/vcpu.c | 367 +++- - arch/loongarch/kvm/vm.c | 120 +- - arch/loongarch/mm/cache.c | 24 +- - arch/loongarch/mm/fault.c | 41 + - arch/loongarch/mm/init.c | 8 +- - arch/loongarch/mm/kasan_init.c | 6 +- - arch/loongarch/mm/pgtable.c | 22 +- - arch/loongarch/power/suspend_asm.S | 6 +- - arch/x86/Kconfig | 17 + - arch/x86/boot/compressed/ident_map_64.c | 34 + - arch/x86/boot/compressed/pgtable_64.c | 4 + - arch/x86/events/zhaoxin/uncore.c | 135 -- - arch/x86/include/asm/asm-prototypes.h | 4 + - arch/x86/include/asm/desc.h | 15 + - arch/x86/include/asm/fixmap.h | 5 + - arch/x86/include/asm/iee-access.h | 34 + - arch/x86/include/asm/iee-cred.h | 149 ++ - arch/x86/include/asm/iee-def.h | 113 ++ - arch/x86/include/asm/iee-key.h | 149 ++ - arch/x86/include/asm/iee-selinuxp.h | 35 + - arch/x86/include/asm/iee-setpgtable.h | 7 + - arch/x86/include/asm/iee-si.h | 27 + - arch/x86/include/asm/iee-token.h | 33 + - arch/x86/include/asm/iee.h | 111 ++ - arch/x86/include/asm/page.h | 10 + - arch/x86/include/asm/page_types.h | 5 + - arch/x86/include/asm/pgalloc.h | 58 + - arch/x86/include/asm/pgtable.h | 51 + - arch/x86/include/asm/pgtable_64.h | 91 + - arch/x86/include/asm/special_insns.h | 15 + - arch/x86/include/asm/stack-slab.h | 9 + - arch/x86/kernel/Makefile | 2 + - arch/x86/kernel/asm-offsets.c | 6 + - arch/x86/kernel/cpu/common.c | 21 + - arch/x86/kernel/cpu/mce/core.c | 6 +- - arch/x86/kernel/head64.c | 8 + - arch/x86/kernel/iee/Makefile | 4 + - arch/x86/kernel/iee/iee-func.c | 369 ++++ - arch/x86/kernel/iee/iee-gate.S | 284 +++ - arch/x86/kernel/iee/iee-selinuxp.c | 38 + - arch/x86/kernel/iee/iee.c | 867 ++++++++ - arch/x86/kernel/iee/page-slab.c | 69 + - arch/x86/kernel/iee/stack-slab.c | 21 + - arch/x86/kernel/setup.c | 92 + - arch/x86/kernel/vmlinux.lds.S | 66 + - arch/x86/kvm/vmx/vmx.c | 5 +- - arch/x86/mm/ident_map_for_iee.c | 197 ++ - arch/x86/mm/init.c | 469 +++++ - arch/x86/mm/init_64.c | 151 ++ - arch/x86/mm/ioremap.c | 35 + - arch/x86/mm/kaslr.c | 7 +- - arch/x86/mm/mm_internal.h | 5 + - arch/x86/mm/pgtable.c | 19 + - arch/x86/mm/pti.c | 36 + - block/sed-opal.c | 8 + - certs/blacklist.c | 7 + - certs/system_keyring.c | 18 + - crypto/af_alg.c | 16 + - crypto/asymmetric_keys/asymmetric_type.c | 20 + - crypto/asymmetric_keys/public_key.c | 16 + - crypto/asymmetric_keys/signature.c | 10 + - debian.master/changelog | 6 + - drivers/acpi/pci_mcfg.c | 12 + - drivers/char/Kconfig | 20 + - drivers/char/Makefile | 2 + - drivers/char/hw_random/Kconfig | 12 + - drivers/char/hw_random/Makefile | 1 + - drivers/char/hw_random/phytium-rng.c | 154 ++ - drivers/char/loongson_se.c | 601 ++++++ - drivers/char/lsse_sdf_cdev.c | 380 ++++ - drivers/cpufreq/loongson3-acpi-cpufreq.c | 2 + - drivers/crypto/ccp/sev-dev.c | 8 + - drivers/firmware/efi/libstub/loongarch.c | 2 + - drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c | 28 +- - drivers/gpu/drm/loongson/Kconfig | 2 + - drivers/gpu/drm/loongson/Makefile | 1 + - drivers/gpu/drm/loongson/ast_old/Kconfig | 14 + - drivers/gpu/drm/loongson/ast_old/Makefile | 8 + - drivers/gpu/drm/loongson/ast_old/ast_dp.c | 299 +++ - drivers/gpu/drm/loongson/ast_old/ast_dp501.c | 429 ++++ - drivers/gpu/drm/loongson/ast_old/ast_dram_tables.h | 125 ++ - drivers/gpu/drm/loongson/ast_old/ast_drv.c | 231 +++ - drivers/gpu/drm/loongson/ast_old/ast_drv.h | 528 +++++ - drivers/gpu/drm/loongson/ast_old/ast_i2c.c | 170 ++ - drivers/gpu/drm/loongson/ast_old/ast_main.c | 486 +++++ - drivers/gpu/drm/loongson/ast_old/ast_mm.c | 101 + - drivers/gpu/drm/loongson/ast_old/ast_mode.c | 1881 ++++++++++++++++++ - drivers/gpu/drm/loongson/ast_old/ast_post.c | 2090 ++++++++++++++++++++ - drivers/gpu/drm/loongson/ast_old/ast_tables.h | 342 ++++ - drivers/gpu/drm/radeon/cik.c | 2 + - drivers/gpu/drm/radeon/evergreen.c | 2 + - drivers/gpu/drm/radeon/r600.c | 2 + - drivers/gpu/drm/radeon/si.c | 2 + - drivers/hwmon/Kconfig | 9 + - drivers/hwmon/Makefile | 1 + - drivers/hwmon/tacho-phytium.c | 416 ++++ - drivers/irqchip/Kconfig | 2 - - drivers/irqchip/Makefile | 2 +- - drivers/irqchip/irq-gic-phytium-2500-its.c | 504 +++-- - drivers/irqchip/irq-gic-phytium-2500.c | 556 ++---- - drivers/irqchip/irq-gic-v3-its.c | 18 + - drivers/irqchip/irq-loongarch-avec.c | 459 +++++ - drivers/irqchip/irq-loongarch-cpu.c | 7 +- - drivers/irqchip/irq-loongson-eiointc.c | 9 +- - drivers/irqchip/irq-loongson-htvec.c | 2 + - drivers/irqchip/irq-loongson-liointc.c | 2 + - drivers/irqchip/irq-loongson-pch-lpc.c | 2 + - drivers/irqchip/irq-loongson-pch-msi.c | 44 +- - drivers/irqchip/irq-loongson-pch-pic.c | 72 +- - drivers/irqchip/irq-loongson.h | 27 + - drivers/md/dm-crypt.c | 20 + - drivers/md/dm-verity-verify-sig.c | 8 + - drivers/misc/Kconfig | 8 - - drivers/misc/Makefile | 1 - - drivers/misc/phytium-lpc-snoop.c | 325 --- - drivers/mmc/host/Kconfig | 35 + - drivers/mmc/host/Makefile | 3 + - drivers/mmc/host/phytium-mci-pci.c | 175 ++ - drivers/mmc/host/phytium-mci-plat.c | 194 ++ - drivers/mmc/host/phytium-mci.c | 1530 ++++++++++++++ - drivers/mmc/host/phytium-mci.h | 355 ++++ - drivers/mmc/host/phytium-sdci.c | 1440 ++++++++++++++ - drivers/mmc/host/phytium-sdci.h | 200 ++ - drivers/net/xen-netfront.c | 5 +- - drivers/nvdimm/security.c | 24 + - drivers/pci/msi/msi.c | 35 + - drivers/pci/pci-driver.c | 4 + - drivers/pci/pci.c | 20 +- - drivers/pci/quirks.c | 14 + - drivers/platform/loongarch/Kconfig | 8 + - drivers/platform/loongarch/Makefile | 1 + - drivers/platform/loongarch/cpu_hwmon.c | 196 ++ - drivers/pwm/Kconfig | 10 + - drivers/pwm/Makefile | 1 + - drivers/pwm/pwm-phytium.c | 590 ++++++ - drivers/pwm/sysfs.c | 9 +- - drivers/scsi/qedf/qedf_main.c | 3 +- - drivers/tty/serial/Kconfig | 12 + - drivers/tty/serial/Makefile | 1 + - drivers/tty/serial/earlycon.c | 4 + - drivers/tty/serial/phytium-uart.c | 927 +++++++++ - drivers/usb/early/ehci-dbgp.c | 4 + - drivers/usb/musb/musb_gadget.c | 15 +- - fs/ceph/file.c | 43 +- - fs/coredump.c | 8 + - fs/crypto/keyring.c | 25 + - fs/crypto/keysetup_v1.c | 12 + - fs/ecryptfs/ecryptfs_kernel.h | 4 + - fs/ecryptfs/keystore.c | 52 + - fs/ecryptfs/main.c | 4 + - fs/erofs/super.c | 5 +- - fs/exec.c | 19 + - fs/f2fs/node.c | 9 + - fs/nfs/flexfilelayout/flexfilelayout.c | 9 + - fs/nfs/nfs4idmap.c | 24 + - fs/nfsd/auth.c | 38 + - fs/nfsd/nfs4callback.c | 8 + - fs/nfsd/nfs4recover.c | 9 + - fs/nfsd/nfsfh.c | 8 + - fs/open.c | 26 + - fs/overlayfs/dir.c | 8 + - fs/overlayfs/super.c | 12 + - fs/smb/client/cifs_spnego.c | 29 + - fs/smb/client/cifsacl.c | 51 + - fs/smb/client/connect.c | 8 + - fs/smb/client/sess.c | 4 + - fs/smb/client/smb2pdu.c | 4 + - fs/smb/server/smb_common.c | 12 + - fs/ubifs/auth.c | 8 + - fs/verity/signature.c | 4 + - include/acpi/actbl2.h | 3 +- - include/asm-generic/fixmap.h | 18 + - include/asm-generic/pgtable-nop4d.h | 5 + - include/asm-generic/vmlinux.lds.h | 10 +- - include/drm/drm_cache.h | 2 +- - include/keys/asymmetric-subtype.h | 4 + - include/keys/asymmetric-type.h | 8 + - include/keys/request_key_auth-type.h | 4 + - include/linux/compiler.h | 2 +- - include/linux/cpuhotplug.h | 4 + - include/linux/cred.h | 39 + - include/linux/iee-func.h | 33 + - include/linux/irqchip/arm-gic-phytium-2500.h | 8 +- - include/linux/key.h | 72 + - include/linux/kvm_host.h | 1 + - include/linux/mm.h | 3 +- - include/linux/pgtable.h | 32 + - include/linux/sched.h | 10 + - include/uapi/linux/kvm.h | 8 + - include/uapi/linux/serial_core.h | 3 + - init/initramfs.c | 13 + - init/main.c | 30 + - kernel/cred.c | 147 ++ - kernel/exit.c | 6 + - kernel/fork.c | 29 + - kernel/groups.c | 7 + - kernel/kthread.c | 9 + - kernel/sys.c | 106 + - kernel/trace/bpf_trace.c | 7 +- - kernel/trace/trace_events_user.c | 7 + - kernel/umh.c | 10 + - kernel/user_namespace.c | 17 + - lib/digsig.c | 8 + - mm/Kconfig | 4 + - mm/debug_vm_pgtable.c | 8 + - mm/early_ioremap.c | 57 + - mm/huge_memory.c | 26 + - mm/kasan/init.c | 8 +- - mm/secretmem.c | 4 +- - mm/slab.h | 23 + - mm/slab_common.c | 30 + - mm/slub.c | 273 ++- - mm/sparse-vmemmap.c | 5 + - net/bluetooth/hci_event.c | 15 +- - net/ceph/ceph_common.c | 4 + - net/ceph/crypto.c | 4 + - net/dns_resolver/dns_key.c | 23 + - net/dns_resolver/dns_query.c | 18 + - net/netfilter/ipset/ip_set_bitmap_ip.c | 7 +- - net/rxrpc/af_rxrpc.c | 4 + - net/rxrpc/conn_event.c | 5 + - net/rxrpc/key.c | 16 + - net/rxrpc/rxkad.c | 40 + - net/rxrpc/security.c | 8 + - net/rxrpc/sendmsg.c | 4 + - net/rxrpc/server_key.c | 8 + - net/sctp/ipv6.c | 18 +- - net/sunrpc/auth.c | 26 + - security/commoncap.c | 182 ++ - security/integrity/evm/evm_crypto.c | 9 + - security/keys/big_key.c | 16 + - security/keys/dh.c | 8 + - security/keys/encrypted-keys/encrypted.c | 28 + - security/keys/encrypted-keys/masterkey_trusted.c | 5 + - security/keys/gc.c | 51 + - security/keys/internal.h | 8 + - security/keys/key.c | 236 +++ - security/keys/keyctl.c | 88 + - security/keys/keyring.c | 266 +++ - security/keys/proc.c | 28 + - security/keys/process_keys.c | 80 + - security/keys/request_key.c | 15 + - security/keys/request_key_auth.c | 20 + - security/keys/trusted-keys/trusted_core.c | 8 + - security/keys/user_defined.c | 11 + - security/security.c | 15 + - security/selinux/hooks.c | 56 + - security/selinux/ima.c | 20 + - security/selinux/include/security.h | 9 + - security/selinux/selinuxfs.c | 52 + - security/selinux/ss/services.c | 57 + - security/selinux/status.c | 32 + - security/smack/smack_lsm.c | 11 + - tools/include/uapi/asm/bitsperlong.h | 2 + - tools/objtool/arch/loongarch/decode.c | 11 +- - tools/objtool/arch/x86/Build | 1 + - tools/objtool/arch/x86/orc.c | 188 ++ - tools/objtool/check.c | 75 +- - tools/objtool/include/objtool/elf.h | 2 + - tools/objtool/include/objtool/orc.h | 14 + - tools/objtool/orc_dump.c | 69 +- - tools/objtool/orc_gen.c | 113 +- - virt/kvm/dirty_ring.c | 3 + - 332 files changed, 26124 insertions(+), 1865 deletions(-) - create mode 100644 Documentation/devicetree/bindings/hwmon/phytium,tacho.yaml - delete mode 100644 Documentation/devicetree/bindings/misc/phytium,lpc-snoop.yaml - create mode 100644 Documentation/devicetree/bindings/mmc/phytium,mci.yaml - create mode 100644 Documentation/devicetree/bindings/mmc/phytium,sdci.yaml - create mode 100644 Documentation/devicetree/bindings/pwm/phytium,pwm.yaml - create mode 100644 Documentation/devicetree/bindings/rng/phytium,rng.yaml - create mode 100644 Documentation/devicetree/bindings/security/loongson_se/se.yaml - create mode 100644 arch/loongarch/include/asm/kvm_extioi.h - create mode 100644 arch/loongarch/include/asm/kvm_ipi.h - create mode 100644 arch/loongarch/include/asm/kvm_pch_pic.h - create mode 100644 arch/loongarch/include/asm/qspinlock.h - create mode 100644 arch/loongarch/include/asm/se.h - create mode 100644 arch/loongarch/include/asm/shmparam.h - create mode 100644 arch/loongarch/include/uapi/asm/bitsperlong.h - create mode 100644 arch/loongarch/include/uapi/asm/kvm_para.h - create mode 100644 arch/loongarch/kvm/intc/extioi.c - create mode 100644 arch/loongarch/kvm/intc/ipi.c - create mode 100644 arch/loongarch/kvm/intc/pch_pic.c - create mode 100644 arch/loongarch/kvm/irqfd.c - create mode 100644 arch/x86/include/asm/iee-access.h - create mode 100644 arch/x86/include/asm/iee-cred.h - create mode 100644 arch/x86/include/asm/iee-def.h - create mode 100644 arch/x86/include/asm/iee-key.h - create mode 100644 arch/x86/include/asm/iee-selinuxp.h - create mode 100644 arch/x86/include/asm/iee-setpgtable.h - create mode 100644 arch/x86/include/asm/iee-si.h - create mode 100644 arch/x86/include/asm/iee-token.h - create mode 100644 arch/x86/include/asm/iee.h - create mode 100644 arch/x86/include/asm/stack-slab.h - create mode 100644 arch/x86/kernel/iee/Makefile - create mode 100644 arch/x86/kernel/iee/iee-func.c - create mode 100644 arch/x86/kernel/iee/iee-gate.S - create mode 100644 arch/x86/kernel/iee/iee-selinuxp.c - create mode 100644 arch/x86/kernel/iee/iee.c - create mode 100644 arch/x86/kernel/iee/page-slab.c - create mode 100644 arch/x86/kernel/iee/stack-slab.c - create mode 100644 arch/x86/mm/ident_map_for_iee.c - create mode 100644 drivers/char/hw_random/phytium-rng.c - create mode 100644 drivers/char/loongson_se.c - create mode 100644 drivers/char/lsse_sdf_cdev.c - create mode 100644 drivers/gpu/drm/loongson/ast_old/Kconfig - create mode 100644 drivers/gpu/drm/loongson/ast_old/Makefile - create mode 100644 drivers/gpu/drm/loongson/ast_old/ast_dp.c - create mode 100644 drivers/gpu/drm/loongson/ast_old/ast_dp501.c - create mode 100644 drivers/gpu/drm/loongson/ast_old/ast_dram_tables.h - create mode 100644 drivers/gpu/drm/loongson/ast_old/ast_drv.c - create mode 100644 drivers/gpu/drm/loongson/ast_old/ast_drv.h - create mode 100644 drivers/gpu/drm/loongson/ast_old/ast_i2c.c - create mode 100644 drivers/gpu/drm/loongson/ast_old/ast_main.c - create mode 100644 drivers/gpu/drm/loongson/ast_old/ast_mm.c - create mode 100644 drivers/gpu/drm/loongson/ast_old/ast_mode.c - create mode 100644 drivers/gpu/drm/loongson/ast_old/ast_post.c - create mode 100644 drivers/gpu/drm/loongson/ast_old/ast_tables.h - create mode 100644 drivers/hwmon/tacho-phytium.c - create mode 100644 drivers/irqchip/irq-loongarch-avec.c - create mode 100644 drivers/irqchip/irq-loongson.h - delete mode 100644 drivers/misc/phytium-lpc-snoop.c - create mode 100644 drivers/mmc/host/phytium-mci-pci.c - create mode 100644 drivers/mmc/host/phytium-mci-plat.c - create mode 100644 drivers/mmc/host/phytium-mci.c - create mode 100644 drivers/mmc/host/phytium-mci.h - create mode 100644 drivers/mmc/host/phytium-sdci.c - create mode 100644 drivers/mmc/host/phytium-sdci.h - create mode 100644 drivers/platform/loongarch/cpu_hwmon.c - create mode 100644 drivers/pwm/pwm-phytium.c - create mode 100644 drivers/tty/serial/phytium-uart.c - create mode 100644 include/linux/iee-func.h - create mode 100644 tools/objtool/arch/x86/orc.c - create mode 100644 tools/objtool/include/objtool/orc.h - -diff --git a/Documentation/arch/loongarch/irq-chip-model.rst b/Documentation/arch/loongarch/irq-chip-model.rst -index 7988f41..6dd4825 100644 ---- a/Documentation/arch/loongarch/irq-chip-model.rst -+++ b/Documentation/arch/loongarch/irq-chip-model.rst -@@ -85,6 +85,38 @@ to CPUINTC directly:: - | Devices | - +---------+ - -+Advanced Extended IRQ model -+=========================== -+ -+In this model, IPI (Inter-Processor Interrupt) and CPU Local Timer interrupt go -+to CPUINTC directly, CPU UARTS interrupts go to LIOINTC, PCH-MSI interrupts go -+to AVECINTC, and then go to CPUINTC directly, while all other devices interrupts -+go to PCH-PIC/PCH-LPC and gathered by EIOINTC, and then go to CPUINTC directly:: -+ -+ +-----+ +-----------------------+ +-------+ -+ | IPI | --> | CPUINTC | <-- | Timer | -+ +-----+ +-----------------------+ +-------+ -+ ^ ^ ^ -+ | | | -+ +---------+ +----------+ +---------+ +-------+ -+ | EIOINTC | | AVECINTC | | LIOINTC | <-- | UARTs | -+ +---------+ +----------+ +---------+ +-------+ -+ ^ ^ -+ | | -+ +---------+ +---------+ -+ | PCH-PIC | | PCH-MSI | -+ +---------+ +---------+ -+ ^ ^ ^ -+ | | | -+ +---------+ +---------+ +---------+ -+ | Devices | | PCH-LPC | | Devices | -+ +---------+ +---------+ +---------+ -+ ^ -+ | -+ +---------+ -+ | Devices | -+ +---------+ -+ - ACPI-related definitions - ======================== - -diff --git a/Documentation/devicetree/bindings/hwmon/phytium,tacho.yaml b/Documentation/devicetree/bindings/hwmon/phytium,tacho.yaml -new file mode 100644 -index 0000000..d2443e0 ---- /dev/null -+++ b/Documentation/devicetree/bindings/hwmon/phytium,tacho.yaml -@@ -0,0 +1,81 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/hwmon/phytium,tacho.yaml -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Phytium Fan Tacho and capture counter controller device driver -+ -+maintainers: -+ - Chen Baozi <chenbaozi@phytium.com.cn> -+ -+description: | -+ The controller can support one input signal. The function of controller is to -+ measure the speed of fan and the edge number of input signal. The function -+ can be selected by devicetree setting. The edging mode and anti-jitter level -+ can also setted in devicetree. -+ -+properties: -+ compatible: -+ const: phytium,tacho -+ -+ reg: -+ maxItems: 1 -+ -+ clocks: -+ maxItems: 1 -+ -+ '#address-cells': -+ const: 1 -+ -+ '#size-cells': -+ const: 1 -+ -+ tacho: -+ $ref: /schemas/types.yaml#/definitions/flag -+ description: -+ set the controller work as fan tachometer, which is a default option. -+ -+ capture: -+ $ref: /schemas/types.yaml#/definitions/flag -+ description: -+ set the controller work as capture counter. -+ -+ up: -+ $ref: /schemas/types.yaml#/definitions/flag -+ description: -+ set the input edging mode as ascending, which is a default option. -+ -+ down: -+ $ref: /schemas/types.yaml#/definitions/flag -+ description: -+ set the input edging mode as descending. -+ -+ double: -+ $ref: /schemas/types.yaml#/definitions/flag -+ description: -+ set the input edging mode as doule-edging. -+ -+ debounce-level: -+ $ref: /schemas/types.yaml#/definitions/uint32 -+ enum: [0, 1, 2, 3] -+ -+required: -+ - compatible -+ - reg -+ - clocks -+ - '#address-cells' -+ - '#size-cells' -+ -+examples: -+ - | -+ tacho: tacho@28054000 { -+ #address-cells = <1>; -+ #size-cells = <1>; -+ reg = <0x0 0x28054000 0x0 0x1000>; -+ compatible = "phytium,tacho"; -+ clocks = <&sysclk>; -+ tacho; -+ up; -+ debounce-level = <2>; -+ }; -diff --git a/Documentation/devicetree/bindings/misc/phytium,lpc-snoop.yaml b/Documentation/devicetree/bindings/misc/phytium,lpc-snoop.yaml -deleted file mode 100644 -index 642026b..0000000 ---- a/Documentation/devicetree/bindings/misc/phytium,lpc-snoop.yaml -+++ /dev/null -@@ -1,53 +0,0 @@ --# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) --%YAML 1.2 ----- --$id: http://devicetree.org/schemas/misc/phytium,lpc-snoop.yaml# --$schema: http://devicetree.org/meta-schemas/core.yaml# -- --title: Phytium lpc-snoop -- --maintainers: -- - Lan Hengyu <lanhengyu1395@phytium.com.cn> -- --description: -- The LPC snoop interface allows the BMC to listen on and record the data -- bytes written by the Host to the targeted LPC I/O pots. -- --properties: -- compatible: -- items: -- - enum: -- - phytium,lpc-snoop -- reg: -- maxItems: 1 -- -- interrupts: -- maxItems: 1 -- -- snoop-ports: -- $ref: /schemas/types.yaml#/definitions/uint32-array -- description: The LPC I/O ports to snoop -- --required: -- - compatible -- - interrupts -- - snoop-ports -- --examples: -- - | -- lpc: lpc@28010000 { -- compatible = "simple-mfd", "syscon"; -- reg = <0x0 0x28010000 0x1000>; -- reg-io-width = <4>; -- -- #address-cells = <1>; -- #size-cells = <1>; -- ranges = <0x0 0x0 0x28010000 0x1000>; -- -- lpc_snoop: lpc-snoop@90 { -- compatible = "phytium,lpc-snoop"; -- reg = <0x90 0x8>; -- interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>; -- snoop-ports = <0x80>; -- }; -- }; -diff --git a/Documentation/devicetree/bindings/mmc/phytium,mci.yaml b/Documentation/devicetree/bindings/mmc/phytium,mci.yaml -new file mode 100644 -index 0000000..a0748c7 ---- /dev/null -+++ b/Documentation/devicetree/bindings/mmc/phytium,mci.yaml -@@ -0,0 +1,67 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/mmc/phytium,mci.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Phytium Multimedia Card Interface controller -+ -+description: | -+ The highspeed MMC host controller on Phytium SoCs provides an interface -+ for MMC, SD and SDIO types of memory cards. -+ -+maintainers: -+ - Chen Baozi <chenbaozi@phytium.com.cn> -+ -+allOf: -+ - $ref: "mmc-controller.yaml" -+ -+properties: -+ compatible: -+ const: phytium,mci -+ -+ reg: -+ maxItems: 1 -+ description: mmc controller base registers. -+ -+ interrupts: -+ maxItems: 1 -+ description: mmc controller interrupt. -+ -+ clocks: -+ maxItems: 1 -+ description: phandles to input clocks. -+ -+ clock-names: -+ items: -+ - const: phytium_mci_clk -+ -+required: -+ - compatible -+ - reg -+ - interrupts -+ - clocks -+ - clock-names -+ -+examples: -+ - | -+ mmc0: mmc@28000000 { -+ compatible = "phytium,mci"; -+ reg = <0x0 0x28000000 0x0 0x1000>; -+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; -+ clocks = <&sysclk_1200mhz>; -+ clock-names = "phytium_mci_clk"; -+ status = "disabled"; -+ }; -+ -+ &mmc0 { -+ bus-width = <4>; -+ max-frequency = <50000000>; -+ cap-sdio-irq; -+ cap-sd-highspeed; -+ sd-uhs-sdr12; -+ sd-uhs-sdr25; -+ sd-uhs-sdr50; -+ no-mmc; -+ status = "ok"; -+ }; -diff --git a/Documentation/devicetree/bindings/mmc/phytium,sdci.yaml b/Documentation/devicetree/bindings/mmc/phytium,sdci.yaml -new file mode 100644 -index 0000000..9c56e5f ---- /dev/null -+++ b/Documentation/devicetree/bindings/mmc/phytium,sdci.yaml -@@ -0,0 +1,58 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/mmc/phytium,sdci.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Phytium SDCI Controller Binding -+ -+maintainers: -+ - Chen Baozi <chenbaozi@phytium.com.cn> -+ -+allOf: -+ - $ref: mmc-controller.yaml# -+ -+properties: -+ compatible: -+ enum: -+ - phytium,sdci -+ -+ reg: -+ maxItems: 1 -+ -+ interrupts: -+ minItems: 3 -+ maxItems: 3 -+ -+ clocks: -+ minItems: 1 -+ items: -+ - description: core clock -+ -+ clock-names: -+ minItems: 1 -+ items: -+ - const: phytium_sdc_clk -+ -+required: -+ - compatible -+ - reg -+ - interrupts -+ - clocks -+ - clock-names -+ -+unevaluatedProperties: false -+ -+examples: -+ - | -+ sdci: sdci@28207c00 { -+ compatible = "phytium,sdci"; -+ reg = <0x0 0x28207c00 0x0 0x100>; -+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>, -+ <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>, -+ <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>; -+ clocks = <&sysclk_600mhz>; -+ clock-names = "phytium_sdc_clk"; -+ }; -+ -+... -diff --git a/Documentation/devicetree/bindings/pwm/phytium,pwm.yaml b/Documentation/devicetree/bindings/pwm/phytium,pwm.yaml -new file mode 100644 -index 0000000..b142aa6 ---- /dev/null -+++ b/Documentation/devicetree/bindings/pwm/phytium,pwm.yaml -@@ -0,0 +1,60 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/pwm/phytium,pwm.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Phytium PWM controller -+ -+maintainers: -+ - Chen Baozi <chenbaozi@phytium.com.cn> -+ -+allOf: -+ - $ref: pwm.yaml# -+ -+properties: -+ compatible: -+ const: phytium,pwm -+ -+ reg: -+ maxItems: 1 -+ -+ clocks: -+ description: Clock specifiers for both ipg and per clocks. -+ -+ interrupts: -+ maxItems: 1 -+ -+ phytium,db: -+ description: | -+ One or two <cntmod dutymod div updbcly dbpolarity> to describe dead-band configurations. -+ "cntmod" indicates the counter mode (0 for modulo, 1 for up-and-down). -+ "dutymod" indicdates which duty to compare with (0 for PMW_CCR, 1 for FIFO). -+ "div" selects the clock divider value, from 0 to 1023. -+ "updbcly" selects the rising edge delay cycles. -+ "dbpolarity" selects the polarity for dead-band. -+ $ref: /schemas/types.yaml#/definitions/uint32-array -+ uniqueItems: true -+ items: -+ minimum: 1 -+ maximum: 2 -+ -+ -+required: -+ - compatible -+ - reg -+ - clocks -+ - interrupts -+ - phytium,db -+ -+additionalProperties: false -+ -+examples: -+ - | -+ pwm0: pwm@2804a000 { -+ compatible = "phytium,pwm"; -+ reg= <0x0 0x2804a000 0x0 0x1000>; -+ interrupts = <GIC_SPI 173 IRQ_TYPE_LEVEL_HIGH>; -+ clocks = <&sysclk_48mhz>; -+ phytium,db = <0 0 0 1000 0>; -+ }; -diff --git a/Documentation/devicetree/bindings/rng/phytium,rng.yaml b/Documentation/devicetree/bindings/rng/phytium,rng.yaml -new file mode 100644 -index 0000000..e32fc39 ---- /dev/null -+++ b/Documentation/devicetree/bindings/rng/phytium,rng.yaml -@@ -0,0 +1,30 @@ -+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/rng/phytium,rng.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Phytium Random Number Generator -+ -+maintainers: -+ - Chen Baozi <chenbaozi@phytium.com.cn> -+ -+properties: -+ compatible: -+ const: phytium,rng -+ -+ reg: -+ maxItems: 1 -+ -+required: -+ - compatible -+ - reg -+ -+additionalProperties: false -+ -+examples: -+ - | -+ rng@0x31a06000 { -+ compatible = "phytium,rng"; -+ reg = <0x0 0x31a06000 0x0 0x1000>; -+ }; -diff --git a/Documentation/devicetree/bindings/security/loongson_se/se.yaml b/Documentation/devicetree/bindings/security/loongson_se/se.yaml -new file mode 100644 -index 0000000..c79313e ---- /dev/null -+++ b/Documentation/devicetree/bindings/security/loongson_se/se.yaml -@@ -0,0 +1,32 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/security/loongson_se/se.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Loongson SE module -+ -+description: -+ Loongson SE module -+maintainers: -+ - Qunqin Zhao <zhaoqunqin@loongson.cn> -+ -+allOf: -+ - $ref: se.yaml# -+ -+properties: -+ compatible: -+ const: loongson,ls3c6000se -+ -+ reg: -+ maxItems: 2 -+ -+ interrupts: -+ maxItems: 2 -+ -+required: -+ - compatible -+ - reg -+ - interrupts -+ -+additionalProperties: false -diff --git a/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst b/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst -index f1e9ab1..4727619 100644 ---- a/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst -+++ b/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst -@@ -87,6 +87,38 @@ PCH-LPC/PCH-MSI,然后被EIOINTC统一收集,再直接到达CPUINTC:: - | Devices | - +---------+ - -+高级扩展IRQ模型 -+=============== -+ -+在这种模型里面,IPI(Inter-Processor Interrupt)和CPU本地时钟中断直接发送到CPUINTC, -+CPU串口(UARTs)中断发送到LIOINTC,PCH-MSI中断发送到AVECINTC,而后通过AVECINTC直接 -+送达CPUINTC,而其他所有设备的中断则分别发送到所连接的PCH-PIC/PCH-LPC,然后由EIOINTC -+统一收集,再直接到达CPUINTC:: -+ -+ +-----+ +-----------------------+ +-------+ -+ | IPI | --> | CPUINTC | <-- | Timer | -+ +-----+ +-----------------------+ +-------+ -+ ^ ^ ^ -+ | | | -+ +---------+ +----------+ +---------+ +-------+ -+ | EIOINTC | | AVECINTC | | LIOINTC | <-- | UARTs | -+ +---------+ +----------+ +---------+ +-------+ -+ ^ ^ -+ | | -+ +---------+ +---------+ -+ | PCH-PIC | | PCH-MSI | -+ +---------+ +---------+ -+ ^ ^ ^ -+ | | | -+ +---------+ +---------+ +---------+ -+ | Devices | | PCH-LPC | | Devices | -+ +---------+ +---------+ +---------+ -+ ^ -+ | -+ +---------+ -+ | Devices | -+ +---------+ -+ - ACPI相关的定义 - ============== - -diff --git a/MAINTAINERS b/MAINTAINERS -index 0fe344e..3973ffb 100644 ---- a/MAINTAINERS -+++ b/MAINTAINERS -@@ -7046,6 +7046,7 @@ L: dri-devel@lists.freedesktop.org - S: Supported - T: git git://anongit.freedesktop.org/drm/drm-misc - F: drivers/gpu/drm/loongson/ -+F: drivers/gpu/drm/loongson/ast_old/ - - DRM DRIVERS FOR MEDIATEK - M: Chun-Kuang Hu <chunkuang.hu@kernel.org> -@@ -11610,6 +11611,7 @@ L: kvm@vger.kernel.org - L: loongarch@lists.linux.dev - S: Maintained - T: git git://git.kernel.org/pub/scm/virt/kvm/kvm.git -+F: Documentation/virt/kvm/loongarch/ - F: arch/loongarch/include/asm/kvm* - F: arch/loongarch/include/uapi/asm/kvm* - F: arch/loongarch/kvm/ -@@ -12436,6 +12438,7 @@ F: Documentation/arch/loongarch/ - F: Documentation/translations/zh_CN/arch/loongarch/ - F: arch/loongarch/ - F: drivers/*/*loongarch* -+F: drivers/*/*loongson* - - LOONGSON GPIO DRIVER - M: Yinbo Zhu <zhuyinbo@loongson.cn> -@@ -12491,6 +12494,14 @@ S: Maintained - F: Documentation/devicetree/bindings/pinctrl/loongson,ls2k-pinctrl.yaml - F: drivers/pinctrl/pinctrl-loongson2.c - -+LOONGSON SE DRIVER -+M: Qunqin Zhao <zhaoqunqin@loongson.cn> -+S: Maintained -+F: Documentation/devicetree/bindings/security/loongson_se/se.yaml -+F: arch/loongarch/include/asm/se.h -+F: drivers/char/loongson_se.c -+F: drivers/char/lsse_sdf_cdev.c -+ - LOONGSON-2 SOC SERIES THERMAL DRIVER - M: zhanghongchen <zhanghongchen@loongson.cn> - M: Yinbo Zhu <zhuyinbo@loongson.cn> -diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig -index 4809043..aeb4b62 100644 ---- a/arch/arm64/configs/defconfig -+++ b/arch/arm64/configs/defconfig -@@ -446,6 +446,14 @@ CONFIG_INPUT_HISI_POWERKEY=y - # CONFIG_SERIO_SERPORT is not set - CONFIG_SERIO_AMBAKMI=y - CONFIG_LEGACY_PTY_COUNT=16 -+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_SERIAL_8250=y - CONFIG_SERIAL_8250_CONSOLE=y - CONFIG_SERIAL_8250_EXTENDED=y -diff --git a/arch/arm64/configs/openkylin_generic_defconfig b/arch/arm64/configs/openkylin_generic_defconfig -index d4d0406..8292291 100644 ---- a/arch/arm64/configs/openkylin_generic_defconfig -+++ b/arch/arm64/configs/openkylin_generic_defconfig -@@ -1042,7 +1042,14 @@ CONFIG_SERIO_AMBAKMI=y - CONFIG_SERIO_RAW=m - CONFIG_SERIO_ALTERA_PS2=m - CONFIG_SERIO_ARC_PS2=m --# CONFIG_VT_CONSOLE is not set -+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_SERIAL_8250=y - # CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set -@@ -1186,8 +1193,6 @@ CONFIG_MEDIA_CEC_SUPPORT=y - CONFIG_USB_PULSE8_CEC=m - CONFIG_USB_RAINSHADOW_CEC=m - CONFIG_DRM=m --CONFIG_DRM_PANIC=y --CONFIG_DRM_PANIC_DEBUG=y - CONFIG_DRM_LOAD_EDID_FIRMWARE=y - CONFIG_DRM_DP_AUX_CHARDEV=y - CONFIG_DRM_DP_CEC=y -diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig -index 6557664..75dffe2 100644 ---- a/arch/loongarch/Kconfig -+++ b/arch/loongarch/Kconfig -@@ -78,6 +78,7 @@ config LOONGARCH - select GENERIC_ENTRY - select GENERIC_GETTIMEOFDAY - select GENERIC_IOREMAP if !ARCH_IOREMAP -+ select GENERIC_IRQ_MATRIX_ALLOCATOR - select GENERIC_IRQ_MULTI_HANDLER - select GENERIC_IRQ_PROBE - select GENERIC_IRQ_SHOW -@@ -139,7 +140,7 @@ config LOONGARCH - select HAVE_LIVEPATCH - select HAVE_MOD_ARCH_SPECIFIC - select HAVE_NMI -- select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS -+ select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS && AS_HAS_THIN_ADD_SUB - select HAVE_PCI - select HAVE_PERF_EVENTS - select HAVE_PERF_REGS -@@ -268,6 +269,9 @@ config AS_HAS_EXPLICIT_RELOCS - config AS_HAS_FCSR_CLASS - def_bool $(as-instr,movfcsr2gr \$t0$(comma)\$fcsr0) - -+config AS_HAS_THIN_ADD_SUB -+ def_bool $(cc-option,-Wa$(comma)-mthin-add-sub) || AS_IS_LLVM -+ - config AS_HAS_LSX_EXTENSION - def_bool $(as-instr,vld \$vr0$(comma)\$a0$(comma)0) - -diff --git a/arch/loongarch/Kconfig.debug b/arch/loongarch/Kconfig.debug -index 98d6063..8b2ce5b 100644 ---- a/arch/loongarch/Kconfig.debug -+++ b/arch/loongarch/Kconfig.debug -@@ -28,6 +28,7 @@ config UNWINDER_PROLOGUE - - config UNWINDER_ORC - bool "ORC unwinder" -+ depends on HAVE_OBJTOOL - select OBJTOOL - help - This option enables the ORC (Oops Rewind Capability) unwinder for -diff --git a/arch/loongarch/configs/loongson3_defconfig b/arch/loongarch/configs/loongson3_defconfig -index ec3cdb9..3bfd270 100644 ---- a/arch/loongarch/configs/loongson3_defconfig -+++ b/arch/loongarch/configs/loongson3_defconfig -@@ -687,7 +687,7 @@ CONFIG_DRM_AMDGPU_USERPTR=y - CONFIG_DRM_AST=y - CONFIG_DRM_QXL=m - CONFIG_DRM_VIRTIO_GPU=m --CONFIG_DRM_LOONGSON=y -+CONFIG_DRM_LOONGSON=m - CONFIG_FB=y - CONFIG_FB_EFI=y - CONFIG_FB_RADEON=y -diff --git a/arch/loongarch/configs/openkylin_generic_defconfig b/arch/loongarch/configs/openkylin_generic_defconfig -index e1e6637..21c8966 100644 ---- a/arch/loongarch/configs/openkylin_generic_defconfig -+++ b/arch/loongarch/configs/openkylin_generic_defconfig -@@ -47,10 +47,10 @@ CONFIG_NUMA=y - CONFIG_CPU_HAS_LSX=y - CONFIG_CPU_HAS_LASX=y - CONFIG_CPU_HAS_LBT=y -+CONFIG_LIVEPATCH=y - CONFIG_CPU_FREQ=y - CONFIG_CPU_FREQ_STAT=y - CONFIG_CPU_FREQ_GOV_POWERSAVE=y --CONFIG_LOONGSON3_ACPI_CPUFREQ=y - CONFIG_HIBERNATION=y - CONFIG_PM_DEBUG=y - CONFIG_ACPI_SPCR_TABLE=y -@@ -168,7 +168,6 @@ CONFIG_TCP_CONG_DCTCP=m - CONFIG_TCP_CONG_CDG=m - CONFIG_TCP_CONG_BBR=m - CONFIG_TCP_MD5SIG=y --CONFIG_IPV6=y - CONFIG_IPV6_ROUTER_PREF=y - CONFIG_IPV6_ROUTE_INFO=y - CONFIG_IPV6_OPTIMISTIC_DAD=y -@@ -191,7 +190,6 @@ CONFIG_IPV6_SEG6_HMAC=y - CONFIG_IPV6_RPL_LWTUNNEL=y - CONFIG_NETLABEL=y - CONFIG_MPTCP=y --CONFIG_MPTCP_IPV6=y - # CONFIG_MPTCP_KUNIT_TEST is not set - CONFIG_NETWORK_PHY_TIMESTAMPING=y - CONFIG_NETFILTER=y -@@ -690,7 +688,7 @@ CONFIG_CDROM_PKTCDVD=m - CONFIG_VIRTIO_BLK=m - CONFIG_BLK_DEV_RBD=m - CONFIG_BLK_DEV_UBLK=m --CONFIG_BLK_DEV_NVME=m -+CONFIG_BLK_DEV_NVME=y - CONFIG_NVME_MULTIPATH=y - CONFIG_NVME_RDMA=m - CONFIG_NVME_FC=m -@@ -722,7 +720,7 @@ CONFIG_UACCE=m - CONFIG_PVPANIC=y - CONFIG_PVPANIC_MMIO=m - CONFIG_PVPANIC_PCI=m --CONFIG_BLK_DEV_SD=m -+CONFIG_BLK_DEV_SD=y - CONFIG_CHR_DEV_ST=m - CONFIG_BLK_DEV_SR=m - CONFIG_CHR_DEV_SG=m -@@ -1538,9 +1536,9 @@ CONFIG_VIDEO_UPD64031A=m - CONFIG_VIDEO_UPD64083=m - CONFIG_VIDEO_M52790=m - CONFIG_DRM=y -+# CONFIG_DRM_KUNIT_TEST is not set - CONFIG_DRM_PANIC=y - CONFIG_DRM_PANIC_DEBUG=y --# CONFIG_DRM_KUNIT_TEST is not set - CONFIG_DRM_LOAD_EDID_FIRMWARE=y - CONFIG_DRM_DP_AUX_CHARDEV=y - CONFIG_DRM_DP_CEC=y -@@ -1555,11 +1553,11 @@ CONFIG_DRM_AMD_ACP=y - CONFIG_DRM_NOUVEAU=m - CONFIG_DRM_VKMS=m - CONFIG_DRM_UDL=m --CONFIG_DRM_AST=y -+CONFIG_DRM_AST_LOONGSON=y - CONFIG_DRM_MGAG200=m - CONFIG_DRM_QXL=m - CONFIG_DRM_VIRTIO_GPU=m --CONFIG_DRM_LOONGSON=y -+CONFIG_DRM_LOONGSON=m - CONFIG_DRM_BOCHS=m - CONFIG_DRM_CIRRUS_QEMU=m - CONFIG_DRM_GM12U320=m -@@ -2409,7 +2407,6 @@ CONFIG_SECONDARY_TRUSTED_KEYRING=y - CONFIG_SYSTEM_BLACKLIST_KEYRING=y - CONFIG_SYSTEM_REVOCATION_LIST=y - CONFIG_PRIME_NUMBERS=m --CONFIG_CRC_T10DIF=y - CONFIG_CRC_ITU_T=y - CONFIG_CRC7=m - CONFIG_QRLIB=y -@@ -2448,6 +2445,7 @@ CONFIG_RCU_TORTURE_TEST=m - CONFIG_RCU_REF_SCALE_TEST=m - CONFIG_RCU_CPU_STALL_TIMEOUT=60 - # CONFIG_RCU_TRACE is not set -+CONFIG_FUNCTION_TRACER=y - CONFIG_BOOTTIME_TRACING=y - CONFIG_STACK_TRACER=y - CONFIG_SCHED_TRACER=y -@@ -2460,6 +2458,7 @@ CONFIG_RING_BUFFER_BENCHMARK=m - CONFIG_KUNIT=m - CONFIG_KUNIT_ALL_TESTS=m - # CONFIG_TEST_SORT is not set -+CONFIG_UNWINDER_ORC=y - CONFIG_ATOMIC64_SELFTEST=y - CONFIG_ASYNC_RAID6_TEST=m - CONFIG_TEST_KSTRTOX=m -@@ -2467,3 +2466,4 @@ CONFIG_TEST_VMALLOC=m - CONFIG_TEST_BPF=m - # CONFIG_BITFIELD_KUNIT is not set - CONFIG_LINEAR_RANGES_TEST=m -+CONFIG_CMDLINE="nokaslr" -diff --git a/arch/loongarch/include/asm/Kbuild b/arch/loongarch/include/asm/Kbuild -index c862672..aa4ab6c 100644 ---- a/arch/loongarch/include/asm/Kbuild -+++ b/arch/loongarch/include/asm/Kbuild -@@ -6,7 +6,6 @@ generic-y += mcs_spinlock.h - generic-y += parport.h - generic-y += early_ioremap.h - generic-y += qrwlock.h --generic-y += qspinlock.h - generic-y += rwsem.h - generic-y += segment.h - generic-y += user.h -diff --git a/arch/loongarch/include/asm/addrspace.h b/arch/loongarch/include/asm/addrspace.h -index 838fa4d..8ef3e36 100644 ---- a/arch/loongarch/include/asm/addrspace.h -+++ b/arch/loongarch/include/asm/addrspace.h -@@ -37,6 +37,10 @@ extern unsigned long vm_map_base; - #define UNCACHE_BASE CSR_DMW0_BASE - #endif - -+#ifndef WRITECOMBINE_BASE -+#define WRITECOMBINE_BASE CSR_DMW2_BASE -+#endif -+ - #define DMW_PABITS 48 - #define TO_PHYS_MASK ((1ULL << DMW_PABITS) - 1) - -diff --git a/arch/loongarch/include/asm/atomic.h b/arch/loongarch/include/asm/atomic.h -index 99af8b3..c86f0ab 100644 ---- a/arch/loongarch/include/asm/atomic.h -+++ b/arch/loongarch/include/asm/atomic.h -@@ -15,6 +15,7 @@ - #define __LL "ll.w " - #define __SC "sc.w " - #define __AMADD "amadd.w " -+#define __AMOR "amor.w " - #define __AMAND_DB "amand_db.w " - #define __AMOR_DB "amor_db.w " - #define __AMXOR_DB "amxor_db.w " -@@ -22,6 +23,7 @@ - #define __LL "ll.d " - #define __SC "sc.d " - #define __AMADD "amadd.d " -+#define __AMOR "amor.d " - #define __AMAND_DB "amand_db.d " - #define __AMOR_DB "amor_db.d " - #define __AMXOR_DB "amxor_db.d " -diff --git a/arch/loongarch/include/asm/cpu-features.h b/arch/loongarch/include/asm/cpu-features.h -index 2eafe6a..16a716f 100644 ---- a/arch/loongarch/include/asm/cpu-features.h -+++ b/arch/loongarch/include/asm/cpu-features.h -@@ -65,5 +65,6 @@ - #define cpu_has_guestid cpu_opt(LOONGARCH_CPU_GUESTID) - #define cpu_has_hypervisor cpu_opt(LOONGARCH_CPU_HYPERVISOR) - #define cpu_has_ptw cpu_opt(LOONGARCH_CPU_PTW) -+#define cpu_has_avecint cpu_opt(LOONGARCH_CPU_AVECINT) - - #endif /* __ASM_CPU_FEATURES_H */ -diff --git a/arch/loongarch/include/asm/cpu.h b/arch/loongarch/include/asm/cpu.h -index 48b9f71..843f9c4 100644 ---- a/arch/loongarch/include/asm/cpu.h -+++ b/arch/loongarch/include/asm/cpu.h -@@ -99,6 +99,7 @@ enum cpu_type_enum { - #define CPU_FEATURE_GUESTID 24 /* CPU has GuestID feature */ - #define CPU_FEATURE_HYPERVISOR 25 /* CPU has hypervisor (running in VM) */ - #define CPU_FEATURE_PTW 26 /* CPU has hardware page table walker */ -+#define CPU_FEATURE_AVECINT 27 /* CPU has avec interrupt */ - - #define LOONGARCH_CPU_CPUCFG BIT_ULL(CPU_FEATURE_CPUCFG) - #define LOONGARCH_CPU_LAM BIT_ULL(CPU_FEATURE_LAM) -@@ -127,5 +128,6 @@ enum cpu_type_enum { - #define LOONGARCH_CPU_GUESTID BIT_ULL(CPU_FEATURE_GUESTID) - #define LOONGARCH_CPU_HYPERVISOR BIT_ULL(CPU_FEATURE_HYPERVISOR) - #define LOONGARCH_CPU_PTW BIT_ULL(CPU_FEATURE_PTW) -+#define LOONGARCH_CPU_AVECINT BIT_ULL(CPU_FEATURE_AVECINT) - - #endif /* _ASM_CPU_H */ -diff --git a/arch/loongarch/include/asm/hardirq.h b/arch/loongarch/include/asm/hardirq.h -index b26d596..5f70cb7 100644 ---- a/arch/loongarch/include/asm/hardirq.h -+++ b/arch/loongarch/include/asm/hardirq.h -@@ -15,8 +15,9 @@ extern void ack_bad_irq(unsigned int irq); - enum ipi_msg_type { - IPI_RESCHEDULE, - IPI_CALL_FUNCTION, -+ IPI_CLEAR_VECTOR, - }; --#define NR_IPI 2 -+#define NR_IPI 3 - - typedef struct { - unsigned int ipi_irqs[NR_IPI]; -diff --git a/arch/loongarch/include/asm/hugetlb.h b/arch/loongarch/include/asm/hugetlb.h -index aa44b3f..5da32c0 100644 ---- a/arch/loongarch/include/asm/hugetlb.h -+++ b/arch/loongarch/include/asm/hugetlb.h -@@ -34,7 +34,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, - unsigned long addr, pte_t *ptep) - { - pte_t clear; -- pte_t pte = *ptep; -+ pte_t pte = ptep_get(ptep); - - pte_val(clear) = (unsigned long)invalid_pte_table; - set_pte_at(mm, addr, ptep, clear); -@@ -65,7 +65,7 @@ static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, - pte_t *ptep, pte_t pte, - int dirty) - { -- int changed = !pte_same(*ptep, pte); -+ int changed = !pte_same(ptep_get(ptep), pte); - - if (changed) { - set_pte_at(vma->vm_mm, addr, ptep, pte); -diff --git a/arch/loongarch/include/asm/hw_irq.h b/arch/loongarch/include/asm/hw_irq.h -index af4f4e8..8156ffb 100644 ---- a/arch/loongarch/include/asm/hw_irq.h -+++ b/arch/loongarch/include/asm/hw_irq.h -@@ -9,6 +9,8 @@ - - extern atomic_t irq_err_count; - -+#define ARCH_IRQ_INIT_FLAGS IRQ_NOPROBE -+ - /* - * interrupt-retrigger: NOP for now. This may not be appropriate for all - * machines, we'll see ... -diff --git a/arch/loongarch/include/asm/io.h b/arch/loongarch/include/asm/io.h -index c2f9979..5e95a60 100644 ---- a/arch/loongarch/include/asm/io.h -+++ b/arch/loongarch/include/asm/io.h -@@ -25,10 +25,16 @@ extern void __init early_iounmap(void __iomem *addr, unsigned long size); - static inline void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size, - unsigned long prot_val) - { -- if (prot_val & _CACHE_CC) -+ switch (prot_val & _CACHE_MASK) { -+ case _CACHE_CC: - return (void __iomem *)(unsigned long)(CACHE_BASE + offset); -- else -+ case _CACHE_SUC: - return (void __iomem *)(unsigned long)(UNCACHE_BASE + offset); -+ case _CACHE_WUC: -+ return (void __iomem *)(unsigned long)(WRITECOMBINE_BASE + offset); -+ default: -+ return NULL; -+ } - } - - #define ioremap(offset, size) \ -diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h -index 79f4c83..78253da 100644 ---- a/arch/loongarch/include/asm/irq.h -+++ b/arch/loongarch/include/asm/irq.h -@@ -39,12 +39,23 @@ void spurious_interrupt(void); - - #define NR_IRQS_LEGACY 16 - -+/* -+ * 256 Vectors Mapping for AVECINTC: -+ * -+ * 0 - 15: Mapping classic IPs, e.g. IP0-12. -+ * 16 - 255: Mapping vectors for external IRQ. -+ * -+ */ -+#define NR_VECTORS 256 -+#define NR_LEGACY_VECTORS 16 -+#define IRQ_MATRIX_BITS NR_VECTORS -+ - #define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace - extern bool arch_trigger_cpumask_backtrace(const cpumask_t *mask, - int exclude_cpu); - --#define MAX_IO_PICS 2 --#define NR_IRQS (64 + (256 * MAX_IO_PICS)) -+#define MAX_IO_PICS 16 -+#define NR_IRQS (64 + NR_VECTORS * (NR_CPUS + MAX_IO_PICS)) - - struct acpi_vector_group { - int node; -@@ -67,7 +78,7 @@ extern struct acpi_vector_group msi_group[MAX_IO_PICS]; - #define LOONGSON_LPC_LAST_IRQ (LOONGSON_LPC_IRQ_BASE + 15) - - #define LOONGSON_CPU_IRQ_BASE 16 --#define LOONGSON_CPU_LAST_IRQ (LOONGSON_CPU_IRQ_BASE + 14) -+#define LOONGSON_CPU_LAST_IRQ (LOONGSON_CPU_IRQ_BASE + 15) - - #define LOONGSON_PCH_IRQ_BASE 64 - #define LOONGSON_PCH_ACPI_IRQ (LOONGSON_PCH_IRQ_BASE + 47) -@@ -90,20 +101,8 @@ struct acpi_madt_bio_pic; - struct acpi_madt_msi_pic; - struct acpi_madt_lpc_pic; - --int liointc_acpi_init(struct irq_domain *parent, -- struct acpi_madt_lio_pic *acpi_liointc); --int eiointc_acpi_init(struct irq_domain *parent, -- struct acpi_madt_eio_pic *acpi_eiointc); -- --int htvec_acpi_init(struct irq_domain *parent, -- struct acpi_madt_ht_pic *acpi_htvec); --int pch_lpc_acpi_init(struct irq_domain *parent, -- struct acpi_madt_lpc_pic *acpi_pchlpc); --int pch_msi_acpi_init(struct irq_domain *parent, -- struct acpi_madt_msi_pic *acpi_pchmsi); --int pch_pic_acpi_init(struct irq_domain *parent, -- struct acpi_madt_bio_pic *acpi_pchpic); --int find_pch_pic(u32 gsi); -+void complete_irq_moving(void); -+ - struct fwnode_handle *get_pch_msi_handle(int pci_segment); - - extern struct acpi_madt_lio_pic *acpi_liointc; -diff --git a/arch/loongarch/include/asm/kfence.h b/arch/loongarch/include/asm/kfence.h -index 92636e8..da9e930 100644 ---- a/arch/loongarch/include/asm/kfence.h -+++ b/arch/loongarch/include/asm/kfence.h -@@ -53,13 +53,13 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect) - { - pte_t *pte = virt_to_kpte(addr); - -- if (WARN_ON(!pte) || pte_none(*pte)) -+ if (WARN_ON(!pte) || pte_none(ptep_get(pte))) - return false; - - if (protect) -- set_pte(pte, __pte(pte_val(*pte) & ~(_PAGE_VALID | _PAGE_PRESENT))); -+ set_pte(pte, __pte(pte_val(ptep_get(pte)) & ~(_PAGE_VALID | _PAGE_PRESENT))); - else -- set_pte(pte, __pte(pte_val(*pte) | (_PAGE_VALID | _PAGE_PRESENT))); -+ set_pte(pte, __pte(pte_val(ptep_get(pte)) | (_PAGE_VALID | _PAGE_PRESENT))); - - preempt_disable(); - local_flush_tlb_one(addr); -diff --git a/arch/loongarch/include/asm/kvm_csr.h b/arch/loongarch/include/asm/kvm_csr.h -index 0a52f11..4a76ce7 100644 ---- a/arch/loongarch/include/asm/kvm_csr.h -+++ b/arch/loongarch/include/asm/kvm_csr.h -@@ -181,6 +181,7 @@ __BUILD_GCSR_OP(tlbidx) - - #define kvm_save_hw_gcsr(csr, gid) (csr->csrs[gid] = gcsr_read(gid)) - #define kvm_restore_hw_gcsr(csr, gid) (gcsr_write(csr->csrs[gid], gid)) -+ - #define kvm_read_clear_hw_gcsr(csr, gid) (csr->csrs[gid] = gcsr_write(0, gid)) - - int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu); -@@ -210,9 +211,7 @@ static __always_inline void kvm_change_sw_gcsr(struct loongarch_csrs *csr, - csr->csrs[gid] |= val & _mask; - } - --#define KVM_PMU_EVENT_ENABLED (CSR_PERFCTRL_PLV0 | \ -- CSR_PERFCTRL_PLV1 | \ -- CSR_PERFCTRL_PLV2 | \ -- CSR_PERFCTRL_PLV3) -+#define KVM_PMU_EVENT_ENABLED (CSR_PERFCTRL_PLV0 | CSR_PERFCTRL_PLV1 | \ -+ CSR_PERFCTRL_PLV2 | CSR_PERFCTRL_PLV3) - - #endif /* __ASM_LOONGARCH_KVM_CSR_H__ */ -diff --git a/arch/loongarch/include/asm/kvm_extioi.h b/arch/loongarch/include/asm/kvm_extioi.h -new file mode 100644 -index 0000000..c2bd295 ---- /dev/null -+++ b/arch/loongarch/include/asm/kvm_extioi.h -@@ -0,0 +1,96 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2024 Loongson Technology Corporation Limited -+ */ -+ -+#ifndef LOONGARCH_EXTIOI_H -+#define LOONGARCH_EXTIOI_H -+ -+#include <kvm/iodev.h> -+ -+#define EXTIOI_IRQS 256 -+#define EXTIOI_ROUTE_MAX_VCPUS 256 -+#define EXTIOI_IRQS_U8_NUMS (EXTIOI_IRQS / 8) -+#define EXTIOI_IRQS_U32_NUMS (EXTIOI_IRQS_U8_NUMS / 4) -+#define EXTIOI_IRQS_U64_NUMS (EXTIOI_IRQS_U32_NUMS / 2) -+/* map to ipnum per 32 irqs */ -+#define EXTIOI_IRQS_NODETYPE_COUNT 16 -+ -+#define EXTIOI_BASE 0x1400 -+#define EXTIOI_SIZE 0x900 -+ -+#define EXTIOI_NODETYPE_START 0xa0 -+#define EXTIOI_NODETYPE_END 0xbf -+#define EXTIOI_IPMAP_START 0xc0 -+#define EXTIOI_IPMAP_END 0xc7 -+#define EXTIOI_ENABLE_START 0x200 -+#define EXTIOI_ENABLE_END 0x21f -+#define EXTIOI_BOUNCE_START 0x280 -+#define EXTIOI_BOUNCE_END 0x29f -+#define EXTIOI_ISR_START 0x300 -+#define EXTIOI_ISR_END 0x31f -+#define EXTIOI_COREISR_START 0x400 -+#define EXTIOI_COREISR_END 0x71f -+#define EXTIOI_COREMAP_START 0x800 -+#define EXTIOI_COREMAP_END 0x8ff -+ -+#define LS3A_INTC_IP 8 -+ -+#define EXTIOI_SW_COREMAP_FLAG (1 << 0) -+ -+struct loongarch_extioi { -+ spinlock_t lock; -+ struct kvm *kvm; -+ struct kvm_io_device device; -+ /* hardware state */ -+ union nodetype { -+ u64 reg_u64[EXTIOI_IRQS_NODETYPE_COUNT / 4]; -+ u32 reg_u32[EXTIOI_IRQS_NODETYPE_COUNT / 2]; -+ uint16_t reg_u16[EXTIOI_IRQS_NODETYPE_COUNT]; -+ u8 reg_u8[EXTIOI_IRQS_NODETYPE_COUNT * 2]; -+ } nodetype; -+ -+ /* one bit shows the state of one irq */ -+ union bounce { -+ u64 reg_u64[EXTIOI_IRQS_U64_NUMS]; -+ u32 reg_u32[EXTIOI_IRQS_U32_NUMS]; -+ u8 reg_u8[EXTIOI_IRQS_U8_NUMS]; -+ } bounce; -+ -+ union isr { -+ u64 reg_u64[EXTIOI_IRQS_U64_NUMS]; -+ u32 reg_u32[EXTIOI_IRQS_U32_NUMS]; -+ u8 reg_u8[EXTIOI_IRQS_U8_NUMS]; -+ } isr; -+ union coreisr { -+ u64 reg_u64[EXTIOI_ROUTE_MAX_VCPUS][EXTIOI_IRQS_U64_NUMS]; -+ u32 reg_u32[EXTIOI_ROUTE_MAX_VCPUS][EXTIOI_IRQS_U32_NUMS]; -+ u8 reg_u8[EXTIOI_ROUTE_MAX_VCPUS][EXTIOI_IRQS_U8_NUMS]; -+ } coreisr; -+ union enable { -+ u64 reg_u64[EXTIOI_IRQS_U64_NUMS]; -+ u32 reg_u32[EXTIOI_IRQS_U32_NUMS]; -+ u8 reg_u8[EXTIOI_IRQS_U8_NUMS]; -+ } enable; -+ -+ /* use one byte to config ipmap for 32 irqs at once */ -+ union ipmap { -+ u64 reg_u64; -+ u32 reg_u32[EXTIOI_IRQS_U32_NUMS / 4]; -+ u8 reg_u8[EXTIOI_IRQS_U8_NUMS / 4]; -+ } ipmap; -+ /* use one byte to config coremap for one irq */ -+ union coremap { -+ u64 reg_u64[EXTIOI_IRQS / 8]; -+ u32 reg_u32[EXTIOI_IRQS / 4]; -+ u8 reg_u8[EXTIOI_IRQS]; -+ } coremap; -+ -+ DECLARE_BITMAP(sw_coreisr[EXTIOI_ROUTE_MAX_VCPUS][LS3A_INTC_IP], EXTIOI_IRQS); -+ uint8_t sw_coremap[EXTIOI_IRQS]; -+}; -+ -+void extioi_set_irq(struct loongarch_extioi *s, int irq, int level); -+int kvm_loongarch_register_extioi_device(void); -+int kvm_loongarch_reset_extioi(struct kvm *kvm); -+#endif /* LOONGARCH_EXTIOI_H */ -diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h -index 7e77884..f8528e18 100644 ---- a/arch/loongarch/include/asm/kvm_host.h -+++ b/arch/loongarch/include/asm/kvm_host.h -@@ -19,6 +19,9 @@ - #include <asm/inst.h> - #include <asm/kvm_mmu.h> - #include <asm/loongarch.h> -+#include <asm/kvm_ipi.h> -+#include <asm/kvm_extioi.h> -+#include <asm/kvm_pch_pic.h> - - /* Loongarch KVM register ids */ - #define KVM_GET_IOC_CSR_IDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT) -@@ -26,12 +29,27 @@ - - #define KVM_MAX_VCPUS 256 - #define KVM_MAX_CPUCFG_REGS 21 --/* memory slots that does not exposed to userspace */ --#define KVM_PRIVATE_MEM_SLOTS 0 - - #define KVM_HALT_POLL_NS_DEFAULT 500000 - #define KVM_REQ_TLB_FLUSH_GPA KVM_ARCH_REQ(0) - #define KVM_REQ_STEAL_UPDATE KVM_ARCH_REQ(1) -+#define KVM_REQ_PMU KVM_ARCH_REQ(2) -+ -+/* KVM_IRQ_LINE irq field index values */ -+#define KVM_LOONGARCH_IRQ_TYPE_SHIFT 24 -+#define KVM_LOONGARCH_IRQ_TYPE_MASK 0xff -+#define KVM_LOONGARCH_IRQ_VCPU_SHIFT 16 -+#define KVM_LOONGARCH_IRQ_VCPU_MASK 0xff -+#define KVM_LOONGARCH_IRQ_NUM_SHIFT 0 -+#define KVM_LOONGARCH_IRQ_NUM_MASK 0xffff -+ -+/* irq_type field */ -+#define KVM_LOONGARCH_IRQ_TYPE_CPU_IP 0 -+#define KVM_LOONGARCH_IRQ_TYPE_CPU_IO 1 -+#define KVM_LOONGARCH_IRQ_TYPE_HT 2 -+#define KVM_LOONGARCH_IRQ_TYPE_MSI 3 -+#define KVM_LOONGARCH_IRQ_TYPE_IOAPIC 4 -+#define KVM_LOONGARCH_IRQ_TYPE_ROUTE 5 - - #define KVM_GUESTDBG_SW_BP_MASK \ - (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP) -@@ -45,6 +63,12 @@ struct kvm_vm_stat { - struct kvm_vm_stat_generic generic; - u64 pages; - u64 hugepages; -+ u64 ipi_read_exits; -+ u64 ipi_write_exits; -+ u64 extioi_read_exits; -+ u64 extioi_write_exits; -+ u64 pch_pic_read_exits; -+ u64 pch_pic_write_exits; - }; - - struct kvm_vcpu_stat { -@@ -62,12 +86,11 @@ struct kvm_arch_memory_slot { - unsigned long flags; - }; - --#define KVM_REQ_PMU KVM_ARCH_REQ(0) - #define HOST_MAX_PMNUM 16 - struct kvm_context { - unsigned long vpid_cache; - struct kvm_vcpu *last_vcpu; -- /* Save host pmu csr */ -+ /* Host PMU CSR */ - u64 perf_ctrl[HOST_MAX_PMNUM]; - u64 perf_cntr[HOST_MAX_PMNUM]; - }; -@@ -114,9 +137,14 @@ struct kvm_arch { - unsigned int root_level; - spinlock_t phyid_map_lock; - struct kvm_phyid_map *phyid_map; -+ /* Enabled PV features */ -+ unsigned long pv_features; - - s64 time_offset; - struct kvm_context __percpu *vmcs; -+ struct loongarch_ipi *ipi; -+ struct loongarch_extioi *extioi; -+ struct loongarch_pch_pic *pch_pic; - }; - - #define CSR_MAX_NUMS 0x800 -@@ -140,10 +168,15 @@ enum emulation_result { - #define KVM_LARCH_FPU (0x1 << 0) - #define KVM_LARCH_LSX (0x1 << 1) - #define KVM_LARCH_LASX (0x1 << 2) --#define KVM_LARCH_SWCSR_LATEST (0x1 << 3) --#define KVM_LARCH_HWCSR_USABLE (0x1 << 4) --#define KVM_GUEST_PMU_ENABLE (0x1 << 5) --#define KVM_GUEST_PMU_ACTIVE (0x1 << 6) -+#define KVM_LARCH_LBT (0x1 << 3) -+#define KVM_LARCH_PMU (0x1 << 4) -+#define KVM_LARCH_SWCSR_LATEST (0x1 << 5) -+#define KVM_LARCH_HWCSR_USABLE (0x1 << 6) -+ -+#define LOONGARCH_PV_FEAT_UPDATED BIT_ULL(63) -+#define LOONGARCH_PV_FEAT_MASK (BIT(KVM_FEATURE_IPI) | \ -+ BIT(KVM_FEATURE_STEAL_TIME) | \ -+ BIT(KVM_FEATURE_VIRT_EXTIOI)) - - struct kvm_vcpu_arch { - /* -@@ -177,6 +210,7 @@ struct kvm_vcpu_arch { - - /* FPU state */ - struct loongarch_fpu fpu FPU_ALIGN; -+ struct loongarch_lbt lbt; - - /* CSR state */ - struct loongarch_csrs *csr; -@@ -215,6 +249,8 @@ struct kvm_vcpu_arch { - int last_sched_cpu; - /* mp state */ - struct kvm_mp_state mp_state; -+ /* ipi state */ -+ struct ipi_state ipi_state; - /* cpucfg */ - u32 cpucfg[KVM_MAX_CPUCFG_REGS]; - -@@ -251,14 +287,19 @@ static inline bool kvm_guest_has_lasx(struct kvm_vcpu_arch *arch) - return arch->cpucfg[2] & CPUCFG2_LASX; - } - -+static inline bool kvm_guest_has_lbt(struct kvm_vcpu_arch *arch) -+{ -+ return arch->cpucfg[2] & (CPUCFG2_X86BT | CPUCFG2_ARMBT | CPUCFG2_MIPSBT); -+} -+ - static inline bool kvm_guest_has_pmu(struct kvm_vcpu_arch *arch) - { -- return arch->cpucfg[LOONGARCH_CPUCFG6] & CPUCFG6_PMP; -+ return arch->cpucfg[6] & CPUCFG6_PMP; - } - - static inline int kvm_get_pmu_num(struct kvm_vcpu_arch *arch) - { -- return (arch->cpucfg[LOONGARCH_CPUCFG6] & CPUCFG6_PMNUM) >> CPUCFG6_PMNUM_SHIFT; -+ return (arch->cpucfg[6] & CPUCFG6_PMNUM) >> CPUCFG6_PMNUM_SHIFT; - } - - /* Debug: dump vcpu state */ -diff --git a/arch/loongarch/include/asm/kvm_ipi.h b/arch/loongarch/include/asm/kvm_ipi.h -new file mode 100644 -index 0000000..729dfc1 ---- /dev/null -+++ b/arch/loongarch/include/asm/kvm_ipi.h -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2024 Loongson Technology Corporation Limited -+ */ -+ -+#ifndef __LS3A_KVM_IPI_H -+#define __LS3A_KVM_IPI_H -+ -+#include <kvm/iodev.h> -+ -+#define LARCH_INT_IPI 12 -+ -+struct loongarch_ipi { -+ spinlock_t lock; -+ struct kvm *kvm; -+ struct kvm_io_device device; -+ struct kvm_io_device mail_dev; -+}; -+ -+struct ipi_state { -+ spinlock_t lock; -+ uint32_t status; -+ uint32_t en; -+ uint32_t set; -+ uint32_t clear; -+ uint64_t buf[4]; -+}; -+ -+#define SMP_MAILBOX 0x1000 -+#define KVM_IOCSR_IPI_ADDR_SIZE 0x48 -+ -+#define CORE_STATUS_OFF 0x000 -+#define CORE_EN_OFF 0x004 -+#define CORE_SET_OFF 0x008 -+#define CORE_CLEAR_OFF 0x00c -+#define CORE_BUF_20 0x020 -+#define CORE_BUF_28 0x028 -+#define CORE_BUF_30 0x030 -+#define CORE_BUF_38 0x038 -+#define IOCSR_IPI_SEND 0x040 -+ -+#define IOCSR_MAIL_SEND 0x048 -+#define IOCSR_ANY_SEND 0x158 -+ -+#define MAIL_SEND_ADDR (SMP_MAILBOX + IOCSR_MAIL_SEND) -+#define KVM_IOCSR_MAIL_ADDR_SIZE 0x118 -+ -+#define MAIL_SEND_OFFSET 0 -+#define ANY_SEND_OFFSET (IOCSR_ANY_SEND - IOCSR_MAIL_SEND) -+ -+int kvm_loongarch_register_ipi_device(void); -+#endif -diff --git a/arch/loongarch/include/asm/kvm_para.h b/arch/loongarch/include/asm/kvm_para.h -index 335fb86..d0f0878 100644 ---- a/arch/loongarch/include/asm/kvm_para.h -+++ b/arch/loongarch/include/asm/kvm_para.h -@@ -2,6 +2,8 @@ - #ifndef _ASM_LOONGARCH_KVM_PARA_H - #define _ASM_LOONGARCH_KVM_PARA_H - -+#include <uapi/asm/kvm_para.h> -+ - /* - * Hypercall code field - */ -@@ -39,9 +41,9 @@ struct kvm_steal_time { - * Hypercall interface for KVM hypervisor - * - * a0: function identifier -- * a1-a6: args -+ * a1-a5: args - * Return value will be placed in a0. -- * Up to 6 arguments are passed in a1, a2, a3, a4, a5, a6. -+ * Up to 5 arguments are passed in a1, a2, a3, a4, a5. - */ - static __always_inline long kvm_hypercall0(u64 fid) - { -diff --git a/arch/loongarch/include/asm/kvm_pch_pic.h b/arch/loongarch/include/asm/kvm_pch_pic.h -new file mode 100644 -index 0000000..91bd5a5 ---- /dev/null -+++ b/arch/loongarch/include/asm/kvm_pch_pic.h -@@ -0,0 +1,61 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2024 Loongson Technology Corporation Limited -+ */ -+ -+#ifndef LOONGARCH_PCH_PIC_H -+#define LOONGARCH_PCH_PIC_H -+ -+#include <kvm/iodev.h> -+ -+#define PCH_PIC_SIZE 0x3e8 -+ -+#define PCH_PIC_INT_ID_START 0x0 -+#define PCH_PIC_INT_ID_END 0x7 -+#define PCH_PIC_MASK_START 0x20 -+#define PCH_PIC_MASK_END 0x27 -+#define PCH_PIC_HTMSI_EN_START 0x40 -+#define PCH_PIC_HTMSI_EN_END 0x47 -+#define PCH_PIC_EDGE_START 0x60 -+#define PCH_PIC_EDGE_END 0x67 -+#define PCH_PIC_CLEAR_START 0x80 -+#define PCH_PIC_CLEAR_END 0x87 -+#define PCH_PIC_AUTO_CTRL0_START 0xc0 -+#define PCH_PIC_AUTO_CTRL0_END 0xc7 -+#define PCH_PIC_AUTO_CTRL1_START 0xe0 -+#define PCH_PIC_AUTO_CTRL1_END 0xe7 -+#define PCH_PIC_ROUTE_ENTRY_START 0x100 -+#define PCH_PIC_ROUTE_ENTRY_END 0x13f -+#define PCH_PIC_HTMSI_VEC_START 0x200 -+#define PCH_PIC_HTMSI_VEC_END 0x23f -+#define PCH_PIC_INT_IRR_START 0x380 -+#define PCH_PIC_INT_IRR_END 0x38f -+#define PCH_PIC_INT_ISR_START 0x3a0 -+#define PCH_PIC_INT_ISR_END 0x3af -+#define PCH_PIC_POLARITY_START 0x3e0 -+#define PCH_PIC_POLARITY_END 0x3e7 -+#define PCH_PIC_INT_ID_VAL 0x7000000UL -+#define PCH_PIC_INT_ID_VER 0x1UL -+ -+struct loongarch_pch_pic { -+ spinlock_t lock; -+ struct kvm *kvm; -+ struct kvm_io_device device; -+ uint64_t mask; /* 1:disable irq, 0:enable irq */ -+ uint64_t htmsi_en; /* 1:msi */ -+ uint64_t edge; /* 1:edge triggered, 0:level triggered */ -+ uint64_t auto_ctrl0; /* only use default value 00b */ -+ uint64_t auto_ctrl1; /* only use default value 00b */ -+ uint64_t last_intirr; /* edge detection */ -+ uint64_t irr; /* interrupt request register */ -+ uint64_t isr; /* interrupt service register */ -+ uint64_t polarity; /* 0: high level trigger, 1: low level trigger */ -+ uint8_t route_entry[64]; /* default value 0, route to int0: extioi */ -+ uint8_t htmsi_vector[64]; /* irq route table for routing to extioi */ -+ uint64_t pch_pic_base; -+}; -+ -+void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level); -+void pch_msi_set_irq(struct kvm *kvm, int irq, int level); -+int kvm_loongarch_register_pch_pic_device(void); -+#endif /* LOONGARCH_PCH_PIC_H */ -diff --git a/arch/loongarch/include/asm/kvm_vcpu.h b/arch/loongarch/include/asm/kvm_vcpu.h -index c416cb7..d7e8f7d 100644 ---- a/arch/loongarch/include/asm/kvm_vcpu.h -+++ b/arch/loongarch/include/asm/kvm_vcpu.h -@@ -75,8 +75,13 @@ static inline void kvm_save_lasx(struct loongarch_fpu *fpu) { } - static inline void kvm_restore_lasx(struct loongarch_fpu *fpu) { } - #endif - -+#ifdef CONFIG_CPU_HAS_LBT -+int kvm_own_lbt(struct kvm_vcpu *vcpu); -+#else -+static inline int kvm_own_lbt(struct kvm_vcpu *vcpu) { return -EINVAL; } -+#endif -+ - void kvm_init_timer(struct kvm_vcpu *vcpu, unsigned long hz); --void kvm_reset_timer(struct kvm_vcpu *vcpu); - void kvm_save_timer(struct kvm_vcpu *vcpu); - void kvm_restore_timer(struct kvm_vcpu *vcpu); - -@@ -125,4 +130,9 @@ static inline bool kvm_pvtime_supported(void) - return !!sched_info_on(); - } - -+static inline bool kvm_guest_has_pv_feature(struct kvm_vcpu *vcpu, unsigned int feature) -+{ -+ return vcpu->kvm->arch.pv_features & BIT(feature); -+} -+ - #endif /* __ASM_LOONGARCH_KVM_VCPU_H__ */ -diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h -index 6829c7b..a2117ed 100644 ---- a/arch/loongarch/include/asm/loongarch.h -+++ b/arch/loongarch/include/asm/loongarch.h -@@ -161,16 +161,8 @@ - - /* - * CPUCFG index area: 0x40000000 -- 0x400000ff -- * SW emulation for KVM hypervirsor -+ * SW emulation for KVM hypervirsor, see arch/loongarch/include/uapi/asm/kvm_para.h - */ --#define CPUCFG_KVM_BASE 0x40000000 --#define CPUCFG_KVM_SIZE 0x100 -- --#define CPUCFG_KVM_SIG (CPUCFG_KVM_BASE + 0) --#define KVM_SIGNATURE "KVM\0" --#define CPUCFG_KVM_FEATURE (CPUCFG_KVM_BASE + 4) --#define KVM_FEATURE_IPI BIT(1) --#define KVM_FEATURE_STEAL_TIME BIT(2) - - #ifndef __ASSEMBLY__ - -@@ -255,8 +247,8 @@ - #define CSR_ESTAT_EXC_WIDTH 6 - #define CSR_ESTAT_EXC (_ULCAST_(0x3f) << CSR_ESTAT_EXC_SHIFT) - #define CSR_ESTAT_IS_SHIFT 0 --#define CSR_ESTAT_IS_WIDTH 14 --#define CSR_ESTAT_IS (_ULCAST_(0x3fff) << CSR_ESTAT_IS_SHIFT) -+#define CSR_ESTAT_IS_WIDTH 15 -+#define CSR_ESTAT_IS (_ULCAST_(0x7fff) << CSR_ESTAT_IS_SHIFT) - - #define LOONGARCH_CSR_ERA 0x6 /* ERA */ - -@@ -651,6 +643,13 @@ - - #define LOONGARCH_CSR_CTAG 0x98 /* TagLo + TagHi */ - -+#define LOONGARCH_CSR_ISR0 0xa0 -+#define LOONGARCH_CSR_ISR1 0xa1 -+#define LOONGARCH_CSR_ISR2 0xa2 -+#define LOONGARCH_CSR_ISR3 0xa3 -+ -+#define LOONGARCH_CSR_IRR 0xa4 -+ - #define LOONGARCH_CSR_PRID 0xc0 - - /* Shadow MCSR : 0xc0 ~ 0xff */ -@@ -880,7 +879,7 @@ - #define LOONGARCH_CSR_DMWIN2 0x182 /* 64 direct map win2: MEM */ - #define LOONGARCH_CSR_DMWIN3 0x183 /* 64 direct map win3: MEM */ - --/* Direct Map window 0/1 */ -+/* Direct Map window 0/1/2/3 */ - #define CSR_DMW0_PLV0 _CONST64_(1 << 0) - #define CSR_DMW0_VSEG _CONST64_(0x8000) - #define CSR_DMW0_BASE (CSR_DMW0_VSEG << DMW_PABITS) -@@ -892,6 +891,14 @@ - #define CSR_DMW1_BASE (CSR_DMW1_VSEG << DMW_PABITS) - #define CSR_DMW1_INIT (CSR_DMW1_BASE | CSR_DMW1_MAT | CSR_DMW1_PLV0) - -+#define CSR_DMW2_PLV0 _CONST64_(1 << 0) -+#define CSR_DMW2_MAT _CONST64_(2 << 4) -+#define CSR_DMW2_VSEG _CONST64_(0xa000) -+#define CSR_DMW2_BASE (CSR_DMW2_VSEG << DMW_PABITS) -+#define CSR_DMW2_INIT (CSR_DMW2_BASE | CSR_DMW2_MAT | CSR_DMW2_PLV0) -+ -+#define CSR_DMW3_INIT 0x0 -+ - /* Performance Counter registers */ - #define LOONGARCH_CSR_PERFCTRL0 0x200 /* 32 perf event 0 config */ - #define LOONGARCH_CSR_PERFCNTR0 0x201 /* 64 perf event 0 count value */ -@@ -1005,7 +1012,7 @@ - /* - * CSR_ECFG IM - */ --#define ECFG0_IM 0x00001fff -+#define ECFG0_IM 0x00005fff - #define ECFGB_SIP0 0 - #define ECFGF_SIP0 (_ULCAST_(1) << ECFGB_SIP0) - #define ECFGB_SIP1 1 -@@ -1048,6 +1055,7 @@ - #define IOCSRF_EIODECODE BIT_ULL(9) - #define IOCSRF_FLATMODE BIT_ULL(10) - #define IOCSRF_VM BIT_ULL(11) -+#define IOCSRF_AVEC BIT_ULL(15) - - #define LOONGARCH_IOCSR_VENDOR 0x10 - -@@ -1058,6 +1066,7 @@ - #define LOONGARCH_IOCSR_MISC_FUNC 0x420 - #define IOCSR_MISC_FUNC_TIMER_RESET BIT_ULL(21) - #define IOCSR_MISC_FUNC_EXT_IOI_EN BIT_ULL(48) -+#define IOCSR_MISC_FUNC_AVEC_EN BIT_ULL(51) - - #define LOONGARCH_IOCSR_CPUTEMP 0x428 - -@@ -1378,9 +1387,10 @@ __BUILD_CSR_OP(tlbidx) - #define INT_TI 11 /* Timer */ - #define INT_IPI 12 - #define INT_NMI 13 -+#define INT_AVEC 14 - - /* ExcCodes corresponding to interrupts */ --#define EXCCODE_INT_NUM (INT_NMI + 1) -+#define EXCCODE_INT_NUM (INT_AVEC + 1) - #define EXCCODE_INT_START 64 - #define EXCCODE_INT_END (EXCCODE_INT_START + EXCCODE_INT_NUM - 1) - -diff --git a/arch/loongarch/include/asm/mmu_context.h b/arch/loongarch/include/asm/mmu_context.h -index 9f97c34..304363b 100644 ---- a/arch/loongarch/include/asm/mmu_context.h -+++ b/arch/loongarch/include/asm/mmu_context.h -@@ -49,12 +49,12 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) - - /* Normal, classic get_new_mmu_context */ - static inline void --get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) -+get_new_mmu_context(struct mm_struct *mm, unsigned long cpu, bool *need_flush) - { - u64 asid = asid_cache(cpu); - - if (!((++asid) & cpu_asid_mask(&cpu_data[cpu]))) -- local_flush_tlb_user(); /* start new asid cycle */ -+ *need_flush = true; /* start new asid cycle */ - - cpu_context(cpu, mm) = asid_cache(cpu) = asid; - } -@@ -74,21 +74,34 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm) - return 0; - } - -+static inline void atomic_update_pgd_asid(unsigned long asid, unsigned long pgdl) -+{ -+ __asm__ __volatile__( -+ "csrwr %[pgdl_val], %[pgdl_reg] \n\t" -+ "csrwr %[asid_val], %[asid_reg] \n\t" -+ : [asid_val] "+r" (asid), [pgdl_val] "+r" (pgdl) -+ : [asid_reg] "i" (LOONGARCH_CSR_ASID), [pgdl_reg] "i" (LOONGARCH_CSR_PGDL) -+ : "memory" -+ ); -+} -+ - static inline void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk) - { -+ bool need_flush = false; - unsigned int cpu = smp_processor_id(); - - /* Check if our ASID is of an older version and thus invalid */ - if (!asid_valid(next, cpu)) -- get_new_mmu_context(next, cpu); -- -- write_csr_asid(cpu_asid(cpu, next)); -+ get_new_mmu_context(next, cpu, &need_flush); - - if (next != &init_mm) -- csr_write64((unsigned long)next->pgd, LOONGARCH_CSR_PGDL); -+ atomic_update_pgd_asid(cpu_asid(cpu, next), (unsigned long)next->pgd); - else -- csr_write64((unsigned long)invalid_pg_dir, LOONGARCH_CSR_PGDL); -+ atomic_update_pgd_asid(cpu_asid(cpu, next), (unsigned long)invalid_pg_dir); -+ -+ if (need_flush) -+ local_flush_tlb_user(); /* Flush tlb after update ASID */ - - /* - * Mark current->active_mm as not "active" anymore. -@@ -135,9 +148,15 @@ drop_mmu_context(struct mm_struct *mm, unsigned int cpu) - asid = read_csr_asid() & cpu_asid_mask(¤t_cpu_data); - - if (asid == cpu_asid(cpu, mm)) { -+ bool need_flush = false; -+ - if (!current->mm || (current->mm == mm)) { -- get_new_mmu_context(mm, cpu); -+ get_new_mmu_context(mm, cpu, &need_flush); -+ - write_csr_asid(cpu_asid(cpu, mm)); -+ if (need_flush) -+ local_flush_tlb_user(); /* Flush tlb after update ASID */ -+ - goto out; - } - } -diff --git a/arch/loongarch/include/asm/paravirt.h b/arch/loongarch/include/asm/paravirt.h -index dddec49..6375467 100644 ---- a/arch/loongarch/include/asm/paravirt.h -+++ b/arch/loongarch/include/asm/paravirt.h -@@ -31,5 +31,11 @@ static inline int pv_time_init(void) - { - return 0; - } -+ -+static inline int pv_spinlock_init(void) -+{ -+ return 0; -+} -+ - #endif // CONFIG_PARAVIRT - #endif -diff --git a/arch/loongarch/include/asm/pgalloc.h b/arch/loongarch/include/asm/pgalloc.h -index 79470f0..c9f9895 100644 ---- a/arch/loongarch/include/asm/pgalloc.h -+++ b/arch/loongarch/include/asm/pgalloc.h -@@ -10,6 +10,7 @@ - - #define __HAVE_ARCH_PMD_ALLOC_ONE - #define __HAVE_ARCH_PUD_ALLOC_ONE -+#define __HAVE_ARCH_PTE_ALLOC_ONE_KERNEL - #include <asm-generic/pgalloc.h> - - static inline void pmd_populate_kernel(struct mm_struct *mm, -@@ -44,6 +45,16 @@ extern void pagetable_init(void); - - extern pgd_t *pgd_alloc(struct mm_struct *mm); - -+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm) -+{ -+ pte_t *pte = __pte_alloc_one_kernel(mm); -+ -+ if (pte) -+ kernel_pte_init(pte); -+ -+ return pte; -+} -+ - #define __pte_free_tlb(tlb, pte, address) \ - do { \ - pagetable_pte_dtor(page_ptdesc(pte)); \ -diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h -index d4d5ba3..b93f372 100644 ---- a/arch/loongarch/include/asm/pgtable.h -+++ b/arch/loongarch/include/asm/pgtable.h -@@ -106,6 +106,9 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; - #define KFENCE_AREA_START (VMEMMAP_END + 1) - #define KFENCE_AREA_END (KFENCE_AREA_START + KFENCE_AREA_SIZE - 1) - -+#define ptep_get(ptep) READ_ONCE(*(ptep)) -+#define pmdp_get(pmdp) READ_ONCE(*(pmdp)) -+ - #define pte_ERROR(e) \ - pr_err("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e)) - #ifndef __PAGETABLE_PMD_FOLDED -@@ -147,11 +150,6 @@ static inline int p4d_present(p4d_t p4d) - return p4d_val(p4d) != (unsigned long)invalid_pud_table; - } - --static inline void p4d_clear(p4d_t *p4dp) --{ -- p4d_val(*p4dp) = (unsigned long)invalid_pud_table; --} -- - static inline pud_t *p4d_pgtable(p4d_t p4d) - { - return (pud_t *)p4d_val(p4d); -@@ -159,7 +157,12 @@ static inline pud_t *p4d_pgtable(p4d_t p4d) - - static inline void set_p4d(p4d_t *p4d, p4d_t p4dval) - { -- *p4d = p4dval; -+ WRITE_ONCE(*p4d, p4dval); -+} -+ -+static inline void p4d_clear(p4d_t *p4dp) -+{ -+ set_p4d(p4dp, __p4d((unsigned long)invalid_pud_table)); - } - - #define p4d_phys(p4d) PHYSADDR(p4d_val(p4d)) -@@ -193,17 +196,20 @@ static inline int pud_present(pud_t pud) - return pud_val(pud) != (unsigned long)invalid_pmd_table; - } - --static inline void pud_clear(pud_t *pudp) -+static inline pmd_t *pud_pgtable(pud_t pud) - { -- pud_val(*pudp) = ((unsigned long)invalid_pmd_table); -+ return (pmd_t *)pud_val(pud); - } - --static inline pmd_t *pud_pgtable(pud_t pud) -+static inline void set_pud(pud_t *pud, pud_t pudval) - { -- return (pmd_t *)pud_val(pud); -+ WRITE_ONCE(*pud, pudval); - } - --#define set_pud(pudptr, pudval) do { *(pudptr) = (pudval); } while (0) -+static inline void pud_clear(pud_t *pudp) -+{ -+ set_pud(pudp, __pud((unsigned long)invalid_pmd_table)); -+} - - #define pud_phys(pud) PHYSADDR(pud_val(pud)) - #define pud_page(pud) (pfn_to_page(pud_phys(pud) >> PAGE_SHIFT)) -@@ -231,12 +237,15 @@ static inline int pmd_present(pmd_t pmd) - return pmd_val(pmd) != (unsigned long)invalid_pte_table; - } - --static inline void pmd_clear(pmd_t *pmdp) -+static inline void set_pmd(pmd_t *pmd, pmd_t pmdval) - { -- pmd_val(*pmdp) = ((unsigned long)invalid_pte_table); -+ WRITE_ONCE(*pmd, pmdval); - } - --#define set_pmd(pmdptr, pmdval) do { *(pmdptr) = (pmdval); } while (0) -+static inline void pmd_clear(pmd_t *pmdp) -+{ -+ set_pmd(pmdp, __pmd((unsigned long)invalid_pte_table)); -+} - - #define pmd_phys(pmd) PHYSADDR(pmd_val(pmd)) - -@@ -260,6 +269,7 @@ extern void set_pmd_at(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp, pm - extern void pgd_init(void *addr); - extern void pud_init(void *addr); - extern void pmd_init(void *addr); -+extern void kernel_pte_init(void *addr); - - /* - * Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that -@@ -314,46 +324,19 @@ extern void paging_init(void); - - static inline void set_pte(pte_t *ptep, pte_t pteval) - { -- *ptep = pteval; -- if (pte_val(pteval) & _PAGE_GLOBAL) { -- pte_t *buddy = ptep_buddy(ptep); -- /* -- * Make sure the buddy is global too (if it's !none, -- * it better already be global) -- */ -+ WRITE_ONCE(*ptep, pteval); -+ - #ifdef CONFIG_SMP -- /* -- * For SMP, multiple CPUs can race, so we need to do -- * this atomically. -- */ -- unsigned long page_global = _PAGE_GLOBAL; -- unsigned long tmp; -- -- __asm__ __volatile__ ( -- "1:" __LL "%[tmp], %[buddy] \n" -- " bnez %[tmp], 2f \n" -- " or %[tmp], %[tmp], %[global] \n" -- __SC "%[tmp], %[buddy] \n" -- " beqz %[tmp], 1b \n" -- " nop \n" -- "2: \n" -- __WEAK_LLSC_MB -- : [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp) -- : [global] "r" (page_global)); --#else /* !CONFIG_SMP */ -- if (pte_none(*buddy)) -- pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL; --#endif /* CONFIG_SMP */ -- } -+ if (pte_val(pteval) & _PAGE_GLOBAL) -+ DBAR(0b11000); /* o_wrw = 0b11000 */ -+#endif - } - - static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) - { -- /* Preserve global status for the pair */ -- if (pte_val(*ptep_buddy(ptep)) & _PAGE_GLOBAL) -- set_pte(ptep, __pte(_PAGE_GLOBAL)); -- else -- set_pte(ptep, __pte(0)); -+ pte_t pte = ptep_get(ptep); -+ pte_val(pte) &= _PAGE_GLOBAL; -+ set_pte(ptep, pte); - } - - #define PGD_T_LOG2 (__builtin_ffs(sizeof(pgd_t)) - 1) -@@ -588,7 +571,7 @@ static inline pmd_t pmd_mkinvalid(pmd_t pmd) - static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, - unsigned long address, pmd_t *pmdp) - { -- pmd_t old = *pmdp; -+ pmd_t old = pmdp_get(pmdp); - - pmd_clear(pmdp); - -diff --git a/arch/loongarch/include/asm/qspinlock.h b/arch/loongarch/include/asm/qspinlock.h -new file mode 100644 -index 0000000..e76d3aa ---- /dev/null -+++ b/arch/loongarch/include/asm/qspinlock.h -@@ -0,0 +1,41 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _ASM_LOONGARCH_QSPINLOCK_H -+#define _ASM_LOONGARCH_QSPINLOCK_H -+ -+#include <linux/jump_label.h> -+ -+#ifdef CONFIG_PARAVIRT -+ -+DECLARE_STATIC_KEY_FALSE(virt_spin_lock_key); -+ -+#define virt_spin_lock virt_spin_lock -+ -+static inline bool virt_spin_lock(struct qspinlock *lock) -+{ -+ int val; -+ -+ if (!static_branch_unlikely(&virt_spin_lock_key)) -+ return false; -+ -+ /* -+ * On hypervisors without PARAVIRT_SPINLOCKS support we fall -+ * back to a Test-and-Set spinlock, because fair locks have -+ * horrible lock 'holder' preemption issues. -+ */ -+ -+__retry: -+ val = atomic_read(&lock->val); -+ -+ if (val || !atomic_try_cmpxchg(&lock->val, &val, _Q_LOCKED_VAL)) { -+ cpu_relax(); -+ goto __retry; -+ } -+ -+ return true; -+} -+ -+#endif /* CONFIG_PARAVIRT */ -+ -+#include <asm-generic/qspinlock.h> -+ -+#endif // _ASM_LOONGARCH_QSPINLOCK_H -diff --git a/arch/loongarch/include/asm/se.h b/arch/loongarch/include/asm/se.h -new file mode 100644 -index 0000000..d0f9d43 ---- /dev/null -+++ b/arch/loongarch/include/asm/se.h -@@ -0,0 +1,147 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2012 IBM Corporation -+ * -+ * Copyright 2023 Loongson Technology, Inc. -+ * Yinggang Gu <guyinggang@loongson.cn> -+ * -+ * Device driver for Loongson SE module. -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License as -+ * published by the Free Software Foundation, version 2 of the -+ * License. -+ * -+ */ -+#ifndef __LOONGSON_SE_H__ -+#define __LOONGSON_SE_H__ -+ -+#define SE_MAILBOX_S 0x0 -+#define SE_MAILBOX_L 0x20 -+#define SE_S2LINT_STAT 0x88 -+#define SE_S2LINT_EN 0x8c -+#define SE_S2LINT_SET 0x90 -+#define SE_S2LINT_CL 0x94 -+#define SE_L2SINT_STAT 0x98 -+#define SE_L2SINT_EN 0x9c -+#define SE_L2SINT_SET 0xa0 -+#define SE_L2SINT_CL 0xa4 -+ -+/* INT bit definition */ -+#define SE_INT_SETUP BIT(0) -+#define SE_INT_SM2 BIT(0) -+#define SE_INT_SM3 BIT(0) -+#define SE_INT_SM4 BIT(0) -+#define SE_INT_RNG BIT(0) -+#define SE_INT_TPM BIT(5) -+#define SE_INT_ALL 0xffffffff -+ -+#define SE_CMD_START 0x0 -+#define SE_CMD_STOP 0x1 -+#define SE_CMD_GETVER 0x2 -+#define SE_CMD_SETBUF 0x3 -+#define SE_CMD_SETMSG 0x4 -+ -+#define SE_CMD_RNG 0x100 -+ -+#define SE_CMD_SM2_SIGN 0x200 -+#define SE_CMD_SM2_VSIGN 0x201 -+ -+#define SE_CMD_SM3_DIGEST 0x300 -+#define SE_CMD_SM3_UPDATE 0x301 -+#define SE_CMD_SM3_FINISH 0x302 -+ -+#define SE_CMD_SM4_ECB_ENCRY 0x400 -+#define SE_CMD_SM4_ECB_DECRY 0x401 -+#define SE_CMD_SM4_CBC_ENCRY 0x402 -+#define SE_CMD_SM4_CBC_DECRY 0x403 -+#define SE_CMD_SM4_CTR 0x404 -+ -+#define SE_CMD_TPM 0x500 -+#define SE_CMD_ZUC_INIT_READ 0x600 -+#define SE_CMD_ZUC_READ 0x601 -+ -+#define SE_CMD_SDF 0x700 -+ -+#define SE_CH_MAX 32 -+ -+#define SE_CH_RNG 1 -+#define SE_CH_SM2 2 -+#define SE_CH_SM3 3 -+#define SE_CH_SM4 4 -+#define SE_CH_TPM 5 -+#define SE_CH_ZUC 6 -+#define SE_CH_SDF 7 -+ -+struct se_msg { -+ u32 cmd; -+ u32 data_off; -+ u32 data_len; -+ u32 info[5]; -+}; -+ -+struct se_cmd { -+ u32 cmd; -+ u32 info[7]; -+}; -+ -+struct se_res { -+ u32 cmd; -+ u32 cmd_ret; -+ u32 info[6]; -+}; -+ -+struct se_mailbox_data { -+ u32 int_bit; -+ union { -+ u32 mailbox[8]; -+ struct se_cmd gcmd; -+ struct se_res res; -+ } u; -+}; -+ -+struct lsse_ch { -+ u32 id; -+ u32 int_bit; -+ struct loongson_se *se; -+ void *priv; -+ spinlock_t ch_lock; -+ void *smsg; -+ void *rmsg; -+ int msg_size; -+ void *data_buffer; -+ dma_addr_t data_addr; -+ int data_size; -+ -+ void (*complete)(struct lsse_ch *se_ch); -+}; -+ -+struct loongson_se { -+ struct device *dev; -+ void __iomem *base; -+ u32 version; -+ u32 ch_status; -+ spinlock_t cmd_lock; -+ spinlock_t dev_lock; -+ -+ /* Interaction memory */ -+ void *mem_base; -+ dma_addr_t mem_addr; -+ unsigned long *mem_map; -+ int mem_map_size; -+ void *smsg; -+ void *rmsg; -+ -+ /* Synchronous CMD */ -+ struct completion cmd_completion; -+ -+ /* Virtual Channel */ -+ struct lsse_ch chs[SE_CH_MAX]; -+}; -+ -+struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv, -+ void (*complete)(struct lsse_ch *se_ch)); -+void se_deinit_ch(struct lsse_ch *ch); -+int se_send_ch_requeset(struct lsse_ch *ch); -+ -+#endif -diff --git a/arch/loongarch/include/asm/setup.h b/arch/loongarch/include/asm/setup.h -index ee52fb1..eefb30c3 100644 ---- a/arch/loongarch/include/asm/setup.h -+++ b/arch/loongarch/include/asm/setup.h -@@ -12,6 +12,7 @@ - - #define VECSIZE 0x200 - -+extern bool disable_pci_irq_limit; - extern unsigned long eentry; - extern unsigned long tlbrentry; - extern char init_command_line[COMMAND_LINE_SIZE]; -diff --git a/arch/loongarch/include/asm/shmparam.h b/arch/loongarch/include/asm/shmparam.h -new file mode 100644 -index 0000000..8af1e70 ---- /dev/null -+++ b/arch/loongarch/include/asm/shmparam.h -@@ -0,0 +1,11 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2020-2022 Loongson Technology Corporation Limited -+ */ -+#ifndef _ASM_SHMPARAM_H -+#define _ASM_SHMPARAM_H -+ -+#define __ARCH_FORCE_SHMLBA 1 -+#include <asm-generic/shmparam.h> -+ -+#endif /* _ASM_SHMPARAM_H */ -diff --git a/arch/loongarch/include/asm/smp.h b/arch/loongarch/include/asm/smp.h -index 75d3052..cc23290 100644 ---- a/arch/loongarch/include/asm/smp.h -+++ b/arch/loongarch/include/asm/smp.h -@@ -67,9 +67,11 @@ extern int __cpu_logical_map[NR_CPUS]; - #define ACTION_BOOT_CPU 0 - #define ACTION_RESCHEDULE 1 - #define ACTION_CALL_FUNCTION 2 -+#define ACTION_CLEAR_VECTOR 3 - #define SMP_BOOT_CPU BIT(ACTION_BOOT_CPU) - #define SMP_RESCHEDULE BIT(ACTION_RESCHEDULE) - #define SMP_CALL_FUNCTION BIT(ACTION_CALL_FUNCTION) -+#define SMP_CLEAR_VECTOR BIT(ACTION_CLEAR_VECTOR) - - struct secondary_data { - unsigned long stack; -@@ -100,4 +102,7 @@ static inline void __cpu_die(unsigned int cpu) - } - #endif - -+int topo_add_cpu(int physid); -+int topo_get_cpu(int physid); -+ - #endif /* __ASM_SMP_H */ -diff --git a/arch/loongarch/include/asm/stackframe.h b/arch/loongarch/include/asm/stackframe.h -index d9eafd3..6673683 100644 ---- a/arch/loongarch/include/asm/stackframe.h -+++ b/arch/loongarch/include/asm/stackframe.h -@@ -38,6 +38,17 @@ - cfi_restore \reg \offset \docfi - .endm - -+ .macro SETUP_DMWINS temp -+ li.d \temp, CSR_DMW0_INIT # WUC, PLV0, 0x8000 xxxx xxxx xxxx -+ csrwr \temp, LOONGARCH_CSR_DMWIN0 -+ li.d \temp, CSR_DMW1_INIT # CAC, PLV0, 0x9000 xxxx xxxx xxxx -+ csrwr \temp, LOONGARCH_CSR_DMWIN1 -+ li.d \temp, CSR_DMW2_INIT # WUC, PLV0, 0xa000 xxxx xxxx xxxx -+ csrwr \temp, LOONGARCH_CSR_DMWIN2 -+ li.d \temp, CSR_DMW3_INIT # 0x0, unused -+ csrwr \temp, LOONGARCH_CSR_DMWIN3 -+ .endm -+ - /* Jump to the runtime virtual address. */ - .macro JUMP_VIRT_ADDR temp1 temp2 - li.d \temp1, CACHE_BASE -diff --git a/arch/loongarch/include/uapi/asm/bitsperlong.h b/arch/loongarch/include/uapi/asm/bitsperlong.h -new file mode 100644 -index 0000000..00b4ba1 ---- /dev/null -+++ b/arch/loongarch/include/uapi/asm/bitsperlong.h -@@ -0,0 +1,9 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+#ifndef __ASM_LOONGARCH_BITSPERLONG_H -+#define __ASM_LOONGARCH_BITSPERLONG_H -+ -+#define __BITS_PER_LONG (__SIZEOF_LONG__ * 8) -+ -+#include <asm-generic/bitsperlong.h> -+ -+#endif /* __ASM_LOONGARCH_BITSPERLONG_H */ -diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h -index 71baa77..d65a299 100644 ---- a/arch/loongarch/include/uapi/asm/kvm.h -+++ b/arch/loongarch/include/uapi/asm/kvm.h -@@ -18,6 +18,7 @@ - - #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 - #define KVM_DIRTY_LOG_PAGE_OFFSET 64 -+#define __KVM_HAVE_IRQ_LINE - - #define KVM_GUESTDBG_USE_SW_BP 0x00010000 - -@@ -66,6 +67,7 @@ struct kvm_fpu { - #define KVM_REG_LOONGARCH_KVM (KVM_REG_LOONGARCH | 0x20000ULL) - #define KVM_REG_LOONGARCH_FPSIMD (KVM_REG_LOONGARCH | 0x30000ULL) - #define KVM_REG_LOONGARCH_CPUCFG (KVM_REG_LOONGARCH | 0x40000ULL) -+#define KVM_REG_LOONGARCH_LBT (KVM_REG_LOONGARCH | 0x50000ULL) - #define KVM_REG_LOONGARCH_MASK (KVM_REG_LOONGARCH | 0x70000ULL) - #define KVM_CSR_IDX_MASK 0x7fff - #define KVM_CPUCFG_IDX_MASK 0x7fff -@@ -79,11 +81,30 @@ struct kvm_fpu { - /* Debugging: Special instruction for software breakpoint */ - #define KVM_REG_LOONGARCH_DEBUG_INST (KVM_REG_LOONGARCH_KVM | KVM_REG_SIZE_U64 | 3) - -+/* LBT registers */ -+#define KVM_REG_LOONGARCH_LBT_SCR0 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 1) -+#define KVM_REG_LOONGARCH_LBT_SCR1 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 2) -+#define KVM_REG_LOONGARCH_LBT_SCR2 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 3) -+#define KVM_REG_LOONGARCH_LBT_SCR3 (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 4) -+#define KVM_REG_LOONGARCH_LBT_EFLAGS (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 5) -+#define KVM_REG_LOONGARCH_LBT_FTOP (KVM_REG_LOONGARCH_LBT | KVM_REG_SIZE_U64 | 6) -+ - #define LOONGARCH_REG_SHIFT 3 - #define LOONGARCH_REG_64(TYPE, REG) (TYPE | KVM_REG_SIZE_U64 | (REG << LOONGARCH_REG_SHIFT)) - #define KVM_IOC_CSRID(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CSR, REG) - #define KVM_IOC_CPUCFG(REG) LOONGARCH_REG_64(KVM_REG_LOONGARCH_CPUCFG, REG) - -+/* Device Control API on vm fd */ -+#define KVM_LOONGARCH_VM_FEAT_CTRL 0 -+#define KVM_LOONGARCH_VM_FEAT_LSX 0 -+#define KVM_LOONGARCH_VM_FEAT_LASX 1 -+#define KVM_LOONGARCH_VM_FEAT_X86BT 2 -+#define KVM_LOONGARCH_VM_FEAT_ARMBT 3 -+#define KVM_LOONGARCH_VM_FEAT_MIPSBT 4 -+#define KVM_LOONGARCH_VM_FEAT_PMU 5 -+#define KVM_LOONGARCH_VM_FEAT_PV_IPI 6 -+#define KVM_LOONGARCH_VM_FEAT_PV_STEALTIME 7 -+ - /* Device Control API on vcpu fd */ - #define KVM_LOONGARCH_VCPU_CPUCFG 0 - #define KVM_LOONGARCH_VCPU_PVTIME_CTRL 1 -@@ -114,4 +135,15 @@ struct kvm_iocsr_entry { - #define KVM_IRQCHIP_NUM_PINS 64 - #define KVM_MAX_CORES 256 - -+#define KVM_LOONGARCH_VM_HAVE_IRQCHIP 0x40000001 -+ -+#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 0x40000002 -+ -+#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000003 -+ -+#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000004 -+#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0 -+ -+#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS 0x40000005 -+ - #endif /* __UAPI_ASM_LOONGARCH_KVM_H */ -diff --git a/arch/loongarch/include/uapi/asm/kvm_para.h b/arch/loongarch/include/uapi/asm/kvm_para.h -new file mode 100644 -index 0000000..b0604aa ---- /dev/null -+++ b/arch/loongarch/include/uapi/asm/kvm_para.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+#ifndef _UAPI_ASM_KVM_PARA_H -+#define _UAPI_ASM_KVM_PARA_H -+ -+#include <linux/types.h> -+ -+/* -+ * CPUCFG index area: 0x40000000 -- 0x400000ff -+ * SW emulation for KVM hypervirsor -+ */ -+#define CPUCFG_KVM_BASE 0x40000000 -+#define CPUCFG_KVM_SIZE 0x100 -+#define CPUCFG_KVM_SIG (CPUCFG_KVM_BASE + 0) -+#define KVM_SIGNATURE "KVM\0" -+#define CPUCFG_KVM_FEATURE (CPUCFG_KVM_BASE + 4) -+#define KVM_FEATURE_IPI 1 -+#define KVM_FEATURE_STEAL_TIME 2 -+/* BIT 24 - 31 are features configurable by user space vmm */ -+#define KVM_FEATURE_VIRT_EXTIOI 24 -+ -+#endif /* _UAPI_ASM_KVM_PARA_H */ -diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c -index 2c5066a..f5b1396 100644 ---- a/arch/loongarch/kernel/acpi.c -+++ b/arch/loongarch/kernel/acpi.c -@@ -71,10 +71,10 @@ int set_processor_mask(u32 id, u32 flags) - return -ENODEV; - - } -- if (cpuid == loongson_sysconf.boot_cpu_id) -- cpu = 0; -- else -- cpu = cpumask_next_zero(-1, cpu_present_mask); -+ -+ cpu = topo_add_cpu(cpuid); -+ if (cpu < 0) -+ return -EEXIST; - - if (flags & ACPI_MADT_ENABLED) { - num_processors++; -@@ -197,8 +197,6 @@ void __init acpi_boot_table_init(void) - goto fdt_earlycon; - } - -- loongson_sysconf.boot_cpu_id = read_csr_cpuid(); -- - /* - * Process the Multiple APIC Description Table (MADT), if present - */ -@@ -248,7 +246,7 @@ void __init numa_set_distance(int from, int to, int distance) - void __init - acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) - { -- int pxm, node; -+ int pxm, node, cpu; - - if (srat_disabled()) - return; -@@ -277,6 +275,11 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) - return; - } - -+ cpu = topo_get_cpu(pa->apic_id); -+ /* Check whether apic_id exists in MADT table */ -+ if (cpu < 0) -+ return; -+ - early_numa_add_cpu(pa->apic_id, node); - - set_cpuid_to_node(pa->apic_id, node); -@@ -315,12 +318,17 @@ int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 acpi_id, int *pcpu - { - int cpu; - -- cpu = set_processor_mask(physid, ACPI_MADT_ENABLED); -+ cpu = topo_get_cpu(physid); -+ /* Check whether apic_id exists in MADT table */ - if (cpu < 0) { - pr_info(PREFIX "Unable to map lapic to logical cpu number\n"); - return cpu; - } - -+ num_processors++; -+ set_cpu_present(cpu, true); -+ __cpu_number_map[physid] = cpu; -+ __cpu_logical_map[cpu] = physid; - acpi_map_cpu2node(handle, cpu, physid); - - *pcpu = cpu; -diff --git a/arch/loongarch/kernel/cpu-probe.c b/arch/loongarch/kernel/cpu-probe.c -index 5532081..14f0449 100644 ---- a/arch/loongarch/kernel/cpu-probe.c -+++ b/arch/loongarch/kernel/cpu-probe.c -@@ -106,7 +106,6 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c) - elf_hwcap |= HWCAP_LOONGARCH_CRC32; - } - -- - config = read_cpucfg(LOONGARCH_CPUCFG2); - if (config & CPUCFG2_LAM) { - c->options |= LOONGARCH_CPU_LAM; -@@ -174,6 +173,8 @@ static void cpu_probe_common(struct cpuinfo_loongarch *c) - c->options |= LOONGARCH_CPU_FLATMODE; - if (config & IOCSRF_EIODECODE) - c->options |= LOONGARCH_CPU_EIODECODE; -+ if (config & IOCSRF_AVEC) -+ c->options |= LOONGARCH_CPU_AVECINT; - if (config & IOCSRF_VM) - c->options |= LOONGARCH_CPU_HYPERVISOR; - -diff --git a/arch/loongarch/kernel/fpu.S b/arch/loongarch/kernel/fpu.S -index 69a85f2..6ab6401 100644 ---- a/arch/loongarch/kernel/fpu.S -+++ b/arch/loongarch/kernel/fpu.S -@@ -530,6 +530,10 @@ SYM_FUNC_END(_restore_lasx_context) - - #ifdef CONFIG_CPU_HAS_LBT - STACK_FRAME_NON_STANDARD _restore_fp -+#ifdef CONFIG_CPU_HAS_LSX - STACK_FRAME_NON_STANDARD _restore_lsx -+#endif -+#ifdef CONFIG_CPU_HAS_LASX - STACK_FRAME_NON_STANDARD _restore_lasx - #endif -+#endif -diff --git a/arch/loongarch/kernel/head.S b/arch/loongarch/kernel/head.S -index 4677ea8..5305f5e 100644 ---- a/arch/loongarch/kernel/head.S -+++ b/arch/loongarch/kernel/head.S -@@ -44,11 +44,7 @@ SYM_DATA(kernel_fsize, .long _kernel_fsize); - SYM_CODE_START(kernel_entry) # kernel entry point - - /* Config direct window and set PG */ -- li.d t0, CSR_DMW0_INIT # UC, PLV0, 0x8000 xxxx xxxx xxxx -- csrwr t0, LOONGARCH_CSR_DMWIN0 -- li.d t0, CSR_DMW1_INIT # CA, PLV0, 0x9000 xxxx xxxx xxxx -- csrwr t0, LOONGARCH_CSR_DMWIN1 -- -+ SETUP_DMWINS t0 - JUMP_VIRT_ADDR t0, t1 - - /* Enable PG */ -@@ -124,11 +120,9 @@ SYM_CODE_END(kernel_entry) - * function after setting up the stack and tp registers. - */ - SYM_CODE_START(smpboot_entry) -- li.d t0, CSR_DMW0_INIT # UC, PLV0 -- csrwr t0, LOONGARCH_CSR_DMWIN0 -- li.d t0, CSR_DMW1_INIT # CA, PLV0 -- csrwr t0, LOONGARCH_CSR_DMWIN1 -- -+ -+ /* Config direct window and set PG */ -+ SETUP_DMWINS t0 - JUMP_VIRT_ADDR t0, t1 - - #ifdef CONFIG_PAGE_SIZE_4KB -diff --git a/arch/loongarch/kernel/irq.c b/arch/loongarch/kernel/irq.c -index a8aaaae..657e1a7 100644 ---- a/arch/loongarch/kernel/irq.c -+++ b/arch/loongarch/kernel/irq.c -@@ -122,6 +122,19 @@ void fixup_irqs(void) - } - #endif - -+int __init arch_probe_nr_irqs(void) -+{ -+ int nr_io_pics = bitmap_weight(loongson_sysconf.cores_io_master, NR_CPUS); -+ -+ if (!cpu_has_avecint) -+ nr_irqs = (64 + NR_VECTORS * nr_io_pics); -+ else -+ nr_irqs = (64 + NR_VECTORS * (nr_cpu_ids + nr_io_pics)); -+ -+ return NR_IRQS_LEGACY; -+} -+ -+ - void __init init_IRQ(void) - { - int i, ret; -@@ -150,9 +163,6 @@ void __init init_IRQ(void) - smp_ops.init_ipi(); - #endif - -- for (i = 0; i < NR_IRQS; i++) -- irq_set_noprobe(i); -- - for_each_possible_cpu(i) { - page = alloc_pages_node(cpu_to_node(i), GFP_KERNEL, order); - -diff --git a/arch/loongarch/kernel/legacy_boot.h b/arch/loongarch/kernel/legacy_boot.h -index 9a127ae..65a3d14 100644 ---- a/arch/loongarch/kernel/legacy_boot.h -+++ b/arch/loongarch/kernel/legacy_boot.h -@@ -4,6 +4,7 @@ - #include <linux/acpi.h> - #include <linux/screen_info.h> - #include <linux/of_address.h> -+#include <asm/loongson.h> - #define ADDRESS_TYPE_SYSRAM 1 - #define ADDRESS_TYPE_RESERVED 2 - #define ADDRESS_TYPE_ACPI 3 -@@ -88,4 +89,14 @@ extern int __init - pch_msi_parse_madt(union acpi_subtable_headers *header, - const unsigned long end); - extern struct irq_domain *get_pchpic_irq_domain(void); -+extern __init void fw_init_cmdline(unsigned long argc, unsigned long cmdp); -+ -+extern int liointc_acpi_init(struct irq_domain *parent, -+ struct acpi_madt_lio_pic *acpi_liointc); -+extern int eiointc_acpi_init(struct irq_domain *parent, -+ struct acpi_madt_eio_pic *acpi_eiointc); -+extern int htvec_acpi_init(struct irq_domain *parent, -+ struct acpi_madt_ht_pic *acpi_htvec); -+extern int pch_lpc_acpi_init(struct irq_domain *parent, -+ struct acpi_madt_lpc_pic *acpi_pchlpc); - #endif -diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c -index 9abe8b7..38bbd62 100644 ---- a/arch/loongarch/kernel/paravirt.c -+++ b/arch/loongarch/kernel/paravirt.c -@@ -12,6 +12,7 @@ static int has_steal_clock; - struct static_key paravirt_steal_enabled; - struct static_key paravirt_steal_rq_enabled; - static DEFINE_PER_CPU(struct kvm_steal_time, steal_time) __aligned(64); -+DEFINE_STATIC_KEY_FALSE(virt_spin_lock_key); - - static u64 native_steal_clock(int cpu) - { -@@ -165,7 +166,7 @@ int __init pv_ipi_init(void) - - if (!cpu_has_hypervisor) - return 0; -- if (!kvm_para_available()) -+ if (!(feature & BIT(KVM_FEATURE_IPI))) - return 0; - - feature = read_cpucfg(CPUCFG_KVM_FEATURE); -@@ -173,9 +174,9 @@ int __init pv_ipi_init(void) - return 0; - - #ifdef CONFIG_SMP -- mp_ops.init_ipi = pv_init_ipi; -- mp_ops.send_ipi_single = pv_send_ipi_single; -- mp_ops.send_ipi_mask = pv_send_ipi_mask; -+ smp_ops.init_ipi = pv_init_ipi; -+ smp_ops.send_ipi_single = pv_send_ipi_single; -+ smp_ops.send_ipi_mask = pv_send_ipi_mask; - #endif - - return 0; -@@ -200,7 +201,7 @@ static int pv_enable_steal_time(void) - } - - addr |= KVM_STEAL_PHYS_VALID; -- kvm_hypercall2(KVM_HCALL_FUNC_NOTIFY, KVM_FEATURE_STEAL_TIME, addr); -+ kvm_hypercall2(KVM_HCALL_FUNC_NOTIFY, BIT(KVM_FEATURE_STEAL_TIME), addr); - - return 0; - } -@@ -208,7 +209,7 @@ static int pv_enable_steal_time(void) - static void pv_disable_steal_time(void) - { - if (has_steal_clock) -- kvm_hypercall2(KVM_HCALL_FUNC_NOTIFY, KVM_FEATURE_STEAL_TIME, 0); -+ kvm_hypercall2(KVM_HCALL_FUNC_NOTIFY, BIT(KVM_FEATURE_STEAL_TIME), 0); - } - - #ifdef CONFIG_SMP -@@ -260,7 +261,7 @@ int __init pv_time_init(void) - return 0; - - feature = read_cpucfg(CPUCFG_KVM_FEATURE); -- if (!(feature & KVM_FEATURE_STEAL_TIME)) -+ if (!(feature & BIT(KVM_FEATURE_STEAL_TIME))) - return 0; - - has_steal_clock = 1; -@@ -294,3 +295,13 @@ int __init pv_time_init(void) - - return 0; - } -+ -+int __init pv_spinlock_init(void) -+{ -+ if (!cpu_has_hypervisor) -+ return 0; -+ -+ static_branch_enable(&virt_spin_lock_key); -+ -+ return 0; -+} -diff --git a/arch/loongarch/kernel/relocate.c b/arch/loongarch/kernel/relocate.c -index 1acfa70..14e5bb8 100644 ---- a/arch/loongarch/kernel/relocate.c -+++ b/arch/loongarch/kernel/relocate.c -@@ -13,8 +13,10 @@ - #include <asm/bootinfo.h> - #include <asm/early_ioremap.h> - #include <asm/inst.h> -+#include <asm/io.h> - #include <asm/sections.h> - #include <asm/setup.h> -+#include "legacy_boot.h" - - #define RELOCATED(x) ((void *)((long)x + reloc_offset)) - #define RELOCATED_KASLR(x) ((void *)((long)x + random_offset)) -@@ -170,9 +172,12 @@ unsigned long __init relocate_kernel(void) - unsigned long kernel_length; - unsigned long random_offset = 0; - void *location_new = _text; /* Default to original kernel start */ -- char *cmdline = early_ioremap(fw_arg1, COMMAND_LINE_SIZE); /* Boot command line is passed in fw_arg1 */ -+ char *cmdline = early_memremap_ro(fw_arg1, COMMAND_LINE_SIZE); /* Boot command line is passed in fw_arg1 */ - -- strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE); -+ if (fw_arg0 < 2) -+ strscpy(boot_command_line, cmdline, COMMAND_LINE_SIZE); -+ else -+ fw_init_cmdline(fw_arg0, TO_CACHE(fw_arg1)); /* OLD BPI parameters */ - - #ifdef CONFIG_RANDOMIZE_BASE - location_new = determine_relocation_address(); -@@ -182,6 +187,7 @@ unsigned long __init relocate_kernel(void) - random_offset = (unsigned long)location_new - (unsigned long)(_text); - #endif - reloc_offset = (unsigned long)_text - VMLINUX_LOAD_ADDRESS; -+ early_memunmap(cmdline, COMMAND_LINE_SIZE); - - if (random_offset) { - kernel_length = (long)(_end) - (long)(_text); -diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c -index 0c3bfd0..ce5a982 100644 ---- a/arch/loongarch/kernel/setup.c -+++ b/arch/loongarch/kernel/setup.c -@@ -57,6 +57,7 @@ - #define SMBIOS_FREQHIGH_OFFSET 0x17 - #define SMBIOS_FREQLOW_MASK 0xFF - #define SMBIOS_CORE_PACKAGE_OFFSET 0x23 -+#define SMBIOS_THREAD_PACKAGE_OFFSET 0x25 - #define LOONGSON_EFI_ENABLE (1 << 3) - - #ifdef CONFIG_EFI -@@ -71,6 +72,8 @@ EXPORT_SYMBOL(cpu_data); - - struct loongson_board_info b_info; - static const char dmi_empty_string[] = " "; -+static int possible_cpus; -+static bool bsp_added; - - /* - * Setup information -@@ -131,7 +134,7 @@ static void __init parse_cpu_table(const struct dmi_header *dm) - cpu_clock_freq = freq_temp * 1000000; - - loongson_sysconf.cpuname = (void *)dmi_string_parse(dm, dmi_data[16]); -- loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_CORE_PACKAGE_OFFSET); -+ loongson_sysconf.cores_per_package = *(dmi_data + SMBIOS_THREAD_PACKAGE_OFFSET); - - pr_info("CpuClock = %llu\n", cpu_clock_freq); - } -@@ -185,12 +188,14 @@ bool wc_enabled = false; - - EXPORT_SYMBOL(wc_enabled); - -+static int wc_arg = -1; -+ - static int __init setup_writecombine(char *p) - { - if (!strcmp(p, "on")) -- wc_enabled = true; -+ wc_arg = true; - else if (!strcmp(p, "off")) -- wc_enabled = false; -+ wc_arg = false; - else - pr_warn("Unknown writecombine setting \"%s\".\n", p); - -@@ -359,10 +364,75 @@ static void __init bootcmdline_init(char **cmdline_p) - *cmdline_p = boot_command_line; - } - -+int topo_get_cpu(int physid) -+{ -+ int i; -+ -+ for (i = 0; i < possible_cpus; i++) -+ if (cpu_logical_map(i) == physid) -+ break; -+ -+ if (i == possible_cpus) -+ return -ENOENT; -+ -+ return i; -+} -+ -+int topo_add_cpu(int physid) -+{ -+ int cpu; -+ -+ if (!bsp_added && (physid == loongson_sysconf.boot_cpu_id)) { -+ bsp_added = true; -+ return 0; -+ } -+ -+ cpu = topo_get_cpu(physid); -+ if (cpu >= 0) { -+ pr_warn("Adding duplicated physical cpuid 0x%x\n", physid); -+ return -EEXIST; -+ } -+ -+ if (possible_cpus >= nr_cpu_ids) -+ return -ERANGE; -+ -+ __cpu_logical_map[possible_cpus] = physid; -+ cpu = possible_cpus++; -+ return cpu; -+} -+ -+static void __init topo_init(void) -+{ -+ loongson_sysconf.boot_cpu_id = read_csr_cpuid(); -+ __cpu_logical_map[0] = loongson_sysconf.boot_cpu_id; -+ possible_cpus++; -+} -+ -+static void __init writecombine_detect(void) -+{ -+ u64 cpuname; -+ -+ if (wc_arg >= 0) { -+ wc_enabled = wc_arg; -+ return; -+ } -+ -+ cpuname = iocsr_read64(LOONGARCH_IOCSR_CPUNAME); -+ cpuname &= 0x0000ffffffffffff; -+ switch (cpuname) { -+ case 0x0000303030364333: -+ wc_enabled = false; -+ break; -+ default: -+ break; -+ } -+} -+ - void __init platform_init(void) - { - arch_reserve_vmcore(); - arch_reserve_crashkernel(); -+ topo_init(); - - #ifdef CONFIG_ACPI_TABLE_UPGRADE - acpi_table_upgrade(); -@@ -382,6 +452,8 @@ void __init platform_init(void) - smbios_parse(); - pr_info("The BIOS Version: %s\n", b_info.bios_version); - -+ writecombine_detect(); -+ pr_info("WriteCombine: %s\n", wc_enabled ? "on":"off"); - efi_runtime_init(); - } - -@@ -618,6 +690,8 @@ void __init setup_arch(char **cmdline_p) - arch_mem_init(cmdline_p); - - resource_init(); -+ jump_label_init(); /* Initialise the static keys for paravirtualization */ -+ - #ifdef CONFIG_SMP - plat_smp_setup(); - prefill_possible_map(); -diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c -index 963dd32..bd13247 100644 ---- a/arch/loongarch/kernel/smp.c -+++ b/arch/loongarch/kernel/smp.c -@@ -71,6 +71,7 @@ static DEFINE_PER_CPU(int, cpu_state); - static const char *ipi_types[NR_IPI] __tracepoint_string = { - [IPI_RESCHEDULE] = "Rescheduling interrupts", - [IPI_CALL_FUNCTION] = "Function call interrupts", -+ [IPI_CLEAR_VECTOR] = "Clear vector interrupts", - }; - - void show_ipi_list(struct seq_file *p, int prec) -@@ -245,6 +246,11 @@ static irqreturn_t loongson_ipi_interrupt(int irq, void *dev) - per_cpu(irq_stat, cpu).ipi_irqs[IPI_CALL_FUNCTION]++; - } - -+ if (action & SMP_CLEAR_VECTOR) { -+ complete_irq_moving(); -+ per_cpu(irq_stat, cpu).ipi_irqs[IPI_CLEAR_VECTOR]++; -+ } -+ - return IRQ_HANDLED; - } - -@@ -282,11 +288,9 @@ static void __init fdt_smp_setup(void) - if (cpuid >= nr_cpu_ids) - continue; - -- if (cpuid == loongson_sysconf.boot_cpu_id) { -- cpu = 0; -- } else { -- cpu = cpumask_next_zero(-1, cpu_present_mask); -- } -+ cpu = topo_add_cpu(cpuid); -+ if (cpu < 0) -+ continue; - - num_processors++; - set_cpu_possible(cpu, true); -@@ -294,7 +298,7 @@ static void __init fdt_smp_setup(void) - __cpu_number_map[cpuid] = cpu; - __cpu_logical_map[cpu] = cpuid; - -- early_numa_add_cpu(cpu, 0); -+ early_numa_add_cpu(cpuid, 0); - set_cpuid_to_node(cpuid, 0); - } - -@@ -471,7 +475,7 @@ core_initcall(ipi_pm_init); - #endif - - /* Preload SMP state for boot cpu */ --void smp_prepare_boot_cpu(void) -+void __init smp_prepare_boot_cpu(void) - { - unsigned int cpu, node, rr_node; - -@@ -504,6 +508,8 @@ void smp_prepare_boot_cpu(void) - rr_node = next_node_in(rr_node, node_online_map); - } - } -+ -+ pv_spinlock_init(); - } - - /* called from main before smp_init() */ -diff --git a/arch/loongarch/kvm/Kconfig b/arch/loongarch/kvm/Kconfig -index f1a9b51..39c6645 100644 ---- a/arch/loongarch/kvm/Kconfig -+++ b/arch/loongarch/kvm/Kconfig -@@ -24,6 +24,10 @@ config KVM - select HAVE_KVM_DIRTY_RING_ACQ_REL - select HAVE_KVM_EVENTFD - select HAVE_KVM_VCPU_ASYNC_IOCTL -+ select HAVE_KVM_IRQ_ROUTING -+ select HAVE_KVM_IRQCHIP -+ select HAVE_KVM_IRQFD -+ select HAVE_KVM_MSI - select KVM_GENERIC_DIRTYLOG_READ_PROTECT - select KVM_GENERIC_HARDWARE_ENABLING - select KVM_GENERIC_MMU_NOTIFIER -diff --git a/arch/loongarch/kvm/Makefile b/arch/loongarch/kvm/Makefile -index 244467d..f363e4b 100644 ---- a/arch/loongarch/kvm/Makefile -+++ b/arch/loongarch/kvm/Makefile -@@ -18,5 +18,9 @@ kvm-y += timer.o - kvm-y += tlb.o - kvm-y += vcpu.o - kvm-y += vm.o -+kvm-y += intc/ipi.o -+kvm-y += intc/extioi.o -+kvm-y += intc/pch_pic.o -+kvm-y += irqfd.o - - CFLAGS_exit.o += $(call cc-option,-Wno-override-init,) -diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c -index ef37d82..7b40b01 100644 ---- a/arch/loongarch/kvm/exit.c -+++ b/arch/loongarch/kvm/exit.c -@@ -50,9 +50,7 @@ static int kvm_emu_cpucfg(struct kvm_vcpu *vcpu, larch_inst inst) - vcpu->arch.gprs[rd] = *(unsigned int *)KVM_SIGNATURE; - break; - case CPUCFG_KVM_FEATURE: -- ret = KVM_FEATURE_IPI; -- if (kvm_pvtime_supported()) -- ret |= KVM_FEATURE_STEAL_TIME; -+ ret = vcpu->kvm->arch.pv_features & LOONGARCH_PV_FEAT_MASK; - vcpu->arch.gprs[rd] = ret; - break; - default: -@@ -159,7 +157,7 @@ static int kvm_handle_csr(struct kvm_vcpu *vcpu, larch_inst inst) - int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu) - { - int ret; -- unsigned long val; -+ unsigned long *val; - u32 addr, rd, rj, opcode; - - /* -@@ -172,6 +170,7 @@ int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu) - ret = EMULATE_DO_IOCSR; - run->iocsr_io.phys_addr = addr; - run->iocsr_io.is_write = 0; -+ val = &vcpu->arch.gprs[rd]; - - /* LoongArch is Little endian */ - switch (opcode) { -@@ -205,15 +204,21 @@ int kvm_emu_iocsr(larch_inst inst, struct kvm_run *run, struct kvm_vcpu *vcpu) - break; - default: - ret = EMULATE_FAIL; -- break; -+ return ret; - } - -- if (ret == EMULATE_DO_IOCSR) { -- if (run->iocsr_io.is_write) { -- val = vcpu->arch.gprs[rd]; -- memcpy(run->iocsr_io.data, &val, run->iocsr_io.len); -- } -- vcpu->arch.io_gpr = rd; -+ if (run->iocsr_io.is_write) { -+ if (!kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, run->iocsr_io.len, val)) -+ ret = EMULATE_DONE; -+ else -+ /* Save data and let user space to write it */ -+ memcpy(run->iocsr_io.data, val, run->iocsr_io.len); -+ } else { -+ if (!kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, run->iocsr_io.len, val)) -+ ret = EMULATE_DONE; -+ else -+ /* Save register id for iocsr read completion */ -+ vcpu->arch.io_gpr = rd; - } - - return ret; -@@ -449,18 +454,30 @@ int kvm_emu_mmio_read(struct kvm_vcpu *vcpu, larch_inst inst) - } - - if (ret == EMULATE_DO_MMIO) { -+ /* -+ * if mmio device such as pch pic is emulated in KVM, -+ * it need not return to user space to handle the mmio -+ * exception. -+ */ -+ ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, vcpu->arch.badv, -+ run->mmio.len, &vcpu->arch.gprs[rd]); -+ if (!ret) { -+ update_pc(&vcpu->arch); -+ vcpu->mmio_needed = 0; -+ return EMULATE_DONE; -+ } - /* Set for kvm_complete_mmio_read() use */ - vcpu->arch.io_gpr = rd; - run->mmio.is_write = 0; - vcpu->mmio_is_write = 0; - trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, run->mmio.len, - run->mmio.phys_addr, NULL); -- } else { -- kvm_err("Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", -- inst.word, vcpu->arch.pc, vcpu->arch.badv); -- kvm_arch_vcpu_dump_regs(vcpu); -- vcpu->mmio_needed = 0; -+ return EMULATE_DO_MMIO; - } -+ kvm_err("Read not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", -+ inst.word, vcpu->arch.pc, vcpu->arch.badv); -+ kvm_arch_vcpu_dump_regs(vcpu); -+ vcpu->mmio_needed = 0; - - return ret; - } -@@ -602,19 +619,30 @@ int kvm_emu_mmio_write(struct kvm_vcpu *vcpu, larch_inst inst) - } - - if (ret == EMULATE_DO_MMIO) { -+ /* -+ * if mmio device such as pch pic is emulated in KVM, -+ * it need not return to user space to handle the mmio -+ * exception. -+ */ -+ ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, vcpu->arch.badv, -+ run->mmio.len, data); -+ if (!ret) -+ return EMULATE_DONE; -+ - run->mmio.is_write = 1; - vcpu->mmio_needed = 1; - vcpu->mmio_is_write = 1; - trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, run->mmio.len, - run->mmio.phys_addr, data); -- } else { -- vcpu->arch.pc = curr_pc; -- kvm_err("Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", -- inst.word, vcpu->arch.pc, vcpu->arch.badv); -- kvm_arch_vcpu_dump_regs(vcpu); -- /* Rollback PC if emulation was unsuccessful */ -+ return EMULATE_DO_MMIO; - } - -+ vcpu->arch.pc = curr_pc; -+ kvm_err("Write not supported Inst=0x%08x @%lx BadVaddr:%#lx\n", -+ inst.word, vcpu->arch.pc, vcpu->arch.badv); -+ kvm_arch_vcpu_dump_regs(vcpu); -+ /* Rollback PC if emulation was unsuccessful */ -+ - return ret; - } - -@@ -756,6 +784,14 @@ static int kvm_handle_lasx_disabled(struct kvm_vcpu *vcpu) - return RESUME_GUEST; - } - -+static int kvm_handle_lbt_disabled(struct kvm_vcpu *vcpu) -+{ -+ if (kvm_own_lbt(vcpu)) -+ kvm_queue_exception(vcpu, EXCCODE_INE, 0); -+ -+ return RESUME_GUEST; -+} -+ - static int kvm_send_pv_ipi(struct kvm_vcpu *vcpu) - { - unsigned int min, cpu, i; -@@ -789,19 +825,21 @@ static int kvm_send_pv_ipi(struct kvm_vcpu *vcpu) - */ - static void kvm_handle_service(struct kvm_vcpu *vcpu) - { -+ long ret = KVM_HCALL_INVALID_CODE; - unsigned long func = kvm_read_reg(vcpu, LOONGARCH_GPR_A0); -- long ret; - - switch (func) { - case KVM_HCALL_FUNC_IPI: -- kvm_send_pv_ipi(vcpu); -- ret = KVM_HCALL_SUCCESS; -+ if (kvm_guest_has_pv_feature(vcpu, KVM_FEATURE_IPI)) { -+ kvm_send_pv_ipi(vcpu); -+ ret = KVM_HCALL_SUCCESS; -+ } - break; - case KVM_HCALL_FUNC_NOTIFY: -- ret = kvm_save_notify(vcpu); -+ if (kvm_guest_has_pv_feature(vcpu, KVM_FEATURE_STEAL_TIME)) -+ ret = kvm_save_notify(vcpu); - break; - default: -- ret = KVM_HCALL_INVALID_CODE; - break; - } - -@@ -873,6 +911,7 @@ static exit_handle_fn kvm_fault_tables[EXCCODE_INT_START] = { - [EXCCODE_FPDIS] = kvm_handle_fpu_disabled, - [EXCCODE_LSXDIS] = kvm_handle_lsx_disabled, - [EXCCODE_LASXDIS] = kvm_handle_lasx_disabled, -+ [EXCCODE_BTDIS] = kvm_handle_lbt_disabled, - [EXCCODE_GSPR] = kvm_handle_gspr, - [EXCCODE_HVC] = kvm_handle_hypercall, - }; -diff --git a/arch/loongarch/kvm/intc/extioi.c b/arch/loongarch/kvm/intc/extioi.c -new file mode 100644 -index 0000000..5327066 ---- /dev/null -+++ b/arch/loongarch/kvm/intc/extioi.c -@@ -0,0 +1,804 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2024 Loongson Technology Corporation Limited -+ */ -+ -+#include <asm/kvm_extioi.h> -+#include <asm/kvm_vcpu.h> -+#include <linux/count_zeros.h> -+ -+#define loongarch_ext_irq_lock(s, flags) spin_lock_irqsave(&s->lock, flags) -+#define loongarch_ext_irq_unlock(s, flags) spin_unlock_irqrestore(&s->lock, flags) -+ -+static void extioi_update_irq(struct loongarch_extioi *s, int irq, int level) -+{ -+ int ipnum, cpu, found, irq_index, irq_mask; -+ struct kvm_interrupt vcpu_irq; -+ struct kvm_vcpu *vcpu; -+ -+ ipnum = s->ipmap.reg_u8[irq / 32]; -+ ipnum = count_trailing_zeros(ipnum); -+ ipnum = (ipnum >= 0 && ipnum < 4) ? ipnum : 0; -+ -+ cpu = s->sw_coremap[irq]; -+ vcpu = kvm_get_vcpu(s->kvm, cpu); -+ irq_index = irq / 32; -+ /* length of accessing core isr is 4 bytes */ -+ irq_mask = 1 << (irq & 0x1f); -+ -+ if (level) { -+ /* if not enable return false */ -+ if (((s->enable.reg_u32[irq_index]) & irq_mask) == 0) -+ return; -+ s->coreisr.reg_u32[cpu][irq_index] |= irq_mask; -+ found = find_first_bit(s->sw_coreisr[cpu][ipnum], EXTIOI_IRQS); -+ set_bit(irq, s->sw_coreisr[cpu][ipnum]); -+ } else { -+ s->coreisr.reg_u32[cpu][irq_index] &= ~irq_mask; -+ clear_bit(irq, s->sw_coreisr[cpu][ipnum]); -+ found = find_first_bit(s->sw_coreisr[cpu][ipnum], EXTIOI_IRQS); -+ } -+ -+ if (found < EXTIOI_IRQS) -+ /* other irq is handling, need not update parent irq level */ -+ return; -+ -+ vcpu_irq.irq = level ? INT_HWI0 + ipnum : -(INT_HWI0 + ipnum); -+ kvm_vcpu_ioctl_interrupt(vcpu, &vcpu_irq); -+} -+ -+static void extioi_set_sw_coreisr(struct loongarch_extioi *s) -+{ -+ int ipnum, cpu, irq_index, irq_mask, irq; -+ -+ for (irq = 0; irq < EXTIOI_IRQS; irq++) { -+ ipnum = s->ipmap.reg_u8[irq / 32]; -+ ipnum = count_trailing_zeros(ipnum); -+ ipnum = (ipnum >= 0 && ipnum < 4) ? ipnum : 0; -+ irq_index = irq / 32; -+ /* length of accessing core isr is 4 bytes */ -+ irq_mask = 1 << (irq & 0x1f); -+ -+ cpu = s->coremap.reg_u8[irq]; -+ if (!!(s->coreisr.reg_u32[cpu][irq_index] & irq_mask)) -+ set_bit(irq, s->sw_coreisr[cpu][ipnum]); -+ else -+ clear_bit(irq, s->sw_coreisr[cpu][ipnum]); -+ } -+} -+ -+void extioi_set_irq(struct loongarch_extioi *s, int irq, int level) -+{ -+ unsigned long *isr = (unsigned long *)s->isr.reg_u8; -+ unsigned long flags; -+ -+ level ? set_bit(irq, isr) : clear_bit(irq, isr); -+ if (!level) -+ return; -+ loongarch_ext_irq_lock(s, flags); -+ extioi_update_irq(s, irq, level); -+ loongarch_ext_irq_unlock(s, flags); -+} -+ -+static inline void extioi_enable_irq(struct kvm_vcpu *vcpu, struct loongarch_extioi *s, -+ int index, u8 mask, int level) -+{ -+ u8 val; -+ int irq; -+ -+ val = mask & s->isr.reg_u8[index]; -+ irq = ffs(val); -+ while (irq != 0) { -+ /* -+ * enable bit change from 0 to 1, -+ * need to update irq by pending bits -+ */ -+ extioi_update_irq(s, irq - 1 + index * 8, level); -+ val &= ~(1 << (irq - 1)); -+ irq = ffs(val); -+ } -+} -+ -+static int loongarch_extioi_writeb(struct kvm_vcpu *vcpu, -+ struct loongarch_extioi *s, -+ gpa_t addr, int len, const void *val) -+{ -+ int index, irq, ret = 0; -+ u8 data, old_data, cpu; -+ u8 coreisr, old_coreisr; -+ gpa_t offset; -+ -+ data = *(u8 *)val; -+ offset = addr - EXTIOI_BASE; -+ -+ switch (offset) { -+ case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END: -+ index = (offset - EXTIOI_NODETYPE_START); -+ s->nodetype.reg_u8[index] = data; -+ break; -+ case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END: -+ /* -+ * ipmap cannot be set at runtime, can be set only at the beginning -+ * of intr driver, need not update upper irq level -+ */ -+ index = (offset - EXTIOI_IPMAP_START); -+ s->ipmap.reg_u8[index] = data; -+ break; -+ case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END: -+ index = (offset - EXTIOI_ENABLE_START); -+ old_data = s->enable.reg_u8[index]; -+ s->enable.reg_u8[index] = data; -+ /* -+ * 1: enable irq. -+ * update irq when isr is set. -+ */ -+ data = s->enable.reg_u8[index] & ~old_data & s->isr.reg_u8[index]; -+ extioi_enable_irq(vcpu, s, index, data, 1); -+ /* -+ * 0: disable irq. -+ * update irq when isr is set. -+ */ -+ data = ~s->enable.reg_u8[index] & old_data & s->isr.reg_u8[index]; -+ extioi_enable_irq(vcpu, s, index, data, 0); -+ break; -+ case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END: -+ /* do not emulate hw bounced irq routing */ -+ index = offset - EXTIOI_BOUNCE_START; -+ s->bounce.reg_u8[index] = data; -+ break; -+ case EXTIOI_COREISR_START ... EXTIOI_COREISR_END: -+ /* length of accessing core isr is 8 bytes */ -+ index = (offset - EXTIOI_COREISR_START); -+ /* using attrs to get current cpu index */ -+ cpu = vcpu->vcpu_id; -+ coreisr = data; -+ old_coreisr = s->coreisr.reg_u8[cpu][index]; -+ /* write 1 to clear interrupt */ -+ s->coreisr.reg_u8[cpu][index] = old_coreisr & ~coreisr; -+ coreisr &= old_coreisr; -+ irq = ffs(coreisr); -+ while (irq != 0) { -+ extioi_update_irq(s, irq - 1 + index * 8, 0); -+ coreisr &= ~(1 << (irq - 1)); -+ irq = ffs(coreisr); -+ } -+ break; -+ case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END: -+ irq = offset - EXTIOI_COREMAP_START; -+ index = irq; -+ s->coremap.reg_u8[index] = data; -+ -+ cpu = data & 0xff; -+ cpu = ffs(cpu) - 1; -+ cpu = (cpu >= 4) ? 0 : cpu; -+ -+ if (s->sw_coremap[irq] == cpu) -+ break; -+ -+ if (test_bit(irq, (unsigned long *)s->isr.reg_u8)) { -+ /* -+ * lower irq at old cpu and raise irq at new cpu -+ */ -+ extioi_update_irq(s, irq, 0); -+ s->sw_coremap[irq] = cpu; -+ extioi_update_irq(s, irq, 1); -+ } else -+ s->sw_coremap[irq] = cpu; -+ -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+static int loongarch_extioi_writew(struct kvm_vcpu *vcpu, -+ struct loongarch_extioi *s, -+ gpa_t addr, int len, const void *val) -+{ -+ int i, index, irq, ret = 0; -+ u8 cpu; -+ u32 data, old_data; -+ u32 coreisr, old_coreisr; -+ gpa_t offset; -+ -+ data = *(u32 *)val; -+ offset = addr - EXTIOI_BASE; -+ -+ switch (offset) { -+ case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END: -+ index = (offset - EXTIOI_NODETYPE_START) >> 2; -+ s->nodetype.reg_u32[index] = data; -+ break; -+ case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END: -+ /* -+ * ipmap cannot be set at runtime, can be set only at the beginning -+ * of intr driver, need not update upper irq level -+ */ -+ index = (offset - EXTIOI_IPMAP_START) >> 2; -+ s->ipmap.reg_u32[index] = data; -+ break; -+ case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END: -+ index = (offset - EXTIOI_ENABLE_START) >> 2; -+ old_data = s->enable.reg_u32[index]; -+ s->enable.reg_u32[index] = data; -+ /* -+ * 1: enable irq. -+ * update irq when isr is set. -+ */ -+ data = s->enable.reg_u32[index] & ~old_data & s->isr.reg_u32[index]; -+ index = index << 2; -+ for (i = 0; i < sizeof(data); i++) { -+ u8 mask = (data >> (i * 8)) & 0xff; -+ -+ extioi_enable_irq(vcpu, s, index + i, mask, 1); -+ } -+ /* -+ * 0: disable irq. -+ * update irq when isr is set. -+ */ -+ data = ~s->enable.reg_u32[index] & old_data & s->isr.reg_u32[index]; -+ for (i = 0; i < sizeof(data); i++) { -+ u8 mask = (data >> (i * 8)) & 0xff; -+ -+ extioi_enable_irq(vcpu, s, index, mask, 0); -+ } -+ break; -+ case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END: -+ /* do not emulate hw bounced irq routing */ -+ index = (offset - EXTIOI_BOUNCE_START) >> 2; -+ s->bounce.reg_u32[index] = data; -+ break; -+ case EXTIOI_COREISR_START ... EXTIOI_COREISR_END: -+ /* length of accessing core isr is 8 bytes */ -+ index = (offset - EXTIOI_COREISR_START) >> 2; -+ /* using attrs to get current cpu index */ -+ cpu = vcpu->vcpu_id; -+ coreisr = data; -+ old_coreisr = s->coreisr.reg_u32[cpu][index]; -+ /* write 1 to clear interrupt */ -+ s->coreisr.reg_u32[cpu][index] = old_coreisr & ~coreisr; -+ coreisr &= old_coreisr; -+ irq = ffs(coreisr); -+ while (irq != 0) { -+ extioi_update_irq(s, irq - 1 + index * 32, 0); -+ coreisr &= ~(1 << (irq - 1)); -+ irq = ffs(coreisr); -+ } -+ break; -+ case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END: -+ irq = offset - EXTIOI_COREMAP_START; -+ index = irq >> 2; -+ -+ s->coremap.reg_u32[index] = data; -+ -+ for (i = 0; i < sizeof(data); i++) { -+ cpu = data & 0xff; -+ cpu = ffs(cpu) - 1; -+ cpu = (cpu >= 4) ? 0 : cpu; -+ data = data >> 8; -+ -+ if (s->sw_coremap[irq + i] == cpu) -+ continue; -+ -+ if (test_bit(irq, (unsigned long *)s->isr.reg_u8)) { -+ /* -+ * lower irq at old cpu and raise irq at new cpu -+ */ -+ extioi_update_irq(s, irq + i, 0); -+ s->sw_coremap[irq + i] = cpu; -+ extioi_update_irq(s, irq + i, 1); -+ } else -+ s->sw_coremap[irq + i] = cpu; -+ } -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+static int loongarch_extioi_writel(struct kvm_vcpu *vcpu, -+ struct loongarch_extioi *s, -+ gpa_t addr, int len, const void *val) -+{ -+ int i, index, irq, bits, ret = 0; -+ u8 cpu; -+ u64 data, old_data; -+ u64 coreisr, old_coreisr; -+ gpa_t offset; -+ -+ data = *(u64 *)val; -+ offset = addr - EXTIOI_BASE; -+ -+ switch (offset) { -+ case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END: -+ index = (offset - EXTIOI_NODETYPE_START) >> 3; -+ s->nodetype.reg_u64[index] = data; -+ break; -+ case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END: -+ /* -+ * ipmap cannot be set at runtime, can be set only at the beginning -+ * of intr driver, need not update upper irq level -+ */ -+ index = (offset - EXTIOI_IPMAP_START) >> 3; -+ s->ipmap.reg_u64 = data; -+ break; -+ case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END: -+ index = (offset - EXTIOI_ENABLE_START) >> 3; -+ old_data = s->enable.reg_u64[index]; -+ s->enable.reg_u64[index] = data; -+ /* -+ * 1: enable irq. -+ * update irq when isr is set. -+ */ -+ data = s->enable.reg_u64[index] & ~old_data & s->isr.reg_u64[index]; -+ index = index << 3; -+ for (i = 0; i < sizeof(data); i++) { -+ u8 mask = (data >> (i * 8)) & 0xff; -+ -+ extioi_enable_irq(vcpu, s, index + i, mask, 1); -+ } -+ /* -+ * 0: disable irq. -+ * update irq when isr is set. -+ */ -+ data = ~s->enable.reg_u64[index] & old_data & s->isr.reg_u64[index]; -+ for (i = 0; i < sizeof(data); i++) { -+ u8 mask = (data >> (i * 8)) & 0xff; -+ -+ extioi_enable_irq(vcpu, s, index, mask, 0); -+ } -+ break; -+ case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END: -+ /* do not emulate hw bounced irq routing */ -+ index = (offset - EXTIOI_BOUNCE_START) >> 3; -+ s->bounce.reg_u64[index] = data; -+ break; -+ case EXTIOI_COREISR_START ... EXTIOI_COREISR_END: -+ /* length of accessing core isr is 8 bytes */ -+ index = (offset - EXTIOI_COREISR_START) >> 3; -+ /* using attrs to get current cpu index */ -+ cpu = vcpu->vcpu_id; -+ coreisr = data; -+ old_coreisr = s->coreisr.reg_u64[cpu][index]; -+ /* write 1 to clear interrupt */ -+ s->coreisr.reg_u64[cpu][index] = old_coreisr & ~coreisr; -+ coreisr &= old_coreisr; -+ -+ bits = sizeof(u64) * 8; -+ irq = find_first_bit((void *)&coreisr, bits); -+ while (irq < bits) { -+ extioi_update_irq(s, irq + index * bits, 0); -+ bitmap_clear((void *)&coreisr, irq, 1); -+ irq = find_first_bit((void *)&coreisr, bits); -+ } -+ break; -+ case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END: -+ irq = offset - EXTIOI_COREMAP_START; -+ index = irq >> 3; -+ -+ s->coremap.reg_u64[index] = data; -+ -+ for (i = 0; i < sizeof(data); i++) { -+ cpu = data & 0xff; -+ cpu = ffs(cpu) - 1; -+ cpu = (cpu >= 4) ? 0 : cpu; -+ data = data >> 8; -+ -+ if (s->sw_coremap[irq + i] == cpu) -+ continue; -+ -+ if (test_bit(irq, (unsigned long *)s->isr.reg_u8)) { -+ /* -+ * lower irq at old cpu and raise irq at new cpu -+ */ -+ extioi_update_irq(s, irq + i, 0); -+ s->sw_coremap[irq + i] = cpu; -+ extioi_update_irq(s, irq + i, 1); -+ } else -+ s->sw_coremap[irq + i] = cpu; -+ } -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ return ret; -+} -+ -+static int kvm_loongarch_extioi_write(struct kvm_vcpu *vcpu, -+ struct kvm_io_device *dev, -+ gpa_t addr, int len, const void *val) -+{ -+ int ret; -+ struct loongarch_extioi *extioi = vcpu->kvm->arch.extioi; -+ unsigned long flags; -+ -+ if (!extioi) { -+ kvm_err("%s: extioi irqchip not valid!\n", __func__); -+ return -EINVAL; -+ } -+ -+ vcpu->kvm->stat.extioi_write_exits++; -+ loongarch_ext_irq_lock(extioi, flags); -+ -+ switch (len) { -+ case 1: -+ ret = loongarch_extioi_writeb(vcpu, extioi, addr, len, val); -+ break; -+ case 4: -+ ret = loongarch_extioi_writew(vcpu, extioi, addr, len, val); -+ break; -+ case 8: -+ ret = loongarch_extioi_writel(vcpu, extioi, addr, len, val); -+ break; -+ default: -+ WARN_ONCE(1, "%s: Abnormal address access:addr 0x%llx,size %d\n", -+ __func__, addr, len); -+ } -+ -+ loongarch_ext_irq_unlock(extioi, flags); -+ -+ -+ return ret; -+} -+ -+static int loongarch_extioi_readb(struct kvm_vcpu *vcpu, struct loongarch_extioi *s, -+ gpa_t addr, int len, void *val) -+{ -+ int index, ret = 0; -+ gpa_t offset; -+ u64 data; -+ -+ offset = addr - EXTIOI_BASE; -+ switch (offset) { -+ case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END: -+ index = offset - EXTIOI_NODETYPE_START; -+ data = s->nodetype.reg_u8[index]; -+ break; -+ case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END: -+ index = offset - EXTIOI_IPMAP_START; -+ data = s->ipmap.reg_u8[index]; -+ break; -+ case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END: -+ index = offset - EXTIOI_ENABLE_START; -+ data = s->enable.reg_u8[index]; -+ break; -+ case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END: -+ index = offset - EXTIOI_BOUNCE_START; -+ data = s->bounce.reg_u8[index]; -+ break; -+ case EXTIOI_COREISR_START ... EXTIOI_COREISR_END: -+ /* length of accessing core isr is 8 bytes */ -+ index = offset - EXTIOI_COREISR_START; -+ data = s->coreisr.reg_u8[vcpu->vcpu_id][index]; -+ break; -+ case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END: -+ index = offset - EXTIOI_COREMAP_START; -+ data = s->coremap.reg_u8[index]; -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ *(u8 *)val = data; -+ -+ return ret; -+} -+ -+static int loongarch_extioi_readw(struct kvm_vcpu *vcpu, struct loongarch_extioi *s, -+ gpa_t addr, int len, void *val) -+{ -+ int index, ret = 0; -+ gpa_t offset; -+ u64 data; -+ -+ offset = addr - EXTIOI_BASE; -+ switch (offset) { -+ case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END: -+ index = (offset - EXTIOI_NODETYPE_START) >> 2; -+ data = s->nodetype.reg_u32[index]; -+ break; -+ case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END: -+ index = (offset - EXTIOI_IPMAP_START) >> 2; -+ data = s->ipmap.reg_u32[index]; -+ break; -+ case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END: -+ index = (offset - EXTIOI_ENABLE_START) >> 2; -+ data = s->enable.reg_u32[index]; -+ break; -+ case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END: -+ index = (offset - EXTIOI_BOUNCE_START) >> 2; -+ data = s->bounce.reg_u32[index]; -+ break; -+ case EXTIOI_COREISR_START ... EXTIOI_COREISR_END: -+ /* length of accessing core isr is 8 bytes */ -+ index = (offset - EXTIOI_COREISR_START) >> 2; -+ data = s->coreisr.reg_u32[vcpu->vcpu_id][index]; -+ break; -+ case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END: -+ index = (offset - EXTIOI_COREMAP_START) >> 2; -+ data = s->coremap.reg_u32[index]; -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ *(u32 *)val = data; -+ -+ return ret; -+} -+ -+static int loongarch_extioi_readl(struct kvm_vcpu *vcpu, struct loongarch_extioi *s, -+ gpa_t addr, int len, void *val) -+{ -+ int index, ret = 0; -+ gpa_t offset; -+ u64 data; -+ -+ offset = addr - EXTIOI_BASE; -+ switch (offset) { -+ case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END: -+ index = (offset - EXTIOI_NODETYPE_START) >> 3; -+ data = s->nodetype.reg_u64[index]; -+ break; -+ case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END: -+ index = (offset - EXTIOI_IPMAP_START) >> 3; -+ data = s->ipmap.reg_u64; -+ break; -+ case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END: -+ index = (offset - EXTIOI_ENABLE_START) >> 3; -+ data = s->enable.reg_u64[index]; -+ break; -+ case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END: -+ index = (offset - EXTIOI_BOUNCE_START) >> 3; -+ data = s->bounce.reg_u64[index]; -+ break; -+ case EXTIOI_COREISR_START ... EXTIOI_COREISR_END: -+ /* length of accessing core isr is 8 bytes */ -+ index = (offset - EXTIOI_COREISR_START) >> 3; -+ data = s->coreisr.reg_u64[vcpu->vcpu_id][index]; -+ break; -+ case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END: -+ index = (offset - EXTIOI_COREMAP_START) >> 3; -+ data = s->coremap.reg_u64[index]; -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ *(u64 *)val = data; -+ -+ return ret; -+} -+ -+static int kvm_loongarch_extioi_read(struct kvm_vcpu *vcpu, -+ struct kvm_io_device *dev, -+ gpa_t addr, int len, void *val) -+{ -+ int ret; -+ struct loongarch_extioi *extioi = vcpu->kvm->arch.extioi; -+ unsigned long flags; -+ -+ if (!extioi) { -+ kvm_err("%s: extioi irqchip not valid!\n", __func__); -+ return -EINVAL; -+ } -+ -+ vcpu->kvm->stat.extioi_read_exits++; -+ loongarch_ext_irq_lock(extioi, flags); -+ -+ switch (len) { -+ case 1: -+ ret = loongarch_extioi_readb(vcpu, extioi, addr, len, val); -+ break; -+ case 4: -+ ret = loongarch_extioi_readw(vcpu, extioi, addr, len, val); -+ break; -+ case 8: -+ ret = loongarch_extioi_readl(vcpu, extioi, addr, len, val); -+ break; -+ default: -+ WARN_ONCE(1, "%s: Abnormal address access:addr 0x%llx,size %d\n", -+ __func__, addr, len); -+ } -+ -+ loongarch_ext_irq_unlock(extioi, flags); -+ -+ return ret; -+} -+ -+static const struct kvm_io_device_ops kvm_loongarch_extioi_ops = { -+ .read = kvm_loongarch_extioi_read, -+ .write = kvm_loongarch_extioi_write, -+}; -+ -+static int kvm_loongarch_extioi_regs_access(struct kvm_device *dev, -+ struct kvm_device_attr *attr, -+ bool is_write) -+{ -+ int len, addr; -+ void __user *data; -+ void *p = NULL; -+ struct loongarch_extioi *s; -+ unsigned long flags; -+ -+ s = dev->kvm->arch.extioi; -+ addr = attr->attr; -+ data = (void __user *)attr->addr; -+ -+ loongarch_ext_irq_lock(s, flags); -+ switch (addr) { -+ case EXTIOI_NODETYPE_START: -+ p = s->nodetype.reg_u8; -+ len = sizeof(s->nodetype); -+ break; -+ case EXTIOI_IPMAP_START: -+ p = s->ipmap.reg_u8; -+ len = sizeof(s->ipmap); -+ break; -+ case EXTIOI_ENABLE_START: -+ p = s->enable.reg_u8; -+ len = sizeof(s->enable); -+ break; -+ case EXTIOI_BOUNCE_START: -+ p = s->bounce.reg_u8; -+ len = sizeof(s->bounce); -+ break; -+ case EXTIOI_ISR_START: -+ p = s->isr.reg_u8; -+ len = sizeof(s->isr); -+ break; -+ case EXTIOI_COREISR_START: -+ p = s->coreisr.reg_u8; -+ len = sizeof(s->coreisr); -+ break; -+ case EXTIOI_COREMAP_START: -+ p = s->coremap.reg_u8; -+ len = sizeof(s->coremap); -+ break; -+ case EXTIOI_SW_COREMAP_FLAG: -+ p = s->sw_coremap; -+ len = sizeof(s->sw_coremap); -+ break; -+ default: -+ loongarch_ext_irq_unlock(s, flags); -+ kvm_err("%s: unknown extioi register, addr = %d\n", __func__, addr); -+ return -EINVAL; -+ } -+ -+ loongarch_ext_irq_unlock(s, flags); -+ -+ if (is_write) { -+ if (copy_from_user(p, data, len)) -+ return -EFAULT; -+ } else { -+ if (copy_to_user(data, p, len)) -+ return -EFAULT; -+ } -+ -+ if ((addr == EXTIOI_COREISR_START) && is_write) { -+ loongarch_ext_irq_lock(s, flags); -+ extioi_set_sw_coreisr(s); -+ loongarch_ext_irq_unlock(s, flags); -+ } -+ -+ return 0; -+} -+ -+static int kvm_loongarch_extioi_get_attr(struct kvm_device *dev, -+ struct kvm_device_attr *attr) -+{ -+ if (attr->group == KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS) -+ return kvm_loongarch_extioi_regs_access(dev, attr, false); -+ -+ return -EINVAL; -+} -+ -+static int kvm_loongarch_extioi_set_attr(struct kvm_device *dev, -+ struct kvm_device_attr *attr) -+{ -+ if (attr->group == KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS) -+ return kvm_loongarch_extioi_regs_access(dev, attr, true); -+ -+ return -EINVAL; -+} -+ -+static void kvm_loongarch_extioi_destroy(struct kvm_device *dev) -+{ -+ struct kvm *kvm; -+ struct loongarch_extioi *extioi; -+ struct kvm_io_device *device; -+ -+ if (!dev) -+ return; -+ -+ kvm = dev->kvm; -+ if (!kvm) -+ return; -+ -+ extioi = kvm->arch.extioi; -+ if (!extioi) -+ return; -+ -+ device = &extioi->device; -+ kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, device); -+ kfree(extioi); -+} -+ -+static int kvm_loongarch_extioi_create(struct kvm_device *dev, u32 type) -+{ -+ int ret; -+ struct loongarch_extioi *s; -+ struct kvm_io_device *device; -+ struct kvm *kvm = dev->kvm; -+ -+ /* extioi has been created */ -+ if (kvm->arch.extioi) -+ return -EINVAL; -+ -+ s = kzalloc(sizeof(struct loongarch_extioi), GFP_KERNEL); -+ if (!s) -+ return -ENOMEM; -+ spin_lock_init(&s->lock); -+ s->kvm = kvm; -+ -+ /* -+ * Initialize IOCSR device -+ */ -+ device = &s->device; -+ kvm_iodevice_init(device, &kvm_loongarch_extioi_ops); -+ mutex_lock(&kvm->slots_lock); -+ ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, EXTIOI_BASE, EXTIOI_SIZE, device); -+ mutex_unlock(&kvm->slots_lock); -+ if (ret < 0) { -+ kfree(s); -+ return -EFAULT; -+ } -+ -+ kvm->arch.extioi = s; -+ -+ kvm_info("create extioi device successfully\n"); -+ return 0; -+} -+ -+static struct kvm_device_ops kvm_loongarch_extioi_dev_ops = { -+ .name = "kvm-loongarch-extioi", -+ .create = kvm_loongarch_extioi_create, -+ .destroy = kvm_loongarch_extioi_destroy, -+ .set_attr = kvm_loongarch_extioi_set_attr, -+ .get_attr = kvm_loongarch_extioi_get_attr, -+}; -+ -+int kvm_loongarch_register_extioi_device(void) -+{ -+ return kvm_register_device_ops(&kvm_loongarch_extioi_dev_ops, -+ KVM_DEV_TYPE_LA_EXTIOI); -+} -+ -+int kvm_loongarch_reset_extioi(struct kvm *kvm) -+{ -+ struct loongarch_extioi *extioi = kvm->arch.extioi; -+ unsigned long flags; -+ u8 offset, size; -+ u8 *pstart; -+ -+ if (!extioi) -+ return -EINVAL; -+ -+ pstart = (char *)&extioi->nodetype; -+ offset = (char *)&extioi->nodetype - (char *)extioi; -+ size = sizeof(struct loongarch_extioi) - offset; -+ -+ loongarch_ext_irq_lock(extioi, flags); -+ memset(pstart, 0, size); -+ loongarch_ext_irq_unlock(extioi, flags); -+ -+ return 0; -+} -diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c -new file mode 100644 -index 0000000..12024d9 ---- /dev/null -+++ b/arch/loongarch/kvm/intc/ipi.c -@@ -0,0 +1,538 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2024 Loongson Technology Corporation Limited -+ */ -+ -+#include <linux/kvm_host.h> -+#include <asm/kvm_ipi.h> -+#include <asm/kvm_vcpu.h> -+ -+static void ipi_send(struct kvm *kvm, uint64_t data) -+{ -+ struct kvm_vcpu *vcpu; -+ struct kvm_interrupt irq; -+ int cpu, action, status; -+ -+ cpu = ((data & 0xffffffff) >> 16) & 0x3ff; -+ vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); -+ if (unlikely(vcpu == NULL)) { -+ kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); -+ return; -+ } -+ -+ action = 1 << (data & 0x1f); -+ -+ spin_lock(&vcpu->arch.ipi_state.lock); -+ status = vcpu->arch.ipi_state.status; -+ vcpu->arch.ipi_state.status |= action; -+ if (status == 0) { -+ irq.irq = LARCH_INT_IPI; -+ kvm_vcpu_ioctl_interrupt(vcpu, &irq); -+ } -+ spin_unlock(&vcpu->arch.ipi_state.lock); -+} -+ -+static void ipi_clear(struct kvm_vcpu *vcpu, uint64_t data) -+{ -+ struct kvm_interrupt irq; -+ -+ spin_lock(&vcpu->arch.ipi_state.lock); -+ vcpu->arch.ipi_state.status &= ~data; -+ if (!vcpu->arch.ipi_state.status) { -+ irq.irq = -LARCH_INT_IPI; -+ kvm_vcpu_ioctl_interrupt(vcpu, &irq); -+ } -+ spin_unlock(&vcpu->arch.ipi_state.lock); -+} -+ -+static uint64_t read_mailbox(struct kvm_vcpu *vcpu, int offset, int len) -+{ -+ void *pbuf; -+ uint64_t ret = 0; -+ -+ spin_lock(&vcpu->arch.ipi_state.lock); -+ pbuf = (void *)vcpu->arch.ipi_state.buf + (offset - 0x20); -+ if (len == 1) -+ ret = *(unsigned char *)pbuf; -+ else if (len == 2) -+ ret = *(unsigned short *)pbuf; -+ else if (len == 4) -+ ret = *(unsigned int *)pbuf; -+ else if (len == 8) -+ ret = *(unsigned long *)pbuf; -+ else -+ kvm_err("%s: unknown data len: %d\n", __func__, len); -+ spin_unlock(&vcpu->arch.ipi_state.lock); -+ -+ return ret; -+} -+ -+static void write_mailbox(struct kvm_vcpu *vcpu, int offset, -+ uint64_t data, int len) -+{ -+ void *pbuf; -+ -+ spin_lock(&vcpu->arch.ipi_state.lock); -+ pbuf = (void *)vcpu->arch.ipi_state.buf + (offset - 0x20); -+ if (len == 1) -+ *(unsigned char *)pbuf = (unsigned char)data; -+ else if (len == 2) -+ *(unsigned short *)pbuf = (unsigned short)data; -+ else if (len == 4) -+ *(unsigned int *)pbuf = (unsigned int)data; -+ else if (len == 8) -+ *(unsigned long *)pbuf = (unsigned long)data; -+ else -+ kvm_err("%s: unknown data len: %d\n", __func__, len); -+ spin_unlock(&vcpu->arch.ipi_state.lock); -+} -+ -+static int loongarch_ipi_writel(struct kvm_vcpu *vcpu, gpa_t addr, -+ int len, const void *val) -+{ -+ uint64_t data; -+ uint32_t offset; -+ int ret = 0; -+ -+ data = *(uint64_t *)val; -+ -+ offset = (uint32_t)(addr & 0xff); -+ WARN_ON_ONCE(offset & (len - 1)); -+ -+ switch (offset) { -+ case CORE_STATUS_OFF: -+ kvm_err("CORE_SET_OFF Can't be write\n"); -+ ret = -EINVAL; -+ break; -+ case CORE_EN_OFF: -+ spin_lock(&vcpu->arch.ipi_state.lock); -+ vcpu->arch.ipi_state.en = data; -+ spin_unlock(&vcpu->arch.ipi_state.lock); -+ break; -+ case IOCSR_IPI_SEND: -+ ipi_send(vcpu->kvm, data); -+ break; -+ case CORE_SET_OFF: -+ kvm_info("CORE_SET_OFF simulation is required\n"); -+ ret = -EINVAL; -+ break; -+ case CORE_CLEAR_OFF: -+ /* Just clear the status of the current vcpu */ -+ ipi_clear(vcpu, data); -+ break; -+ case CORE_BUF_20 ... CORE_BUF_38 + 7: -+ if (offset + len > CORE_BUF_38 + 8) { -+ kvm_err("%s: invalid offset or len: offset = %d, len = %d\n", -+ __func__, offset, len); -+ ret = -EINVAL; -+ break; -+ } -+ write_mailbox(vcpu, offset, data, len); -+ break; -+ default: -+ kvm_err("%s: unknown addr: %llx\n", __func__, addr); -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static int loongarch_ipi_readl(struct kvm_vcpu *vcpu, gpa_t addr, -+ int len, void *val) -+{ -+ uint32_t offset; -+ uint64_t res = 0; -+ int ret = 0; -+ -+ offset = (uint32_t)(addr & 0xff); -+ WARN_ON_ONCE(offset & (len - 1)); -+ -+ switch (offset) { -+ case CORE_STATUS_OFF: -+ spin_lock(&vcpu->arch.ipi_state.lock); -+ res = vcpu->arch.ipi_state.status; -+ spin_unlock(&vcpu->arch.ipi_state.lock); -+ break; -+ case CORE_EN_OFF: -+ spin_lock(&vcpu->arch.ipi_state.lock); -+ res = vcpu->arch.ipi_state.en; -+ spin_unlock(&vcpu->arch.ipi_state.lock); -+ break; -+ case CORE_SET_OFF: -+ res = 0; -+ break; -+ case CORE_CLEAR_OFF: -+ res = 0; -+ break; -+ case CORE_BUF_20 ... CORE_BUF_38 + 7: -+ if (offset + len > CORE_BUF_38 + 8) { -+ kvm_err("%s: invalid offset or len: offset = %d, len = %d\n", -+ __func__, offset, len); -+ ret = -EINVAL; -+ break; -+ } -+ res = read_mailbox(vcpu, offset, len); -+ break; -+ default: -+ kvm_err("%s: unknown addr: %llx\n", __func__, addr); -+ ret = -EINVAL; -+ break; -+ } -+ -+ *(uint64_t *)val = res; -+ -+ return ret; -+} -+ -+static int kvm_loongarch_ipi_write(struct kvm_vcpu *vcpu, -+ struct kvm_io_device *dev, -+ gpa_t addr, int len, const void *val) -+{ -+ struct loongarch_ipi *ipi; -+ int ret; -+ -+ ipi = vcpu->kvm->arch.ipi; -+ if (!ipi) { -+ kvm_err("%s: ipi irqchip not valid!\n", __func__); -+ return -EINVAL; -+ } -+ -+ ipi->kvm->stat.ipi_write_exits++; -+ ret = loongarch_ipi_writel(vcpu, addr, len, val); -+ -+ return ret; -+} -+ -+static int kvm_loongarch_ipi_read(struct kvm_vcpu *vcpu, -+ struct kvm_io_device *dev, -+ gpa_t addr, int len, void *val) -+{ -+ struct loongarch_ipi *ipi; -+ int ret; -+ -+ ipi = vcpu->kvm->arch.ipi; -+ if (!ipi) { -+ kvm_err("%s: ipi irqchip not valid!\n", __func__); -+ return -EINVAL; -+ } -+ -+ ipi->kvm->stat.ipi_read_exits++; -+ ret = loongarch_ipi_readl(vcpu, addr, len, val); -+ -+ return ret; -+} -+ -+static int send_ipi_data(struct kvm_vcpu *vcpu, gpa_t addr, uint64_t data) -+{ -+ int i, ret; -+ uint32_t val = 0, mask = 0; -+ /* -+ * Bit 27-30 is mask for byte writing. -+ * If the mask is 0, we need not to do anything. -+ */ -+ if ((data >> 27) & 0xf) { -+ /* Read the old val */ -+ ret = kvm_io_bus_read(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val); -+ if (unlikely(ret)) { -+ kvm_err("%s: : read date from addr %llx failed\n", __func__, addr); -+ return ret; -+ } -+ /* Construct the mask by scanning the bit 27-30 */ -+ for (i = 0; i < 4; i++) { -+ if (data & (0x1 << (27 + i))) -+ mask |= (0xff << (i * 8)); -+ } -+ /* Save the old part of val */ -+ val &= mask; -+ } -+ -+ val |= ((uint32_t)(data >> 32) & ~mask); -+ ret = kvm_io_bus_write(vcpu, KVM_IOCSR_BUS, addr, sizeof(val), &val); -+ if (unlikely(ret)) -+ kvm_err("%s: : write date to addr %llx failed\n", __func__, addr); -+ -+ return ret; -+} -+ -+static int mail_send(struct kvm *kvm, uint64_t data) -+{ -+ struct kvm_vcpu *vcpu; -+ int cpu, mailbox; -+ int offset, ret; -+ -+ cpu = ((data & 0xffffffff) >> 16) & 0x3ff; -+ vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); -+ if (unlikely(vcpu == NULL)) { -+ kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); -+ return -EINVAL; -+ } -+ -+ mailbox = ((data & 0xffffffff) >> 2) & 0x7; -+ offset = SMP_MAILBOX + CORE_BUF_20 + mailbox * 4; -+ ret = send_ipi_data(vcpu, offset, data); -+ -+ return ret; -+} -+ -+static int any_send(struct kvm *kvm, uint64_t data) -+{ -+ struct kvm_vcpu *vcpu; -+ int cpu, offset, ret; -+ -+ cpu = ((data & 0xffffffff) >> 16) & 0x3ff; -+ vcpu = kvm_get_vcpu_by_cpuid(kvm, cpu); -+ if (unlikely(vcpu == NULL)) { -+ kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); -+ return -EINVAL; -+ } -+ -+ offset = data & 0xffff; -+ ret = send_ipi_data(vcpu, offset, data); -+ return ret; -+} -+ -+static int kvm_loongarch_mail_write(struct kvm_vcpu *vcpu, -+ struct kvm_io_device *dev, -+ gpa_t addr, int len, const void *val) -+{ -+ struct loongarch_ipi *ipi; -+ int ret; -+ -+ ipi = vcpu->kvm->arch.ipi; -+ if (!ipi) { -+ kvm_err("%s: ipi irqchip not valid!\n", __func__); -+ return -EINVAL; -+ } -+ -+ addr &= 0xfff; -+ addr -= IOCSR_MAIL_SEND; -+ -+ switch (addr) { -+ case MAIL_SEND_OFFSET: -+ ret = mail_send(vcpu->kvm, *(uint64_t *)val); -+ break; -+ case ANY_SEND_OFFSET: -+ ret = any_send(vcpu->kvm, *(uint64_t *)val); -+ break; -+ default: -+ kvm_err("%s: invalid addr %llx!\n", __func__, addr); -+ ret = -EINVAL; -+ break; -+ } -+ -+ return ret; -+} -+ -+static const struct kvm_io_device_ops kvm_loongarch_ipi_ops = { -+ .read = kvm_loongarch_ipi_read, -+ .write = kvm_loongarch_ipi_write, -+}; -+ -+static const struct kvm_io_device_ops kvm_loongarch_mail_ops = { -+ .write = kvm_loongarch_mail_write, -+}; -+ -+static int kvm_loongarch_ipi_regs_access(struct kvm_device *dev, -+ struct kvm_device_attr *attr, -+ bool is_write) -+{ -+ uint64_t val; -+ int cpu, addr; -+ void *p = NULL; -+ int len = 4; -+ struct kvm_vcpu *vcpu; -+ -+ cpu = (attr->attr >> 16) & 0x3ff; -+ addr = attr->attr & 0xff; -+ -+ vcpu = kvm_get_vcpu(dev->kvm, cpu); -+ if (unlikely(vcpu == NULL)) { -+ kvm_err("%s: invalid target cpu: %d\n", __func__, cpu); -+ return -EINVAL; -+ } -+ switch (addr) { -+ case CORE_STATUS_OFF: -+ p = &vcpu->arch.ipi_state.status; -+ break; -+ case CORE_EN_OFF: -+ p = &vcpu->arch.ipi_state.en; -+ break; -+ case CORE_SET_OFF: -+ p = &vcpu->arch.ipi_state.set; -+ break; -+ case CORE_CLEAR_OFF: -+ p = &vcpu->arch.ipi_state.clear; -+ break; -+ case CORE_BUF_20: -+ p = &vcpu->arch.ipi_state.buf[0]; -+ len = 8; -+ break; -+ case CORE_BUF_28: -+ p = &vcpu->arch.ipi_state.buf[1]; -+ len = 8; -+ break; -+ case CORE_BUF_30: -+ p = &vcpu->arch.ipi_state.buf[2]; -+ len = 8; -+ break; -+ case CORE_BUF_38: -+ p = &vcpu->arch.ipi_state.buf[3]; -+ len = 8; -+ break; -+ default: -+ kvm_err("%s: unknown ipi register, addr = %d\n", __func__, addr); -+ return -EINVAL; -+ } -+ -+ if (is_write) { -+ if (len == 4) { -+ if (get_user(val, (uint32_t __user *)attr->addr)) -+ return -EFAULT; -+ *(uint32_t *)p = (uint32_t)val; -+ } else if (len == 8) { -+ if (get_user(val, (uint64_t __user *)attr->addr)) -+ return -EFAULT; -+ *(uint64_t *)p = val; -+ } -+ } else { -+ if (len == 4) { -+ val = *(uint32_t *)p; -+ return put_user(val, (uint32_t __user *)attr->addr); -+ } else if (len == 8) { -+ val = *(uint64_t *)p; -+ return put_user(val, (uint64_t __user *)attr->addr); -+ } -+ } -+ -+ return 0; -+} -+ -+static int kvm_loongarch_ipi_get_attr(struct kvm_device *dev, -+ struct kvm_device_attr *attr) -+{ -+ switch (attr->group) { -+ case KVM_DEV_LOONGARCH_IPI_GRP_REGS: -+ return kvm_loongarch_ipi_regs_access(dev, attr, false); -+ default: -+ kvm_err("%s: unknown group (%d)\n", __func__, attr->group); -+ return -EINVAL; -+ } -+} -+ -+static int kvm_loongarch_ipi_set_attr(struct kvm_device *dev, -+ struct kvm_device_attr *attr) -+{ -+ switch (attr->group) { -+ case KVM_DEV_LOONGARCH_IPI_GRP_REGS: -+ return kvm_loongarch_ipi_regs_access(dev, attr, true); -+ default: -+ kvm_err("%s: unknown group (%d)\n", __func__, attr->group); -+ return -EINVAL; -+ } -+} -+ -+static void kvm_loongarch_ipi_destroy(struct kvm_device *dev) -+{ -+ struct kvm *kvm; -+ struct loongarch_ipi *ipi; -+ struct kvm_io_device *device; -+ -+ if (!dev) -+ return; -+ -+ kvm = dev->kvm; -+ if (!kvm) -+ return; -+ -+ ipi = kvm->arch.ipi; -+ if (!ipi) -+ return; -+ -+ device = &ipi->device; -+ kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, device); -+ -+ device = &ipi->mail_dev; -+ kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, device); -+ -+ kfree(ipi); -+} -+ -+static int kvm_loongarch_ipi_create(struct kvm_device *dev, u32 type) -+{ -+ struct kvm *kvm; -+ struct loongarch_ipi *s; -+ unsigned long addr; -+ struct kvm_io_device *device; -+ int ret; -+ -+ kvm_info("begin create loongarch ipi in kvm ...\n"); -+ if (!dev) { -+ kvm_err("%s: kvm_device ptr is invalid!\n", __func__); -+ return -EINVAL; -+ } -+ -+ kvm = dev->kvm; -+ if (kvm->arch.ipi) { -+ kvm_err("%s: loongarch ipi has been created!\n", __func__); -+ return -EINVAL; -+ } -+ -+ s = kzalloc(sizeof(struct loongarch_ipi), GFP_KERNEL); -+ if (!s) -+ return -ENOMEM; -+ spin_lock_init(&s->lock); -+ s->kvm = kvm; -+ -+ /* -+ * Initialize IOCSR device -+ */ -+ device = &s->device; -+ kvm_iodevice_init(device, &kvm_loongarch_ipi_ops); -+ addr = SMP_MAILBOX; -+ mutex_lock(&kvm->slots_lock); -+ ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, addr, -+ KVM_IOCSR_IPI_ADDR_SIZE, device); -+ mutex_unlock(&kvm->slots_lock); -+ if (ret < 0) { -+ kvm_err("%s: initialize IOCSR dev failed, ret = %d\n", __func__, ret); -+ goto err; -+ } -+ -+ device = &s->mail_dev; -+ kvm_iodevice_init(device, &kvm_loongarch_mail_ops); -+ addr = MAIL_SEND_ADDR; -+ mutex_lock(&kvm->slots_lock); -+ ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, addr, -+ KVM_IOCSR_MAIL_ADDR_SIZE, device); -+ mutex_unlock(&kvm->slots_lock); -+ if (ret < 0) { -+ device = &s->device; -+ kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, device); -+ kvm_err("%s: initialize mail box dev failed, ret = %d\n", __func__, ret); -+ goto err; -+ } -+ -+ kvm->arch.ipi = s; -+ kvm_info("create loongarch ipi in kvm done!\n"); -+ -+ return 0; -+ -+err: -+ kfree(s); -+ return -EFAULT; -+} -+ -+static struct kvm_device_ops kvm_loongarch_ipi_dev_ops = { -+ .name = "kvm-loongarch-ipi", -+ .create = kvm_loongarch_ipi_create, -+ .destroy = kvm_loongarch_ipi_destroy, -+ .set_attr = kvm_loongarch_ipi_set_attr, -+ .get_attr = kvm_loongarch_ipi_get_attr, -+}; -+ -+int kvm_loongarch_register_ipi_device(void) -+{ -+ return kvm_register_device_ops(&kvm_loongarch_ipi_dev_ops, -+ KVM_DEV_TYPE_LA_IPI); -+} -diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c -new file mode 100644 -index 0000000..7d053db ---- /dev/null -+++ b/arch/loongarch/kvm/intc/pch_pic.c -@@ -0,0 +1,540 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2024 Loongson Technology Corporation Limited -+ */ -+ -+#include <asm/kvm_extioi.h> -+#include <asm/kvm_pch_pic.h> -+#include <asm/kvm_vcpu.h> -+#include <linux/count_zeros.h> -+ -+/* update the isr according to irq level and route irq to extioi */ -+static void pch_pic_update_irq(struct loongarch_pch_pic *s, int irq, int level) -+{ -+ u64 mask = (1 << irq); -+ -+ /* -+ * set isr and route irq to extioi and -+ * the route table is in htmsi_vector[] -+ */ -+ if (level) { -+ if (mask & s->irr & ~s->mask) { -+ s->isr |= mask; -+ irq = s->htmsi_vector[irq]; -+ extioi_set_irq(s->kvm->arch.extioi, irq, level); -+ } -+ } else { -+ if (mask & s->isr & ~s->irr) { -+ s->isr &= ~mask; -+ irq = s->htmsi_vector[irq]; -+ extioi_set_irq(s->kvm->arch.extioi, irq, level); -+ } -+ } -+} -+ -+/* msi irq handler */ -+void pch_msi_set_irq(struct kvm *kvm, int irq, int level) -+{ -+ extioi_set_irq(kvm->arch.extioi, irq, level); -+} -+ -+/* called when a irq is triggered in pch pic */ -+void pch_pic_set_irq(struct loongarch_pch_pic *s, int irq, int level) -+{ -+ u64 mask = (1 << irq); -+ -+ spin_lock(&s->lock); -+ if (level) -+ /* set irr */ -+ s->irr |= mask; -+ else { -+ /* 0 level signal in edge triggered irq does not mean to clear irq -+ * The irr register variable is cleared when the cpu writes to the -+ * PCH_PIC_CLEAR_START address area -+ */ -+ if (s->edge & mask) { -+ spin_unlock(&s->lock); -+ return; -+ } -+ s->irr &= ~mask; -+ } -+ pch_pic_update_irq(s, irq, level); -+ spin_unlock(&s->lock); -+} -+ -+/* update batch irqs, the irq_mask is a bitmap of irqs */ -+static void pch_pic_update_batch_irqs(struct loongarch_pch_pic *s, u64 irq_mask, int level) -+{ -+ int irq, bits; -+ -+ /* find each irq by irqs bitmap and update each irq */ -+ bits = sizeof(irq_mask) * 8; -+ irq = find_first_bit((void *)&irq_mask, bits); -+ while (irq < bits) { -+ pch_pic_update_irq(s, irq, level); -+ bitmap_clear((void *)&irq_mask, irq, 1); -+ irq = find_first_bit((void *)&irq_mask, bits); -+ } -+} -+ -+/* -+ * pch pic register is 64-bit, but it is accessed by 32-bit, -+ * so we use high to get whether low or high 32 bits we want -+ * to read. -+ */ -+static u32 pch_pic_read_reg(u64 *s, int high) -+{ -+ u64 val = *s; -+ -+ /* read the high 32 bits when the high is 1 */ -+ return high ? (u32)(val >> 32) : (u32)val; -+} -+ -+/* -+ * pch pic register is 64-bit, but it is accessed by 32-bit, -+ * so we use high to get whether low or high 32 bits we want -+ * to write. -+ */ -+static u32 pch_pic_write_reg(u64 *s, int high, u32 v) -+{ -+ u64 val = *s, data = v; -+ -+ if (high) { -+ /* -+ * Clear val high 32 bits -+ * write the high 32 bits when the high is 1 -+ */ -+ *s = (val << 32 >> 32) | (data << 32); -+ val >>= 32; -+ } else -+ /* -+ * Clear val low 32 bits -+ * write the low 32 bits when the high is 0 -+ */ -+ *s = (val >> 32 << 32) | v; -+ -+ return (u32)val; -+} -+ -+static int loongarch_pch_pic_write(struct loongarch_pch_pic *s, gpa_t addr, -+ int len, const void *val) -+{ -+ u32 old, data, offset, index; -+ u64 irq; -+ int ret; -+ -+ ret = 0; -+ data = *(u32 *)val; -+ offset = addr - s->pch_pic_base; -+ -+ spin_lock(&s->lock); -+ switch (offset) { -+ case PCH_PIC_MASK_START ... PCH_PIC_MASK_END: -+ offset -= PCH_PIC_MASK_START; -+ /* get whether high or low 32 bits we want to write */ -+ index = offset >> 2; -+ old = pch_pic_write_reg(&s->mask, index, data); -+ -+ /* enable irq when mask value change to 0 */ -+ irq = (old & ~data) << (32 * index); -+ pch_pic_update_batch_irqs(s, irq, 1); -+ -+ /* disable irq when mask value change to 1 */ -+ irq = (~old & data) << (32 * index); -+ pch_pic_update_batch_irqs(s, irq, 0); -+ break; -+ case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END: -+ offset -= PCH_PIC_HTMSI_EN_START; -+ index = offset >> 2; -+ pch_pic_write_reg(&s->htmsi_en, index, data); -+ break; -+ case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END: -+ offset -= PCH_PIC_EDGE_START; -+ index = offset >> 2; -+ /* 1: edge triggered, 0: level triggered */ -+ pch_pic_write_reg(&s->edge, index, data); -+ break; -+ case PCH_PIC_CLEAR_START ... PCH_PIC_CLEAR_END: -+ offset -= PCH_PIC_CLEAR_START; -+ index = offset >> 2; -+ /* write 1 to clear edge irq */ -+ old = pch_pic_read_reg(&s->irr, index); -+ /* -+ * get the irq bitmap which is edge triggered and -+ * already set and to be cleared -+ */ -+ irq = old & pch_pic_read_reg(&s->edge, index) & data; -+ /* write irr to the new state where irqs have been cleared */ -+ pch_pic_write_reg(&s->irr, index, old & ~irq); -+ /* update cleared irqs */ -+ pch_pic_update_batch_irqs(s, irq, 0); -+ break; -+ case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END: -+ offset -= PCH_PIC_AUTO_CTRL0_START; -+ index = offset >> 2; -+ /* we only use default mode: fixed interrupt distribution mode */ -+ pch_pic_write_reg(&s->auto_ctrl0, index, 0); -+ break; -+ case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END: -+ offset -= PCH_PIC_AUTO_CTRL1_START; -+ index = offset >> 2; -+ /* we only use default mode: fixed interrupt distribution mode */ -+ pch_pic_write_reg(&s->auto_ctrl1, index, 0); -+ break; -+ case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END: -+ offset -= PCH_PIC_ROUTE_ENTRY_START; -+ /* only route to int0: extioi */ -+ s->route_entry[offset] = 1; -+ break; -+ case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END: -+ /* route table to extioi */ -+ offset -= PCH_PIC_HTMSI_VEC_START; -+ s->htmsi_vector[offset] = (u8)data; -+ break; -+ case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END: -+ offset -= PCH_PIC_POLARITY_START; -+ index = offset >> 2; -+ -+ /* we only use defalut value 0: high level triggered */ -+ pch_pic_write_reg(&s->polarity, index, 0); -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ -+ spin_unlock(&s->lock); -+ return ret; -+} -+ -+static int kvm_loongarch_pch_pic_write(struct kvm_vcpu *vcpu, -+ struct kvm_io_device *dev, -+ gpa_t addr, int len, const void *val) -+{ -+ int ret; -+ struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic; -+ -+ if (!s) { -+ kvm_err("%s: pch pic irqchip not valid!\n", __func__); -+ return -EINVAL; -+ } -+ -+ /* statistics of pch pic writing */ -+ vcpu->kvm->stat.pch_pic_write_exits++; -+ ret = loongarch_pch_pic_write(s, addr, len, val); -+ -+ return ret; -+} -+ -+static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int len, void *val) -+{ -+ int offset, index, ret = 0; -+ u32 data = 0; -+ u64 int_id = 0; -+ -+ offset = addr - s->pch_pic_base; -+ -+ spin_lock(&s->lock); -+ switch (offset) { -+ case PCH_PIC_INT_ID_START ... PCH_PIC_INT_ID_END: -+ /* int id version */ -+ int_id |= (u64)PCH_PIC_INT_ID_VER << 32; -+ /* irq number */ -+ int_id |= (u64)31 << (32 + 16); -+ /* int id value */ -+ int_id |= PCH_PIC_INT_ID_VAL; -+ *(u64 *)val = int_id; -+ break; -+ case PCH_PIC_MASK_START ... PCH_PIC_MASK_END: -+ offset -= PCH_PIC_MASK_START; -+ index = offset >> 2; -+ /* read mask reg */ -+ data = pch_pic_read_reg(&s->mask, index); -+ *(u32 *)val = data; -+ break; -+ case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END: -+ offset -= PCH_PIC_HTMSI_EN_START; -+ index = offset >> 2; -+ /* read htmsi enable reg */ -+ data = pch_pic_read_reg(&s->htmsi_en, index); -+ *(u32 *)val = data; -+ break; -+ case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END: -+ offset -= PCH_PIC_EDGE_START; -+ index = offset >> 2; -+ /* read edge enable reg */ -+ data = pch_pic_read_reg(&s->edge, index); -+ *(u32 *)val = data; -+ break; -+ case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END: -+ case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END: -+ /* we only use default mode: fixed interrupt distribution mode */ -+ *(u32 *)val = 0; -+ break; -+ case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END: -+ /* only route to int0: extioi */ -+ *(u8 *)val = 1; -+ break; -+ case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END: -+ offset -= PCH_PIC_HTMSI_VEC_START; -+ /* read htmsi vector */ -+ data = s->htmsi_vector[offset]; -+ *(u8 *)val = data; -+ break; -+ case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END: -+ /* we only use defalut value 0: high level triggered */ -+ *(u32 *)val = 0; -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ spin_unlock(&s->lock); -+ return ret; -+} -+ -+static int kvm_loongarch_pch_pic_read(struct kvm_vcpu *vcpu, -+ struct kvm_io_device *dev, -+ gpa_t addr, int len, void *val) -+{ -+ int ret; -+ struct loongarch_pch_pic *s = vcpu->kvm->arch.pch_pic; -+ -+ if (!s) { -+ kvm_err("%s: pch pic irqchip not valid!\n", __func__); -+ return -EINVAL; -+ } -+ -+ /* statistics of pch pic reading */ -+ vcpu->kvm->stat.pch_pic_read_exits++; -+ ret = loongarch_pch_pic_read(s, addr, len, val); -+ return ret; -+} -+ -+static const struct kvm_io_device_ops kvm_loongarch_pch_pic_ops = { -+ .read = kvm_loongarch_pch_pic_read, -+ .write = kvm_loongarch_pch_pic_write, -+}; -+ -+static int kvm_loongarch_pch_pic_init(struct kvm_device *dev, u64 addr) -+{ -+ int ret; -+ struct loongarch_pch_pic *s = dev->kvm->arch.pch_pic; -+ struct kvm_io_device *device; -+ struct kvm *kvm = dev->kvm; -+ -+ s->pch_pic_base = addr; -+ device = &s->device; -+ /* init device by pch pic writing and reading ops */ -+ kvm_iodevice_init(device, &kvm_loongarch_pch_pic_ops); -+ mutex_lock(&kvm->slots_lock); -+ /* register pch pic device */ -+ ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, addr, PCH_PIC_SIZE, device); -+ mutex_unlock(&kvm->slots_lock); -+ if (ret < 0) -+ return -EFAULT; -+ -+ return 0; -+} -+ -+/* used by user space to get or set pch pic registers */ -+static int kvm_loongarch_pch_pic_regs_access(struct kvm_device *dev, -+ struct kvm_device_attr *attr, -+ bool is_write) -+{ -+ int addr, len = 8, ret = 0; -+ void __user *data; -+ void *p = NULL; -+ struct loongarch_pch_pic *s; -+ -+ s = dev->kvm->arch.pch_pic; -+ addr = attr->attr; -+ data = (void __user *)attr->addr; -+ -+ spin_lock(&s->lock); -+ /* get pointer to pch pic register by addr */ -+ switch (addr) { -+ case PCH_PIC_MASK_START: -+ p = &s->mask; -+ break; -+ case PCH_PIC_HTMSI_EN_START: -+ p = &s->htmsi_en; -+ break; -+ case PCH_PIC_EDGE_START: -+ p = &s->edge; -+ break; -+ case PCH_PIC_AUTO_CTRL0_START: -+ p = &s->auto_ctrl0; -+ break; -+ case PCH_PIC_AUTO_CTRL1_START: -+ p = &s->auto_ctrl1; -+ break; -+ case PCH_PIC_ROUTE_ENTRY_START: -+ p = s->route_entry; -+ len = 64; -+ break; -+ case PCH_PIC_HTMSI_VEC_START: -+ p = s->htmsi_vector; -+ len = 64; -+ break; -+ case PCH_PIC_INT_IRR_START: -+ p = &s->irr; -+ break; -+ case PCH_PIC_INT_ISR_START: -+ p = &s->isr; -+ break; -+ case PCH_PIC_POLARITY_START: -+ p = &s->polarity; -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ -+ /* write or read value according to is_write */ -+ if (is_write) { -+ if (copy_from_user(p, data, len)) -+ ret = -EFAULT; -+ } else { -+ if (copy_to_user(data, p, len)) -+ ret = -EFAULT; -+ } -+ -+ spin_unlock(&s->lock); -+ return ret; -+} -+ -+static int kvm_loongarch_pch_pic_get_attr(struct kvm_device *dev, -+ struct kvm_device_attr *attr) -+{ -+ /* only support pch pic group registers */ -+ if (attr->group == KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS) -+ return kvm_loongarch_pch_pic_regs_access(dev, attr, false); -+ -+ return -EINVAL; -+} -+ -+static int kvm_loongarch_pch_pic_set_attr(struct kvm_device *dev, -+ struct kvm_device_attr *attr) -+{ -+ int ret = -EINVAL; -+ u64 addr; -+ void __user *uaddr = (void __user *)(long)attr->addr; -+ -+ switch (attr->group) { -+ case KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL: -+ switch (attr->attr) { -+ case KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT: -+ if (copy_from_user(&addr, uaddr, sizeof(addr))) -+ return -EFAULT; -+ -+ if (!dev->kvm->arch.pch_pic) { -+ kvm_err("%s: please create pch_pic irqchip first!\n", __func__); -+ ret = -EFAULT; -+ break; -+ } -+ -+ ret = kvm_loongarch_pch_pic_init(dev, addr); -+ break; -+ default: -+ kvm_err("%s: unknown group (%d) attr (%lld)\n", __func__, attr->group, -+ attr->attr); -+ ret = -EINVAL; -+ break; -+ } -+ break; -+ case KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS: -+ ret = kvm_loongarch_pch_pic_regs_access(dev, attr, true); -+ break; -+ default: -+ break; -+ } -+ -+ return ret; -+} -+ -+static int kvm_setup_default_irq_routing(struct kvm *kvm) -+{ -+ struct kvm_irq_routing_entry *entries; -+ -+ u32 nr = KVM_IRQCHIP_NUM_PINS; -+ int i, ret; -+ -+ entries = kcalloc(nr, sizeof(*entries), GFP_KERNEL); -+ if (!entries) -+ return -ENOMEM; -+ -+ for (i = 0; i < nr; i++) { -+ entries[i].gsi = i; -+ entries[i].type = KVM_IRQ_ROUTING_IRQCHIP; -+ entries[i].u.irqchip.irqchip = 0; -+ entries[i].u.irqchip.pin = i; -+ } -+ ret = kvm_set_irq_routing(kvm, entries, nr, 0); -+ kfree(entries); -+ -+ return 0; -+} -+ -+static void kvm_loongarch_pch_pic_destroy(struct kvm_device *dev) -+{ -+ struct kvm *kvm; -+ struct loongarch_pch_pic *s; -+ struct kvm_io_device *device; -+ -+ if (!dev) -+ return; -+ -+ kvm = dev->kvm; -+ if (!kvm) -+ return; -+ -+ s = kvm->arch.pch_pic; -+ if (!s) -+ return; -+ -+ device = &s->device; -+ /* unregister pch pic device and free it's memory */ -+ kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, device); -+ kfree(s); -+} -+ -+static int kvm_loongarch_pch_pic_create(struct kvm_device *dev, u32 type) -+{ -+ int ret; -+ struct loongarch_pch_pic *s; -+ struct kvm *kvm = dev->kvm; -+ -+ /* pch pic should not has been created */ -+ if (kvm->arch.pch_pic) -+ return -EINVAL; -+ -+ ret = kvm_setup_default_irq_routing(kvm); -+ if (ret) -+ return -ENOMEM; -+ -+ s = kzalloc(sizeof(struct loongarch_pch_pic), GFP_KERNEL); -+ if (!s) -+ return -ENOMEM; -+ -+ spin_lock_init(&s->lock); -+ s->kvm = kvm; -+ -+ -+ kvm->arch.pch_pic = s; -+ -+ kvm_info("create pch pic device successfully\n"); -+ return 0; -+} -+ -+static struct kvm_device_ops kvm_loongarch_pch_pic_dev_ops = { -+ .name = "kvm-loongarch-pch-pic", -+ .create = kvm_loongarch_pch_pic_create, -+ .destroy = kvm_loongarch_pch_pic_destroy, -+ .set_attr = kvm_loongarch_pch_pic_set_attr, -+ .get_attr = kvm_loongarch_pch_pic_get_attr, -+}; -+ -+int kvm_loongarch_register_pch_pic_device(void) -+{ -+ return kvm_register_device_ops(&kvm_loongarch_pch_pic_dev_ops, -+ KVM_DEV_TYPE_LA_IOAPIC); -+} -diff --git a/arch/loongarch/kvm/irqfd.c b/arch/loongarch/kvm/irqfd.c -new file mode 100644 -index 0000000..bf67f32 ---- /dev/null -+++ b/arch/loongarch/kvm/irqfd.c -@@ -0,0 +1,87 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2024 Loongson Technology Corporation Limited -+ */ -+ -+#include <linux/kvm_host.h> -+#include <trace/events/kvm.h> -+#include <asm/kvm_pch_pic.h> -+ -+static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e, -+ struct kvm *kvm, int irq_source_id, -+ int level, bool line_status) -+{ -+ /* ioapic pin (0 ~ 64) <---> gsi(0 ~ 64) */ -+ pch_pic_set_irq(kvm->arch.pch_pic, e->irqchip.pin, level); -+ -+ return 0; -+} -+ -+/* -+ * kvm_set_routing_entry: populate a kvm routing entry -+ * from a user routing entry -+ * -+ * @kvm: the VM this entry is applied to -+ * @e: kvm kernel routing entry handle -+ * @ue: user api routing entry handle -+ * return 0 on success, -EINVAL on errors. -+ */ -+int kvm_set_routing_entry(struct kvm *kvm, -+ struct kvm_kernel_irq_routing_entry *e, -+ const struct kvm_irq_routing_entry *ue) -+{ -+ int r = -EINVAL; -+ -+ switch (ue->type) { -+ case KVM_IRQ_ROUTING_IRQCHIP: -+ e->set = kvm_set_ioapic_irq; -+ -+ e->irqchip.irqchip = ue->u.irqchip.irqchip; -+ e->irqchip.pin = ue->u.irqchip.pin; -+ -+ if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS) -+ goto out; -+ break; -+ case KVM_IRQ_ROUTING_MSI: -+ e->set = kvm_set_msi; -+ e->msi.address_lo = ue->u.msi.address_lo; -+ e->msi.address_hi = ue->u.msi.address_hi; -+ e->msi.data = ue->u.msi.data; -+ break; -+ default: -+ goto out; -+ } -+ r = 0; -+out: -+ return r; -+} -+ -+int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e, -+ struct kvm *kvm, int irq_source_id, -+ int level, bool line_status) -+{ -+ if (e->type == KVM_IRQ_ROUTING_MSI) { -+ pch_msi_set_irq(kvm, e->msi.data, 1); -+ return 0; -+ } -+ -+ return -EWOULDBLOCK; -+} -+ -+/** -+ * kvm_set_msi: inject the MSI corresponding to the -+ * MSI routing entry -+ * -+ * This is the entry point for irqfd MSI injection -+ * and userspace MSI injection. -+ */ -+int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, -+ struct kvm *kvm, int irq_source_id, -+ int level, bool line_status) -+{ -+ if (!level) -+ return -1; -+ -+ pch_msi_set_irq(kvm, e->msi.data, level); -+ return 0; -+} -diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c -index 844736b..1f50f67 100644 ---- a/arch/loongarch/kvm/main.c -+++ b/arch/loongarch/kvm/main.c -@@ -9,6 +9,8 @@ - #include <asm/cacheflush.h> - #include <asm/cpufeature.h> - #include <asm/kvm_csr.h> -+#include <asm/kvm_extioi.h> -+#include <asm/kvm_pch_pic.h> - #include "trace.h" - - unsigned long vpid_mask; -@@ -313,7 +315,7 @@ void kvm_arch_hardware_disable(void) - - static int kvm_loongarch_env_init(void) - { -- int cpu, order; -+ int cpu, order, ret; - void *addr; - struct kvm_context *context; - -@@ -368,7 +370,20 @@ static int kvm_loongarch_env_init(void) - - kvm_init_gcsr_flag(); - -- return 0; -+ /* Register loongarch ipi interrupt controller interface. */ -+ ret = kvm_loongarch_register_ipi_device(); -+ if (ret) -+ return ret; -+ -+ /* Register loongarch extioi interrupt controller interface. */ -+ ret = kvm_loongarch_register_extioi_device(); -+ if (ret) -+ return ret; -+ -+ /* Register loongarch pch pic interrupt controller interface. */ -+ ret = kvm_loongarch_register_pch_pic_device(); -+ -+ return ret; - } - - static void kvm_loongarch_env_exit(void) -diff --git a/arch/loongarch/kvm/mmu.c b/arch/loongarch/kvm/mmu.c -index bfcd123..df8403f 100644 ---- a/arch/loongarch/kvm/mmu.c -+++ b/arch/loongarch/kvm/mmu.c -@@ -758,7 +758,7 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, - if (pud_none(pud) || !pud_present(pud)) - goto out; - -- pmd = READ_ONCE(*pmd_offset(&pud, hva)); -+ pmd = pmdp_get(pmd_offset(&pud, hva)); - if (pmd_none(pmd) || !pmd_present(pmd)) - goto out; - -diff --git a/arch/loongarch/kvm/switch.S b/arch/loongarch/kvm/switch.S -index 80e9889..0c292f8 100644 ---- a/arch/loongarch/kvm/switch.S -+++ b/arch/loongarch/kvm/switch.S -@@ -277,6 +277,10 @@ SYM_DATA(kvm_enter_guest_size, .quad kvm_enter_guest_end - kvm_enter_guest) - - #ifdef CONFIG_CPU_HAS_LBT - STACK_FRAME_NON_STANDARD kvm_restore_fpu -+#ifdef CONFIG_CPU_HAS_LSX - STACK_FRAME_NON_STANDARD kvm_restore_lsx -+#endif -+#ifdef CONFIG_CPU_HAS_LASX - STACK_FRAME_NON_STANDARD kvm_restore_lasx - #endif -+#endif -diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c -index bcc6b6d..74a4b5c 100644 ---- a/arch/loongarch/kvm/timer.c -+++ b/arch/loongarch/kvm/timer.c -@@ -188,10 +188,3 @@ void kvm_save_timer(struct kvm_vcpu *vcpu) - kvm_save_hw_gcsr(csr, LOONGARCH_CSR_ESTAT); - preempt_enable(); - } -- --void kvm_reset_timer(struct kvm_vcpu *vcpu) --{ -- write_gcsr_timercfg(0); -- kvm_write_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TCFG, 0); -- hrtimer_cancel(&vcpu->arch.swtimer); --} -diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c -index bdfac8a..50bd40d 100644 ---- a/arch/loongarch/kvm/vcpu.c -+++ b/arch/loongarch/kvm/vcpu.c -@@ -6,6 +6,7 @@ - #include <linux/kvm_host.h> - #include <linux/entry-kvm.h> - #include <asm/fpu.h> -+#include <asm/lbt.h> - #include <asm/loongarch.h> - #include <asm/setup.h> - #include <asm/time.h> -@@ -31,63 +32,19 @@ const struct kvm_stats_header kvm_vcpu_stats_header = { - sizeof(kvm_vcpu_stats_desc), - }; - --static void kvm_update_stolen_time(struct kvm_vcpu *vcpu) --{ -- u32 version; -- u64 steal; -- gpa_t gpa; -- struct kvm_memslots *slots; -- struct kvm_steal_time __user *st; -- struct gfn_to_hva_cache *ghc; -- -- ghc = &vcpu->arch.st.cache; -- gpa = vcpu->arch.st.guest_addr; -- if (!(gpa & KVM_STEAL_PHYS_VALID)) -- return; -- -- gpa &= KVM_STEAL_PHYS_MASK; -- slots = kvm_memslots(vcpu->kvm); -- if (slots->generation != ghc->generation || gpa != ghc->gpa) { -- if (kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc, gpa, sizeof(*st))) { -- ghc->gpa = INVALID_GPA; -- return; -- } -- } -- -- st = (struct kvm_steal_time __user *)ghc->hva; -- unsafe_get_user(version, &st->version, out); -- if (version & 1) -- version += 1; /* first time write, random junk */ -- -- version += 1; -- unsafe_put_user(version, &st->version, out); -- smp_wmb(); -- -- unsafe_get_user(steal, &st->steal, out); -- steal += current->sched_info.run_delay - vcpu->arch.st.last_steal; -- vcpu->arch.st.last_steal = current->sched_info.run_delay; -- unsafe_put_user(steal, &st->steal, out); -- -- smp_wmb(); -- version += 1; -- unsafe_put_user(version, &st->version, out); --out: -- mark_page_dirty_in_slot(vcpu->kvm, ghc->memslot, gpa_to_gfn(ghc->gpa)); --} -- - static inline void kvm_save_host_pmu(struct kvm_vcpu *vcpu) - { - struct kvm_context *context; - - context = this_cpu_ptr(vcpu->kvm->arch.vmcs); -- context->perf_ctrl[0] = write_csr_perfctrl0(0); -- context->perf_ctrl[1] = write_csr_perfctrl1(0); -- context->perf_ctrl[2] = write_csr_perfctrl2(0); -- context->perf_ctrl[3] = write_csr_perfctrl3(0); - context->perf_cntr[0] = read_csr_perfcntr0(); - context->perf_cntr[1] = read_csr_perfcntr1(); - context->perf_cntr[2] = read_csr_perfcntr2(); - context->perf_cntr[3] = read_csr_perfcntr3(); -+ context->perf_ctrl[0] = write_csr_perfctrl0(0); -+ context->perf_ctrl[1] = write_csr_perfctrl1(0); -+ context->perf_ctrl[2] = write_csr_perfctrl2(0); -+ context->perf_ctrl[3] = write_csr_perfctrl3(0); - } - - static inline void kvm_restore_host_pmu(struct kvm_vcpu *vcpu) -@@ -105,18 +62,19 @@ static inline void kvm_restore_host_pmu(struct kvm_vcpu *vcpu) - write_csr_perfctrl3(context->perf_ctrl[3]); - } - -+ - static inline void kvm_save_guest_pmu(struct kvm_vcpu *vcpu) - { - struct loongarch_csrs *csr = vcpu->arch.csr; - -- kvm_read_clear_hw_gcsr(csr, LOONGARCH_CSR_PERFCTRL0); -- kvm_read_clear_hw_gcsr(csr, LOONGARCH_CSR_PERFCTRL1); -- kvm_read_clear_hw_gcsr(csr, LOONGARCH_CSR_PERFCTRL2); -- kvm_read_clear_hw_gcsr(csr, LOONGARCH_CSR_PERFCTRL3); - kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PERFCNTR0); - kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PERFCNTR1); - kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PERFCNTR2); - kvm_save_hw_gcsr(csr, LOONGARCH_CSR_PERFCNTR3); -+ kvm_read_clear_hw_gcsr(csr, LOONGARCH_CSR_PERFCTRL0); -+ kvm_read_clear_hw_gcsr(csr, LOONGARCH_CSR_PERFCTRL1); -+ kvm_read_clear_hw_gcsr(csr, LOONGARCH_CSR_PERFCTRL2); -+ kvm_read_clear_hw_gcsr(csr, LOONGARCH_CSR_PERFCTRL3); - } - - static inline void kvm_restore_guest_pmu(struct kvm_vcpu *vcpu) -@@ -133,70 +91,109 @@ static inline void kvm_restore_guest_pmu(struct kvm_vcpu *vcpu) - kvm_restore_hw_gcsr(csr, LOONGARCH_CSR_PERFCTRL3); - } - -+static int kvm_own_pmu(struct kvm_vcpu *vcpu) -+{ -+ unsigned long val; -+ -+ if (!kvm_guest_has_pmu(&vcpu->arch)) -+ return -EINVAL; -+ -+ kvm_save_host_pmu(vcpu); -+ -+ /* Set PM0-PM(num) to guest */ -+ val = read_csr_gcfg() & ~CSR_GCFG_GPERF; -+ val |= (kvm_get_pmu_num(&vcpu->arch) + 1) << CSR_GCFG_GPERF_SHIFT; -+ write_csr_gcfg(val); -+ -+ kvm_restore_guest_pmu(vcpu); -+ -+ return 0; -+} -+ - static void kvm_lose_pmu(struct kvm_vcpu *vcpu) - { - unsigned long val; - struct loongarch_csrs *csr = vcpu->arch.csr; - -- if (!(vcpu->arch.aux_inuse & KVM_GUEST_PMU_ENABLE)) -- return; -- if (!(vcpu->arch.aux_inuse & KVM_GUEST_PMU_ACTIVE)) -+ if (!(vcpu->arch.aux_inuse & KVM_LARCH_PMU)) - return; - - kvm_save_guest_pmu(vcpu); -+ - /* Disable pmu access from guest */ - write_csr_gcfg(read_csr_gcfg() & ~CSR_GCFG_GPERF); - - /* -- * Clear KVM_GUEST_PMU_ENABLE if the guest is not using PMU CSRs -- * when exiting the guest, so that the next time trap into the guest. -- * we don't need to deal with PMU CSRs contexts. -+ * Clear KVM_LARCH_PMU if the guest is not using PMU CSRs when -+ * exiting the guest, so that the next time trap into the guest. -+ * We don't need to deal with PMU CSRs contexts. - */ - val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL0); - val |= kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL1); - val |= kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL2); - val |= kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL3); - if (!(val & KVM_PMU_EVENT_ENABLED)) -- vcpu->arch.aux_inuse &= ~KVM_GUEST_PMU_ENABLE; -- kvm_restore_host_pmu(vcpu); -+ vcpu->arch.aux_inuse &= ~KVM_LARCH_PMU; - -- /* KVM_GUEST_PMU_ACTIVE needs to be cleared when exiting the guest */ -- vcpu->arch.aux_inuse &= ~KVM_GUEST_PMU_ACTIVE; -+ kvm_restore_host_pmu(vcpu); - } - --static void kvm_own_pmu(struct kvm_vcpu *vcpu) -+static void kvm_restore_pmu(struct kvm_vcpu *vcpu) - { -- unsigned long val; -- -- kvm_save_host_pmu(vcpu); -- /* Set PM0-PM(num) to guest */ -- val = read_csr_gcfg() & ~CSR_GCFG_GPERF; -- val |= (kvm_get_pmu_num(&vcpu->arch) + 1) << CSR_GCFG_GPERF_SHIFT; -- write_csr_gcfg(val); -- kvm_restore_guest_pmu(vcpu); -+ if ((vcpu->arch.aux_inuse & KVM_LARCH_PMU)) -+ kvm_make_request(KVM_REQ_PMU, vcpu); - } - --static void kvm_restore_pmu(struct kvm_vcpu *vcpu) -+static void kvm_check_pmu(struct kvm_vcpu *vcpu) - { -- if (!(vcpu->arch.aux_inuse & KVM_GUEST_PMU_ENABLE)) -- return; -- -- kvm_make_request(KVM_REQ_PMU, vcpu); -+ if (kvm_check_request(KVM_REQ_PMU, vcpu)) { -+ kvm_own_pmu(vcpu); -+ vcpu->arch.aux_inuse |= KVM_LARCH_PMU; -+ } - } - --static void kvm_check_pmu(struct kvm_vcpu *vcpu) -+static void kvm_update_stolen_time(struct kvm_vcpu *vcpu) - { -- if (!kvm_check_request(KVM_REQ_PMU, vcpu)) -+ u32 version; -+ u64 steal; -+ gpa_t gpa; -+ struct kvm_memslots *slots; -+ struct kvm_steal_time __user *st; -+ struct gfn_to_hva_cache *ghc; -+ -+ ghc = &vcpu->arch.st.cache; -+ gpa = vcpu->arch.st.guest_addr; -+ if (!(gpa & KVM_STEAL_PHYS_VALID)) - return; - -- kvm_own_pmu(vcpu); -+ gpa &= KVM_STEAL_PHYS_MASK; -+ slots = kvm_memslots(vcpu->kvm); -+ if (slots->generation != ghc->generation || gpa != ghc->gpa) { -+ if (kvm_gfn_to_hva_cache_init(vcpu->kvm, ghc, gpa, sizeof(*st))) { -+ ghc->gpa = INVALID_GPA; -+ return; -+ } -+ } - -- /* -- * Set KVM_GUEST PMU_ENABLE and GUEST_PMU_ACTIVE -- * when guest has KVM_REQ_PMU request. -- */ -- vcpu->arch.aux_inuse |= KVM_GUEST_PMU_ENABLE; -- vcpu->arch.aux_inuse |= KVM_GUEST_PMU_ACTIVE; -+ st = (struct kvm_steal_time __user *)ghc->hva; -+ unsafe_get_user(version, &st->version, out); -+ if (version & 1) -+ version += 1; /* first time write, random junk */ -+ -+ version += 1; -+ unsafe_put_user(version, &st->version, out); -+ smp_wmb(); -+ -+ unsafe_get_user(steal, &st->steal, out); -+ steal += current->sched_info.run_delay - vcpu->arch.st.last_steal; -+ vcpu->arch.st.last_steal = current->sched_info.run_delay; -+ unsafe_put_user(steal, &st->steal, out); -+ -+ smp_wmb(); -+ version += 1; -+ unsafe_put_user(version, &st->version, out); -+out: -+ mark_page_dirty_in_slot(vcpu->kvm, ghc->memslot, gpa_to_gfn(ghc->gpa)); - } - - /* -@@ -602,10 +599,11 @@ static int _kvm_setcsr(struct kvm_vcpu *vcpu, unsigned int id, u64 val) - if (id >= LOONGARCH_CSR_PERFCTRL0 && id <= LOONGARCH_CSR_PERFCNTR3) { - unsigned long val; - -- val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL0); -- val |= kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL1); -- val |= kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL2); -- val |= kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL3); -+ val = kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL0) | -+ kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL1) | -+ kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL2) | -+ kvm_read_sw_gcsr(csr, LOONGARCH_CSR_PERFCTRL3); -+ - if (val & KVM_PMU_EVENT_ENABLED) - kvm_make_request(KVM_REQ_PMU, vcpu); - } -@@ -639,6 +637,12 @@ static int _kvm_get_cpucfg_mask(int id, u64 *v) - *v |= CPUCFG2_LSX; - if (cpu_has_lasx) - *v |= CPUCFG2_LASX; -+ if (cpu_has_lbt_x86) -+ *v |= CPUCFG2_X86BT; -+ if (cpu_has_lbt_arm) -+ *v |= CPUCFG2_ARMBT; -+ if (cpu_has_lbt_mips) -+ *v |= CPUCFG2_MIPSBT; - - return 0; - case LOONGARCH_CPUCFG3: -@@ -672,7 +676,7 @@ static int _kvm_get_cpucfg_mask(int id, u64 *v) - - static int kvm_check_cpucfg(int id, u64 val) - { -- int ret, host; -+ int ret; - u64 mask = 0; - - ret = _kvm_get_cpucfg_mask(id, &mask); -@@ -700,9 +704,8 @@ static int kvm_check_cpucfg(int id, u64 val) - return 0; - case LOONGARCH_CPUCFG6: - if (val & CPUCFG6_PMP) { -- host = read_cpucfg(LOONGARCH_CPUCFG6); -+ u32 host = read_cpucfg(LOONGARCH_CPUCFG6); - if ((val & CPUCFG6_PMBITS) != (host & CPUCFG6_PMBITS)) -- /* Guest pmbits must be the same with host */ - return -EINVAL; - if ((val & CPUCFG6_PMNUM) > (host & CPUCFG6_PMNUM)) - return -EINVAL; -@@ -737,6 +740,34 @@ static int kvm_get_one_reg(struct kvm_vcpu *vcpu, - else - ret = -EINVAL; - break; -+ case KVM_REG_LOONGARCH_LBT: -+ if (!kvm_guest_has_lbt(&vcpu->arch)) -+ return -ENXIO; -+ -+ switch (reg->id) { -+ case KVM_REG_LOONGARCH_LBT_SCR0: -+ *v = vcpu->arch.lbt.scr0; -+ break; -+ case KVM_REG_LOONGARCH_LBT_SCR1: -+ *v = vcpu->arch.lbt.scr1; -+ break; -+ case KVM_REG_LOONGARCH_LBT_SCR2: -+ *v = vcpu->arch.lbt.scr2; -+ break; -+ case KVM_REG_LOONGARCH_LBT_SCR3: -+ *v = vcpu->arch.lbt.scr3; -+ break; -+ case KVM_REG_LOONGARCH_LBT_EFLAGS: -+ *v = vcpu->arch.lbt.eflags; -+ break; -+ case KVM_REG_LOONGARCH_LBT_FTOP: -+ *v = vcpu->arch.fpu.ftop; -+ break; -+ default: -+ ret = -EINVAL; -+ break; -+ } -+ break; - case KVM_REG_LOONGARCH_KVM: - switch (reg->id) { - case KVM_REG_LOONGARCH_COUNTER: -@@ -795,9 +826,36 @@ static int kvm_set_one_reg(struct kvm_vcpu *vcpu, - if (ret) - break; - vcpu->arch.cpucfg[id] = (u32)v; -- if (id == LOONGARCH_CPUCFG6) { -- vcpu->arch.max_pmu_csrid = LOONGARCH_CSR_PERFCTRL0 + -- 2 * kvm_get_pmu_num(&vcpu->arch) + 1; -+ if (id == LOONGARCH_CPUCFG6) -+ vcpu->arch.max_pmu_csrid = -+ LOONGARCH_CSR_PERFCTRL0 + 2 * kvm_get_pmu_num(&vcpu->arch) + 1; -+ break; -+ case KVM_REG_LOONGARCH_LBT: -+ if (!kvm_guest_has_lbt(&vcpu->arch)) -+ return -ENXIO; -+ -+ switch (reg->id) { -+ case KVM_REG_LOONGARCH_LBT_SCR0: -+ vcpu->arch.lbt.scr0 = v; -+ break; -+ case KVM_REG_LOONGARCH_LBT_SCR1: -+ vcpu->arch.lbt.scr1 = v; -+ break; -+ case KVM_REG_LOONGARCH_LBT_SCR2: -+ vcpu->arch.lbt.scr2 = v; -+ break; -+ case KVM_REG_LOONGARCH_LBT_SCR3: -+ vcpu->arch.lbt.scr3 = v; -+ break; -+ case KVM_REG_LOONGARCH_LBT_EFLAGS: -+ vcpu->arch.lbt.eflags = v; -+ break; -+ case KVM_REG_LOONGARCH_LBT_FTOP: -+ vcpu->arch.fpu.ftop = v; -+ break; -+ default: -+ ret = -EINVAL; -+ break; - } - break; - case KVM_REG_LOONGARCH_KVM: -@@ -811,7 +869,9 @@ static int kvm_set_one_reg(struct kvm_vcpu *vcpu, - vcpu->kvm->arch.time_offset = (signed long)(v - drdtime()); - break; - case KVM_REG_LOONGARCH_VCPU_RESET: -- kvm_reset_timer(vcpu); -+ vcpu->arch.st.guest_addr = 0; -+ if (vcpu->vcpu_id == 0) -+ kvm_loongarch_reset_extioi(vcpu->kvm); - memset(&vcpu->arch.irq_pending, 0, sizeof(vcpu->arch.irq_pending)); - memset(&vcpu->arch.irq_clear, 0, sizeof(vcpu->arch.irq_clear)); - break; -@@ -895,6 +955,8 @@ static int kvm_loongarch_cpucfg_has_attr(struct kvm_vcpu *vcpu, - case LOONGARCH_CPUCFG2: - case LOONGARCH_CPUCFG6: - return 0; -+ case CPUCFG_KVM_FEATURE: -+ return 0; - default: - return -ENXIO; - } -@@ -905,8 +967,8 @@ static int kvm_loongarch_cpucfg_has_attr(struct kvm_vcpu *vcpu, - static int kvm_loongarch_pvtime_has_attr(struct kvm_vcpu *vcpu, - struct kvm_device_attr *attr) - { -- if (!kvm_pvtime_supported() || -- attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA) -+ if (!kvm_guest_has_pv_feature(vcpu, KVM_FEATURE_STEAL_TIME) -+ || attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA) - return -ENXIO; - - return 0; -@@ -938,9 +1000,18 @@ static int kvm_loongarch_cpucfg_get_attr(struct kvm_vcpu *vcpu, - uint64_t val; - uint64_t __user *uaddr = (uint64_t __user *)attr->addr; - -- ret = _kvm_get_cpucfg_mask(attr->attr, &val); -- if (ret) -- return ret; -+ switch (attr->attr) { -+ case 0 ... (KVM_MAX_CPUCFG_REGS - 1): -+ ret = _kvm_get_cpucfg_mask(attr->attr, &val); -+ if (ret) -+ return ret; -+ break; -+ case CPUCFG_KVM_FEATURE: -+ val = vcpu->kvm->arch.pv_features & LOONGARCH_PV_FEAT_MASK; -+ break; -+ default: -+ return -ENXIO; -+ } - - put_user(val, uaddr); - -@@ -953,8 +1024,8 @@ static int kvm_loongarch_pvtime_get_attr(struct kvm_vcpu *vcpu, - u64 gpa; - u64 __user *user = (u64 __user *)attr->addr; - -- if (!kvm_pvtime_supported() || -- attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA) -+ if (!kvm_guest_has_pv_feature(vcpu, KVM_FEATURE_STEAL_TIME) -+ || attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA) - return -ENXIO; - - gpa = vcpu->arch.st.guest_addr; -@@ -986,7 +1057,28 @@ static int kvm_loongarch_vcpu_get_attr(struct kvm_vcpu *vcpu, - static int kvm_loongarch_cpucfg_set_attr(struct kvm_vcpu *vcpu, - struct kvm_device_attr *attr) - { -- return -ENXIO; -+ u64 val, valid; -+ u64 __user *user = (u64 __user *)attr->addr; -+ struct kvm *kvm = vcpu->kvm; -+ -+ switch (attr->attr) { -+ case CPUCFG_KVM_FEATURE: -+ if (get_user(val, user)) -+ return -EFAULT; -+ -+ valid = LOONGARCH_PV_FEAT_MASK; -+ if (val & ~valid) -+ return -EINVAL; -+ -+ /* All vCPUs need set the same PV features */ -+ if ((kvm->arch.pv_features & LOONGARCH_PV_FEAT_UPDATED) -+ && ((kvm->arch.pv_features & valid) != val)) -+ return -EINVAL; -+ kvm->arch.pv_features = val | LOONGARCH_PV_FEAT_UPDATED; -+ return 0; -+ default: -+ return -ENXIO; -+ } - } - - static int kvm_loongarch_pvtime_set_attr(struct kvm_vcpu *vcpu, -@@ -996,8 +1088,8 @@ static int kvm_loongarch_pvtime_set_attr(struct kvm_vcpu *vcpu, - u64 gpa, __user *user = (u64 __user *)attr->addr; - struct kvm *kvm = vcpu->kvm; - -- if (!kvm_pvtime_supported() || -- attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA) -+ if (!kvm_guest_has_pv_feature(vcpu, KVM_FEATURE_STEAL_TIME) -+ || attr->attr != KVM_LOONGARCH_VCPU_PVTIME_GPA) - return -ENXIO; - - if (get_user(gpa, user)) -@@ -1142,12 +1234,66 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) - return 0; - } - -+#ifdef CONFIG_CPU_HAS_LBT -+int kvm_own_lbt(struct kvm_vcpu *vcpu) -+{ -+ if (!kvm_guest_has_lbt(&vcpu->arch)) -+ return -EINVAL; -+ -+ preempt_disable(); -+ set_csr_euen(CSR_EUEN_LBTEN); -+ _restore_lbt(&vcpu->arch.lbt); -+ vcpu->arch.aux_inuse |= KVM_LARCH_LBT; -+ preempt_enable(); -+ -+ return 0; -+} -+ -+static void kvm_lose_lbt(struct kvm_vcpu *vcpu) -+{ -+ preempt_disable(); -+ if (vcpu->arch.aux_inuse & KVM_LARCH_LBT) { -+ _save_lbt(&vcpu->arch.lbt); -+ clear_csr_euen(CSR_EUEN_LBTEN); -+ vcpu->arch.aux_inuse &= ~KVM_LARCH_LBT; -+ } -+ preempt_enable(); -+} -+ -+static void kvm_check_fcsr(struct kvm_vcpu *vcpu, unsigned long fcsr) -+{ -+ /* -+ * If TM is enabled, top register save/restore will -+ * cause lbt exception, here enable lbt in advance -+ */ -+ if (fcsr & FPU_CSR_TM) -+ kvm_own_lbt(vcpu); -+} -+ -+static void kvm_check_fcsr_alive(struct kvm_vcpu *vcpu) -+{ -+ if (vcpu->arch.aux_inuse & KVM_LARCH_FPU) { -+ if (vcpu->arch.aux_inuse & KVM_LARCH_LBT) -+ return; -+ kvm_check_fcsr(vcpu, read_fcsr(LOONGARCH_FCSR0)); -+ } -+} -+#else -+static inline void kvm_lose_lbt(struct kvm_vcpu *vcpu) { } -+static inline void kvm_check_fcsr(struct kvm_vcpu *vcpu, unsigned long fcsr) { } -+static inline void kvm_check_fcsr_alive(struct kvm_vcpu *vcpu) { } -+#endif -+ - /* Enable FPU and restore context */ - void kvm_own_fpu(struct kvm_vcpu *vcpu) - { - preempt_disable(); - -- /* Enable FPU */ -+ /* -+ * Enable FPU for guest -+ * Set FR and FRE according to guest context -+ */ -+ kvm_check_fcsr(vcpu, vcpu->arch.fpu.fcsr); - set_csr_euen(CSR_EUEN_FPEN); - - kvm_restore_fpu(&vcpu->arch.fpu); -@@ -1167,6 +1313,7 @@ int kvm_own_lsx(struct kvm_vcpu *vcpu) - preempt_disable(); - - /* Enable LSX for guest */ -+ kvm_check_fcsr(vcpu, vcpu->arch.fpu.fcsr); - set_csr_euen(CSR_EUEN_LSXEN | CSR_EUEN_FPEN); - switch (vcpu->arch.aux_inuse & KVM_LARCH_FPU) { - case KVM_LARCH_FPU: -@@ -1201,6 +1348,7 @@ int kvm_own_lasx(struct kvm_vcpu *vcpu) - - preempt_disable(); - -+ kvm_check_fcsr(vcpu, vcpu->arch.fpu.fcsr); - set_csr_euen(CSR_EUEN_FPEN | CSR_EUEN_LSXEN | CSR_EUEN_LASXEN); - switch (vcpu->arch.aux_inuse & (KVM_LARCH_FPU | KVM_LARCH_LSX)) { - case KVM_LARCH_LSX: -@@ -1232,6 +1380,7 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu) - { - preempt_disable(); - -+ kvm_check_fcsr_alive(vcpu); - if (vcpu->arch.aux_inuse & KVM_LARCH_LASX) { - kvm_save_lasx(&vcpu->arch.fpu); - vcpu->arch.aux_inuse &= ~(KVM_LARCH_LSX | KVM_LARCH_FPU | KVM_LARCH_LASX); -@@ -1254,6 +1403,7 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu) - /* Disable FPU */ - clear_csr_euen(CSR_EUEN_FPEN); - } -+ kvm_lose_lbt(vcpu); - - preempt_enable(); - } -@@ -1327,6 +1477,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) - /* Init */ - vcpu->arch.last_sched_cpu = -1; - -+ /* Init ipi_state lock */ -+ spin_lock_init(&vcpu->arch.ipi_state.lock); -+ - /* - * Initialize guest register state to valid architectural reset state. - */ -diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c -index 6b2e4f6..e7e43e6 100644 ---- a/arch/loongarch/kvm/vm.c -+++ b/arch/loongarch/kvm/vm.c -@@ -5,6 +5,9 @@ - - #include <linux/kvm_host.h> - #include <asm/kvm_mmu.h> -+#include <asm/kvm_vcpu.h> -+#include <asm/kvm_extioi.h> -+#include <asm/kvm_pch_pic.h> - - const struct _kvm_stats_desc kvm_vm_stats_desc[] = { - KVM_GENERIC_VM_STATS(), -@@ -39,6 +42,12 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) - spin_lock_init(&kvm->arch.phyid_map_lock); - - kvm_init_vmcs(kvm); -+ -+ /* Enable all PV features by default */ -+ kvm->arch.pv_features = BIT(KVM_FEATURE_IPI); -+ if (kvm_pvtime_supported()) -+ kvm->arch.pv_features |= BIT(KVM_FEATURE_STEAL_TIME); -+ - kvm->arch.gpa_size = BIT(cpu_vabits - 1); - kvm->arch.root_level = CONFIG_PGTABLE_LEVELS - 1; - kvm->arch.invalid_ptes[0] = 0; -@@ -69,6 +78,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) - int r; - - switch (ext) { -+ case KVM_CAP_IRQCHIP: - case KVM_CAP_ONE_REG: - case KVM_CAP_ENABLE_CAP: - case KVM_CAP_READONLY_MEM: -@@ -77,6 +87,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) - case KVM_CAP_IOEVENTFD: - case KVM_CAP_MP_STATE: - case KVM_CAP_SET_GUEST_DEBUG: -+ case KVM_CAP_VM_ATTRIBUTES: - r = 1; - break; - case KVM_CAP_NR_VCPUS: -@@ -99,7 +110,114 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) - return r; - } - -+static int kvm_vm_feature_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) -+{ -+ switch (attr->attr) { -+ case KVM_LOONGARCH_VM_FEAT_LSX: -+ if (cpu_has_lsx) -+ return 0; -+ return -ENXIO; -+ case KVM_LOONGARCH_VM_FEAT_LASX: -+ if (cpu_has_lasx) -+ return 0; -+ return -ENXIO; -+ case KVM_LOONGARCH_VM_FEAT_X86BT: -+ if (cpu_has_lbt_x86) -+ return 0; -+ return -ENXIO; -+ case KVM_LOONGARCH_VM_FEAT_ARMBT: -+ if (cpu_has_lbt_arm) -+ return 0; -+ return -ENXIO; -+ case KVM_LOONGARCH_VM_FEAT_MIPSBT: -+ if (cpu_has_lbt_mips) -+ return 0; -+ return -ENXIO; -+ case KVM_LOONGARCH_VM_FEAT_PMU: -+ if (cpu_has_pmp) -+ return 0; -+ return -ENXIO; -+ case KVM_LOONGARCH_VM_FEAT_PV_IPI: -+ return 0; -+ case KVM_LOONGARCH_VM_FEAT_PV_STEALTIME: -+ if (kvm_pvtime_supported()) -+ return 0; -+ return -ENXIO; -+ default: -+ return -ENXIO; -+ } -+} -+ -+static int kvm_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) -+{ -+ switch (attr->group) { -+ case KVM_LOONGARCH_VM_FEAT_CTRL: -+ return kvm_vm_feature_has_attr(kvm, attr); -+ case KVM_LOONGARCH_VM_HAVE_IRQCHIP: -+ return 0; -+ default: -+ return -ENXIO; -+ } -+} -+ - int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) - { -- return -ENOIOCTLCMD; -+ int r; -+ void __user *argp = (void __user *)arg; -+ struct kvm *kvm = filp->private_data; -+ struct kvm_device_attr attr; -+ -+ switch (ioctl) { -+ case KVM_CREATE_IRQCHIP: { -+ r = 1; -+ break; -+ } -+ case KVM_HAS_DEVICE_ATTR: { -+ if (copy_from_user(&attr, argp, sizeof(attr))) -+ return -EFAULT; -+ -+ return kvm_vm_has_attr(kvm, &attr); -+ } -+ default: -+ return -EINVAL; -+ } -+ -+ return r; -+} -+ -+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *data, -+ bool line_status) -+{ -+ bool level; -+ struct loongarch_pch_pic *s; -+ int type, vcpu, irq, vcpus, val, ret = 0; -+ -+ level = data->level; -+ val = data->irq; -+ s = kvm->arch.pch_pic; -+ vcpus = atomic_read(&kvm->online_vcpus); -+ -+ type = (val >> KVM_LOONGARCH_IRQ_TYPE_SHIFT) & KVM_LOONGARCH_IRQ_TYPE_MASK; -+ vcpu = (val >> KVM_LOONGARCH_IRQ_VCPU_SHIFT) & KVM_LOONGARCH_IRQ_VCPU_MASK; -+ irq = (val >> KVM_LOONGARCH_IRQ_NUM_SHIFT) & KVM_LOONGARCH_IRQ_NUM_MASK; -+ -+ switch (type) { -+ case KVM_LOONGARCH_IRQ_TYPE_IOAPIC: -+ if (irq < KVM_IRQCHIP_NUM_PINS) -+ pch_pic_set_irq(s, irq, level); -+ else if (irq < 256) -+ pch_msi_set_irq(kvm, irq, level); -+ else -+ ret = -EINVAL; -+ break; -+ default: -+ ret = -EINVAL; -+ } -+ -+ return ret; -+} -+ -+bool kvm_arch_irqchip_in_kernel(struct kvm *kvm) -+{ -+ return (bool)((!!kvm->arch.extioi) && (!!kvm->arch.pch_pic)); - } -diff --git a/arch/loongarch/mm/cache.c b/arch/loongarch/mm/cache.c -index 6be04d3..e278b8c68 100644 ---- a/arch/loongarch/mm/cache.c -+++ b/arch/loongarch/mm/cache.c -@@ -63,6 +63,28 @@ static void flush_cache_leaf(unsigned int leaf) - } while (--nr_nodes > 0); - } - -+static void flush_cache_last_level(unsigned int leaf) -+{ -+ u64 addr; -+ int i, j, nr_nodes, way_size; -+ struct cache_desc *cdesc = current_cpu_data.cache_leaves + leaf; -+ -+ nr_nodes = loongson_sysconf.nr_nodes; -+ -+ addr = CSR_DMW1_BASE; -+ iocsr_write8(0x1, 0x280); -+ way_size = cdesc->sets * cdesc->linesz; -+ do { -+ for (i = 0; i < (cdesc->ways * 3); i++) { -+ for (j = 0; j < (cdesc->sets); j++) { -+ *(volatile u32 *)addr; -+ addr += cdesc->linesz; -+ } -+ } -+ addr += 0x100000000000; -+ } while (--nr_nodes > 0); -+} -+ - asmlinkage __visible void __flush_cache_all(void) - { - int leaf; -@@ -71,7 +93,7 @@ asmlinkage __visible void __flush_cache_all(void) - - leaf = cache_present - 1; - if (cache_inclusive(cdesc + leaf)) { -- flush_cache_leaf(leaf); -+ flush_cache_last_level(leaf); - return; - } - -diff --git a/arch/loongarch/mm/fault.c b/arch/loongarch/mm/fault.c -index 97b40de..d4a5703 100644 ---- a/arch/loongarch/mm/fault.c -+++ b/arch/loongarch/mm/fault.c -@@ -31,11 +31,52 @@ - - int show_unhandled_signals = 1; - -+static int __kprobes spurious_fault(unsigned long write, unsigned long address) -+{ -+ pgd_t *pgd; -+ p4d_t *p4d; -+ pud_t *pud; -+ pmd_t *pmd; -+ pte_t *pte; -+ -+ if (!(address & __UA_LIMIT)) -+ return 0; -+ -+ pgd = pgd_offset_k(address); -+ if (!pgd_present(*pgd)) -+ return 0; -+ -+ p4d = p4d_offset(pgd, address); -+ if (!p4d_present(*p4d)) -+ return 0; -+ -+ pud = pud_offset(p4d, address); -+ if (!pud_present(*pud)) -+ return 0; -+ -+ pmd = pmd_offset(pud, address); -+ if (!pmd_present(pmdp_get(pmd))) -+ return 0; -+ -+ if (pmd_leaf(*pmd)) { -+ return write ? pmd_write(pmdp_get(pmd)) : 1; -+ } else { -+ pte = pte_offset_kernel(pmd, address); -+ if (!pte_present(ptep_get(pte))) -+ return 0; -+ -+ return write ? pte_write(ptep_get(pte)) : 1; -+ } -+} -+ - static void __kprobes no_context(struct pt_regs *regs, - unsigned long write, unsigned long address) - { - const int field = sizeof(unsigned long) * 2; - -+ if (spurious_fault(write, address)) -+ return; -+ - /* Are we prepared to handle this kernel fault? */ - if (fixup_exception(regs)) - return; -diff --git a/arch/loongarch/mm/init.c b/arch/loongarch/mm/init.c -index 4dd5342..4cfcfc2 100644 ---- a/arch/loongarch/mm/init.c -+++ b/arch/loongarch/mm/init.c -@@ -140,7 +140,7 @@ void __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node, - int __meminit vmemmap_check_pmd(pmd_t *pmd, int node, - unsigned long addr, unsigned long next) - { -- int huge = pmd_val(*pmd) & _PAGE_HUGE; -+ int huge = pmd_val(pmdp_get(pmd)) & _PAGE_HUGE; - - if (huge) - vmemmap_verify((pte_t *)pmd, node, addr, next); -@@ -194,13 +194,15 @@ pte_t * __init populate_kernel_pte(unsigned long addr) - } - - pmd = pmd_offset(pud, addr); -- if (!pmd_present(*pmd)) { -+ if (!pmd_present(pmdp_get(pmd))) { - pte_t *pte; - - pte = memblock_alloc(PAGE_SIZE, PAGE_SIZE); - if (!pte) - panic("%s: Failed to allocate memory\n", __func__); -+ - pmd_populate_kernel(&init_mm, pmd, pte); -+ kernel_pte_init(pte); - } - - return pte_offset_kernel(pmd, addr); -@@ -215,7 +217,7 @@ void __init __set_fixmap(enum fixed_addresses idx, - BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses); - - ptep = populate_kernel_pte(addr); -- if (!pte_none(*ptep)) { -+ if (!pte_none(ptep_get(ptep))) { - pte_ERROR(*ptep); - return; - } -diff --git a/arch/loongarch/mm/kasan_init.c b/arch/loongarch/mm/kasan_init.c -index c608adc..831be7e 100644 ---- a/arch/loongarch/mm/kasan_init.c -+++ b/arch/loongarch/mm/kasan_init.c -@@ -105,7 +105,7 @@ static phys_addr_t __init kasan_alloc_zeroed_page(int node) - - static pte_t *__init kasan_pte_offset(pmd_t *pmdp, unsigned long addr, int node, bool early) - { -- if (__pmd_none(early, READ_ONCE(*pmdp))) { -+ if (__pmd_none(early, pmdp_get(pmdp))) { - phys_addr_t pte_phys = early ? - __pa_symbol(kasan_early_shadow_pte) : kasan_alloc_zeroed_page(node); - if (!early) -@@ -154,7 +154,7 @@ static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr, - : kasan_alloc_zeroed_page(node); - next = addr + PAGE_SIZE; - set_pte(ptep, pfn_pte(__phys_to_pfn(page_phys), PAGE_KERNEL)); -- } while (ptep++, addr = next, addr != end && __pte_none(early, READ_ONCE(*ptep))); -+ } while (ptep++, addr = next, addr != end && __pte_none(early, ptep_get(ptep))); - } - - static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr, -@@ -166,7 +166,7 @@ static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr, - do { - next = pmd_addr_end(addr, end); - kasan_pte_populate(pmdp, addr, next, node, early); -- } while (pmdp++, addr = next, addr != end && __pmd_none(early, READ_ONCE(*pmdp))); -+ } while (pmdp++, addr = next, addr != end && __pmd_none(early, pmdp_get(pmdp))); - } - - static void __init kasan_pud_populate(p4d_t *p4dp, unsigned long addr, -diff --git a/arch/loongarch/mm/pgtable.c b/arch/loongarch/mm/pgtable.c -index bda0181..3fa69b2 100644 ---- a/arch/loongarch/mm/pgtable.c -+++ b/arch/loongarch/mm/pgtable.c -@@ -116,6 +116,26 @@ void pud_init(void *addr) - EXPORT_SYMBOL_GPL(pud_init); - #endif - -+void kernel_pte_init(void *addr) -+{ -+ unsigned long *p, *end; -+ -+ p = (unsigned long *)addr; -+ end = p + PTRS_PER_PTE; -+ -+ do { -+ p[0] = _PAGE_GLOBAL; -+ p[1] = _PAGE_GLOBAL; -+ p[2] = _PAGE_GLOBAL; -+ p[3] = _PAGE_GLOBAL; -+ p[4] = _PAGE_GLOBAL; -+ p += 8; -+ p[-3] = _PAGE_GLOBAL; -+ p[-2] = _PAGE_GLOBAL; -+ p[-1] = _PAGE_GLOBAL; -+ } while (p != end); -+} -+ - pmd_t mk_pmd(struct page *page, pgprot_t prot) - { - pmd_t pmd; -@@ -128,7 +148,7 @@ pmd_t mk_pmd(struct page *page, pgprot_t prot) - void set_pmd_at(struct mm_struct *mm, unsigned long addr, - pmd_t *pmdp, pmd_t pmd) - { -- *pmdp = pmd; -+ WRITE_ONCE(*pmdp, pmd); - flush_tlb_all(); - } - -diff --git a/arch/loongarch/power/suspend_asm.S b/arch/loongarch/power/suspend_asm.S -index e2fc3b4..c28ad52 100644 ---- a/arch/loongarch/power/suspend_asm.S -+++ b/arch/loongarch/power/suspend_asm.S -@@ -73,11 +73,7 @@ SYM_FUNC_START(loongarch_suspend_enter) - * Reload all of the registers and return. - */ - SYM_INNER_LABEL(loongarch_wakeup_start, SYM_L_GLOBAL) -- li.d t0, CSR_DMW0_INIT # UC, PLV0 -- csrwr t0, LOONGARCH_CSR_DMWIN0 -- li.d t0, CSR_DMW1_INIT # CA, PLV0 -- csrwr t0, LOONGARCH_CSR_DMWIN1 -- -+ SETUP_DMWINS t0 - JUMP_VIRT_ADDR t0, t1 - - /* Enable PG */ -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 601f9b4..8da8f06 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -1528,6 +1528,23 @@ config AMD_MEM_ENCRYPT - This requires an AMD processor that supports Secure Memory - Encryption (SME). - -+config IEE -+ depends on X86_64 -+ def_bool y -+ -+config IEE_SELINUX_P -+ depends on IEE -+ depends on SECURITY_SELINUX -+ def_bool y -+ -+config CREDP -+ depends on IEE -+ def_bool y -+ -+config KEYP -+ depends on IEE -+ def_bool y -+ - # Common NUMA Features - config NUMA - bool "NUMA Memory Allocation and Scheduler Support" -diff --git a/arch/x86/boot/compressed/ident_map_64.c b/arch/x86/boot/compressed/ident_map_64.c -index c51011e..903535d 100644 ---- a/arch/x86/boot/compressed/ident_map_64.c -+++ b/arch/x86/boot/compressed/ident_map_64.c -@@ -23,7 +23,11 @@ - /* Use the static base for this part of the boot process */ - #undef __PAGE_OFFSET - #define __PAGE_OFFSET __PAGE_OFFSET_BASE -+#ifdef CONFIG_PTP -+#include "../../mm/ident_map_for_iee.c" -+#else - #include "../../mm/ident_map.c" -+#endif - - #define _SETUP - #include <asm/setup.h> /* For COMMAND_LINE_SIZE */ -@@ -101,9 +105,15 @@ void kernel_add_identity_map(unsigned long start, unsigned long end) - return; - - /* Build the mapping. */ -+ #ifdef CONFIG_PTP -+ ret = kernel_ident_mapping_init_for_iee(&mapping_info, (pgd_t *)top_level_pgt, start, end); -+ if (ret) -+ error("Error: kernel_ident_mapping_init_for_iee() failed\n"); -+ #else - ret = kernel_ident_mapping_init(&mapping_info, (pgd_t *)top_level_pgt, start, end); - if (ret) - error("Error: kernel_ident_mapping_init() failed\n"); -+ #endif - } - - /* Locates and clears a region for a new top level page table. */ -@@ -179,7 +189,11 @@ void initialize_identity_maps(void *rmode) - sev_prep_identity_maps(top_level_pgt); - - /* Load the new page-table. */ -+ #ifdef CONFIG_IEE -+ native_write_cr3_pre_init(top_level_pgt); -+ #else - write_cr3(top_level_pgt); -+ #endif - - /* - * Now that the required page table mappings are established and a -@@ -207,7 +221,11 @@ static pte_t *split_large_pmd(struct x86_mapping_info *info, - - /* Populate the PTEs */ - for (i = 0; i < PTRS_PER_PMD; i++) { -+ #ifdef CONFIG_PTP -+ iee_set_pte_pre_init(&pte[i], __pte(address | page_flags)); -+ #else - set_pte(&pte[i], __pte(address | page_flags)); -+ #endif - address += PAGE_SIZE; - } - -@@ -221,9 +239,17 @@ static pte_t *split_large_pmd(struct x86_mapping_info *info, - * of a TLB multihit. - */ - pmd = __pmd((unsigned long)pte | info->kernpg_flag); -+ #ifdef CONFIG_PTP -+ iee_set_pmd_pre_init(pmdp, pmd); -+ #else - set_pmd(pmdp, pmd); -+ #endif - /* Flush TLB to establish the new PMD */ -+ #ifdef CONFIG_IEE -+ native_write_cr3_pre_init(top_level_pgt); -+ #else - write_cr3(top_level_pgt); -+ #endif - - return pte + pte_index(__address); - } -@@ -313,7 +339,11 @@ static int set_clr_page_flags(struct x86_mapping_info *info, - pte = *ptep; - pte = pte_set_flags(pte, set); - pte = pte_clear_flags(pte, clr); -+ #ifdef CONFIG_PTP -+ iee_set_pte_pre_init(ptep, pte); -+ #else - set_pte(ptep, pte); -+ #endif - - /* - * If the encryption attribute is being set, then change the page state to -@@ -324,7 +354,11 @@ static int set_clr_page_flags(struct x86_mapping_info *info, - snp_set_page_private(__pa(address & PAGE_MASK)); - - /* Flush TLB after changing encryption attribute */ -+ #ifdef CONFIG_IEE -+ native_write_cr3_pre_init(top_level_pgt); -+ #else - write_cr3(top_level_pgt); -+ #endif - - return 0; - } -diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c -index 7939eb6..c922aec 100644 ---- a/arch/x86/boot/compressed/pgtable_64.c -+++ b/arch/x86/boot/compressed/pgtable_64.c -@@ -196,7 +196,11 @@ asmlinkage void configure_5level_paging(struct boot_params *bp, void *pgtable) - * Move the top level page table out of trampoline memory. - */ - memcpy(pgtable, trampoline_32bit, PAGE_SIZE); -+ #ifdef CONFIG_IEE -+ native_write_cr3_pre_init((unsigned long)pgtable); -+ #else - native_write_cr3((unsigned long)pgtable); -+ #endif - - /* Restore trampoline memory */ - memcpy(trampoline_32bit, trampoline_save, TRAMPOLINE_32BIT_SIZE); -diff --git a/arch/x86/events/zhaoxin/uncore.c b/arch/x86/events/zhaoxin/uncore.c -index c311ab5..2e44499 100644 ---- a/arch/x86/events/zhaoxin/uncore.c -+++ b/arch/x86/events/zhaoxin/uncore.c -@@ -932,56 +932,6 @@ static const struct pci_device_id kh40000_uncore_pci_ids[] = { - .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_MC0, 0), - }, - -- { /* PCIE D2F0 */ -- PCI_DEVICE(0x1D17, 0x0717), -- .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_PCI, 0), -- }, -- -- { /* PCIE D2F1 */ -- PCI_DEVICE(0x1D17, 0x0718), -- .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_PCI, 1), -- }, -- -- { /* PCIE D3F0 */ -- PCI_DEVICE(0x1D17, 0x0719), -- .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_PCI, 2), -- }, -- -- { /* PCIE D3F1 */ -- PCI_DEVICE(0x1D17, 0x071A), -- .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_PCI, 3), -- }, -- -- { /* PCIE D3F2 */ -- PCI_DEVICE(0x1D17, 0x071B), -- .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_PCI, 4), -- }, -- -- { /* PCIE D4F0 */ -- PCI_DEVICE(0x1D17, 0x071C), -- .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_PCI, 5), -- }, -- -- { /* PCIE D4F1 */ -- PCI_DEVICE(0x1D17, 0x071D), -- .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_PCI, 6), -- }, -- -- { /* PCIE D5F0 */ -- PCI_DEVICE(0x1D17, 0x071E), -- .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_PCI, 7), -- }, -- -- { /* PCIE D5F1 */ -- PCI_DEVICE(0x1D17, 0x0731), -- .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_PCI, 8), -- }, -- -- { /* PCIE D5F2 */ -- PCI_DEVICE(0x1D17, 0x0732), -- .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_PCI, 9), -- }, -- - { /* ZPI_DLL */ - PCI_DEVICE(0x1D17, 0x91c1), - .driver_data = UNCORE_PCI_DEV_DATA(KH40000_PCI_UNCORE_ZPI_DLL, 0), -@@ -1272,91 +1222,6 @@ static const struct pci_device_id kx7000_uncore_pci_ids[] = { - .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_MC_A0, 0), - }, - -- { /* PCIE D2F0 */ -- PCI_DEVICE(0x1D17, 0x0717), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 0), -- }, -- -- { /* PCIE D2F1 */ -- PCI_DEVICE(0x1D17, 0x0718), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 1), -- }, -- -- { /* PCIE D2F2 */ -- PCI_DEVICE(0x1D17, 0x0733), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 2), -- }, -- -- { /* PCIE D2F3 */ -- PCI_DEVICE(0x1D17, 0x0734), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 3), -- }, -- -- { /* PCIE D3F0 */ -- PCI_DEVICE(0x1D17, 0x0719), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 4), -- }, -- -- { /* PCIE D3F1 */ -- PCI_DEVICE(0x1D17, 0x0735), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 5), -- }, -- -- { /* PCIE D3F2 */ -- PCI_DEVICE(0x1D17, 0x0739), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 6), -- }, -- -- { /* PCIE D3F3 */ -- PCI_DEVICE(0x1D17, 0x073A), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 7), -- }, -- -- { /* PCIE D4F0 */ -- PCI_DEVICE(0x1D17, 0x071B), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 8), -- }, -- -- { /* PCIE D4F1 */ -- PCI_DEVICE(0x1D17, 0x071C), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 9), -- }, -- -- { /* PCIE D4F2 */ -- PCI_DEVICE(0x1D17, 0x0736), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 10), -- }, -- -- { /* PCIE D4F3 */ -- PCI_DEVICE(0x1D17, 0x0737), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 11), -- }, -- -- { /* PCIE D4F4 */ -- PCI_DEVICE(0x1D17, 0x0738), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 12), -- }, -- -- { /* PCIE D5F0 */ -- PCI_DEVICE(0x1D17, 0x071D), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 13), -- }, -- -- { /* PCIE D5F1 */ -- PCI_DEVICE(0x1D17, 0x071E), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 14), -- }, -- -- { /* PCIE D5F2 */ -- PCI_DEVICE(0x1D17, 0x0732), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 15), -- }, -- -- { /* PCIE D5F3 */ -- PCI_DEVICE(0x1D17, 0x073B), -- .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PCI, 16), -- }, -- - { /* PXPTRF */ - PCI_DEVICE(0x1D17, 0x31B4), - .driver_data = UNCORE_PCI_DEV_DATA(KX7000_PCI_UNCORE_PXPTRF, 0), -diff --git a/arch/x86/include/asm/asm-prototypes.h b/arch/x86/include/asm/asm-prototypes.h -index 0e82074..0f0bb91 100644 ---- a/arch/x86/include/asm/asm-prototypes.h -+++ b/arch/x86/include/asm/asm-prototypes.h -@@ -15,6 +15,10 @@ - #include <asm/gsseg.h> - #include <asm/nospec-branch.h> - -+#ifdef CONFIG_PTP -+#include <asm/iee-setpgtable.h> -+#endif -+ - #ifndef CONFIG_X86_CMPXCHG64 - extern void cmpxchg8b_emu(void); - #endif -diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h -index ab97b22..0a73e4e 100644 ---- a/arch/x86/include/asm/desc.h -+++ b/arch/x86/include/asm/desc.h -@@ -13,6 +13,10 @@ - #include <linux/smp.h> - #include <linux/percpu.h> - -+#ifdef CONFIG_IEE -+#include <asm/iee-si.h> -+#endif -+ - static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *info) - { - desc->limit0 = info->limit & 0x0ffff; -@@ -210,9 +214,20 @@ static inline void native_load_gdt(const struct desc_ptr *dtr) - asm volatile("lgdt %0"::"m" (*dtr)); - } - -+#ifdef CONFIG_IEE -+static __always_inline void iee_load_idt_pre_init(const struct desc_ptr *dtr) -+{ -+ asm volatile("lidt %0"::"m" (*dtr)); -+} -+#endif -+ - static __always_inline void native_load_idt(const struct desc_ptr *dtr) - { -+ #ifdef CONFIG_IEE -+ iee_rwx_gate(IEE_LOAD_IDT, dtr); -+ #else - asm volatile("lidt %0"::"m" (*dtr)); -+ #endif - } - - static inline void native_store_gdt(struct desc_ptr *dtr) -diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h -index d0dcefb..c6dbea6 100644 ---- a/arch/x86/include/asm/fixmap.h -+++ b/arch/x86/include/asm/fixmap.h -@@ -196,5 +196,10 @@ void __init *early_memremap_decrypted_wp(resource_size_t phys_addr, - void __early_set_fixmap(enum fixed_addresses idx, - phys_addr_t phys, pgprot_t flags); - -+#ifdef CONFIG_PTP -+void __iee_set_fixmap_pre_init(enum fixed_addresses idx, -+ phys_addr_t phys, pgprot_t flags); -+#endif -+ - #endif /* !__ASSEMBLY__ */ - #endif /* _ASM_X86_FIXMAP_H */ -diff --git a/arch/x86/include/asm/iee-access.h b/arch/x86/include/asm/iee-access.h -new file mode 100644 -index 0000000..f634f5a ---- /dev/null -+++ b/arch/x86/include/asm/iee-access.h -@@ -0,0 +1,34 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _LINUX_IEE_ACCESS_H -+#define _LINUX_IEE_ACCESS_H -+ -+#include <asm/iee-def.h> -+ -+extern unsigned long long iee_rw_gate(int flag, ...); -+ -+static inline void iee_memcpy(void *dst, const void *src, size_t n) -+{ -+ iee_rw_gate(IEE_OP_MEMCPY, dst, src, n); -+} -+ -+static inline void iee_memset(void *ptr, int data, size_t n) -+{ -+ iee_rw_gate(IEE_OP_MEMSET, ptr, data, n); -+} -+ -+static inline void iee_set_freeptr(void **pptr, void *ptr) -+{ -+ iee_rw_gate(IEE_OP_SET_FREEPTR, pptr, ptr); -+} -+ -+static inline void iee_split_huge_pmd(pmd_t *pmdp, pte_t *pgtable) -+{ -+ iee_rw_gate(IEE_OP_SPLIT_HUGE_PMD, pmdp, pgtable); -+} -+ -+static inline unsigned long iee_test_and_clear_bit(long nr, volatile unsigned long *addr) -+{ -+ return iee_rw_gate(IEE_OP_TEST_CLEAR_BIT, nr, addr); -+} -+ -+#endif -diff --git a/arch/x86/include/asm/iee-cred.h b/arch/x86/include/asm/iee-cred.h -new file mode 100644 -index 0000000..eb93ad0 ---- /dev/null -+++ b/arch/x86/include/asm/iee-cred.h -@@ -0,0 +1,149 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _LINUX_IEE_CRED_H -+#define _LINUX_IEE_CRED_H -+ -+#include <linux/cred.h> -+#include <asm/iee-def.h> -+ -+extern unsigned long long iee_rw_gate(int flag, ...); -+ -+static void __maybe_unused iee_copy_cred(const struct cred *old, struct cred *new) -+{ -+ iee_rw_gate(IEE_OP_COPY_CRED, old, new); -+} -+ -+static void __maybe_unused iee_set_cred_uid(struct cred *cred, kuid_t uid) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_UID, cred, uid); -+} -+ -+static void __maybe_unused iee_set_cred_gid(struct cred *cred, kgid_t gid) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_GID, cred, gid); -+} -+ -+static void __maybe_unused iee_set_cred_suid(struct cred *cred, kuid_t suid) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_SUID, cred, suid); -+} -+ -+static void __maybe_unused iee_set_cred_sgid(struct cred *cred, kgid_t sgid) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_SGID, cred, sgid); -+} -+ -+static void __maybe_unused iee_set_cred_euid(struct cred *cred, kuid_t euid) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_EUID, cred, euid); -+} -+ -+static void __maybe_unused iee_set_cred_egid(struct cred *cred, kgid_t egid) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_EGID, cred, egid); -+} -+ -+static void __maybe_unused iee_set_cred_fsuid(struct cred *cred, kuid_t fsuid) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_FSUID, cred, fsuid); -+} -+ -+static void __maybe_unused iee_set_cred_fsgid(struct cred *cred, kgid_t fsgid) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_FSGID, cred, fsgid); -+} -+ -+static void __maybe_unused iee_set_cred_user(struct cred *cred, struct user_struct *user) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_USER, cred, user); -+} -+ -+static void __maybe_unused iee_set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_USER_NS, cred, user_ns); -+} -+ -+static void __maybe_unused iee_set_cred_ucounts(struct cred *cred, struct ucounts *ucounts) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_UCOUNTS, cred, ucounts); -+} -+ -+static void __maybe_unused iee_set_cred_group_info(struct cred *cred, struct group_info *group_info) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_GROUP_INFO, cred, group_info); -+} -+ -+static void __maybe_unused iee_set_cred_securebits(struct cred *cred, unsigned int securebits) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_SECUREBITS, cred, securebits); -+} -+ -+static void __maybe_unused iee_set_cred_cap_inheritable(struct cred *cred, kernel_cap_t cap_inheritable) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_CAP_INHER, cred, cap_inheritable); -+} -+ -+static void __maybe_unused iee_set_cred_cap_permitted(struct cred *cred, kernel_cap_t cap_permitted) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_CAP_PERM, cred, cap_permitted); -+} -+ -+static void __maybe_unused iee_set_cred_cap_effective(struct cred *cred, kernel_cap_t cap_effective) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_CAP_EFFECT, cred, cap_effective); -+} -+ -+static void __maybe_unused iee_set_cred_cap_bset(struct cred *cred, kernel_cap_t cap_bset) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_CAP_BSET, cred, cap_bset); -+} -+ -+static void __maybe_unused iee_set_cred_cap_ambient(struct cred *cred, kernel_cap_t cap_ambient) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_CAP_AMBIENT, cred, cap_ambient); -+} -+ -+#ifdef CONFIG_KEYS -+static void __maybe_unused iee_set_cred_jit_keyring(struct cred *cred, unsigned char jit_keyring) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_JIT_KEYRING, cred, jit_keyring); -+} -+ -+static void __maybe_unused iee_set_cred_session_keyring(struct cred *cred, struct key *session_keyring) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_SESS_KEYRING, cred, session_keyring); -+} -+ -+static void __maybe_unused iee_set_cred_process_keyring(struct cred *cred, struct key *process_keyring) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_PROC_KEYRING, cred, process_keyring); -+} -+ -+static void __maybe_unused iee_set_cred_thread_keyring(struct cred *cred, struct key *thread_keyring) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_THREAD_KEYRING, cred, thread_keyring); -+} -+ -+static void __maybe_unused iee_set_cred_request_key_auth(struct cred *cred, struct key *request_key_auth) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_REQ_KEYRING, cred, request_key_auth); -+} -+#endif -+ -+static void __maybe_unused iee_set_cred_atomic_set_usage(struct cred *cred, int i) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_ATSET_USAGE, cred, i); -+} -+ -+#ifdef CONFIG_SECURITY -+static void __maybe_unused iee_set_cred_security(struct cred *cred, void *security) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_SECURITY, cred, security); -+} -+#endif -+ -+static void __maybe_unused iee_set_cred_rcu(struct cred *cred, struct rcu_head *rcu) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_RCU, cred, rcu); -+} -+ -+#endif -diff --git a/arch/x86/include/asm/iee-def.h b/arch/x86/include/asm/iee-def.h -new file mode 100644 -index 0000000..002455d ---- /dev/null -+++ b/arch/x86/include/asm/iee-def.h -@@ -0,0 +1,113 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _LINUX_IEE_DEF_H -+#define _LINUX_IEE_DEF_H -+ -+enum { -+ IEE_OP_MEMCPY, -+ IEE_OP_MEMSET, -+ IEE_OP_SET_FREEPTR, -+ IEE_OP_SPLIT_HUGE_PMD, -+ IEE_OP_SET_TOKEN_PGD, -+ IEE_OP_INIT_TOKEN, -+ IEE_OP_INVALIDATE_TOKEN, -+ IEE_OP_VALIDATE_TOKEN, -+ IEE_OP_UNSET_TOKEN, -+ IEE_OP_SET_TOKEN, -+ IEE_OP_TEST_CLEAR_BIT, -+ IEE_SET_SENSITIVE_PTE, -+ IEE_UNSET_SENSITIVE_PTE, -+#ifdef CONFIG_PTP -+ IEE_OP_SET_PTE, -+ IEE_OP_SET_PMD, -+ IEE_OP_SET_PUD, -+ IEE_OP_SET_P4D, -+ IEE_OP_SET_PGD, -+#endif -+#ifdef CONFIG_IEE_SELINUX_P -+ IEE_SEL_SET_STATUS_PG, -+ IEE_SEL_SET_ENFORCING, -+ IEE_SEL_SET_INITIALIZED, -+ IEE_SEL_SET_POLICY_CAP, -+ IEE_SEL_RCU_ASSIGN_POLICY, -+#endif -+#ifdef CONFIG_CREDP -+ IEE_OP_COPY_CRED, -+ IEE_OP_SET_CRED_UID, -+ IEE_OP_SET_CRED_GID, -+ IEE_OP_SET_CRED_SUID, -+ IEE_OP_SET_CRED_SGID, -+ IEE_OP_SET_CRED_EUID, -+ IEE_OP_SET_CRED_EGID, -+ IEE_OP_SET_CRED_FSUID, -+ IEE_OP_SET_CRED_FSGID, -+ IEE_OP_SET_CRED_USER, -+ IEE_OP_SET_CRED_USER_NS, -+ IEE_OP_SET_CRED_GROUP_INFO, -+ IEE_OP_SET_CRED_SECUREBITS, -+ IEE_OP_SET_CRED_CAP_INHER, -+ IEE_OP_SET_CRED_CAP_PERM, -+ IEE_OP_SET_CRED_CAP_EFFECT, -+ IEE_OP_SET_CRED_CAP_BSET, -+ IEE_OP_SET_CRED_CAP_AMBIENT, -+ IEE_OP_SET_CRED_JIT_KEYRING, -+ IEE_OP_SET_CRED_SESS_KEYRING, -+ IEE_OP_SET_CRED_PROC_KEYRING, -+ IEE_OP_SET_CRED_THREAD_KEYRING, -+ IEE_OP_SET_CRED_REQ_KEYRING, -+ IEE_OP_SET_CRED_NON_RCU, -+ IEE_OP_SET_CRED_ATSET_USAGE, -+ IEE_OP_SET_CRED_ATOP_USAGE, -+ IEE_OP_SET_CRED_SECURITY, -+ IEE_OP_SET_CRED_RCU, -+ IEE_OP_SET_CRED_UCOUNTS, -+#endif -+#ifdef CONFIG_KEYP -+ IEE_OP_SET_KEY_UNION, -+ IEE_OP_SET_KEY_STRUCT, -+ IEE_OP_SET_KEY_PAYLOAD, -+ IEE_OP_SET_KEY_USAGE, -+ IEE_OP_SET_KEY_SERIAL, -+ IEE_OP_SET_KEY_WATCHERS, -+ IEE_OP_SET_KEY_USERS, -+ IEE_OP_SET_KEY_SECURITY, -+ IEE_OP_SET_KEY_EXPIRY, -+ IEE_OP_SET_KEY_REVOKED_AT, -+ IEE_OP_SET_KEY_LAST_USED_AT, -+ IEE_OP_SET_KEY_UID, -+ IEE_OP_SET_KEY_GID, -+ IEE_OP_SET_KEY_PERM, -+ IEE_OP_SET_KEY_QUOTALEN, -+ IEE_OP_SET_KEY_DATALEN, -+ IEE_OP_SET_KEY_STATE, -+ IEE_OP_SET_KEY_MAGIC, -+ IEE_OP_SET_KEY_FLAGS, -+ IEE_OP_SET_KEY_INDEX_KEY, -+ IEE_OP_SET_KEY_HASH, -+ IEE_OP_SET_KEY_LEN_DESC, -+ IEE_OP_SET_KEY_TYPE, -+ IEE_OP_SET_KEY_TAG, -+ IEE_OP_SET_KEY_DESCRIPTION, -+ IEE_OP_SET_KEY_RESTRICT_LINK, -+ IEE_OP_SET_KEY_FLAG_BIT, -+#endif -+ IEE_FLAG_END -+}; -+ -+#ifdef CONFIG_CREDP -+#define AT_ADD 1 -+#define AT_INC_NOT_ZERO 2 -+#define AT_SUB_AND_TEST 3 -+#endif -+ -+#ifdef CONFIG_KEYP -+#define REFCOUNT_INC 1 -+#define REFCOUNT_SET 2 -+#define REFCOUNT_DEC_AND_TEST 3 -+#define REFCOUNT_INC_NOT_ZERO 4 -+ -+#define SET_BIT_OP 1 -+#define TEST_AND_CLEAR_BIT 2 -+#define TEST_AND_SET_BIT 3 -+#endif -+ -+#endif /* _LINUX_IEE_DEF_H */ -diff --git a/arch/x86/include/asm/iee-key.h b/arch/x86/include/asm/iee-key.h -new file mode 100644 -index 0000000..3ac495b ---- /dev/null -+++ b/arch/x86/include/asm/iee-key.h -@@ -0,0 +1,149 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _LINUX_IEE_KEY_H -+#define _LINUX_IEE_KEY_H -+ -+#include <linux/key.h> -+#include <asm/iee-def.h> -+ -+extern unsigned long long iee_rw_gate(int flag, ...); -+ -+static void __maybe_unused iee_set_key_union(struct key *key, struct key_union *key_union) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_UNION, key, key_union); -+} -+ -+static void __maybe_unused iee_set_key_struct(struct key *key, struct key_struct *key_struct) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_STRUCT, key, key_struct); -+} -+ -+static void __maybe_unused iee_set_key_payload(struct key *key, union key_payload *key_payload) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_PAYLOAD, key, key_payload); -+} -+ -+extern bool iee_set_key_usage(struct key *key, int n, int flag); -+ -+static void __maybe_unused iee_set_key_serial(struct key *key, key_serial_t serial) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_SERIAL, key, serial); -+} -+ -+#ifdef CONFIG_KEY_NOTIFICATIONS -+static void __maybe_unused iee_set_key_watchers(struct key *key, struct watch_list *watchers) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_WATCHERS, key, watchers); -+} -+#endif -+ -+static void __maybe_unused iee_set_key_user(struct key *key, struct key_user *user) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_USERS, key, user); -+} -+ -+static void __maybe_unused iee_set_key_security(struct key *key, void *security) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_SECURITY, key, security); -+} -+ -+static void __maybe_unused iee_set_key_expiry(struct key *key, time64_t expiry) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_EXPIRY, key, expiry); -+} -+ -+static void __maybe_unused iee_set_key_revoked_at(struct key *key, time64_t revoked_at) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_REVOKED_AT, key, revoked_at); -+} -+ -+static void __maybe_unused iee_set_key_last_used_at(struct key *key, time64_t last_used_at) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_LAST_USED_AT, key, last_used_at); -+} -+ -+static void __maybe_unused iee_set_key_uid(struct key *key, kuid_t uid) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_UID, key, uid); -+} -+ -+static void __maybe_unused iee_set_key_gid(struct key *key, kgid_t gid) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_GID, key, gid); -+} -+ -+static void __maybe_unused iee_set_key_perm(struct key *key, key_perm_t perm) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_PERM, key, perm); -+} -+ -+static void __maybe_unused iee_set_key_quotalen(struct key *key, unsigned short quotalen) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_QUOTALEN, key, quotalen); -+} -+ -+static void __maybe_unused iee_set_key_datalen(struct key *key, unsigned short datalen) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_DATALEN, key, datalen); -+} -+ -+static void __maybe_unused iee_set_key_state(struct key *key, short state) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_STATE, key, state); -+} -+ -+#ifdef KEY_DEBUGGING -+static void __maybe_unused iee_set_key_magic(struct key *key, unsigned int magic) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_MAGIC, key, magic); -+} -+#endif -+ -+static void __maybe_unused iee_set_key_flags(struct key *key, unsigned long flags) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_FLAGS, key, flags); -+} -+ -+static void __maybe_unused iee_set_key_index_key(struct key *key, struct keyring_index_key *index_key) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_INDEX_KEY, key, index_key); -+} -+ -+static void __maybe_unused iee_set_key_hash(struct key *key, unsigned long hash) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_HASH, key, hash); -+} -+ -+static void __maybe_unused iee_set_key_len_desc(struct key *key, unsigned long len_desc) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_LEN_DESC, key, len_desc); -+} -+ -+static void __maybe_unused iee_set_key_type(struct key *key, struct key_type *type) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_TYPE, key, type); -+} -+ -+static void __maybe_unused iee_set_key_domain_tag(struct key *key, struct key_tag *domain_tag) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_TAG, key, domain_tag); -+} -+ -+static void __maybe_unused iee_set_key_description(struct key *key, char *description) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_DESCRIPTION, key, description); -+} -+ -+static void __maybe_unused iee_set_key_restrict_link(struct key *key, struct key_restriction *restrict_link) -+{ -+ iee_rw_gate(IEE_OP_SET_KEY_RESTRICT_LINK, key, restrict_link); -+} -+ -+static bool __maybe_unused iee_set_key_flag_bit(struct key *key, long nr, int flag) -+{ -+ bool ret; -+ -+ ret = iee_rw_gate(IEE_OP_SET_KEY_FLAG_BIT, key, nr, flag); -+ return ret; -+} -+ -+#endif -diff --git a/arch/x86/include/asm/iee-selinuxp.h b/arch/x86/include/asm/iee-selinuxp.h -new file mode 100644 -index 0000000..35dc136 ---- /dev/null -+++ b/arch/x86/include/asm/iee-selinuxp.h -@@ -0,0 +1,35 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _LINUX_IEE_SELINUX_P_H -+#define _LINUX_IEE_SELINUX_P_H -+ -+#include <asm/iee.h> -+#include <linux/mutex.h> -+#include "security.h" -+#include "ss/services.h" -+void __iee_code _iee_set_selinux_status_pg(unsigned long __unused, struct page *new_page); -+void __iee_code _iee_set_selinux_enforcing(unsigned long __unused, bool value); -+void __iee_code _iee_mark_selinux_initialized(unsigned long __unused); -+void __iee_code _iee_set_sel_policy_cap(unsigned long __unused, unsigned int idx, int cap); -+void __iee_code _iee_sel_rcu_assign_policy(unsigned long __unused, -+ struct selinux_policy *new_policy, struct selinux_policy *iee_new_policy); -+ -+extern unsigned long long iee_rw_gate(int flag, ...); -+static inline struct mutex *iee_get_selinux_policy_lock(void) -+{ -+ return (struct mutex *)(selinux_state.policy_mutex.owner.counter); -+} -+ -+static inline struct mutex *iee_get_selinux_status_lock(void) -+{ -+ return (struct mutex *)(selinux_state.status_lock.owner.counter); -+} -+ -+/* APIs for modifying selinux_state */ -+extern void iee_set_selinux_status_pg(struct page *new_page); -+extern void iee_set_sel_policy_cap(unsigned int idx, int cap); -+extern void iee_sel_rcu_assign_policy(struct selinux_policy *new_policy, -+ struct selinux_policy *iee_new_policy); -+ -+extern struct kmem_cache *policy_jar; -+ -+#endif -diff --git a/arch/x86/include/asm/iee-setpgtable.h b/arch/x86/include/asm/iee-setpgtable.h -new file mode 100644 -index 0000000..5cbfcec ---- /dev/null -+++ b/arch/x86/include/asm/iee-setpgtable.h -@@ -0,0 +1,7 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#include <asm/pgtable_types.h> -+extern void iee_set_pte(int flag, pte_t *ptep, pte_t pte); -+extern void iee_set_pmd(int flag, pmd_t *pmdp, pmd_t pmd); -+extern void iee_set_pud(int flag, pud_t *pudp, pud_t pud); -+extern void iee_set_p4d(int flag, p4d_t *p4dp, p4d_t p4d); -+extern void iee_set_pgd(int flag, pgd_t *pgdp, pgd_t pgd); -diff --git a/arch/x86/include/asm/iee-si.h b/arch/x86/include/asm/iee-si.h -new file mode 100644 -index 0000000..01eb1fa ---- /dev/null -+++ b/arch/x86/include/asm/iee-si.h -@@ -0,0 +1,27 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _LINUX_IEE_SI_H -+#define _LINUX_IEE_SI_H -+#define __iee_si_code __section(".iee.si_text") -+#define __iee_si_base __section(".iee.si_base") -+#define __iee_si_data __section(".iee.si_data") -+ -+extern bool iee_pgt_jar_init; -+extern bool iee_init_done; -+extern unsigned long __iee_si_text_start[]; -+extern unsigned long __iee_si_text_end[]; -+extern unsigned long __iee_si_data_start[]; -+extern unsigned long __iee_si_data_end[]; -+extern void iee_rwx_gate(int flag, ...); -+ -+extern const unsigned long cr4_pinned_mask; -+extern struct static_key_false cr_pinning; -+extern unsigned long cr4_pinned_bits; -+// Handler function for sensitive inst -+u64 iee_si_handler(int flag, ...); -+ -+#define IEE_SI_TEST 0 -+#define IEE_WRITE_CR0 1 -+#define IEE_WRITE_CR3 2 -+#define IEE_WRITE_CR4 3 -+#define IEE_LOAD_IDT 4 -+#endif -diff --git a/arch/x86/include/asm/iee-token.h b/arch/x86/include/asm/iee-token.h -new file mode 100644 -index 0000000..414f80b ---- /dev/null -+++ b/arch/x86/include/asm/iee-token.h -@@ -0,0 +1,33 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _LINUX_IEE_TOKEN_H -+#define _LINUX_IEE_TOKEN_H -+ -+#include <asm/iee-def.h> -+#include <asm/pgtable_types.h> -+ -+extern unsigned long long iee_rw_gate(int flag, ...); -+struct task_token; -+struct task_struct; -+struct mm_struct; -+ -+static inline void iee_set_token_pgd(struct task_struct *tsk, pgd_t *pgd) -+{ -+ iee_rw_gate(IEE_OP_SET_TOKEN_PGD, tsk, pgd); -+} -+ -+static inline void iee_init_token(struct task_struct *tsk, void *iee_stack, void *tmp_page) -+{ -+ iee_rw_gate(IEE_OP_INIT_TOKEN, tsk, iee_stack, tmp_page); -+} -+ -+static inline void iee_invalidate_token(struct task_struct *tsk) -+{ -+ iee_rw_gate(IEE_OP_INVALIDATE_TOKEN, tsk); -+} -+ -+static inline void iee_validate_token(struct task_struct *tsk) -+{ -+ iee_rw_gate(IEE_OP_VALIDATE_TOKEN, tsk); -+} -+ -+#endif -diff --git a/arch/x86/include/asm/iee.h b/arch/x86/include/asm/iee.h -new file mode 100644 -index 0000000..434a4b8 ---- /dev/null -+++ b/arch/x86/include/asm/iee.h -@@ -0,0 +1,111 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _LINUX_IEE_H -+#define _LINUX_IEE_H -+#include <asm/pgtable_types.h> -+#include <linux/sched.h> -+ -+extern unsigned long iee_offset; -+extern unsigned long IEE_OFFSET; -+#define __iee_code __section(".iee.text") -+#define __iee_header __section(".iee.text.header") -+void __iee_code _iee_memcpy(unsigned long __unused, void *dst, void *src, size_t n); -+void __iee_code _iee_memset(unsigned long __unused, void *ptr, int data, size_t n); -+void __iee_code _iee_set_freeptr(unsigned long __unused, void **pptr, void *ptr); -+void __iee_code _iee_split_huge_pmd(unsigned long __unused, -+ pmd_t *pmdp, pte_t *pgtable); -+void __iee_code _iee_set_token_pgd(unsigned long __unused, -+ struct task_struct *tsk, pgd_t *pgd); -+void __iee_code _iee_init_token(unsigned long __unused, -+ struct task_struct *tsk, void *iee_stack, void *tmp_page); -+void __iee_code _iee_invalidate_token(unsigned long __unused, -+ struct task_struct *tsk); -+void __iee_code _iee_validate_token(unsigned long __unused, -+ struct task_struct *tsk); -+void __iee_code _iee_unset_token(unsigned long __unused, pte_t *token_ptep, -+ pte_t *token_page_ptep, void *token, void *token_page, unsigned long order); -+void __iee_code _iee_set_token(unsigned long __unused, -+ pte_t *token_ptep, pte_t *new_ptep, void *new, unsigned long order, int use_block_pmd); -+unsigned long __iee_code _iee_test_and_clear_bit(unsigned long __unused, -+ long nr, volatile unsigned long *addr); -+void __iee_code _iee_set_sensitive_pte(unsigned long __unused, -+ pte_t *lm_ptep, int order, int use_block_pmd); -+void __iee_code _iee_unset_sensitive_pte(unsigned long __unused, -+ pte_t *lm_ptep, int order, int use_block_pmd); -+#ifdef CONFIG_PTP -+void __iee_code _iee_set_pte(unsigned long __unused, -+ pte_t *ptep, pte_t pte); -+void __iee_code _iee_set_pmd(unsigned long __unused, -+ pmd_t *pmdp, pmd_t pmd); -+void __iee_code _iee_set_pud(unsigned long __unused, -+ pud_t *pudp, pud_t pud); -+void __iee_code _iee_set_p4d(unsigned long __unused, -+ p4d_t *p4dp, p4d_t p4d); -+void __iee_code _iee_set_pgd(unsigned long __unused, -+ pgd_t *pgdp, pgd_t pgd); -+#endif -+#ifdef CONFIG_CREDP -+#include <linux/cred.h> -+extern struct cred init_cred; -+void __iee_code _iee_set_cred_uid(unsigned long __unused, struct cred *cred, kuid_t uid); -+void __iee_code _iee_set_cred_gid(unsigned long __unused, struct cred *cred, kgid_t gid); -+void __iee_code _iee_copy_cred(unsigned long __unused, struct cred *old, struct cred *new); -+void __iee_code _iee_set_cred_suid(unsigned long __unused, struct cred *cred, kuid_t suid); -+void __iee_code _iee_set_cred_sgid(unsigned long __unused, struct cred *cred, kgid_t sgid); -+void __iee_code _iee_set_cred_euid(unsigned long __unused, struct cred *cred, kuid_t euid); -+void __iee_code _iee_set_cred_egid(unsigned long __unused, struct cred *cred, kgid_t egid); -+void __iee_code _iee_set_cred_fsuid(unsigned long __unused, struct cred *cred, kuid_t fsuid); -+void __iee_code _iee_set_cred_fsgid(unsigned long __unused, struct cred *cred, kgid_t fsgid); -+void __iee_code _iee_set_cred_user(unsigned long __unused, struct cred *cred, struct user_struct *user); -+void __iee_code _iee_set_cred_user_ns(unsigned long __unused, struct cred *cred, struct user_namespace *user_ns); -+void __iee_code _iee_set_cred_group_info(unsigned long __unused, struct cred *cred, struct group_info *group_info); -+void __iee_code _iee_set_cred_securebits(unsigned long __unused, struct cred *cred, unsigned int securebits); -+void __iee_code _iee_set_cred_cap_inheritable(unsigned long __unused, struct cred *cred, kernel_cap_t cap_inheritable); -+void __iee_code _iee_set_cred_cap_permitted(unsigned long __unused, struct cred *cred, kernel_cap_t cap_permitted); -+void __iee_code _iee_set_cred_cap_effective(unsigned long __unused, struct cred *cred, kernel_cap_t cap_effective); -+void __iee_code _iee_set_cred_cap_bset(unsigned long __unused, struct cred *cred, kernel_cap_t cap_bset); -+void __iee_code _iee_set_cred_cap_ambient(unsigned long __unused, struct cred *cred, kernel_cap_t cap_ambient); -+void __iee_code _iee_set_cred_jit_keyring(unsigned long __unused, struct cred *cred, unsigned char jit_keyring); -+void __iee_code _iee_set_cred_session_keyring(unsigned long __unused, struct cred *cred, struct key *session_keyring); -+void __iee_code _iee_set_cred_process_keyring(unsigned long __unused, struct cred *cred, struct key *process_keyring); -+void __iee_code _iee_set_cred_thread_keyring(unsigned long __unused, struct cred *cred, struct key *thread_keyring); -+void __iee_code _iee_set_cred_request_key_auth(unsigned long __unused, struct cred *cred, struct key *request_key_auth); -+void __iee_code _iee_set_cred_non_rcu(unsigned long __unused, struct cred *cred, int non_rcu); -+void __iee_code _iee_set_cred_atomic_set_usage(unsigned long __unused, struct cred *cred, int i); -+unsigned long __iee_code _iee_set_cred_atomic_op_usage(unsigned long __unused, struct cred *cred, int flag, int nr); -+void __iee_code _iee_set_cred_security(unsigned long __unused, struct cred *cred, void *security); -+void __iee_code _iee_set_cred_rcu(unsigned long __unused, struct cred *cred, struct rcu_head *rcu); -+void __iee_code _iee_set_cred_ucounts(unsigned long __unused, struct cred *cred, struct ucounts *ucounts); -+#endif -+#ifdef CONFIG_KEYP -+#include<linux/key.h> -+struct watch_list; -+void __iee_code _iee_set_key_union(unsigned long __unused, struct key *key, struct key_union *key_union); -+void __iee_code _iee_set_key_struct(unsigned long __unused, struct key *key, struct key_struct *key_struct); -+void __iee_code _iee_set_key_payload(unsigned long __unused, struct key *key, union key_payload *key_payload); -+unsigned long __iee_code _iee_set_key_usage(unsigned long __unused, struct key *key, int n, int flag); -+void __iee_code _iee_set_key_serial(unsigned long __unused, struct key *key, key_serial_t serial); -+void __iee_code _iee_set_key_watchers(unsigned long __unused, struct key *key, struct watch_list *watchers); -+void __iee_code _iee_set_key_user(unsigned long __unused, struct key *key, struct key_user *user); -+void __iee_code _iee_set_key_security(unsigned long __unused, struct key *key, void *security); -+void __iee_code _iee_set_key_expiry(unsigned long __unused, struct key *key, time64_t expiry); -+void __iee_code _iee_set_key_revoked_at(unsigned long __unused, struct key *key, time64_t revoked_at); -+void __iee_code _iee_set_key_last_used_at(unsigned long __unused, struct key *key, time64_t last_used_at); -+void __iee_code _iee_set_key_uid(unsigned long __unused, struct key *key, kuid_t uid); -+void __iee_code _iee_set_key_gid(unsigned long __unused, struct key *key, kgid_t gid); -+void __iee_code _iee_set_key_perm(unsigned long __unused, struct key *key, key_perm_t perm); -+void __iee_code _iee_set_key_quotalen(unsigned long __unused, struct key *key, unsigned short quotalen); -+void __iee_code _iee_set_key_datalen(unsigned long __unused, struct key *key, unsigned short datalen); -+void __iee_code _iee_set_key_state(unsigned long __unused, struct key *key, short state); -+void __iee_code _iee_set_key_magic(unsigned long __unused, struct key *key, unsigned int magic); -+void __iee_code _iee_set_key_flags(unsigned long __unused, struct key *key, unsigned long flags); -+void __iee_code _iee_set_key_index_key(unsigned long __unused, struct key *key, struct keyring_index_key *index_key); -+void __iee_code _iee_set_key_hash(unsigned long __unused, struct key *key, unsigned long hash); -+void __iee_code _iee_set_key_len_desc(unsigned long __unused, struct key *key, unsigned long len_desc); -+void __iee_code _iee_set_key_type(unsigned long __unused, struct key *key, struct key_type *type); -+void __iee_code _iee_set_key_domain_tag(unsigned long __unused, struct key *key, struct key_tag *domain_tag); -+void __iee_code _iee_set_key_description(unsigned long __unused, struct key *key, char *description); -+void __iee_code _iee_set_key_restrict_link(unsigned long __unused, struct key *key, -+ struct key_restriction *restrict_link); -+unsigned long __iee_code _iee_set_key_flag_bit(unsigned long __unused, struct key *key, long nr, int flag); -+#endif -+#endif -diff --git a/arch/x86/include/asm/page.h b/arch/x86/include/asm/page.h -index 1b93ff8..e35b4f4 100644 ---- a/arch/x86/include/asm/page.h -+++ b/arch/x86/include/asm/page.h -@@ -61,6 +61,16 @@ static inline void copy_user_page(void *to, void *from, unsigned long vaddr, - #define __boot_va(x) __va(x) - #define __boot_pa(x) __pa(x) - -+#ifdef CONFIG_IEE -+extern unsigned long IEE_OFFSET; -+#ifndef __iee_pa -+#define __iee_pa(x) (__pa(x - IEE_OFFSET)) -+#endif -+#ifndef __phys_to_iee -+#define __phys_to_iee(x) ((void *)(__va(x) + IEE_OFFSET)) -+#endif -+#endif /* CONFIG_IEE*/ -+ - /* - * virt_to_page(kaddr) returns a valid pointer if and only if - * virt_addr_valid(kaddr) returns true. -diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h -index 86bd431..7e03d97 100644 ---- a/arch/x86/include/asm/page_types.h -+++ b/arch/x86/include/asm/page_types.h -@@ -29,6 +29,11 @@ - - #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) - -+#ifdef CONFIG_IEE -+#define SET_RO(x) __pg(pgprot_val(x) & (~__RW) & (~___D)) -+#define SET_NG(x) __pg(pgprot_val(x) & (~_PAGE_GLOBAL)) -+#endif /* CONFIG_IEE*/ -+ - #define VM_DATA_DEFAULT_FLAGS VM_DATA_FLAGS_TSK_EXEC - - #define __PHYSICAL_START ALIGN(CONFIG_PHYSICAL_START, \ -diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h -index dcd836b..d0a5e44 100644 ---- a/arch/x86/include/asm/pgalloc.h -+++ b/arch/x86/include/asm/pgalloc.h -@@ -147,6 +147,64 @@ static inline void pgd_populate_safe(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4 - set_pgd_safe(pgd, __pgd(_PAGE_TABLE | __pa(p4d))); - } - -+#ifdef CONFIG_PTP -+#include <linux/iee-func.h> -+ -+static inline void iee_pmd_populate_kernel_pre_init(struct mm_struct *mm, -+ pmd_t *pmd, pte_t *pte) -+{ -+ paravirt_alloc_pte(mm, __pa(pte) >> PAGE_SHIFT); -+ iee_set_pmd_pre_init(pmd, __pmd(__pa(pte) | _PAGE_TABLE)); -+} -+static inline void iee_pmd_populate_kernel_safe_pre_init(struct mm_struct *mm, -+ pmd_t *pmd, pte_t *pte) -+{ -+ paravirt_alloc_pte(mm, __pa(pte) >> PAGE_SHIFT); -+ iee_set_pmd_safe_pre_init(pmd, __pmd(__pa(pte) | _PAGE_TABLE)); -+} -+ -+static inline void iee_pud_populate_pre_init(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) -+{ -+ paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT); -+ iee_set_pud_pre_init(pud, __pud(_PAGE_TABLE | __pa(pmd))); -+} -+ -+static inline void iee_pud_populate_safe_pre_init(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) -+{ -+ paravirt_alloc_pmd(mm, __pa(pmd) >> PAGE_SHIFT); -+ iee_set_pud_safe_pre_init(pud, __pud(_PAGE_TABLE | __pa(pmd))); -+} -+ -+static inline void iee_p4d_populate_pre_init(struct mm_struct *mm, p4d_t *p4d, pud_t *pud) -+{ -+ paravirt_alloc_pud(mm, __pa(pud) >> PAGE_SHIFT); -+ iee_set_p4d_pre_init(p4d, __p4d(_PAGE_TABLE | __pa(pud))); -+} -+ -+static inline void iee_p4d_populate_safe_pre_init(struct mm_struct *mm, p4d_t *p4d, pud_t *pud) -+{ -+ paravirt_alloc_pud(mm, __pa(pud) >> PAGE_SHIFT); -+ iee_set_p4d_safe_pre_init(p4d, __p4d(_PAGE_TABLE | __pa(pud))); -+} -+ -+static inline void iee_pgd_populate_pre_init(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d) -+{ -+ if (!pgtable_l5_enabled()) -+ return; -+ paravirt_alloc_p4d(mm, __pa(p4d) >> PAGE_SHIFT); -+ iee_set_pgd_pre_init(pgd, __pgd(_PAGE_TABLE | __pa(p4d))); -+} -+ -+static inline void iee_pgd_populate_safe_pre_init(struct mm_struct *mm, pgd_t *pgd, p4d_t *p4d) -+{ -+ if (!pgtable_l5_enabled()) -+ return; -+ paravirt_alloc_p4d(mm, __pa(p4d) >> PAGE_SHIFT); -+ iee_set_pgd_safe_pre_init(pgd, __pgd(_PAGE_TABLE | __pa(p4d))); -+} -+ -+#endif -+ - static inline p4d_t *p4d_alloc_one(struct mm_struct *mm, unsigned long addr) - { - gfp_t gfp = GFP_KERNEL_ACCOUNT; -diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h -index c92de171..6460c84 100644 ---- a/arch/x86/include/asm/pgtable.h -+++ b/arch/x86/include/asm/pgtable.h -@@ -94,6 +94,14 @@ extern pmdval_t early_pmd_flags; - #define pud_clear(pud) native_pud_clear(pud) - #endif - -+#ifdef CONFIG_PTP -+#define iee_set_pte_pre_init(ptep, pte) iee_early_set_pte(ptep, pte) -+#define iee_set_pmd_pre_init(pmdp, pmd) iee_early_set_pmd(pmdp, pmd) -+#define iee_set_pgd_pre_init(pgdp, pgd) iee_early_set_pgd(pgdp, pgd) -+#define iee_set_p4d_pre_init(p4dp, p4d) iee_early_set_p4d(p4dp, p4d) -+#define iee_set_pud_pre_init(pudp, pud) iee_early_set_pud(pudp, pud) -+#endif -+ - #define pte_clear(mm, addr, ptep) native_pte_clear(mm, addr, ptep) - #define pmd_clear(pmd) native_pmd_clear(pmd) - -@@ -252,6 +260,14 @@ static inline unsigned long pgd_pfn(pgd_t pgd) - return (pgd_val(pgd) & PTE_PFN_MASK) >> PAGE_SHIFT; - } - -+#ifdef CONFIG_IEE -+#define __pte_to_phys(pte) (pte_pfn(pte) << PAGE_SHIFT) -+#define __pmd_to_phys(pmd) (__pte_to_phys(__pte(pmd_val(pmd)))) -+#define __pud_to_phys(pud) (__pte_to_phys(__pte(pud_val(pud)))) -+#define __p4d_to_phys(p4d) (__pte_to_phys(__pte(p4d_val(p4d)))) -+#define __pgd_to_phys(pgd) (__pte_to_phys(__pte(pgd_val(pgd)))) -+#endif -+ - #define p4d_leaf p4d_leaf - static inline bool p4d_leaf(p4d_t p4d) - { -@@ -1184,6 +1200,14 @@ static inline int pgd_none(pgd_t pgd) - - extern int direct_gbpages; - void init_mem_mapping(void); -+#ifdef CONFIG_IEE -+void init_iee_mapping(void); -+unsigned long init_memory_mapping_for_iee(unsigned long start, -+ unsigned long end, pgprot_t prot); -+#endif /* CONFIG_IEE*/ -+#ifdef CONFIG_PTP -+void init_iee(void); -+#endif - void early_alloc_pgt_buf(void); - extern void memblock_find_dma_reserve(void); - void __init poking_init(void); -@@ -1284,6 +1308,11 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, - return pte; - } - -+#ifdef CONFIG_PTP -+extern pgprotval_t iee_set_try_cmpxchg(pgprotval_t *pgprotp, pgprotval_t old_pgprotval, pgprotval_t new_pgprotval); -+extern pgprotval_t iee_set_xchg(pgprotval_t *pgprotp, pgprotval_t pgprotval); -+#endif -+ - #define __HAVE_ARCH_PTEP_SET_WRPROTECT - static inline void ptep_set_wrprotect(struct mm_struct *mm, - unsigned long addr, pte_t *ptep) -@@ -1296,9 +1325,15 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, - pte_t old_pte, new_pte; - - old_pte = READ_ONCE(*ptep); -+ #ifdef CONFIG_PTP -+ do { -+ new_pte = pte_wrprotect(old_pte); -+ } while (!iee_set_try_cmpxchg((long *)ptep, pte_val(old_pte), pte_val(new_pte))); -+ #else - do { - new_pte = pte_wrprotect(old_pte); - } while (!try_cmpxchg((long *)&ptep->pte, (long *)&old_pte, *(long *)&new_pte)); -+ #endif - } - - #define flush_tlb_fix_spurious_fault(vma, address, ptep) do { } while (0) -@@ -1358,9 +1393,15 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, - pmd_t old_pmd, new_pmd; - - old_pmd = READ_ONCE(*pmdp); -+ #ifdef CONFIG_PTP -+ do { -+ new_pmd = pmd_wrprotect(old_pmd); -+ } while (!iee_set_try_cmpxchg((long *)pmdp, pmd_val(old_pmd), pmd_val(new_pmd))); -+ #else - do { - new_pmd = pmd_wrprotect(old_pmd); - } while (!try_cmpxchg((long *)pmdp, (long *)&old_pmd, *(long *)&new_pmd)); -+ #endif - } - - #ifndef pmdp_establish -@@ -1370,10 +1411,20 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma, - { - page_table_check_pmd_set(vma->vm_mm, pmdp, pmd); - if (IS_ENABLED(CONFIG_SMP)) { -+ #ifdef CONFIG_PTP -+ pmdval_t pmdval = iee_set_xchg((long *)pmdp, pmd_val(pmd)); -+ -+ return native_make_pmd(pmdval); -+ #else - return xchg(pmdp, pmd); -+ #endif - } else { - pmd_t old = *pmdp; -+ #ifdef CONFIG_PTP -+ set_pmd(pmdp, pmd); -+ #else - WRITE_ONCE(*pmdp, pmd); -+ #endif - return old; - } - } -diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h -index 8108d68d..002fe7d 100644 ---- a/arch/x86/include/asm/pgtable_64.h -+++ b/arch/x86/include/asm/pgtable_64.h -@@ -31,6 +31,13 @@ extern pgd_t init_top_pgt[]; - extern void paging_init(void); - static inline void sync_initial_page_table(void) { } - -+#ifdef CONFIG_PTP -+#include <asm/iee-setpgtable.h> -+#include <asm/iee-def.h> -+extern unsigned long long iee_rw_gate(int flag, ...); -+extern pgprotval_t iee_set_xchg(pgprotval_t *pgprotp, pgprotval_t pgprotval); -+#endif -+ - #define pte_ERROR(e) \ - pr_err("%s:%d: bad pte %p(%016lx)\n", \ - __FILE__, __LINE__, &(e), pte_val(e)) -@@ -64,7 +71,12 @@ void set_pte_vaddr_pud(pud_t *pud_page, unsigned long vaddr, pte_t new_pte); - - static inline void native_set_pte(pte_t *ptep, pte_t pte) - { -+ #ifdef CONFIG_PTP -+ compiletime_assert_rwonce_type(*ptep); -+ iee_set_pte(IEE_OP_SET_PTE, ptep, pte); -+ #else - WRITE_ONCE(*ptep, pte); -+ #endif - } - - static inline void native_pte_clear(struct mm_struct *mm, unsigned long addr, -@@ -80,7 +92,12 @@ static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) - - static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd) - { -+ #ifdef CONFIG_PTP -+ compiletime_assert_rwonce_type(*pmdp); -+ iee_set_pmd(IEE_OP_SET_PMD, pmdp, pmd); -+ #else - WRITE_ONCE(*pmdp, pmd); -+ #endif - } - - static inline void native_pmd_clear(pmd_t *pmd) -@@ -91,7 +108,13 @@ static inline void native_pmd_clear(pmd_t *pmd) - static inline pte_t native_ptep_get_and_clear(pte_t *xp) - { - #ifdef CONFIG_SMP -+ #ifdef CONFIG_PTP -+ pteval_t pteval = iee_set_xchg((long *)xp, 0); -+ -+ return native_make_pte(pteval); -+ #else - return native_make_pte(xchg(&xp->pte, 0)); -+ #endif - #else - /* native_local_ptep_get_and_clear, - but duplicated because of cyclic dependency */ -@@ -104,7 +127,13 @@ static inline pte_t native_ptep_get_and_clear(pte_t *xp) - static inline pmd_t native_pmdp_get_and_clear(pmd_t *xp) - { - #ifdef CONFIG_SMP -+ #ifdef CONFIG_PTP -+ pmdval_t pmdval = iee_set_xchg((long *)xp, 0); -+ -+ return native_make_pmd(pmdval); -+ #else - return native_make_pmd(xchg(&xp->pmd, 0)); -+ #endif - #else - /* native_local_pmdp_get_and_clear, - but duplicated because of cyclic dependency */ -@@ -116,7 +145,12 @@ static inline pmd_t native_pmdp_get_and_clear(pmd_t *xp) - - static inline void native_set_pud(pud_t *pudp, pud_t pud) - { -+ #ifdef CONFIG_PTP -+ compiletime_assert_rwonce_type(*pudp); -+ iee_set_pud(IEE_OP_SET_PUD, pudp, pud); -+ #else - WRITE_ONCE(*pudp, pud); -+ #endif - } - - static inline void native_pud_clear(pud_t *pud) -@@ -127,7 +161,13 @@ static inline void native_pud_clear(pud_t *pud) - static inline pud_t native_pudp_get_and_clear(pud_t *xp) - { - #ifdef CONFIG_SMP -+ #ifdef CONFIG_PTP -+ pudval_t pudval = iee_set_xchg((long *)xp, 0); -+ -+ return native_make_pud(pudval); -+ #else - return native_make_pud(xchg(&xp->pud, 0)); -+ #endif - #else - /* native_local_pudp_get_and_clear, - * but duplicated because of cyclic dependency -@@ -145,13 +185,23 @@ static inline void native_set_p4d(p4d_t *p4dp, p4d_t p4d) - - if (pgtable_l5_enabled() || - !IS_ENABLED(CONFIG_MITIGATION_PAGE_TABLE_ISOLATION)) { -+ #ifdef CONFIG_PTP -+ compiletime_assert_rwonce_type(*p4dp); -+ iee_set_p4d(IEE_OP_SET_P4D, p4dp, p4d); -+ #else - WRITE_ONCE(*p4dp, p4d); -+ #endif - return; - } - - pgd = native_make_pgd(native_p4d_val(p4d)); - pgd = pti_set_user_pgtbl((pgd_t *)p4dp, pgd); -+ #ifdef CONFIG_PTP -+ compiletime_assert_rwonce_type(*p4dp); -+ iee_set_p4d(IEE_OP_SET_P4D, p4dp, native_make_p4d(native_pgd_val(pgd))); -+ #else - WRITE_ONCE(*p4dp, native_make_p4d(native_pgd_val(pgd))); -+ #endif - } - - static inline void native_p4d_clear(p4d_t *p4d) -@@ -161,7 +211,12 @@ static inline void native_p4d_clear(p4d_t *p4d) - - static inline void native_set_pgd(pgd_t *pgdp, pgd_t pgd) - { -+ #ifdef CONFIG_PTP -+ compiletime_assert_rwonce_type(*pgdp); -+ iee_set_pgd(IEE_OP_SET_PGD, pgdp, pti_set_user_pgtbl(pgdp, pgd)); -+ #else - WRITE_ONCE(*pgdp, pti_set_user_pgtbl(pgdp, pgd)); -+ #endif - } - - static inline void native_pgd_clear(pgd_t *pgd) -@@ -169,6 +224,42 @@ static inline void native_pgd_clear(pgd_t *pgd) - native_set_pgd(pgd, native_make_pgd(0)); - } - -+#ifdef CONFIG_PTP -+static inline void iee_early_set_pte(pte_t *ptep, pte_t pte) -+{ -+ WRITE_ONCE(*ptep, pte); -+} -+ -+static inline void iee_early_set_pmd(pmd_t *pmdp, pmd_t pmd) -+{ -+ WRITE_ONCE(*pmdp, pmd); -+} -+ -+static inline void iee_early_set_pud(pud_t *pudp, pud_t pud) -+{ -+ WRITE_ONCE(*pudp, pud); -+} -+ -+static inline void iee_early_set_p4d(p4d_t *p4dp, p4d_t p4d) -+{ -+ pgd_t pgd; -+ -+ if (pgtable_l5_enabled() || !IS_ENABLED(CONFIG_PAGE_TABLE_ISOLATION)) { -+ WRITE_ONCE(*p4dp, p4d); -+ return; -+ } -+ -+ pgd = native_make_pgd(native_p4d_val(p4d)); -+ pgd = pti_set_user_pgtbl((pgd_t *)p4dp, pgd); -+ WRITE_ONCE(*p4dp, native_make_p4d(native_pgd_val(pgd))); -+} -+ -+static inline void iee_early_set_pgd(pgd_t *pgdp, pgd_t pgd) -+{ -+ WRITE_ONCE(*pgdp, pti_set_user_pgtbl(pgdp, pgd)); -+} -+#endif -+ - /* - * Conversion functions: convert a page and protection to a page entry, - * and a page entry and page directory to the page they refer to. -diff --git a/arch/x86/include/asm/special_insns.h b/arch/x86/include/asm/special_insns.h -index 48f8dd4..7dd03d3 100644 ---- a/arch/x86/include/asm/special_insns.h -+++ b/arch/x86/include/asm/special_insns.h -@@ -10,6 +10,10 @@ - #include <linux/irqflags.h> - #include <linux/jump_label.h> - -+#ifdef CONFIG_IEE -+#include <asm/iee-si.h> -+#endif -+ - /* - * The compiler should not reorder volatile asm statements with respect to each - * other: they should execute in program order. However GCC 4.9.x and 5.x have -@@ -51,8 +55,19 @@ static inline unsigned long __native_read_cr3(void) - - static inline void native_write_cr3(unsigned long val) - { -+ #ifdef CONFIG_IEE -+ iee_rwx_gate(IEE_WRITE_CR3, val); -+ #else - asm volatile("mov %0,%%cr3": : "r" (val) : "memory"); -+ #endif -+} -+ -+#ifdef CONFIG_IEE -+static inline void native_write_cr3_pre_init(unsigned long val) -+{ -+ asm volatile("mov %0,%%cr3" : : "r" (val) : "memory"); - } -+#endif - - static inline unsigned long native_read_cr4(void) - { -diff --git a/arch/x86/include/asm/stack-slab.h b/arch/x86/include/asm/stack-slab.h -new file mode 100644 -index 0000000..d8faa62 ---- /dev/null -+++ b/arch/x86/include/asm/stack-slab.h -@@ -0,0 +1,9 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _LINUX_STACK_SLAB_H -+#define _LINUX_STACK_SLAB_H -+ -+extern void __init iee_stack_init(void); -+extern void *get_iee_stack(void); -+extern void free_iee_stack(void *obj); -+ -+#endif -diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile -index faeb14f..ec732f6 100644 ---- a/arch/x86/kernel/Makefile -+++ b/arch/x86/kernel/Makefile -@@ -150,6 +150,8 @@ obj-$(CONFIG_X86_CET) += cet.o - - obj-$(CONFIG_X86_USER_SHADOW_STACK) += shstk.o - -+obj-$(CONFIG_IEE) += iee/ -+ - ### - # 64 bit specific files - ifeq ($(CONFIG_X86_64),y) -diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c -index a98020b..5009bf0 100644 ---- a/arch/x86/kernel/asm-offsets.c -+++ b/arch/x86/kernel/asm-offsets.c -@@ -112,6 +112,12 @@ static void __used common(void) - #ifdef CONFIG_MITIGATION_CALL_DEPTH_TRACKING - OFFSET(X86_call_depth, pcpu_hot, call_depth); - #endif -+#ifdef CONFIG_IEE -+ DEFINE(iee_from_token_offset, offsetof(struct task_token, iee_stack)); -+ DEFINE(tmp_page_from_token_offset, offsetof(struct task_token, tmp_page)); -+ DEFINE(kernel_from_token_offset, offsetof(struct task_token, kernel_stack)); -+ DEFINE(pgd_from_token_offset, offsetof(struct task_token, pgd)); -+#endif - #if IS_ENABLED(CONFIG_CRYPTO_ARIA_AESNI_AVX_X86_64) - /* Offset for fields in aria_ctx */ - BLANK(); -diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c -index 5c1ed18..9bd8a21 100644 ---- a/arch/x86/kernel/cpu/common.c -+++ b/arch/x86/kernel/cpu/common.c -@@ -68,6 +68,9 @@ - #include <asm/tdx.h> - - #include "cpu.h" -+#ifdef CONFIG_IEE -+#include <asm/iee-si.h> -+#endif - - u32 elf_hwcap2 __read_mostly; - -@@ -401,14 +404,25 @@ static __always_inline void setup_umip(struct cpuinfo_x86 *c) - } - - /* These bits should not change their value after CPU init is finished. */ -+#ifdef CONFIG_IEE -+const unsigned long cr4_pinned_mask = -+ X86_CR4_UMIP | -+ X86_CR4_FSGSBASE | X86_CR4_CET; -+DEFINE_STATIC_KEY_FALSE_RO(cr_pinning); -+unsigned long cr4_pinned_bits __ro_after_init; -+#else - static const unsigned long cr4_pinned_mask = - X86_CR4_SMEP | X86_CR4_SMAP | X86_CR4_UMIP | - X86_CR4_FSGSBASE | X86_CR4_CET; - static DEFINE_STATIC_KEY_FALSE_RO(cr_pinning); - static unsigned long cr4_pinned_bits __ro_after_init; -+#endif - - void native_write_cr0(unsigned long val) - { -+#ifdef CONFIG_IEE -+ iee_rwx_gate(IEE_WRITE_CR0, val); -+#else - unsigned long bits_missing = 0; - - set_register: -@@ -423,11 +437,15 @@ void native_write_cr0(unsigned long val) - /* Warn after we've set the missing bits. */ - WARN_ONCE(bits_missing, "CR0 WP bit went missing!?\n"); - } -+#endif - } - EXPORT_SYMBOL(native_write_cr0); - - void __no_profile native_write_cr4(unsigned long val) - { -+#ifdef CONFIG_IEE -+ iee_rwx_gate(IEE_WRITE_CR4, val); -+#else - unsigned long bits_changed = 0; - - set_register: -@@ -443,6 +461,7 @@ void __no_profile native_write_cr4(unsigned long val) - WARN_ONCE(bits_changed, "pinned CR4 bits changed: 0x%lx!?\n", - bits_changed); - } -+#endif - } - #if IS_MODULE(CONFIG_LKDTM) - EXPORT_SYMBOL_GPL(native_write_cr4); -@@ -608,7 +627,9 @@ static __always_inline void setup_cet(struct cpuinfo_x86 *c) - else - wrmsrl(MSR_IA32_S_CET, 0); - -+ #ifndef CONFIG_IEE - cr4_set_bits(X86_CR4_CET); -+ #endif - - if (kernel_ibt && ibt_selftest()) { - pr_err("IBT selftest: Failed!\n"); -diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c -index f6ef401..6a166b9 100644 ---- a/arch/x86/kernel/cpu/mce/core.c -+++ b/arch/x86/kernel/cpu/mce/core.c -@@ -2115,10 +2115,12 @@ static __always_inline void exc_machine_check_kernel(struct pt_regs *regs) - - static __always_inline void exc_machine_check_user(struct pt_regs *regs) - { -- irqentry_enter_from_user_mode(regs); -+ irqentry_state_t irq_state; - -+ irqentry_enter_from_user_mode(regs); -+ irq_state = irqentry_nmi_enter(regs); - do_machine_check(regs); -- -+ irqentry_nmi_exit(regs, irq_state); - irqentry_exit_to_user_mode(regs); - } - -diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c -index ff888f2..d079dfb 100644 ---- a/arch/x86/kernel/head64.c -+++ b/arch/x86/kernel/head64.c -@@ -44,6 +44,10 @@ - #include <asm/csv.h> - #include <asm/init.h> - -+#ifdef CONFIG_IEE -+#include <asm/iee-si.h> -+#endif -+ - /* - * Manage page tables very early on. - */ -@@ -659,7 +663,11 @@ static void startup_64_load_idt(unsigned long physbase) - } - - desc->address = (unsigned long)idt; -+ #ifdef CONFIG_IEE -+ iee_load_idt_pre_init(desc); -+ #else - native_load_idt(desc); -+ #endif - } - - /* This is used when running on kernel addresses */ -diff --git a/arch/x86/kernel/iee/Makefile b/arch/x86/kernel/iee/Makefile -new file mode 100644 -index 0000000..fbdbb00 ---- /dev/null -+++ b/arch/x86/kernel/iee/Makefile -@@ -0,0 +1,4 @@ -+obj-$(CONFIG_IEE) += iee.o iee-gate.o iee-func.o stack-slab.o page-slab.o -+ccflags-y += -I$(srctree)/mm -+obj-$(CONFIG_IEE_SELINUX_P) += iee-selinuxp.o -+ccflags-$(CONFIG_IEE_SELINUX_P) += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include -diff --git a/arch/x86/kernel/iee/iee-func.c b/arch/x86/kernel/iee/iee-func.c -new file mode 100644 -index 0000000..118e4a1 ---- /dev/null -+++ b/arch/x86/kernel/iee/iee-func.c -@@ -0,0 +1,369 @@ -+// SPDX-License-Identifier: GPL-2.0 -+#include <linux/memory.h> -+#include <linux/mm.h> -+#include <linux/hugetlb.h> -+#include <asm/tlb.h> -+#include <asm/tlbflush.h> -+#include <asm/pgalloc.h> -+#include <linux/iee-func.h> -+#include <asm/iee-access.h> -+#include <asm/pgalloc.h> -+#include <asm/set_memory.h> -+ -+static inline void iee_set_sensitive_pte(pte_t *lm_ptep, int order, int use_block_pmd) -+{ -+#ifdef CONFIG_PTP -+ iee_rw_gate(IEE_SET_SENSITIVE_PTE, lm_ptep, order, use_block_pmd); -+#else -+ int i; -+ -+ if (use_block_pmd) { -+ pmd_t pmd = __pmd(pte_val(READ_ONCE(*lm_ptep))); -+ -+ pmd = __pmd((pmd_val(pmd) & (~__RW) & (~___D))); -+ WRITE_ONCE(*lm_ptep, __pte(pmd_val(pmd))); -+ } else { -+ for (i = 0; i < (1 << order); i++) { -+ pte_t pte = READ_ONCE(*lm_ptep); -+ -+ pte = __pte((pte_val(pte) & (~__RW) & (~___D))); -+ WRITE_ONCE(*lm_ptep, pte); -+ lm_ptep++; -+ } -+ } -+#endif -+} -+ -+static inline void iee_unset_sensitive_pte(pte_t *lm_ptep, int order, int use_block_pmd) -+{ -+#ifdef CONFIG_PTP -+ iee_rw_gate(IEE_UNSET_SENSITIVE_PTE, lm_ptep, order, use_block_pmd); -+#else -+ int i; -+ -+ if (use_block_pmd) { -+ pmd_t pmd = __pmd(pte_val(READ_ONCE(*lm_ptep))); -+ -+ pmd = __pmd((pmd_val(pmd) | __RW | ___D)); -+ WRITE_ONCE(*lm_ptep, __pte(pmd_val(pmd))); -+ } else { -+ for (i = 0; i < (1 << order); i++) { -+ pte_t pte = READ_ONCE(*lm_ptep); -+ -+ pte = __pte(pte_val(pte) | __RW | ___D); -+ WRITE_ONCE(*lm_ptep, pte); -+ lm_ptep++; -+ } -+ } -+#endif -+} -+ -+static void do_split_huge_pmd(pmd_t *pmdp) -+{ -+ pte_t *pgtable = pte_alloc_one_kernel(&init_mm); -+ -+ #ifdef CONFIG_PTP -+ iee_split_huge_pmd(pmdp, pgtable); -+ #else -+ int i; -+ struct page *page = pmd_page(*pmdp); -+ pte_t *ptep = (pte_t *)((unsigned long)pgtable); -+ -+ for (i = 0; i < PMD_SIZE / PAGE_SIZE; i++, ptep++) { -+ pte_t entry; -+ pgprot_t pgprot = pmd_pgprot(*pmdp); -+ -+ entry = mk_pte(page + i, pgprot); -+ WRITE_ONCE(*ptep, entry); -+ } -+ #endif -+ spinlock_t *ptl = pmd_lock(&init_mm, pmdp); -+ -+ if (pmd_leaf(READ_ONCE(*pmdp))) { -+ /* avoid two users to split the same huge pmd */ -+ smp_wmb(); -+ pmd_populate_kernel(&init_mm, pmdp, pgtable); -+ pgtable = NULL; -+ } -+ spin_unlock(ptl); -+ if (pgtable) { -+ #ifdef CONFIG_PTP -+ iee_memset(pgtable, 0, PAGE_SIZE); -+ #endif -+ pte_free_kernel(&init_mm, pgtable); -+ } -+} -+ -+// Input is the lm vaddr of sensitive data. -+void set_iee_page(unsigned long addr, int order) -+{ -+ pgd_t *pgdir = swapper_pg_dir; -+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr); -+ p4d_t *p4dp = p4d_offset(pgdp, addr); -+ pud_t *pudp = pud_offset(p4dp, addr); -+ pmd_t *pmdp = pmd_offset(pudp, addr); -+ int use_block_pmd = 0; -+ -+ if (pmd_leaf(*pmdp) && order < 9) -+ do_split_huge_pmd(pmdp); -+ else if (pmd_leaf(*pmdp)) -+ use_block_pmd = 1; -+ -+ pte_t *lm_ptep; -+ -+ if (use_block_pmd) -+ lm_ptep = (pte_t *)pmdp; -+ else -+ lm_ptep = pte_offset_kernel(pmdp, addr); -+ -+ iee_set_sensitive_pte(lm_ptep, order, use_block_pmd); -+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE*(1 << order)); -+} -+ -+// Input is the lm vaddr of sensitive data. -+void unset_iee_page(unsigned long addr, int order) -+{ -+ pgd_t *pgdir = swapper_pg_dir; -+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr); -+ p4d_t *p4dp = p4d_offset(pgdp, addr); -+ pud_t *pudp = pud_offset(p4dp, addr); -+ pmd_t *pmdp = pmd_offset(pudp, addr); -+ pte_t *lm_ptep; -+ int use_block_pmd = 0; -+ // Use Block Descriptor. -+ if (pmd_leaf(*pmdp)) { -+ use_block_pmd = 1; -+ lm_ptep = (pte_t *)pmdp; -+ } else -+ lm_ptep = pte_offset_kernel(pmdp, addr); -+ -+ iee_unset_sensitive_pte(lm_ptep, order, use_block_pmd); -+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE*(1 << order)); -+} -+ -+void iee_set_logical_mem_ro(unsigned long addr) -+{ -+ pgd_t *pgdir = swapper_pg_dir; -+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr); -+ p4d_t *p4dp = p4d_offset(pgdp, addr); -+ pud_t *pudp = pud_offset(p4dp, addr); -+ pmd_t *pmdp = pmd_offset(pudp, addr); -+ -+ if (pmd_leaf(*pmdp)) -+ do_split_huge_pmd(pmdp); -+ -+ pte_t *ptep = pte_offset_kernel(pmdp, addr); -+ pte_t pte = READ_ONCE(*ptep); -+ -+ pte = __pte((pte_val(pte) & (~__RW) & (~___D))); -+ set_pte(ptep, pte); -+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE); -+} -+ -+void set_iee_page_valid(unsigned long addr) {} -+ -+void set_iee_page_invalid(unsigned long addr) {} -+ -+void iee_set_token_page_valid(void *token, void *token_page, unsigned int order) -+{ -+ pgd_t *pgdir = swapper_pg_dir; -+ pgd_t *pgdp = pgd_offset_pgd(pgdir, (unsigned long)token); -+ p4d_t *p4dp = p4d_offset(pgdp, (unsigned long)token); -+ pud_t *pudp = pud_offset(p4dp, (unsigned long)token); -+ pmd_t *token_pmdp = pmd_offset(pudp, (unsigned long)token); -+ pte_t *token_ptep; -+ -+ pgdp = pgd_offset_pgd(pgdir, (unsigned long)token_page); -+ p4dp = p4d_offset(pgdp, (unsigned long)token_page); -+ pudp = pud_offset(p4dp, (unsigned long)token_page); -+ pmd_t *token_page_pmdp = pmd_offset(pudp, (unsigned long)token_page); -+ pte_t *token_page_ptep; -+ int use_block_pmd = 0; -+ -+ if (pmd_leaf(*token_pmdp) && order < 9) { -+ do_split_huge_pmd(token_pmdp); -+ do_split_huge_pmd(token_page_pmdp); -+ } else if (pmd_leaf(*token_pmdp)) { -+ use_block_pmd = 1; -+ } -+ -+ if (use_block_pmd) { -+ token_ptep = (pte_t *)token_pmdp; -+ token_page_ptep = (pte_t *)token_page_pmdp; -+ } else { -+ token_ptep = pte_offset_kernel(token_pmdp, (unsigned long)token); -+ token_page_ptep = pte_offset_kernel(token_page_pmdp, (unsigned long)token_page); -+ } -+ -+#ifdef CONFIG_PTP -+ iee_rw_gate(IEE_OP_SET_TOKEN, token_ptep, token_page_ptep, token_page, order, use_block_pmd); -+#else -+ if (use_block_pmd) { -+ pmd_t *pmdp = (pmd_t *)token_page_ptep; -+ pmd_t pmd = READ_ONCE(*pmdp); -+ -+ pmd = __pmd((pmd_val(pmd) & ~__RW) & ~___D); -+ WRITE_ONCE(*pmdp, pmd); -+ pmdp = (pmd_t *)token_ptep; -+ pmd = READ_ONCE(*pmdp); -+ pmd = __pmd(((pmd_val(pmd) & ~PTE_PFN_MASK)) -+ | (__phys_to_pfn(__pa(token_page)) << PAGE_SHIFT)); -+ WRITE_ONCE(*pmdp, pmd); -+ } else { -+ for (int i = 0; i < (0x1 << order); i++) { -+ pte_t pte = READ_ONCE(*token_ptep); -+ -+ pte = __pte(((pte_val(pte) & ~PTE_PFN_MASK)) -+ | (__phys_to_pfn(__pa(token_page) + i * PAGE_SIZE) << PAGE_SHIFT)); -+ WRITE_ONCE(*token_ptep, pte); -+ pte = READ_ONCE(*token_page_ptep); -+ pte = __pte((pte_val(pte) & ~__RW) & ~___D); -+ WRITE_ONCE(*token_page_ptep, pte); -+ token_ptep++; -+ token_page_ptep++; -+ } -+ } -+#endif -+ flush_tlb_kernel_range((unsigned long)token, (unsigned long)(token + (PAGE_SIZE * (1 << order)))); -+ flush_tlb_kernel_range((unsigned long)token_page, (unsigned long)(token_page + (PAGE_SIZE * (1 << order)))); -+} -+ -+void iee_set_token_page_invalid(void *token, void *__unused, unsigned long order) -+{ -+ pgd_t *pgdir = swapper_pg_dir; -+ pgd_t *pgdp = pgd_offset_pgd(pgdir, (unsigned long)token); -+ p4d_t *p4dp = p4d_offset(pgdp, (unsigned long)token); -+ pud_t *pudp = pud_offset(p4dp, (unsigned long)token); -+ pmd_t *token_pmdp = pmd_offset(pudp, (unsigned long)token); -+ pte_t *token_ptep; -+ void *token_page; -+ int use_block_pmd = 0; -+ -+ if (pmd_leaf(*token_pmdp)) { -+ use_block_pmd = 1; -+ token_ptep = (pte_t *)token_pmdp; -+ token_page = page_address(pmd_page(*token_pmdp)); -+ } else { -+ token_ptep = pte_offset_kernel(token_pmdp, (unsigned long)token); -+ token_page = page_address(pte_page(*token_ptep)); -+ } -+ pgdp = pgd_offset_pgd(pgdir, (unsigned long)token_page); -+ p4dp = p4d_offset(pgdp, (unsigned long)token_page); -+ pudp = pud_offset(p4dp, (unsigned long)token_page); -+ pmd_t *token_page_pmdp = pmd_offset(pudp, (unsigned long)token_page); -+ pte_t *token_page_ptep; -+ -+ if (use_block_pmd) -+ token_page_ptep = (pte_t *)token_page_pmdp; -+ else -+ token_page_ptep = pte_offset_kernel(token_page_pmdp, (unsigned long)token); -+ -+#ifdef CONFIG_PTP -+ if (use_block_pmd) -+ iee_rw_gate(IEE_OP_UNSET_TOKEN, token_ptep, token_page_ptep, token, token_page, 0); -+ else -+ iee_rw_gate(IEE_OP_UNSET_TOKEN, token_ptep, token_page_ptep, token, token_page, order); -+#else -+ if (use_block_pmd) { -+ pmd_t *pmdp = (pmd_t *)token_page_ptep; -+ pmd_t pmd = READ_ONCE(*pmdp); -+ -+ pmd = __pmd(pmd_val(pmd) | ___D | __RW); -+ WRITE_ONCE(*pmdp, pmd); -+ pmdp = (pmd_t *)token_ptep; -+ pmd = READ_ONCE(*pmdp); -+ pmd = __pmd((pmd_val(pmd) & ~PTE_PFN_MASK) -+ | (__phys_to_pfn(__iee_pa(token)) << PAGE_SHIFT)); -+ WRITE_ONCE(*pmdp, pmd); -+ } else { -+ for (int i = 0; i < (0x1 << order); i++) { -+ pte_t pte = READ_ONCE(*token_ptep); -+ -+ pte = __pte((pte_val(pte) & ~PTE_PFN_MASK) -+ | (__phys_to_pfn(__iee_pa(token) + i * PAGE_SIZE) << PAGE_SHIFT)); -+ WRITE_ONCE(*token_ptep, pte); -+ pte = READ_ONCE(*token_page_ptep); -+ pte = __pte(pte_val(pte) | ___D | __RW); -+ WRITE_ONCE(*token_page_ptep, pte); -+ token_ptep++; -+ token_page_ptep++; -+ } -+ } -+#endif -+ free_pages((unsigned long)token_page, order); -+ flush_tlb_kernel_range((unsigned long)token, (unsigned long)(token + (PAGE_SIZE * (1 << order)))); -+ flush_tlb_kernel_range((unsigned long)token_page, (unsigned long)(token_page + (PAGE_SIZE * (1 << order)))); -+} -+ -+void __init iee_set_kernel_upage(unsigned long addr) -+{ -+ pgd_t *pgdir = swapper_pg_dir; -+ pgd_t *pgdp = pgd_offset_pgd(pgdir, addr); -+ pgd_t pgd = READ_ONCE(*pgdp); -+ -+ pgd = __pgd((pgd_val(pgd) | _USR) & ~___G); -+ set_pgd(pgdp, pgd); -+ -+ p4d_t *p4dp = p4d_offset(pgdp, addr); -+ p4d_t p4d = READ_ONCE(*p4dp); -+ -+ p4d = __p4d((p4d_val(p4d) | _USR) & ~___G); -+ set_p4d(p4dp, p4d); -+ -+ pud_t *pudp = pud_offset(p4dp, addr); -+ -+ if (pud_leaf(*pudp)) -+ panic("Huge pud page set upage!\n"); -+ -+ pud_t pud = READ_ONCE(*pudp); -+ -+ pud = __pud((pud_val(pud) | _USR) & ~___G); -+ set_pud(pudp, pud); -+ -+ pmd_t *pmdp = pmd_offset(pudp, addr); -+ -+ if (pmd_leaf(*pmdp)) -+ do_split_huge_pmd(pmdp); -+ -+ pmd_t pmd = READ_ONCE(*pmdp); -+ -+ pmd = __pmd((pmd_val(pmd) | _USR) & ~___G); -+ set_pmd(pmdp, pmd); -+ -+ pte_t *ptep = pte_offset_kernel(pmdp, addr); -+ pte_t pte = READ_ONCE(*ptep); -+ -+ pte = __pte((pte_val(pte) | _USR) & ~___G); -+ set_pte(ptep, pte); -+ flush_tlb_kernel_range(addr, addr + PAGE_SIZE); -+} -+ -+void set_iee_stack_page(unsigned long addr, int order) -+{ -+ set_iee_page(addr, order); -+} -+ -+void unset_iee_stack_page(unsigned long addr, int order) -+{ -+ unset_iee_page(addr, order); -+} -+ -+void __init iee_rest_init(void) -+{ -+ // Prepare data for iee rwx gate -+ unsigned long addr; -+ /* Map .iee.text as U RWX pages */ -+ addr = (unsigned long)__iee_si_text_start; -+ for (; addr < (unsigned long)__iee_si_text_end; addr += PAGE_SIZE) { -+ iee_set_kernel_upage((unsigned long)addr); -+ iee_set_kernel_upage((unsigned long)__va(__pa(addr))); -+ } -+ iee_init_done = true; -+ /* Map .iee.data as RO pages */ -+ set_memory_ro((unsigned long)__iee_si_data_start, -+ ((unsigned long)__iee_si_data_end - (unsigned long)__iee_si_data_start) / PAGE_SIZE); -+ // All initialization is done. Do some simple tests. -+ pr_err("IEE: testing iee_exec_entry si_test..."); -+ iee_rwx_gate(IEE_SI_TEST); -+ pr_err("IEE: testing iee_exec_entry si_test..."); -+} -diff --git a/arch/x86/kernel/iee/iee-gate.S b/arch/x86/kernel/iee/iee-gate.S -new file mode 100644 -index 0000000..ce8f09c ---- /dev/null -+++ b/arch/x86/kernel/iee/iee-gate.S -@@ -0,0 +1,284 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#include <linux/linkage.h> -+#include <asm/asm-offsets.h> -+#include <asm/percpu.h> -+#include <asm/processor-flags.h> -+#include <asm/asm.h> -+ -+#define X86_CR4_SMEP_SMAP (X86_CR4_SMEP | X86_CR4_SMAP) -+ -+/* scratch_reg would be changed, -+caller should dertimine if scratch_reg should be saved and restored */ -+.macro DISABLE_WP scratch_reg:req -+ /* Disable write protection*/ -+ movq %cr0, %\scratch_reg -+ andq $(~X86_CR0_WP), %\scratch_reg -+ movq %\scratch_reg, %cr0 -+.endm -+ -+.macro ENABLE_WP scratch_reg:req -+ /* Enable write protection */ -+ movq %cr0, %\scratch_reg -+1: -+ orq $X86_CR0_WP, %\scratch_reg -+ movq %\scratch_reg, %cr0 -+ testq $X86_CR0_WP, %\scratch_reg -+ je 1b -+.endm -+ -+SYM_FUNC_START(iee_rw_gate) -+ /* save Interrupt flag */ -+ pushf -+ /* close irq*/ -+ cli -+ -+ pushq %r12 -+ -+ DISABLE_WP r12 -+ -+ /* switch to iee stack */ -+ movq PER_CPU_VAR(pcpu_hot) + X86_current_task, %r12 /* r12 -> task_struct */ -+ addq iee_offset(%rip), %r12 -+ movq %rsp, kernel_from_token_offset(%r12) -+ movq iee_from_token_offset(%r12), %rsp -+ -+ /* call iee func */ -+ leaq iee_funcs(%rip), %rax -+ call *(%rax, %rdi, 8) -+ -+ /* switch to kernel stack */ -+ movq kernel_from_token_offset(%r12), %rsp -+ -+ ENABLE_WP r12 -+ -+ popq %r12 -+ -+ /* restore irq*/ -+ popf -+ -+ lfence /* Serializing instruction before the ret */ -+ jmp __x86_return_thunk /* ret */ -+SYM_FUNC_END(iee_rw_gate) -+#if defined(CONFIG_CREDP) || defined(CONFIG_KEYP) || defined(CONFIG_PTP) -+EXPORT_SYMBOL(iee_rw_gate) -+#endif -+ -+SYM_FUNC_START(iee_read_token_stack) -+ /* save Interrupt flag */ -+ pushf -+ /* close irq*/ -+ cli -+ -+ push %r12 -+ -+ DISABLE_WP r12 -+ -+ addq iee_offset(%rip), %rdi -+ movq iee_from_token_offset(%rdi), %rax -+ -+ ENABLE_WP r12 -+ -+ pop %r12 -+ -+ /* restore irq*/ -+ popf -+ -+ lfence /* Serializing instruction before the ret */ -+ jmp __x86_return_thunk /* ret */ -+SYM_FUNC_END(iee_read_token_stack) -+ -+SYM_FUNC_START(iee_read_tmp_page) -+ /* save Interrupt flag */ -+ pushf -+ /* close irq*/ -+ cli -+ -+ push %r12 -+ -+ DISABLE_WP r12 -+ -+ addq iee_offset(%rip), %rdi -+ movq tmp_page_from_token_offset(%rdi), %rax -+ -+ ENABLE_WP r12 -+ -+ pop %r12 -+ -+ /* restore irq*/ -+ popf -+ lfence /* Serializing instruction before the ret */ -+ jmp __x86_return_thunk /* ret */ -+SYM_FUNC_END(iee_read_tmp_page) -+ -+SYM_FUNC_START(iee_read_freeptr) -+ /* save Interrupt flag */ -+ pushf -+ /* close irq*/ -+ cli -+ -+ push %r12 -+ -+ DISABLE_WP r12 -+ -+ addq iee_offset(%rip), %rdi -+ movq (%rdi), %rax -+ -+ ENABLE_WP r12 -+ -+ pop %r12 -+ -+ /* restore irq*/ -+ popf -+ lfence /* Serializing instruction before the ret */ -+ jmp __x86_return_thunk /* ret */ -+SYM_FUNC_END(iee_read_freeptr) -+ -+SYM_FUNC_START(iee_rwx_gate) -+ pushq %r12 -+ -+ /* save Interrupt flag*/ -+ pushfq -+ /* close irq */ -+ cli -+ -+ /* set SMEP=0 to enable supervisor-mode exec user-mode insn */ -+ movq %cr4, %rax /* rax -> cr4 */ -+ andq $(~X86_CR4_SMEP), %rax -+ movq %rax, %cr4 -+ -+ DISABLE_WP r12 -+ -+ movq %rsp, %r12 -+ -+ /* If iee hasn't been initialized, skip stack switch. */ -+ cmpb $0, iee_init_done(%rip) -+ jz 2f -+ -+ /* switch to iee stack */ -+ movq PER_CPU_VAR(pcpu_hot) + X86_current_task, %rax /* rax -> task_struct */ -+ addq iee_offset(%rip), %rax -+ movq %rsp, kernel_from_token_offset(%rax) -+ movq iee_from_token_offset(%rax), %rsp -+ -+2: call iee_si_handler -+ -+ /* switch to kernel stack. If iee hasn't been initialized, skip switch*/ -+ movq %r12, %rsp -+ -+ ENABLE_WP r12 -+ -+ /* set SMEP=1 to disable supervisor-mode exec user-mode insn */ -+ movq %cr4, %rax /* rax -> cr4 */ -+1: orq $X86_CR4_SMEP_SMAP, %rax -+ movq %rax, %cr4 -+ andq $(X86_CR4_SMEP_SMAP), %rax -+ cmpq $(X86_CR4_SMEP_SMAP), %rax -+ jnz 1 -+ -+ /* restore irq*/ -+ popfq -+ -+ popq %r12 -+ jmp __x86_return_thunk /* ret */ -+SYM_FUNC_END(iee_rwx_gate) -+ -+#ifdef CONFIG_PTP -+SYM_FUNC_START(iee_set_xchg) -+.L_set_xchg: -+ xchg %rsi, (%rdi) -+ mov %rsi, %rax -+ jmp __x86_return_thunk /* ret */ -+.E_set_xchg: -+ /* save RFLAGS, close irq */ -+ pushfq -+ cli -+ -+ push %r12 -+ -+ DISABLE_WP r12 -+ -+ addq iee_offset(%rip), %rdi -+ xchg %rsi, (%rdi) -+ mov %rsi, %rax -+ -+ ENABLE_WP r12 -+ -+ popq %r12 -+ -+ /* restore RFLAGS*/ -+ popfq -+ jmp __x86_return_thunk /* ret */ -+ _ASM_EXTABLE(.L_set_xchg, .E_set_xchg) -+SYM_FUNC_END(iee_set_xchg) -+ -+SYM_FUNC_START(iee_set_try_cmpxchg) -+ mov %rsi, %rax -+.L_set_try_cmpxchg: -+ lock cmpxchgq %rdx, (%rdi) -+ jmp __x86_return_thunk /* ret */ -+.E_set_try_cmpxchg: -+ /* save RFLAGS, close irq */ -+ pushfq -+ cli -+ -+ pushq %r12 -+ -+ DISABLE_WP r12 -+ -+ addq iee_offset(%rip), %rdi -+ lock cmpxchgq %rdx, (%rdi) -+ -+ ENABLE_WP r12 -+ -+ popq %r12 -+ /* restore RFLAGS*/ -+ popfq -+ jmp __x86_return_thunk /* ret */ -+ _ASM_EXTABLE(.L_set_try_cmpxchg, .E_set_try_cmpxchg) -+SYM_FUNC_END(iee_set_try_cmpxchg) -+ -+.macro IEE_SET_PGTABLE level -+.L_set_\level: -+ movq %rdx, (%rsi) -+ jmp __x86_return_thunk -+.E_set_\level: -+ pushfq -+ cli -+ -+ DISABLE_WP rdi -+ -+ addq iee_offset(%rip), %rsi -+ movq %rdx, (%rsi) -+ -+ ENABLE_WP rdi -+ -+ popfq -+ jmp __x86_return_thunk -+ _ASM_EXTABLE(.L_set_\level, .E_set_\level) -+.endm -+ -+SYM_FUNC_START(iee_set_pte) -+ IEE_SET_PGTABLE pte -+SYM_FUNC_END(iee_set_pte) -+EXPORT_SYMBOL(iee_set_pte) -+ -+SYM_FUNC_START(iee_set_pmd) -+ IEE_SET_PGTABLE pmd -+SYM_FUNC_END(iee_set_pmd) -+EXPORT_SYMBOL(iee_set_pmd) -+ -+SYM_FUNC_START(iee_set_pud) -+ IEE_SET_PGTABLE pud -+SYM_FUNC_END(iee_set_pud) -+EXPORT_SYMBOL(iee_set_pud) -+ -+SYM_FUNC_START(iee_set_p4d) -+ IEE_SET_PGTABLE p4d -+SYM_FUNC_END(iee_set_p4d) -+EXPORT_SYMBOL(iee_set_p4d) -+ -+SYM_FUNC_START(iee_set_pgd) -+ IEE_SET_PGTABLE pgd -+SYM_FUNC_END(iee_set_pgd) -+EXPORT_SYMBOL(iee_set_pgd) -+#endif -diff --git a/arch/x86/kernel/iee/iee-selinuxp.c b/arch/x86/kernel/iee/iee-selinuxp.c -new file mode 100644 -index 0000000..1e5ecc8 ---- /dev/null -+++ b/arch/x86/kernel/iee/iee-selinuxp.c -@@ -0,0 +1,38 @@ -+// SPDX-License-Identifier: GPL-2.0 -+#include <asm/iee-selinuxp.h> -+#include <asm/iee-def.h> -+#include "security.h" -+#include "ss/services.h" -+ -+#ifdef CONFIG_IEE_SELINUX_P -+inline void iee_set_selinux_status_pg(struct page *new_page) -+{ -+ iee_rw_gate(IEE_SEL_SET_STATUS_PG, new_page); -+} -+ -+inline void enforcing_set(bool value) -+{ -+ iee_rw_gate(IEE_SEL_SET_ENFORCING, value); -+} -+ -+inline void selinux_mark_initialized(void) -+{ -+ iee_rw_gate(IEE_SEL_SET_INITIALIZED); -+} -+ -+inline void iee_set_sel_policy_cap(unsigned int idx, int cap) -+{ -+ iee_rw_gate(IEE_SEL_SET_POLICY_CAP, idx, cap); -+} -+ -+/* -+ * Please make sure param iee_new_policy is from policy_jar memcache. -+ * Need to free new_policy after calling this func as it's only used to -+ * trans data from kernel. -+ */ -+inline void iee_sel_rcu_assign_policy(struct selinux_policy *new_policy, -+ struct selinux_policy *iee_new_policy) -+{ -+ iee_rw_gate(IEE_SEL_RCU_ASSIGN_POLICY, new_policy, iee_new_policy); -+} -+#endif -diff --git a/arch/x86/kernel/iee/iee.c b/arch/x86/kernel/iee/iee.c -new file mode 100644 -index 0000000..b12fb56 ---- /dev/null -+++ b/arch/x86/kernel/iee/iee.c -@@ -0,0 +1,867 @@ -+// SPDX-License-Identifier: GPL-2.0 -+#include <asm/pgtable.h> -+#include <linux/stdarg.h> -+#include <asm/iee.h> -+#include <asm/page.h> -+#include <asm/pgtable_types.h> -+#include <linux/sched.h> -+#include <linux/memory.h> -+#include <linux/pgtable.h> -+#include <linux/cred.h> -+#include <linux/key.h> -+#include <asm/percpu.h> -+#include <linux/swap.h> -+#include <linux/swapops.h> -+#include <linux/mm.h> -+#include <asm/iee-si.h> -+#include <asm/desc_defs.h> -+#include <asm/pgtable_areas.h> -+#include <linux/hugetlb.h> -+#include <asm/iee-def.h> -+#ifdef CONFIG_IEE_SELINUX_P -+#include <asm/iee-selinuxp.h> -+#endif -+ -+typedef void (*iee_func)(void); -+iee_func iee_funcs[] = { -+ (iee_func)_iee_memcpy, -+ (iee_func)_iee_memset, -+ (iee_func)_iee_set_freeptr, -+ (iee_func)_iee_split_huge_pmd, -+ (iee_func)_iee_set_token_pgd, -+ (iee_func)_iee_init_token, -+ (iee_func)_iee_invalidate_token, -+ (iee_func)_iee_validate_token, -+ (iee_func)_iee_unset_token, -+ (iee_func)_iee_set_token, -+ (iee_func)_iee_test_and_clear_bit, -+ (iee_func)_iee_set_sensitive_pte, -+ (iee_func)_iee_unset_sensitive_pte, -+#ifdef CONFIG_PTP -+ (iee_func)_iee_set_pte, -+ (iee_func)_iee_set_pmd, -+ (iee_func)_iee_set_pud, -+ (iee_func)_iee_set_p4d, -+ (iee_func)_iee_set_pgd, -+#endif -+#ifdef CONFIG_IEE_SELINUX_P -+ (iee_func)_iee_set_selinux_status_pg, -+ (iee_func)_iee_set_selinux_enforcing, -+ (iee_func)_iee_mark_selinux_initialized, -+ (iee_func)_iee_set_sel_policy_cap, -+ (iee_func)_iee_sel_rcu_assign_policy, -+#endif -+#ifdef CONFIG_CREDP -+ (iee_func)_iee_copy_cred, -+ (iee_func)_iee_set_cred_uid, -+ (iee_func)_iee_set_cred_gid, -+ (iee_func)_iee_set_cred_suid, -+ (iee_func)_iee_set_cred_sgid, -+ (iee_func)_iee_set_cred_euid, -+ (iee_func)_iee_set_cred_egid, -+ (iee_func)_iee_set_cred_fsuid, -+ (iee_func)_iee_set_cred_fsgid, -+ (iee_func)_iee_set_cred_user, -+ (iee_func)_iee_set_cred_user_ns, -+ (iee_func)_iee_set_cred_group_info, -+ (iee_func)_iee_set_cred_securebits, -+ (iee_func)_iee_set_cred_cap_inheritable, -+ (iee_func)_iee_set_cred_cap_permitted, -+ (iee_func)_iee_set_cred_cap_effective, -+ (iee_func)_iee_set_cred_cap_bset, -+ (iee_func)_iee_set_cred_cap_ambient, -+ (iee_func)_iee_set_cred_jit_keyring, -+ (iee_func)_iee_set_cred_session_keyring, -+ (iee_func)_iee_set_cred_process_keyring, -+ (iee_func)_iee_set_cred_thread_keyring, -+ (iee_func)_iee_set_cred_request_key_auth, -+ (iee_func)_iee_set_cred_non_rcu, -+ (iee_func)_iee_set_cred_atomic_set_usage, -+ (iee_func)_iee_set_cred_atomic_op_usage, -+ (iee_func)_iee_set_cred_security, -+ (iee_func)_iee_set_cred_rcu, -+ (iee_func)_iee_set_cred_ucounts, -+#endif -+#ifdef CONFIG_KEYP -+ (iee_func)_iee_set_key_union, -+ (iee_func)_iee_set_key_struct, -+ (iee_func)_iee_set_key_payload, -+ (iee_func)_iee_set_key_usage, -+ (iee_func)_iee_set_key_serial, -+ (iee_func)_iee_set_key_watchers, -+ (iee_func)_iee_set_key_user, -+ (iee_func)_iee_set_key_security, -+ (iee_func)_iee_set_key_expiry, -+ (iee_func)_iee_set_key_revoked_at, -+ (iee_func)_iee_set_key_last_used_at, -+ (iee_func)_iee_set_key_uid, -+ (iee_func)_iee_set_key_gid, -+ (iee_func)_iee_set_key_perm, -+ (iee_func)_iee_set_key_quotalen, -+ (iee_func)_iee_set_key_datalen, -+ (iee_func)_iee_set_key_state, -+ (iee_func)_iee_set_key_magic, -+ (iee_func)_iee_set_key_flags, -+ (iee_func)_iee_set_key_index_key, -+ (iee_func)_iee_set_key_hash, -+ (iee_func)_iee_set_key_len_desc, -+ (iee_func)_iee_set_key_type, -+ (iee_func)_iee_set_key_domain_tag, -+ (iee_func)_iee_set_key_description, -+ (iee_func)_iee_set_key_restrict_link, -+ (iee_func)_iee_set_key_flag_bit, -+#endif -+ NULL -+}; -+ -+void __iee_code _iee_memcpy(unsigned long __unused, void *dst, void *src, size_t n) -+{ -+ char *_dst, *_src; -+ -+ _dst = (char *)(__phys_to_iee(__pa(dst))); -+ _src = (char *)src; -+ -+ while (n--) -+ *_dst++ = *_src++; -+} -+ -+void __iee_code _iee_memset(unsigned long __unused, void *ptr, int data, size_t n) -+{ -+ char *_ptr; -+ -+ _ptr = (char *)(__phys_to_iee(__pa(ptr))); -+ -+ while (n--) -+ *_ptr++ = data; -+} -+ -+void __iee_code _iee_set_freeptr(unsigned long __unused, void **pptr, void *ptr) -+{ -+ pptr = (void **)(__phys_to_iee(__pa(pptr))); -+ *pptr = ptr; -+} -+ -+void __iee_code _iee_split_huge_pmd(unsigned long __unused, pmd_t *pmdp, pte_t *pgtable) -+{ -+ int i; -+ struct page *page = pmd_page(*pmdp); -+ pte_t *ptep = (pte_t *)(__phys_to_iee(__pa(pgtable))); -+ -+ for (i = 0; i < PMD_SIZE / PAGE_SIZE; i++, ptep++) { -+ pte_t entry; -+ pgprot_t pgprot = pmd_pgprot(*pmdp); -+ -+ entry = mk_pte(page + i, pgprot); -+ WRITE_ONCE(*ptep, entry); -+ } -+} -+ -+void __iee_code _iee_set_token_pgd(unsigned long __unused, struct task_struct *tsk, pgd_t *pgd) -+{ -+ struct task_token *token; -+ -+ token = (struct task_token *)(__phys_to_iee(__pa(tsk))); -+ token->pgd = pgd; -+} -+ -+void __iee_code _iee_init_token(unsigned long __unused, struct task_struct *tsk, void *iee_stack, void *tmp_page) -+{ -+ struct task_token *token; -+ -+ token = (struct task_token *)(__phys_to_iee(__pa(tsk))); -+ token->iee_stack = iee_stack; -+ token->tmp_page = tmp_page; -+} -+ -+void __iee_code _iee_invalidate_token(unsigned long __unused, struct task_struct *tsk) -+{ -+ struct task_token *token = (struct task_token *)(__phys_to_iee(__pa(tsk))); -+ -+ token->pgd = NULL; -+ token->valid = false; -+ token->kernel_stack = NULL; -+} -+ -+void __iee_code _iee_validate_token(unsigned long __unused, struct task_struct *tsk) -+{ -+ struct task_token *token = (struct task_token *)(__phys_to_iee(__pa(tsk))); -+ -+ token->valid = true; -+} -+ -+void __iee_code _iee_unset_token(unsigned long __unused, -+ pte_t *token_ptep, pte_t *token_page_ptep, -+ void *token, void *token_page, unsigned long order) -+{ -+ token_ptep = (pte_t *)(__phys_to_iee(__pa(token_ptep))); -+ token_page_ptep = (pte_t *)(__phys_to_iee(__pa(token_page_ptep))); -+ if (order == 0) { -+ pmd_t *pmdp = (pmd_t *)token_page_ptep; -+ pmd_t pmd = READ_ONCE(*pmdp); -+ -+ pmd = __pmd(pmd_val(pmd) | ___D | __RW); -+ WRITE_ONCE(*pmdp, pmd); -+ pmdp = (pmd_t *)token_ptep; -+ pmd = READ_ONCE(*pmdp); -+ pmd = __pmd((pmd_val(pmd) & ~PTE_PFN_MASK) -+ | (__phys_to_pfn(__iee_pa(token)) << PAGE_SHIFT)); -+ WRITE_ONCE(*pmdp, pmd); -+ } else { -+ for (int i = 0; i < (0x1 << order); i++) { -+ pte_t pte = READ_ONCE(*token_ptep); -+ -+ pte = __pte((pte_val(pte) & ~PTE_PFN_MASK) -+ | (__phys_to_pfn(__iee_pa(token) + i * PAGE_SIZE) << PAGE_SHIFT)); -+ -+ WRITE_ONCE(*token_ptep, pte); -+ pte = READ_ONCE(*token_page_ptep); -+ pte = __pte(pte_val(pte) | ___D | __RW); -+ WRITE_ONCE(*token_page_ptep, pte); -+ token_ptep++; -+ token_page_ptep++; -+ } -+ } -+} -+ -+void __iee_code _iee_set_token(unsigned long __unused, -+ pte_t *token_ptep, pte_t *token_page_ptep, void *token_page, unsigned long order, int use_block_pmd) -+{ -+ token_ptep = (pte_t *)(__phys_to_iee(__pa(token_ptep))); -+ token_page_ptep = (pte_t *)(__phys_to_iee(__pa(token_page_ptep))); -+ if (use_block_pmd) { -+ pmd_t *pmdp = (pmd_t *)token_page_ptep; -+ pmd_t pmd = READ_ONCE(*pmdp); -+ -+ pmd = __pmd((pmd_val(pmd) & ~__RW) & ~___D); -+ WRITE_ONCE(*pmdp, pmd); -+ pmdp = (pmd_t *)token_ptep; -+ pmd = READ_ONCE(*pmdp); -+ pmd = __pmd(((pmd_val(pmd) & ~PTE_PFN_MASK)) -+ | (__phys_to_pfn(__pa(token_page)) << PAGE_SHIFT)); -+ WRITE_ONCE(*pmdp, pmd); -+ } else { -+ for (int i = 0; i < (0x1 << order); i++) { -+ pte_t pte = READ_ONCE(*token_ptep); -+ -+ pte = __pte(((pte_val(pte) & ~PTE_PFN_MASK)) | -+ (__phys_to_pfn(__pa(token_page) + i * PAGE_SIZE) << PAGE_SHIFT)); -+ WRITE_ONCE(*token_ptep, pte); -+ pte = READ_ONCE(*token_page_ptep); -+ pte = __pte((pte_val(pte) & ~__RW) & ~___D); -+ WRITE_ONCE(*token_page_ptep, pte); -+ token_ptep++; -+ token_page_ptep++; -+ } -+ } -+} -+ -+unsigned long __iee_code _iee_test_and_clear_bit(unsigned long __unused, long nr, volatile unsigned long *addr) -+{ -+ unsigned long *iee_addr = (unsigned long *)__phys_to_iee(__pa(addr)); -+ -+ kcsan_mb(); -+ instrument_atomic_read_write(iee_addr + BIT_WORD(nr), sizeof(long)); -+ return arch_test_and_clear_bit(nr, iee_addr); -+} -+ -+void __iee_code _iee_set_sensitive_pte(unsigned long __unused, pte_t *lm_ptep, int order, int use_block_pmd) -+{ -+ int i; -+ -+ lm_ptep = (pte_t *)(__phys_to_iee(__pa(lm_ptep))); -+ if (use_block_pmd) { -+ pmd_t pmd = __pmd(pte_val(READ_ONCE(*lm_ptep))); -+ -+ pmd = __pmd((pmd_val(pmd) & (~__RW) & (~___D))); -+ WRITE_ONCE(*lm_ptep, __pte(pmd_val(pmd))); -+ } else { -+ for (i = 0; i < (1 << order); i++) { -+ pte_t pte = READ_ONCE(*lm_ptep); -+ -+ pte = __pte((pte_val(pte) & (~__RW) & (~___D))); -+ WRITE_ONCE(*lm_ptep, pte); -+ lm_ptep++; -+ } -+ } -+} -+ -+void __iee_code _iee_unset_sensitive_pte(unsigned long __unused, pte_t *lm_ptep, int order, int use_block_pmd) -+{ -+ int i; -+ -+ lm_ptep = (pte_t *)(__phys_to_iee(__pa(lm_ptep))); -+ if (use_block_pmd) { -+ pmd_t pmd = __pmd(pte_val(READ_ONCE(*lm_ptep))); -+ -+ pmd = __pmd((pmd_val(pmd) | __RW | ___D)); -+ WRITE_ONCE(*lm_ptep, __pte(pmd_val(pmd))); -+ } else { -+ for (i = 0; i < (1 << order); i++) { -+ pte_t pte = READ_ONCE(*lm_ptep); -+ -+ pte = __pte(pte_val(pte) | __RW | ___D); -+ WRITE_ONCE(*lm_ptep, pte); -+ lm_ptep++; -+ } -+ } -+} -+ -+#ifdef CONFIG_PTP -+void __iee_code _iee_set_pte(unsigned long __unused, pte_t *ptep, pte_t pte) -+{ -+ WRITE_ONCE(*(pte_t *)(__phys_to_iee(__pa(ptep))), pte); -+} -+ -+void __iee_code _iee_set_pmd(unsigned long __unused, pmd_t *pmdp, pmd_t pmd) -+{ -+ WRITE_ONCE(*(pmd_t *)(__phys_to_iee(__pa(pmdp))), pmd); -+} -+ -+void __iee_code _iee_set_pud(unsigned long __unused, pud_t *pudp, pud_t pud) -+{ -+ WRITE_ONCE(*(pud_t *)(__phys_to_iee(__pa(pudp))), pud); -+} -+ -+void __iee_code _iee_set_p4d(unsigned long __unused, p4d_t *p4dp, p4d_t p4d) -+{ -+ WRITE_ONCE(*(p4d_t *)(__phys_to_iee(__pa(p4dp))), p4d); -+} -+ -+void __iee_code _iee_set_pgd(unsigned long __unused, pgd_t *pgdp, pgd_t pgd) -+{ -+ WRITE_ONCE(*(pgd_t *)(__phys_to_iee(__pa(pgdp))), pgd); -+} -+#endif -+ -+#ifdef CONFIG_IEE_SELINUX_P -+void __iee_code _iee_set_selinux_status_pg(unsigned long __unused, struct page *new_page) -+{ -+ struct page **iee_addr = (struct page **)__phys_to_iee(__pa_symbol(&(selinux_state.status_page))); -+ *iee_addr = new_page; -+} -+ -+void __iee_code _iee_set_selinux_enforcing(unsigned long __unused, bool value) -+{ -+ *(bool *)__phys_to_iee(__pa_symbol(&(selinux_state.enforcing))) = value; -+} -+ -+void __iee_code _iee_mark_selinux_initialized(unsigned long __unused) -+{ -+ /* synchronize selinux status*/ -+ smp_store_release(((bool *)__phys_to_iee(__pa_symbol(&(selinux_state.initialized)))), true); -+} -+ -+void __iee_code _iee_set_sel_policy_cap(unsigned long __unused, unsigned int idx, int cap) -+{ -+ *(bool *)__phys_to_iee(__pa_symbol(&(selinux_state.policycap[idx]))) = cap; -+} -+ -+/* -+ * Please make sure param iee_new_policy is from policy_jar memcache. -+ * Need to free new_policy after calling this func as it's only used to -+ * trans data from kernel. -+ */ -+void __iee_code _iee_sel_rcu_assign_policy(unsigned long __unused, struct selinux_policy *new_policy, -+ struct selinux_policy *iee_new_policy) -+{ -+ struct selinux_policy *iee_addr = (struct selinux_policy *)(__phys_to_iee(__pa(iee_new_policy))); -+ -+ memcpy(iee_addr, new_policy, sizeof(struct selinux_policy)); -+ rcu_assign_pointer(*((struct selinux_policy **)__phys_to_iee(__pa_symbol(&(selinux_state.policy)))), -+ iee_new_policy); -+} -+#endif -+ -+#ifdef CONFIG_CREDP -+static struct cred *iee_cred(unsigned long __unused, struct cred *cred) -+{ -+ if (cred == &init_cred) -+ cred = (struct cred *)__phys_to_iee(__pa_symbol(cred)); -+ else -+ cred = (struct cred *)(__phys_to_iee(__pa(cred))); -+ return cred; -+} -+ -+void __iee_code _iee_set_cred_rcu(unsigned long __unused, struct cred *cred, struct rcu_head *rcu) -+{ -+ cred = iee_cred(__unused, cred); -+ *((struct rcu_head **)(&(cred->rcu.func))) = rcu; -+} -+ -+void __iee_code _iee_set_cred_security(unsigned long __unused, struct cred *cred, void *security) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->security = security; -+} -+ -+unsigned long __iee_code _iee_set_cred_atomic_op_usage(unsigned long __unused, struct cred *cred, int flag, int nr) -+{ -+ cred = iee_cred(__unused, cred); -+ switch (flag) { -+ case AT_ADD: { -+ atomic_long_add(nr, &cred->usage); -+ return 0; -+ } -+ case AT_INC_NOT_ZERO: { -+ return atomic_long_inc_not_zero(&cred->usage); -+ } -+ case AT_SUB_AND_TEST: { -+ return atomic_long_sub_and_test(nr, &cred->usage); -+ } -+ } -+ return 0; -+} -+ -+void __iee_code _iee_set_cred_atomic_set_usage(unsigned long __unused, struct cred *cred, int i) -+{ -+ cred = iee_cred(__unused, cred); -+ atomic_long_set(&cred->usage, i); -+} -+ -+void __iee_code _iee_set_cred_non_rcu(unsigned long __unused, struct cred *cred, int non_rcu) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->non_rcu = non_rcu; -+} -+ -+void __iee_code _iee_set_cred_session_keyring(unsigned long __unused, struct cred *cred, struct key *session_keyring) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->session_keyring = session_keyring; -+} -+ -+void __iee_code _iee_set_cred_process_keyring(unsigned long __unused, struct cred *cred, struct key *process_keyring) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->process_keyring = process_keyring; -+} -+ -+void __iee_code _iee_set_cred_thread_keyring(unsigned long __unused, struct cred *cred, struct key *thread_keyring) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->thread_keyring = thread_keyring; -+} -+ -+void __iee_code _iee_set_cred_request_key_auth(unsigned long __unused, struct cred *cred, struct key *request_key_auth) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->request_key_auth = request_key_auth; -+} -+ -+void __iee_code _iee_set_cred_jit_keyring(unsigned long __unused, struct cred *cred, unsigned char jit_keyring) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->jit_keyring = jit_keyring; -+} -+ -+void __iee_code _iee_set_cred_cap_inheritable(unsigned long __unused, struct cred *cred, kernel_cap_t cap_inheritable) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->cap_inheritable = cap_inheritable; -+} -+ -+void __iee_code _iee_set_cred_cap_permitted(unsigned long __unused, struct cred *cred, kernel_cap_t cap_permitted) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->cap_permitted = cap_permitted; -+} -+ -+void __iee_code _iee_set_cred_cap_effective(unsigned long __unused, struct cred *cred, kernel_cap_t cap_effective) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->cap_effective = cap_effective; -+} -+ -+void __iee_code _iee_set_cred_cap_bset(unsigned long __unused, struct cred *cred, kernel_cap_t cap_bset) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->cap_bset = cap_bset; -+} -+ -+void __iee_code _iee_set_cred_cap_ambient(unsigned long __unused, struct cred *cred, kernel_cap_t cap_ambient) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->cap_ambient = cap_ambient; -+} -+ -+void __iee_code _iee_set_cred_securebits(unsigned long __unused, struct cred *cred, unsigned int securebits) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->securebits = securebits; -+} -+ -+void __iee_code _iee_set_cred_group_info(unsigned long __unused, struct cred *cred, struct group_info *group_info) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->group_info = group_info; -+} -+ -+void __iee_code _iee_set_cred_ucounts(unsigned long __unused, struct cred *cred, struct ucounts *ucounts) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->ucounts = ucounts; -+} -+ -+void __iee_code _iee_set_cred_user_ns(unsigned long __unused, struct cred *cred, struct user_namespace *user_ns) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->user_ns = user_ns; -+} -+ -+void __iee_code _iee_set_cred_user(unsigned long __unused, struct cred *cred, struct user_struct *user) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->user = user; -+} -+ -+void __iee_code _iee_set_cred_fsgid(unsigned long __unused, struct cred *cred, kgid_t fsgid) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->fsgid = fsgid; -+} -+ -+void __iee_code _iee_set_cred_fsuid(unsigned long __unused, struct cred *cred, kuid_t fsuid) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->fsuid = fsuid; -+} -+ -+void __iee_code _iee_set_cred_egid(unsigned long __unused, struct cred *cred, kgid_t egid) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->egid = egid; -+} -+ -+void __iee_code _iee_set_cred_euid(unsigned long __unused, struct cred *cred, kuid_t euid) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->euid = euid; -+} -+ -+void __iee_code _iee_set_cred_sgid(unsigned long __unused, struct cred *cred, kgid_t sgid) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->sgid = sgid; -+} -+ -+void __iee_code _iee_set_cred_suid(unsigned long __unused, struct cred *cred, kuid_t suid) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->suid = suid; -+} -+ -+void __iee_code _iee_copy_cred(unsigned long __unused, struct cred *old, struct cred *new) -+{ -+ if (new == &init_cred) -+ panic("copy_cred for init_cred: %lx\n", (unsigned long)new); -+ -+ struct rcu_head *rcu = (struct rcu_head *)(new->rcu.func); -+ struct cred *_new = (struct cred *)__phys_to_iee(__pa(new)); -+ -+ _iee_memcpy(__unused, new, old, sizeof(struct cred)); -+ *(struct rcu_head **)(&(_new->rcu.func)) = rcu; -+ *(struct rcu_head *)(_new->rcu.func) = *(struct rcu_head *)(old->rcu.func); -+} -+ -+void __iee_code _iee_set_cred_gid(unsigned long __unused, struct cred *cred, kgid_t gid) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->gid = gid; -+} -+ -+void __iee_code _iee_set_cred_uid(unsigned long __unused, struct cred *cred, kuid_t uid) -+{ -+ cred = iee_cred(__unused, cred); -+ cred->uid = uid; -+} -+#endif -+ -+#ifdef CONFIG_KEYP -+unsigned long __iee_code _iee_set_key_flag_bit(unsigned long __unused, struct key *key, -+ long nr, int flag) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ switch (flag) { -+ case SET_BIT_OP: { -+ set_bit(nr, &key->flags); -+ break; -+ } -+ case TEST_AND_CLEAR_BIT: { -+ return test_and_clear_bit(nr, &key->flags); -+ } -+ case TEST_AND_SET_BIT: { -+ return test_and_set_bit(nr, &key->flags); -+ } -+ } -+ return 0; -+} -+ -+void __iee_code _iee_set_key_restrict_link(unsigned long __unused, -+ struct key *key, -+ struct key_restriction *restrict_link) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->restrict_link = restrict_link; -+} -+ -+void __iee_code _iee_set_key_magic(unsigned long __unused, struct key *key, -+ unsigned int magic) -+{ -+#ifdef KEY_DEBUGGING -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->magic = magic; -+#endif -+} -+ -+void __iee_code _iee_set_key_flags(unsigned long __unused, struct key *key, -+ unsigned long flags) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->flags = flags; -+} -+ -+void __iee_code _iee_set_key_index_key(unsigned long __unused, -+ struct key *key, -+ struct keyring_index_key *index_key) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->index_key = *index_key; -+} -+ -+void __iee_code _iee_set_key_hash(unsigned long __unused, struct key *key, -+ unsigned long hash) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->hash = hash; -+} -+ -+void __iee_code _iee_set_key_len_desc(unsigned long __unused, struct key *key, -+ unsigned long len_desc) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->len_desc = len_desc; -+} -+ -+void __iee_code _iee_set_key_type(unsigned long __unused, struct key *key, -+ struct key_type *type) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->type = type; -+} -+ -+void __iee_code _iee_set_key_domain_tag(unsigned long __unused, -+ struct key *key, -+ struct key_tag *domain_tag) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->domain_tag = domain_tag; -+} -+ -+void __iee_code _iee_set_key_description(unsigned long __unused, -+ struct key *key, char *description) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->description = description; -+} -+ -+void __iee_code _iee_set_key_uid(unsigned long __unused, struct key *key, -+ kuid_t uid) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->uid = uid; -+} -+ -+void __iee_code _iee_set_key_gid(unsigned long __unused, struct key *key, -+ kgid_t gid) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->gid = gid; -+} -+ -+void __iee_code _iee_set_key_perm(unsigned long __unused, struct key *key, -+ key_perm_t perm) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->perm = perm; -+} -+ -+void __iee_code _iee_set_key_quotalen(unsigned long __unused, struct key *key, -+ unsigned short quotalen) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->quotalen = quotalen; -+} -+ -+void __iee_code _iee_set_key_datalen(unsigned long __unused, struct key *key, -+ unsigned short datalen) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->datalen = datalen; -+} -+ -+void __iee_code _iee_set_key_state(unsigned long __unused, struct key *key, -+ short state) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ WRITE_ONCE(key->state, state); -+} -+ -+void __iee_code _iee_set_key_user(unsigned long __unused, struct key *key, -+ struct key_user *user) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->user = user; -+} -+ -+void __iee_code _iee_set_key_security(unsigned long __unused, struct key *key, -+ void *security) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->security = security; -+} -+ -+void __iee_code _iee_set_key_expiry(unsigned long __unused, struct key *key, -+ time64_t expiry) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->expiry = expiry; -+} -+ -+void __iee_code _iee_set_key_revoked_at(unsigned long __unused, -+ struct key *key, time64_t revoked_at) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->revoked_at = revoked_at; -+} -+ -+void __iee_code _iee_set_key_last_used_at(unsigned long __unused, -+ struct key *key, -+ time64_t last_used_at) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->last_used_at = last_used_at; -+} -+ -+unsigned long __iee_code _iee_set_key_usage(unsigned long __unused, struct key *key, -+ int n, int flag) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ switch (flag) { -+ case REFCOUNT_INC: { -+ refcount_inc(&key->usage); -+ break; -+ } -+ case REFCOUNT_SET: { -+ refcount_set(&key->usage, n); -+ break; -+ } -+ case REFCOUNT_DEC_AND_TEST: { -+ return refcount_dec_and_test(&key->usage); -+ } -+ case REFCOUNT_INC_NOT_ZERO: { -+ return refcount_inc_not_zero(&key->usage); -+ } -+ } -+ return 0; -+} -+ -+void __iee_code _iee_set_key_serial(unsigned long __unused, struct key *key, -+ key_serial_t serial) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->serial = serial; -+} -+ -+void __iee_code _iee_set_key_watchers(unsigned long __unused, struct key *key, struct watch_list *watchers) -+{ -+#ifdef CONFIG_KEY_NOTIFICATIONS -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->watchers = watchers; -+#endif -+} -+ -+void __iee_code _iee_set_key_union(unsigned long __unused, struct key *key, -+ struct key_union *key_union) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->graveyard_link.next = (struct list_head *)key_union; -+} -+ -+void __iee_code _iee_set_key_struct(unsigned long __unused, struct key *key, -+ struct key_struct *key_struct) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->name_link.prev = (struct list_head *)key_struct; -+} -+ -+void __iee_code _iee_set_key_payload(unsigned long __unused, struct key *key, -+ union key_payload *key_payload) -+{ -+ key = (struct key *)(__phys_to_iee(__pa(key))); -+ key->name_link.next = (struct list_head *)key_payload; -+} -+#endif -+ -+/* iee si */ -+bool iee_pgt_jar_init __iee_si_data; -+bool iee_init_done __iee_si_data; -+ -+u64 __iee_si_code notrace iee_si_handler(int flag, ...) -+{ -+ va_list pArgs; -+ u64 val; -+ -+ va_start(pArgs, flag); -+ switch (flag) { -+ case IEE_SI_TEST: -+ break; -+ case IEE_WRITE_CR0: { -+ val = va_arg(pArgs, u64); -+ unsigned long bits_missing = 0; -+set_register_cr0: -+ asm volatile("mov %0,%%cr0" : "+r"(val) : : "memory"); -+ if (static_branch_likely(&cr_pinning)) { -+ if (unlikely((val & X86_CR0_WP) != X86_CR0_WP)) { -+ bits_missing = X86_CR0_WP; -+ val |= bits_missing; -+ goto set_register_cr0; -+ } -+ /* Warn after we've set the missing bits. */ -+ WARN_ONCE(bits_missing, "CR0 WP bit went missing!?\n"); -+ } -+ break; -+ } -+ case IEE_WRITE_CR3: { -+ val = va_arg(pArgs, u64); -+ asm volatile("mov %0,%%cr3" : : "r"(val) : "memory"); -+ break; -+ } -+ case IEE_WRITE_CR4: { -+ val = va_arg(pArgs, u64); -+ val &= ~(X86_CR4_SMEP); -+ unsigned long bits_changed = 0; -+set_register_cr4: -+ asm volatile("mov %0,%%cr4" : "+r" (val) : : "memory"); -+ if (static_branch_likely(&cr_pinning)) { -+ if (unlikely((val & cr4_pinned_mask) != cr4_pinned_bits)) { -+ bits_changed = (val & cr4_pinned_mask) ^ cr4_pinned_bits; -+ val = (val & ~cr4_pinned_mask) | cr4_pinned_bits; -+ goto set_register_cr4; -+ } -+ /* Warn after we've corrected the changed bits. */ -+ WARN_ONCE(bits_changed, "pinned CR4 bits changed: 0x%lx!?\n", -+ bits_changed); -+ } -+ break; -+ } -+ case IEE_LOAD_IDT: { -+ const struct desc_ptr *new_val = va_arg(pArgs, const struct desc_ptr*); -+ unsigned long new_addr = new_val->address; -+ -+ asm volatile("lidt %0"::"m" (*new_val)); -+ break; -+ } -+ } -+ va_end(pArgs); -+ return 0; -+} -diff --git a/arch/x86/kernel/iee/page-slab.c b/arch/x86/kernel/iee/page-slab.c -new file mode 100644 -index 0000000..8c1b3cc ---- /dev/null -+++ b/arch/x86/kernel/iee/page-slab.c -@@ -0,0 +1,69 @@ -+// SPDX-License-Identifier: GPL-2.0 -+#include <linux/mm.h> -+#include <linux/slab.h> -+#include <linux/iee-func.h> -+#include <asm/stack-slab.h> -+#include <linux/mm_types.h> -+#include <asm/io.h> -+#include "slab.h" -+ -+struct iee_free_slab_work { -+ struct work_struct work; -+ struct kmem_cache *s; -+ struct slab *slab; -+}; -+ -+void iee_free_task_struct_slab(struct work_struct *work) -+{ -+ struct iee_free_slab_work *iee_free_slab_work = container_of(work, struct iee_free_slab_work, work); -+ struct kmem_cache *s = iee_free_slab_work->s; -+ struct slab *slab = iee_free_slab_work->slab; -+ struct folio *folio = slab_folio(slab); -+ int order = folio_order(folio); -+ // Free stack and tmp page. -+ int i; -+ void *start = fixup_red_left(s, page_address(folio_page(folio, 0))); -+ void *obj; -+ void *iee_stack; -+ void *tmp_page; -+ void *token; -+ -+ for (i = 0; i < iee_get_oo_objects(s); i++) { -+ obj = start + s->random_seq[i]; -+ iee_stack = (void *)iee_read_token_stack((struct task_struct *)obj); -+ if (iee_stack) -+ free_iee_stack((void *)(iee_stack - PAGE_SIZE * 4)); -+ -+ tmp_page = iee_read_tmp_page((struct task_struct *)obj); -+ free_pages((unsigned long)tmp_page, 0); -+ } -+ // Free token. -+ token = (void *)__phys_to_iee(page_to_phys(folio_page(folio, 0))); -+ iee_set_token_page_invalid(token, NULL, order); -+ __free_pages(&folio->page, order); -+ kfree(iee_free_slab_work); -+} -+ -+#ifdef CONFIG_CREDP -+void iee_free_cred_slab(struct work_struct *work) -+{ -+ struct iee_free_slab_work *iee_free_slab_work = container_of(work, struct iee_free_slab_work, work); -+ struct slab *slab = iee_free_slab_work->slab; -+ struct folio *folio = slab_folio(slab); -+ int order = folio_order(folio); -+ -+ unset_iee_page((unsigned long)page_address(folio_page(slab_folio(slab), 0)), order); -+ __free_pages(&folio->page, order); -+ kfree(iee_free_slab_work); -+} -+#endif -+ -+void iee_free_slab(struct kmem_cache *s, struct slab *slab, void (*do_free_slab)(struct work_struct *work)) -+{ -+ struct iee_free_slab_work *iee_free_slab_work = kmalloc(sizeof(struct iee_free_slab_work), GFP_ATOMIC); -+ -+ iee_free_slab_work->s = s; -+ iee_free_slab_work->slab = slab; -+ INIT_WORK(&iee_free_slab_work->work, do_free_slab); -+ schedule_work(&iee_free_slab_work->work); -+} -diff --git a/arch/x86/kernel/iee/stack-slab.c b/arch/x86/kernel/iee/stack-slab.c -new file mode 100644 -index 0000000..f80a430 ---- /dev/null -+++ b/arch/x86/kernel/iee/stack-slab.c -@@ -0,0 +1,21 @@ -+// SPDX-License-Identifier: GPL-2.0 -+#include <linux/slab.h> -+#include <linux/mm.h> -+ -+struct kmem_cache *iee_stack_jar; -+ -+void __init iee_stack_init(void) -+{ -+ iee_stack_jar = kmem_cache_create("iee_stack_jar", (PAGE_SIZE << 2), -+ (PAGE_SIZE << 2), SLAB_PANIC, NULL); -+} -+ -+void *get_iee_stack(void) -+{ -+ return __phys_to_iee(__pa(kmem_cache_alloc(iee_stack_jar, GFP_KERNEL))); -+} -+ -+void free_iee_stack(void *obj) -+{ -+ kmem_cache_free(iee_stack_jar, __va(__iee_pa(obj))); -+} -diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c -index 8c8c872..3e01c4a 100644 ---- a/arch/x86/kernel/setup.c -+++ b/arch/x86/kernel/setup.c -@@ -56,6 +56,10 @@ - #include <asm/vsyscall.h> - #include <linux/vmalloc.h> - #include <asm/csv.h> -+#ifdef CONFIG_IEE -+#include <linux/iee-func.h> -+void *init_token_page_vaddr; -+#endif - - /* - * max_low_pfn_mapped: highest directly mapped pfn < 4 GB -@@ -714,6 +718,60 @@ static void __init x86_report_nx(void) - } - } - -+#ifdef CONFIG_IEE -+#include <asm/pgalloc.h> -+unsigned long IEE_OFFSET = 0x200000000000; -+EXPORT_SYMBOL(IEE_OFFSET); -+unsigned long iee_offset = 0x200000000000; -+#ifdef CONFIG_X86_5LEVEL -+void init_iee_offset(void) -+{ -+ if (pgtable_l5_enabled()) { -+ IEE_OFFSET = 0x40000000000000; -+ iee_offset = IEE_OFFSET; -+ } -+} -+#endif /* CONFIG_X86_5LEVEL */ -+ -+void __init iee_set_token_page_valid_pre_init(void *token, void *token_page) -+{ -+ pgd_t *pgdir = swapper_pg_dir; -+ pgd_t *pgdp = pgd_offset_pgd(pgdir, (unsigned long)token); -+ p4d_t *p4dp = p4d_offset(pgdp, (unsigned long)token); -+ pud_t *pudp = pud_offset(p4dp, (unsigned long)token); -+ pmd_t *pmdp = pmd_offset(pudp, (unsigned long)token); -+ -+ if (pmd_leaf(*pmdp)) { -+ pte_t *pgtable = alloc_low_pages(1); -+ struct page *page = pmd_page(*pmdp); -+ pte_t *ptep = (pte_t *)((unsigned long)pgtable); -+ -+ for (int i = 0; i < PMD_SIZE / PAGE_SIZE; i++, ptep++) { -+ pte_t entry; -+ pgprot_t pgprot = pmd_pgprot(*pmdp); -+ -+ entry = mk_pte(page + i, pgprot); -+ WRITE_ONCE(*ptep, entry); -+ } -+ #ifdef CONFIG_PTP -+ iee_pmd_populate_kernel_pre_init(&init_mm, pmdp, pgtable); -+ #else -+ pmd_populate_kernel(&init_mm, pmdp, pgtable); -+ #endif -+ } -+ pte_t *ptep = pte_offset_kernel(pmdp, (unsigned long)token); -+ pte_t pte = READ_ONCE(*ptep); -+ -+ pte = __pte(((pte_val(pte) & ~PTE_PFN_MASK) | __PP) | (__phys_to_pfn(__pa(token_page)) << PAGE_SHIFT)); -+ #ifdef CONFIG_PTP -+ iee_set_pte_pre_init(ptep, pte); -+ #else -+ set_pte(ptep, pte); -+ #endif -+ flush_tlb_kernel_range((unsigned long)token, (unsigned long)(token+PAGE_SIZE)); -+} -+#endif /* CONFIG_IEE */ -+ - /* - * Determine if we were loaded by an EFI loader. If so, then we have also been - * passed the efi memmap, systab, etc., so we should use these data structures -@@ -955,6 +1013,9 @@ void __init setup_arch(char **cmdline_p) - * Define random base addresses for memory sections after max_pfn is - * defined and before each memory section base is used. - */ -+ #if defined(CONFIG_IEE) && defined(CONFIG_X86_5LEVEL) -+ init_iee_offset(); -+ #endif - kernel_randomize_memory(); - - #ifdef CONFIG_X86_32 -@@ -1040,6 +1101,37 @@ void __init setup_arch(char **cmdline_p) - - init_mem_mapping(); - -+ #ifdef CONFIG_IEE -+ init_iee_mapping(); -+ -+ // Change init_task image va to Logival VA -+ unsigned long init_task_la = (unsigned long)__va(__pa_symbol(&init_task)); -+ -+ raw_cpu_write(pcpu_hot.current_task, (struct task_struct *)init_task_la); -+ init_task.cpus_ptr = &(((struct task_struct *)(__va(__pa_symbol(&init_task))))->cpus_mask); -+ init_task.children.prev = (__va(__pa_symbol(init_task.children.prev))); -+ init_task.children.next = (__va(__pa_symbol(init_task.children.next))); -+ -+ void *new; -+ void *init_token; -+ struct task_token *token; -+ -+ // Alloc a page for init_token. -+ new = alloc_low_pages(1); -+ init_token_page_vaddr = new; -+ init_token = (void *)__phys_to_iee(__pa_symbol(&init_task)); -+ // Use lm to write token before IEE initialized. -+ token = (struct task_token *)((unsigned long)new + (((unsigned long)&init_task) & ~PAGE_MASK)); -+ token->pgd = NULL; -+ token->iee_stack = (void *)__phys_to_iee(__pa_symbol(init_iee_stack_end)); -+ token->valid = true; -+ iee_set_token_page_valid_pre_init(init_token, new); -+ #endif /* CONFIG_IEE*/ -+ -+ #ifdef CONFIG_PTP -+ init_iee(); -+ #endif -+ - idt_setup_early_pf(); - - /* -diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S -index 8d1143a..28e74fe 100644 ---- a/arch/x86/kernel/vmlinux.lds.S -+++ b/arch/x86/kernel/vmlinux.lds.S -@@ -99,6 +99,60 @@ jiffies = jiffies_64; - - #endif - -+#ifdef CONFIG_IEE -+#define IEE_TEXT \ -+ . = ALIGN(PAGE_SIZE); \ -+ __iee_code_start = .; \ -+ *(.iee.text.header) \ -+ *(.iee.text) \ -+ . = ALIGN(PAGE_SIZE); \ -+ __iee_code_end = .; -+#else -+#define IEE_TEXT -+#endif -+#ifdef CONFIG_IEE -+#define IEE_SI_TEXT \ -+ . = ALIGN(PAGE_SIZE); \ -+ __iee_si_text_start = .; \ -+ *(.iee.si_text) \ -+ . = ALIGN(PAGE_SIZE); \ -+ __iee_trampoline_si_text_start = .; \ -+ *(.iee.trampoline.si_text) \ -+ __iee_trampoline_si_text_end = .; \ -+ . = ALIGN(PAGE_SIZE); \ -+ __iee_si_text_end = .; -+#else -+#define IEE_SI_TEXT -+#endif -+#ifdef CONFIG_IEE -+#define IEE_SI_DATA \ -+ . = ALIGN(PAGE_SIZE); \ -+ __iee_si_data_start = .; \ -+ *(.iee.si_data) \ -+ . = ALIGN(PAGE_SIZE); \ -+ __iee_si_data_end = .; -+#else -+#define IEE_SI_DATA -+#endif -+ -+#ifdef CONFIG_IEE_SELINUX_P -+ #define IEE_SELINUX_DATA \ -+ . = ALIGN(PAGE_SIZE); \ -+ *(.iee.selinux) \ -+ . = ALIGN(PAGE_SIZE); -+#else -+ #define IEE_SELINUX_DATA -+#endif -+ -+#ifdef CONFIG_CREDP -+ #define CRED_DATA \ -+ . = ALIGN(PAGE_SIZE); \ -+ *(.iee.cred) \ -+ . = ALIGN(PAGE_SIZE); -+#else -+ #define CRED_DATA -+#endif -+ - PHDRS { - text PT_LOAD FLAGS(5); /* R_E */ - data PT_LOAD FLAGS(6); /* RW_ */ -@@ -128,6 +182,8 @@ SECTIONS - /* bootstrapping code */ - HEAD_TEXT - TEXT_TEXT -+ IEE_TEXT -+ IEE_SI_TEXT - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT -@@ -181,6 +237,9 @@ SECTIONS - CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES) - - DATA_DATA -+ IEE_SI_DATA -+ IEE_SELINUX_DATA -+ CRED_DATA - CONSTRUCTORS - - /* rarely changed data like cpu maps */ -@@ -408,6 +467,13 @@ SECTIONS - __bss_stop = .; - } - -+#ifdef CONFIG_IEE -+ . = ALIGN(PAGE_SIZE*4); -+ init_iee_stack_begin = .; -+ . += PAGE_SIZE*4; -+ init_iee_stack_end = .; -+#endif -+ - /* - * The memory occupied from _text to here, __end_of_kernel_reserve, is - * automatically reserved in setup_arch(). Anything after here must be -diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c -index 3da98ab..55e8c45 100644 ---- a/arch/x86/kvm/vmx/vmx.c -+++ b/arch/x86/kvm/vmx/vmx.c -@@ -212,10 +212,11 @@ module_param(ple_window_shrink, uint, 0444); - static unsigned int ple_window_max = KVM_VMX_DEFAULT_PLE_WINDOW_MAX; - module_param(ple_window_max, uint, 0444); - --/* Default is SYSTEM mode, 1 for host-guest mode */ -+/* Default is SYSTEM mode, 1 for host-guest mode (which is BROKEN) */ - int __read_mostly pt_mode = PT_MODE_SYSTEM; -+#ifdef CONFIG_BROKEN - module_param(pt_mode, int, S_IRUGO); -- -+#endif - static u32 zx_ext_vmcs_cap; - - static DEFINE_STATIC_KEY_FALSE(vmx_l1d_should_flush); -diff --git a/arch/x86/mm/ident_map_for_iee.c b/arch/x86/mm/ident_map_for_iee.c -new file mode 100644 -index 0000000..1e722de ---- /dev/null -+++ b/arch/x86/mm/ident_map_for_iee.c -@@ -0,0 +1,197 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Helper routines for building identity mapping page tables. This is -+ * included by both the compressed kernel and the regular kernel. -+ */ -+ -+#ifdef CONFIG_PTP -+static void ident_pmd_init_for_iee(struct x86_mapping_info *info, pmd_t *pmd_page, -+ unsigned long addr, unsigned long end) -+{ -+ addr &= PMD_MASK; -+ for (; addr < end; addr += PMD_SIZE) { -+ pmd_t *pmd = pmd_page + pmd_index(addr); -+ -+ if (pmd_present(*pmd)) -+ continue; -+ -+ #ifdef CONFIG_PTP -+ iee_set_pmd_pre_init(pmd, __pmd((addr - info->offset) | info->page_flag)); -+ #else -+ set_pmd(pmd, __pmd((addr - info->offset) | info->page_flag)); -+ #endif -+ } -+} -+ -+static int ident_pud_init_for_iee(struct x86_mapping_info *info, pud_t *pud_page, -+ unsigned long addr, unsigned long end) -+{ -+ unsigned long next; -+ -+ for (; addr < end; addr = next) { -+ pud_t *pud = pud_page + pud_index(addr); -+ pmd_t *pmd; -+ -+ next = (addr & PUD_MASK) + PUD_SIZE; -+ if (next > end) -+ next = end; -+ -+ if (info->direct_gbpages) { -+ pud_t pudval; -+ -+ if (pud_present(*pud)) -+ continue; -+ -+ addr &= PUD_MASK; -+ pudval = __pud((addr - info->offset) | info->page_flag); -+ #ifdef CONFIG_PTP -+ iee_set_pud_pre_init(pud, pudval); -+ #else -+ set_pud(pud, pudval); -+ #endif -+ continue; -+ } -+ -+ if (pud_present(*pud)) { -+ pmd = pmd_offset(pud, 0); -+ #ifdef CONFIG_PTP -+ ident_pmd_init_for_iee(info, pmd, addr, next); -+ #else -+ ident_pmd_init(info, pmd, addr, next); -+ #endif -+ continue; -+ } -+ pmd = (pmd_t *)info->alloc_pgt_page(info->context); -+ if (!pmd) -+ return -ENOMEM; -+ #ifdef CONFIG_PTP -+ ident_pmd_init_for_iee(info, pmd, addr, next); -+ #else -+ ident_pmd_init(info, pmd, addr, next); -+ #endif -+ #ifdef CONFIG_PTP -+ iee_set_pud_pre_init(pud, __pud(__pa(pmd) | info->kernpg_flag)); -+ #else -+ set_pud(pud, __pud(__pa(pmd) | info->kernpg_flag)); -+ #endif -+ } -+ -+ return 0; -+} -+ -+static int ident_p4d_init_for_iee(struct x86_mapping_info *info, p4d_t *p4d_page, -+ unsigned long addr, unsigned long end) -+{ -+ unsigned long next; -+ int result; -+ -+ for (; addr < end; addr = next) { -+ p4d_t *p4d = p4d_page + p4d_index(addr); -+ pud_t *pud; -+ -+ next = (addr & P4D_MASK) + P4D_SIZE; -+ if (next > end) -+ next = end; -+ -+ if (p4d_present(*p4d)) { -+ pud = pud_offset(p4d, 0); -+ #ifdef CONFIG_PTP -+ result = ident_pud_init_for_iee(info, pud, addr, next); -+ #else -+ result = ident_pud_init(info, pud, addr, next); -+ #endif -+ if (result) -+ return result; -+ -+ continue; -+ } -+ pud = (pud_t *)info->alloc_pgt_page(info->context); -+ if (!pud) -+ return -ENOMEM; -+ -+ #ifdef CONFIG_PTP -+ result = ident_pud_init_for_iee(info, pud, addr, next); -+ #else -+ result = ident_pud_init(info, pud, addr, next); -+ #endif -+ if (result) -+ return result; -+ -+ #ifdef CONFIG_PTP -+ iee_set_p4d_pre_init(p4d, __p4d(__pa(pud) | info->kernpg_flag)); -+ #else -+ set_p4d(p4d, __p4d(__pa(pud) | info->kernpg_flag)); -+ #endif -+ } -+ -+ return 0; -+} -+ -+int kernel_ident_mapping_init_for_iee(struct x86_mapping_info *info, pgd_t *pgd_page, -+ unsigned long pstart, unsigned long pend) -+{ -+ unsigned long addr = pstart + info->offset; -+ unsigned long end = pend + info->offset; -+ unsigned long next; -+ int result; -+ -+ /* Set the default pagetable flags if not supplied */ -+ if (!info->kernpg_flag) -+ info->kernpg_flag = _KERNPG_TABLE; -+ -+ /* Filter out unsupported __PAGE_KERNEL_* bits: */ -+ info->kernpg_flag &= __default_kernel_pte_mask; -+ -+ for (; addr < end; addr = next) { -+ pgd_t *pgd = pgd_page + pgd_index(addr); -+ p4d_t *p4d; -+ -+ next = (addr & PGDIR_MASK) + PGDIR_SIZE; -+ if (next > end) -+ next = end; -+ -+ if (pgd_present(*pgd)) { -+ p4d = p4d_offset(pgd, 0); -+ #ifdef CONFIG_PTP -+ result = ident_p4d_init_for_iee(info, p4d, addr, next); -+ #else -+ result = ident_p4d_init(info, p4d, addr, next); -+ #endif -+ if (result) -+ return result; -+ continue; -+ } -+ -+ p4d = (p4d_t *)info->alloc_pgt_page(info->context); -+ if (!p4d) -+ return -ENOMEM; -+ #ifdef CONFIG_PTP -+ result = ident_p4d_init_for_iee(info, p4d, addr, next); -+ #else -+ result = ident_p4d_init(info, p4d, addr, next); -+ #endif -+ if (result) -+ return result; -+ if (pgtable_l5_enabled()) { -+ #ifdef CONFIG_PTP -+ iee_set_pgd_pre_init(pgd, __pgd(__pa(p4d) | info->kernpg_flag)); -+ #else -+ set_pgd(pgd, __pgd(__pa(p4d) | info->kernpg_flag)); -+ #endif -+ } else { -+ /* -+ * With p4d folded, pgd is equal to p4d. -+ * The pgd entry has to point to the pud page table in this case. -+ */ -+ pud_t *pud = pud_offset(p4d, 0); -+ #ifdef CONFIG_PTP -+ iee_set_pgd_pre_init(pgd, __pgd(__pa(pud) | info->kernpg_flag)); -+ #else -+ set_pgd(pgd, __pgd(__pa(pud) | info->kernpg_flag)); -+ #endif -+ } -+ } -+ -+ return 0; -+} -+#endif -diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c -index 679893e..245c2e8 100644 ---- a/arch/x86/mm/init.c -+++ b/arch/x86/mm/init.c -@@ -28,6 +28,10 @@ - #include <asm/memtype.h> - #include <asm/paravirt.h> - -+#ifdef CONFIG_PTP -+#include <asm/pgalloc.h> -+#endif -+ - /* - * We need to define the tracepoints somewhere, and tlb.c - * is only compiled when SMP=y. -@@ -252,6 +256,7 @@ static void __init probe_page_size_mask(void) - if (cpu_feature_enabled(X86_FEATURE_PTI)) - __default_kernel_pte_mask &= ~_PAGE_GLOBAL; - -+ #ifndef CONFIG_IEE - /* Enable 1 GB linear kernel mappings if available: */ - if (direct_gbpages && boot_cpu_has(X86_FEATURE_GBPAGES)) { - printk(KERN_INFO "Using GB pages for direct mapping\n"); -@@ -259,6 +264,7 @@ static void __init probe_page_size_mask(void) - } else { - direct_gbpages = 0; - } -+ #endif - } - - #define INTEL_MATCH(_model) { .vendor = X86_VENDOR_INTEL, \ -@@ -449,6 +455,7 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range, - } - - #ifdef CONFIG_X86_64 -+#ifndef CONFIG_IEE - /* big page (1G) range */ - start_pfn = round_up(pfn, PFN_DOWN(PUD_SIZE)); - end_pfn = round_down(limit_pfn, PFN_DOWN(PUD_SIZE)); -@@ -467,6 +474,7 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range, - page_size_mask & (1<<PG_LEVEL_2M)); - pfn = end_pfn; - } -+#endif - #endif - - /* tail is not big page (2M) alignment */ -@@ -808,6 +816,467 @@ void __init init_mem_mapping(void) - early_memtest(0, max_pfn_mapped << PAGE_SHIFT); - } - -+#ifdef CONFIG_IEE -+extern unsigned long IEE_OFFSET; -+static unsigned long __init init_range_memory_mapping_for_iee( -+ unsigned long r_start, -+ unsigned long r_end) -+{ -+ unsigned long start_pfn, end_pfn; -+ unsigned long mapped_ram_size = 0; -+ int i; -+ -+ for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, NULL) { -+ u64 start = clamp_val(PFN_PHYS(start_pfn), r_start, r_end); -+ u64 end = clamp_val(PFN_PHYS(end_pfn), r_start, r_end); -+ -+ if (start >= end) -+ continue; -+ /* -+ * if it is overlapping with brk pgt, we need to -+ * alloc pgt buf from memblock instead. -+ */ -+ can_use_brk_pgt = max(start, (u64)pgt_buf_end<<PAGE_SHIFT) >= -+ min(end, (u64)pgt_buf_top<<PAGE_SHIFT); -+ init_memory_mapping_for_iee(start, end, SET_RO(PAGE_KERNEL)); -+ mapped_ram_size += end - start; -+ can_use_brk_pgt = true; -+ } -+ return mapped_ram_size; -+} -+static void __init memory_map_top_down_for_iee(unsigned long map_start, -+ unsigned long map_end) -+{ -+ unsigned long real_end, last_start; -+ unsigned long step_size; -+ unsigned long addr; -+ unsigned long mapped_ram_size = 0; -+ /* -+ * Systems that have many reserved areas near top of the memory, -+ * e.g. QEMU with less than 1G RAM and EFI enabled, or Xen, will -+ * require lots of 4K mappings which may exhaust pgt_buf. -+ * Start with top-most PMD_SIZE range aligned at PMD_SIZE to ensure -+ * there is enough mapped memory that can be allocated from -+ * memblock. -+ */ -+ addr = memblock_phys_alloc_range(PMD_SIZE, PMD_SIZE, map_start, -+ map_end); -+ memblock_phys_free(addr, PMD_SIZE); -+ real_end = addr + PMD_SIZE; -+ /* step_size need to be small so pgt_buf from BRK could cover it */ -+ step_size = PMD_SIZE; -+ // max_pfn_mapped = 0; /* will get exact value next */ -+ min_pfn_mapped = real_end >> PAGE_SHIFT; -+ last_start = real_end; -+ /* -+ * We start from the top (end of memory) and go to the bottom. -+ * The memblock_find_in_range() gets us a block of RAM from the -+ * end of RAM in [min_pfn_mapped, max_pfn_mapped) used as new pages -+ * for page table. -+ */ -+ while (last_start > map_start) { -+ unsigned long start; -+ -+ if (last_start > step_size) { -+ start = round_down(last_start - 1, step_size); -+ if (start < map_start) -+ start = map_start; -+ } else -+ start = map_start; -+ mapped_ram_size += init_range_memory_mapping_for_iee(start, -+ last_start); -+ last_start = start; -+ min_pfn_mapped = last_start >> PAGE_SHIFT; -+ if (mapped_ram_size >= step_size) -+ step_size = get_new_step_size(step_size); -+ } -+ if (real_end < map_end) -+ init_range_memory_mapping_for_iee(real_end, map_end); -+} -+/** -+ * memory_map_bottom_up - Map [map_start, map_end) bottom up -+ * @map_start: start address of the target memory range -+ * @map_end: end address of the target memory range -+ * -+ * This function will setup direct mapping for memory range -+ * [map_start, map_end) in bottom-up. Since we have limited the -+ * bottom-up allocation above the kernel, the page tables will -+ * be allocated just above the kernel and we map the memory -+ * in [map_start, map_end) in bottom-up. -+ */ -+static void __init memory_map_bottom_up_for_iee(unsigned long map_start, -+ unsigned long map_end) -+{ -+ unsigned long next, start; -+ unsigned long mapped_ram_size = 0; -+ /* step_size need to be small so pgt_buf from BRK could cover it */ -+ unsigned long step_size = PMD_SIZE; -+ -+ start = map_start; -+ min_pfn_mapped = start >> PAGE_SHIFT; -+ /* -+ * We start from the bottom (@map_start) and go to the top (@map_end). -+ * The memblock_find_in_range() gets us a block of RAM from the -+ * end of RAM in [min_pfn_mapped, max_pfn_mapped) used as new pages -+ * for page table. -+ */ -+ while (start < map_end) { -+ if (step_size && map_end - start > step_size) { -+ next = round_up(start + 1, step_size); -+ if (next > map_end) -+ next = map_end; -+ } else { -+ next = map_end; -+ } -+ mapped_ram_size += init_range_memory_mapping_for_iee(start, next); -+ start = next; -+ if (mapped_ram_size >= step_size) -+ step_size = get_new_step_size(step_size); -+ } -+} -+unsigned long __ref init_memory_mapping_for_iee(unsigned long start, -+ unsigned long end, pgprot_t prot) -+{ -+ struct map_range mr[NR_RANGE_MR]; -+ unsigned long ret = 0; -+ int nr_range, i; -+ -+ memset(mr, 0, sizeof(mr)); -+ nr_range = split_mem_range(mr, 0, start, end); -+ for (i = 0; i < nr_range; i++) -+ ret = kernel_physical_mapping_init_for_iee(mr[i].start, mr[i].end, -+ mr[i].page_size_mask, -+ prot); -+ -+ add_pfn_range_mapped(start >> PAGE_SHIFT, ret >> PAGE_SHIFT); -+ return ret >> PAGE_SHIFT; -+} -+void __init init_iee_mapping(void) -+{ -+ unsigned long end; -+#ifdef CONFIG_X86_64 -+ end = max_pfn << PAGE_SHIFT; -+#else -+ end = max_low_pfn << PAGE_SHIFT; -+#endif -+ /* the ISA range is always mapped regardless of memory holes */ -+ init_memory_mapping_for_iee(0, ISA_END_ADDRESS, SET_RO(PAGE_KERNEL)); -+ if (__pa_symbol(_end) > IEE_OFFSET) -+ panic("Image on too high phys mem.\n"); -+ -+ /* -+ * If the allocation is in bottom-up direction, we setup direct mapping -+ * in bottom-up, otherwise we setup direct mapping in top-down. -+ */ -+ if (memblock_bottom_up()) { -+ unsigned long kernel_end = __pa_symbol(_end); -+ -+ /* -+ * we need two separate calls here. This is because we want to -+ * allocate page tables above the kernel. So we first map -+ * [kernel_end, end) to make memory above the kernel be mapped -+ * as soon as possible. And then use page tables allocated above -+ * the kernel to map [ISA_END_ADDRESS, kernel_end). -+ */ -+ -+ memory_map_bottom_up_for_iee(kernel_end, end); -+ memory_map_bottom_up_for_iee(ISA_END_ADDRESS, kernel_end); -+ } else { -+ memory_map_top_down_for_iee(ISA_END_ADDRESS, end); -+ } -+#ifdef CONFIG_X86_64 -+ if (max_pfn > max_low_pfn) { -+ /* can we preserve max_low_pfn ?*/ -+ max_low_pfn = max_pfn; -+ } -+#else -+ early_ioremap_page_table_range_init(); -+#endif -+ early_memtest(0, max_pfn_mapped << PAGE_SHIFT); -+} -+#endif /* CONFIG_IEE*/ -+ -+#ifdef CONFIG_PTP -+void __init set_iee_valid_pre_init(unsigned long addr) {} -+ -+static void __init move_pte_table_into_iee(pmd_t *pmdp, unsigned long addr, unsigned long end) -+{ -+ pmd_t pmd = READ_ONCE(*pmdp); -+ unsigned long iee_addr = (unsigned long)__phys_to_iee(__pmd_to_phys(pmd)); -+ -+ set_iee_valid_pre_init(iee_addr); -+} -+ -+static void __init move_pmd_table_into_iee(pud_t *pudp, unsigned long addr, unsigned long end) -+{ -+ unsigned long next; -+ pud_t pud = READ_ONCE(*pudp); -+ pmd_t *pmdp; -+ pmd_t pmd; -+ -+ unsigned long iee_addr = (unsigned long)__phys_to_iee(__pud_to_phys(pud)); -+ -+ set_iee_valid_pre_init(iee_addr); -+ pmdp = pmd_offset(pudp, addr); -+ do { -+ next = pmd_addr_end(addr, end); -+ pmd = READ_ONCE(*pmdp); -+ if (pmd_val(pmd) & _PSE) -+ continue; -+ else -+ move_pte_table_into_iee(pmdp, addr, next); -+ } while (pmdp++, addr = next, addr != end); -+} -+ -+static void __init move_pud_table_into_iee(p4d_t *p4dp, unsigned long addr, unsigned long end) -+{ -+ unsigned long next; -+ p4d_t p4d = READ_ONCE(*p4dp); -+ pud_t *pudp; -+ pud_t pud; -+ unsigned long iee_addr = (unsigned long)__phys_to_iee(__p4d_to_phys(p4d)); -+ -+ set_iee_valid_pre_init(iee_addr); -+ pudp = pud_offset(p4dp, addr); -+ do { -+ next = pud_addr_end(addr, end); -+ pud = READ_ONCE(*pudp); -+ if (pud_val(pud) & _PSE) -+ continue; -+ else -+ move_pmd_table_into_iee(pudp, addr, next); -+ } while (pudp++, addr = next, addr != end); -+} -+ -+static void __init move_p4d_table_into_iee(pgd_t *pgdp, unsigned long addr, unsigned long end) -+{ -+ unsigned long next; -+ pgd_t pgd = READ_ONCE(*pgdp); -+ p4d_t *p4dp; -+ p4d_t p4d; -+ unsigned long iee_addr = (unsigned long)__phys_to_iee(__pgd_to_phys(pgd)); -+ -+ set_iee_valid_pre_init(iee_addr); -+ p4dp = p4d_offset(pgdp, addr); -+ do { -+ next = p4d_addr_end(addr, end); -+ p4d = READ_ONCE(*p4dp); -+ /* No 512 GiB huge pages yet */ -+ move_pud_table_into_iee(p4dp, addr, next); -+ } while (p4dp++, addr = next, addr != end); -+} -+ -+static void __init init_iee_for_one_region(pgd_t *pgdir, unsigned long va_start, unsigned long va_end) -+{ -+ unsigned long addr, end, next; -+ pgd_t *pgdp = pgd_offset_pgd(pgdir, va_start); -+ -+ addr = va_start & PAGE_MASK; -+ end = PAGE_ALIGN(va_end); -+ do { -+ next = pgd_addr_end(addr, end); -+ move_p4d_table_into_iee(pgdp, addr, next); -+ } while (pgdp++, addr = next, addr != end); -+} -+ -+void __init init_iee(void) -+{ -+ unsigned long iee_addr; -+ pgd_t *pgdp; -+ phys_addr_t start, end; -+ u64 i; -+ -+ // handling 1-level page table swapper_pg_dir -+ pgdp = swapper_pg_dir; -+ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(swapper_pg_dir)); -+ set_iee_valid_pre_init(iee_addr); -+ #if PGD_ALLOCATION_ORDER == 1 -+ set_iee_valid_pre_init(iee_addr + PAGE_SIZE); -+ #endif -+ -+ #ifdef CONFIG_X86_5LEVEL -+ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(level4_kernel_pgt)); -+ set_iee_valid_pre_init(iee_addr); -+ #endif -+ -+ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(level3_kernel_pgt)); -+ set_iee_valid_pre_init(iee_addr); -+ -+ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(level2_kernel_pgt)); -+ set_iee_valid_pre_init(iee_addr); -+ -+ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(level2_fixmap_pgt)); -+ set_iee_valid_pre_init(iee_addr); -+ -+ iee_addr = (unsigned long)__phys_to_iee(__pa_symbol(level1_fixmap_pgt)); -+ for (i = 0; i < FIXMAP_PMD_NUM; i++) -+ set_iee_valid_pre_init(iee_addr + PAGE_SIZE * i); -+ -+ // handling 2/3/4-level page table for kernel -+ init_iee_for_one_region(pgdp, (unsigned long)_text, (unsigned long)_etext); -+ init_iee_for_one_region(pgdp, (unsigned long)__start_rodata, (unsigned long)__end_rodata); -+ init_iee_for_one_region(pgdp, (unsigned long)_sdata, (unsigned long)_edata); -+ init_iee_for_one_region(pgdp, (unsigned long)__bss_start, (unsigned long)__bss_stop); -+ -+ // handling page table for fixmap i.e. FIXADDR_START ~ FIXADDR_TOP -+ // printk("fixmap into iee:\n"); -+ init_iee_for_one_region(pgdp, FIXADDR_START, FIXADDR_TOP); -+ -+ // handling page table for %esp fixup stacks -+ // espfix_pud_page in espfix_64.c -+ -+ // handling 2/3/4-level page table for logical mem and iee -+ for_each_mem_range(i, &start, &end) { -+ if (start >= end) -+ break; -+ init_iee_for_one_region(pgdp, -+ (unsigned long)__va(start), (unsigned long)__va(end)); -+ init_iee_for_one_region(pgdp, -+ (unsigned long)__phys_to_iee(start), (unsigned long)__phys_to_iee(end)); -+ } -+} -+ -+static void __init iee_set_pte_table_ro(pmd_t *pmdp, unsigned long addr, unsigned long end) -+{ -+ pmd_t pmd = READ_ONCE(*pmdp); -+ unsigned long logical_addr = (unsigned long)__va(__pmd_to_phys(pmd)); -+ -+ iee_set_logical_mem_ro(logical_addr); -+} -+ -+static void __init iee_set_pmd_table_ro(pud_t *pudp, unsigned long addr, unsigned long end) -+{ -+ unsigned long next; -+ pud_t pud = READ_ONCE(*pudp); -+ pmd_t *pmdp; -+ pmd_t pmd; -+ unsigned long logical_addr = (unsigned long)__va(__pud_to_phys(pud)); -+ -+ iee_set_logical_mem_ro(logical_addr); -+ pmdp = pmd_offset(pudp, addr); -+ do { -+ next = pmd_addr_end(addr, end); -+ pmd = READ_ONCE(*pmdp); -+ if (pmd_val(pmd) & _PSE) -+ continue; -+ else -+ iee_set_pte_table_ro(pmdp, addr, next); -+ } while (pmdp++, addr = next, addr != end); -+} -+ -+static void __init iee_set_pud_table_ro(p4d_t *p4dp, unsigned long addr, unsigned long end) -+{ -+ unsigned long next; -+ p4d_t p4d = READ_ONCE(*p4dp); -+ pud_t *pudp; -+ pud_t pud; -+ unsigned long logical_addr = (unsigned long)__va(__p4d_to_phys(p4d)); -+ -+ iee_set_logical_mem_ro(logical_addr); -+ pudp = pud_offset(p4dp, addr); -+ do { -+ next = pud_addr_end(addr, end); -+ pud = READ_ONCE(*pudp); -+ if (pud_val(pud) & _PSE) -+ continue; -+ else -+ iee_set_pmd_table_ro(pudp, addr, next); -+ } while (pudp++, addr = next, addr != end); -+} -+ -+static void __init iee_set_p4d_table_ro(pgd_t *pgdp, unsigned long addr, unsigned long end) -+{ -+ unsigned long next; -+ pgd_t pgd = READ_ONCE(*pgdp); -+ p4d_t *p4dp; -+ p4d_t p4d; -+ unsigned long logical_addr = (unsigned long)__va(__pgd_to_phys(pgd)); -+ -+ iee_set_logical_mem_ro(logical_addr); -+ p4dp = p4d_offset(pgdp, addr); -+ do { -+ next = p4d_addr_end(addr, end); -+ p4d = READ_ONCE(*p4dp); -+ /* No 512 GiB huge pages yet */ -+ iee_set_pud_table_ro(p4dp, addr, next); -+ } while (p4dp++, addr = next, addr != end); -+} -+ -+static void __init iee_mark_pgtable_for_one_region_ro(pgd_t *pgdir, unsigned long va_start, unsigned long va_end) -+{ -+ unsigned long addr, end, next; -+ pgd_t *pgdp = pgd_offset_pgd(pgdir, va_start); -+ -+ addr = va_start & PAGE_MASK; -+ end = PAGE_ALIGN(va_end); -+ -+ do { -+ next = pgd_addr_end(addr, end); -+ iee_set_p4d_table_ro(pgdp, addr, next); -+ } while (pgdp++, addr = next, addr != end); -+} -+ -+// Mark pgtable outside as RO. -+void __init iee_mark_all_lm_pgtable_ro(void) -+{ -+ unsigned long logical_addr; -+ phys_addr_t start, end; -+ u64 i; -+ pgd_t *pgdp; -+ -+ // handling 1-level page table swapper_pg_dir -+ pgdp = swapper_pg_dir; -+ iee_set_logical_mem_ro((unsigned long)swapper_pg_dir); -+ logical_addr = (unsigned long)__va(__pa_symbol(swapper_pg_dir)); -+ iee_set_logical_mem_ro(logical_addr); -+ -+ // handling 2/3/4/5-level page table for kernel -+ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)_text, (unsigned long)_etext); -+ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__start_rodata, (unsigned long)__end_rodata); -+ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)_sdata, (unsigned long)_edata); -+ iee_mark_pgtable_for_one_region_ro(pgdp, (unsigned long)__bss_start, (unsigned long)__bss_stop); -+ -+ // handling 2/3/4/5-level statically allocated page table -+ #ifdef CONFIG_X86_5LEVEL -+ iee_set_logical_mem_ro((unsigned long)level4_kernel_pgt); -+ logical_addr = (unsigned long)__va(__pa_symbol(level4_kernel_pgt)); -+ iee_set_logical_mem_ro(logical_addr); -+ #endif -+ -+ iee_set_logical_mem_ro((unsigned long)level3_kernel_pgt); -+ logical_addr = (unsigned long)__va(__pa_symbol(level3_kernel_pgt)); -+ iee_set_logical_mem_ro(logical_addr); -+ -+ iee_set_logical_mem_ro((unsigned long)level2_kernel_pgt); -+ logical_addr = (unsigned long)__va(__pa_symbol(level2_kernel_pgt)); -+ iee_set_logical_mem_ro(logical_addr); -+ -+ iee_set_logical_mem_ro((unsigned long)level2_fixmap_pgt); -+ logical_addr = (unsigned long)__va(__pa_symbol(level2_fixmap_pgt)); -+ iee_set_logical_mem_ro(logical_addr); -+ -+ iee_set_logical_mem_ro((unsigned long)level1_fixmap_pgt); -+ logical_addr = (unsigned long)__va(__pa_symbol(level1_fixmap_pgt)); -+ for (i = 0; i < FIXMAP_PMD_NUM; i++) -+ iee_set_logical_mem_ro(logical_addr + PAGE_SIZE * i); -+ -+ // handling 2/3/4-level page table for logical mem and iee -+ for_each_mem_range(i, &start, &end) { -+ if (start >= end) -+ break; -+ /* -+ * The linear map must allow allocation tags reading/writing -+ * if MTE is present. Otherwise, it has the same attributes as -+ * PAGE_KERNEL. -+ */ -+ iee_mark_pgtable_for_one_region_ro(pgdp, -+ (unsigned long)__va(start), (unsigned long)__va(end)); -+ iee_mark_pgtable_for_one_region_ro(pgdp, -+ (unsigned long)__phys_to_iee(start), (unsigned long)__phys_to_iee(end)); -+ } -+} -+#endif /* CONFIG_PTP */ -+ - /* - * Initialize an mm_struct to be used during poking and a pointer to be used - * during patching. -diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c -index 5386b2f..b2fc470 100644 ---- a/arch/x86/mm/init_64.c -+++ b/arch/x86/mm/init_64.c -@@ -60,6 +60,10 @@ - - #include "ident_map.c" - -+#ifdef CONFIG_PTP -+#include <linux/iee-func.h> -+#endif -+ - #define DEFINE_POPULATE(fname, type1, type2, init) \ - static inline void fname##_init(struct mm_struct *mm, \ - type1##_t *arg1, type2##_t *arg2, bool init) \ -@@ -90,6 +94,38 @@ DEFINE_ENTRY(pud, pud, init) - DEFINE_ENTRY(pmd, pmd, init) - DEFINE_ENTRY(pte, pte, init) - -+#ifdef CONFIG_PTP -+#define DEFINE_IEE_POPULATE(fname, type1, type2, init) \ -+static inline void iee_##fname##_init(struct mm_struct *mm, \ -+ type1##_t * arg1, type2##_t * arg2, bool init) \ -+{ \ -+ if (init) \ -+ iee_##fname##_safe_pre_init(mm, arg1, arg2); \ -+ else \ -+ iee_##fname##_pre_init(mm, arg1, arg2); \ -+} -+ -+DEFINE_IEE_POPULATE(p4d_populate, p4d, pud, init) -+DEFINE_IEE_POPULATE(pgd_populate, pgd, p4d, init) -+DEFINE_IEE_POPULATE(pud_populate, pud, pmd, init) -+DEFINE_IEE_POPULATE(pmd_populate_kernel, pmd, pte, init) -+ -+#define DEFINE_IEE_ENTRY(type1, type2, init) \ -+static inline void iee_set_##type1##_init(type1##_t * arg1, \ -+ type2##_t arg2, bool init) \ -+{ \ -+ if (init) \ -+ iee_set_##type1##_safe_pre_init(arg1, arg2); \ -+ else \ -+ iee_set_##type1##_pre_init(arg1, arg2); \ -+} -+ -+DEFINE_IEE_ENTRY(p4d, p4d, init) -+DEFINE_IEE_ENTRY(pud, pud, init) -+DEFINE_IEE_ENTRY(pmd, pmd, init) -+DEFINE_IEE_ENTRY(pte, pte, init) -+#endif -+ - static inline pgprot_t prot_sethuge(pgprot_t prot) - { - WARN_ON_ONCE(pgprot_val(prot) & _PAGE_PAT); -@@ -442,7 +478,11 @@ void __init cleanup_highmap(void) - if (pmd_none(*pmd)) - continue; - if (vaddr < (unsigned long) _text || vaddr > end) -+ #ifdef CONFIG_PTP -+ iee_set_pmd_pre_init(pmd, __pmd(0)); -+ #else - set_pmd(pmd, __pmd(0)); -+ #endif - } - } - -@@ -470,7 +510,11 @@ phys_pte_init(pte_t *pte_page, unsigned long paddr, unsigned long paddr_end, - E820_TYPE_RAM) && - !e820__mapped_any(paddr & PAGE_MASK, paddr_next, - E820_TYPE_RESERVED_KERN)) -+ #ifdef CONFIG_PTP -+ iee_set_pte_init(pte, __pte(0), init); -+ #else - set_pte_init(pte, __pte(0), init); -+ #endif - continue; - } - -@@ -490,7 +534,11 @@ phys_pte_init(pte_t *pte_page, unsigned long paddr, unsigned long paddr_end, - pr_info(" pte=%p addr=%lx pte=%016lx\n", pte, paddr, - pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL).pte); - pages++; -+ #ifdef CONFIG_PTP -+ iee_set_pte_init(pte, pfn_pte(paddr >> PAGE_SHIFT, prot), init); -+ #else - set_pte_init(pte, pfn_pte(paddr >> PAGE_SHIFT, prot), init); -+ #endif - paddr_last = (paddr & PAGE_MASK) + PAGE_SIZE; - } - -@@ -525,7 +573,11 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end, - E820_TYPE_RAM) && - !e820__mapped_any(paddr & PMD_MASK, paddr_next, - E820_TYPE_RESERVED_KERN)) -+ #ifdef CONFIG_PTP -+ iee_set_pmd_init(pmd, __pmd(0), init); -+ #else - set_pmd_init(pmd, __pmd(0), init); -+ #endif - continue; - } - -@@ -563,9 +615,15 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end, - if (page_size_mask & (1<<PG_LEVEL_2M)) { - pages++; - spin_lock(&init_mm.page_table_lock); -+ #ifdef CONFIG_PTP -+ iee_set_pmd_init(pmd, -+ pfn_pmd(paddr >> PAGE_SHIFT, prot_sethuge(prot)), -+ init); -+ #else - set_pmd_init(pmd, - pfn_pmd(paddr >> PAGE_SHIFT, prot_sethuge(prot)), - init); -+ #endif - spin_unlock(&init_mm.page_table_lock); - paddr_last = paddr_next; - continue; -@@ -575,7 +633,11 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long paddr, unsigned long paddr_end, - paddr_last = phys_pte_init(pte, paddr, paddr_end, new_prot, init); - - spin_lock(&init_mm.page_table_lock); -+ #ifdef CONFIG_PTP -+ iee_pmd_populate_kernel_init(&init_mm, pmd, pte, init); -+ #else - pmd_populate_kernel_init(&init_mm, pmd, pte, init); -+ #endif - spin_unlock(&init_mm.page_table_lock); - } - update_page_count(PG_LEVEL_2M, pages); -@@ -612,7 +674,11 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end, - E820_TYPE_RAM) && - !e820__mapped_any(paddr & PUD_MASK, paddr_next, - E820_TYPE_RESERVED_KERN)) -+ #ifdef CONFIG_PTP -+ iee_set_pud_init(pud, __pud(0), init); -+ #else - set_pud_init(pud, __pud(0), init); -+ #endif - continue; - } - -@@ -649,9 +715,15 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end, - if (page_size_mask & (1<<PG_LEVEL_1G)) { - pages++; - spin_lock(&init_mm.page_table_lock); -+ #ifdef CONFIG_PTP -+ iee_set_pud_init(pud, -+ pfn_pud(paddr >> PAGE_SHIFT, prot_sethuge(prot)), -+ init); -+ #else - set_pud_init(pud, - pfn_pud(paddr >> PAGE_SHIFT, prot_sethuge(prot)), - init); -+ #endif - spin_unlock(&init_mm.page_table_lock); - paddr_last = paddr_next; - continue; -@@ -662,7 +734,11 @@ phys_pud_init(pud_t *pud_page, unsigned long paddr, unsigned long paddr_end, - page_size_mask, prot, init); - - spin_lock(&init_mm.page_table_lock); -+ #ifdef CONFIG_PTP -+ iee_pud_populate_init(&init_mm, pud, pmd, init); -+ #else - pud_populate_init(&init_mm, pud, pmd, init); -+ #endif - spin_unlock(&init_mm.page_table_lock); - } - -@@ -715,7 +791,11 @@ phys_p4d_init(p4d_t *p4d_page, unsigned long paddr, unsigned long paddr_end, - page_size_mask, prot, init); - - spin_lock(&init_mm.page_table_lock); -+ #ifdef CONFIG_PTP -+ iee_p4d_populate_init(&init_mm, p4d, pud, init); -+ #else - p4d_populate_init(&init_mm, p4d, pud, init); -+ #endif - spin_unlock(&init_mm.page_table_lock); - } - -@@ -757,10 +837,19 @@ __kernel_physical_mapping_init(unsigned long paddr_start, - - spin_lock(&init_mm.page_table_lock); - if (pgtable_l5_enabled()) -+ #ifdef CONFIG_PTP -+ iee_pgd_populate_init(&init_mm, pgd, p4d, init); -+ #else - pgd_populate_init(&init_mm, pgd, p4d, init); -+ #endif - else -+ #ifdef CONFIG_PTP -+ iee_p4d_populate_init(&init_mm, p4d_offset(pgd, vaddr), -+ (pud_t *) p4d, init); -+ #else - p4d_populate_init(&init_mm, p4d_offset(pgd, vaddr), - (pud_t *) p4d, init); -+ #endif - - spin_unlock(&init_mm.page_table_lock); - pgd_changed = true; -@@ -788,6 +877,68 @@ kernel_physical_mapping_init(unsigned long paddr_start, - page_size_mask, prot, true); - } - -+#ifdef CONFIG_IEE -+static unsigned long __meminit -+__kernel_physical_mapping_init_for_iee(unsigned long paddr_start, -+ unsigned long paddr_end, -+ unsigned long page_size_mask, -+ pgprot_t prot, bool init) -+{ -+ bool pgd_changed = false; -+ unsigned long vaddr, vaddr_start, vaddr_end, vaddr_next, paddr_last; -+ -+ paddr_last = paddr_end; -+ vaddr = (unsigned long)__phys_to_iee(paddr_start); -+ vaddr_end = (unsigned long)__phys_to_iee(paddr_end); -+ vaddr_start = vaddr; -+ for (; vaddr < vaddr_end; vaddr = vaddr_next) { -+ pgd_t *pgd = pgd_offset_k(vaddr); -+ p4d_t *p4d; -+ -+ vaddr_next = (vaddr & PGDIR_MASK) + PGDIR_SIZE; -+ if (pgd_val(*pgd)) { -+ p4d = (p4d_t *)pgd_page_vaddr(*pgd); -+ paddr_last = phys_p4d_init(p4d, __iee_pa(vaddr), -+ __iee_pa(vaddr_end), -+ page_size_mask, prot, init); -+ continue; -+ } -+ p4d = alloc_low_page(); -+ paddr_last = phys_p4d_init(p4d, __iee_pa(vaddr), -+ __iee_pa(vaddr_end), -+ page_size_mask, prot, init); -+ spin_lock(&init_mm.page_table_lock); -+ if (pgtable_l5_enabled()) -+ #ifdef CONFIG_PTP -+ iee_pgd_populate_init(&init_mm, pgd, p4d, init); -+ #else -+ pgd_populate_init(&init_mm, pgd, p4d, init); -+ #endif -+ else -+ #ifdef CONFIG_PTP -+ iee_p4d_populate_init(&init_mm, p4d_offset(pgd, vaddr), -+ (pud_t *) p4d, init); -+ #else -+ p4d_populate_init(&init_mm, p4d_offset(pgd, vaddr), -+ (pud_t *) p4d, init); -+ #endif -+ spin_unlock(&init_mm.page_table_lock); -+ pgd_changed = true; -+ } -+ if (pgd_changed) -+ sync_global_pgds(vaddr_start, vaddr_end - 1); -+ return paddr_last; -+} -+unsigned long __meminit -+kernel_physical_mapping_init_for_iee(unsigned long paddr_start, -+ unsigned long paddr_end, -+ unsigned long page_size_mask, pgprot_t prot) -+{ -+ return __kernel_physical_mapping_init_for_iee(paddr_start, paddr_end, -+ page_size_mask, prot, true); -+} -+#endif /* CONFIG_IEE*/ -+ - /* - * This function is similar to kernel_physical_mapping_init() above with the - * exception that it uses set_{pud,pmd}() instead of the set_{pud,pte}_safe() -diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c -index aa7d279..fc40592 100644 ---- a/arch/x86/mm/ioremap.c -+++ b/arch/x86/mm/ioremap.c -@@ -888,7 +888,11 @@ void __init early_ioremap_init(void) - - pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)); - memset(bm_pte, 0, sizeof(bm_pte)); -+ #ifdef CONFIG_PTP -+ iee_pmd_populate_kernel_pre_init(&init_mm, pmd, bm_pte); -+ #else - pmd_populate_kernel(&init_mm, pmd, bm_pte); -+ #endif - - /* - * The boot-ioremap range spans multiple pmds, for which -@@ -929,8 +933,39 @@ void __init __early_set_fixmap(enum fixed_addresses idx, - pgprot_val(flags) &= __supported_pte_mask; - - if (pgprot_val(flags)) -+ #ifdef CONFIG_PTP -+ iee_set_pte_pre_init(pte, pfn_pte(phys >> PAGE_SHIFT, flags)); -+ #else - set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags)); -+ #endif - else -+ #ifdef CONFIG_PTP -+ iee_set_pte_pre_init(pte, __pte(0)); -+ #else - pte_clear(&init_mm, addr, pte); -+ #endif - flush_tlb_one_kernel(addr); - } -+ -+#ifdef CONFIG_PTP -+void __init __iee_set_fixmap_pre_init(enum fixed_addresses idx, -+ phys_addr_t phys, pgprot_t flags) -+{ -+ unsigned long addr = __fix_to_virt(idx); -+ pte_t *pte; -+ -+ if (idx >= __end_of_fixed_addresses) -+ return; -+ -+ pte = early_ioremap_pte(addr); -+ -+ /* Sanitize 'prot' against any unsupported bits: */ -+ pgprot_val(flags) &= __supported_pte_mask; -+ -+ if (pgprot_val(flags)) -+ iee_set_pte_pre_init(pte, pfn_pte(phys >> PAGE_SHIFT, flags)); -+ else -+ iee_set_pte_pre_init(pte, __pte(0)); -+ flush_tlb_one_kernel(addr); -+} -+#endif -diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c -index 37db264..f89317a 100644 ---- a/arch/x86/mm/kaslr.c -+++ b/arch/x86/mm/kaslr.c -@@ -30,7 +30,9 @@ - #include <asm/kaslr.h> - - #include "mm_internal.h" -- -+#ifdef CONFIG_IEE -+#include <asm/iee.h> -+#endif - #define TB_SHIFT 40 - - /* -@@ -136,6 +138,9 @@ void __init kernel_randomize_memory(void) - vaddr = round_up(vaddr + 1, PUD_SIZE); - remain_entropy -= entropy; - } -+ #ifdef CONFIG_IEE -+ iee_offset = *kaslr_regions[0].base - vaddr_start + IEE_OFFSET; -+ #endif /* CONFIG_IEE*/ - } - - void __meminit init_trampoline_kaslr(void) -diff --git a/arch/x86/mm/mm_internal.h b/arch/x86/mm/mm_internal.h -index 3f37b5c..a371bd6 100644 ---- a/arch/x86/mm/mm_internal.h -+++ b/arch/x86/mm/mm_internal.h -@@ -14,6 +14,11 @@ unsigned long kernel_physical_mapping_init(unsigned long start, - unsigned long end, - unsigned long page_size_mask, - pgprot_t prot); -+#ifdef CONFIG_IEE -+unsigned long kernel_physical_mapping_init_for_iee(unsigned long paddr_start, -+ unsigned long paddr_end, -+ unsigned long page_size_mask, pgprot_t prot); -+#endif /* CONFIG_IEE*/ - unsigned long kernel_physical_mapping_change(unsigned long start, - unsigned long end, - unsigned long page_size_mask); -diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c -index 438b2ec..5bbff04 100644 ---- a/arch/x86/mm/pgtable.c -+++ b/arch/x86/mm/pgtable.c -@@ -6,6 +6,10 @@ - #include <asm/tlb.h> - #include <asm/fixmap.h> - #include <asm/mtrr.h> -+#ifdef CONFIG_PTP -+#include <linux/iee-func.h> -+#include <asm/iee-access.h> -+#endif - - #ifdef CONFIG_DYNAMIC_PHYSICAL_MASK - phys_addr_t physical_mask __ro_after_init = (1ULL << __PHYSICAL_MASK_SHIFT) - 1; -@@ -557,8 +561,13 @@ int ptep_test_and_clear_young(struct vm_area_struct *vma, - int ret = 0; - - if (pte_young(*ptep)) -+ #ifdef CONFIG_PTP -+ ret = iee_test_and_clear_bit(_PAGE_BIT_ACCESSED, -+ (unsigned long *) &ptep->pte); -+ #else - ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, - (unsigned long *) &ptep->pte); -+ #endif - - return ret; - } -@@ -570,8 +579,13 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma, - int ret = 0; - - if (pmd_young(*pmdp)) -+ #ifdef CONFIG_PTP -+ ret = iee_test_and_clear_bit(_PAGE_BIT_ACCESSED, -+ (unsigned long *)pmdp); -+ #else - ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, - (unsigned long *)pmdp); -+ #endif - - return ret; - } -@@ -584,8 +598,13 @@ int pudp_test_and_clear_young(struct vm_area_struct *vma, - int ret = 0; - - if (pud_young(*pudp)) -+ #ifdef CONFIG_PTP -+ ret = iee_test_and_clear_bit(_PAGE_BIT_ACCESSED, -+ (unsigned long *)pudp); -+ #else - ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, - (unsigned long *)pudp); -+ #endif - - return ret; - } -diff --git a/arch/x86/mm/pti.c b/arch/x86/mm/pti.c -index 43ab55b..970c61a 100644 ---- a/arch/x86/mm/pti.c -+++ b/arch/x86/mm/pti.c -@@ -38,6 +38,9 @@ - #include <asm/desc.h> - #include <asm/sections.h> - #include <asm/set_memory.h> -+#ifdef CONFIG_PTP -+#include <linux/iee-func.h> -+#endif - - #undef pr_fmt - #define pr_fmt(fmt) "Kernel/User page tables isolation: " fmt -@@ -139,7 +142,11 @@ pgd_t __pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd) - * The user page tables get the full PGD, accessible from - * userspace: - */ -+ #ifdef CONFIG_PTP -+ iee_set_pgd(IEE_OP_SET_PGD, kernel_to_user_pgdp(pgdp), pgd); -+ #else - kernel_to_user_pgdp(pgdp)->pgd = pgd.pgd; -+ #endif - - /* - * If this is normal user memory, make it NX in the kernel -@@ -287,7 +294,12 @@ static void __init pti_setup_vsyscall(void) - if (WARN_ON(!target_pte)) - return; - -+ #ifdef CONFIG_PTP -+ set_pte(target_pte, *pte); -+ #else - *target_pte = *pte; -+ #endif -+ - set_vsyscall_pgtable_user_bits(kernel_to_user_pgdp(swapper_pg_dir)); - } - #else -@@ -365,14 +377,22 @@ pti_clone_pgtable(unsigned long start, unsigned long end, - * code that only set this bit when supported. - */ - if (boot_cpu_has(X86_FEATURE_PGE)) -+ #ifdef CONFIG_PTP -+ set_pmd(pmd, pmd_set_flags(*pmd, _PAGE_GLOBAL)); -+ #else - *pmd = pmd_set_flags(*pmd, _PAGE_GLOBAL); -+ #endif - - /* - * Copy the PMD. That is, the kernelmode and usermode - * tables will share the last-level page tables of this - * address range - */ -+ #ifdef CONFIG_PTP -+ set_pmd(target_pmd, *pmd); -+ #else - *target_pmd = *pmd; -+ #endif - - addr = round_up(addr + 1, PMD_SIZE); - -@@ -396,10 +416,18 @@ pti_clone_pgtable(unsigned long start, unsigned long end, - - /* Set GLOBAL bit in both PTEs */ - if (boot_cpu_has(X86_FEATURE_PGE)) -+ #ifdef CONFIG_PTP -+ set_pte(pte, pte_set_flags(*pte, _PAGE_GLOBAL)); -+ #else - *pte = pte_set_flags(*pte, _PAGE_GLOBAL); -+ #endif - - /* Clone the PTE */ -+ #ifdef CONFIG_PTP -+ set_pte(target_pte, *pte); -+ #else - *target_pte = *pte; -+ #endif - - addr = round_up(addr + 1, PAGE_SIZE); - -@@ -425,7 +453,11 @@ static void __init pti_clone_p4d(unsigned long addr) - - kernel_pgd = pgd_offset_k(addr); - kernel_p4d = p4d_offset(kernel_pgd, addr); -+ #ifdef CONFIG_PTP -+ set_p4d(user_p4d, *kernel_p4d); -+ #else - *user_p4d = *kernel_p4d; -+ #endif - } - - /* -@@ -456,7 +488,11 @@ static void __init pti_clone_user_shared(void) - if (WARN_ON(!target_pte)) - return; - -+ #ifdef CONFIG_PTP -+ set_pte(target_pte, pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL)); -+ #else - *target_pte = pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL); -+ #endif - } - } - -diff --git a/block/sed-opal.c b/block/sed-opal.c -index 1a1cb35..7149485 100644 ---- a/block/sed-opal.c -+++ b/block/sed-opal.c -@@ -316,7 +316,11 @@ static int read_sed_opal_key(const char *key_name, u_char *buffer, int buflen) - return PTR_ERR(kref); - - key = key_ref_to_ptr(kref); -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(key)); -+ #else - down_read(&key->sem); -+ #endif - ret = key_validate(key); - if (ret == 0) { - if (buflen > key->datalen) -@@ -324,7 +328,11 @@ static int read_sed_opal_key(const char *key_name, u_char *buffer, int buflen) - - ret = key->type->read(key, (char *)buffer, buflen); - } -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - - key_ref_put(kref); - -diff --git a/certs/blacklist.c b/certs/blacklist.c -index 675dd7a..4e63758 100644 ---- a/certs/blacklist.c -+++ b/certs/blacklist.c -@@ -17,6 +17,9 @@ - #include <linux/uidgid.h> - #include <keys/asymmetric-type.h> - #include <keys/system_keyring.h> -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif - #include "blacklist.h" - - /* -@@ -91,7 +94,11 @@ static int blacklist_key_instantiate(struct key *key, - #endif - - /* Sets safe default permissions for keys loaded by user space. */ -+ #ifdef CONFIG_KEYP -+ iee_set_key_perm(key, BLACKLIST_KEY_PERM); -+ #else - key->perm = BLACKLIST_KEY_PERM; -+ #endif - - /* - * Skips the authentication step for builtin hashes, they are not -diff --git a/certs/system_keyring.c b/certs/system_keyring.c -index 9de610b..f9245f8 100644 ---- a/certs/system_keyring.c -+++ b/certs/system_keyring.c -@@ -93,9 +93,15 @@ int restrict_link_by_builtin_and_secondary_trusted( - /* If we have a secondary trusted keyring, then that contains a link - * through to the builtin keyring and the search will follow that link. - */ -+ #ifdef CONFIG_KEYP -+ if (type == &key_type_keyring && -+ dest_keyring == secondary_trusted_keys && -+ payload == (union key_payload *)(builtin_trusted_keys->name_link.next)) -+ #else - if (type == &key_type_keyring && - dest_keyring == secondary_trusted_keys && - payload == &builtin_trusted_keys->payload) -+ #endif - /* Allow the builtin keyring to be added to the secondary */ - return 0; - -@@ -122,9 +128,15 @@ int restrict_link_by_digsig_builtin_and_secondary(struct key *dest_keyring, - /* If we have a secondary trusted keyring, then that contains a link - * through to the builtin keyring and the search will follow that link. - */ -+ #ifdef CONFIG_KEYP -+ if (type == &key_type_keyring && -+ dest_keyring == secondary_trusted_keys && -+ payload == (union key_payload *)(builtin_trusted_keys->name_link.next)) -+ #else - if (type == &key_type_keyring && - dest_keyring == secondary_trusted_keys && - payload == &builtin_trusted_keys->payload) -+ #endif - /* Allow the builtin keyring to be added to the secondary */ - return 0; - -@@ -209,9 +221,15 @@ int restrict_link_by_builtin_secondary_and_machine( - const union key_payload *payload, - struct key *restrict_key) - { -+ #ifdef CONFIG_KEYP -+ if (machine_trusted_keys && type == &key_type_keyring && -+ dest_keyring == secondary_trusted_keys && -+ payload == (union key_payload *)(machine_trusted_keys->name_link.next)) -+ #else - if (machine_trusted_keys && type == &key_type_keyring && - dest_keyring == secondary_trusted_keys && - payload == &machine_trusted_keys->payload) -+ #endif - /* Allow the machine keyring to be added to the secondary */ - return 0; - -diff --git a/crypto/af_alg.c b/crypto/af_alg.c -index 68cc929..6d4415d 100644 ---- a/crypto/af_alg.c -+++ b/crypto/af_alg.c -@@ -304,7 +304,11 @@ static int alg_setkey_by_key_serial(struct alg_sock *ask, sockptr_t optval, - if (IS_ERR(key)) - return PTR_ERR(key); - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(key)); -+ #else - down_read(&key->sem); -+ #endif - - ret = ERR_PTR(-ENOPROTOOPT); - if (!strcmp(key->type->name, "user") || -@@ -319,21 +323,33 @@ static int alg_setkey_by_key_serial(struct alg_sock *ask, sockptr_t optval, - } - - if (IS_ERR(ret)) { -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - return PTR_ERR(ret); - } - - key_data = sock_kmalloc(&ask->sk, key_datalen, GFP_KERNEL); - if (!key_data) { -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - return -ENOMEM; - } - - memcpy(key_data, ret, key_datalen); - -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - - err = type->setkey(ask->private, key_data, key_datalen); -diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c -index a5da8cc..e767714 100644 ---- a/crypto/asymmetric_keys/asymmetric_type.c -+++ b/crypto/asymmetric_keys/asymmetric_type.c -@@ -15,6 +15,9 @@ - #include <linux/ctype.h> - #include <keys/system_keyring.h> - #include <keys/user-type.h> -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif - #include "asymmetric_keys.h" - - -@@ -466,6 +469,17 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) - static void asymmetric_key_destroy(struct key *key) - { - struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key); -+#ifdef CONFIG_KEYP -+ struct asymmetric_key_ids *kids = ((union key_payload *)(key->name_link.next))->data[asym_key_ids]; -+ union key_payload *key_payload = (union key_payload *)(key->name_link.next); -+ void *data = ((union key_payload *)(key->name_link.next))->data[asym_crypto]; -+ void *auth = ((union key_payload *)(key->name_link.next))->data[asym_auth]; -+ -+ key_payload->data[asym_crypto] = NULL; -+ key_payload->data[asym_subtype] = NULL; -+ key_payload->data[asym_key_ids] = NULL; -+ key_payload->data[asym_auth] = NULL; -+#else - struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids]; - void *data = key->payload.data[asym_crypto]; - void *auth = key->payload.data[asym_auth]; -@@ -474,6 +488,7 @@ static void asymmetric_key_destroy(struct key *key) - key->payload.data[asym_subtype] = NULL; - key->payload.data[asym_key_ids] = NULL; - key->payload.data[asym_auth] = NULL; -+#endif - - if (subtype) { - subtype->destroy(data, auth); -@@ -579,8 +594,13 @@ int asymmetric_key_eds_op(struct kernel_pkey_params *params, - if (key->type != &key_type_asymmetric) - return -EINVAL; - subtype = asymmetric_key_subtype(key); -+ #ifdef CONFIG_KEYP -+ if (!subtype || -+ !((union key_payload *)(key->name_link.next))->data[0]) -+ #else - if (!subtype || - !key->payload.data[0]) -+ #endif - return -EINVAL; - if (!subtype->eds_op) - return -ENOTSUPP; -diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c -index 1dcab27..490ba98 100644 ---- a/crypto/asymmetric_keys/public_key.c -+++ b/crypto/asymmetric_keys/public_key.c -@@ -30,7 +30,11 @@ MODULE_LICENSE("GPL"); - static void public_key_describe(const struct key *asymmetric_key, - struct seq_file *m) - { -+ #ifdef CONFIG_KEYP -+ struct public_key *key = ((union key_payload *)(asymmetric_key->name_link.next))->data[asym_crypto]; -+ #else - struct public_key *key = asymmetric_key->payload.data[asym_crypto]; -+ #endif - - if (key) - seq_printf(m, "%s.%s", key->id_type, key->pkey_algo); -@@ -158,7 +162,11 @@ static int software_key_query(const struct kernel_pkey_params *params, - struct kernel_pkey_query *info) - { - struct crypto_akcipher *tfm; -+ #ifdef CONFIG_KEYP -+ struct public_key *pkey = ((union key_payload *)(params->key->name_link.next))->data[asym_crypto]; -+ #else - struct public_key *pkey = params->key->payload.data[asym_crypto]; -+ #endif - char alg_name[CRYPTO_MAX_ALG_NAME]; - struct crypto_sig *sig; - u8 *key, *ptr; -@@ -273,7 +281,11 @@ static int software_key_query(const struct kernel_pkey_params *params, - static int software_key_eds_op(struct kernel_pkey_params *params, - const void *in, void *out) - { -+ #ifdef CONFIG_KEYP -+ const struct public_key *pkey = ((union key_payload *)(params->key->name_link.next))->data[asym_crypto]; -+ #else - const struct public_key *pkey = params->key->payload.data[asym_crypto]; -+ #endif - char alg_name[CRYPTO_MAX_ALG_NAME]; - struct crypto_akcipher *tfm; - struct crypto_sig *sig; -@@ -453,7 +465,11 @@ EXPORT_SYMBOL_GPL(public_key_verify_signature); - static int public_key_verify_signature_2(const struct key *key, - const struct public_key_signature *sig) - { -+ #ifdef CONFIG_KEYP -+ const struct public_key *pk = ((union key_payload *)(key->name_link.next))->data[asym_crypto]; -+ #else - const struct public_key *pk = key->payload.data[asym_crypto]; -+ #endif - return public_key_verify_signature(pk, sig); - } - -diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c -index 2deff81..696fa2c 100644 ---- a/crypto/asymmetric_keys/signature.c -+++ b/crypto/asymmetric_keys/signature.c -@@ -51,8 +51,13 @@ int query_asymmetric_key(const struct kernel_pkey_params *params, - if (key->type != &key_type_asymmetric) - return -EINVAL; - subtype = asymmetric_key_subtype(key); -+ #ifdef CONFIG_KEYP -+ if (!subtype || -+ !((union key_payload *)(key->name_link.next))->data[0]) -+ #else - if (!subtype || - !key->payload.data[0]) -+ #endif - return -EINVAL; - if (!subtype->query) - return -ENOTSUPP; -@@ -145,8 +150,13 @@ int verify_signature(const struct key *key, - if (key->type != &key_type_asymmetric) - return -EINVAL; - subtype = asymmetric_key_subtype(key); -+ #ifdef CONFIG_KEYP -+ if (!subtype || -+ !((union key_payload *)(key->name_link.next))->data[0]) -+ #else - if (!subtype || - !key->payload.data[0]) -+ #endif - return -EINVAL; - if (!subtype->verify_signature) - return -ENOTSUPP; -diff --git a/debian.master/changelog b/debian.master/changelog -index 4a253dd..9d9f81a 100644 ---- a/debian.master/changelog -+++ b/debian.master/changelog -@@ -1,3 +1,9 @@ -+linux (6.6.0-15.0ok10) nile; urgency=medium -+ -+ * rebase linux-6.6-next, build ok10 -+ -+ -- XieWei <xiewei@kylinos.cn> Thu, 16 Jan 2025 10:30:06 +0800 -+ - linux (6.6.0-15.0ok9) nile; urgency=medium - - [ user ] -diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c -index 96eccc4..ffda7c0 100644 ---- a/drivers/acpi/pci_mcfg.c -+++ b/drivers/acpi/pci_mcfg.c -@@ -185,6 +185,18 @@ static struct mcfg_fixup mcfg_quirks[] = { - LOONGSON_ECAM_MCFG("LOONGSON", 0), - LOONGSON_ECAM_MCFG("\0", 1), - LOONGSON_ECAM_MCFG("LOONGSON", 1), -+ LOONGSON_ECAM_MCFG("\0", 2), -+ LOONGSON_ECAM_MCFG("LOONGSON", 2), -+ LOONGSON_ECAM_MCFG("\0", 3), -+ LOONGSON_ECAM_MCFG("LOONGSON", 3), -+ LOONGSON_ECAM_MCFG("\0", 4), -+ LOONGSON_ECAM_MCFG("LOONGSON", 4), -+ LOONGSON_ECAM_MCFG("\0", 5), -+ LOONGSON_ECAM_MCFG("LOONGSON", 5), -+ LOONGSON_ECAM_MCFG("\0", 6), -+ LOONGSON_ECAM_MCFG("LOONGSON", 6), -+ LOONGSON_ECAM_MCFG("\0", 7), -+ LOONGSON_ECAM_MCFG("LOONGSON", 7), - #endif /* LOONGARCH */ - }; - -diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index 907a541..e27cc5e 100644 ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -391,6 +391,26 @@ config UV_MMTIMER - The uv_mmtimer device allows direct userspace access to the - UV system timer. - -+config LOONGSON_SE -+ tristate "LOONGSON SECURITY MODULE Interface" -+ depends on LOONGARCH -+ default m -+ help -+ If you have LOONGSON security module (SE) support say Yes and it -+ will be accessible from within Linux. -+ To compile this driver as a module, choose M here,the module will -+ be called loongson-se. -+ -+config LOONGSON_SE_SDF -+ tristate "LOONGSON SECURITY MODULE SDF Interface" -+ depends on LOONGARCH && LOONGSON_SE -+ default m -+ help -+ If you want to use LOONGSON security module (SE) as SDF say Yes -+ and it will be accessible from within Linux. -+ To compile this driver as a module, choose M here,the module will -+ be called loongson-se. -+ - source "drivers/char/tpm/Kconfig" - - config TELCLOCK -diff --git a/drivers/char/Makefile b/drivers/char/Makefile -index 8a10c23..a2d2abc 100644 ---- a/drivers/char/Makefile -+++ b/drivers/char/Makefile -@@ -32,6 +32,8 @@ obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o - obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o - obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o - obj-$(CONFIG_TELCLOCK) += tlclk.o -+obj-$(CONFIG_LOONGSON_SE) += loongson_se.o -+obj-$(CONFIG_LOONGSON_SE_SDF) += lsse_sdf_cdev.o - - obj-$(CONFIG_MWAVE) += mwave/ - obj-y += agp/ -diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig -index d0d86e3..bc62e52 100644 ---- a/drivers/char/hw_random/Kconfig -+++ b/drivers/char/hw_random/Kconfig -@@ -586,6 +586,18 @@ config HW_RANDOM_JH7110 - To compile this driver as a module, choose M here. - The module will be called jh7110-trng. - -+config HW_RANDOM_PHYTIUM -+ tristate "Phytium Random Number Generator support" -+ depends on ARCH_PHYTIUM || COMPILE_TEST -+ help -+ This driver provides kernel-side support for the Random Number -+ Generator hardware found on Phytium SoCs. -+ -+ To compile this driver as a module, choose M here: the -+ module will be called phytium-rng. -+ -+ If unsure, say Y. -+ - endif # HW_RANDOM - - config UML_RANDOM -diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile -index ef5b3ae..50c4045 100644 ---- a/drivers/char/hw_random/Makefile -+++ b/drivers/char/hw_random/Makefile -@@ -50,3 +50,4 @@ obj-$(CONFIG_HW_RANDOM_ARM_SMCCC_TRNG) += arm_smccc_trng.o - obj-$(CONFIG_HW_RANDOM_CN10K) += cn10k-rng.o - obj-$(CONFIG_HW_RANDOM_POLARFIRE_SOC) += mpfs-rng.o - obj-$(CONFIG_HW_RANDOM_JH7110) += jh7110-trng.o -+obj-$(CONFIG_HW_RANDOM_PHYTIUM) += phytium-rng.o -diff --git a/drivers/char/hw_random/phytium-rng.c b/drivers/char/hw_random/phytium-rng.c -new file mode 100644 -index 0000000..ef4c137 ---- /dev/null -+++ b/drivers/char/hw_random/phytium-rng.c -@@ -0,0 +1,154 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Phytium SoC RNG Driver -+ * -+ * Copyright (C) 2021-2023, Phytium Technology Co., Ltd. -+ */ -+ -+#include <linux/bits.h> -+#include <linux/err.h> -+#include <linux/hw_random.h> -+#include <linux/io.h> -+#include <linux/iopoll.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/platform_device.h> -+#include <linux/random.h> -+#include <linux/string.h> -+ -+#define TRNG_CR 0x00 -+#define TRNG_CR_RNGEN BIT(0) -+#define TRNG_CR_ROSEN_MASK GENMASK(7, 4) -+#define TRNG_CR_DIEN BIT(16) -+#define TRNG_CR_ERIEN BIT(17) -+#define TRNG_CR_IRQEN BIT(24) -+#define TRNG_MSEL 0x04 -+#define TRNG_MSEL_MSEL BIT(0) -+#define TRNG_SR 0x08 -+#define TRNG_SR_HTF BIT(0) -+#define TRNG_SR_DRDY BIT(1) -+#define TRNG_SR_ERERR BIT(3) -+#define TRNG_DR 0x0C -+#define TRNG_RESEED 0x40 -+#define TRNG_RESEED_RSED BIT(0) -+ -+#define DELAY 10 -+#define TIMEOUT 100 -+ -+static int msel; -+module_param(msel, int, 0444); -+MODULE_PARM_DESC(msel, "Phytium RNG mode selection: 0 - TRNG. 1 - PRNG."); -+ -+struct phytium_rng { -+ struct hwrng rng; -+ void __iomem *base; -+}; -+ -+static int phytium_rng_init(struct hwrng *rng) -+{ -+ struct phytium_rng *priv = container_of(rng, struct phytium_rng, rng); -+ u32 reg; -+ -+ /* Mode Selection */ -+ reg = msel ? TRNG_MSEL_MSEL : 0; -+ writel(reg, priv->base + TRNG_MSEL); -+ -+ /* If PRGN mode is on, do reseed operations */ -+ if (msel) -+ writel(TRNG_RESEED_RSED, priv->base + TRNG_RESEED); -+ -+ /* Clear status */ -+ writel(0x7, priv->base + TRNG_SR); -+ -+ /* Enable TRNG */ -+ reg = readl(priv->base + TRNG_CR) | TRNG_CR_ROSEN_MASK | TRNG_CR_RNGEN; -+ writel(reg, priv->base + TRNG_CR); -+ -+ return 0; -+} -+ -+static void phytium_rng_cleanup(struct hwrng *rng) -+{ -+ struct phytium_rng *priv = container_of(rng, struct phytium_rng, rng); -+ -+ writel(0x7, priv->base + TRNG_SR); -+} -+ -+static int phytium_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait) -+{ -+ struct phytium_rng *priv = container_of(rng, struct phytium_rng, rng); -+ u32 reg; -+ int ret = 0; -+ -+ /* TRNG can generate at most 8*32bit random number per time */ -+ max = max > 8 ? 8 : max; -+ -+ reg = readl(priv->base + TRNG_SR); -+ if (!(reg & TRNG_SR_DRDY) && wait) { -+ ret = readl_poll_timeout(priv->base + TRNG_SR, reg, -+ reg & TRNG_SR_DRDY, DELAY, TIMEOUT); -+ if (ret) { -+ dev_err((struct device *)priv->rng.priv, -+ "%s: timeout %x!\n", __func__, reg); -+ return -EIO; -+ } -+ } -+ -+ while (max > 4) { -+ *(u32 *)buf = readl(priv->base + TRNG_DR); -+ -+ ret += sizeof(u32); -+ buf += sizeof(u32); -+ max -= sizeof(u32); -+ } -+ -+ /* Clear DRDY by writing 1 */ -+ writel(reg | TRNG_SR_DRDY, priv->base + TRNG_SR); -+ -+ return ret; -+} -+ -+static int scto_rng_probe(struct platform_device *pdev) -+{ -+ struct phytium_rng *priv; -+ struct resource *mem; -+ -+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ platform_set_drvdata(pdev, priv); -+ -+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ priv->base = devm_ioremap_resource(&pdev->dev, mem); -+ if (IS_ERR(priv->base)) -+ return PTR_ERR(priv->base); -+ -+ priv->rng.name = pdev->name; -+ priv->rng.init = phytium_rng_init; -+ priv->rng.cleanup = phytium_rng_cleanup; -+ priv->rng.read = phytium_rng_read; -+ priv->rng.priv = (unsigned long)&pdev->dev; -+ -+ return devm_hwrng_register(&pdev->dev, &priv->rng); -+} -+ -+static const struct of_device_id phytium_rng_dt_ids[] = { -+ { .compatible = "phytium,rng" }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, phytium_rng_dt_ids); -+ -+static struct platform_driver phytium_rng_driver = { -+ .probe = scto_rng_probe, -+ .driver = { -+ .name = "phytium-rng", -+ .of_match_table = of_match_ptr(phytium_rng_dt_ids), -+ } -+}; -+module_platform_driver(phytium_rng_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Phytium random number generator driver"); -+MODULE_AUTHOR("Chen Baozi <chenbaozi@phytium.com.cn>"); -diff --git a/drivers/char/loongson_se.c b/drivers/char/loongson_se.c -new file mode 100644 -index 0000000..40d2d651 ---- /dev/null -+++ b/drivers/char/loongson_se.c -@@ -0,0 +1,601 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include <linux/kernel.h> -+#include <linux/delay.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/errno.h> -+#include <linux/cdev.h> -+#include <linux/device.h> -+#include <linux/of.h> -+#include <linux/of_address.h> -+#include <linux/platform_device.h> -+#include <linux/miscdevice.h> -+#include <linux/iopoll.h> -+#include <linux/dma-mapping.h> -+#include <linux/interrupt.h> -+#include <asm/se.h> -+ -+static int se_mem_size = 0x800000; -+module_param(se_mem_size, int, 0444); -+MODULE_PARM_DESC(se_mem_size, "LOONGSON SE shared memory size"); -+ -+static int se_mem_page = PAGE_SIZE; -+module_param(se_mem_page, int, 0444); -+MODULE_PARM_DESC(se_mem_page, "LOONGSON SE shared memory page size"); -+ -+static struct loongson_se se_dev; -+ -+static int lsse_open(struct inode *inode, struct file *filp) -+{ -+ return 0; -+} -+ -+static ssize_t lsse_write(struct file *filp, const char __user *buf, -+ size_t cnt, loff_t *offt) -+{ -+ return 0; -+} -+ -+static const struct file_operations lsse_fops = { -+ .owner = THIS_MODULE, -+ .open = lsse_open, -+ .write = lsse_write, -+}; -+ -+static const struct miscdevice lsse_miscdev = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "loongson-se", -+ .fops = &lsse_fops, -+}; -+ -+static inline u32 se_readl(u64 addr) -+{ -+ return readl(se_dev.base + addr); -+} -+ -+static inline void se_writel(u32 val, u64 addr) -+{ -+ writel(val, se_dev.base + addr); -+} -+ -+static inline bool se_ch_status(struct loongson_se *se, u32 int_bit) -+{ -+ return !!(se->ch_status & int_bit) == 1; -+} -+ -+static void se_enable_int(struct loongson_se *se, u32 int_bit) -+{ -+ unsigned long flag; -+ u32 tmp; -+ -+ if (!int_bit) -+ return; -+ -+ spin_lock_irqsave(&se->dev_lock, flag); -+ -+ tmp = se_readl(SE_S2LINT_EN); -+ tmp |= int_bit; -+ se_writel(tmp, SE_S2LINT_EN); -+ -+ spin_unlock_irqrestore(&se->dev_lock, flag); -+} -+ -+static void se_disable_int(struct loongson_se *se, u32 int_bit) -+{ -+ unsigned long flag; -+ u32 tmp; -+ -+ if (!int_bit) -+ return; -+ -+ spin_lock_irqsave(&se->dev_lock, flag); -+ -+ tmp = se_readl(SE_S2LINT_EN); -+ tmp &= ~(int_bit); -+ se_writel(tmp, SE_S2LINT_EN); -+ -+ spin_unlock_irqrestore(&se->dev_lock, flag); -+} -+ -+static int se_send_requeset(struct loongson_se *se, -+ struct se_mailbox_data *req) -+{ -+ unsigned long flag; -+ u32 status; -+ int err = 0; -+ int i; -+ -+ if (!se || !req) -+ return -EINVAL; -+ -+ if (se_readl(SE_L2SINT_STAT) || -+ !(se_readl(SE_L2SINT_EN) & req->int_bit)) -+ return -EBUSY; -+ -+ spin_lock_irqsave(&se->cmd_lock, flag); -+ -+ for (i = 0; i < ARRAY_SIZE(req->u.mailbox); i++) -+ se_writel(req->u.mailbox[i], SE_MAILBOX_S + i * 4); -+ -+ se_writel(req->int_bit, SE_L2SINT_SET); -+ -+ err = readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status, -+ !(status & req->int_bit), 10, 10000); -+ -+ spin_unlock_irqrestore(&se->cmd_lock, flag); -+ -+ return err; -+} -+ -+static int se_get_response(struct loongson_se *se, -+ struct se_mailbox_data *res) -+{ -+ unsigned long flag; -+ int i; -+ -+ if (!se || !res) -+ return -EINVAL; -+ -+ if ((se_readl(SE_S2LINT_STAT) & res->int_bit) == 0) -+ return -EBUSY; -+ -+ spin_lock_irqsave(&se->cmd_lock, flag); -+ -+ for (i = 0; i < ARRAY_SIZE(res->u.mailbox); i++) -+ res->u.mailbox[i] = se_readl(SE_MAILBOX_L + i * 4); -+ -+ se_writel(res->int_bit, SE_S2LINT_CL); -+ -+ spin_unlock_irqrestore(&se->cmd_lock, flag); -+ -+ return 0; -+} -+ -+static int loongson_se_get_res(struct loongson_se *se, u32 int_bit, u32 cmd, -+ struct se_mailbox_data *res) -+{ -+ int err = 0; -+ -+ res->int_bit = int_bit; -+ -+ if (se_get_response(se, res)) { -+ dev_err(se->dev, "Int 0x%x get response fail.\n", int_bit); -+ return -EFAULT; -+ } -+ -+ /* Check response */ -+ if (res->u.res.cmd == cmd) -+ err = 0; -+ else { -+ dev_err(se->dev, "Response cmd is 0x%x, not expect cmd 0x%x.\n", -+ res->u.res.cmd, cmd); -+ err = -EFAULT; -+ } -+ -+ return err; -+} -+ -+static int se_send_genl_cmd(struct loongson_se *se, struct se_mailbox_data *req, -+ struct se_mailbox_data *res, int retry) -+{ -+ int err = 0, cnt = 0; -+ -+try_again: -+ if (cnt++ >= retry) { -+ err = -ETIMEDOUT; -+ goto out; -+ } -+ -+ dev_dbg(se->dev, "%d time send cmd 0x%x\n", cnt, req->u.gcmd.cmd); -+ -+ err = se_send_requeset(se, req); -+ if (err) -+ goto try_again; -+ -+ if (!wait_for_completion_timeout(&se->cmd_completion, -+ msecs_to_jiffies(0x1000))) { -+ se_enable_int(se, req->int_bit); -+ goto try_again; -+ } -+ -+ err = loongson_se_get_res(se, req->int_bit, req->u.gcmd.cmd, res); -+ if (err || res->u.res.cmd_ret) { -+ se_enable_int(se, req->int_bit); -+ goto try_again; -+ } -+ -+out: -+ se_enable_int(se, req->int_bit); -+ -+ return err; -+} -+ -+static int loongson_se_set_msg(struct lsse_ch *ch) -+{ -+ struct loongson_se *se = ch->se; -+ struct se_mailbox_data req = {0}; -+ struct se_mailbox_data res = {0}; -+ int err; -+ -+ req.int_bit = SE_INT_SETUP; -+ req.u.gcmd.cmd = SE_CMD_SETMSG; -+ /* MSG off */ -+ req.u.gcmd.info[0] = ch->id; -+ req.u.gcmd.info[1] = ch->smsg - se->mem_base; -+ req.u.gcmd.info[2] = ch->msg_size; -+ -+ dev_dbg(se->dev, "Set Channel %d msg off 0x%x, msg size %d\n", ch->id, -+ req.u.gcmd.info[1], req.u.gcmd.info[2]); -+ -+ err = se_send_genl_cmd(se, &req, &res, 5); -+ if (res.u.res.cmd_ret) -+ return res.u.res.cmd_ret; -+ -+ return err; -+} -+ -+static irqreturn_t loongson_se_irq(int irq, void *dev_id) -+{ -+ struct loongson_se *se = (struct loongson_se *)dev_id; -+ struct lsse_ch *ch; -+ u32 int_status; -+ -+ int_status = se_readl(SE_S2LINT_STAT); -+ -+ dev_dbg(se->dev, "%s int status is 0x%x\n", __func__, int_status); -+ -+ se_disable_int(se, int_status); -+ -+ if (int_status & SE_INT_SETUP) { -+ complete(&se->cmd_completion); -+ int_status &= ~SE_INT_SETUP; -+ } -+ -+ while (int_status) { -+ int id = __ffs(int_status); -+ -+ ch = &se->chs[id]; -+ if (ch->complete) -+ ch->complete(ch); -+ int_status &= ~BIT(id); -+ se_writel(BIT(id), SE_S2LINT_CL); -+ } -+ -+ return IRQ_HANDLED; -+} -+ -+static int se_init_hw(struct loongson_se *se) -+{ -+ struct se_mailbox_data req = {0}; -+ struct se_mailbox_data res = {0}; -+ struct device *dev = se->dev; -+ int err, retry = 5; -+ u64 size; -+ -+ size = se_mem_size; -+ -+ if (size & (size - 1)) { -+ size = roundup_pow_of_two(size); -+ se_mem_size = size; -+ } -+ -+ se_enable_int(se, SE_INT_SETUP); -+ -+ /* Start engine */ -+ memset(&req, 0, sizeof(struct se_mailbox_data)); -+ memset(&res, 0, sizeof(struct se_mailbox_data)); -+ req.int_bit = SE_INT_SETUP; -+ req.u.gcmd.cmd = SE_CMD_START; -+ err = se_send_genl_cmd(se, &req, &res, retry); -+ if (err) -+ return err; -+ -+ /* Get Version */ -+ memset(&req, 0, sizeof(struct se_mailbox_data)); -+ memset(&res, 0, sizeof(struct se_mailbox_data)); -+ req.int_bit = SE_INT_SETUP; -+ req.u.gcmd.cmd = SE_CMD_GETVER; -+ err = se_send_genl_cmd(se, &req, &res, retry); -+ if (err) -+ return err; -+ -+ se->version = res.u.res.info[0]; -+ -+ /* Setup data buffer */ -+ se->mem_base = dmam_alloc_coherent(dev, size, -+ &se->mem_addr, GFP_KERNEL); -+ if (!se->mem_base) -+ return -ENOMEM; -+ -+ memset(se->mem_base, 0, size); -+ -+ memset(&req, 0, sizeof(struct se_mailbox_data)); -+ memset(&res, 0, sizeof(struct se_mailbox_data)); -+ req.int_bit = SE_INT_SETUP; -+ req.u.gcmd.cmd = SE_CMD_SETBUF; -+ /* MMAP */ -+ req.u.gcmd.info[0] = (se->mem_addr & 0xffffffff) | 0x80; -+ req.u.gcmd.info[1] = se->mem_addr >> 32; -+ /* MASK */ -+ req.u.gcmd.info[2] = ~(size - 1); -+ req.u.gcmd.info[3] = 0xffffffff; -+ -+ pr_debug("Set win mmap 0x%llx, mask 0x%llx\n", -+ ((u64)req.u.gcmd.info[1] << 32) | req.u.gcmd.info[0], -+ ((u64)req.u.gcmd.info[3] << 32) | req.u.gcmd.info[2]); -+ -+ err = se_send_genl_cmd(se, &req, &res, retry); -+ if (err) -+ return err; -+ -+ se->mem_map_size = size / se_mem_page; -+ se->mem_map = bitmap_zalloc(se->mem_map_size, GFP_KERNEL); -+ if (!se->mem_map) -+ return -ENOMEM; -+ -+ dev_info(se->dev, "SE module setup down, shared memory size is 0x%x bytes, memory page size is 0x%x bytes\n", -+ se_mem_size, se_mem_page); -+ -+ return err; -+} -+ -+static void loongson_se_disable_hw(struct loongson_se *se) -+{ -+ struct se_mailbox_data req = {0}; -+ struct se_mailbox_data res = {0}; -+ int retry = 5; -+ -+ /* Stop engine */ -+ req.int_bit = SE_INT_SETUP; -+ req.u.gcmd.cmd = SE_CMD_STOP; -+ se_send_genl_cmd(se, &req, &res, retry); -+ -+ se_disable_int(se, SE_INT_ALL); -+ kfree(se->mem_map); -+} -+ -+int se_send_ch_requeset(struct lsse_ch *ch) -+{ -+ struct loongson_se *se; -+ u32 status, int_bit; -+ int err = 0; -+ -+ if (!ch) -+ return -EINVAL; -+ -+ se = ch->se; -+ int_bit = ch->int_bit; -+ -+ if ((se_readl(SE_L2SINT_STAT) & int_bit) || -+ !(se_readl(SE_L2SINT_EN) & int_bit)) -+ return -EBUSY; -+ -+ se_enable_int(se, int_bit); -+ se_writel(int_bit, SE_L2SINT_SET); -+ -+ err = readl_relaxed_poll_timeout_atomic(se->base + SE_L2SINT_STAT, status, -+ !(status & int_bit), 10, 10000); -+ -+ return err; -+} -+EXPORT_SYMBOL_GPL(se_send_ch_requeset); -+ -+struct lsse_ch *se_init_ch(int id, int data_size, int msg_size, void *priv, -+ void (*complete)(struct lsse_ch *se_ch)) -+{ -+ struct loongson_se *se = &se_dev; -+ struct lsse_ch *ch; -+ unsigned long flag; -+ int data_first, data_nr; -+ int msg_first, msg_nr; -+ -+ if (!se) { -+ pr_err("SE has bot been initialized\n"); -+ return NULL; -+ } -+ -+ if (id == 0 || id > SE_CH_MAX) { -+ dev_err(se->dev, "Channel number %d is invalid\n", id); -+ return NULL; -+ } -+ -+ if (se_ch_status(se, BIT(id))) { -+ dev_err(se->dev, "Channel number %d has been initialized\n", id); -+ return NULL; -+ } -+ -+ spin_lock_irqsave(&se->dev_lock, flag); -+ -+ ch = &se_dev.chs[id]; -+ ch->se = se; -+ ch->id = id; -+ ch->int_bit = BIT(id); -+ se->ch_status |= BIT(id); -+ -+ data_nr = round_up(data_size, se_mem_page) / se_mem_page; -+ data_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_size, -+ 0, data_nr, 0); -+ if (data_first >= se->mem_map_size) { -+ dev_err(se->dev, "Insufficient memory space\n"); -+ spin_unlock_irqrestore(&se->dev_lock, flag); -+ return NULL; -+ } -+ -+ bitmap_set(se->mem_map, data_first, data_nr); -+ ch->data_buffer = se->mem_base + data_first * se_mem_page; -+ ch->data_addr = se->mem_addr + data_first * se_mem_page; -+ ch->data_size = data_size; -+ -+ msg_nr = round_up(msg_size, se_mem_page) / se_mem_page; -+ msg_first = bitmap_find_next_zero_area(se->mem_map, se->mem_map_size, -+ 0, msg_nr, 0); -+ if (msg_first >= se->mem_map_size) { -+ dev_err(se->dev, "Insufficient memory space\n"); -+ bitmap_clear(se->mem_map, data_first, data_nr); -+ spin_unlock_irqrestore(&se->dev_lock, flag); -+ return NULL; -+ } -+ -+ bitmap_set(se->mem_map, msg_first, msg_nr); -+ ch->smsg = se->mem_base + msg_first * se_mem_page; -+ ch->rmsg = ch->smsg + msg_size / 2; -+ ch->msg_size = msg_size; -+ -+ ch->complete = complete; -+ ch->priv = priv; -+ -+ spin_lock_init(&ch->ch_lock); -+ -+ spin_unlock_irqrestore(&se->dev_lock, flag); -+ -+ if (loongson_se_set_msg(ch)) { -+ dev_err(se->dev, "Channel %d setup message address failed\n", id); -+ return NULL; -+ } -+ -+ se_enable_int(se, ch->int_bit); -+ -+ return ch; -+} -+EXPORT_SYMBOL_GPL(se_init_ch); -+ -+void se_deinit_ch(struct lsse_ch *ch) -+{ -+ struct loongson_se *se = &se_dev; -+ unsigned long flag; -+ int first, nr; -+ int id = ch->id; -+ -+ if (!se) { -+ pr_err("SE has bot been initialized\n"); -+ return; -+ } -+ -+ if (id == 0 || id > SE_CH_MAX) { -+ dev_err(se->dev, "Channel number %d is invalid\n", id); -+ return; -+ } -+ -+ if (!se_ch_status(se, BIT(id))) { -+ dev_err(se->dev, "Channel number %d has not been initialized\n", id); -+ return; -+ } -+ -+ spin_lock_irqsave(&se->dev_lock, flag); -+ -+ se->ch_status &= ~BIT(ch->id); -+ -+ first = (ch->data_buffer - se->mem_base) / se_mem_page; -+ nr = round_up(ch->data_size, se_mem_page) / se_mem_page; -+ bitmap_clear(se->mem_map, first, nr); -+ -+ first = (ch->smsg - se->mem_base) / se_mem_page; -+ nr = round_up(ch->msg_size, se_mem_page) / se_mem_page; -+ bitmap_clear(se->mem_map, first, nr); -+ -+ spin_unlock_irqrestore(&se->dev_lock, flag); -+ -+ se_disable_int(se, ch->int_bit); -+} -+EXPORT_SYMBOL_GPL(se_deinit_ch); -+ -+static struct platform_device lsse_sdf_pdev = { -+ .name = "loongson-sdf", -+ .id = -1, -+}; -+ -+static const struct of_device_id loongson_se_of_match[] = { -+ { .compatible = "loongson,ls3c6000se", }, -+ {} -+}; -+MODULE_DEVICE_TABLE(of, loongson_se_of_match); -+ -+static int loongson_se_probe(struct platform_device *pdev) -+{ -+ struct loongson_se *se = &se_dev; -+ struct resource *res; -+ struct device *dev = &pdev->dev; -+ int nr_irq, err, i; -+ int irq[8]; -+ -+ nr_irq = platform_irq_count(pdev); -+ if (nr_irq < 0) -+ return -ENODEV; -+ -+ for (i = 0; i < nr_irq; i++) { -+ irq[i] = platform_get_irq(pdev, i); -+ if (irq[i] < 0) -+ return -ENODEV; -+ } -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) -+ return -ENODEV; -+ -+ se->base = devm_ioremap_resource(dev, res); -+ if (IS_ERR(se->base)) -+ return PTR_ERR(se->base); -+ -+ se->dev = &pdev->dev; -+ platform_set_drvdata(pdev, se); -+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); -+ init_completion(&se->cmd_completion); -+ spin_lock_init(&se->cmd_lock); -+ spin_lock_init(&se->dev_lock); -+ -+ for (i = 0; i < nr_irq; i++) { -+ err = devm_request_irq(dev, irq[i], loongson_se_irq, 0, -+ "loongson-se", se); -+ if (err) -+ goto out; -+ } -+ -+ err = se_init_hw(se); -+ if (err) -+ goto disable_hw; -+ -+ err = misc_register(&lsse_miscdev); -+ if (err) -+ goto disable_hw; -+ -+ err = platform_device_register(&lsse_sdf_pdev); -+ if (err) -+ pr_err("register sdf device failed\n"); -+ -+ return 0; -+ -+disable_hw: -+ loongson_se_disable_hw(se); -+out: -+ for ( ; i >= 0; i--) -+ devm_free_irq(dev, irq[i], se); -+ -+ return err; -+} -+ -+static int loongson_se_remove(struct platform_device *pdev) -+{ -+ struct loongson_se *se = platform_get_drvdata(pdev); -+ -+ misc_deregister(&lsse_miscdev); -+ loongson_se_disable_hw(se); -+ platform_device_unregister(&lsse_sdf_pdev); -+ -+ return 0; -+} -+ -+static struct platform_driver loongson_se_driver = { -+ .probe = loongson_se_probe, -+ .remove = loongson_se_remove, -+ .driver = { -+ .name = "loongson-se", -+ .of_match_table = loongson_se_of_match, -+ }, -+}; -+ -+module_platform_driver(loongson_se_driver); -+ -+MODULE_AUTHOR("Yinggang Gu"); -+MODULE_DESCRIPTION("Loongson SE driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/char/lsse_sdf_cdev.c b/drivers/char/lsse_sdf_cdev.c -new file mode 100644 -index 0000000..a4806fb ---- /dev/null -+++ b/drivers/char/lsse_sdf_cdev.c -@@ -0,0 +1,380 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/miscdevice.h> -+#include <linux/module.h> -+#include <linux/cdev.h> -+#include <linux/module.h> -+#include <linux/wait.h> -+#include <linux/of.h> -+#include <linux/iopoll.h> -+#include <linux/platform_device.h> -+#include <linux/uaccess.h> -+#include <asm/se.h> -+#include <linux/list.h> -+ -+#define SE_SDF_BUFSIZE (PAGE_SIZE * 2) -+#define SDF_OPENSESSION 0x204 -+#define SDF_CLOSESESSION 0x205 -+ -+struct lsse_sdf_dev { -+ struct lsse_ch *se_ch; -+ struct mutex data_lock; -+ bool processing_cmd; -+ -+ /* Synchronous CMD */ -+ wait_queue_head_t wq; -+}; -+ -+struct se_sdf_msg { -+ u32 cmd; -+ u32 data_off; -+ u32 data_len; -+ u32 info[5]; -+}; -+ -+struct sdf_command_header { -+ int command; -+ union { -+ int param_cnt; -+ int ret; -+ } u; -+ int param_len[14]; -+}; -+ -+struct sdf_kernel_command { -+ struct sdf_command_header header; -+ void *handle; -+}; -+ -+#define KERNEL_COMMAND_SIZE (sizeof(struct sdf_kernel_command)) -+ -+struct sdf_handle { -+ struct list_head handle_list; -+ void *handle; -+}; -+ -+struct sdf_file_pvt_data { -+ struct lsse_sdf_dev *se; -+ struct list_head handle_list; -+ struct sdf_kernel_command skc; -+ struct sdf_handle *ph; -+}; -+ -+static struct lsse_sdf_dev *se_sdf_dev; -+ -+static void lsse_sdf_complete(struct lsse_ch *ch) -+{ -+ struct lsse_sdf_dev *se = (struct lsse_sdf_dev *)ch->priv; -+ -+ se->processing_cmd = false; -+ wake_up(&se->wq); -+} -+ -+static int se_send_sdf_cmd(struct lsse_sdf_dev *se, int len, int retry) -+{ -+ struct se_sdf_msg *smsg = (struct se_sdf_msg *)se->se_ch->smsg; -+ unsigned long flag; -+ int err; -+ -+ spin_lock_irqsave(&se->se_ch->ch_lock, flag); -+ -+ smsg->cmd = SE_CMD_SDF; -+ /* One time one cmd */ -+ smsg->data_off = se->se_ch->data_buffer - se->se_ch->se->mem_base; -+ smsg->data_len = len; -+ -+try_again: -+ if (!retry--) -+ goto out; -+ -+ pr_debug("Send sdf cmd, last retry %d times\n", retry); -+ -+ err = se_send_ch_requeset(se->se_ch); -+ if (err) { -+ udelay(5); -+ goto try_again; -+ } -+ -+out: -+ spin_unlock_irqrestore(&se->se_ch->ch_lock, flag); -+ -+ return err; -+} -+ -+static int lsse_sdf_recv(struct sdf_file_pvt_data *pvt, char *buf, -+ size_t size, int user, int *se_ret) -+{ -+ int len, time, ret = 0; -+ struct se_sdf_msg *rmsg; -+ struct sdf_kernel_command *skc; -+ struct sdf_handle *ph; -+ struct lsse_sdf_dev *se = pvt->se; -+ -+ if (!se->se_ch->rmsg) { -+ pr_err("se device is not ready\n"); -+ return -EBUSY; -+ } -+ -+ time = wait_event_timeout(se->wq, !se->processing_cmd, HZ*30); -+ if (!time) -+ return -ETIME; -+ -+ rmsg = (struct se_sdf_msg *)se->se_ch->rmsg; -+ if (rmsg->cmd != SE_CMD_SDF) { -+ pr_err("se get wrong response\n"); -+ return -EIO; -+ } -+ len = rmsg->data_len; -+ -+ if ((!user && len > KERNEL_COMMAND_SIZE) || len > SE_SDF_BUFSIZE -+ || (size && len > size)) -+ return -E2BIG; -+ -+ if (user) { -+ ret = copy_to_user((char __user *)buf, -+ se->se_ch->data_buffer + rmsg->data_off, len); -+ if (!se_ret) -+ return ret; -+ -+ skc = (struct sdf_kernel_command *) -+ (se->se_ch->data_buffer + rmsg->data_off); -+ *se_ret = skc->header.u.ret; -+ if (skc->header.command == SDF_OPENSESSION && !*se_ret) { -+ ph = kmalloc(sizeof(*ph), GFP_KERNEL); -+ if (!ph) -+ return -ENOMEM; -+ ph->handle = skc->handle; -+ list_add(&ph->handle_list, &pvt->handle_list); -+ } -+ } else -+ memcpy(buf, se->se_ch->data_buffer + rmsg->data_off, len); -+ -+ return ret; -+} -+ -+static struct sdf_handle *find_sdf_handle(void *handle, -+ struct sdf_file_pvt_data *pvt) -+{ -+ struct sdf_handle *ph; -+ -+ list_for_each_entry(ph, &pvt->handle_list, handle_list) { -+ if (ph->handle == handle) -+ return ph; -+ } -+ -+ return NULL; -+} -+ -+static int lsse_sdf_send(struct sdf_file_pvt_data *pvt, const char *buf, -+ size_t count, int user) -+{ -+ int ret, se_ret; -+ struct sdf_handle *ph = NULL; -+ struct sdf_kernel_command *skc; -+ struct lsse_sdf_dev *se = pvt->se; -+ -+ if (!se->se_ch->smsg) { -+ pr_err("se device is not ready\n"); -+ return 0; -+ } -+ -+ if (count > se->se_ch->data_size) { -+ pr_err("Invalid size in send: count=%zd, size=%d\n", -+ count, se->se_ch->data_size); -+ return -EIO; -+ } -+ -+ if (user) { -+ ret = mutex_lock_interruptible(&se->data_lock); -+ if (ret) -+ goto out; -+ } else -+ mutex_lock(&se->data_lock); -+ -+ if (user) { -+ ret = copy_from_user(se->se_ch->data_buffer, buf, count); -+ if (ret) { -+ ret = -EFAULT; -+ goto out_unlock; -+ } -+ skc = (struct sdf_kernel_command *)se->se_ch->data_buffer; -+ if (skc->header.command == SDF_CLOSESESSION) -+ ph = find_sdf_handle(skc->handle, pvt); -+ } else -+ memcpy(se->se_ch->data_buffer, buf, count); -+ -+ se->processing_cmd = true; -+ ret = se_send_sdf_cmd(se, count, 5); -+ if (ret) { -+ pr_err("se_send_sdf_cmd failed\n"); -+ goto out_unlock; -+ } -+ -+ ret = lsse_sdf_recv(pvt, (char *)buf, 0, user, &se_ret); -+ if (ret) { -+ pr_err("recv failed ret: %x\n", ret); -+ goto out_unlock; -+ } -+ if (ph && !se_ret) { -+ list_del(&ph->handle_list); -+ kfree(ph); -+ } -+out_unlock: -+ mutex_unlock(&se->data_lock); -+out: -+ return ret; -+} -+ -+static ssize_t lsse_sdf_write(struct file *filp, const char __user *buf, -+ size_t cnt, loff_t *offt) -+{ -+ struct sdf_file_pvt_data *pvt = filp->private_data; -+ -+ if (cnt > SE_SDF_BUFSIZE) -+ return -E2BIG; -+ -+ if (lsse_sdf_send(pvt, buf, cnt, 1)) -+ return -EFAULT; -+ -+ return cnt; -+} -+ -+static ssize_t lsse_sdf_read(struct file *filp, char __user *buf, -+ size_t size, loff_t *off) -+{ -+ return lsse_sdf_recv(filp->private_data, buf, size, 1, NULL); -+} -+ -+static int close_one_handle(struct sdf_file_pvt_data *pvt, struct sdf_handle *ph) -+{ -+ struct sdf_kernel_command *skc = &pvt->skc; -+ -+ skc->header.command = 0x205; -+ skc->header.u.param_cnt = 1; -+ skc->header.param_len[0] = 8; -+ skc->handle = ph->handle; -+ /* close one session */ -+ lsse_sdf_send(pvt, (char *)&pvt->skc, KERNEL_COMMAND_SIZE, 0); -+ if (skc->header.u.ret) { -+ pr_err("Auto Close Session failed, session handle: %llx, ret: %d\n", -+ (u64)ph->handle, skc->header.u.ret); -+ return skc->header.u.ret; -+ } -+ kfree(ph); -+ -+ return 0; -+} -+ -+static int close_all_handle(struct sdf_file_pvt_data *pvt) -+{ -+ int ret = 0; -+ struct sdf_handle *ph, *tmp; -+ -+ list_for_each_entry_safe(ph, tmp, &pvt->handle_list, handle_list) { -+ list_del(&ph->handle_list); -+ ret = close_one_handle(pvt, ph); -+ if (ret) -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int lsse_sdf_release(struct inode *inode, struct file *filp) -+{ -+ int ret; -+ struct sdf_file_pvt_data *pvt = filp->private_data; -+ -+ ret = close_all_handle(pvt); -+ filp->private_data = NULL; -+ kfree(pvt); -+ -+ if (ret) -+ ret = -EFAULT; -+ return ret; -+} -+ -+static int lsse_sdf_open(struct inode *inode, struct file *filp) -+{ -+ struct sdf_file_pvt_data *pvt = kmalloc(sizeof(*pvt), GFP_KERNEL); -+ -+ if (!pvt) -+ return -ENOMEM; -+ -+ INIT_LIST_HEAD(&pvt->handle_list); -+ pvt->se = se_sdf_dev; -+ filp->private_data = pvt; -+ -+ return 0; -+} -+ -+static const struct file_operations lsse_sdf_fops = { -+ .owner = THIS_MODULE, -+ .open = lsse_sdf_open, -+ .write = lsse_sdf_write, -+ .read = lsse_sdf_read, -+ .release = lsse_sdf_release, -+}; -+ -+static const struct miscdevice lsse_sdf_miscdev = { -+ .minor = MISC_DYNAMIC_MINOR, -+ .name = "lsse_sdf", -+ .fops = &lsse_sdf_fops, -+}; -+ -+static int lsse_sdf_probe(struct platform_device *pdev) -+{ -+ int msg_size; -+ int ret; -+ -+ se_sdf_dev = kzalloc(sizeof(*se_sdf_dev), GFP_KERNEL); -+ if (IS_ERR_OR_NULL(se_sdf_dev)) -+ return PTR_ERR(se_sdf_dev); -+ -+ mutex_init(&se_sdf_dev->data_lock); -+ init_waitqueue_head(&se_sdf_dev->wq); -+ se_sdf_dev->processing_cmd = false; -+ -+ msg_size = 2 * sizeof(struct se_sdf_msg); -+ se_sdf_dev->se_ch = se_init_ch(SE_CH_SDF, SE_SDF_BUFSIZE, msg_size, -+ se_sdf_dev, lsse_sdf_complete); -+ -+ ret = misc_register(&lsse_sdf_miscdev); -+ if (ret < 0) { -+ pr_err("register sdf dev failed!\n"); -+ goto out; -+ } -+ -+ return 0; -+ -+out: -+ kfree(se_sdf_dev); -+ -+ return ret; -+} -+ -+static int lsse_sdf_remove(struct platform_device *pdev) -+{ -+ misc_deregister(&lsse_sdf_miscdev); -+ se_deinit_ch(se_sdf_dev->se_ch); -+ kfree(se_sdf_dev); -+ -+ return 0; -+} -+ -+static struct platform_driver loongson_sdf_driver = { -+ .probe = lsse_sdf_probe, -+ .remove = lsse_sdf_remove, -+ .driver = { -+ .name = "loongson-sdf", -+ }, -+}; -+module_platform_driver(loongson_sdf_driver); -+ -+MODULE_ALIAS("platform:loongson-sdf"); -+MODULE_AUTHOR("Yinggang Gu"); -+MODULE_DESCRIPTION("Loongson SE sdf driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/cpufreq/loongson3-acpi-cpufreq.c b/drivers/cpufreq/loongson3-acpi-cpufreq.c -index 018b529..67e4876 100644 ---- a/drivers/cpufreq/loongson3-acpi-cpufreq.c -+++ b/drivers/cpufreq/loongson3-acpi-cpufreq.c -@@ -1241,6 +1241,8 @@ static int loongson3_cpufreq_cpu_init(struct cpufreq_policy *policy) - if (has_boost_freq() && boost_supported()) - loongson3_cpufreq_attr[1] = &cpufreq_freq_attr_scaling_boost_freqs; - -+ policy->cur = core->normal_max_freq * 1000; -+ - pr_info("CPU%u - ACPI performance management activated.\n", cpu); - for (i = 0; i < perf->state_count; i++) - pr_debug(" %cP%d: %d MHz, %d mW, %d uS %d level\n", -diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c -index bc631d1..767ccb7 100644 ---- a/drivers/crypto/ccp/sev-dev.c -+++ b/drivers/crypto/ccp/sev-dev.c -@@ -30,6 +30,10 @@ - #include <asm/smp.h> - #include <asm/cacheflush.h> - -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+ - #include "psp-dev.h" - #include "sev-dev.h" - -@@ -205,7 +209,11 @@ static struct file *open_file_as_root(const char *filename, int flags, umode_t m - cred = prepare_creds(); - if (!cred) - return ERR_PTR(-ENOMEM); -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(cred, GLOBAL_ROOT_UID); -+ #else - cred->fsuid = GLOBAL_ROOT_UID; -+ #endif - old_cred = override_creds(cred); - - fp = file_open_root(&root, filename, flags, mode); -diff --git a/drivers/firmware/efi/libstub/loongarch.c b/drivers/firmware/efi/libstub/loongarch.c -index d0ef935..3782d0a 100644 ---- a/drivers/firmware/efi/libstub/loongarch.c -+++ b/drivers/firmware/efi/libstub/loongarch.c -@@ -74,6 +74,8 @@ efi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image, - /* Config Direct Mapping */ - csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0); - csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1); -+ csr_write64(CSR_DMW2_INIT, LOONGARCH_CSR_DMWIN2); -+ csr_write64(CSR_DMW3_INIT, LOONGARCH_CSR_DMWIN3); - - real_kernel_entry = (void *)kernel_entry_address(kernel_addr, image); - -diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c -index 1c2c9ff..47b72a3 100644 ---- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c -+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c -@@ -402,7 +402,7 @@ static ssize_t amdgpu_debugfs_gprwave_read(struct file *f, char __user *buf, siz - int r; - uint32_t *data, x; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); -@@ -522,7 +522,7 @@ static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf, - ssize_t result = 0; - int r; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); -@@ -578,7 +578,7 @@ static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user - ssize_t result = 0; - int r; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); -@@ -635,7 +635,7 @@ static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf, - ssize_t result = 0; - int r; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - if (!adev->didt_rreg) -@@ -694,7 +694,7 @@ static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user - ssize_t result = 0; - int r; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - if (!adev->didt_wreg) -@@ -757,7 +757,7 @@ static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf, - if (!adev->smc_rreg) - return -EOPNOTSUPP; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); -@@ -816,7 +816,7 @@ static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user * - if (!adev->smc_wreg) - return -EOPNOTSUPP; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); -@@ -876,7 +876,7 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf, - int r; - uint32_t *config, no_regs = 0; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - config = kmalloc_array(256, sizeof(*config), GFP_KERNEL); -@@ -1231,7 +1231,7 @@ static ssize_t amdgpu_debugfs_gfxoff_residency_read(struct file *f, char __user - ssize_t result = 0; - int r; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); -@@ -1282,7 +1282,7 @@ static ssize_t amdgpu_debugfs_gfxoff_residency_write(struct file *f, const char - ssize_t result = 0; - int r; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); -@@ -1330,7 +1330,7 @@ static ssize_t amdgpu_debugfs_gfxoff_count_read(struct file *f, char __user *buf - ssize_t result = 0; - int r; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); -@@ -1381,7 +1381,7 @@ static ssize_t amdgpu_debugfs_gfxoff_write(struct file *f, const char __user *bu - ssize_t result = 0; - int r; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); -@@ -1429,7 +1429,7 @@ static ssize_t amdgpu_debugfs_gfxoff_read(struct file *f, char __user *buf, - ssize_t result = 0; - int r; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); -@@ -1466,7 +1466,7 @@ static ssize_t amdgpu_debugfs_gfxoff_status_read(struct file *f, char __user *bu - ssize_t result = 0; - int r; - -- if (size & 0x3 || *pos & 0x3) -+ if (size > 4096 || size & 0x3 || *pos & 0x3) - return -EINVAL; - - r = pm_runtime_get_sync(adev_to_drm(adev)->dev); -diff --git a/drivers/gpu/drm/loongson/Kconfig b/drivers/gpu/drm/loongson/Kconfig -index df6946d..a9c1526 100644 ---- a/drivers/gpu/drm/loongson/Kconfig -+++ b/drivers/gpu/drm/loongson/Kconfig -@@ -15,3 +15,5 @@ config DRM_LOONGSON - If "M" is selected, the module will be called loongson. - - If in doubt, say "N". -+ -+source "drivers/gpu/drm/loongson/ast_old/Kconfig" -diff --git a/drivers/gpu/drm/loongson/Makefile b/drivers/gpu/drm/loongson/Makefile -index 91e72bd..a7f05d3 100644 ---- a/drivers/gpu/drm/loongson/Makefile -+++ b/drivers/gpu/drm/loongson/Makefile -@@ -20,3 +20,4 @@ loongson-y += loongson_device.o \ - loongson_module.o - - obj-$(CONFIG_DRM_LOONGSON) += loongson.o -+obj-$(CONFIG_DRM_AST_LOONGSON) += ast_old/ -diff --git a/drivers/gpu/drm/loongson/ast_old/Kconfig b/drivers/gpu/drm/loongson/ast_old/Kconfig -new file mode 100644 -index 0000000..40af693 ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/Kconfig -@@ -0,0 +1,14 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+config DRM_AST_LOONGSON -+ tristate "AST server chips for Loongson Platform" -+ depends on DRM && PCI && MMU && LOONGARCH -+ select DRM_KMS_HELPER -+ select DRM_VRAM_HELPER -+ select DRM_TTM -+ select DRM_TTM_HELPER -+ help -+ Say yes for experimental AST GPU driver. Do not enable -+ this driver without having a working -modesetting, -+ and a version of AST that knows to fail if KMS -+ is bound to the driver. These GPUs are commonly found -+ in server chipsets. -diff --git a/drivers/gpu/drm/loongson/ast_old/Makefile b/drivers/gpu/drm/loongson/ast_old/Makefile -new file mode 100644 -index 0000000..02d40f9 ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/Makefile -@@ -0,0 +1,8 @@ -+# SPDX-License-Identifier: GPL-2.0-only -+# -+# Makefile for the drm device driver. This driver provides support for the -+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -+ -+ast-y := ast_drv.o ast_i2c.o ast_main.o ast_mm.o ast_mode.o ast_post.o ast_dp501.o ast_dp.o -+ -+obj-$(CONFIG_DRM_AST_LOONGSON) := ast.o -diff --git a/drivers/gpu/drm/loongson/ast_old/ast_dp.c b/drivers/gpu/drm/loongson/ast_old/ast_dp.c -new file mode 100644 -index 0000000..b7e1f51 ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/ast_dp.c -@@ -0,0 +1,299 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (c) 2021, ASPEED Technology Inc. -+// Authors: KuoHsiang Chou <kuohsiang_chou@aspeedtech.com> -+ -+#include <linux/firmware.h> -+#include <linux/delay.h> -+#include <drm/drm_print.h> -+#include "ast_drv.h" -+ -+int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ u8 i = 0, j = 0; -+ -+ /* -+ * CRD1[b5]: DP MCU FW is executing -+ * CRDC[b0]: DP link success -+ * CRDF[b0]: DP HPD -+ * CRE5[b0]: Host reading EDID process is done -+ */ -+ if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, -+ ASTDP_MCU_FW_EXECUTING) && -+ ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, -+ ASTDP_LINK_SUCCESS) && -+ ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD) && -+ ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, -+ ASTDP_HOST_EDID_READ_DONE_MASK))) { -+ goto err_astdp_edid_not_ready; -+ } -+ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, -+ (u8)~ASTDP_HOST_EDID_READ_DONE_MASK, 0x00); -+ -+ for (i = 0; i < 32; i++) { -+ /* -+ * CRE4[7:0]: Read-Pointer for EDID (Unit: 4bytes); valid range: 0~64 -+ */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE4, -+ ASTDP_AND_CLEAR_MASK, (u8)i); -+ j = 0; -+ -+ /* -+ * CRD7[b0]: valid flag for EDID -+ * CRD6[b0]: mirror read pointer for EDID -+ */ -+ while ((ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD7, -+ ASTDP_EDID_VALID_FLAG_MASK) != -+ 0x01) || -+ (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD6, -+ ASTDP_EDID_READ_POINTER_MASK) != -+ i)) { -+ /* -+ * Delay are getting longer with each retry. -+ * 1. The Delays are often 2 loops when users request "Display Settings" -+ * of right-click of mouse. -+ * 2. The Delays are often longer a lot when system resume from S3/S4. -+ */ -+ mdelay(j + 1); -+ -+ if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, -+ 0xD1, -+ ASTDP_MCU_FW_EXECUTING) && -+ ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, -+ 0xDC, -+ ASTDP_LINK_SUCCESS) && -+ ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, -+ 0xDF, ASTDP_HPD))) { -+ goto err_astdp_jump_out_loop_of_edid; -+ } -+ -+ j++; -+ if (j > 200) -+ goto err_astdp_jump_out_loop_of_edid; -+ } -+ -+ *(ediddata) = ast_get_index_reg_mask( -+ ast, AST_IO_CRTC_PORT, 0xD8, ASTDP_EDID_READ_DATA_MASK); -+ *(ediddata + 1) = ast_get_index_reg_mask( -+ ast, AST_IO_CRTC_PORT, 0xD9, ASTDP_EDID_READ_DATA_MASK); -+ *(ediddata + 2) = ast_get_index_reg_mask( -+ ast, AST_IO_CRTC_PORT, 0xDA, ASTDP_EDID_READ_DATA_MASK); -+ *(ediddata + 3) = ast_get_index_reg_mask( -+ ast, AST_IO_CRTC_PORT, 0xDB, ASTDP_EDID_READ_DATA_MASK); -+ -+ if (i == 31) { -+ /* -+ * For 128-bytes EDID_1.3, -+ * 1. Add the value of Bytes-126 to Bytes-127. -+ * The Bytes-127 is Checksum. Sum of all 128bytes should -+ * equal 0 (mod 256). -+ * 2. Modify Bytes-126 to be 0. -+ * The Bytes-126 indicates the Number of extensions to -+ * follow. 0 represents noextensions. -+ */ -+ *(ediddata + 3) = *(ediddata + 3) + *(ediddata + 2); -+ *(ediddata + 2) = 0; -+ } -+ -+ ediddata += 4; -+ } -+ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, -+ (u8)~ASTDP_HOST_EDID_READ_DONE_MASK, -+ ASTDP_HOST_EDID_READ_DONE); -+ -+ return 0; -+ -+err_astdp_jump_out_loop_of_edid: -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, -+ (u8)~ASTDP_HOST_EDID_READ_DONE_MASK, -+ ASTDP_HOST_EDID_READ_DONE); -+ return (~(j + 256) + 1); -+ -+err_astdp_edid_not_ready: -+ if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, -+ ASTDP_MCU_FW_EXECUTING))) -+ return (~0xD1 + 1); -+ if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, -+ ASTDP_LINK_SUCCESS))) -+ return (~0xDC + 1); -+ if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD))) -+ return (~0xDF + 1); -+ if (!(ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, -+ ASTDP_HOST_EDID_READ_DONE_MASK))) -+ return (~0xE5 + 1); -+ -+ return 0; -+} -+ -+/* -+ * Launch Aspeed DP -+ */ -+void ast_dp_launch(struct drm_device *dev, u8 bPower) -+{ -+ u32 i = 0, j = 0, WaitCount = 1; -+ u8 bDPTX = 0; -+ u8 bDPExecute = 1; -+ -+ struct ast_private *ast = to_ast_private(dev); -+ // S3 come back, need more time to wait BMC ready. -+ if (bPower) -+ WaitCount = 300; -+ -+ // Wait total count by different condition. -+ for (j = 0; j < WaitCount; j++) { -+ bDPTX = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, -+ TX_TYPE_MASK); -+ -+ if (bDPTX) -+ break; -+ -+ msleep(100); -+ } -+ -+ // 0xE : ASTDP with DPMCU FW handling -+ if (bDPTX == ASTDP_DPMCU_TX) { -+ // Wait one second then timeout. -+ i = 0; -+ -+ while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, -+ COPROCESSOR_LAUNCH) != -+ COPROCESSOR_LAUNCH) { -+ i++; -+ // wait 100 ms -+ msleep(100); -+ -+ if (i >= 10) { -+ // DP would not be ready. -+ bDPExecute = 0; -+ break; -+ } -+ } -+ -+ if (bDPExecute) -+ ast->tx_chip_types |= BIT(AST_TX_ASTDP); -+ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5, -+ (u8)~ASTDP_HOST_EDID_READ_DONE_MASK, -+ ASTDP_HOST_EDID_READ_DONE); -+ } -+} -+ -+void ast_dp_power_on_off(struct drm_device *dev, bool on) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ // Read and Turn off DP PHY sleep -+ u8 bE3 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, -+ AST_DP_VIDEO_ENABLE); -+ -+ // Turn on DP PHY sleep -+ if (!on) -+ bE3 |= AST_DP_PHY_SLEEP; -+ -+ // DP Power on/off -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, -+ (u8)~AST_DP_PHY_SLEEP, bE3); -+} -+ -+void ast_dp_set_on_off(struct drm_device *dev, bool on) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ u8 video_on_off = on; -+ -+ // Video On/Off -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE3, -+ (u8)~AST_DP_VIDEO_ENABLE, on); -+ -+ // If DP plug in and link successful then check video on / off status -+ if (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDC, -+ ASTDP_LINK_SUCCESS) && -+ ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, ASTDP_HPD)) { -+ video_on_off <<= 4; -+ while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xDF, -+ ASTDP_MIRROR_VIDEO_ENABLE) != -+ video_on_off) { -+ // wait 1 ms -+ mdelay(1); -+ } -+ } -+} -+ -+void ast_dp_set_mode(struct drm_crtc *crtc, -+ struct ast_vbios_mode_info *vbios_mode) -+{ -+ struct ast_private *ast = to_ast_private(crtc->dev); -+ -+ u32 ulRefreshRateIndex; -+ u8 ModeIdx; -+ -+ ulRefreshRateIndex = vbios_mode->enh_table->refresh_rate_index - 1; -+ -+ switch (crtc->mode.crtc_hdisplay) { -+ case 320: -+ ModeIdx = ASTDP_320x240_60; -+ break; -+ case 400: -+ ModeIdx = ASTDP_400x300_60; -+ break; -+ case 512: -+ ModeIdx = ASTDP_512x384_60; -+ break; -+ case 640: -+ ModeIdx = (ASTDP_640x480_60 + (u8)ulRefreshRateIndex); -+ break; -+ case 800: -+ ModeIdx = (ASTDP_800x600_56 + (u8)ulRefreshRateIndex); -+ break; -+ case 1024: -+ ModeIdx = (ASTDP_1024x768_60 + (u8)ulRefreshRateIndex); -+ break; -+ case 1152: -+ ModeIdx = ASTDP_1152x864_75; -+ break; -+ case 1280: -+ if (crtc->mode.crtc_vdisplay == 800) -+ ModeIdx = -+ (ASTDP_1280x800_60_RB - (u8)ulRefreshRateIndex); -+ else // 1024 -+ ModeIdx = (ASTDP_1280x1024_60 + (u8)ulRefreshRateIndex); -+ break; -+ case 1360: -+ case 1366: -+ ModeIdx = ASTDP_1366x768_60; -+ break; -+ case 1440: -+ ModeIdx = (ASTDP_1440x900_60_RB - (u8)ulRefreshRateIndex); -+ break; -+ case 1600: -+ if (crtc->mode.crtc_vdisplay == 900) -+ ModeIdx = -+ (ASTDP_1600x900_60_RB - (u8)ulRefreshRateIndex); -+ else //1200 -+ ModeIdx = ASTDP_1600x1200_60; -+ break; -+ case 1680: -+ ModeIdx = (ASTDP_1680x1050_60_RB - (u8)ulRefreshRateIndex); -+ break; -+ case 1920: -+ if (crtc->mode.crtc_vdisplay == 1080) -+ ModeIdx = ASTDP_1920x1080_60; -+ else //1200 -+ ModeIdx = ASTDP_1920x1200_60; -+ break; -+ default: -+ return; -+ } -+ -+ /* -+ * CRE0[7:0]: MISC0 ((0x00: 18-bpp) or (0x20: 24-bpp) -+ * CRE1[7:0]: MISC1 (default: 0x00) -+ * CRE2[7:0]: video format index (0x00 ~ 0x20 or 0x40 ~ 0x50) -+ */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE0, -+ ASTDP_AND_CLEAR_MASK, ASTDP_MISC0_24bpp); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE1, -+ ASTDP_AND_CLEAR_MASK, ASTDP_MISC1); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE2, -+ ASTDP_AND_CLEAR_MASK, ModeIdx); -+} -diff --git a/drivers/gpu/drm/loongson/ast_old/ast_dp501.c b/drivers/gpu/drm/loongson/ast_old/ast_dp501.c -new file mode 100644 -index 0000000..39474bf ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/ast_dp501.c -@@ -0,0 +1,429 @@ -+// SPDX-License-Identifier: GPL-2.0 -+ -+#include <linux/delay.h> -+#include <linux/firmware.h> -+#include <linux/module.h> -+ -+#include "ast_drv.h" -+ -+MODULE_FIRMWARE("ast_dp501_fw.bin"); -+ -+static void ast_release_firmware(void *data) -+{ -+ struct ast_private *ast = data; -+ -+ release_firmware(ast->dp501_fw); -+ ast->dp501_fw = NULL; -+} -+ -+static int ast_load_dp501_microcode(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ int ret; -+ -+ ret = request_firmware(&ast->dp501_fw, "ast_dp501_fw.bin", dev->dev); -+ if (ret) -+ return ret; -+ -+ return devm_add_action_or_reset(dev->dev, ast_release_firmware, ast); -+} -+ -+static void send_ack(struct ast_private *ast) -+{ -+ u8 sendack; -+ -+ sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff); -+ sendack |= 0x80; -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack); -+} -+ -+static void send_nack(struct ast_private *ast) -+{ -+ u8 sendack; -+ -+ sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff); -+ sendack &= ~0x80; -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack); -+} -+ -+static bool wait_ack(struct ast_private *ast) -+{ -+ u8 waitack; -+ u32 retry = 0; -+ -+ do { -+ waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, -+ 0xff); -+ waitack &= 0x80; -+ udelay(100); -+ } while ((!waitack) && (retry++ < 1000)); -+ -+ if (retry < 1000) -+ return true; -+ else -+ return false; -+} -+ -+static bool wait_nack(struct ast_private *ast) -+{ -+ u8 waitack; -+ u32 retry = 0; -+ -+ do { -+ waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, -+ 0xff); -+ waitack &= 0x80; -+ udelay(100); -+ } while ((waitack) && (retry++ < 1000)); -+ -+ if (retry < 1000) -+ return true; -+ else -+ return false; -+} -+ -+static void set_cmd_trigger(struct ast_private *ast) -+{ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x40); -+} -+ -+static void clear_cmd_trigger(struct ast_private *ast) -+{ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x00); -+} -+ -+static bool ast_write_cmd(struct drm_device *dev, u8 data) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ int retry = 0; -+ -+ if (wait_nack(ast)) { -+ send_nack(ast); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data); -+ send_ack(ast); -+ set_cmd_trigger(ast); -+ do { -+ if (wait_ack(ast)) { -+ clear_cmd_trigger(ast); -+ send_nack(ast); -+ return true; -+ } -+ } while (retry++ < 100); -+ } -+ clear_cmd_trigger(ast); -+ send_nack(ast); -+ return false; -+} -+ -+static bool ast_write_data(struct drm_device *dev, u8 data) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ -+ if (wait_nack(ast)) { -+ send_nack(ast); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data); -+ send_ack(ast); -+ if (wait_ack(ast)) { -+ send_nack(ast); -+ return true; -+ } -+ } -+ send_nack(ast); -+ return false; -+} -+ -+void ast_set_dp501_video_output(struct drm_device *dev, u8 mode) -+{ -+ ast_write_cmd(dev, 0x40); -+ ast_write_data(dev, mode); -+ -+ /* -+ * msleep < 20ms can sleep for up to 20ms; -+ * see Documentation/timers/timers-howto.rst -+ */ -+ msleep(20); -+} -+ -+static u32 get_fw_base(struct ast_private *ast) -+{ -+ return ast_mindwm(ast, 0x1e6e2104) & 0x7fffffff; -+} -+ -+bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ u32 i, data; -+ u32 boot_address; -+ -+ if (ast->config_mode != ast_use_p2a) -+ return false; -+ -+ data = ast_mindwm(ast, 0x1e6e2100) & 0x01; -+ if (data) { -+ boot_address = get_fw_base(ast); -+ for (i = 0; i < size; i += 4) -+ *(u32 *)(addr + i) = ast_mindwm(ast, boot_address + i); -+ return true; -+ } -+ return false; -+} -+ -+static bool ast_launch_m68k(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ u32 i, data, len = 0; -+ u32 boot_address; -+ u8 *fw_addr = NULL; -+ u8 jreg; -+ -+ if (ast->config_mode != ast_use_p2a) -+ return false; -+ -+ data = ast_mindwm(ast, 0x1e6e2100) & 0x01; -+ if (!data) { -+ if (ast->dp501_fw_addr) { -+ fw_addr = ast->dp501_fw_addr; -+ len = 32 * 1024; -+ } else { -+ if (!ast->dp501_fw && ast_load_dp501_microcode(dev) < 0) -+ return false; -+ -+ fw_addr = (u8 *)ast->dp501_fw->data; -+ len = ast->dp501_fw->size; -+ } -+ /* Get BootAddress */ -+ ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8); -+ data = ast_mindwm(ast, 0x1e6e0004); -+ switch (data & 0x03) { -+ case 0: -+ boot_address = 0x44000000; -+ break; -+ default: -+ case 1: -+ boot_address = 0x48000000; -+ break; -+ case 2: -+ boot_address = 0x50000000; -+ break; -+ case 3: -+ boot_address = 0x60000000; -+ break; -+ } -+ boot_address -= 0x200000; /* -2MB */ -+ -+ /* copy image to buffer */ -+ for (i = 0; i < len; i += 4) { -+ data = *(u32 *)(fw_addr + i); -+ ast_moutdwm(ast, boot_address + i, data); -+ } -+ -+ /* Init SCU */ -+ ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8); -+ -+ /* Launch FW */ -+ ast_moutdwm(ast, 0x1e6e2104, 0x80000000 + boot_address); -+ ast_moutdwm(ast, 0x1e6e2100, 1); -+ -+ /* Update Scratch */ -+ data = ast_mindwm(ast, 0x1e6e2040) & -+ 0xfffff1ff; /* D[11:9] = 100b: UEFI handling */ -+ data |= 0x800; -+ ast_moutdwm(ast, 0x1e6e2040, data); -+ -+ jreg = ast_get_index_reg_mask( -+ ast, AST_IO_CRTC_PORT, 0x99, -+ 0xfc); /* D[1:0]: Reserved Video Buffer */ -+ jreg |= 0x02; -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x99, jreg); -+ } -+ return true; -+} -+ -+bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ u32 i, boot_address, offset, data; -+ u32 *pEDIDidx; -+ -+ if (ast->config_mode == ast_use_p2a) { -+ boot_address = get_fw_base(ast); -+ -+ /* validate FW version */ -+ offset = AST_DP501_GBL_VERSION; -+ data = ast_mindwm(ast, boot_address + offset); -+ if ((data & AST_DP501_FW_VERSION_MASK) != -+ AST_DP501_FW_VERSION_1) -+ return false; -+ -+ /* validate PnP Monitor */ -+ offset = AST_DP501_PNPMONITOR; -+ data = ast_mindwm(ast, boot_address + offset); -+ if (!(data & AST_DP501_PNP_CONNECTED)) -+ return false; -+ -+ /* Read EDID */ -+ offset = AST_DP501_EDID_DATA; -+ for (i = 0; i < 128; i += 4) { -+ data = ast_mindwm(ast, boot_address + offset + i); -+ pEDIDidx = (u32 *)(ediddata + i); -+ *pEDIDidx = data; -+ } -+ } else { -+ if (!ast->dp501_fw_buf) -+ return false; -+ -+ /* dummy read */ -+ offset = 0x0000; -+ data = readl(ast->dp501_fw_buf + offset); -+ -+ /* validate FW version */ -+ offset = AST_DP501_GBL_VERSION; -+ data = readl(ast->dp501_fw_buf + offset); -+ if ((data & AST_DP501_FW_VERSION_MASK) != -+ AST_DP501_FW_VERSION_1) -+ return false; -+ -+ /* validate PnP Monitor */ -+ offset = AST_DP501_PNPMONITOR; -+ data = readl(ast->dp501_fw_buf + offset); -+ if (!(data & AST_DP501_PNP_CONNECTED)) -+ return false; -+ -+ /* Read EDID */ -+ offset = AST_DP501_EDID_DATA; -+ for (i = 0; i < 128; i += 4) { -+ data = readl(ast->dp501_fw_buf + offset + i); -+ pEDIDidx = (u32 *)(ediddata + i); -+ *pEDIDidx = data; -+ } -+ } -+ -+ return true; -+} -+ -+static bool ast_init_dvo(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ u8 jreg; -+ u32 data; -+ -+ ast_write32(ast, 0xf004, 0x1e6e0000); -+ ast_write32(ast, 0xf000, 0x1); -+ ast_write32(ast, 0x12000, 0x1688a8a8); -+ -+ jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); -+ if (!(jreg & 0x80)) { -+ /* Init SCU DVO Settings */ -+ data = ast_read32(ast, 0x12008); -+ /* delay phase */ -+ data &= 0xfffff8ff; -+ data |= 0x00000500; -+ ast_write32(ast, 0x12008, data); -+ -+ if (ast->chip == AST2300) { -+ data = ast_read32(ast, 0x12084); -+ /* multi-pins for DVO single-edge */ -+ data |= 0xfffe0000; -+ ast_write32(ast, 0x12084, data); -+ -+ data = ast_read32(ast, 0x12088); -+ /* multi-pins for DVO single-edge */ -+ data |= 0x000fffff; -+ ast_write32(ast, 0x12088, data); -+ -+ data = ast_read32(ast, 0x12090); -+ /* multi-pins for DVO single-edge */ -+ data &= 0xffffffcf; -+ data |= 0x00000020; -+ ast_write32(ast, 0x12090, data); -+ } else { /* AST2400 */ -+ data = ast_read32(ast, 0x12088); -+ /* multi-pins for DVO single-edge */ -+ data |= 0x30000000; -+ ast_write32(ast, 0x12088, data); -+ -+ data = ast_read32(ast, 0x1208c); -+ /* multi-pins for DVO single-edge */ -+ data |= 0x000000cf; -+ ast_write32(ast, 0x1208c, data); -+ -+ data = ast_read32(ast, 0x120a4); -+ /* multi-pins for DVO single-edge */ -+ data |= 0xffff0000; -+ ast_write32(ast, 0x120a4, data); -+ -+ data = ast_read32(ast, 0x120a8); -+ /* multi-pins for DVO single-edge */ -+ data |= 0x0000000f; -+ ast_write32(ast, 0x120a8, data); -+ -+ data = ast_read32(ast, 0x12094); -+ /* multi-pins for DVO single-edge */ -+ data |= 0x00000002; -+ ast_write32(ast, 0x12094, data); -+ } -+ } -+ -+ /* Force to DVO */ -+ data = ast_read32(ast, 0x1202c); -+ data &= 0xfffbffff; -+ ast_write32(ast, 0x1202c, data); -+ -+ /* Init VGA DVO Settings */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80); -+ return true; -+} -+ -+static void ast_init_analog(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ u32 data; -+ -+ /* -+ * Set DAC source to VGA mode in SCU2C via the P2A -+ * bridge. First configure the P2U to target the SCU -+ * in case it isn't at this stage. -+ */ -+ ast_write32(ast, 0xf004, 0x1e6e0000); -+ ast_write32(ast, 0xf000, 0x1); -+ -+ /* Then unlock the SCU with the magic password */ -+ ast_write32(ast, 0x12000, 0x1688a8a8); -+ ast_write32(ast, 0x12000, 0x1688a8a8); -+ ast_write32(ast, 0x12000, 0x1688a8a8); -+ -+ /* Finally, clear bits [17:16] of SCU2c */ -+ data = ast_read32(ast, 0x1202c); -+ data &= 0xfffcffff; -+ ast_write32(ast, 0, data); -+ -+ /* Disable DVO */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x00); -+} -+ -+void ast_init_3rdtx(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ u8 jreg; -+ -+ if (ast->chip == AST2300 || ast->chip == AST2400) { -+ jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, -+ 0xff); -+ switch (jreg & 0x0e) { -+ case 0x04: -+ ast_init_dvo(dev); -+ break; -+ case 0x08: -+ ast_launch_m68k(dev); -+ break; -+ case 0x0c: -+ ast_init_dvo(dev); -+ break; -+ default: -+ if (ast->tx_chip_types & BIT(AST_TX_SIL164)) -+ ast_init_dvo(dev); -+ else -+ ast_init_analog(dev); -+ } -+ } -+} -diff --git a/drivers/gpu/drm/loongson/ast_old/ast_dram_tables.h b/drivers/gpu/drm/loongson/ast_old/ast_dram_tables.h -new file mode 100644 -index 0000000..114b1de ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/ast_dram_tables.h -@@ -0,0 +1,125 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef AST_DRAM_TABLES_H -+#define AST_DRAM_TABLES_H -+ -+/* DRAM timing tables */ -+struct ast_dramstruct { -+ u16 index; -+ u32 data; -+}; -+ -+static const struct ast_dramstruct ast2000_dram_table_data[] = { -+ { 0x0108, 0x00000000 }, { 0x0120, 0x00004a21 }, { 0xFF00, 0x00000043 }, -+ { 0x0000, 0xFFFFFFFF }, { 0x0004, 0x00000089 }, { 0x0008, 0x22331353 }, -+ { 0x000C, 0x0d07000b }, { 0x0010, 0x11113333 }, { 0x0020, 0x00110350 }, -+ { 0x0028, 0x1e0828f0 }, { 0x0024, 0x00000001 }, { 0x001C, 0x00000000 }, -+ { 0x0014, 0x00000003 }, { 0xFF00, 0x00000043 }, { 0x0018, 0x00000131 }, -+ { 0x0014, 0x00000001 }, { 0xFF00, 0x00000043 }, { 0x0018, 0x00000031 }, -+ { 0x0014, 0x00000001 }, { 0xFF00, 0x00000043 }, { 0x0028, 0x1e0828f1 }, -+ { 0x0024, 0x00000003 }, { 0x002C, 0x1f0f28fb }, { 0x0030, 0xFFFFFE01 }, -+ { 0xFFFF, 0xFFFFFFFF } -+}; -+ -+static const struct ast_dramstruct ast1100_dram_table_data[] = { -+ { 0x2000, 0x1688a8a8 }, { 0x2020, 0x000041f0 }, { 0xFF00, 0x00000043 }, -+ { 0x0000, 0xfc600309 }, { 0x006C, 0x00909090 }, { 0x0064, 0x00050000 }, -+ { 0x0004, 0x00000585 }, { 0x0008, 0x0011030f }, { 0x0010, 0x22201724 }, -+ { 0x0018, 0x1e29011a }, { 0x0020, 0x00c82222 }, { 0x0014, 0x01001523 }, -+ { 0x001C, 0x1024010d }, { 0x0024, 0x00cb2522 }, { 0x0038, 0xffffff82 }, -+ { 0x003C, 0x00000000 }, { 0x0040, 0x00000000 }, { 0x0044, 0x00000000 }, -+ { 0x0048, 0x00000000 }, { 0x004C, 0x00000000 }, { 0x0050, 0x00000000 }, -+ { 0x0054, 0x00000000 }, { 0x0058, 0x00000000 }, { 0x005C, 0x00000000 }, -+ { 0x0060, 0x032aa02a }, { 0x0064, 0x002d3000 }, { 0x0068, 0x00000000 }, -+ { 0x0070, 0x00000000 }, { 0x0074, 0x00000000 }, { 0x0078, 0x00000000 }, -+ { 0x007C, 0x00000000 }, { 0x0034, 0x00000001 }, { 0xFF00, 0x00000043 }, -+ { 0x002C, 0x00000732 }, { 0x0030, 0x00000040 }, { 0x0028, 0x00000005 }, -+ { 0x0028, 0x00000007 }, { 0x0028, 0x00000003 }, { 0x0028, 0x00000001 }, -+ { 0x000C, 0x00005a08 }, { 0x002C, 0x00000632 }, { 0x0028, 0x00000001 }, -+ { 0x0030, 0x000003c0 }, { 0x0028, 0x00000003 }, { 0x0030, 0x00000040 }, -+ { 0x0028, 0x00000003 }, { 0x000C, 0x00005a21 }, { 0x0034, 0x00007c03 }, -+ { 0x0120, 0x00004c41 }, { 0xffff, 0xffffffff }, -+}; -+ -+static const struct ast_dramstruct ast2100_dram_table_data[] = { -+ { 0x2000, 0x1688a8a8 }, { 0x2020, 0x00004120 }, { 0xFF00, 0x00000043 }, -+ { 0x0000, 0xfc600309 }, { 0x006C, 0x00909090 }, { 0x0064, 0x00070000 }, -+ { 0x0004, 0x00000489 }, { 0x0008, 0x0011030f }, { 0x0010, 0x32302926 }, -+ { 0x0018, 0x274c0122 }, { 0x0020, 0x00ce2222 }, { 0x0014, 0x01001523 }, -+ { 0x001C, 0x1024010d }, { 0x0024, 0x00cb2522 }, { 0x0038, 0xffffff82 }, -+ { 0x003C, 0x00000000 }, { 0x0040, 0x00000000 }, { 0x0044, 0x00000000 }, -+ { 0x0048, 0x00000000 }, { 0x004C, 0x00000000 }, { 0x0050, 0x00000000 }, -+ { 0x0054, 0x00000000 }, { 0x0058, 0x00000000 }, { 0x005C, 0x00000000 }, -+ { 0x0060, 0x0f2aa02a }, { 0x0064, 0x003f3005 }, { 0x0068, 0x02020202 }, -+ { 0x0070, 0x00000000 }, { 0x0074, 0x00000000 }, { 0x0078, 0x00000000 }, -+ { 0x007C, 0x00000000 }, { 0x0034, 0x00000001 }, { 0xFF00, 0x00000043 }, -+ { 0x002C, 0x00000942 }, { 0x0030, 0x00000040 }, { 0x0028, 0x00000005 }, -+ { 0x0028, 0x00000007 }, { 0x0028, 0x00000003 }, { 0x0028, 0x00000001 }, -+ { 0x000C, 0x00005a08 }, { 0x002C, 0x00000842 }, { 0x0028, 0x00000001 }, -+ { 0x0030, 0x000003c0 }, { 0x0028, 0x00000003 }, { 0x0030, 0x00000040 }, -+ { 0x0028, 0x00000003 }, { 0x000C, 0x00005a21 }, { 0x0034, 0x00007c03 }, -+ { 0x0120, 0x00005061 }, { 0xffff, 0xffffffff }, -+}; -+ -+/* -+ * AST2500 DRAM settings modules -+ */ -+#define REGTBL_NUM 17 -+#define REGIDX_010 0 -+#define REGIDX_014 1 -+#define REGIDX_018 2 -+#define REGIDX_020 3 -+#define REGIDX_024 4 -+#define REGIDX_02C 5 -+#define REGIDX_030 6 -+#define REGIDX_214 7 -+#define REGIDX_2E0 8 -+#define REGIDX_2E4 9 -+#define REGIDX_2E8 10 -+#define REGIDX_2EC 11 -+#define REGIDX_2F0 12 -+#define REGIDX_2F4 13 -+#define REGIDX_2F8 14 -+#define REGIDX_RFC 15 -+#define REGIDX_PLL 16 -+ -+static const u32 ast2500_ddr3_1600_timing_table[REGTBL_NUM] = { -+ 0x64604D38, /* 0x010 */ -+ 0x29690599, /* 0x014 */ -+ 0x00000300, /* 0x018 */ -+ 0x00000000, /* 0x020 */ -+ 0x00000000, /* 0x024 */ -+ 0x02181E70, /* 0x02C */ -+ 0x00000040, /* 0x030 */ -+ 0x00000024, /* 0x214 */ -+ 0x02001300, /* 0x2E0 */ -+ 0x0E0000A0, /* 0x2E4 */ -+ 0x000E001B, /* 0x2E8 */ -+ 0x35B8C105, /* 0x2EC */ -+ 0x08090408, /* 0x2F0 */ -+ 0x9B000800, /* 0x2F4 */ -+ 0x0E400A00, /* 0x2F8 */ -+ 0x9971452F, /* tRFC */ -+ 0x000071C1 /* PLL */ -+}; -+ -+static const u32 ast2500_ddr4_1600_timing_table[REGTBL_NUM] = { -+ 0x63604E37, /* 0x010 */ -+ 0xE97AFA99, /* 0x014 */ -+ 0x00019000, /* 0x018 */ -+ 0x08000000, /* 0x020 */ -+ 0x00000400, /* 0x024 */ -+ 0x00000410, /* 0x02C */ -+ 0x00000101, /* 0x030 */ -+ 0x00000024, /* 0x214 */ -+ 0x03002900, /* 0x2E0 */ -+ 0x0E0000A0, /* 0x2E4 */ -+ 0x000E001C, /* 0x2E8 */ -+ 0x35B8C106, /* 0x2EC */ -+ 0x08080607, /* 0x2F0 */ -+ 0x9B000900, /* 0x2F4 */ -+ 0x0E400A00, /* 0x2F8 */ -+ 0x99714545, /* tRFC */ -+ 0x000071C1 /* PLL */ -+}; -+ -+#endif -diff --git a/drivers/gpu/drm/loongson/ast_old/ast_drv.c b/drivers/gpu/drm/loongson/ast_old/ast_drv.c -new file mode 100644 -index 0000000..2e069fe ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/ast_drv.c -@@ -0,0 +1,231 @@ -+/* -+ * Copyright 2012 Red Hat Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sub license, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, -+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -+ * USE OR OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * The above copyright notice and this permission notice (including the -+ * next paragraph) shall be included in all copies or substantial portions -+ * of the Software. -+ * -+ */ -+/* -+ * Authors: Dave Airlie <airlied@redhat.com> -+ */ -+ -+#include <linux/module.h> -+#include <linux/pci.h> -+ -+#include <drm/drm_aperture.h> -+#include <drm/drm_atomic_helper.h> -+#include <drm/drm_crtc_helper.h> -+#include <drm/drm_drv.h> -+#include <drm/drm_gem_vram_helper.h> -+#include <drm/drm_module.h> -+#include <drm/drm_probe_helper.h> -+#include <drm/drm_fbdev_generic.h> -+#include "ast_drv.h" -+ -+static int ast_modeset = -1; -+ -+MODULE_PARM_DESC(modeset, "Disable/Enable modesetting"); -+module_param_named(modeset, ast_modeset, int, 0400); -+ -+/* -+ * DRM driver -+ */ -+ -+DEFINE_DRM_GEM_FOPS(ast_fops); -+ -+static const struct drm_driver ast_driver = { .driver_features = DRIVER_ATOMIC | -+ DRIVER_GEM | -+ DRIVER_MODESET, -+ -+ .fops = &ast_fops, -+ .name = DRIVER_NAME, -+ .desc = DRIVER_DESC, -+ .date = DRIVER_DATE, -+ .major = DRIVER_MAJOR, -+ .minor = DRIVER_MINOR, -+ .patchlevel = DRIVER_PATCHLEVEL, -+ -+ DRM_GEM_VRAM_DRIVER }; -+ -+/* -+ * PCI driver -+ */ -+ -+#define PCI_VENDOR_ASPEED 0x1a03 -+ -+#define AST_VGA_DEVICE(id, info) \ -+ { .class = PCI_BASE_CLASS_DISPLAY << 16, \ -+ .class_mask = 0xff0000, \ -+ .vendor = PCI_VENDOR_ASPEED, \ -+ .device = id, \ -+ .subvendor = PCI_ANY_ID, \ -+ .subdevice = PCI_ANY_ID, \ -+ .driver_data = (unsigned long)info } -+ -+static const struct pci_device_id ast_pciidlist[] = { -+ AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL), -+ AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL), -+ { 0, 0, 0 }, -+}; -+ -+MODULE_DEVICE_TABLE(pci, ast_pciidlist); -+ -+static int ast_remove_conflicting_framebuffers(struct pci_dev *pdev) -+{ -+ resource_size_t base, size; -+ -+ base = pci_resource_start(pdev, 0); -+ size = pci_resource_len(pdev, 0); -+ -+ return drm_aperture_remove_conflicting_framebuffers(base, size, -+ &ast_driver); -+} -+ -+static int ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -+{ -+ struct ast_private *ast; -+ struct drm_device *dev; -+ int ret; -+ -+ ret = ast_remove_conflicting_framebuffers(pdev); -+ if (ret) -+ return ret; -+ -+ ret = pcim_enable_device(pdev); -+ if (ret) -+ return ret; -+ -+ ast = ast_device_create(&ast_driver, pdev, ent->driver_data); -+ if (IS_ERR(ast)) -+ return PTR_ERR(ast); -+ dev = &ast->base; -+ -+ ret = drm_dev_register(dev, ent->driver_data); -+ if (ret) -+ return ret; -+ -+ drm_fbdev_generic_setup(dev, 32); -+ -+ return 0; -+} -+ -+static void ast_pci_remove(struct pci_dev *pdev) -+{ -+ struct drm_device *dev = pci_get_drvdata(pdev); -+ -+ drm_dev_unregister(dev); -+ drm_atomic_helper_shutdown(dev); -+} -+ -+static int ast_drm_freeze(struct drm_device *dev) -+{ -+ int error; -+ -+ error = drm_mode_config_helper_suspend(dev); -+ if (error) -+ return error; -+ pci_save_state(to_pci_dev(dev->dev)); -+ return 0; -+} -+ -+static int ast_drm_thaw(struct drm_device *dev) -+{ -+ ast_post_gpu(dev); -+ -+ return drm_mode_config_helper_resume(dev); -+} -+ -+static int ast_drm_resume(struct drm_device *dev) -+{ -+ if (pci_enable_device(to_pci_dev(dev->dev))) -+ return -EIO; -+ -+ return ast_drm_thaw(dev); -+} -+ -+static int ast_pm_suspend(struct device *dev) -+{ -+ struct pci_dev *pdev = to_pci_dev(dev); -+ struct drm_device *ddev = pci_get_drvdata(pdev); -+ int error; -+ -+ error = ast_drm_freeze(ddev); -+ if (error) -+ return error; -+ -+ pci_disable_device(pdev); -+ pci_set_power_state(pdev, PCI_D3hot); -+ return 0; -+} -+ -+static int ast_pm_resume(struct device *dev) -+{ -+ struct pci_dev *pdev = to_pci_dev(dev); -+ struct drm_device *ddev = pci_get_drvdata(pdev); -+ -+ return ast_drm_resume(ddev); -+} -+ -+static int ast_pm_freeze(struct device *dev) -+{ -+ struct pci_dev *pdev = to_pci_dev(dev); -+ struct drm_device *ddev = pci_get_drvdata(pdev); -+ -+ return ast_drm_freeze(ddev); -+} -+ -+static int ast_pm_thaw(struct device *dev) -+{ -+ struct pci_dev *pdev = to_pci_dev(dev); -+ struct drm_device *ddev = pci_get_drvdata(pdev); -+ -+ return ast_drm_thaw(ddev); -+} -+ -+static int ast_pm_poweroff(struct device *dev) -+{ -+ struct pci_dev *pdev = to_pci_dev(dev); -+ struct drm_device *ddev = pci_get_drvdata(pdev); -+ -+ return ast_drm_freeze(ddev); -+} -+ -+static const struct dev_pm_ops ast_pm_ops = { -+ .suspend = ast_pm_suspend, -+ .resume = ast_pm_resume, -+ .freeze = ast_pm_freeze, -+ .thaw = ast_pm_thaw, -+ .poweroff = ast_pm_poweroff, -+ .restore = ast_pm_resume, -+}; -+ -+static struct pci_driver ast_pci_driver = { -+ .name = DRIVER_NAME, -+ .id_table = ast_pciidlist, -+ .probe = ast_pci_probe, -+ .remove = ast_pci_remove, -+ .driver.pm = &ast_pm_ops, -+}; -+ -+drm_module_pci_driver_if_modeset(ast_pci_driver, ast_modeset); -+ -+MODULE_AUTHOR(DRIVER_AUTHOR); -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_LICENSE("GPL and additional rights"); -diff --git a/drivers/gpu/drm/loongson/ast_old/ast_drv.h b/drivers/gpu/drm/loongson/ast_old/ast_drv.h -new file mode 100644 -index 0000000..29a2965 ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/ast_drv.h -@@ -0,0 +1,528 @@ -+/* -+ * Copyright 2012 Red Hat Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sub license, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, -+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -+ * USE OR OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * The above copyright notice and this permission notice (including the -+ * next paragraph) shall be included in all copies or substantial portions -+ * of the Software. -+ * -+ */ -+/* -+ * Authors: Dave Airlie <airlied@redhat.com> -+ */ -+#ifndef __AST_DRV_H__ -+#define __AST_DRV_H__ -+ -+#include <linux/i2c.h> -+#include <linux/i2c-algo-bit.h> -+#include <linux/io.h> -+#include <linux/types.h> -+ -+#include <drm/drm_connector.h> -+#include <drm/drm_crtc.h> -+#include <drm/drm_encoder.h> -+#include <drm/drm_mode.h> -+#include <drm/drm_framebuffer.h> -+#include <drm/drm_fb_helper.h> -+ -+#define DRIVER_AUTHOR "Dave Airlie" -+ -+#define DRIVER_NAME "ast" -+#define DRIVER_DESC "AST" -+#define DRIVER_DATE "20120228" -+ -+#define DRIVER_MAJOR 0 -+#define DRIVER_MINOR 1 -+#define DRIVER_PATCHLEVEL 0 -+ -+#define PCI_CHIP_AST2000 0x2000 -+#define PCI_CHIP_AST2100 0x2010 -+ -+enum ast_chip { -+ AST2000, -+ AST2100, -+ AST1100, -+ AST2200, -+ AST2150, -+ AST2300, -+ AST2400, -+ AST2500, -+ AST2600, -+}; -+ -+enum ast_tx_chip { -+ AST_TX_NONE, -+ AST_TX_SIL164, -+ AST_TX_DP501, -+ AST_TX_ASTDP, -+}; -+ -+#define AST_TX_NONE_BIT BIT(AST_TX_NONE) -+#define AST_TX_SIL164_BIT BIT(AST_TX_SIL164) -+#define AST_TX_DP501_BIT BIT(AST_TX_DP501) -+#define AST_TX_ASTDP_BIT BIT(AST_TX_ASTDP) -+ -+#define AST_DRAM_512Mx16 0 -+#define AST_DRAM_1Gx16 1 -+#define AST_DRAM_512Mx32 2 -+#define AST_DRAM_1Gx32 3 -+#define AST_DRAM_2Gx16 6 -+#define AST_DRAM_4Gx16 7 -+#define AST_DRAM_8Gx16 8 -+ -+/* -+ * Hardware cursor -+ */ -+ -+#define AST_MAX_HWC_WIDTH 64 -+#define AST_MAX_HWC_HEIGHT 64 -+ -+#define AST_HWC_SIZE (AST_MAX_HWC_WIDTH * AST_MAX_HWC_HEIGHT * 2) -+#define AST_HWC_SIGNATURE_SIZE 32 -+ -+/* define for signature structure */ -+#define AST_HWC_SIGNATURE_CHECKSUM 0x00 -+#define AST_HWC_SIGNATURE_SizeX 0x04 -+#define AST_HWC_SIGNATURE_SizeY 0x08 -+#define AST_HWC_SIGNATURE_X 0x0C -+#define AST_HWC_SIGNATURE_Y 0x10 -+#define AST_HWC_SIGNATURE_HOTSPOTX 0x14 -+#define AST_HWC_SIGNATURE_HOTSPOTY 0x18 -+ -+/* -+ * Planes -+ */ -+ -+struct ast_plane { -+ struct drm_plane base; -+ -+ struct drm_gem_vram_object *gbo; -+ struct iosys_map map; -+ u64 off; -+}; -+ -+static inline struct ast_plane *to_ast_plane(struct drm_plane *plane) -+{ -+ return container_of(plane, struct ast_plane, base); -+} -+ -+/* -+ * Connector with i2c channel -+ */ -+ -+struct ast_i2c_chan { -+ struct i2c_adapter adapter; -+ struct drm_device *dev; -+ struct i2c_algo_bit_data bit; -+}; -+ -+struct ast_vga_connector { -+ struct drm_connector base; -+ struct ast_i2c_chan *i2c; -+}; -+ -+static inline struct ast_vga_connector * -+to_ast_vga_connector(struct drm_connector *connector) -+{ -+ return container_of(connector, struct ast_vga_connector, base); -+} -+ -+struct ast_sil164_connector { -+ struct drm_connector base; -+ struct ast_i2c_chan *i2c; -+}; -+ -+static inline struct ast_sil164_connector * -+to_ast_sil164_connector(struct drm_connector *connector) -+{ -+ return container_of(connector, struct ast_sil164_connector, base); -+} -+ -+/* -+ * Device -+ */ -+ -+struct ast_private { -+ struct drm_device base; -+ -+ struct mutex ioregs_lock; /* Protects access to I/O registers in ioregs */ -+ void __iomem *regs; -+ void __iomem *ioregs; -+ void __iomem *dp501_fw_buf; -+ -+ enum ast_chip chip; -+ bool vga2_clone; -+ uint32_t dram_bus_width; -+ uint32_t dram_type; -+ uint32_t mclk; -+ -+ struct drm_plane primary_plane; -+ struct ast_plane cursor_plane; -+ struct drm_crtc crtc; -+ struct { -+ struct { -+ struct drm_encoder encoder; -+ struct ast_vga_connector vga_connector; -+ } vga; -+ struct { -+ struct drm_encoder encoder; -+ struct ast_sil164_connector sil164_connector; -+ } sil164; -+ struct { -+ struct drm_encoder encoder; -+ struct drm_connector connector; -+ } dp501; -+ struct { -+ struct drm_encoder encoder; -+ struct drm_connector connector; -+ } astdp; -+ } output; -+ -+ bool support_wide_screen; -+ enum { ast_use_p2a, ast_use_dt, ast_use_defaults } config_mode; -+ -+ unsigned long tx_chip_types; /* bitfield of enum ast_chip_type */ -+ u8 *dp501_fw_addr; -+ const struct firmware *dp501_fw; /* dp501 fw */ -+}; -+ -+static inline struct ast_private *to_ast_private(struct drm_device *dev) -+{ -+ return container_of(dev, struct ast_private, base); -+} -+ -+struct ast_private *ast_device_create(const struct drm_driver *drv, -+ struct pci_dev *pdev, -+ unsigned long flags); -+ -+#define AST_IO_AR_PORT_WRITE (0x40) -+#define AST_IO_MISC_PORT_WRITE (0x42) -+#define AST_IO_VGA_ENABLE_PORT (0x43) -+#define AST_IO_SEQ_PORT (0x44) -+#define AST_IO_DAC_INDEX_READ (0x47) -+#define AST_IO_DAC_INDEX_WRITE (0x48) -+#define AST_IO_DAC_DATA (0x49) -+#define AST_IO_GR_PORT (0x4E) -+#define AST_IO_CRTC_PORT (0x54) -+#define AST_IO_INPUT_STATUS1_READ (0x5A) -+#define AST_IO_MISC_PORT_READ (0x4C) -+ -+#define AST_IO_MM_OFFSET (0x380) -+ -+#define AST_IO_VGAIR1_VREFRESH BIT(3) -+ -+#define AST_IO_VGACRCB_HWC_ENABLED BIT(1) -+#define AST_IO_VGACRCB_HWC_16BPP \ -+ BIT(0) /* set: ARGB4444, cleared: 2bpp palette */ -+ -+static inline u8 ast_read8(struct ast_private *ast, u32 reg) -+{ -+ u8 val = 0; -+ -+ val = ioread8(ast->regs + reg); -+ return val; -+} -+ -+static inline u16 ast_read16(struct ast_private *ast, u32 reg) -+{ -+ u16 val = 0; -+ -+ val = ioread16(ast->regs + reg); -+ return val; -+} -+ -+static inline u32 ast_read32(struct ast_private *ast, u32 reg) -+{ -+ u32 val = 0; -+ -+ val = ioread32(ast->regs + reg); -+ return val; -+} -+ -+static inline u8 ast_io_read8(struct ast_private *ast, u32 reg) -+{ -+ u8 val = 0; -+ -+ val = ioread8(ast->ioregs + reg); -+ return val; -+} -+ -+static inline u16 ast_io_read16(struct ast_private *ast, u32 reg) -+{ -+ u16 val = 0; -+ -+ val = ioread16(ast->ioregs + reg); -+ return val; -+} -+ -+static inline u32 ast_io_read32(struct ast_private *ast, u32 reg) -+{ -+ u32 val = 0; -+ -+ val = ioread32(ast->ioregs + reg); -+ return val; -+} -+ -+#define __ast_write(x) \ -+ static inline void ast_write##x(struct ast_private *ast, u32 reg, \ -+ u##x val) \ -+ { \ -+ iowrite##x(val, ast->regs + reg); \ -+ } -+ -+__ast_write(8); -+__ast_write(16); -+__ast_write(32); -+ -+#define __ast_io_write(x) \ -+ static inline void ast_io_write##x(struct ast_private *ast, u32 reg, \ -+ u##x val) \ -+ { \ -+ iowrite##x(val, ast->ioregs + reg); \ -+ } -+ -+__ast_io_write(8); -+__ast_io_write(16); -+#undef __ast_io_write -+ -+static inline void ast_set_index_reg(struct ast_private *ast, uint32_t base, -+ uint8_t index, uint8_t val) -+{ -+ ast_io_write16(ast, base, ((u16)val << 8) | index); -+} -+ -+void ast_set_index_reg_mask(struct ast_private *ast, uint32_t base, -+ uint8_t index, uint8_t mask, uint8_t val); -+uint8_t ast_get_index_reg(struct ast_private *ast, uint32_t base, -+ uint8_t index); -+uint8_t ast_get_index_reg_mask(struct ast_private *ast, uint32_t base, -+ uint8_t index, uint8_t mask); -+ -+static inline void ast_open_key(struct ast_private *ast) -+{ -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x80, 0xA8); -+} -+ -+#define AST_VIDMEM_SIZE_8M 0x00800000 -+#define AST_VIDMEM_SIZE_16M 0x01000000 -+#define AST_VIDMEM_SIZE_32M 0x02000000 -+#define AST_VIDMEM_SIZE_64M 0x04000000 -+#define AST_VIDMEM_SIZE_128M 0x08000000 -+ -+#define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M -+ -+struct ast_vbios_stdtable { -+ u8 misc; -+ u8 seq[4]; -+ u8 crtc[25]; -+ u8 ar[20]; -+ u8 gr[9]; -+}; -+ -+struct ast_vbios_enhtable { -+ u32 ht; -+ u32 hde; -+ u32 hfp; -+ u32 hsync; -+ u32 vt; -+ u32 vde; -+ u32 vfp; -+ u32 vsync; -+ u32 dclk_index; -+ u32 flags; -+ u32 refresh_rate; -+ u32 refresh_rate_index; -+ u32 mode_id; -+}; -+ -+struct ast_vbios_dclk_info { -+ u8 param1; -+ u8 param2; -+ u8 param3; -+}; -+ -+struct ast_vbios_mode_info { -+ const struct ast_vbios_stdtable *std_table; -+ const struct ast_vbios_enhtable *enh_table; -+}; -+ -+struct ast_crtc_state { -+ struct drm_crtc_state base; -+ -+ /* Last known format of primary plane */ -+ const struct drm_format_info *format; -+ -+ struct ast_vbios_mode_info vbios_mode_info; -+}; -+ -+#define to_ast_crtc_state(state) \ -+ container_of(state, struct ast_crtc_state, base) -+ -+int ast_mode_config_init(struct ast_private *ast); -+ -+#define AST_MM_ALIGN_SHIFT 4 -+#define AST_MM_ALIGN_MASK ((1 << AST_MM_ALIGN_SHIFT) - 1) -+ -+#define AST_DP501_FW_VERSION_MASK GENMASK(7, 4) -+#define AST_DP501_FW_VERSION_1 BIT(4) -+#define AST_DP501_PNP_CONNECTED BIT(1) -+ -+#define AST_DP501_DEFAULT_DCLK 65 -+ -+#define AST_DP501_GBL_VERSION 0xf000 -+#define AST_DP501_PNPMONITOR 0xf010 -+#define AST_DP501_LINKRATE 0xf014 -+#define AST_DP501_EDID_DATA 0xf020 -+ -+/* Define for Soc scratched reg */ -+#define COPROCESSOR_LAUNCH BIT(5) -+ -+/* -+ * Display Transmitter Type: -+ */ -+#define TX_TYPE_MASK GENMASK(3, 1) -+#define NO_TX (0 << 1) -+#define ITE66121_VBIOS_TX (1 << 1) -+#define SI164_VBIOS_TX (2 << 1) -+#define CH7003_VBIOS_TX (3 << 1) -+#define DP501_VBIOS_TX (4 << 1) -+#define ANX9807_VBIOS_TX (5 << 1) -+#define TX_FW_EMBEDDED_FW_TX (6 << 1) -+#define ASTDP_DPMCU_TX (7 << 1) -+ -+#define AST_VRAM_INIT_STATUS_MASK GENMASK(7, 6) -+//#define AST_VRAM_INIT_BY_BMC BIT(7) -+//#define AST_VRAM_INIT_READY BIT(6) -+ -+/* Define for Soc scratched reg used on ASTDP */ -+#define AST_DP_PHY_SLEEP BIT(4) -+#define AST_DP_VIDEO_ENABLE BIT(0) -+ -+#define AST_DP_POWER_ON true -+#define AST_DP_POWER_OFF false -+ -+/* -+ * CRD1[b5]: DP MCU FW is executing -+ * CRDC[b0]: DP link success -+ * CRDF[b0]: DP HPD -+ * CRE5[b0]: Host reading EDID process is done -+ */ -+#define ASTDP_MCU_FW_EXECUTING BIT(5) -+#define ASTDP_LINK_SUCCESS BIT(0) -+#define ASTDP_HPD BIT(0) -+#define ASTDP_HOST_EDID_READ_DONE BIT(0) -+#define ASTDP_HOST_EDID_READ_DONE_MASK GENMASK(0, 0) -+ -+/* -+ * CRB8[b1]: Enable VSYNC off -+ * CRB8[b0]: Enable HSYNC off -+ */ -+#define AST_DPMS_VSYNC_OFF BIT(1) -+#define AST_DPMS_HSYNC_OFF BIT(0) -+ -+/* -+ * CRDF[b4]: Mirror of AST_DP_VIDEO_ENABLE -+ * Precondition: A. ~AST_DP_PHY_SLEEP && -+ * B. DP_HPD && -+ * C. DP_LINK_SUCCESS -+ */ -+#define ASTDP_MIRROR_VIDEO_ENABLE BIT(4) -+ -+#define ASTDP_EDID_READ_POINTER_MASK GENMASK(7, 0) -+#define ASTDP_EDID_VALID_FLAG_MASK GENMASK(0, 0) -+#define ASTDP_EDID_READ_DATA_MASK GENMASK(7, 0) -+ -+/* -+ * ASTDP setmode registers: -+ * CRE0[7:0]: MISC0 ((0x00: 18-bpp) or (0x20: 24-bpp) -+ * CRE1[7:0]: MISC1 (default: 0x00) -+ * CRE2[7:0]: video format index (0x00 ~ 0x20 or 0x40 ~ 0x50) -+ */ -+#define ASTDP_MISC0_24bpp BIT(5) -+#define ASTDP_MISC1 0 -+#define ASTDP_AND_CLEAR_MASK 0x00 -+ -+/* -+ * ASTDP resoultion table: -+ * EX: ASTDP_A_B_C: -+ * A: Resolution -+ * B: Refresh Rate -+ * C: Misc information, such as CVT, Reduce Blanked -+ */ -+#define ASTDP_640x480_60 0x00 -+#define ASTDP_640x480_72 0x01 -+#define ASTDP_640x480_75 0x02 -+#define ASTDP_640x480_85 0x03 -+#define ASTDP_800x600_56 0x04 -+#define ASTDP_800x600_60 0x05 -+#define ASTDP_800x600_72 0x06 -+#define ASTDP_800x600_75 0x07 -+#define ASTDP_800x600_85 0x08 -+#define ASTDP_1024x768_60 0x09 -+#define ASTDP_1024x768_70 0x0A -+#define ASTDP_1024x768_75 0x0B -+#define ASTDP_1024x768_85 0x0C -+#define ASTDP_1280x1024_60 0x0D -+#define ASTDP_1280x1024_75 0x0E -+#define ASTDP_1280x1024_85 0x0F -+#define ASTDP_1600x1200_60 0x10 -+#define ASTDP_320x240_60 0x11 -+#define ASTDP_400x300_60 0x12 -+#define ASTDP_512x384_60 0x13 -+#define ASTDP_1920x1200_60 0x14 -+#define ASTDP_1920x1080_60 0x15 -+#define ASTDP_1280x800_60 0x16 -+#define ASTDP_1280x800_60_RB 0x17 -+#define ASTDP_1440x900_60 0x18 -+#define ASTDP_1440x900_60_RB 0x19 -+#define ASTDP_1680x1050_60 0x1A -+#define ASTDP_1680x1050_60_RB 0x1B -+#define ASTDP_1600x900_60 0x1C -+#define ASTDP_1600x900_60_RB 0x1D -+#define ASTDP_1366x768_60 0x1E -+#define ASTDP_1152x864_75 0x1F -+ -+int ast_mm_init(struct ast_private *ast); -+ -+/* ast post */ -+void ast_enable_vga(struct drm_device *dev); -+void ast_enable_mmio(struct drm_device *dev); -+bool ast_is_vga_enabled(struct drm_device *dev); -+void ast_post_gpu(struct drm_device *dev); -+u32 ast_mindwm(struct ast_private *ast, u32 r); -+void ast_moutdwm(struct ast_private *ast, u32 r, u32 v); -+void ast_patch_ahb_2500(struct ast_private *ast); -+/* ast dp501 */ -+void ast_set_dp501_video_output(struct drm_device *dev, u8 mode); -+bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size); -+bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata); -+u8 ast_get_dp501_max_clk(struct drm_device *dev); -+void ast_init_3rdtx(struct drm_device *dev); -+ -+/* ast_i2c.c */ -+struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev); -+ -+/* aspeed DP */ -+int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata); -+void ast_dp_launch(struct drm_device *dev, u8 bPower); -+void ast_dp_power_on_off(struct drm_device *dev, bool no); -+void ast_dp_set_on_off(struct drm_device *dev, bool no); -+void ast_dp_set_mode(struct drm_crtc *crtc, -+ struct ast_vbios_mode_info *vbios_mode); -+ -+#endif -diff --git a/drivers/gpu/drm/loongson/ast_old/ast_i2c.c b/drivers/gpu/drm/loongson/ast_old/ast_i2c.c -new file mode 100644 -index 0000000..a3daabe ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/ast_i2c.c -@@ -0,0 +1,170 @@ -+// SPDX-License-Identifier: MIT -+/* -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sub license, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, -+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -+ * USE OR OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * The above copyright notice and this permission notice (including the -+ * next paragraph) shall be included in all copies or substantial portions -+ * of the Software. -+ */ -+ -+#include <drm/drm_managed.h> -+#include <drm/drm_print.h> -+ -+#include "ast_drv.h" -+ -+static void ast_i2c_setsda(void *i2c_priv, int data) -+{ -+ struct ast_i2c_chan *i2c = i2c_priv; -+ struct ast_private *ast = to_ast_private(i2c->dev); -+ int i; -+ u8 ujcrb7, jtemp; -+ -+ for (i = 0; i < 0x10000; i++) { -+ ujcrb7 = ((data & 0x01) ? 0 : 1) << 2; -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf1, -+ ujcrb7); -+ jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, -+ 0x04); -+ if (ujcrb7 == jtemp) -+ break; -+ } -+} -+ -+static void ast_i2c_setscl(void *i2c_priv, int clock) -+{ -+ struct ast_i2c_chan *i2c = i2c_priv; -+ struct ast_private *ast = to_ast_private(i2c->dev); -+ int i; -+ u8 ujcrb7, jtemp; -+ -+ for (i = 0; i < 0x10000; i++) { -+ ujcrb7 = ((clock & 0x01) ? 0 : 1); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xf4, -+ ujcrb7); -+ jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, -+ 0x01); -+ if (ujcrb7 == jtemp) -+ break; -+ } -+} -+ -+static int ast_i2c_getsda(void *i2c_priv) -+{ -+ struct ast_i2c_chan *i2c = i2c_priv; -+ struct ast_private *ast = to_ast_private(i2c->dev); -+ uint32_t val, val2, count, pass; -+ -+ count = 0; -+ pass = 0; -+ val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5) & -+ 0x01; -+ do { -+ val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, -+ 0x20) >> -+ 5) & -+ 0x01; -+ if (val == val2) { -+ pass++; -+ } else { -+ pass = 0; -+ val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, -+ 0xb7, 0x20) >> -+ 5) & -+ 0x01; -+ } -+ } while ((pass < 5) && (count++ < 0x10000)); -+ -+ return val & 1 ? 1 : 0; -+} -+ -+static int ast_i2c_getscl(void *i2c_priv) -+{ -+ struct ast_i2c_chan *i2c = i2c_priv; -+ struct ast_private *ast = to_ast_private(i2c->dev); -+ uint32_t val, val2, count, pass; -+ -+ count = 0; -+ pass = 0; -+ val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4) & -+ 0x01; -+ do { -+ val2 = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, -+ 0x10) >> -+ 4) & -+ 0x01; -+ if (val == val2) { -+ pass++; -+ } else { -+ pass = 0; -+ val = (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, -+ 0xb7, 0x10) >> -+ 4) & -+ 0x01; -+ } -+ } while ((pass < 5) && (count++ < 0x10000)); -+ -+ return val & 1 ? 1 : 0; -+} -+ -+static void ast_i2c_release(struct drm_device *dev, void *res) -+{ -+ struct ast_i2c_chan *i2c = res; -+ -+ i2c_del_adapter(&i2c->adapter); -+ kfree(i2c); -+} -+ -+struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev) -+{ -+ struct ast_i2c_chan *i2c; -+ int ret; -+ -+ i2c = kzalloc(sizeof(struct ast_i2c_chan), GFP_KERNEL); -+ if (!i2c) -+ return NULL; -+ -+ i2c->adapter.owner = THIS_MODULE; -+ i2c->adapter.class = I2C_CLASS_DDC; -+ i2c->adapter.dev.parent = dev->dev; -+ i2c->dev = dev; -+ i2c_set_adapdata(&i2c->adapter, i2c); -+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), -+ "AST i2c bit bus"); -+ i2c->adapter.algo_data = &i2c->bit; -+ -+ i2c->bit.udelay = 20; -+ i2c->bit.timeout = 2; -+ i2c->bit.data = i2c; -+ i2c->bit.setsda = ast_i2c_setsda; -+ i2c->bit.setscl = ast_i2c_setscl; -+ i2c->bit.getsda = ast_i2c_getsda; -+ i2c->bit.getscl = ast_i2c_getscl; -+ ret = i2c_bit_add_bus(&i2c->adapter); -+ if (ret) { -+ drm_err(dev, "Failed to register bit i2c\n"); -+ goto out_kfree; -+ } -+ -+ ret = drmm_add_action_or_reset(dev, ast_i2c_release, i2c); -+ if (ret) -+ return NULL; -+ return i2c; -+ -+out_kfree: -+ kfree(i2c); -+ return NULL; -+} -diff --git a/drivers/gpu/drm/loongson/ast_old/ast_main.c b/drivers/gpu/drm/loongson/ast_old/ast_main.c -new file mode 100644 -index 0000000..ab6195b ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/ast_main.c -@@ -0,0 +1,486 @@ -+/* -+ * Copyright 2012 Red Hat Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sub license, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, -+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -+ * USE OR OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * The above copyright notice and this permission notice (including the -+ * next paragraph) shall be included in all copies or substantial portions -+ * of the Software. -+ * -+ */ -+/* -+ * Authors: Dave Airlie <airlied@redhat.com> -+ */ -+ -+#include <linux/pci.h> -+ -+#include <drm/drm_atomic_helper.h> -+#include <drm/drm_crtc_helper.h> -+#include <drm/drm_drv.h> -+#include <drm/drm_gem.h> -+#include <drm/drm_gem_vram_helper.h> -+#include <drm/drm_managed.h> -+ -+#include "ast_drv.h" -+ -+void ast_set_index_reg_mask(struct ast_private *ast, uint32_t base, -+ uint8_t index, uint8_t mask, uint8_t val) -+{ -+ u8 tmp; -+ -+ ast_io_write8(ast, base, index); -+ tmp = (ast_io_read8(ast, base + 1) & mask) | val; -+ ast_set_index_reg(ast, base, index, tmp); -+} -+ -+uint8_t ast_get_index_reg(struct ast_private *ast, uint32_t base, uint8_t index) -+{ -+ uint8_t ret; -+ -+ ast_io_write8(ast, base, index); -+ ret = ast_io_read8(ast, base + 1); -+ return ret; -+} -+ -+uint8_t ast_get_index_reg_mask(struct ast_private *ast, uint32_t base, -+ uint8_t index, uint8_t mask) -+{ -+ uint8_t ret; -+ -+ ast_io_write8(ast, base, index); -+ ret = ast_io_read8(ast, base + 1) & mask; -+ return ret; -+} -+ -+static void ast_detect_config_mode(struct drm_device *dev, u32 *scu_rev) -+{ -+ struct device_node *np = dev->dev->of_node; -+ struct ast_private *ast = to_ast_private(dev); -+ struct pci_dev *pdev = to_pci_dev(dev->dev); -+ uint32_t data, jregd0, jregd1; -+ -+ /* Defaults */ -+ ast->config_mode = ast_use_defaults; -+ *scu_rev = 0xffffffff; -+ -+ /* Check if we have device-tree properties */ -+ if (np && -+ !of_property_read_u32(np, "aspeed,scu-revision-id", scu_rev)) { -+ /* We do, disable P2A access */ -+ ast->config_mode = ast_use_dt; -+ drm_info(dev, "Using device-tree for configuration\n"); -+ return; -+ } -+ -+ /* Not all families have a P2A bridge */ -+ if (pdev->device != PCI_CHIP_AST2000) -+ return; -+ -+ /* -+ * The BMC will set SCU 0x40 D[12] to 1 if the P2 bridge -+ * is disabled. We force using P2A if VGA only mode bit -+ * is set D[7] -+ */ -+ jregd0 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); -+ jregd1 = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 0xff); -+ if (!(jregd0 & 0x80) || !(jregd1 & 0x10)) { -+ /* Patch AST2500 */ -+ if (((pdev->revision & 0xF0) == 0x40) && -+ ((jregd0 & AST_VRAM_INIT_STATUS_MASK) == 0)) -+ ast_patch_ahb_2500(ast); -+ -+ /* Double check it's actually working */ -+ data = ast_read32(ast, 0xf004); -+ if ((data != 0xFFFFFFFF) && (data != 0x00)) { -+ /* P2A works, grab silicon revision */ -+ ast->config_mode = ast_use_p2a; -+ -+ drm_info(dev, "Using P2A bridge for configuration\n"); -+ -+ /* Read SCU7c (silicon revision register) */ -+ ast_write32(ast, 0xf004, 0x1e6e0000); -+ ast_write32(ast, 0xf000, 0x1); -+ *scu_rev = ast_read32(ast, 0x1207c); -+ return; -+ } -+ } -+ -+ /* We have a P2A bridge but it's disabled */ -+ drm_info(dev, "P2A bridge disabled, using default configuration\n"); -+} -+ -+static int ast_detect_chip(struct drm_device *dev, bool *need_post) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ struct pci_dev *pdev = to_pci_dev(dev->dev); -+ uint32_t jreg, scu_rev; -+ -+ /* -+ * If VGA isn't enabled, we need to enable now or subsequent -+ * access to the scratch registers will fail. We also inform -+ * our caller that it needs to POST the chip -+ * (Assumption: VGA not enabled -> need to POST) -+ */ -+ if (!ast_is_vga_enabled(dev)) { -+ ast_enable_vga(dev); -+ drm_info(dev, -+ "VGA not enabled on entry, requesting chip POST\n"); -+ *need_post = true; -+ } else -+ *need_post = false; -+ -+ /* Enable extended register access */ -+ ast_open_key(ast); -+ ast_enable_mmio(dev); -+ -+ /* Find out whether P2A works or whether to use device-tree */ -+ ast_detect_config_mode(dev, &scu_rev); -+ -+ /* Identify chipset */ -+ if (pdev->revision >= 0x50) { -+ ast->chip = AST2600; -+ drm_info(dev, "AST 2600 detected\n"); -+ } else if (pdev->revision >= 0x40) { -+ ast->chip = AST2500; -+ drm_info(dev, "AST 2500 detected\n"); -+ } else if (pdev->revision >= 0x30) { -+ ast->chip = AST2400; -+ drm_info(dev, "AST 2400 detected\n"); -+ } else if (pdev->revision >= 0x20) { -+ ast->chip = AST2300; -+ drm_info(dev, "AST 2300 detected\n"); -+ } else if (pdev->revision >= 0x10) { -+ switch (scu_rev & 0x0300) { -+ case 0x0200: -+ ast->chip = AST1100; -+ drm_info(dev, "AST 1100 detected\n"); -+ break; -+ case 0x0100: -+ ast->chip = AST2200; -+ drm_info(dev, "AST 2200 detected\n"); -+ break; -+ case 0x0000: -+ ast->chip = AST2150; -+ drm_info(dev, "AST 2150 detected\n"); -+ break; -+ default: -+ ast->chip = AST2100; -+ drm_info(dev, "AST 2100 detected\n"); -+ break; -+ } -+ ast->vga2_clone = false; -+ } else { -+ ast->chip = AST2000; -+ drm_info(dev, "AST 2000 detected\n"); -+ } -+ -+ /* Check if we support wide screen */ -+ switch (ast->chip) { -+ case AST2000: -+ ast->support_wide_screen = false; -+ break; -+ default: -+ jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, -+ 0xff); -+ if (!(jreg & 0x80)) -+ ast->support_wide_screen = true; -+ else if (jreg & 0x01) -+ ast->support_wide_screen = true; -+ else { -+ ast->support_wide_screen = false; -+ if (ast->chip == AST2300 && -+ (scu_rev & 0x300) == 0x0) /* ast1300 */ -+ ast->support_wide_screen = true; -+ if (ast->chip == AST2400 && -+ (scu_rev & 0x300) == 0x100) /* ast1400 */ -+ ast->support_wide_screen = true; -+ if (ast->chip == AST2500 && -+ scu_rev == 0x100) /* ast2510 */ -+ ast->support_wide_screen = true; -+ if (ast->chip == AST2600) /* ast2600 */ -+ ast->support_wide_screen = true; -+ } -+ break; -+ } -+ -+ /* Check 3rd Tx option (digital output afaik) */ -+ ast->tx_chip_types |= AST_TX_NONE_BIT; -+ -+ /* -+ * VGACRA3 Enhanced Color Mode Register, check if DVO is already -+ * enabled, in that case, assume we have a SIL164 TMDS transmitter -+ * -+ * Don't make that assumption if we the chip wasn't enabled and -+ * is at power-on reset, otherwise we'll incorrectly "detect" a -+ * SIL164 when there is none. -+ */ -+ if (!*need_post) { -+ jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, -+ 0xff); -+ if (jreg & 0x80) -+ ast->tx_chip_types = AST_TX_SIL164_BIT; -+ } -+ -+ if ((ast->chip == AST2300) || (ast->chip == AST2400) || -+ (ast->chip == AST2500)) { -+ /* -+ * On AST2300 and 2400, look the configuration set by the SoC in -+ * the SOC scratch register #1 bits 11:8 (interestingly marked -+ * as "reserved" in the spec) -+ */ -+ jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, -+ 0xff); -+ switch (jreg) { -+ case 0x04: -+ ast->tx_chip_types = AST_TX_SIL164_BIT; -+ break; -+ case 0x08: -+ ast->dp501_fw_addr = -+ drmm_kzalloc(dev, 32 * 1024, GFP_KERNEL); -+ if (ast->dp501_fw_addr) { -+ /* backup firmware */ -+ if (ast_backup_fw(dev, ast->dp501_fw_addr, -+ 32 * 1024)) { -+ drmm_kfree(dev, ast->dp501_fw_addr); -+ ast->dp501_fw_addr = NULL; -+ } -+ } -+ fallthrough; -+ case 0x0c: -+ ast->tx_chip_types = AST_TX_DP501_BIT; -+ } -+ } else if (ast->chip == AST2600) -+ ast_dp_launch(&ast->base, 0); -+ -+ /* Print stuff for diagnostic purposes */ -+ if (ast->tx_chip_types & AST_TX_NONE_BIT) -+ drm_info(dev, "Using analog VGA\n"); -+ if (ast->tx_chip_types & AST_TX_SIL164_BIT) -+ drm_info(dev, "Using Sil164 TMDS transmitter\n"); -+ if (ast->tx_chip_types & AST_TX_DP501_BIT) -+ drm_info(dev, "Using DP501 DisplayPort transmitter\n"); -+ -+ return 0; -+} -+ -+static int ast_get_dram_info(struct drm_device *dev) -+{ -+ struct device_node *np = dev->dev->of_node; -+ struct ast_private *ast = to_ast_private(dev); -+ uint32_t mcr_cfg, mcr_scu_mpll, mcr_scu_strap; -+ uint32_t denum, num, div, ref_pll, dsel; -+ -+ switch (ast->config_mode) { -+ case ast_use_dt: -+ /* -+ * If some properties are missing, use reasonable -+ * defaults for AST2400 -+ */ -+ if (of_property_read_u32(np, "aspeed,mcr-configuration", -+ &mcr_cfg)) -+ mcr_cfg = 0x00000577; -+ if (of_property_read_u32(np, "aspeed,mcr-scu-mpll", -+ &mcr_scu_mpll)) -+ mcr_scu_mpll = 0x000050C0; -+ if (of_property_read_u32(np, "aspeed,mcr-scu-strap", -+ &mcr_scu_strap)) -+ mcr_scu_strap = 0; -+ break; -+ case ast_use_p2a: -+ ast_write32(ast, 0xf004, 0x1e6e0000); -+ ast_write32(ast, 0xf000, 0x1); -+ mcr_cfg = ast_read32(ast, 0x10004); -+ mcr_scu_mpll = ast_read32(ast, 0x10120); -+ mcr_scu_strap = ast_read32(ast, 0x10170); -+ break; -+ case ast_use_defaults: -+ default: -+ ast->dram_bus_width = 16; -+ ast->dram_type = AST_DRAM_1Gx16; -+ if (ast->chip == AST2500) -+ ast->mclk = 800; -+ else -+ ast->mclk = 396; -+ return 0; -+ } -+ -+ if (mcr_cfg & 0x40) -+ ast->dram_bus_width = 16; -+ else -+ ast->dram_bus_width = 32; -+ -+ if (ast->chip == AST2500) { -+ switch (mcr_cfg & 0x03) { -+ case 0: -+ ast->dram_type = AST_DRAM_1Gx16; -+ break; -+ default: -+ case 1: -+ ast->dram_type = AST_DRAM_2Gx16; -+ break; -+ case 2: -+ ast->dram_type = AST_DRAM_4Gx16; -+ break; -+ case 3: -+ ast->dram_type = AST_DRAM_8Gx16; -+ break; -+ } -+ } else if (ast->chip == AST2300 || ast->chip == AST2400) { -+ switch (mcr_cfg & 0x03) { -+ case 0: -+ ast->dram_type = AST_DRAM_512Mx16; -+ break; -+ default: -+ case 1: -+ ast->dram_type = AST_DRAM_1Gx16; -+ break; -+ case 2: -+ ast->dram_type = AST_DRAM_2Gx16; -+ break; -+ case 3: -+ ast->dram_type = AST_DRAM_4Gx16; -+ break; -+ } -+ } else { -+ switch (mcr_cfg & 0x0c) { -+ case 0: -+ case 4: -+ ast->dram_type = AST_DRAM_512Mx16; -+ break; -+ case 8: -+ if (mcr_cfg & 0x40) -+ ast->dram_type = AST_DRAM_1Gx16; -+ else -+ ast->dram_type = AST_DRAM_512Mx32; -+ break; -+ case 0xc: -+ ast->dram_type = AST_DRAM_1Gx32; -+ break; -+ } -+ } -+ -+ if (mcr_scu_strap & 0x2000) -+ ref_pll = 14318; -+ else -+ ref_pll = 12000; -+ -+ denum = mcr_scu_mpll & 0x1f; -+ num = (mcr_scu_mpll & 0x3fe0) >> 5; -+ dsel = (mcr_scu_mpll & 0xc000) >> 14; -+ switch (dsel) { -+ case 3: -+ div = 0x4; -+ break; -+ case 2: -+ case 1: -+ div = 0x2; -+ break; -+ default: -+ div = 0x1; -+ break; -+ } -+ ast->mclk = ref_pll * (num + 2) / ((denum + 2) * (div * 1000)); -+ return 0; -+} -+ -+/* -+ * Run this function as part of the HW device cleanup; not -+ * when the DRM device gets released. -+ */ -+static void ast_device_release(void *data) -+{ -+ struct ast_private *ast = data; -+ -+ /* enable standard VGA decode */ -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x04); -+} -+ -+struct ast_private *ast_device_create(const struct drm_driver *drv, -+ struct pci_dev *pdev, unsigned long flags) -+{ -+ struct drm_device *dev; -+ struct ast_private *ast; -+ bool need_post; -+ int ret = 0; -+ -+ ast = devm_drm_dev_alloc(&pdev->dev, drv, struct ast_private, base); -+ if (IS_ERR(ast)) -+ return ast; -+ dev = &ast->base; -+ -+ pci_set_drvdata(pdev, dev); -+ -+ ret = drmm_mutex_init(dev, &ast->ioregs_lock); -+ if (ret) -+ return ERR_PTR(ret); -+ -+ ast->regs = pcim_iomap(pdev, 1, 0); -+ if (!ast->regs) -+ return ERR_PTR(-EIO); -+ -+ /* -+ * If we don't have IO space at all, use MMIO now and -+ * assume the chip has MMIO enabled by default (rev 0x20 -+ * and higher). -+ */ -+ if (!(pci_resource_flags(pdev, 2) & IORESOURCE_IO)) { -+ drm_info(dev, "platform has no IO space, trying MMIO\n"); -+ ast->ioregs = ast->regs + AST_IO_MM_OFFSET; -+ } -+ -+ /* "map" IO regs if the above hasn't done so already */ -+ if (!ast->ioregs) { -+ ast->ioregs = pcim_iomap(pdev, 2, 0); -+ if (!ast->ioregs) -+ return ERR_PTR(-EIO); -+ } -+ -+ ast_detect_chip(dev, &need_post); -+ -+ ret = ast_get_dram_info(dev); -+ if (ret) -+ return ERR_PTR(ret); -+ -+ drm_info(dev, "dram MCLK=%u Mhz type=%d bus_width=%d\n", ast->mclk, -+ ast->dram_type, ast->dram_bus_width); -+ -+ if (need_post) -+ ast_post_gpu(dev); -+ -+ ret = ast_mm_init(ast); -+ if (ret) -+ return ERR_PTR(ret); -+ -+ /* map reserved buffer */ -+ ast->dp501_fw_buf = NULL; -+ if (dev->vram_mm->vram_size < pci_resource_len(pdev, 0)) { -+ ast->dp501_fw_buf = -+ pci_iomap_range(pdev, 0, dev->vram_mm->vram_size, 0); -+ if (!ast->dp501_fw_buf) -+ drm_info(dev, "failed to map reserved buffer!\n"); -+ } -+ -+ ret = ast_mode_config_init(ast); -+ if (ret) -+ return ERR_PTR(ret); -+ -+ ret = devm_add_action_or_reset(dev->dev, ast_device_release, ast); -+ if (ret) -+ return ERR_PTR(ret); -+ -+ return ast; -+} -diff --git a/drivers/gpu/drm/loongson/ast_old/ast_mm.c b/drivers/gpu/drm/loongson/ast_old/ast_mm.c -new file mode 100644 -index 0000000..6e99940 ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/ast_mm.c -@@ -0,0 +1,101 @@ -+/* -+ * Copyright 2012 Red Hat Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sub license, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, -+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -+ * USE OR OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * The above copyright notice and this permission notice (including the -+ * next paragraph) shall be included in all copies or substantial portions -+ * of the Software. -+ * -+ */ -+/* -+ * Authors: Dave Airlie <airlied@redhat.com> -+ */ -+ -+#include <linux/pci.h> -+ -+#include <drm/drm_gem_vram_helper.h> -+#include <drm/drm_managed.h> -+#include <drm/drm_print.h> -+ -+#include "ast_drv.h" -+ -+static u32 ast_get_vram_size(struct ast_private *ast) -+{ -+ u8 jreg; -+ u32 vram_size; -+ -+ ast_open_key(ast); -+ -+ vram_size = AST_VIDMEM_DEFAULT_SIZE; -+ jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xaa, 0xff); -+ switch (jreg & 3) { -+ case 0: -+ vram_size = AST_VIDMEM_SIZE_8M; -+ break; -+ case 1: -+ vram_size = AST_VIDMEM_SIZE_16M; -+ break; -+ case 2: -+ vram_size = AST_VIDMEM_SIZE_32M; -+ break; -+ case 3: -+ vram_size = AST_VIDMEM_SIZE_64M; -+ break; -+ } -+ -+ jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x99, 0xff); -+ switch (jreg & 0x03) { -+ case 1: -+ vram_size -= 0x100000; -+ break; -+ case 2: -+ vram_size -= 0x200000; -+ break; -+ case 3: -+ vram_size -= 0x400000; -+ break; -+ } -+ -+ return vram_size; -+} -+ -+int ast_mm_init(struct ast_private *ast) -+{ -+ struct drm_device *dev = &ast->base; -+ struct pci_dev *pdev = to_pci_dev(dev->dev); -+ resource_size_t base, size; -+ u32 vram_size; -+ int ret; -+ -+ base = pci_resource_start(pdev, 0); -+ size = pci_resource_len(pdev, 0); -+ -+ /* Don't fail on errors, but performance might be reduced. */ -+ devm_arch_io_reserve_memtype_wc(dev->dev, base, size); -+ devm_arch_phys_wc_add(dev->dev, base, size); -+ -+ vram_size = ast_get_vram_size(ast); -+ -+ ret = drmm_vram_helper_init(dev, base, vram_size); -+ if (ret) { -+ drm_err(dev, "Error initializing VRAM MM; %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -diff --git a/drivers/gpu/drm/loongson/ast_old/ast_mode.c b/drivers/gpu/drm/loongson/ast_old/ast_mode.c -new file mode 100644 -index 0000000..5374fc3 ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/ast_mode.c -@@ -0,0 +1,1881 @@ -+/* -+ * Copyright 2012 Red Hat Inc. -+ * Parts based on xf86-video-ast -+ * Copyright (c) 2005 ASPEED Technology Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sub license, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, -+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -+ * USE OR OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * The above copyright notice and this permission notice (including the -+ * next paragraph) shall be included in all copies or substantial portions -+ * of the Software. -+ * -+ */ -+/* -+ * Authors: Dave Airlie <airlied@redhat.com> -+ */ -+ -+#include <linux/export.h> -+#include <linux/pci.h> -+ -+#include <drm/drm_atomic.h> -+#include <drm/drm_atomic_helper.h> -+#include <drm/drm_atomic_state_helper.h> -+#include <drm/drm_crtc.h> -+#include <drm/drm_crtc_helper.h> -+#include <drm/drm_edid.h> -+#include <drm/drm_fourcc.h> -+#include <drm/drm_gem_atomic_helper.h> -+#include <drm/drm_gem_framebuffer_helper.h> -+#include <drm/drm_gem_vram_helper.h> -+#include <drm/drm_managed.h> -+#include <drm/drm_probe_helper.h> -+#include <drm/drm_simple_kms_helper.h> -+ -+#include "ast_drv.h" -+#include "ast_tables.h" -+ -+#define AST_LUT_SIZE 256 -+ -+static inline void ast_load_palette_index(struct ast_private *ast, u8 index, -+ u8 red, u8 green, u8 blue) -+{ -+ ast_io_write8(ast, AST_IO_DAC_INDEX_WRITE, index); -+ ast_io_read8(ast, AST_IO_SEQ_PORT); -+ ast_io_write8(ast, AST_IO_DAC_DATA, red); -+ ast_io_read8(ast, AST_IO_SEQ_PORT); -+ ast_io_write8(ast, AST_IO_DAC_DATA, green); -+ ast_io_read8(ast, AST_IO_SEQ_PORT); -+ ast_io_write8(ast, AST_IO_DAC_DATA, blue); -+ ast_io_read8(ast, AST_IO_SEQ_PORT); -+} -+ -+static void ast_crtc_set_gamma_linear(struct ast_private *ast, -+ const struct drm_format_info *format) -+{ -+ int i; -+ -+ switch (format->format) { -+ case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */ -+ case DRM_FORMAT_RGB565: -+ case DRM_FORMAT_XRGB8888: -+ for (i = 0; i < AST_LUT_SIZE; i++) -+ ast_load_palette_index(ast, i, i, i, i); -+ break; -+ default: -+ drm_warn_once(&ast->base, -+ "Unsupported format %p4cc for gamma correction\n", -+ &format->format); -+ break; -+ } -+} -+ -+static void ast_crtc_set_gamma(struct ast_private *ast, -+ const struct drm_format_info *format, -+ struct drm_color_lut *lut) -+{ -+ int i; -+ -+ switch (format->format) { -+ case DRM_FORMAT_C8: /* In this case, gamma table is used as color palette */ -+ case DRM_FORMAT_RGB565: -+ case DRM_FORMAT_XRGB8888: -+ for (i = 0; i < AST_LUT_SIZE; i++) -+ ast_load_palette_index(ast, i, lut[i].red >> 8, -+ lut[i].green >> 8, -+ lut[i].blue >> 8); -+ break; -+ default: -+ drm_warn_once(&ast->base, -+ "Unsupported format %p4cc for gamma correction\n", -+ &format->format); -+ break; -+ } -+} -+ -+static bool ast_get_vbios_mode_info(const struct drm_format_info *format, -+ const struct drm_display_mode *mode, -+ struct drm_display_mode *adjusted_mode, -+ struct ast_vbios_mode_info *vbios_mode) -+{ -+ u32 refresh_rate_index = 0, refresh_rate; -+ const struct ast_vbios_enhtable *best = NULL; -+ u32 hborder, vborder; -+ bool check_sync; -+ -+ switch (format->cpp[0] * 8) { -+ case 8: -+ vbios_mode->std_table = &vbios_stdtable[VGAModeIndex]; -+ break; -+ case 16: -+ vbios_mode->std_table = &vbios_stdtable[HiCModeIndex]; -+ break; -+ case 24: -+ case 32: -+ vbios_mode->std_table = &vbios_stdtable[TrueCModeIndex]; -+ break; -+ default: -+ return false; -+ } -+ -+ switch (mode->crtc_hdisplay) { -+ case 640: -+ vbios_mode->enh_table = &res_640x480[refresh_rate_index]; -+ break; -+ case 800: -+ vbios_mode->enh_table = &res_800x600[refresh_rate_index]; -+ break; -+ case 1024: -+ vbios_mode->enh_table = &res_1024x768[refresh_rate_index]; -+ break; -+ case 1152: -+ vbios_mode->enh_table = &res_1152x864[refresh_rate_index]; -+ break; -+ case 1280: -+ if (mode->crtc_vdisplay == 800) -+ vbios_mode->enh_table = -+ &res_1280x800[refresh_rate_index]; -+ else -+ vbios_mode->enh_table = -+ &res_1280x1024[refresh_rate_index]; -+ break; -+ case 1360: -+ vbios_mode->enh_table = &res_1360x768[refresh_rate_index]; -+ break; -+ case 1440: -+ vbios_mode->enh_table = &res_1440x900[refresh_rate_index]; -+ break; -+ case 1600: -+ if (mode->crtc_vdisplay == 900) -+ vbios_mode->enh_table = -+ &res_1600x900[refresh_rate_index]; -+ else -+ vbios_mode->enh_table = -+ &res_1600x1200[refresh_rate_index]; -+ break; -+ case 1680: -+ vbios_mode->enh_table = &res_1680x1050[refresh_rate_index]; -+ break; -+ case 1920: -+ if (mode->crtc_vdisplay == 1080) -+ vbios_mode->enh_table = -+ &res_1920x1080[refresh_rate_index]; -+ else -+ vbios_mode->enh_table = -+ &res_1920x1200[refresh_rate_index]; -+ break; -+ default: -+ return false; -+ } -+ -+ refresh_rate = drm_mode_vrefresh(mode); -+ check_sync = vbios_mode->enh_table->flags & WideScreenMode; -+ -+ while (1) { -+ const struct ast_vbios_enhtable *loop = vbios_mode->enh_table; -+ -+ while (loop->refresh_rate != 0xff) { -+ if ((check_sync) && -+ (((mode->flags & DRM_MODE_FLAG_NVSYNC) && -+ (loop->flags & PVSync)) || -+ ((mode->flags & DRM_MODE_FLAG_PVSYNC) && -+ (loop->flags & NVSync)) || -+ ((mode->flags & DRM_MODE_FLAG_NHSYNC) && -+ (loop->flags & PHSync)) || -+ ((mode->flags & DRM_MODE_FLAG_PHSYNC) && -+ (loop->flags & NHSync)))) { -+ loop++; -+ continue; -+ } -+ if (loop->refresh_rate <= refresh_rate && -+ (!best || loop->refresh_rate > best->refresh_rate)) -+ best = loop; -+ loop++; -+ } -+ if (best || !check_sync) -+ break; -+ check_sync = 0; -+ } -+ -+ if (best) -+ vbios_mode->enh_table = best; -+ -+ hborder = (vbios_mode->enh_table->flags & HBorder) ? 8 : 0; -+ vborder = (vbios_mode->enh_table->flags & VBorder) ? 8 : 0; -+ -+ adjusted_mode->crtc_htotal = vbios_mode->enh_table->ht; -+ adjusted_mode->crtc_hblank_start = vbios_mode->enh_table->hde + hborder; -+ adjusted_mode->crtc_hblank_end = vbios_mode->enh_table->ht - hborder; -+ adjusted_mode->crtc_hsync_start = vbios_mode->enh_table->hde + hborder + -+ vbios_mode->enh_table->hfp; -+ adjusted_mode->crtc_hsync_end = -+ (vbios_mode->enh_table->hde + hborder + -+ vbios_mode->enh_table->hfp + vbios_mode->enh_table->hsync); -+ -+ adjusted_mode->crtc_vtotal = vbios_mode->enh_table->vt; -+ adjusted_mode->crtc_vblank_start = vbios_mode->enh_table->vde + vborder; -+ adjusted_mode->crtc_vblank_end = vbios_mode->enh_table->vt - vborder; -+ adjusted_mode->crtc_vsync_start = vbios_mode->enh_table->vde + vborder + -+ vbios_mode->enh_table->vfp; -+ adjusted_mode->crtc_vsync_end = -+ (vbios_mode->enh_table->vde + vborder + -+ vbios_mode->enh_table->vfp + vbios_mode->enh_table->vsync); -+ -+ return true; -+} -+ -+static void -+ast_set_vbios_color_reg(struct ast_private *ast, -+ const struct drm_format_info *format, -+ const struct ast_vbios_mode_info *vbios_mode) -+{ -+ u32 color_index; -+ -+ switch (format->cpp[0]) { -+ case 1: -+ color_index = VGAModeIndex - 1; -+ break; -+ case 2: -+ color_index = HiCModeIndex; -+ break; -+ case 3: -+ case 4: -+ color_index = TrueCModeIndex; -+ break; -+ default: -+ return; -+ } -+ -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8c, -+ (u8)((color_index & 0x0f) << 4)); -+ -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0x00); -+ -+ if (vbios_mode->enh_table->flags & NewModeInfo) { -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, -+ format->cpp[0] * 8); -+ } -+} -+ -+static void ast_set_vbios_mode_reg(struct ast_private *ast, -+ const struct drm_display_mode *adjusted_mode, -+ const struct ast_vbios_mode_info *vbios_mode) -+{ -+ u32 refresh_rate_index, mode_id; -+ -+ refresh_rate_index = vbios_mode->enh_table->refresh_rate_index; -+ mode_id = vbios_mode->enh_table->mode_id; -+ -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8d, -+ refresh_rate_index & 0xff); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff); -+ -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0x00); -+ -+ if (vbios_mode->enh_table->flags & NewModeInfo) { -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, -+ adjusted_mode->clock / 1000); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, -+ adjusted_mode->crtc_hdisplay); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, -+ adjusted_mode->crtc_hdisplay >> 8); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x96, -+ adjusted_mode->crtc_vdisplay); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x97, -+ adjusted_mode->crtc_vdisplay >> 8); -+ } -+} -+ -+static void ast_set_std_reg(struct ast_private *ast, -+ struct drm_display_mode *mode, -+ struct ast_vbios_mode_info *vbios_mode) -+{ -+ const struct ast_vbios_stdtable *stdtable; -+ u32 i; -+ u8 jreg; -+ -+ stdtable = vbios_mode->std_table; -+ -+ jreg = stdtable->misc; -+ ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg); -+ -+ /* Set SEQ; except Screen Disable field */ -+ ast_set_index_reg(ast, AST_IO_SEQ_PORT, 0x00, 0x03); -+ ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x01, 0xdf, -+ stdtable->seq[0]); -+ for (i = 1; i < 4; i++) { -+ jreg = stdtable->seq[i]; -+ ast_set_index_reg(ast, AST_IO_SEQ_PORT, (i + 1), jreg); -+ } -+ -+ /* Set CRTC; except base address and offset */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x00); -+ for (i = 0; i < 12; i++) -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]); -+ for (i = 14; i < 19; i++) -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]); -+ for (i = 20; i < 25; i++) -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]); -+ -+ /* set AR */ -+ jreg = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ); -+ for (i = 0; i < 20; i++) { -+ jreg = stdtable->ar[i]; -+ ast_io_write8(ast, AST_IO_AR_PORT_WRITE, (u8)i); -+ ast_io_write8(ast, AST_IO_AR_PORT_WRITE, jreg); -+ } -+ ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x14); -+ ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x00); -+ -+ jreg = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ); -+ ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x20); -+ -+ /* Set GR */ -+ for (i = 0; i < 9; i++) -+ ast_set_index_reg(ast, AST_IO_GR_PORT, i, stdtable->gr[i]); -+} -+ -+static void ast_set_crtc_reg(struct ast_private *ast, -+ struct drm_display_mode *mode, -+ struct ast_vbios_mode_info *vbios_mode) -+{ -+ u8 jreg05 = 0, jreg07 = 0, jreg09 = 0, jregAC = 0, jregAD = 0, -+ jregAE = 0; -+ u16 temp, precache = 0; -+ -+ if ((ast->chip == AST2500 || ast->chip == AST2600) && -+ (vbios_mode->enh_table->flags & AST2500PreCatchCRT)) -+ precache = 40; -+ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x00); -+ -+ temp = (mode->crtc_htotal >> 3) - 5; -+ if (temp & 0x100) -+ jregAC |= 0x01; /* HT D[8] */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x00, 0x00, temp); -+ -+ temp = (mode->crtc_hdisplay >> 3) - 1; -+ if (temp & 0x100) -+ jregAC |= 0x04; /* HDE D[8] */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x01, 0x00, temp); -+ -+ temp = (mode->crtc_hblank_start >> 3) - 1; -+ if (temp & 0x100) -+ jregAC |= 0x10; /* HBS D[8] */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x02, 0x00, temp); -+ -+ temp = ((mode->crtc_hblank_end >> 3) - 1) & 0x7f; -+ if (temp & 0x20) -+ jreg05 |= 0x80; /* HBE D[5] */ -+ if (temp & 0x40) -+ jregAD |= 0x01; /* HBE D[5] */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x03, 0xE0, -+ (temp & 0x1f)); -+ -+ temp = ((mode->crtc_hsync_start - precache) >> 3) - 1; -+ if (temp & 0x100) -+ jregAC |= 0x40; /* HRS D[5] */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x04, 0x00, temp); -+ -+ temp = (((mode->crtc_hsync_end - precache) >> 3) - 1) & 0x3f; -+ if (temp & 0x20) -+ jregAD |= 0x04; /* HRE D[5] */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x05, 0x60, -+ (u8)((temp & 0x1f) | jreg05)); -+ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAC, 0x00, jregAC); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAD, 0x00, jregAD); -+ -+ // Workaround for HSync Time non octave pixels (1920x1080@60Hz HSync 44 pixels); -+ if ((ast->chip == AST2600) && (mode->crtc_vdisplay == 1080)) -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xFC, 0xFD, 0x02); -+ else -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xFC, 0xFD, 0x00); -+ -+ /* vert timings */ -+ temp = (mode->crtc_vtotal) - 2; -+ if (temp & 0x100) -+ jreg07 |= 0x01; -+ if (temp & 0x200) -+ jreg07 |= 0x20; -+ if (temp & 0x400) -+ jregAE |= 0x01; -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x06, 0x00, temp); -+ -+ temp = (mode->crtc_vsync_start) - 1; -+ if (temp & 0x100) -+ jreg07 |= 0x04; -+ if (temp & 0x200) -+ jreg07 |= 0x80; -+ if (temp & 0x400) -+ jregAE |= 0x08; -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x10, 0x00, temp); -+ -+ temp = (mode->crtc_vsync_end - 1) & 0x3f; -+ if (temp & 0x10) -+ jregAE |= 0x20; -+ if (temp & 0x20) -+ jregAE |= 0x40; -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x70, temp & 0xf); -+ -+ temp = mode->crtc_vdisplay - 1; -+ if (temp & 0x100) -+ jreg07 |= 0x02; -+ if (temp & 0x200) -+ jreg07 |= 0x40; -+ if (temp & 0x400) -+ jregAE |= 0x02; -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x12, 0x00, temp); -+ -+ temp = mode->crtc_vblank_start - 1; -+ if (temp & 0x100) -+ jreg07 |= 0x08; -+ if (temp & 0x200) -+ jreg09 |= 0x20; -+ if (temp & 0x400) -+ jregAE |= 0x04; -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x15, 0x00, temp); -+ -+ temp = mode->crtc_vblank_end - 1; -+ if (temp & 0x100) -+ jregAE |= 0x10; -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x16, 0x00, temp); -+ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x07, 0x00, jreg07); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x09, 0xdf, jreg09); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAE, 0x00, -+ (jregAE | 0x80)); -+ -+ if (precache) -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0x3f, 0x80); -+ else -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0x3f, 0x00); -+ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x80); -+} -+ -+static void ast_set_offset_reg(struct ast_private *ast, -+ struct drm_framebuffer *fb) -+{ -+ u16 offset; -+ -+ offset = fb->pitches[0] >> 3; -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff)); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f); -+} -+ -+static void ast_set_dclk_reg(struct ast_private *ast, -+ struct drm_display_mode *mode, -+ struct ast_vbios_mode_info *vbios_mode) -+{ -+ const struct ast_vbios_dclk_info *clk_info; -+ -+ if ((ast->chip == AST2500) || (ast->chip == AST2600)) -+ clk_info = -+ &dclk_table_ast2500[vbios_mode->enh_table->dclk_index]; -+ else -+ clk_info = &dclk_table[vbios_mode->enh_table->dclk_index]; -+ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xc0, 0x00, -+ clk_info->param1); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xc1, 0x00, -+ clk_info->param2); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xbb, 0x0f, -+ (clk_info->param3 & 0xc0) | -+ ((clk_info->param3 & 0x3) << 4)); -+} -+ -+static void ast_set_color_reg(struct ast_private *ast, -+ const struct drm_format_info *format) -+{ -+ u8 jregA0 = 0, jregA3 = 0, jregA8 = 0; -+ -+ switch (format->cpp[0] * 8) { -+ case 8: -+ jregA0 = 0x70; -+ jregA3 = 0x01; -+ jregA8 = 0x00; -+ break; -+ case 15: -+ case 16: -+ jregA0 = 0x70; -+ jregA3 = 0x04; -+ jregA8 = 0x02; -+ break; -+ case 32: -+ jregA0 = 0x70; -+ jregA3 = 0x08; -+ jregA8 = 0x02; -+ break; -+ } -+ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa0, 0x8f, jregA0); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xf0, jregA3); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa8, 0xfd, jregA8); -+} -+ -+static void ast_set_crtthd_reg(struct ast_private *ast) -+{ -+ /* Set Threshold */ -+ if (ast->chip == AST2600) { -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0xe0); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0xa0); -+ } else if (ast->chip == AST2300 || ast->chip == AST2400 || -+ ast->chip == AST2500) { -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60); -+ } else if (ast->chip == AST2100 || ast->chip == AST1100 || -+ ast->chip == AST2200 || ast->chip == AST2150) { -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x3f); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x2f); -+ } else { -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x2f); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x1f); -+ } -+} -+ -+static void ast_set_sync_reg(struct ast_private *ast, -+ struct drm_display_mode *mode, -+ struct ast_vbios_mode_info *vbios_mode) -+{ -+ u8 jreg; -+ -+ jreg = ast_io_read8(ast, AST_IO_MISC_PORT_READ); -+ jreg &= ~0xC0; -+ if (vbios_mode->enh_table->flags & NVSync) -+ jreg |= 0x80; -+ if (vbios_mode->enh_table->flags & NHSync) -+ jreg |= 0x40; -+ ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg); -+} -+ -+static void ast_set_start_address_crt1(struct ast_private *ast, -+ unsigned int offset) -+{ -+ u32 addr; -+ -+ addr = offset >> 2; -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x0d, (u8)(addr & 0xff)); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x0c, -+ (u8)((addr >> 8) & 0xff)); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xaf, -+ (u8)((addr >> 16) & 0xff)); -+} -+ -+static void ast_wait_for_vretrace(struct ast_private *ast) -+{ -+ unsigned long timeout = jiffies + HZ; -+ u8 vgair1; -+ -+ do { -+ vgair1 = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ); -+ } while (!(vgair1 & AST_IO_VGAIR1_VREFRESH) && -+ time_before(jiffies, timeout)); -+} -+ -+/* -+ * Primary plane -+ */ -+ -+static const uint32_t ast_primary_plane_formats[] = { -+ DRM_FORMAT_XRGB8888, -+ DRM_FORMAT_RGB565, -+ DRM_FORMAT_C8, -+}; -+ -+static int ast_primary_plane_helper_atomic_check(struct drm_plane *plane, -+ struct drm_atomic_state *state) -+{ -+ struct drm_device *dev = plane->dev; -+ struct drm_plane_state *new_plane_state = -+ drm_atomic_get_new_plane_state(state, plane); -+ struct drm_crtc_state *new_crtc_state = NULL; -+ struct ast_crtc_state *new_ast_crtc_state; -+ int ret; -+ -+ if (new_plane_state->crtc) -+ new_crtc_state = drm_atomic_get_new_crtc_state( -+ state, new_plane_state->crtc); -+ -+ ret = drm_atomic_helper_check_plane_state( -+ new_plane_state, new_crtc_state, DRM_PLANE_NO_SCALING, -+ DRM_PLANE_NO_SCALING, false, true); -+ if (ret) { -+ return ret; -+ } else if (!new_plane_state->visible) { -+ if (drm_WARN_ON( -+ dev, -+ new_plane_state->crtc)) /* cannot legally happen */ -+ return -EINVAL; -+ else -+ return 0; -+ } -+ -+ new_ast_crtc_state = to_ast_crtc_state(new_crtc_state); -+ -+ new_ast_crtc_state->format = new_plane_state->fb->format; -+ -+ return 0; -+} -+ -+static void -+ast_primary_plane_helper_atomic_update(struct drm_plane *plane, -+ struct drm_atomic_state *state) -+{ -+ struct drm_device *dev = plane->dev; -+ struct ast_private *ast = to_ast_private(dev); -+ struct drm_plane_state *plane_state = -+ drm_atomic_get_new_plane_state(state, plane); -+ struct drm_framebuffer *fb = plane_state->fb; -+ struct drm_plane_state *old_plane_state = -+ drm_atomic_get_old_plane_state(state, plane); -+ struct drm_framebuffer *old_fb = old_plane_state->fb; -+ struct drm_gem_vram_object *gbo; -+ s64 gpu_addr; -+ -+ if (!old_fb || (fb->format != old_fb->format)) { -+ struct drm_crtc *crtc = plane_state->crtc; -+ struct drm_crtc_state *crtc_state = -+ drm_atomic_get_new_crtc_state(state, crtc); -+ struct ast_crtc_state *ast_crtc_state = -+ to_ast_crtc_state(crtc_state); -+ struct ast_vbios_mode_info *vbios_mode_info = -+ &ast_crtc_state->vbios_mode_info; -+ -+ ast_set_color_reg(ast, fb->format); -+ ast_set_vbios_color_reg(ast, fb->format, vbios_mode_info); -+ } -+ -+ gbo = drm_gem_vram_of_gem(fb->obj[0]); -+ gpu_addr = drm_gem_vram_offset(gbo); -+ if (drm_WARN_ON_ONCE(dev, gpu_addr < 0)) -+ return; /* Bug: we didn't pin the BO to VRAM in prepare_fb. */ -+ -+ ast_set_offset_reg(ast, fb); -+ ast_set_start_address_crt1(ast, (u32)gpu_addr); -+ -+ ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x00); -+} -+ -+static void -+ast_primary_plane_helper_atomic_disable(struct drm_plane *plane, -+ struct drm_atomic_state *state) -+{ -+ struct ast_private *ast = to_ast_private(plane->dev); -+ -+ ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x20); -+} -+ -+static const struct drm_plane_helper_funcs ast_primary_plane_helper_funcs = { -+ DRM_GEM_VRAM_PLANE_HELPER_FUNCS, -+ .atomic_check = ast_primary_plane_helper_atomic_check, -+ .atomic_update = ast_primary_plane_helper_atomic_update, -+ .atomic_disable = ast_primary_plane_helper_atomic_disable, -+}; -+ -+static const struct drm_plane_funcs ast_primary_plane_funcs = { -+ .update_plane = drm_atomic_helper_update_plane, -+ .disable_plane = drm_atomic_helper_disable_plane, -+ .destroy = drm_plane_cleanup, -+ .reset = drm_atomic_helper_plane_reset, -+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, -+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, -+}; -+ -+static int ast_primary_plane_init(struct ast_private *ast) -+{ -+ struct drm_device *dev = &ast->base; -+ struct drm_plane *primary_plane = &ast->primary_plane; -+ int ret; -+ -+ ret = drm_universal_plane_init(dev, primary_plane, 0x01, -+ &ast_primary_plane_funcs, -+ ast_primary_plane_formats, -+ ARRAY_SIZE(ast_primary_plane_formats), -+ NULL, DRM_PLANE_TYPE_PRIMARY, NULL); -+ if (ret) { -+ drm_err(dev, "drm_universal_plane_init() failed: %d\n", ret); -+ return ret; -+ } -+ drm_plane_helper_add(primary_plane, &ast_primary_plane_helper_funcs); -+ -+ return 0; -+} -+ -+/* -+ * Cursor plane -+ */ -+ -+static void ast_update_cursor_image(u8 __iomem *dst, const u8 *src, int width, -+ int height) -+{ -+ union { -+ u32 ul; -+ u8 b[4]; -+ } srcdata32[2], data32; -+ union { -+ u16 us; -+ u8 b[2]; -+ } data16; -+ u32 csum = 0; -+ s32 alpha_dst_delta, last_alpha_dst_delta; -+ u8 __iomem *dstxor; -+ const u8 *srcxor; -+ int i, j; -+ u32 per_pixel_copy, two_pixel_copy; -+ -+ alpha_dst_delta = AST_MAX_HWC_WIDTH << 1; -+ last_alpha_dst_delta = alpha_dst_delta - (width << 1); -+ -+ srcxor = src; -+ dstxor = (u8 *)dst + last_alpha_dst_delta + -+ (AST_MAX_HWC_HEIGHT - height) * alpha_dst_delta; -+ per_pixel_copy = width & 1; -+ two_pixel_copy = width >> 1; -+ -+ for (j = 0; j < height; j++) { -+ for (i = 0; i < two_pixel_copy; i++) { -+ srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0; -+ srcdata32[1].ul = *((u32 *)(srcxor + 4)) & 0xf0f0f0f0; -+ data32.b[0] = srcdata32[0].b[1] | -+ (srcdata32[0].b[0] >> 4); -+ data32.b[1] = srcdata32[0].b[3] | -+ (srcdata32[0].b[2] >> 4); -+ data32.b[2] = srcdata32[1].b[1] | -+ (srcdata32[1].b[0] >> 4); -+ data32.b[3] = srcdata32[1].b[3] | -+ (srcdata32[1].b[2] >> 4); -+ -+ writel(data32.ul, dstxor); -+ csum += data32.ul; -+ -+ dstxor += 4; -+ srcxor += 8; -+ } -+ -+ for (i = 0; i < per_pixel_copy; i++) { -+ srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0; -+ data16.b[0] = srcdata32[0].b[1] | -+ (srcdata32[0].b[0] >> 4); -+ data16.b[1] = srcdata32[0].b[3] | -+ (srcdata32[0].b[2] >> 4); -+ writew(data16.us, dstxor); -+ csum += (u32)data16.us; -+ -+ dstxor += 2; -+ srcxor += 4; -+ } -+ dstxor += last_alpha_dst_delta; -+ } -+ -+ /* write checksum + signature */ -+ dst += AST_HWC_SIZE; -+ writel(csum, dst); -+ writel(width, dst + AST_HWC_SIGNATURE_SizeX); -+ writel(height, dst + AST_HWC_SIGNATURE_SizeY); -+ writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTX); -+ writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTY); -+} -+ -+static void ast_set_cursor_base(struct ast_private *ast, u64 address) -+{ -+ u8 addr0 = (address >> 3) & 0xff; -+ u8 addr1 = (address >> 11) & 0xff; -+ u8 addr2 = (address >> 19) & 0xff; -+ -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc8, addr0); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc9, addr1); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xca, addr2); -+} -+ -+static void ast_set_cursor_location(struct ast_private *ast, u16 x, u16 y, -+ u8 x_offset, u8 y_offset) -+{ -+ u8 x0 = (x & 0x00ff); -+ u8 x1 = (x & 0x0f00) >> 8; -+ u8 y0 = (y & 0x00ff); -+ u8 y1 = (y & 0x0700) >> 8; -+ -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc2, x_offset); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc3, y_offset); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc4, x0); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc5, x1); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc6, y0); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, y1); -+} -+ -+static void ast_set_cursor_enabled(struct ast_private *ast, bool enabled) -+{ -+ static const u8 mask = -+ (u8) ~(AST_IO_VGACRCB_HWC_16BPP | AST_IO_VGACRCB_HWC_ENABLED); -+ -+ u8 vgacrcb = AST_IO_VGACRCB_HWC_16BPP; -+ -+ if (enabled) -+ vgacrcb |= AST_IO_VGACRCB_HWC_ENABLED; -+ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, mask, vgacrcb); -+} -+ -+static const uint32_t ast_cursor_plane_formats[] = { -+ DRM_FORMAT_ARGB8888, -+}; -+ -+static int ast_cursor_plane_helper_atomic_check(struct drm_plane *plane, -+ struct drm_atomic_state *state) -+{ -+ struct drm_plane_state *new_plane_state = -+ drm_atomic_get_new_plane_state(state, plane); -+ struct drm_framebuffer *new_fb = new_plane_state->fb; -+ struct drm_crtc_state *new_crtc_state = NULL; -+ int ret; -+ -+ if (new_plane_state->crtc) -+ new_crtc_state = drm_atomic_get_new_crtc_state( -+ state, new_plane_state->crtc); -+ -+ ret = drm_atomic_helper_check_plane_state( -+ new_plane_state, new_crtc_state, DRM_PLANE_NO_SCALING, -+ DRM_PLANE_NO_SCALING, true, true); -+ if (ret || !new_plane_state->visible) -+ return ret; -+ -+ if (new_fb->width > AST_MAX_HWC_WIDTH || -+ new_fb->height > AST_MAX_HWC_HEIGHT) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static void -+ast_cursor_plane_helper_atomic_update(struct drm_plane *plane, -+ struct drm_atomic_state *state) -+{ -+ struct ast_plane *ast_plane = to_ast_plane(plane); -+ struct drm_plane_state *plane_state = -+ drm_atomic_get_new_plane_state(state, plane); -+ struct drm_shadow_plane_state *shadow_plane_state = -+ to_drm_shadow_plane_state(plane_state); -+ struct drm_framebuffer *fb = plane_state->fb; -+ struct drm_plane_state *old_plane_state = -+ drm_atomic_get_old_plane_state(state, plane); -+ struct drm_framebuffer *old_fb = old_plane_state->fb; -+ struct ast_private *ast = to_ast_private(plane->dev); -+ struct iosys_map dst_map = ast_plane->map; -+ u64 dst_off = ast_plane->off; -+ struct iosys_map src_map = shadow_plane_state->data[0]; -+ unsigned int offset_x, offset_y; -+ u16 x, y; -+ u8 x_offset, y_offset; -+ u8 __iomem *dst; -+ u8 __iomem *sig; -+ const u8 *src; -+ -+ src = src_map.vaddr; /* TODO: Use mapping abstraction properly */ -+ dst = dst_map.vaddr_iomem; /* TODO: Use mapping abstraction properly */ -+ sig = dst + AST_HWC_SIZE; /* TODO: Use mapping abstraction properly */ -+ -+ /* -+ * Do data transfer to HW cursor BO. If a new cursor image was installed, -+ * point the scanout engine to dst_gbo's offset and page-flip the HWC buffers. -+ */ -+ -+ ast_update_cursor_image(dst, src, fb->width, fb->height); -+ -+ if (fb != old_fb) -+ ast_set_cursor_base(ast, dst_off); -+ -+ /* -+ * Update location in HWC signature and registers. -+ */ -+ -+ writel(plane_state->crtc_x, sig + AST_HWC_SIGNATURE_X); -+ writel(plane_state->crtc_y, sig + AST_HWC_SIGNATURE_Y); -+ -+ offset_x = AST_MAX_HWC_WIDTH - fb->width; -+ offset_y = AST_MAX_HWC_HEIGHT - fb->height; -+ -+ if (plane_state->crtc_x < 0) { -+ x_offset = (-plane_state->crtc_x) + offset_x; -+ x = 0; -+ } else { -+ x_offset = offset_x; -+ x = plane_state->crtc_x; -+ } -+ if (plane_state->crtc_y < 0) { -+ y_offset = (-plane_state->crtc_y) + offset_y; -+ y = 0; -+ } else { -+ y_offset = offset_y; -+ y = plane_state->crtc_y; -+ } -+ -+ ast_set_cursor_location(ast, x, y, x_offset, y_offset); -+ -+ /* Dummy write to enable HWC and make the HW pick-up the changes. */ -+ ast_set_cursor_enabled(ast, true); -+} -+ -+static void -+ast_cursor_plane_helper_atomic_disable(struct drm_plane *plane, -+ struct drm_atomic_state *state) -+{ -+ struct ast_private *ast = to_ast_private(plane->dev); -+ -+ ast_set_cursor_enabled(ast, false); -+} -+ -+static const struct drm_plane_helper_funcs ast_cursor_plane_helper_funcs = { -+ DRM_GEM_SHADOW_PLANE_HELPER_FUNCS, -+ .atomic_check = ast_cursor_plane_helper_atomic_check, -+ .atomic_update = ast_cursor_plane_helper_atomic_update, -+ .atomic_disable = ast_cursor_plane_helper_atomic_disable, -+}; -+ -+static void ast_cursor_plane_destroy(struct drm_plane *plane) -+{ -+ struct ast_plane *ast_plane = to_ast_plane(plane); -+ struct drm_gem_vram_object *gbo = ast_plane->gbo; -+ struct iosys_map map = ast_plane->map; -+ -+ drm_gem_vram_vunmap(gbo, &map); -+ drm_gem_vram_unpin(gbo); -+ drm_gem_vram_put(gbo); -+ -+ drm_plane_cleanup(plane); -+} -+ -+static const struct drm_plane_funcs ast_cursor_plane_funcs = { -+ .update_plane = drm_atomic_helper_update_plane, -+ .disable_plane = drm_atomic_helper_disable_plane, -+ .destroy = ast_cursor_plane_destroy, -+ DRM_GEM_SHADOW_PLANE_FUNCS, -+}; -+ -+static int ast_cursor_plane_init(struct ast_private *ast) -+{ -+ struct drm_device *dev = &ast->base; -+ struct ast_plane *ast_plane = &ast->cursor_plane; -+ struct drm_plane *cursor_plane = &ast_plane->base; -+ size_t size; -+ struct drm_gem_vram_object *gbo; -+ struct iosys_map map; -+ int ret; -+ s64 off; -+ -+ /* -+ * Allocate backing storage for cursors. The BOs are permanently -+ * pinned to the top end of the VRAM. -+ */ -+ -+ size = roundup(AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE, PAGE_SIZE); -+ -+ gbo = drm_gem_vram_create(dev, size, 0); -+ if (IS_ERR(gbo)) -+ return PTR_ERR(gbo); -+ -+ ret = drm_gem_vram_pin(gbo, DRM_GEM_VRAM_PL_FLAG_VRAM | -+ DRM_GEM_VRAM_PL_FLAG_TOPDOWN); -+ if (ret) -+ goto err_drm_gem_vram_put; -+ ret = drm_gem_vram_vmap(gbo, &map); -+ if (ret) -+ goto err_drm_gem_vram_unpin; -+ off = drm_gem_vram_offset(gbo); -+ if (off < 0) { -+ ret = off; -+ goto err_drm_gem_vram_vunmap; -+ } -+ -+ ast_plane->gbo = gbo; -+ ast_plane->map = map; -+ ast_plane->off = off; -+ -+ /* -+ * Create the cursor plane. The plane's destroy callback will release -+ * the backing storages' BO memory. -+ */ -+ -+ ret = drm_universal_plane_init(dev, cursor_plane, 0x01, -+ &ast_cursor_plane_funcs, -+ ast_cursor_plane_formats, -+ ARRAY_SIZE(ast_cursor_plane_formats), -+ NULL, DRM_PLANE_TYPE_CURSOR, NULL); -+ if (ret) { -+ drm_err(dev, "drm_universal_plane failed(): %d\n", ret); -+ goto err_drm_gem_vram_vunmap; -+ } -+ drm_plane_helper_add(cursor_plane, &ast_cursor_plane_helper_funcs); -+ -+ return 0; -+ -+err_drm_gem_vram_vunmap: -+ drm_gem_vram_vunmap(gbo, &map); -+err_drm_gem_vram_unpin: -+ drm_gem_vram_unpin(gbo); -+err_drm_gem_vram_put: -+ drm_gem_vram_put(gbo); -+ return ret; -+} -+ -+/* -+ * CRTC -+ */ -+ -+static void ast_crtc_dpms(struct drm_crtc *crtc, int mode) -+{ -+ struct ast_private *ast = to_ast_private(crtc->dev); -+ u8 ch = AST_DPMS_VSYNC_OFF | AST_DPMS_HSYNC_OFF; -+ struct ast_crtc_state *ast_state; -+ const struct drm_format_info *format; -+ struct ast_vbios_mode_info *vbios_mode_info; -+ -+ /* TODO: Maybe control display signal generation with -+ * Sync Enable (bit CR17.7). -+ */ -+ switch (mode) { -+ case DRM_MODE_DPMS_ON: -+ ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x01, 0xdf, 0); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xfc, 0); -+ if (ast->tx_chip_types & AST_TX_DP501_BIT) -+ ast_set_dp501_video_output(crtc->dev, 1); -+ -+ if (ast->tx_chip_types & AST_TX_ASTDP_BIT) { -+ ast_dp_power_on_off(crtc->dev, AST_DP_POWER_ON); -+ ast_wait_for_vretrace(ast); -+ ast_dp_set_on_off(crtc->dev, 1); -+ } -+ -+ ast_state = to_ast_crtc_state(crtc->state); -+ format = ast_state->format; -+ -+ if (format) { -+ vbios_mode_info = &ast_state->vbios_mode_info; -+ -+ ast_set_color_reg(ast, format); -+ ast_set_vbios_color_reg(ast, format, vbios_mode_info); -+ if (crtc->state->gamma_lut) -+ ast_crtc_set_gamma( -+ ast, format, -+ crtc->state->gamma_lut->data); -+ else -+ ast_crtc_set_gamma_linear(ast, format); -+ } -+ break; -+ case DRM_MODE_DPMS_STANDBY: -+ case DRM_MODE_DPMS_SUSPEND: -+ case DRM_MODE_DPMS_OFF: -+ ch = mode; -+ if (ast->tx_chip_types & AST_TX_DP501_BIT) -+ ast_set_dp501_video_output(crtc->dev, 0); -+ -+ if (ast->tx_chip_types & AST_TX_ASTDP_BIT) { -+ ast_dp_set_on_off(crtc->dev, 0); -+ ast_dp_power_on_off(crtc->dev, AST_DP_POWER_OFF); -+ } -+ -+ ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x01, 0xdf, 0x20); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xfc, ch); -+ break; -+ } -+} -+ -+static enum drm_mode_status -+ast_crtc_helper_mode_valid(struct drm_crtc *crtc, -+ const struct drm_display_mode *mode) -+{ -+ struct ast_private *ast = to_ast_private(crtc->dev); -+ enum drm_mode_status status; -+ uint32_t jtemp; -+ -+ if (ast->support_wide_screen) { -+ if ((mode->hdisplay == 1680) && (mode->vdisplay == 1050)) -+ return MODE_OK; -+ if ((mode->hdisplay == 1280) && (mode->vdisplay == 800)) -+ return MODE_OK; -+ if ((mode->hdisplay == 1440) && (mode->vdisplay == 900)) -+ return MODE_OK; -+ if ((mode->hdisplay == 1360) && (mode->vdisplay == 768)) -+ return MODE_OK; -+ if ((mode->hdisplay == 1600) && (mode->vdisplay == 900)) -+ return MODE_OK; -+ if ((mode->hdisplay == 1152) && (mode->vdisplay == 864)) -+ return MODE_OK; -+ -+ if ((ast->chip == AST2100) || (ast->chip == AST2200) || -+ (ast->chip == AST2300) || (ast->chip == AST2400) || -+ (ast->chip == AST2500) || (ast->chip == AST2600)) { -+ if ((mode->hdisplay == 1920) && -+ (mode->vdisplay == 1080)) -+ return MODE_OK; -+ -+ if ((mode->hdisplay == 1920) && -+ (mode->vdisplay == 1200)) { -+ jtemp = ast_get_index_reg_mask( -+ ast, AST_IO_CRTC_PORT, 0xd1, 0xff); -+ if (jtemp & 0x01) -+ return MODE_NOMODE; -+ else -+ return MODE_OK; -+ } -+ } -+ } -+ -+ status = MODE_NOMODE; -+ -+ switch (mode->hdisplay) { -+ case 640: -+ if (mode->vdisplay == 480) -+ status = MODE_OK; -+ break; -+ case 800: -+ if (mode->vdisplay == 600) -+ status = MODE_OK; -+ break; -+ case 1024: -+ if (mode->vdisplay == 768) -+ status = MODE_OK; -+ break; -+ case 1152: -+ if (mode->vdisplay == 864) -+ status = MODE_OK; -+ break; -+ case 1280: -+ if (mode->vdisplay == 1024) -+ status = MODE_OK; -+ break; -+ case 1600: -+ if (mode->vdisplay == 1200) -+ status = MODE_OK; -+ break; -+ default: -+ break; -+ } -+ -+ return status; -+} -+ -+static int ast_crtc_helper_atomic_check(struct drm_crtc *crtc, -+ struct drm_atomic_state *state) -+{ -+ struct drm_crtc_state *crtc_state = -+ drm_atomic_get_new_crtc_state(state, crtc); -+ struct drm_crtc_state *old_crtc_state = -+ drm_atomic_get_old_crtc_state(state, crtc); -+ struct ast_crtc_state *old_ast_crtc_state = -+ to_ast_crtc_state(old_crtc_state); -+ struct drm_device *dev = crtc->dev; -+ struct ast_crtc_state *ast_state; -+ const struct drm_format_info *format; -+ bool succ; -+ int ret; -+ -+ if (!crtc_state->enable) -+ return 0; -+ -+ ret = drm_atomic_helper_check_crtc_primary_plane(crtc_state); -+ if (ret) -+ return ret; -+ -+ ast_state = to_ast_crtc_state(crtc_state); -+ -+ format = ast_state->format; -+ if (drm_WARN_ON_ONCE(dev, !format)) -+ return -EINVAL; /* BUG: We didn't set format in primary check(). */ -+ -+ /* -+ * The gamma LUT has to be reloaded after changing the primary -+ * plane's color format. -+ */ -+ if (old_ast_crtc_state->format != format) -+ crtc_state->color_mgmt_changed = true; -+ -+ if (crtc_state->color_mgmt_changed && crtc_state->gamma_lut) { -+ if (crtc_state->gamma_lut->length != -+ AST_LUT_SIZE * sizeof(struct drm_color_lut)) { -+ drm_err(dev, "Wrong size for gamma_lut %zu\n", -+ crtc_state->gamma_lut->length); -+ return -EINVAL; -+ } -+ } -+ -+ succ = ast_get_vbios_mode_info(format, &crtc_state->mode, -+ &crtc_state->adjusted_mode, -+ &ast_state->vbios_mode_info); -+ if (!succ) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static void ast_crtc_helper_atomic_flush(struct drm_crtc *crtc, -+ struct drm_atomic_state *state) -+{ -+ struct drm_crtc_state *crtc_state = -+ drm_atomic_get_new_crtc_state(state, crtc); -+ struct drm_device *dev = crtc->dev; -+ struct ast_private *ast = to_ast_private(dev); -+ struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); -+ struct ast_vbios_mode_info *vbios_mode_info = -+ &ast_crtc_state->vbios_mode_info; -+ -+ /* -+ * The gamma LUT has to be reloaded after changing the primary -+ * plane's color format. -+ */ -+ if (crtc_state->enable && crtc_state->color_mgmt_changed) { -+ if (crtc_state->gamma_lut) -+ ast_crtc_set_gamma(ast, ast_crtc_state->format, -+ crtc_state->gamma_lut->data); -+ else -+ ast_crtc_set_gamma_linear(ast, ast_crtc_state->format); -+ } -+ -+ //Set Aspeed Display-Port -+ if (ast->tx_chip_types & AST_TX_ASTDP_BIT) -+ ast_dp_set_mode(crtc, vbios_mode_info); -+} -+ -+static void ast_crtc_helper_atomic_enable(struct drm_crtc *crtc, -+ struct drm_atomic_state *state) -+{ -+ struct drm_device *dev = crtc->dev; -+ struct ast_private *ast = to_ast_private(dev); -+ struct drm_crtc_state *crtc_state = -+ drm_atomic_get_new_crtc_state(state, crtc); -+ struct ast_crtc_state *ast_crtc_state = to_ast_crtc_state(crtc_state); -+ struct ast_vbios_mode_info *vbios_mode_info = -+ &ast_crtc_state->vbios_mode_info; -+ struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; -+ -+ ast_set_vbios_mode_reg(ast, adjusted_mode, vbios_mode_info); -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x06); -+ ast_set_std_reg(ast, adjusted_mode, vbios_mode_info); -+ ast_set_crtc_reg(ast, adjusted_mode, vbios_mode_info); -+ ast_set_dclk_reg(ast, adjusted_mode, vbios_mode_info); -+ ast_set_crtthd_reg(ast); -+ ast_set_sync_reg(ast, adjusted_mode, vbios_mode_info); -+ -+ ast_crtc_dpms(crtc, DRM_MODE_DPMS_ON); -+} -+ -+static void ast_crtc_helper_atomic_disable(struct drm_crtc *crtc, -+ struct drm_atomic_state *state) -+{ -+ struct drm_crtc_state *old_crtc_state = -+ drm_atomic_get_old_crtc_state(state, crtc); -+ struct drm_device *dev = crtc->dev; -+ struct ast_private *ast = to_ast_private(dev); -+ -+ ast_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); -+ -+ /* -+ * HW cursors require the underlying primary plane and CRTC to -+ * display a valid mode and image. This is not the case during -+ * full modeset operations. So we temporarily disable any active -+ * plane, including the HW cursor. Each plane's atomic_update() -+ * helper will re-enable it if necessary. -+ * -+ * We only do this during *full* modesets. It does not affect -+ * simple pageflips on the planes. -+ */ -+ drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false); -+ -+ /* -+ * Ensure that no scanout takes place before reprogramming mode -+ * and format registers. -+ */ -+ ast_wait_for_vretrace(ast); -+} -+ -+static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = { -+ .mode_valid = ast_crtc_helper_mode_valid, -+ .atomic_check = ast_crtc_helper_atomic_check, -+ .atomic_flush = ast_crtc_helper_atomic_flush, -+ .atomic_enable = ast_crtc_helper_atomic_enable, -+ .atomic_disable = ast_crtc_helper_atomic_disable, -+}; -+ -+static void ast_crtc_reset(struct drm_crtc *crtc) -+{ -+ struct ast_crtc_state *ast_state = -+ kzalloc(sizeof(*ast_state), GFP_KERNEL); -+ -+ if (crtc->state) -+ crtc->funcs->atomic_destroy_state(crtc, crtc->state); -+ -+ if (ast_state) -+ __drm_atomic_helper_crtc_reset(crtc, &ast_state->base); -+ else -+ __drm_atomic_helper_crtc_reset(crtc, NULL); -+} -+ -+static struct drm_crtc_state * -+ast_crtc_atomic_duplicate_state(struct drm_crtc *crtc) -+{ -+ struct ast_crtc_state *new_ast_state, *ast_state; -+ struct drm_device *dev = crtc->dev; -+ -+ if (drm_WARN_ON(dev, !crtc->state)) -+ return NULL; -+ -+ new_ast_state = kmalloc(sizeof(*new_ast_state), GFP_KERNEL); -+ if (!new_ast_state) -+ return NULL; -+ __drm_atomic_helper_crtc_duplicate_state(crtc, &new_ast_state->base); -+ -+ ast_state = to_ast_crtc_state(crtc->state); -+ -+ new_ast_state->format = ast_state->format; -+ memcpy(&new_ast_state->vbios_mode_info, &ast_state->vbios_mode_info, -+ sizeof(new_ast_state->vbios_mode_info)); -+ -+ return &new_ast_state->base; -+} -+ -+static void ast_crtc_atomic_destroy_state(struct drm_crtc *crtc, -+ struct drm_crtc_state *state) -+{ -+ struct ast_crtc_state *ast_state = to_ast_crtc_state(state); -+ -+ __drm_atomic_helper_crtc_destroy_state(&ast_state->base); -+ kfree(ast_state); -+} -+ -+static const struct drm_crtc_funcs ast_crtc_funcs = { -+ .reset = ast_crtc_reset, -+ .destroy = drm_crtc_cleanup, -+ .set_config = drm_atomic_helper_set_config, -+ .page_flip = drm_atomic_helper_page_flip, -+ .atomic_duplicate_state = ast_crtc_atomic_duplicate_state, -+ .atomic_destroy_state = ast_crtc_atomic_destroy_state, -+}; -+ -+static int ast_crtc_init(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ struct drm_crtc *crtc = &ast->crtc; -+ int ret; -+ -+ ret = drm_crtc_init_with_planes(dev, crtc, &ast->primary_plane, -+ &ast->cursor_plane.base, -+ &ast_crtc_funcs, NULL); -+ if (ret) -+ return ret; -+ -+ drm_mode_crtc_set_gamma_size(crtc, AST_LUT_SIZE); -+ drm_crtc_enable_color_mgmt(crtc, 0, false, AST_LUT_SIZE); -+ -+ drm_crtc_helper_add(crtc, &ast_crtc_helper_funcs); -+ -+ return 0; -+} -+ -+/* -+ * VGA Connector -+ */ -+ -+static int ast_vga_connector_helper_get_modes(struct drm_connector *connector) -+{ -+ struct ast_vga_connector *ast_vga_connector = -+ to_ast_vga_connector(connector); -+ struct drm_device *dev = connector->dev; -+ struct ast_private *ast = to_ast_private(dev); -+ struct edid *edid; -+ int count; -+ -+ if (!ast_vga_connector->i2c) -+ goto err_drm_connector_update_edid_property; -+ -+ /* -+ * Protect access to I/O registers from concurrent modesetting -+ * by acquiring the I/O-register lock. -+ */ -+ mutex_lock(&ast->ioregs_lock); -+ -+ edid = drm_get_edid(connector, &ast_vga_connector->i2c->adapter); -+ if (!edid) -+ goto err_mutex_unlock; -+ -+ mutex_unlock(&ast->ioregs_lock); -+ -+ count = drm_add_edid_modes(connector, edid); -+ kfree(edid); -+ -+ return count; -+ -+err_mutex_unlock: -+ mutex_unlock(&ast->ioregs_lock); -+err_drm_connector_update_edid_property: -+ drm_connector_update_edid_property(connector, NULL); -+ return 0; -+} -+ -+static const struct drm_connector_helper_funcs ast_vga_connector_helper_funcs = { -+ .get_modes = ast_vga_connector_helper_get_modes, -+}; -+ -+static const struct drm_connector_funcs ast_vga_connector_funcs = { -+ .reset = drm_atomic_helper_connector_reset, -+ .fill_modes = drm_helper_probe_single_connector_modes, -+ .destroy = drm_connector_cleanup, -+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -+}; -+ -+static int ast_vga_connector_init(struct drm_device *dev, -+ struct ast_vga_connector *ast_vga_connector) -+{ -+ struct drm_connector *connector = &ast_vga_connector->base; -+ int ret; -+ -+ ast_vga_connector->i2c = ast_i2c_create(dev); -+ if (!ast_vga_connector->i2c) -+ drm_err(dev, "failed to add ddc bus for connector\n"); -+ -+ if (ast_vga_connector->i2c) -+ ret = drm_connector_init_with_ddc( -+ dev, connector, &ast_vga_connector_funcs, -+ DRM_MODE_CONNECTOR_VGA, -+ &ast_vga_connector->i2c->adapter); -+ else -+ ret = drm_connector_init(dev, connector, -+ &ast_vga_connector_funcs, -+ DRM_MODE_CONNECTOR_VGA); -+ if (ret) -+ return ret; -+ -+ drm_connector_helper_add(connector, &ast_vga_connector_helper_funcs); -+ -+ connector->interlace_allowed = 0; -+ connector->doublescan_allowed = 0; -+ -+ connector->polled = DRM_CONNECTOR_POLL_CONNECT; -+ -+ return 0; -+} -+ -+static int ast_vga_output_init(struct ast_private *ast) -+{ -+ struct drm_device *dev = &ast->base; -+ struct drm_crtc *crtc = &ast->crtc; -+ struct drm_encoder *encoder = &ast->output.vga.encoder; -+ struct ast_vga_connector *ast_vga_connector = -+ &ast->output.vga.vga_connector; -+ struct drm_connector *connector = &ast_vga_connector->base; -+ int ret; -+ -+ ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_DAC); -+ if (ret) -+ return ret; -+ encoder->possible_crtcs = drm_crtc_mask(crtc); -+ -+ ret = ast_vga_connector_init(dev, ast_vga_connector); -+ if (ret) -+ return ret; -+ -+ ret = drm_connector_attach_encoder(connector, encoder); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+/* -+ * SIL164 Connector -+ */ -+ -+static int -+ast_sil164_connector_helper_get_modes(struct drm_connector *connector) -+{ -+ struct ast_sil164_connector *ast_sil164_connector = -+ to_ast_sil164_connector(connector); -+ struct drm_device *dev = connector->dev; -+ struct ast_private *ast = to_ast_private(dev); -+ struct edid *edid; -+ int count; -+ -+ if (!ast_sil164_connector->i2c) -+ goto err_drm_connector_update_edid_property; -+ -+ /* -+ * Protect access to I/O registers from concurrent modesetting -+ * by acquiring the I/O-register lock. -+ */ -+ mutex_lock(&ast->ioregs_lock); -+ -+ edid = drm_get_edid(connector, &ast_sil164_connector->i2c->adapter); -+ if (!edid) -+ goto err_mutex_unlock; -+ -+ mutex_unlock(&ast->ioregs_lock); -+ -+ count = drm_add_edid_modes(connector, edid); -+ kfree(edid); -+ -+ return count; -+ -+err_mutex_unlock: -+ mutex_unlock(&ast->ioregs_lock); -+err_drm_connector_update_edid_property: -+ drm_connector_update_edid_property(connector, NULL); -+ return 0; -+} -+ -+static const struct drm_connector_helper_funcs -+ ast_sil164_connector_helper_funcs = { -+ .get_modes = ast_sil164_connector_helper_get_modes, -+ }; -+ -+static const struct drm_connector_funcs ast_sil164_connector_funcs = { -+ .reset = drm_atomic_helper_connector_reset, -+ .fill_modes = drm_helper_probe_single_connector_modes, -+ .destroy = drm_connector_cleanup, -+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -+}; -+ -+static int -+ast_sil164_connector_init(struct drm_device *dev, -+ struct ast_sil164_connector *ast_sil164_connector) -+{ -+ struct drm_connector *connector = &ast_sil164_connector->base; -+ int ret; -+ -+ ast_sil164_connector->i2c = ast_i2c_create(dev); -+ if (!ast_sil164_connector->i2c) -+ drm_err(dev, "failed to add ddc bus for connector\n"); -+ -+ if (ast_sil164_connector->i2c) -+ ret = drm_connector_init_with_ddc( -+ dev, connector, &ast_sil164_connector_funcs, -+ DRM_MODE_CONNECTOR_DVII, -+ &ast_sil164_connector->i2c->adapter); -+ else -+ ret = drm_connector_init(dev, connector, -+ &ast_sil164_connector_funcs, -+ DRM_MODE_CONNECTOR_DVII); -+ if (ret) -+ return ret; -+ -+ drm_connector_helper_add(connector, &ast_sil164_connector_helper_funcs); -+ -+ connector->interlace_allowed = 0; -+ connector->doublescan_allowed = 0; -+ -+ connector->polled = DRM_CONNECTOR_POLL_CONNECT; -+ -+ return 0; -+} -+ -+static int ast_sil164_output_init(struct ast_private *ast) -+{ -+ struct drm_device *dev = &ast->base; -+ struct drm_crtc *crtc = &ast->crtc; -+ struct drm_encoder *encoder = &ast->output.sil164.encoder; -+ struct ast_sil164_connector *ast_sil164_connector = -+ &ast->output.sil164.sil164_connector; -+ struct drm_connector *connector = &ast_sil164_connector->base; -+ int ret; -+ -+ ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS); -+ if (ret) -+ return ret; -+ encoder->possible_crtcs = drm_crtc_mask(crtc); -+ -+ ret = ast_sil164_connector_init(dev, ast_sil164_connector); -+ if (ret) -+ return ret; -+ -+ ret = drm_connector_attach_encoder(connector, encoder); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+/* -+ * DP501 Connector -+ */ -+ -+static int ast_dp501_connector_helper_get_modes(struct drm_connector *connector) -+{ -+ void *edid; -+ bool succ; -+ int count; -+ -+ edid = kmalloc(EDID_LENGTH, GFP_KERNEL); -+ if (!edid) -+ goto err_drm_connector_update_edid_property; -+ -+ succ = ast_dp501_read_edid(connector->dev, edid); -+ if (!succ) -+ goto err_kfree; -+ -+ drm_connector_update_edid_property(connector, edid); -+ count = drm_add_edid_modes(connector, edid); -+ kfree(edid); -+ -+ return count; -+ -+err_kfree: -+ kfree(edid); -+err_drm_connector_update_edid_property: -+ drm_connector_update_edid_property(connector, NULL); -+ return 0; -+} -+ -+static const struct drm_connector_helper_funcs -+ ast_dp501_connector_helper_funcs = { -+ .get_modes = ast_dp501_connector_helper_get_modes, -+ }; -+ -+static const struct drm_connector_funcs ast_dp501_connector_funcs = { -+ .reset = drm_atomic_helper_connector_reset, -+ .fill_modes = drm_helper_probe_single_connector_modes, -+ .destroy = drm_connector_cleanup, -+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -+}; -+ -+static int ast_dp501_connector_init(struct drm_device *dev, -+ struct drm_connector *connector) -+{ -+ int ret; -+ -+ ret = drm_connector_init(dev, connector, &ast_dp501_connector_funcs, -+ DRM_MODE_CONNECTOR_DisplayPort); -+ if (ret) -+ return ret; -+ -+ drm_connector_helper_add(connector, &ast_dp501_connector_helper_funcs); -+ -+ connector->interlace_allowed = 0; -+ connector->doublescan_allowed = 0; -+ -+ connector->polled = DRM_CONNECTOR_POLL_CONNECT; -+ -+ return 0; -+} -+ -+static int ast_dp501_output_init(struct ast_private *ast) -+{ -+ struct drm_device *dev = &ast->base; -+ struct drm_crtc *crtc = &ast->crtc; -+ struct drm_encoder *encoder = &ast->output.dp501.encoder; -+ struct drm_connector *connector = &ast->output.dp501.connector; -+ int ret; -+ -+ ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS); -+ if (ret) -+ return ret; -+ encoder->possible_crtcs = drm_crtc_mask(crtc); -+ -+ ret = ast_dp501_connector_init(dev, connector); -+ if (ret) -+ return ret; -+ -+ ret = drm_connector_attach_encoder(connector, encoder); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+/* -+ * ASPEED Display-Port Connector -+ */ -+ -+static int ast_astdp_connector_helper_get_modes(struct drm_connector *connector) -+{ -+ void *edid; -+ -+ int succ; -+ int count; -+ -+ edid = kmalloc(EDID_LENGTH, GFP_KERNEL); -+ if (!edid) -+ goto err_drm_connector_update_edid_property; -+ -+ succ = ast_astdp_read_edid(connector->dev, edid); -+ if (succ < 0) -+ goto err_kfree; -+ -+ drm_connector_update_edid_property(connector, edid); -+ count = drm_add_edid_modes(connector, edid); -+ kfree(edid); -+ -+ return count; -+ -+err_kfree: -+ kfree(edid); -+err_drm_connector_update_edid_property: -+ drm_connector_update_edid_property(connector, NULL); -+ return 0; -+} -+ -+static const struct drm_connector_helper_funcs -+ ast_astdp_connector_helper_funcs = { -+ .get_modes = ast_astdp_connector_helper_get_modes, -+ }; -+ -+static const struct drm_connector_funcs ast_astdp_connector_funcs = { -+ .reset = drm_atomic_helper_connector_reset, -+ .fill_modes = drm_helper_probe_single_connector_modes, -+ .destroy = drm_connector_cleanup, -+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, -+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -+}; -+ -+static int ast_astdp_connector_init(struct drm_device *dev, -+ struct drm_connector *connector) -+{ -+ int ret; -+ -+ ret = drm_connector_init(dev, connector, &ast_astdp_connector_funcs, -+ DRM_MODE_CONNECTOR_DisplayPort); -+ if (ret) -+ return ret; -+ -+ drm_connector_helper_add(connector, &ast_astdp_connector_helper_funcs); -+ -+ connector->interlace_allowed = 0; -+ connector->doublescan_allowed = 0; -+ -+ connector->polled = DRM_CONNECTOR_POLL_CONNECT; -+ -+ return 0; -+} -+ -+static int ast_astdp_output_init(struct ast_private *ast) -+{ -+ struct drm_device *dev = &ast->base; -+ struct drm_crtc *crtc = &ast->crtc; -+ struct drm_encoder *encoder = &ast->output.astdp.encoder; -+ struct drm_connector *connector = &ast->output.astdp.connector; -+ int ret; -+ -+ ret = drm_simple_encoder_init(dev, encoder, DRM_MODE_ENCODER_TMDS); -+ if (ret) -+ return ret; -+ encoder->possible_crtcs = drm_crtc_mask(crtc); -+ -+ ret = ast_astdp_connector_init(dev, connector); -+ if (ret) -+ return ret; -+ -+ ret = drm_connector_attach_encoder(connector, encoder); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+/* -+ * Mode config -+ */ -+ -+static void -+ast_mode_config_helper_atomic_commit_tail(struct drm_atomic_state *state) -+{ -+ struct ast_private *ast = to_ast_private(state->dev); -+ -+ /* -+ * Concurrent operations could possibly trigger a call to -+ * drm_connector_helper_funcs.get_modes by trying to read the -+ * display modes. Protect access to I/O registers by acquiring -+ * the I/O-register lock. Released in atomic_flush(). -+ */ -+ mutex_lock(&ast->ioregs_lock); -+ drm_atomic_helper_commit_tail_rpm(state); -+ mutex_unlock(&ast->ioregs_lock); -+} -+ -+static const struct drm_mode_config_helper_funcs ast_mode_config_helper_funcs = { -+ .atomic_commit_tail = ast_mode_config_helper_atomic_commit_tail, -+}; -+ -+static const struct drm_mode_config_funcs ast_mode_config_funcs = { -+ .fb_create = drm_gem_fb_create, -+ .mode_valid = drm_vram_helper_mode_valid, -+ .atomic_check = drm_atomic_helper_check, -+ .atomic_commit = drm_atomic_helper_commit, -+}; -+ -+int ast_mode_config_init(struct ast_private *ast) -+{ -+ struct drm_device *dev = &ast->base; -+ int ret; -+ -+ ret = drmm_mode_config_init(dev); -+ if (ret) -+ return ret; -+ -+ dev->mode_config.funcs = &ast_mode_config_funcs; -+ dev->mode_config.min_width = 0; -+ dev->mode_config.min_height = 0; -+ dev->mode_config.preferred_depth = 24; -+ dev->mode_config.prefer_shadow = 1; -+ -+ if (ast->chip == AST2100 || ast->chip == AST2200 || -+ ast->chip == AST2300 || ast->chip == AST2400 || -+ ast->chip == AST2500 || ast->chip == AST2600) { -+ dev->mode_config.max_width = 1920; -+ dev->mode_config.max_height = 2048; -+ } else { -+ dev->mode_config.max_width = 1600; -+ dev->mode_config.max_height = 1200; -+ } -+ -+ dev->mode_config.helper_private = &ast_mode_config_helper_funcs; -+ -+ ret = ast_primary_plane_init(ast); -+ if (ret) -+ return ret; -+ -+ ret = ast_cursor_plane_init(ast); -+ if (ret) -+ return ret; -+ -+ ast_crtc_init(dev); -+ -+ if (ast->tx_chip_types & AST_TX_NONE_BIT) { -+ ret = ast_vga_output_init(ast); -+ if (ret) -+ return ret; -+ } -+ if (ast->tx_chip_types & AST_TX_SIL164_BIT) { -+ ret = ast_sil164_output_init(ast); -+ if (ret) -+ return ret; -+ } -+ if (ast->tx_chip_types & AST_TX_DP501_BIT) { -+ ret = ast_dp501_output_init(ast); -+ if (ret) -+ return ret; -+ } -+ if (ast->tx_chip_types & AST_TX_ASTDP_BIT) { -+ ret = ast_astdp_output_init(ast); -+ if (ret) -+ return ret; -+ } -+ -+ drm_mode_config_reset(dev); -+ -+ return 0; -+} -diff --git a/drivers/gpu/drm/loongson/ast_old/ast_post.c b/drivers/gpu/drm/loongson/ast_old/ast_post.c -new file mode 100644 -index 0000000..a7a9c37 ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/ast_post.c -@@ -0,0 +1,2090 @@ -+/* -+ * Copyright 2012 Red Hat Inc. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sub license, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL -+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, -+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -+ * USE OR OTHER DEALINGS IN THE SOFTWARE. -+ * -+ * The above copyright notice and this permission notice (including the -+ * next paragraph) shall be included in all copies or substantial portions -+ * of the Software. -+ * -+ */ -+/* -+ * Authors: Dave Airlie <airlied@redhat.com> -+ */ -+ -+#include <linux/delay.h> -+#include <linux/pci.h> -+ -+#include <drm/drm_print.h> -+ -+#include "ast_dram_tables.h" -+#include "ast_drv.h" -+ -+static void ast_post_chip_2300(struct drm_device *dev); -+static void ast_post_chip_2500(struct drm_device *dev); -+ -+void ast_enable_vga(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ -+ ast_io_write8(ast, AST_IO_VGA_ENABLE_PORT, 0x01); -+ ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, 0x01); -+} -+ -+void ast_enable_mmio(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa1, 0x06); -+} -+ -+bool ast_is_vga_enabled(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ u8 ch; -+ -+ ch = ast_io_read8(ast, AST_IO_VGA_ENABLE_PORT); -+ -+ return !!(ch & 0x01); -+} -+ -+static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff }; -+static const u8 extreginfo_ast2300a0[] = { 0x0f, 0x04, 0x1c, 0xff }; -+static const u8 extreginfo_ast2300[] = { 0x0f, 0x04, 0x1f, 0xff }; -+ -+static void ast_set_def_ext_reg(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ struct pci_dev *pdev = to_pci_dev(dev->dev); -+ u8 i, index, reg; -+ const u8 *ext_reg_info; -+ -+ /* reset scratch */ -+ for (i = 0x81; i <= 0x9f; i++) -+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, 0x00); -+ -+ if (ast->chip == AST2300 || ast->chip == AST2400 || -+ ast->chip == AST2500) { -+ if (pdev->revision >= 0x20) -+ ext_reg_info = extreginfo_ast2300; -+ else -+ ext_reg_info = extreginfo_ast2300a0; -+ } else -+ ext_reg_info = extreginfo; -+ -+ index = 0xa0; -+ while (*ext_reg_info != 0xff) { -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, index, 0x00, -+ *ext_reg_info); -+ index++; -+ ext_reg_info++; -+ } -+ -+ /* disable standard IO/MEM decode if secondary */ -+ /* ast_set_index_reg-mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x3); */ -+ -+ /* Set Ext. Default */ -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x8c, 0x00, 0x01); -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x00, 0x00); -+ -+ /* Enable RAMDAC for A1 */ -+ reg = 0x04; -+ if (ast->chip == AST2300 || ast->chip == AST2400 || -+ ast->chip == AST2500) -+ reg |= 0x20; -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff, reg); -+} -+ -+u32 ast_mindwm(struct ast_private *ast, u32 r) -+{ -+ uint32_t data; -+ -+ ast_write32(ast, 0xf004, r & 0xffff0000); -+ ast_write32(ast, 0xf000, 0x1); -+ -+ do { -+ data = ast_read32(ast, 0xf004) & 0xffff0000; -+ } while (data != (r & 0xffff0000)); -+ return ast_read32(ast, 0x10000 + (r & 0x0000ffff)); -+} -+ -+void ast_moutdwm(struct ast_private *ast, u32 r, u32 v) -+{ -+ uint32_t data; -+ -+ ast_write32(ast, 0xf004, r & 0xffff0000); -+ ast_write32(ast, 0xf000, 0x1); -+ do { -+ data = ast_read32(ast, 0xf004) & 0xffff0000; -+ } while (data != (r & 0xffff0000)); -+ ast_write32(ast, 0x10000 + (r & 0x0000ffff), v); -+} -+ -+/* -+ * AST2100/2150 DLL CBR Setting -+ */ -+#define CBR_SIZE_AST2150 ((16 << 10) - 1) -+#define CBR_PASSNUM_AST2150 5 -+#define CBR_THRESHOLD_AST2150 10 -+#define CBR_THRESHOLD2_AST2150 10 -+#define TIMEOUT_AST2150 5000000 -+ -+#define CBR_PATNUM_AST2150 8 -+ -+static const u32 pattern_AST2150[14] = { 0xFF00FF00, 0xCC33CC33, 0xAA55AA55, -+ 0xFFFE0001, 0x683501FE, 0x0F1929B0, -+ 0x2D0B4346, 0x60767F02, 0x6FBE36A6, -+ 0x3A253035, 0x3019686D, 0x41C6167E, -+ 0x620152BF, 0x20F050E0 }; -+ -+static u32 mmctestburst2_ast2150(struct ast_private *ast, u32 datagen) -+{ -+ u32 data, timeout; -+ -+ ast_moutdwm(ast, 0x1e6e0070, 0x00000000); -+ ast_moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3)); -+ timeout = 0; -+ do { -+ data = ast_mindwm(ast, 0x1e6e0070) & 0x40; -+ if (++timeout > TIMEOUT_AST2150) { -+ ast_moutdwm(ast, 0x1e6e0070, 0x00000000); -+ return 0xffffffff; -+ } -+ } while (!data); -+ ast_moutdwm(ast, 0x1e6e0070, 0x00000000); -+ ast_moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3)); -+ timeout = 0; -+ do { -+ data = ast_mindwm(ast, 0x1e6e0070) & 0x40; -+ if (++timeout > TIMEOUT_AST2150) { -+ ast_moutdwm(ast, 0x1e6e0070, 0x00000000); -+ return 0xffffffff; -+ } -+ } while (!data); -+ data = (ast_mindwm(ast, 0x1e6e0070) & 0x80) >> 7; -+ ast_moutdwm(ast, 0x1e6e0070, 0x00000000); -+ return data; -+} -+ -+static int cbrtest_ast2150(struct ast_private *ast) -+{ -+ int i; -+ -+ for (i = 0; i < 8; i++) -+ if (mmctestburst2_ast2150(ast, i)) -+ return 0; -+ return 1; -+} -+ -+static int cbrscan_ast2150(struct ast_private *ast, int busw) -+{ -+ u32 patcnt, loop; -+ -+ for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) { -+ ast_moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]); -+ for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) { -+ if (cbrtest_ast2150(ast)) -+ break; -+ } -+ if (loop == CBR_PASSNUM_AST2150) -+ return 0; -+ } -+ return 1; -+} -+ -+static void cbrdlli_ast2150(struct ast_private *ast, int busw) -+{ -+ u32 dll_min[4], dll_max[4], dlli, data, passcnt; -+ -+cbr_start: -+ dll_min[0] = dll_min[1] = dll_min[2] = dll_min[3] = 0xff; -+ dll_max[0] = dll_max[1] = dll_max[2] = dll_max[3] = 0x0; -+ passcnt = 0; -+ -+ for (dlli = 0; dlli < 100; dlli++) { -+ ast_moutdwm(ast, 0x1e6e0068, -+ dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); -+ data = cbrscan_ast2150(ast, busw); -+ if (data != 0) { -+ if (data & 0x1) { -+ if (dll_min[0] > dlli) -+ dll_min[0] = dlli; -+ if (dll_max[0] < dlli) -+ dll_max[0] = dlli; -+ } -+ passcnt++; -+ } else if (passcnt >= CBR_THRESHOLD_AST2150) -+ goto cbr_start; -+ } -+ if (dll_max[0] == 0 || -+ (dll_max[0] - dll_min[0]) < CBR_THRESHOLD_AST2150) -+ goto cbr_start; -+ -+ dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4); -+ ast_moutdwm(ast, 0x1e6e0068, -+ dlli | (dlli << 8) | (dlli << 16) | (dlli << 24)); -+} -+ -+static void ast_init_dram_reg(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ u8 j; -+ u32 data, temp, i; -+ const struct ast_dramstruct *dram_reg_info; -+ -+ j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); -+ -+ if ((j & 0x80) == 0) { /* VGA only */ -+ if (ast->chip == AST2000) { -+ dram_reg_info = ast2000_dram_table_data; -+ ast_write32(ast, 0xf004, 0x1e6e0000); -+ ast_write32(ast, 0xf000, 0x1); -+ ast_write32(ast, 0x10100, 0xa8); -+ -+ do { -+ ; -+ } while (ast_read32(ast, 0x10100) != 0xa8); -+ } else { /* AST2100/1100 */ -+ if (ast->chip == AST2100 || ast->chip == 2200) -+ dram_reg_info = ast2100_dram_table_data; -+ else -+ dram_reg_info = ast1100_dram_table_data; -+ -+ ast_write32(ast, 0xf004, 0x1e6e0000); -+ ast_write32(ast, 0xf000, 0x1); -+ ast_write32(ast, 0x12000, 0x1688A8A8); -+ do { -+ ; -+ } while (ast_read32(ast, 0x12000) != 0x01); -+ -+ ast_write32(ast, 0x10000, 0xfc600309); -+ do { -+ ; -+ } while (ast_read32(ast, 0x10000) != 0x01); -+ } -+ -+ while (dram_reg_info->index != 0xffff) { -+ if (dram_reg_info->index == 0xff00) { /* delay fn */ -+ for (i = 0; i < 15; i++) -+ udelay(dram_reg_info->data); -+ } else if (dram_reg_info->index == 0x4 && -+ ast->chip != AST2000) { -+ data = dram_reg_info->data; -+ if (ast->dram_type == AST_DRAM_1Gx16) -+ data = 0x00000d89; -+ else if (ast->dram_type == AST_DRAM_1Gx32) -+ data = 0x00000c8d; -+ -+ temp = ast_read32(ast, 0x12070); -+ temp &= 0xc; -+ temp <<= 2; -+ ast_write32(ast, 0x10000 + dram_reg_info->index, -+ data | temp); -+ } else -+ ast_write32(ast, 0x10000 + dram_reg_info->index, -+ dram_reg_info->data); -+ dram_reg_info++; -+ } -+ -+ /* AST 2100/2150 DRAM calibration */ -+ data = ast_read32(ast, 0x10120); -+ if (data == 0x5061) { /* 266Mhz */ -+ data = ast_read32(ast, 0x10004); -+ if (data & 0x40) -+ cbrdlli_ast2150(ast, 16); /* 16 bits */ -+ else -+ cbrdlli_ast2150(ast, 32); /* 32 bits */ -+ } -+ -+ switch (ast->chip) { -+ case AST2000: -+ temp = ast_read32(ast, 0x10140); -+ ast_write32(ast, 0x10140, temp | 0x40); -+ break; -+ case AST1100: -+ case AST2100: -+ case AST2200: -+ case AST2150: -+ temp = ast_read32(ast, 0x1200c); -+ ast_write32(ast, 0x1200c, temp & 0xfffffffd); -+ temp = ast_read32(ast, 0x12040); -+ ast_write32(ast, 0x12040, temp | 0x40); -+ break; -+ default: -+ break; -+ } -+ } -+ -+ /* wait ready */ -+ do { -+ j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); -+ } while ((j & 0x40) == 0); -+} -+ -+void ast_post_gpu(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ struct pci_dev *pdev = to_pci_dev(dev->dev); -+ u32 reg; -+ -+ pci_read_config_dword(pdev, 0x04, ®); -+ reg |= 0x3; -+ pci_write_config_dword(pdev, 0x04, reg); -+ -+ ast_enable_vga(dev); -+ ast_open_key(ast); -+ ast_enable_mmio(dev); -+ ast_set_def_ext_reg(dev); -+ -+ if (ast->chip == AST2600) { -+ ast_dp_launch(dev, 1); -+ } else if (ast->config_mode == ast_use_p2a) { -+ if (ast->chip == AST2500) -+ ast_post_chip_2500(dev); -+ else if (ast->chip == AST2300 || ast->chip == AST2400) -+ ast_post_chip_2300(dev); -+ else -+ ast_init_dram_reg(dev); -+ -+ ast_init_3rdtx(dev); -+ } else { -+ if (ast->tx_chip_types & AST_TX_SIL164_BIT) -+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, -+ 0xcf, 0x80); /* Enable DVO */ -+ } -+} -+ -+/* AST 2300 DRAM settings */ -+#define AST_DDR3 0 -+#define AST_DDR2 1 -+ -+struct ast2300_dram_param { -+ u32 dram_type; -+ u32 dram_chipid; -+ u32 dram_freq; -+ u32 vram_size; -+ u32 odt; -+ u32 wodt; -+ u32 rodt; -+ u32 dram_config; -+ u32 reg_PERIOD; -+ u32 reg_MADJ; -+ u32 reg_SADJ; -+ u32 reg_MRS; -+ u32 reg_EMRS; -+ u32 reg_AC1; -+ u32 reg_AC2; -+ u32 reg_DQSIC; -+ u32 reg_DRV; -+ u32 reg_IOZ; -+ u32 reg_DQIDLY; -+ u32 reg_FREQ; -+ u32 madj_max; -+ u32 dll2_finetune_step; -+}; -+ -+/* -+ * DQSI DLL CBR Setting -+ */ -+#define CBR_SIZE0 ((1 << 10) - 1) -+#define CBR_SIZE1 ((4 << 10) - 1) -+#define CBR_SIZE2 ((64 << 10) - 1) -+#define CBR_PASSNUM 5 -+#define CBR_PASSNUM2 5 -+#define CBR_THRESHOLD 10 -+#define CBR_THRESHOLD2 10 -+#define TIMEOUT 5000000 -+#define CBR_PATNUM 8 -+ -+static const u32 pattern[8] = { 0xFF00FF00, 0xCC33CC33, 0xAA55AA55, 0x88778877, -+ 0x92CC4D6E, 0x543D3CDE, 0xF1E843C7, 0x7C61D253 }; -+ -+static bool mmc_test(struct ast_private *ast, u32 datagen, u8 test_ctl) -+{ -+ u32 data, timeout; -+ -+ ast_moutdwm(ast, 0x1e6e0070, 0x00000000); -+ ast_moutdwm(ast, 0x1e6e0070, (datagen << 3) | test_ctl); -+ timeout = 0; -+ do { -+ data = ast_mindwm(ast, 0x1e6e0070) & 0x3000; -+ if (data & 0x2000) -+ return false; -+ if (++timeout > TIMEOUT) { -+ ast_moutdwm(ast, 0x1e6e0070, 0x00000000); -+ return false; -+ } -+ } while (!data); -+ ast_moutdwm(ast, 0x1e6e0070, 0x0); -+ return true; -+} -+ -+static u32 mmc_test2(struct ast_private *ast, u32 datagen, u8 test_ctl) -+{ -+ u32 data, timeout; -+ -+ ast_moutdwm(ast, 0x1e6e0070, 0x00000000); -+ ast_moutdwm(ast, 0x1e6e0070, (datagen << 3) | test_ctl); -+ timeout = 0; -+ do { -+ data = ast_mindwm(ast, 0x1e6e0070) & 0x1000; -+ if (++timeout > TIMEOUT) { -+ ast_moutdwm(ast, 0x1e6e0070, 0x0); -+ return 0xffffffff; -+ } -+ } while (!data); -+ data = ast_mindwm(ast, 0x1e6e0078); -+ data = (data | (data >> 16)) & 0xffff; -+ ast_moutdwm(ast, 0x1e6e0070, 0x00000000); -+ return data; -+} -+ -+static bool mmc_test_burst(struct ast_private *ast, u32 datagen) -+{ -+ return mmc_test(ast, datagen, 0xc1); -+} -+ -+static u32 mmc_test_burst2(struct ast_private *ast, u32 datagen) -+{ -+ return mmc_test2(ast, datagen, 0x41); -+} -+ -+static bool mmc_test_single(struct ast_private *ast, u32 datagen) -+{ -+ return mmc_test(ast, datagen, 0xc5); -+} -+ -+static u32 mmc_test_single2(struct ast_private *ast, u32 datagen) -+{ -+ return mmc_test2(ast, datagen, 0x05); -+} -+ -+static bool mmc_test_single_2500(struct ast_private *ast, u32 datagen) -+{ -+ return mmc_test(ast, datagen, 0x85); -+} -+ -+static int cbr_test(struct ast_private *ast) -+{ -+ u32 data; -+ int i; -+ -+ data = mmc_test_single2(ast, 0); -+ if ((data & 0xff) && (data & 0xff00)) -+ return 0; -+ for (i = 0; i < 8; i++) { -+ data = mmc_test_burst2(ast, i); -+ if ((data & 0xff) && (data & 0xff00)) -+ return 0; -+ } -+ if (!data) -+ return 3; -+ else if (data & 0xff) -+ return 2; -+ return 1; -+} -+ -+static int cbr_scan(struct ast_private *ast) -+{ -+ u32 data, data2, patcnt, loop; -+ -+ data2 = 3; -+ for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { -+ ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); -+ for (loop = 0; loop < CBR_PASSNUM2; loop++) { -+ data = cbr_test(ast); -+ if (data != 0) { -+ data2 &= data; -+ if (!data2) -+ return 0; -+ break; -+ } -+ } -+ if (loop == CBR_PASSNUM2) -+ return 0; -+ } -+ return data2; -+} -+ -+static u32 cbr_test2(struct ast_private *ast) -+{ -+ u32 data; -+ -+ data = mmc_test_burst2(ast, 0); -+ if (data == 0xffff) -+ return 0; -+ data |= mmc_test_single2(ast, 0); -+ if (data == 0xffff) -+ return 0; -+ -+ return ~data & 0xffff; -+} -+ -+static u32 cbr_scan2(struct ast_private *ast) -+{ -+ u32 data, data2, patcnt, loop; -+ -+ data2 = 0xffff; -+ for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { -+ ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); -+ for (loop = 0; loop < CBR_PASSNUM2; loop++) { -+ data = cbr_test2(ast); -+ if (data != 0) { -+ data2 &= data; -+ if (!data2) -+ return 0; -+ break; -+ } -+ } -+ if (loop == CBR_PASSNUM2) -+ return 0; -+ } -+ return data2; -+} -+ -+static bool cbr_test3(struct ast_private *ast) -+{ -+ if (!mmc_test_burst(ast, 0)) -+ return false; -+ if (!mmc_test_single(ast, 0)) -+ return false; -+ return true; -+} -+ -+static bool cbr_scan3(struct ast_private *ast) -+{ -+ u32 patcnt, loop; -+ -+ for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) { -+ ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]); -+ for (loop = 0; loop < 2; loop++) { -+ if (cbr_test3(ast)) -+ break; -+ } -+ if (loop == 2) -+ return false; -+ } -+ return true; -+} -+ -+static bool finetuneDQI_L(struct ast_private *ast, -+ struct ast2300_dram_param *param) -+{ -+ u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, -+ passcnt, retry = 0; -+ bool status = false; -+FINETUNE_START: -+ for (cnt = 0; cnt < 16; cnt++) { -+ dllmin[cnt] = 0xff; -+ dllmax[cnt] = 0x0; -+ } -+ passcnt = 0; -+ for (dlli = 0; dlli < 76; dlli++) { -+ ast_moutdwm(ast, 0x1E6E0068, -+ 0x00001400 | (dlli << 16) | (dlli << 24)); -+ ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE1); -+ data = cbr_scan2(ast); -+ if (data != 0) { -+ mask = 0x00010001; -+ for (cnt = 0; cnt < 16; cnt++) { -+ if (data & mask) { -+ if (dllmin[cnt] > dlli) -+ dllmin[cnt] = dlli; -+ if (dllmax[cnt] < dlli) -+ dllmax[cnt] = dlli; -+ } -+ mask <<= 1; -+ } -+ passcnt++; -+ } else if (passcnt >= CBR_THRESHOLD2) { -+ break; -+ } -+ } -+ gold_sadj[0] = 0x0; -+ passcnt = 0; -+ for (cnt = 0; cnt < 16; cnt++) { -+ if ((dllmax[cnt] > dllmin[cnt]) && -+ ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { -+ gold_sadj[0] += dllmin[cnt]; -+ passcnt++; -+ } -+ } -+ if (retry++ > 10) -+ goto FINETUNE_DONE; -+ if (passcnt != 16) -+ goto FINETUNE_START; -+ status = true; -+FINETUNE_DONE: -+ gold_sadj[0] = gold_sadj[0] >> 4; -+ gold_sadj[1] = gold_sadj[0]; -+ -+ data = 0; -+ for (cnt = 0; cnt < 8; cnt++) { -+ data >>= 3; -+ if ((dllmax[cnt] > dllmin[cnt]) && -+ ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { -+ dlli = dllmin[cnt]; -+ if (gold_sadj[0] >= dlli) { -+ dlli = ((gold_sadj[0] - dlli) * 19) >> 5; -+ if (dlli > 3) -+ dlli = 3; -+ } else { -+ dlli = ((dlli - gold_sadj[0]) * 19) >> 5; -+ if (dlli > 4) -+ dlli = 4; -+ dlli = (8 - dlli) & 0x7; -+ } -+ data |= dlli << 21; -+ } -+ } -+ ast_moutdwm(ast, 0x1E6E0080, data); -+ -+ data = 0; -+ for (cnt = 8; cnt < 16; cnt++) { -+ data >>= 3; -+ if ((dllmax[cnt] > dllmin[cnt]) && -+ ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) { -+ dlli = dllmin[cnt]; -+ if (gold_sadj[1] >= dlli) { -+ dlli = ((gold_sadj[1] - dlli) * 19) >> 5; -+ if (dlli > 3) -+ dlli = 3; -+ else -+ dlli = (dlli - 1) & 0x7; -+ } else { -+ dlli = ((dlli - gold_sadj[1]) * 19) >> 5; -+ dlli += 1; -+ if (dlli > 4) -+ dlli = 4; -+ dlli = (8 - dlli) & 0x7; -+ } -+ data |= dlli << 21; -+ } -+ } -+ ast_moutdwm(ast, 0x1E6E0084, data); -+ return status; -+} /* finetuneDQI_L */ -+ -+static void finetuneDQSI(struct ast_private *ast) -+{ -+ u32 dlli, dqsip, dqidly; -+ u32 reg_mcr18, reg_mcr0c, passcnt[2], diff; -+ u32 g_dqidly, g_dqsip, g_margin, g_side; -+ u16 pass[32][2][2]; -+ char tag[2][76]; -+ -+ /* Disable DQI CBR */ -+ reg_mcr0c = ast_mindwm(ast, 0x1E6E000C); -+ reg_mcr18 = ast_mindwm(ast, 0x1E6E0018); -+ reg_mcr18 &= 0x0000ffff; -+ ast_moutdwm(ast, 0x1E6E0018, reg_mcr18); -+ -+ for (dlli = 0; dlli < 76; dlli++) { -+ tag[0][dlli] = 0x0; -+ tag[1][dlli] = 0x0; -+ } -+ for (dqidly = 0; dqidly < 32; dqidly++) { -+ pass[dqidly][0][0] = 0xff; -+ pass[dqidly][0][1] = 0x0; -+ pass[dqidly][1][0] = 0xff; -+ pass[dqidly][1][1] = 0x0; -+ } -+ for (dqidly = 0; dqidly < 32; dqidly++) { -+ passcnt[0] = passcnt[1] = 0; -+ for (dqsip = 0; dqsip < 2; dqsip++) { -+ ast_moutdwm(ast, 0x1E6E000C, 0); -+ ast_moutdwm(ast, 0x1E6E0018, -+ reg_mcr18 | (dqidly << 16) | (dqsip << 23)); -+ ast_moutdwm(ast, 0x1E6E000C, reg_mcr0c); -+ for (dlli = 0; dlli < 76; dlli++) { -+ ast_moutdwm(ast, 0x1E6E0068, -+ 0x00001300 | (dlli << 16) | -+ (dlli << 24)); -+ ast_moutdwm(ast, 0x1E6E0070, 0); -+ ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE0); -+ if (cbr_scan3(ast)) { -+ if (dlli == 0) -+ break; -+ passcnt[dqsip]++; -+ tag[dqsip][dlli] = 'P'; -+ if (dlli < pass[dqidly][dqsip][0]) -+ pass[dqidly][dqsip][0] = -+ (u16)dlli; -+ if (dlli > pass[dqidly][dqsip][1]) -+ pass[dqidly][dqsip][1] = -+ (u16)dlli; -+ } -+ if (passcnt[dqsip] >= 5) -+ break; -+ if (!cbr_scan3(ast)) { -+ pass[dqidly][dqsip][0] = 0xff; -+ pass[dqidly][dqsip][1] = 0x0; -+ } -+ } -+ } -+ if (passcnt[0] == 0 && passcnt[1] == 0) -+ dqidly++; -+ } -+ /* Search margin */ -+ g_dqidly = g_dqsip = g_margin = g_side = 0; -+ -+ for (dqidly = 0; dqidly < 32; dqidly++) { -+ for (dqsip = 0; dqsip < 2; dqsip++) { -+ if (pass[dqidly][dqsip][0] > pass[dqidly][dqsip][1]) -+ continue; -+ diff = pass[dqidly][dqsip][1] - pass[dqidly][dqsip][0]; -+ if ((diff + 2) < g_margin) -+ continue; -+ passcnt[0] = passcnt[1] = 0; -+ for (dlli = pass[dqidly][dqsip][0]; -+ dlli > 0 && tag[dqsip][dlli] != 0; -+ dlli--, passcnt[0]++) -+ ; -+ for (dlli = pass[dqidly][dqsip][1]; -+ dlli < 76 && tag[dqsip][dlli] != 0; -+ dlli++, passcnt[1]++) -+ ; -+ if (passcnt[0] > passcnt[1]) -+ passcnt[0] = passcnt[1]; -+ passcnt[1] = 0; -+ if (passcnt[0] > g_side) -+ passcnt[1] = passcnt[0] - g_side; -+ if (diff > (g_margin + 1) && -+ (passcnt[1] > 0 || passcnt[0] > 8)) { -+ g_margin = diff; -+ g_dqidly = dqidly; -+ g_dqsip = dqsip; -+ g_side = passcnt[0]; -+ } else if (passcnt[1] > 1 && g_side < 8) { -+ if (diff > g_margin) -+ g_margin = diff; -+ g_dqidly = dqidly; -+ g_dqsip = dqsip; -+ g_side = passcnt[0]; -+ } -+ } -+ } -+ reg_mcr18 = reg_mcr18 | (g_dqidly << 16) | (g_dqsip << 23); -+ ast_moutdwm(ast, 0x1E6E0018, reg_mcr18); -+} -+static bool cbr_dll2(struct ast_private *ast, struct ast2300_dram_param *param) -+{ -+ u32 dllmin[2], dllmax[2], dlli, data, passcnt, retry = 0; -+ bool status = false; -+ -+ finetuneDQSI(ast); -+ if (finetuneDQI_L(ast, param) == false) -+ return status; -+ -+CBR_START2: -+ dllmin[0] = dllmin[1] = 0xff; -+ dllmax[0] = dllmax[1] = 0x0; -+ passcnt = 0; -+ for (dlli = 0; dlli < 76; dlli++) { -+ ast_moutdwm(ast, 0x1E6E0068, -+ 0x00001300 | (dlli << 16) | (dlli << 24)); -+ ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE2); -+ data = cbr_scan(ast); -+ if (data != 0) { -+ if (data & 0x1) { -+ if (dllmin[0] > dlli) -+ dllmin[0] = dlli; -+ if (dllmax[0] < dlli) -+ dllmax[0] = dlli; -+ } -+ if (data & 0x2) { -+ if (dllmin[1] > dlli) -+ dllmin[1] = dlli; -+ if (dllmax[1] < dlli) -+ dllmax[1] = dlli; -+ } -+ passcnt++; -+ } else if (passcnt >= CBR_THRESHOLD) { -+ break; -+ } -+ } -+ if (retry++ > 10) -+ goto CBR_DONE2; -+ if (dllmax[0] == 0 || (dllmax[0] - dllmin[0]) < CBR_THRESHOLD) -+ goto CBR_START2; -+ if (dllmax[1] == 0 || (dllmax[1] - dllmin[1]) < CBR_THRESHOLD) -+ goto CBR_START2; -+ status = true; -+CBR_DONE2: -+ dlli = (dllmin[1] + dllmax[1]) >> 1; -+ dlli <<= 8; -+ dlli += (dllmin[0] + dllmax[0]) >> 1; -+ ast_moutdwm(ast, 0x1E6E0068, -+ ast_mindwm(ast, 0x1E720058) | (dlli << 16)); -+ return status; -+} /* CBRDLL2 */ -+ -+static void get_ddr3_info(struct ast_private *ast, -+ struct ast2300_dram_param *param) -+{ -+ u32 trap, trap_AC2, trap_MRS; -+ -+ ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8); -+ -+ /* Ger trap info */ -+ trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3; -+ trap_AC2 = 0x00020000 + (trap << 16); -+ trap_AC2 |= 0x00300000 + ((trap & 0x2) << 19); -+ trap_MRS = 0x00000010 + (trap << 4); -+ trap_MRS |= ((trap & 0x2) << 18); -+ -+ param->reg_MADJ = 0x00034C4C; -+ param->reg_SADJ = 0x00001800; -+ param->reg_DRV = 0x000000F0; -+ param->reg_PERIOD = param->dram_freq; -+ param->rodt = 0; -+ -+ switch (param->dram_freq) { -+ case 336: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0190); -+ param->wodt = 0; -+ param->reg_AC1 = 0x22202725; -+ param->reg_AC2 = 0xAA007613 | trap_AC2; -+ param->reg_DQSIC = 0x000000BA; -+ param->reg_MRS = 0x04001400 | trap_MRS; -+ param->reg_EMRS = 0x00000000; -+ param->reg_IOZ = 0x00000023; -+ param->reg_DQIDLY = 0x00000074; -+ param->reg_FREQ = 0x00004DC0; -+ param->madj_max = 96; -+ param->dll2_finetune_step = 3; -+ switch (param->dram_chipid) { -+ default: -+ case AST_DRAM_512Mx16: -+ case AST_DRAM_1Gx16: -+ param->reg_AC2 = 0xAA007613 | trap_AC2; -+ break; -+ case AST_DRAM_2Gx16: -+ param->reg_AC2 = 0xAA00761C | trap_AC2; -+ break; -+ case AST_DRAM_4Gx16: -+ param->reg_AC2 = 0xAA007636 | trap_AC2; -+ break; -+ } -+ break; -+ default: -+ case 396: -+ ast_moutdwm(ast, 0x1E6E2020, 0x03F1); -+ param->wodt = 1; -+ param->reg_AC1 = 0x33302825; -+ param->reg_AC2 = 0xCC009617 | trap_AC2; -+ param->reg_DQSIC = 0x000000E2; -+ param->reg_MRS = 0x04001600 | trap_MRS; -+ param->reg_EMRS = 0x00000000; -+ param->reg_IOZ = 0x00000034; -+ param->reg_DRV = 0x000000FA; -+ param->reg_DQIDLY = 0x00000089; -+ param->reg_FREQ = 0x00005040; -+ param->madj_max = 96; -+ param->dll2_finetune_step = 4; -+ -+ switch (param->dram_chipid) { -+ default: -+ case AST_DRAM_512Mx16: -+ case AST_DRAM_1Gx16: -+ param->reg_AC2 = 0xCC009617 | trap_AC2; -+ break; -+ case AST_DRAM_2Gx16: -+ param->reg_AC2 = 0xCC009622 | trap_AC2; -+ break; -+ case AST_DRAM_4Gx16: -+ param->reg_AC2 = 0xCC00963F | trap_AC2; -+ break; -+ } -+ break; -+ -+ case 408: -+ ast_moutdwm(ast, 0x1E6E2020, 0x01F0); -+ param->wodt = 1; -+ param->reg_AC1 = 0x33302825; -+ param->reg_AC2 = 0xCC009617 | trap_AC2; -+ param->reg_DQSIC = 0x000000E2; -+ param->reg_MRS = 0x04001600 | trap_MRS; -+ param->reg_EMRS = 0x00000000; -+ param->reg_IOZ = 0x00000023; -+ param->reg_DRV = 0x000000FA; -+ param->reg_DQIDLY = 0x00000089; -+ param->reg_FREQ = 0x000050C0; -+ param->madj_max = 96; -+ param->dll2_finetune_step = 4; -+ -+ switch (param->dram_chipid) { -+ default: -+ case AST_DRAM_512Mx16: -+ case AST_DRAM_1Gx16: -+ param->reg_AC2 = 0xCC009617 | trap_AC2; -+ break; -+ case AST_DRAM_2Gx16: -+ param->reg_AC2 = 0xCC009622 | trap_AC2; -+ break; -+ case AST_DRAM_4Gx16: -+ param->reg_AC2 = 0xCC00963F | trap_AC2; -+ break; -+ } -+ -+ break; -+ case 456: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0230); -+ param->wodt = 0; -+ param->reg_AC1 = 0x33302926; -+ param->reg_AC2 = 0xCD44961A; -+ param->reg_DQSIC = 0x000000FC; -+ param->reg_MRS = 0x00081830; -+ param->reg_EMRS = 0x00000000; -+ param->reg_IOZ = 0x00000045; -+ param->reg_DQIDLY = 0x00000097; -+ param->reg_FREQ = 0x000052C0; -+ param->madj_max = 88; -+ param->dll2_finetune_step = 4; -+ break; -+ case 504: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0270); -+ param->wodt = 1; -+ param->reg_AC1 = 0x33302926; -+ param->reg_AC2 = 0xDE44A61D; -+ param->reg_DQSIC = 0x00000117; -+ param->reg_MRS = 0x00081A30; -+ param->reg_EMRS = 0x00000000; -+ param->reg_IOZ = 0x070000BB; -+ param->reg_DQIDLY = 0x000000A0; -+ param->reg_FREQ = 0x000054C0; -+ param->madj_max = 79; -+ param->dll2_finetune_step = 4; -+ break; -+ case 528: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0290); -+ param->wodt = 1; -+ param->rodt = 1; -+ param->reg_AC1 = 0x33302926; -+ param->reg_AC2 = 0xEF44B61E; -+ param->reg_DQSIC = 0x00000125; -+ param->reg_MRS = 0x00081A30; -+ param->reg_EMRS = 0x00000040; -+ param->reg_DRV = 0x000000F5; -+ param->reg_IOZ = 0x00000023; -+ param->reg_DQIDLY = 0x00000088; -+ param->reg_FREQ = 0x000055C0; -+ param->madj_max = 76; -+ param->dll2_finetune_step = 3; -+ break; -+ case 576: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0140); -+ param->reg_MADJ = 0x00136868; -+ param->reg_SADJ = 0x00004534; -+ param->wodt = 1; -+ param->rodt = 1; -+ param->reg_AC1 = 0x33302A37; -+ param->reg_AC2 = 0xEF56B61E; -+ param->reg_DQSIC = 0x0000013F; -+ param->reg_MRS = 0x00101A50; -+ param->reg_EMRS = 0x00000040; -+ param->reg_DRV = 0x000000FA; -+ param->reg_IOZ = 0x00000023; -+ param->reg_DQIDLY = 0x00000078; -+ param->reg_FREQ = 0x000057C0; -+ param->madj_max = 136; -+ param->dll2_finetune_step = 3; -+ break; -+ case 600: -+ ast_moutdwm(ast, 0x1E6E2020, 0x02E1); -+ param->reg_MADJ = 0x00136868; -+ param->reg_SADJ = 0x00004534; -+ param->wodt = 1; -+ param->rodt = 1; -+ param->reg_AC1 = 0x32302A37; -+ param->reg_AC2 = 0xDF56B61F; -+ param->reg_DQSIC = 0x0000014D; -+ param->reg_MRS = 0x00101A50; -+ param->reg_EMRS = 0x00000004; -+ param->reg_DRV = 0x000000F5; -+ param->reg_IOZ = 0x00000023; -+ param->reg_DQIDLY = 0x00000078; -+ param->reg_FREQ = 0x000058C0; -+ param->madj_max = 132; -+ param->dll2_finetune_step = 3; -+ break; -+ case 624: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0160); -+ param->reg_MADJ = 0x00136868; -+ param->reg_SADJ = 0x00004534; -+ param->wodt = 1; -+ param->rodt = 1; -+ param->reg_AC1 = 0x32302A37; -+ param->reg_AC2 = 0xEF56B621; -+ param->reg_DQSIC = 0x0000015A; -+ param->reg_MRS = 0x02101A50; -+ param->reg_EMRS = 0x00000004; -+ param->reg_DRV = 0x000000F5; -+ param->reg_IOZ = 0x00000034; -+ param->reg_DQIDLY = 0x00000078; -+ param->reg_FREQ = 0x000059C0; -+ param->madj_max = 128; -+ param->dll2_finetune_step = 3; -+ break; -+ } /* switch freq */ -+ -+ switch (param->dram_chipid) { -+ case AST_DRAM_512Mx16: -+ param->dram_config = 0x130; -+ break; -+ default: -+ case AST_DRAM_1Gx16: -+ param->dram_config = 0x131; -+ break; -+ case AST_DRAM_2Gx16: -+ param->dram_config = 0x132; -+ break; -+ case AST_DRAM_4Gx16: -+ param->dram_config = 0x133; -+ break; -+ } /* switch size */ -+ -+ switch (param->vram_size) { -+ default: -+ case AST_VIDMEM_SIZE_8M: -+ param->dram_config |= 0x00; -+ break; -+ case AST_VIDMEM_SIZE_16M: -+ param->dram_config |= 0x04; -+ break; -+ case AST_VIDMEM_SIZE_32M: -+ param->dram_config |= 0x08; -+ break; -+ case AST_VIDMEM_SIZE_64M: -+ param->dram_config |= 0x0c; -+ break; -+ } -+} -+ -+static void ddr3_init(struct ast_private *ast, struct ast2300_dram_param *param) -+{ -+ u32 data, data2, retry = 0; -+ -+ddr3_init_start: -+ ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); -+ ast_moutdwm(ast, 0x1E6E0018, 0x00000100); -+ ast_moutdwm(ast, 0x1E6E0024, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0034, 0x00000000); -+ udelay(10); -+ ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ); -+ ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ); -+ udelay(10); -+ ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000); -+ udelay(10); -+ -+ ast_moutdwm(ast, 0x1E6E0004, param->dram_config); -+ ast_moutdwm(ast, 0x1E6E0008, 0x90040f); -+ ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1); -+ ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2); -+ ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC); -+ ast_moutdwm(ast, 0x1E6E0080, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0084, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY); -+ ast_moutdwm(ast, 0x1E6E0018, 0x4000A170); -+ ast_moutdwm(ast, 0x1E6E0018, 0x00002370); -+ ast_moutdwm(ast, 0x1E6E0038, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0040, 0xFF444444); -+ ast_moutdwm(ast, 0x1E6E0044, 0x22222222); -+ ast_moutdwm(ast, 0x1E6E0048, 0x22222222); -+ ast_moutdwm(ast, 0x1E6E004C, 0x00000002); -+ ast_moutdwm(ast, 0x1E6E0050, 0x80000000); -+ ast_moutdwm(ast, 0x1E6E0050, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0054, 0); -+ ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV); -+ ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ); -+ ast_moutdwm(ast, 0x1E6E0070, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0074, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0078, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E007C, 0x00000000); -+ /* Wait MCLK2X lock to MCLK */ -+ do { -+ data = ast_mindwm(ast, 0x1E6E001C); -+ } while (!(data & 0x08000000)); -+ data = ast_mindwm(ast, 0x1E6E001C); -+ data = (data >> 8) & 0xff; -+ while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) { -+ data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4; -+ if ((data2 & 0xff) > param->madj_max) -+ break; -+ ast_moutdwm(ast, 0x1E6E0064, data2); -+ if (data2 & 0x00100000) -+ data2 = ((data2 & 0xff) >> 3) + 3; -+ else -+ data2 = ((data2 & 0xff) >> 2) + 5; -+ data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff; -+ data2 += data & 0xff; -+ data = data | (data2 << 8); -+ ast_moutdwm(ast, 0x1E6E0068, data); -+ udelay(10); -+ ast_moutdwm(ast, 0x1E6E0064, -+ ast_mindwm(ast, 0x1E6E0064) | 0xC0000); -+ udelay(10); -+ data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff; -+ ast_moutdwm(ast, 0x1E6E0018, data); -+ data = data | 0x200; -+ ast_moutdwm(ast, 0x1E6E0018, data); -+ do { -+ data = ast_mindwm(ast, 0x1E6E001C); -+ } while (!(data & 0x08000000)); -+ -+ data = ast_mindwm(ast, 0x1E6E001C); -+ data = (data >> 8) & 0xff; -+ } -+ ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0068) & 0xffff); -+ data = ast_mindwm(ast, 0x1E6E0018) | 0xC00; -+ ast_moutdwm(ast, 0x1E6E0018, data); -+ -+ ast_moutdwm(ast, 0x1E6E0034, 0x00000001); -+ ast_moutdwm(ast, 0x1E6E000C, 0x00000040); -+ udelay(50); -+ /* Mode Register Setting */ -+ ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100); -+ ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000005); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000007); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000003); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000001); -+ ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS); -+ ast_moutdwm(ast, 0x1E6E000C, 0x00005C08); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000001); -+ -+ ast_moutdwm(ast, 0x1E6E000C, 0x00005C01); -+ data = 0; -+ if (param->wodt) -+ data = 0x300; -+ if (param->rodt) -+ data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3); -+ ast_moutdwm(ast, 0x1E6E0034, data | 0x3); -+ -+ /* Calibrate the DQSI delay */ -+ if ((cbr_dll2(ast, param) == false) && (retry++ < 10)) -+ goto ddr3_init_start; -+ -+ ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ); -+ /* ECC Memory Initialization */ -+#ifdef ECC -+ ast_moutdwm(ast, 0x1E6E007C, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0070, 0x221); -+ do { -+ data = ast_mindwm(ast, 0x1E6E0070); -+ } while (!(data & 0x00001000)); -+ ast_moutdwm(ast, 0x1E6E0070, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0050, 0x80000000); -+ ast_moutdwm(ast, 0x1E6E0050, 0x00000000); -+#endif -+} -+ -+static void get_ddr2_info(struct ast_private *ast, -+ struct ast2300_dram_param *param) -+{ -+ u32 trap, trap_AC2, trap_MRS; -+ -+ ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8); -+ -+ /* Ger trap info */ -+ trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3; -+ trap_AC2 = (trap << 20) | (trap << 16); -+ trap_AC2 += 0x00110000; -+ trap_MRS = 0x00000040 | (trap << 4); -+ -+ param->reg_MADJ = 0x00034C4C; -+ param->reg_SADJ = 0x00001800; -+ param->reg_DRV = 0x000000F0; -+ param->reg_PERIOD = param->dram_freq; -+ param->rodt = 0; -+ -+ switch (param->dram_freq) { -+ case 264: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0130); -+ param->wodt = 0; -+ param->reg_AC1 = 0x11101513; -+ param->reg_AC2 = 0x78117011; -+ param->reg_DQSIC = 0x00000092; -+ param->reg_MRS = 0x00000842; -+ param->reg_EMRS = 0x00000000; -+ param->reg_DRV = 0x000000F0; -+ param->reg_IOZ = 0x00000034; -+ param->reg_DQIDLY = 0x0000005A; -+ param->reg_FREQ = 0x00004AC0; -+ param->madj_max = 138; -+ param->dll2_finetune_step = 3; -+ break; -+ case 336: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0190); -+ param->wodt = 1; -+ param->reg_AC1 = 0x22202613; -+ param->reg_AC2 = 0xAA009016 | trap_AC2; -+ param->reg_DQSIC = 0x000000BA; -+ param->reg_MRS = 0x00000A02 | trap_MRS; -+ param->reg_EMRS = 0x00000040; -+ param->reg_DRV = 0x000000FA; -+ param->reg_IOZ = 0x00000034; -+ param->reg_DQIDLY = 0x00000074; -+ param->reg_FREQ = 0x00004DC0; -+ param->madj_max = 96; -+ param->dll2_finetune_step = 3; -+ switch (param->dram_chipid) { -+ default: -+ case AST_DRAM_512Mx16: -+ param->reg_AC2 = 0xAA009012 | trap_AC2; -+ break; -+ case AST_DRAM_1Gx16: -+ param->reg_AC2 = 0xAA009016 | trap_AC2; -+ break; -+ case AST_DRAM_2Gx16: -+ param->reg_AC2 = 0xAA009023 | trap_AC2; -+ break; -+ case AST_DRAM_4Gx16: -+ param->reg_AC2 = 0xAA00903B | trap_AC2; -+ break; -+ } -+ break; -+ default: -+ case 396: -+ ast_moutdwm(ast, 0x1E6E2020, 0x03F1); -+ param->wodt = 1; -+ param->rodt = 0; -+ param->reg_AC1 = 0x33302714; -+ param->reg_AC2 = 0xCC00B01B | trap_AC2; -+ param->reg_DQSIC = 0x000000E2; -+ param->reg_MRS = 0x00000C02 | trap_MRS; -+ param->reg_EMRS = 0x00000040; -+ param->reg_DRV = 0x000000FA; -+ param->reg_IOZ = 0x00000034; -+ param->reg_DQIDLY = 0x00000089; -+ param->reg_FREQ = 0x00005040; -+ param->madj_max = 96; -+ param->dll2_finetune_step = 4; -+ -+ switch (param->dram_chipid) { -+ case AST_DRAM_512Mx16: -+ param->reg_AC2 = 0xCC00B016 | trap_AC2; -+ break; -+ default: -+ case AST_DRAM_1Gx16: -+ param->reg_AC2 = 0xCC00B01B | trap_AC2; -+ break; -+ case AST_DRAM_2Gx16: -+ param->reg_AC2 = 0xCC00B02B | trap_AC2; -+ break; -+ case AST_DRAM_4Gx16: -+ param->reg_AC2 = 0xCC00B03F | trap_AC2; -+ break; -+ } -+ -+ break; -+ -+ case 408: -+ ast_moutdwm(ast, 0x1E6E2020, 0x01F0); -+ param->wodt = 1; -+ param->rodt = 0; -+ param->reg_AC1 = 0x33302714; -+ param->reg_AC2 = 0xCC00B01B | trap_AC2; -+ param->reg_DQSIC = 0x000000E2; -+ param->reg_MRS = 0x00000C02 | trap_MRS; -+ param->reg_EMRS = 0x00000040; -+ param->reg_DRV = 0x000000FA; -+ param->reg_IOZ = 0x00000034; -+ param->reg_DQIDLY = 0x00000089; -+ param->reg_FREQ = 0x000050C0; -+ param->madj_max = 96; -+ param->dll2_finetune_step = 4; -+ -+ switch (param->dram_chipid) { -+ case AST_DRAM_512Mx16: -+ param->reg_AC2 = 0xCC00B016 | trap_AC2; -+ break; -+ default: -+ case AST_DRAM_1Gx16: -+ param->reg_AC2 = 0xCC00B01B | trap_AC2; -+ break; -+ case AST_DRAM_2Gx16: -+ param->reg_AC2 = 0xCC00B02B | trap_AC2; -+ break; -+ case AST_DRAM_4Gx16: -+ param->reg_AC2 = 0xCC00B03F | trap_AC2; -+ break; -+ } -+ -+ break; -+ case 456: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0230); -+ param->wodt = 0; -+ param->reg_AC1 = 0x33302815; -+ param->reg_AC2 = 0xCD44B01E; -+ param->reg_DQSIC = 0x000000FC; -+ param->reg_MRS = 0x00000E72; -+ param->reg_EMRS = 0x00000000; -+ param->reg_DRV = 0x00000000; -+ param->reg_IOZ = 0x00000034; -+ param->reg_DQIDLY = 0x00000097; -+ param->reg_FREQ = 0x000052C0; -+ param->madj_max = 88; -+ param->dll2_finetune_step = 3; -+ break; -+ case 504: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0261); -+ param->wodt = 1; -+ param->rodt = 1; -+ param->reg_AC1 = 0x33302815; -+ param->reg_AC2 = 0xDE44C022; -+ param->reg_DQSIC = 0x00000117; -+ param->reg_MRS = 0x00000E72; -+ param->reg_EMRS = 0x00000040; -+ param->reg_DRV = 0x0000000A; -+ param->reg_IOZ = 0x00000045; -+ param->reg_DQIDLY = 0x000000A0; -+ param->reg_FREQ = 0x000054C0; -+ param->madj_max = 79; -+ param->dll2_finetune_step = 3; -+ break; -+ case 528: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0120); -+ param->wodt = 1; -+ param->rodt = 1; -+ param->reg_AC1 = 0x33302815; -+ param->reg_AC2 = 0xEF44D024; -+ param->reg_DQSIC = 0x00000125; -+ param->reg_MRS = 0x00000E72; -+ param->reg_EMRS = 0x00000004; -+ param->reg_DRV = 0x000000F9; -+ param->reg_IOZ = 0x00000045; -+ param->reg_DQIDLY = 0x000000A7; -+ param->reg_FREQ = 0x000055C0; -+ param->madj_max = 76; -+ param->dll2_finetune_step = 3; -+ break; -+ case 552: -+ ast_moutdwm(ast, 0x1E6E2020, 0x02A1); -+ param->wodt = 1; -+ param->rodt = 1; -+ param->reg_AC1 = 0x43402915; -+ param->reg_AC2 = 0xFF44E025; -+ param->reg_DQSIC = 0x00000132; -+ param->reg_MRS = 0x00000E72; -+ param->reg_EMRS = 0x00000040; -+ param->reg_DRV = 0x0000000A; -+ param->reg_IOZ = 0x00000045; -+ param->reg_DQIDLY = 0x000000AD; -+ param->reg_FREQ = 0x000056C0; -+ param->madj_max = 76; -+ param->dll2_finetune_step = 3; -+ break; -+ case 576: -+ ast_moutdwm(ast, 0x1E6E2020, 0x0140); -+ param->wodt = 1; -+ param->rodt = 1; -+ param->reg_AC1 = 0x43402915; -+ param->reg_AC2 = 0xFF44E027; -+ param->reg_DQSIC = 0x0000013F; -+ param->reg_MRS = 0x00000E72; -+ param->reg_EMRS = 0x00000004; -+ param->reg_DRV = 0x000000F5; -+ param->reg_IOZ = 0x00000045; -+ param->reg_DQIDLY = 0x000000B3; -+ param->reg_FREQ = 0x000057C0; -+ param->madj_max = 76; -+ param->dll2_finetune_step = 3; -+ break; -+ } -+ -+ switch (param->dram_chipid) { -+ case AST_DRAM_512Mx16: -+ param->dram_config = 0x100; -+ break; -+ default: -+ case AST_DRAM_1Gx16: -+ param->dram_config = 0x121; -+ break; -+ case AST_DRAM_2Gx16: -+ param->dram_config = 0x122; -+ break; -+ case AST_DRAM_4Gx16: -+ param->dram_config = 0x123; -+ break; -+ } /* switch size */ -+ -+ switch (param->vram_size) { -+ default: -+ case AST_VIDMEM_SIZE_8M: -+ param->dram_config |= 0x00; -+ break; -+ case AST_VIDMEM_SIZE_16M: -+ param->dram_config |= 0x04; -+ break; -+ case AST_VIDMEM_SIZE_32M: -+ param->dram_config |= 0x08; -+ break; -+ case AST_VIDMEM_SIZE_64M: -+ param->dram_config |= 0x0c; -+ break; -+ } -+} -+ -+static void ddr2_init(struct ast_private *ast, struct ast2300_dram_param *param) -+{ -+ u32 data, data2, retry = 0; -+ -+ddr2_init_start: -+ ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); -+ ast_moutdwm(ast, 0x1E6E0018, 0x00000100); -+ ast_moutdwm(ast, 0x1E6E0024, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ); -+ ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ); -+ udelay(10); -+ ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000); -+ udelay(10); -+ -+ ast_moutdwm(ast, 0x1E6E0004, param->dram_config); -+ ast_moutdwm(ast, 0x1E6E0008, 0x90040f); -+ ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1); -+ ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2); -+ ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC); -+ ast_moutdwm(ast, 0x1E6E0080, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0084, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY); -+ ast_moutdwm(ast, 0x1E6E0018, 0x4000A130); -+ ast_moutdwm(ast, 0x1E6E0018, 0x00002330); -+ ast_moutdwm(ast, 0x1E6E0038, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0040, 0xFF808000); -+ ast_moutdwm(ast, 0x1E6E0044, 0x88848466); -+ ast_moutdwm(ast, 0x1E6E0048, 0x44440008); -+ ast_moutdwm(ast, 0x1E6E004C, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0050, 0x80000000); -+ ast_moutdwm(ast, 0x1E6E0050, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0054, 0); -+ ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV); -+ ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ); -+ ast_moutdwm(ast, 0x1E6E0070, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0074, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0078, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E007C, 0x00000000); -+ -+ /* Wait MCLK2X lock to MCLK */ -+ do { -+ data = ast_mindwm(ast, 0x1E6E001C); -+ } while (!(data & 0x08000000)); -+ data = ast_mindwm(ast, 0x1E6E001C); -+ data = (data >> 8) & 0xff; -+ while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) { -+ data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4; -+ if ((data2 & 0xff) > param->madj_max) -+ break; -+ ast_moutdwm(ast, 0x1E6E0064, data2); -+ if (data2 & 0x00100000) -+ data2 = ((data2 & 0xff) >> 3) + 3; -+ else -+ data2 = ((data2 & 0xff) >> 2) + 5; -+ data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff; -+ data2 += data & 0xff; -+ data = data | (data2 << 8); -+ ast_moutdwm(ast, 0x1E6E0068, data); -+ udelay(10); -+ ast_moutdwm(ast, 0x1E6E0064, -+ ast_mindwm(ast, 0x1E6E0064) | 0xC0000); -+ udelay(10); -+ data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff; -+ ast_moutdwm(ast, 0x1E6E0018, data); -+ data = data | 0x200; -+ ast_moutdwm(ast, 0x1E6E0018, data); -+ do { -+ data = ast_mindwm(ast, 0x1E6E001C); -+ } while (!(data & 0x08000000)); -+ -+ data = ast_mindwm(ast, 0x1E6E001C); -+ data = (data >> 8) & 0xff; -+ } -+ ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0008) & 0xffff); -+ data = ast_mindwm(ast, 0x1E6E0018) | 0xC00; -+ ast_moutdwm(ast, 0x1E6E0018, data); -+ -+ ast_moutdwm(ast, 0x1E6E0034, 0x00000001); -+ ast_moutdwm(ast, 0x1E6E000C, 0x00000000); -+ udelay(50); -+ /* Mode Register Setting */ -+ ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100); -+ ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000005); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000007); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000003); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000001); -+ -+ ast_moutdwm(ast, 0x1E6E000C, 0x00005C08); -+ ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000001); -+ ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS | 0x380); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000003); -+ ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS); -+ ast_moutdwm(ast, 0x1E6E0028, 0x00000003); -+ -+ ast_moutdwm(ast, 0x1E6E000C, 0x7FFF5C01); -+ data = 0; -+ if (param->wodt) -+ data = 0x500; -+ if (param->rodt) -+ data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3); -+ ast_moutdwm(ast, 0x1E6E0034, data | 0x3); -+ ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ); -+ -+ /* Calibrate the DQSI delay */ -+ if ((cbr_dll2(ast, param) == false) && (retry++ < 10)) -+ goto ddr2_init_start; -+ -+ /* ECC Memory Initialization */ -+#ifdef ECC -+ ast_moutdwm(ast, 0x1E6E007C, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0070, 0x221); -+ do { -+ data = ast_mindwm(ast, 0x1E6E0070); -+ } while (!(data & 0x00001000)); -+ ast_moutdwm(ast, 0x1E6E0070, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0050, 0x80000000); -+ ast_moutdwm(ast, 0x1E6E0050, 0x00000000); -+#endif -+} -+ -+static void ast_post_chip_2300(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ struct ast2300_dram_param param; -+ u32 temp; -+ u8 reg; -+ -+ reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); -+ if ((reg & 0x80) == 0) { /* vga only */ -+ ast_write32(ast, 0xf004, 0x1e6e0000); -+ ast_write32(ast, 0xf000, 0x1); -+ ast_write32(ast, 0x12000, 0x1688a8a8); -+ do { -+ ; -+ } while (ast_read32(ast, 0x12000) != 0x1); -+ -+ ast_write32(ast, 0x10000, 0xfc600309); -+ do { -+ ; -+ } while (ast_read32(ast, 0x10000) != 0x1); -+ -+ /* Slow down CPU/AHB CLK in VGA only mode */ -+ temp = ast_read32(ast, 0x12008); -+ temp |= 0x73; -+ ast_write32(ast, 0x12008, temp); -+ -+ param.dram_freq = 396; -+ param.dram_type = AST_DDR3; -+ temp = ast_mindwm(ast, 0x1e6e2070); -+ if (temp & 0x01000000) -+ param.dram_type = AST_DDR2; -+ switch (temp & 0x18000000) { -+ case 0: -+ param.dram_chipid = AST_DRAM_512Mx16; -+ break; -+ default: -+ case 0x08000000: -+ param.dram_chipid = AST_DRAM_1Gx16; -+ break; -+ case 0x10000000: -+ param.dram_chipid = AST_DRAM_2Gx16; -+ break; -+ case 0x18000000: -+ param.dram_chipid = AST_DRAM_4Gx16; -+ break; -+ } -+ switch (temp & 0x0c) { -+ default: -+ case 0x00: -+ param.vram_size = AST_VIDMEM_SIZE_8M; -+ break; -+ -+ case 0x04: -+ param.vram_size = AST_VIDMEM_SIZE_16M; -+ break; -+ -+ case 0x08: -+ param.vram_size = AST_VIDMEM_SIZE_32M; -+ break; -+ -+ case 0x0c: -+ param.vram_size = AST_VIDMEM_SIZE_64M; -+ break; -+ } -+ -+ if (param.dram_type == AST_DDR3) { -+ get_ddr3_info(ast, ¶m); -+ ddr3_init(ast, ¶m); -+ } else { -+ get_ddr2_info(ast, ¶m); -+ ddr2_init(ast, ¶m); -+ } -+ -+ temp = ast_mindwm(ast, 0x1e6e2040); -+ ast_moutdwm(ast, 0x1e6e2040, temp | 0x40); -+ } -+ -+ /* wait ready */ -+ do { -+ reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); -+ } while ((reg & 0x40) == 0); -+} -+ -+static bool cbr_test_2500(struct ast_private *ast) -+{ -+ ast_moutdwm(ast, 0x1E6E0074, 0x0000FFFF); -+ ast_moutdwm(ast, 0x1E6E007C, 0xFF00FF00); -+ if (!mmc_test_burst(ast, 0)) -+ return false; -+ if (!mmc_test_single_2500(ast, 0)) -+ return false; -+ return true; -+} -+ -+static bool ddr_test_2500(struct ast_private *ast) -+{ -+ ast_moutdwm(ast, 0x1E6E0074, 0x0000FFFF); -+ ast_moutdwm(ast, 0x1E6E007C, 0xFF00FF00); -+ if (!mmc_test_burst(ast, 0)) -+ return false; -+ if (!mmc_test_burst(ast, 1)) -+ return false; -+ if (!mmc_test_burst(ast, 2)) -+ return false; -+ if (!mmc_test_burst(ast, 3)) -+ return false; -+ if (!mmc_test_single_2500(ast, 0)) -+ return false; -+ return true; -+} -+ -+static void ddr_init_common_2500(struct ast_private *ast) -+{ -+ ast_moutdwm(ast, 0x1E6E0034, 0x00020080); -+ ast_moutdwm(ast, 0x1E6E0008, 0x2003000F); -+ ast_moutdwm(ast, 0x1E6E0038, 0x00000FFF); -+ ast_moutdwm(ast, 0x1E6E0040, 0x88448844); -+ ast_moutdwm(ast, 0x1E6E0044, 0x24422288); -+ ast_moutdwm(ast, 0x1E6E0048, 0x22222222); -+ ast_moutdwm(ast, 0x1E6E004C, 0x22222222); -+ ast_moutdwm(ast, 0x1E6E0050, 0x80000000); -+ ast_moutdwm(ast, 0x1E6E0208, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0218, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0220, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0228, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0230, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E02A8, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E02B0, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0240, 0x86000000); -+ ast_moutdwm(ast, 0x1E6E0244, 0x00008600); -+ ast_moutdwm(ast, 0x1E6E0248, 0x80000000); -+ ast_moutdwm(ast, 0x1E6E024C, 0x80808080); -+} -+ -+static void ddr_phy_init_2500(struct ast_private *ast) -+{ -+ u32 data, pass, timecnt; -+ -+ pass = 0; -+ ast_moutdwm(ast, 0x1E6E0060, 0x00000005); -+ while (!pass) { -+ for (timecnt = 0; timecnt < TIMEOUT; timecnt++) { -+ data = ast_mindwm(ast, 0x1E6E0060) & 0x1; -+ if (!data) -+ break; -+ } -+ if (timecnt != TIMEOUT) { -+ data = ast_mindwm(ast, 0x1E6E0300) & 0x000A0000; -+ if (!data) -+ pass = 1; -+ } -+ if (!pass) { -+ ast_moutdwm(ast, 0x1E6E0060, 0x00000000); -+ udelay(10); /* delay 10 us */ -+ ast_moutdwm(ast, 0x1E6E0060, 0x00000005); -+ } -+ } -+ -+ ast_moutdwm(ast, 0x1E6E0060, 0x00000006); -+} -+ -+/* -+ * Check DRAM Size -+ * 1Gb : 0x80000000 ~ 0x87FFFFFF -+ * 2Gb : 0x80000000 ~ 0x8FFFFFFF -+ * 4Gb : 0x80000000 ~ 0x9FFFFFFF -+ * 8Gb : 0x80000000 ~ 0xBFFFFFFF -+ */ -+static void check_dram_size_2500(struct ast_private *ast, u32 tRFC) -+{ -+ u32 reg_04, reg_14; -+ -+ reg_04 = ast_mindwm(ast, 0x1E6E0004) & 0xfffffffc; -+ reg_14 = ast_mindwm(ast, 0x1E6E0014) & 0xffffff00; -+ -+ ast_moutdwm(ast, 0xA0100000, 0x41424344); -+ ast_moutdwm(ast, 0x90100000, 0x35363738); -+ ast_moutdwm(ast, 0x88100000, 0x292A2B2C); -+ ast_moutdwm(ast, 0x80100000, 0x1D1E1F10); -+ -+ /* Check 8Gbit */ -+ if (ast_mindwm(ast, 0xA0100000) == 0x41424344) { -+ reg_04 |= 0x03; -+ reg_14 |= (tRFC >> 24) & 0xFF; -+ /* Check 4Gbit */ -+ } else if (ast_mindwm(ast, 0x90100000) == 0x35363738) { -+ reg_04 |= 0x02; -+ reg_14 |= (tRFC >> 16) & 0xFF; -+ /* Check 2Gbit */ -+ } else if (ast_mindwm(ast, 0x88100000) == 0x292A2B2C) { -+ reg_04 |= 0x01; -+ reg_14 |= (tRFC >> 8) & 0xFF; -+ } else { -+ reg_14 |= tRFC & 0xFF; -+ } -+ ast_moutdwm(ast, 0x1E6E0004, reg_04); -+ ast_moutdwm(ast, 0x1E6E0014, reg_14); -+} -+ -+static void enable_cache_2500(struct ast_private *ast) -+{ -+ u32 reg_04, data; -+ -+ reg_04 = ast_mindwm(ast, 0x1E6E0004); -+ ast_moutdwm(ast, 0x1E6E0004, reg_04 | 0x1000); -+ -+ do -+ data = ast_mindwm(ast, 0x1E6E0004); -+ while (!(data & 0x80000)); -+ ast_moutdwm(ast, 0x1E6E0004, reg_04 | 0x400); -+} -+ -+static void set_mpll_2500(struct ast_private *ast) -+{ -+ u32 addr, data, param; -+ -+ /* Reset MMC */ -+ ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); -+ ast_moutdwm(ast, 0x1E6E0034, 0x00020080); -+ for (addr = 0x1e6e0004; addr < 0x1e6e0090;) { -+ ast_moutdwm(ast, addr, 0x0); -+ addr += 4; -+ } -+ ast_moutdwm(ast, 0x1E6E0034, 0x00020000); -+ -+ ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8); -+ data = ast_mindwm(ast, 0x1E6E2070) & 0x00800000; -+ if (data) { -+ /* CLKIN = 25MHz */ -+ param = 0x930023E0; -+ ast_moutdwm(ast, 0x1E6E2160, 0x00011320); -+ } else { -+ /* CLKIN = 24MHz */ -+ param = 0x93002400; -+ } -+ ast_moutdwm(ast, 0x1E6E2020, param); -+ udelay(100); -+} -+ -+static void reset_mmc_2500(struct ast_private *ast) -+{ -+ ast_moutdwm(ast, 0x1E78505C, 0x00000004); -+ ast_moutdwm(ast, 0x1E785044, 0x00000001); -+ ast_moutdwm(ast, 0x1E785048, 0x00004755); -+ ast_moutdwm(ast, 0x1E78504C, 0x00000013); -+ mdelay(100); -+ ast_moutdwm(ast, 0x1E785054, 0x00000077); -+ ast_moutdwm(ast, 0x1E6E0000, 0xFC600309); -+} -+ -+static void ddr3_init_2500(struct ast_private *ast, const u32 *ddr_table) -+{ -+ ast_moutdwm(ast, 0x1E6E0004, 0x00000303); -+ ast_moutdwm(ast, 0x1E6E0010, ddr_table[REGIDX_010]); -+ ast_moutdwm(ast, 0x1E6E0014, ddr_table[REGIDX_014]); -+ ast_moutdwm(ast, 0x1E6E0018, ddr_table[REGIDX_018]); -+ ast_moutdwm(ast, 0x1E6E0020, ddr_table[REGIDX_020]); /* MODEREG4/6 */ -+ ast_moutdwm(ast, 0x1E6E0024, ddr_table[REGIDX_024]); /* MODEREG5 */ -+ ast_moutdwm(ast, 0x1E6E002C, -+ ddr_table[REGIDX_02C] | 0x100); /* MODEREG0/2 */ -+ ast_moutdwm(ast, 0x1E6E0030, ddr_table[REGIDX_030]); /* MODEREG1/3 */ -+ -+ /* DDR PHY Setting */ -+ ast_moutdwm(ast, 0x1E6E0200, 0x02492AAE); -+ ast_moutdwm(ast, 0x1E6E0204, 0x00001001); -+ ast_moutdwm(ast, 0x1E6E020C, 0x55E00B0B); -+ ast_moutdwm(ast, 0x1E6E0210, 0x20000000); -+ ast_moutdwm(ast, 0x1E6E0214, ddr_table[REGIDX_214]); -+ ast_moutdwm(ast, 0x1E6E02E0, ddr_table[REGIDX_2E0]); -+ ast_moutdwm(ast, 0x1E6E02E4, ddr_table[REGIDX_2E4]); -+ ast_moutdwm(ast, 0x1E6E02E8, ddr_table[REGIDX_2E8]); -+ ast_moutdwm(ast, 0x1E6E02EC, ddr_table[REGIDX_2EC]); -+ ast_moutdwm(ast, 0x1E6E02F0, ddr_table[REGIDX_2F0]); -+ ast_moutdwm(ast, 0x1E6E02F4, ddr_table[REGIDX_2F4]); -+ ast_moutdwm(ast, 0x1E6E02F8, ddr_table[REGIDX_2F8]); -+ ast_moutdwm(ast, 0x1E6E0290, 0x00100008); -+ ast_moutdwm(ast, 0x1E6E02C0, 0x00000006); -+ -+ /* Controller Setting */ -+ ast_moutdwm(ast, 0x1E6E0034, 0x00020091); -+ -+ /* Wait DDR PHY init done */ -+ ddr_phy_init_2500(ast); -+ -+ ast_moutdwm(ast, 0x1E6E0120, ddr_table[REGIDX_PLL]); -+ ast_moutdwm(ast, 0x1E6E000C, 0x42AA5C81); -+ ast_moutdwm(ast, 0x1E6E0034, 0x0001AF93); -+ -+ check_dram_size_2500(ast, ddr_table[REGIDX_RFC]); -+ enable_cache_2500(ast); -+ ast_moutdwm(ast, 0x1E6E001C, 0x00000008); -+ ast_moutdwm(ast, 0x1E6E0038, 0xFFFFFF00); -+} -+ -+static void ddr4_init_2500(struct ast_private *ast, const u32 *ddr_table) -+{ -+ u32 data, data2, pass, retrycnt; -+ u32 ddr_vref, phy_vref; -+ u32 min_ddr_vref = 0, min_phy_vref = 0; -+ u32 max_ddr_vref = 0, max_phy_vref = 0; -+ -+ ast_moutdwm(ast, 0x1E6E0004, 0x00000313); -+ ast_moutdwm(ast, 0x1E6E0010, ddr_table[REGIDX_010]); -+ ast_moutdwm(ast, 0x1E6E0014, ddr_table[REGIDX_014]); -+ ast_moutdwm(ast, 0x1E6E0018, ddr_table[REGIDX_018]); -+ ast_moutdwm(ast, 0x1E6E0020, ddr_table[REGIDX_020]); /* MODEREG4/6 */ -+ ast_moutdwm(ast, 0x1E6E0024, ddr_table[REGIDX_024]); /* MODEREG5 */ -+ ast_moutdwm(ast, 0x1E6E002C, -+ ddr_table[REGIDX_02C] | 0x100); /* MODEREG0/2 */ -+ ast_moutdwm(ast, 0x1E6E0030, ddr_table[REGIDX_030]); /* MODEREG1/3 */ -+ -+ /* DDR PHY Setting */ -+ ast_moutdwm(ast, 0x1E6E0200, 0x42492AAE); -+ ast_moutdwm(ast, 0x1E6E0204, 0x09002000); -+ ast_moutdwm(ast, 0x1E6E020C, 0x55E00B0B); -+ ast_moutdwm(ast, 0x1E6E0210, 0x20000000); -+ ast_moutdwm(ast, 0x1E6E0214, ddr_table[REGIDX_214]); -+ ast_moutdwm(ast, 0x1E6E02E0, ddr_table[REGIDX_2E0]); -+ ast_moutdwm(ast, 0x1E6E02E4, ddr_table[REGIDX_2E4]); -+ ast_moutdwm(ast, 0x1E6E02E8, ddr_table[REGIDX_2E8]); -+ ast_moutdwm(ast, 0x1E6E02EC, ddr_table[REGIDX_2EC]); -+ ast_moutdwm(ast, 0x1E6E02F0, ddr_table[REGIDX_2F0]); -+ ast_moutdwm(ast, 0x1E6E02F4, ddr_table[REGIDX_2F4]); -+ ast_moutdwm(ast, 0x1E6E02F8, ddr_table[REGIDX_2F8]); -+ ast_moutdwm(ast, 0x1E6E0290, 0x00100008); -+ ast_moutdwm(ast, 0x1E6E02C4, 0x3C183C3C); -+ ast_moutdwm(ast, 0x1E6E02C8, 0x00631E0E); -+ -+ /* Controller Setting */ -+ ast_moutdwm(ast, 0x1E6E0034, 0x0001A991); -+ -+ /* Train PHY Vref first */ -+ pass = 0; -+ -+ for (retrycnt = 0; retrycnt < 4 && pass == 0; retrycnt++) { -+ max_phy_vref = 0x0; -+ pass = 0; -+ ast_moutdwm(ast, 0x1E6E02C0, 0x00001C06); -+ for (phy_vref = 0x40; phy_vref < 0x80; phy_vref++) { -+ ast_moutdwm(ast, 0x1E6E000C, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0060, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E02CC, -+ phy_vref | (phy_vref << 8)); -+ /* Fire DFI Init */ -+ ddr_phy_init_2500(ast); -+ ast_moutdwm(ast, 0x1E6E000C, 0x00005C01); -+ if (cbr_test_2500(ast)) { -+ pass++; -+ data = ast_mindwm(ast, 0x1E6E03D0); -+ data2 = data >> 8; -+ data = data & 0xff; -+ if (data > data2) -+ data = data2; -+ if (max_phy_vref < data) { -+ max_phy_vref = data; -+ min_phy_vref = phy_vref; -+ } -+ } else if (pass > 0) -+ break; -+ } -+ } -+ ast_moutdwm(ast, 0x1E6E02CC, min_phy_vref | (min_phy_vref << 8)); -+ -+ /* Train DDR Vref next */ -+ pass = 0; -+ -+ for (retrycnt = 0; retrycnt < 4 && pass == 0; retrycnt++) { -+ min_ddr_vref = 0xFF; -+ max_ddr_vref = 0x0; -+ pass = 0; -+ for (ddr_vref = 0x00; ddr_vref < 0x40; ddr_vref++) { -+ ast_moutdwm(ast, 0x1E6E000C, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0060, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E02C0, -+ 0x00000006 | (ddr_vref << 8)); -+ /* Fire DFI Init */ -+ ddr_phy_init_2500(ast); -+ ast_moutdwm(ast, 0x1E6E000C, 0x00005C01); -+ if (cbr_test_2500(ast)) { -+ pass++; -+ if (min_ddr_vref > ddr_vref) -+ min_ddr_vref = ddr_vref; -+ if (max_ddr_vref < ddr_vref) -+ max_ddr_vref = ddr_vref; -+ } else if (pass != 0) -+ break; -+ } -+ } -+ -+ ast_moutdwm(ast, 0x1E6E000C, 0x00000000); -+ ast_moutdwm(ast, 0x1E6E0060, 0x00000000); -+ ddr_vref = (min_ddr_vref + max_ddr_vref + 1) >> 1; -+ ast_moutdwm(ast, 0x1E6E02C0, 0x00000006 | (ddr_vref << 8)); -+ -+ /* Wait DDR PHY init done */ -+ ddr_phy_init_2500(ast); -+ -+ ast_moutdwm(ast, 0x1E6E0120, ddr_table[REGIDX_PLL]); -+ ast_moutdwm(ast, 0x1E6E000C, 0x42AA5C81); -+ ast_moutdwm(ast, 0x1E6E0034, 0x0001AF93); -+ -+ check_dram_size_2500(ast, ddr_table[REGIDX_RFC]); -+ enable_cache_2500(ast); -+ ast_moutdwm(ast, 0x1E6E001C, 0x00000008); -+ ast_moutdwm(ast, 0x1E6E0038, 0xFFFFFF00); -+} -+ -+static bool ast_dram_init_2500(struct ast_private *ast) -+{ -+ u32 data; -+ u32 max_tries = 5; -+ -+ do { -+ if (max_tries-- == 0) -+ return false; -+ set_mpll_2500(ast); -+ reset_mmc_2500(ast); -+ ddr_init_common_2500(ast); -+ -+ data = ast_mindwm(ast, 0x1E6E2070); -+ if (data & 0x01000000) -+ ddr4_init_2500(ast, ast2500_ddr4_1600_timing_table); -+ else -+ ddr3_init_2500(ast, ast2500_ddr3_1600_timing_table); -+ } while (!ddr_test_2500(ast)); -+ -+ ast_moutdwm(ast, 0x1E6E2040, ast_mindwm(ast, 0x1E6E2040) | 0x41); -+ -+ /* Patch code */ -+ data = ast_mindwm(ast, 0x1E6E200C) & 0xF9FFFFFF; -+ ast_moutdwm(ast, 0x1E6E200C, data | 0x10000000); -+ -+ return true; -+} -+ -+void ast_patch_ahb_2500(struct ast_private *ast) -+{ -+ u32 data; -+ -+ /* Clear bus lock condition */ -+ ast_moutdwm(ast, 0x1e600000, 0xAEED1A03); -+ ast_moutdwm(ast, 0x1e600084, 0x00010000); -+ ast_moutdwm(ast, 0x1e600088, 0x00000000); -+ ast_moutdwm(ast, 0x1e6e2000, 0x1688A8A8); -+ data = ast_mindwm(ast, 0x1e6e2070); -+ if (data & 0x08000000) { /* check fast reset */ -+ /* -+ * If "Fast restet" is enabled for ARM-ICE debugger, -+ * then WDT needs to enable, that -+ * WDT04 is WDT#1 Reload reg. -+ * WDT08 is WDT#1 counter restart reg to avoid system deadlock -+ * WDT0C is WDT#1 control reg -+ * [6:5]:= 01:Full chip -+ * [4]:= 1:1MHz clock source -+ * [1]:= 1:WDT will be cleeared and disabled after timeout occurs -+ * [0]:= 1:WDT enable -+ */ -+ ast_moutdwm(ast, 0x1E785004, 0x00000010); -+ ast_moutdwm(ast, 0x1E785008, 0x00004755); -+ ast_moutdwm(ast, 0x1E78500c, 0x00000033); -+ udelay(1000); -+ } -+ do { -+ ast_moutdwm(ast, 0x1e6e2000, 0x1688A8A8); -+ data = ast_mindwm(ast, 0x1e6e2000); -+ } while (data != 1); -+ ast_moutdwm(ast, 0x1e6e207c, 0x08000000); /* clear fast reset */ -+} -+ -+void ast_post_chip_2500(struct drm_device *dev) -+{ -+ struct ast_private *ast = to_ast_private(dev); -+ u32 temp; -+ u8 reg; -+ -+ reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); -+ if ((reg & AST_VRAM_INIT_STATUS_MASK) == 0) { /* vga only */ -+ /* Clear bus lock condition */ -+ ast_patch_ahb_2500(ast); -+ -+ /* Disable watchdog */ -+ ast_moutdwm(ast, 0x1E78502C, 0x00000000); -+ ast_moutdwm(ast, 0x1E78504C, 0x00000000); -+ -+ /* -+ * Reset USB port to patch USB unknown device issue -+ * SCU90 is Multi-function Pin Control #5 -+ * [29]:= 1:Enable USB2.0 Host port#1 (that the mutually shared USB2.0 Hub -+ * port). -+ * SCU94 is Multi-function Pin Control #6 -+ * [14:13]:= 1x:USB2.0 Host2 controller -+ * SCU70 is Hardware Strap reg -+ * [23]:= 1:CLKIN is 25MHz and USBCK1 = 24/48 MHz (determined by -+ * [18]: 0(24)/1(48) MHz) -+ * SCU7C is Write clear reg to SCU70 -+ * [23]:= write 1 and then SCU70[23] will be clear as 0b. -+ */ -+ ast_moutdwm(ast, 0x1E6E2090, 0x20000000); -+ ast_moutdwm(ast, 0x1E6E2094, 0x00004000); -+ if (ast_mindwm(ast, 0x1E6E2070) & 0x00800000) { -+ ast_moutdwm(ast, 0x1E6E207C, 0x00800000); -+ mdelay(100); -+ ast_moutdwm(ast, 0x1E6E2070, 0x00800000); -+ } -+ /* Modify eSPI reset pin */ -+ temp = ast_mindwm(ast, 0x1E6E2070); -+ if (temp & 0x02000000) -+ ast_moutdwm(ast, 0x1E6E207C, 0x00004000); -+ -+ /* Slow down CPU/AHB CLK in VGA only mode */ -+ temp = ast_read32(ast, 0x12008); -+ temp |= 0x73; -+ ast_write32(ast, 0x12008, temp); -+ -+ if (!ast_dram_init_2500(ast)) -+ drm_err(dev, "DRAM init failed !\n"); -+ -+ temp = ast_mindwm(ast, 0x1e6e2040); -+ ast_moutdwm(ast, 0x1e6e2040, temp | 0x40); -+ } -+ -+ /* wait ready */ -+ do { -+ reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff); -+ } while ((reg & 0x40) == 0); -+} -diff --git a/drivers/gpu/drm/loongson/ast_old/ast_tables.h b/drivers/gpu/drm/loongson/ast_old/ast_tables.h -new file mode 100644 -index 0000000..e92a17a ---- /dev/null -+++ b/drivers/gpu/drm/loongson/ast_old/ast_tables.h -@@ -0,0 +1,342 @@ -+/* -+ * Copyright (c) 2005 ASPEED Technology Inc. -+ * -+ * Permission to use, copy, modify, distribute, and sell this software and its -+ * documentation for any purpose is hereby granted without fee, provided that -+ * the above copyright notice appear in all copies and that both that -+ * copyright notice and this permission notice appear in supporting -+ * documentation, and that the name of the authors not be used in -+ * advertising or publicity pertaining to distribution of the software without -+ * specific, written prior permission. The authors makes no representations -+ * about the suitability of this software for any purpose. It is provided -+ * "as is" without express or implied warranty. -+ * -+ * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO -+ * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR -+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, -+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER -+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -+ * PERFORMANCE OF THIS SOFTWARE. -+ */ -+/* Ported from xf86-video-ast driver */ -+ -+#ifndef AST_TABLES_H -+#define AST_TABLES_H -+ -+/* Std. Table Index Definition */ -+#define TextModeIndex 0 -+#define EGAModeIndex 1 -+#define VGAModeIndex 2 -+#define HiCModeIndex 3 -+#define TrueCModeIndex 4 -+ -+#define Charx8Dot 0x00000001 -+#define HalfDCLK 0x00000002 -+#define DoubleScanMode 0x00000004 -+#define LineCompareOff 0x00000008 -+#define HBorder 0x00000020 -+#define VBorder 0x00000010 -+#define WideScreenMode 0x00000100 -+#define NewModeInfo 0x00000200 -+#define NHSync 0x00000400 -+#define PHSync 0x00000800 -+#define NVSync 0x00001000 -+#define PVSync 0x00002000 -+#define SyncPP (PVSync | PHSync) -+#define SyncPN (PVSync | NHSync) -+#define SyncNP (NVSync | PHSync) -+#define SyncNN (NVSync | NHSync) -+#define AST2500PreCatchCRT 0x00004000 -+ -+/* DCLK Index */ -+#define VCLK25_175 0x00 -+#define VCLK28_322 0x01 -+#define VCLK31_5 0x02 -+#define VCLK36 0x03 -+#define VCLK40 0x04 -+#define VCLK49_5 0x05 -+#define VCLK50 0x06 -+#define VCLK56_25 0x07 -+#define VCLK65 0x08 -+#define VCLK75 0x09 -+#define VCLK78_75 0x0A -+#define VCLK94_5 0x0B -+#define VCLK108 0x0C -+#define VCLK135 0x0D -+#define VCLK157_5 0x0E -+#define VCLK162 0x0F -+#define VCLK154 0x10 -+#define VCLK83_5 0x11 -+#define VCLK106_5 0x12 -+#define VCLK146_25 0x13 -+#define VCLK148_5 0x14 -+#define VCLK71 0x15 -+#define VCLK88_75 0x16 -+#define VCLK119 0x17 -+#define VCLK85_5 0x18 -+#define VCLK97_75 0x19 -+#define VCLK118_25 0x1A -+ -+static const struct ast_vbios_dclk_info dclk_table[] = { -+ { 0x2C, 0xE7, 0x03 }, /* 00: VCLK25_175 */ -+ { 0x95, 0x62, 0x03 }, /* 01: VCLK28_322 */ -+ { 0x67, 0x63, 0x01 }, /* 02: VCLK31_5 */ -+ { 0x76, 0x63, 0x01 }, /* 03: VCLK36 */ -+ { 0xEE, 0x67, 0x01 }, /* 04: VCLK40 */ -+ { 0x82, 0x62, 0x01 }, /* 05: VCLK49_5 */ -+ { 0xC6, 0x64, 0x01 }, /* 06: VCLK50 */ -+ { 0x94, 0x62, 0x01 }, /* 07: VCLK56_25 */ -+ { 0x80, 0x64, 0x00 }, /* 08: VCLK65 */ -+ { 0x7B, 0x63, 0x00 }, /* 09: VCLK75 */ -+ { 0x67, 0x62, 0x00 }, /* 0A: VCLK78_75 */ -+ { 0x7C, 0x62, 0x00 }, /* 0B: VCLK94_5 */ -+ { 0x8E, 0x62, 0x00 }, /* 0C: VCLK108 */ -+ { 0x85, 0x24, 0x00 }, /* 0D: VCLK135 */ -+ { 0x67, 0x22, 0x00 }, /* 0E: VCLK157_5 */ -+ { 0x6A, 0x22, 0x00 }, /* 0F: VCLK162 */ -+ { 0x4d, 0x4c, 0x80 }, /* 10: VCLK154 */ -+ { 0x68, 0x6f, 0x80 }, /* 11: VCLK83.5 */ -+ { 0x28, 0x49, 0x80 }, /* 12: VCLK106.5 */ -+ { 0x37, 0x49, 0x80 }, /* 13: VCLK146.25 */ -+ { 0x1f, 0x45, 0x80 }, /* 14: VCLK148.5 */ -+ { 0x47, 0x6c, 0x80 }, /* 15: VCLK71 */ -+ { 0x25, 0x65, 0x80 }, /* 16: VCLK88.75 */ -+ { 0x77, 0x58, 0x80 }, /* 17: VCLK119 */ -+ { 0x32, 0x67, 0x80 }, /* 18: VCLK85_5 */ -+ { 0x6a, 0x6d, 0x80 }, /* 19: VCLK97_75 */ -+ { 0x3b, 0x2c, 0x81 }, /* 1A: VCLK118_25 */ -+}; -+ -+static const struct ast_vbios_dclk_info dclk_table_ast2500[] = { -+ { 0x2C, 0xE7, 0x03 }, /* 00: VCLK25_175 */ -+ { 0x95, 0x62, 0x03 }, /* 01: VCLK28_322 */ -+ { 0x67, 0x63, 0x01 }, /* 02: VCLK31_5 */ -+ { 0x76, 0x63, 0x01 }, /* 03: VCLK36 */ -+ { 0xEE, 0x67, 0x01 }, /* 04: VCLK40 */ -+ { 0x82, 0x62, 0x01 }, /* 05: VCLK49_5 */ -+ { 0xC6, 0x64, 0x01 }, /* 06: VCLK50 */ -+ { 0x94, 0x62, 0x01 }, /* 07: VCLK56_25 */ -+ { 0x80, 0x64, 0x00 }, /* 08: VCLK65 */ -+ { 0x7B, 0x63, 0x00 }, /* 09: VCLK75 */ -+ { 0x67, 0x62, 0x00 }, /* 0A: VCLK78_75 */ -+ { 0x7C, 0x62, 0x00 }, /* 0B: VCLK94_5 */ -+ { 0x8E, 0x62, 0x00 }, /* 0C: VCLK108 */ -+ { 0x85, 0x24, 0x00 }, /* 0D: VCLK135 */ -+ { 0x67, 0x22, 0x00 }, /* 0E: VCLK157_5 */ -+ { 0x6A, 0x22, 0x00 }, /* 0F: VCLK162 */ -+ { 0x4d, 0x4c, 0x80 }, /* 10: VCLK154 */ -+ { 0x68, 0x6f, 0x80 }, /* 11: VCLK83.5 */ -+ { 0x28, 0x49, 0x80 }, /* 12: VCLK106.5 */ -+ { 0x37, 0x49, 0x80 }, /* 13: VCLK146.25 */ -+ { 0x1f, 0x45, 0x80 }, /* 14: VCLK148.5 */ -+ { 0x47, 0x6c, 0x80 }, /* 15: VCLK71 */ -+ { 0x25, 0x65, 0x80 }, /* 16: VCLK88.75 */ -+ { 0x58, 0x01, 0x42 }, /* 17: VCLK119 */ -+ { 0x32, 0x67, 0x80 }, /* 18: VCLK85_5 */ -+ { 0x6a, 0x6d, 0x80 }, /* 19: VCLK97_75 */ -+ { 0x44, 0x20, 0x43 }, /* 1A: VCLK118_25 */ -+}; -+ -+static const struct ast_vbios_stdtable vbios_stdtable[] = { -+ /* MD_2_3_400 */ -+ { 0x67, -+ { 0x00, 0x03, 0x00, 0x02 }, -+ { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, -+ 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x8e, -+ 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3, 0xff }, -+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, -+ 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08 }, -+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff } }, -+ /* Mode12/ExtEGATable */ -+ { 0xe3, -+ { 0x01, 0x0f, 0x00, 0x06 }, -+ { 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e, 0x00, -+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x8b, -+ 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, 0xff }, -+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, -+ 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x01, 0x00, 0x0f, 0x00 }, -+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff } }, -+ /* ExtVGATable */ -+ { 0x2f, -+ { 0x01, 0x0f, 0x00, 0x0e }, -+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, 0x00, -+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x8c, -+ 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, 0xff }, -+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, -+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x00, 0x00, 0x00 }, -+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff } }, -+ /* ExtHiCTable */ -+ { 0x2f, -+ { 0x01, 0x0f, 0x00, 0x0e }, -+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, 0x00, -+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x8c, -+ 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, 0xff }, -+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, -+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x00, 0x00, 0x00 }, -+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff } }, -+ /* ExtTrueCTable */ -+ { 0x2f, -+ { 0x01, 0x0f, 0x00, 0x0e }, -+ { 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e, 0x00, -+ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x8c, -+ 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3, 0xff }, -+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, -+ 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x00, 0x00, 0x00 }, -+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff } }, -+}; -+ -+static const struct ast_vbios_enhtable res_640x480[] = { -+ { 800, 640, 8, 96, 525, 480, 2, 2, VCLK25_175, /* 60Hz */ -+ (SyncNN | HBorder | VBorder | Charx8Dot), 60, 1, 0x2E }, -+ { 832, 640, 16, 40, 520, 480, 1, 3, VCLK31_5, /* 72Hz */ -+ (SyncNN | HBorder | VBorder | Charx8Dot), 72, 2, 0x2E }, -+ { 840, 640, 16, 64, 500, 480, 1, 3, VCLK31_5, /* 75Hz */ -+ (SyncNN | Charx8Dot), 75, 3, 0x2E }, -+ { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36, /* 85Hz */ -+ (SyncNN | Charx8Dot), 85, 4, 0x2E }, -+ { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36, /* end */ -+ (SyncNN | Charx8Dot), 0xFF, 4, 0x2E }, -+}; -+ -+static const struct ast_vbios_enhtable res_800x600[] = { -+ { 1024, 800, 24, 72, 625, 600, 1, 2, VCLK36, /* 56Hz */ -+ (SyncPP | Charx8Dot), 56, 1, 0x30 }, -+ { 1056, 800, 40, 128, 628, 600, 1, 4, VCLK40, /* 60Hz */ -+ (SyncPP | Charx8Dot), 60, 2, 0x30 }, -+ { 1040, 800, 56, 120, 666, 600, 37, 6, VCLK50, /* 72Hz */ -+ (SyncPP | Charx8Dot), 72, 3, 0x30 }, -+ { 1056, 800, 16, 80, 625, 600, 1, 3, VCLK49_5, /* 75Hz */ -+ (SyncPP | Charx8Dot), 75, 4, 0x30 }, -+ { 1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25, /* 85Hz */ -+ (SyncPP | Charx8Dot), 84, 5, 0x30 }, -+ { 1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25, /* end */ -+ (SyncPP | Charx8Dot), 0xFF, 5, 0x30 }, -+}; -+ -+static const struct ast_vbios_enhtable res_1024x768[] = { -+ { 1344, 1024, 24, 136, 806, 768, 3, 6, VCLK65, /* 60Hz */ -+ (SyncNN | Charx8Dot), 60, 1, 0x31 }, -+ { 1328, 1024, 24, 136, 806, 768, 3, 6, VCLK75, /* 70Hz */ -+ (SyncNN | Charx8Dot), 70, 2, 0x31 }, -+ { 1312, 1024, 16, 96, 800, 768, 1, 3, VCLK78_75, /* 75Hz */ -+ (SyncPP | Charx8Dot), 75, 3, 0x31 }, -+ { 1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5, /* 85Hz */ -+ (SyncPP | Charx8Dot), 84, 4, 0x31 }, -+ { 1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5, /* end */ -+ (SyncPP | Charx8Dot), 0xFF, 4, 0x31 }, -+}; -+ -+static const struct ast_vbios_enhtable res_1280x1024[] = { -+ { 1688, 1280, 48, 112, 1066, 1024, 1, 3, VCLK108, /* 60Hz */ -+ (SyncPP | Charx8Dot), 60, 1, 0x32 }, -+ { 1688, 1280, 16, 144, 1066, 1024, 1, 3, VCLK135, /* 75Hz */ -+ (SyncPP | Charx8Dot), 75, 2, 0x32 }, -+ { 1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5, /* 85Hz */ -+ (SyncPP | Charx8Dot), 85, 3, 0x32 }, -+ { 1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5, /* end */ -+ (SyncPP | Charx8Dot), 0xFF, 3, 0x32 }, -+}; -+ -+static const struct ast_vbios_enhtable res_1600x1200[] = { -+ { 2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162, /* 60Hz */ -+ (SyncPP | Charx8Dot), 60, 1, 0x33 }, -+ { 2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162, /* end */ -+ (SyncPP | Charx8Dot), 0xFF, 1, 0x33 }, -+}; -+ -+static const struct ast_vbios_enhtable res_1152x864[] = { -+ { 1600, 1152, 64, 128, 900, 864, 1, 3, VCLK108, /* 75Hz */ -+ (SyncPP | Charx8Dot | NewModeInfo), 75, 1, 0x3B }, -+ { 1600, 1152, 64, 128, 900, 864, 1, 3, VCLK108, /* end */ -+ (SyncPP | Charx8Dot | NewModeInfo), 0xFF, 1, 0x3B }, -+}; -+ -+/* 16:9 */ -+static const struct ast_vbios_enhtable res_1360x768[] = { -+ { 1792, 1360, 64, 112, 795, 768, 3, 6, VCLK85_5, /* 60Hz */ -+ (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), -+ 60, 1, 0x39 }, -+ { 1792, 1360, 64, 112, 795, 768, 3, 6, VCLK85_5, /* end */ -+ (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo | -+ AST2500PreCatchCRT), -+ 0xFF, 1, 0x39 }, -+}; -+ -+static const struct ast_vbios_enhtable res_1600x900[] = { -+ { 1760, 1600, 48, 32, 926, 900, 3, 5, VCLK97_75, /* 60Hz CVT RB */ -+ (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo | -+ AST2500PreCatchCRT), -+ 60, 1, 0x3A }, -+ { 2112, 1600, 88, 168, 934, 900, 3, 5, VCLK118_25, /* 60Hz CVT */ -+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), -+ 60, 2, 0x3A }, -+ { 2112, 1600, 88, 168, 934, 900, 3, 5, VCLK118_25, /* 60Hz CVT */ -+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), -+ 0xFF, 2, 0x3A }, -+}; -+ -+static const struct ast_vbios_enhtable res_1920x1080[] = { -+ { 2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */ -+ (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo | -+ AST2500PreCatchCRT), -+ 60, 1, 0x38 }, -+ { 2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */ -+ (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo | -+ AST2500PreCatchCRT), -+ 0xFF, 1, 0x38 }, -+}; -+ -+/* 16:10 */ -+static const struct ast_vbios_enhtable res_1280x800[] = { -+ { 1440, 1280, 48, 32, 823, 800, 3, 6, VCLK71, /* 60Hz RB */ -+ (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo | -+ AST2500PreCatchCRT), -+ 60, 1, 0x35 }, -+ { 1680, 1280, 72, 128, 831, 800, 3, 6, VCLK83_5, /* 60Hz */ -+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), -+ 60, 2, 0x35 }, -+ { 1680, 1280, 72, 128, 831, 800, 3, 6, VCLK83_5, /* 60Hz */ -+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), -+ 0xFF, 2, 0x35 }, -+ -+}; -+ -+static const struct ast_vbios_enhtable res_1440x900[] = { -+ { 1600, 1440, 48, 32, 926, 900, 3, 6, VCLK88_75, /* 60Hz RB */ -+ (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo | -+ AST2500PreCatchCRT), -+ 60, 1, 0x36 }, -+ { 1904, 1440, 80, 152, 934, 900, 3, 6, VCLK106_5, /* 60Hz */ -+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), -+ 60, 2, 0x36 }, -+ { 1904, 1440, 80, 152, 934, 900, 3, 6, VCLK106_5, /* 60Hz */ -+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), -+ 0xFF, 2, 0x36 }, -+}; -+ -+static const struct ast_vbios_enhtable res_1680x1050[] = { -+ { 1840, 1680, 48, 32, 1080, 1050, 3, 6, VCLK119, /* 60Hz RB */ -+ (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo | -+ AST2500PreCatchCRT), -+ 60, 1, 0x37 }, -+ { 2240, 1680, 104, 176, 1089, 1050, 3, 6, VCLK146_25, /* 60Hz */ -+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), -+ 60, 2, 0x37 }, -+ { 2240, 1680, 104, 176, 1089, 1050, 3, 6, VCLK146_25, /* 60Hz */ -+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), -+ 0xFF, 2, 0x37 }, -+}; -+ -+static const struct ast_vbios_enhtable res_1920x1200[] = { -+ { 2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz RB*/ -+ (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo | -+ AST2500PreCatchCRT), -+ 60, 1, 0x34 }, -+ { 2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz RB */ -+ (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo | -+ AST2500PreCatchCRT), -+ 0xFF, 1, 0x34 }, -+}; -+ -+#endif -diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c -index 62cc8a5..dd7c248 100644 ---- a/drivers/gpu/drm/radeon/cik.c -+++ b/drivers/gpu/drm/radeon/cik.c -@@ -8093,7 +8093,9 @@ int cik_irq_process(struct radeon_device *rdev) - if (queue_thermal) - schedule_work(&rdev->pm.dpm.thermal.work); - rdev->ih.rptr = rptr; -+#ifdef CONFIG_LOONGARCH - WREG32(IH_RB_RPTR, rptr); -+#endif - atomic_set(&rdev->ih.lock, 0); - - /* make sure wptr hasn't changed while processing */ -diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c -index 0dc5db5..84ce0e5 100644 ---- a/drivers/gpu/drm/radeon/evergreen.c -+++ b/drivers/gpu/drm/radeon/evergreen.c -@@ -4922,7 +4922,9 @@ int evergreen_irq_process(struct radeon_device *rdev) - if (queue_thermal && rdev->pm.dpm_enabled) - schedule_work(&rdev->pm.dpm.thermal.work); - rdev->ih.rptr = rptr; -+#ifdef CONFIG_LOONGARCH - WREG32(IH_RB_RPTR, rptr); -+#endif - atomic_set(&rdev->ih.lock, 0); - - /* make sure wptr hasn't changed while processing */ -diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c -index 664b10b..43c1fde 100644 ---- a/drivers/gpu/drm/radeon/r600.c -+++ b/drivers/gpu/drm/radeon/r600.c -@@ -4328,7 +4328,9 @@ int r600_irq_process(struct radeon_device *rdev) - if (queue_thermal && rdev->pm.dpm_enabled) - schedule_work(&rdev->pm.dpm.thermal.work); - rdev->ih.rptr = rptr; -+#ifdef CONFIG_LOONGARCH - WREG32(IH_RB_RPTR, rptr); -+#endif - atomic_set(&rdev->ih.lock, 0); - - /* make sure wptr hasn't changed while processing */ -diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c -index 95cb2b4..32c8803 100644 ---- a/drivers/gpu/drm/radeon/si.c -+++ b/drivers/gpu/drm/radeon/si.c -@@ -6442,7 +6442,9 @@ int si_irq_process(struct radeon_device *rdev) - if (queue_thermal && rdev->pm.dpm_enabled) - schedule_work(&rdev->pm.dpm.thermal.work); - rdev->ih.rptr = rptr; -+#ifdef CONFIG_LOONGARCH - WREG32(IH_RB_RPTR, rptr); -+#endif - atomic_set(&rdev->ih.lock, 0); - - /* make sure wptr hasn't changed while processing */ -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 87b8b59..4404af7 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -412,6 +412,15 @@ config SENSORS_ASPEED - This driver can also be built as a module. If so, the module - will be called aspeed_pwm_tacho. - -+config SENSORS_PHYTIUM -+ tristate "Phytium Fan tach and capture counter driver" -+ help -+ This driver provides support for Phytium Fan Tacho and capture -+ counter controllers. -+ -+ This driver can also be built as a module. If so, the module -+ will be called tacho-phytium. -+ - config SENSORS_ATXP1 - tristate "Attansic ATXP1 VID controller" - depends on I2C -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index 025cfdb..521b618 100644 ---- a/drivers/hwmon/Makefile -+++ b/drivers/hwmon/Makefile -@@ -155,6 +155,7 @@ obj-$(CONFIG_MAX31827) += max31827.o - obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o - obj-$(CONFIG_SENSORS_MC34VR500) += mc34vr500.o - obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o -+obj-$(CONFIG_SENSORS_PHYTIUM) += tacho-phytium.o - obj-$(CONFIG_SENSORS_TC654) += tc654.o - obj-$(CONFIG_SENSORS_TPS23861) += tps23861.o - obj-$(CONFIG_SENSORS_MLXREG_FAN) += mlxreg-fan.o -diff --git a/drivers/hwmon/tacho-phytium.c b/drivers/hwmon/tacho-phytium.c -new file mode 100644 -index 0000000..aa6b508 ---- /dev/null -+++ b/drivers/hwmon/tacho-phytium.c -@@ -0,0 +1,416 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Hwmon driver for Phytium tachometer. -+ * -+ * Copyright (C) 2021-2023, Phytium Technology Co., Ltd. -+ */ -+ -+#include <linux/module.h> -+#include <linux/init.h> -+#include <linux/slab.h> -+#include <linux/clk.h> -+#include <linux/delay.h> -+#include <linux/of.h> -+#include <linux/interrupt.h> -+#include <linux/irq.h> -+#include <linux/platform_device.h> -+#include <linux/err.h> -+#include <linux/mutex.h> -+#include <linux/hwmon.h> -+#include <linux/hwmon-sysfs.h> -+ -+#include <linux/acpi.h> -+ -+#define TIMER_CTRL_REG 0x00 -+#define TIMER_CTRL_MODE_SHIFT 0//0:1 -+#define TIMER_CTRL_RESET_SHIFT BIT(2) -+#define TIMER_CTRL_FORCE_SHIFT BIT(3) -+#define TIMER_CTRL_CAPTURE_EN_SHIFT BIT(4) -+#define TIMER_CTRL_CAPTURE_CNT_SHIFT 5//5:11 -+#define TIMER_CTRL_ANTI_JITTER_SHIFT 18//18:19 -+#define TIMER_CTRL_TACHO_MODE_SHIFT 20//20:21 -+#define TIMER_CTRL_TIMER_CNT_MODE_SHIFT BIT(22) -+#define TIMER_CTRL_BIT_SET_SHIFT 24 -+#define TIMER_CTRL_CNT_EN_SHIFT BIT(25) -+#define TIMER_CTRL_CNT_CLR_SHIFT BIT(26) -+#define TIMER_CTRL_TIMER_MODE_SHIFT BIT(27) -+#define TIMER_CTRL_PULSE_NUM_SHIFT 28//28:30 -+#define TIMER_CTRL_TACHO_EN_SHIFT BIT(31) -+#define TIMER_TACHO_RES_REG 0x04 -+#define TIMER_TACHO_RES_VALID_SHIFT BIT(31) -+#define TIMER_TACHO_RES_MASK GENMASK(30, 0) -+#define TIMER_CMP_VALUE_UP_REG 0x08 -+#define TIMER_CMP_VALUE_LOW_REG 0x1C -+#define TIMER_CNT_VALUE_UP_REG 0x20 -+#define TIMER_CNT_VALUE_LOW_REG 0x24 -+#define TIMER_INT_MASK_REG 0x28 -+#define TIMER_INT_STAT_REG 0x2C -+#define TIMER_INT_CAPTURE_SHIFT BIT(5) -+#define TIMER_INT_CYC_COMP_SHIFT BIT(4) -+#define TIMER_INT_ONE_COMP_SHIFT BIT(3) -+#define TIMER_INT_ROLLOVER_SHIFT BIT(2) -+#define TIMER_INT_TACHO_UNDER_SHIFT BIT(1) -+#define TIMER_INT_TACHO_OVER_SHIFT BIT(0) -+#define TIMER_TACHO_OVER_REG 0x30 -+#define TIMER_TACHO_UNDER_REG 0x34 -+#define TIMER_START_VALUE_REG 0x38 -+ -+#define TIMER_INT_CLR_MASK GENMASK(5, 0) -+ -+enum tacho_modes { -+ tacho_mode = 1, -+ capture_mode, -+}; -+ -+enum edge_modes { -+ rising_edge, -+ falling_edge, -+ double_edge, -+}; -+ -+struct phytium_tacho { -+ struct device *dev; -+ struct device *hwmon; -+ void __iomem *base; -+ struct clk *clk; -+ u32 freq; -+ int irq; -+ u8 work_mode; -+ u8 edge_mode; -+ u32 debounce; -+}; -+ -+static u16 capture_count; -+ -+static void phytium_tacho_init(struct phytium_tacho *tacho) -+{ -+ u32 val; -+ -+ if (tacho->work_mode == tacho_mode) { -+ val = (TIMER_CTRL_TACHO_EN_SHIFT | -+ TIMER_CTRL_CNT_EN_SHIFT | -+ (tacho->edge_mode << TIMER_CTRL_TACHO_MODE_SHIFT) | -+ (tacho->debounce << TIMER_CTRL_ANTI_JITTER_SHIFT) | -+ (tacho->work_mode << TIMER_CTRL_MODE_SHIFT)); -+ writel_relaxed(val, tacho->base + TIMER_CTRL_REG); -+ writel_relaxed(0x2faf07f, tacho->base + TIMER_CMP_VALUE_LOW_REG); -+ } else { -+ val = (TIMER_CTRL_TACHO_EN_SHIFT | -+ TIMER_CTRL_CNT_EN_SHIFT | -+ (tacho->edge_mode << TIMER_CTRL_TACHO_MODE_SHIFT) | -+ (tacho->debounce << TIMER_CTRL_ANTI_JITTER_SHIFT) | -+ TIMER_CTRL_CAPTURE_EN_SHIFT | -+ (0x7f << TIMER_CTRL_CAPTURE_CNT_SHIFT) | -+ (tacho->work_mode << TIMER_CTRL_MODE_SHIFT)), -+ writel_relaxed(val, tacho->base + TIMER_CTRL_REG); -+ writel_relaxed(0x20, tacho->base + TIMER_INT_MASK_REG); -+ } -+} -+ -+static int phytium_get_fan_tach_rpm(struct phytium_tacho *priv) -+{ -+ u64 raw_data, tach_div, clk_source; -+ u8 mode, both; -+ unsigned long timeout; -+ unsigned long loopcounter; -+ -+ timeout = jiffies + msecs_to_jiffies(500); -+ -+ for (loopcounter = 0;; loopcounter++) { -+ raw_data = readl_relaxed(priv->base + TIMER_TACHO_RES_REG); -+ -+ if (raw_data & TIMER_TACHO_RES_VALID_SHIFT) -+ break; -+ -+ if (time_after(jiffies, timeout)) -+ return -ETIMEDOUT; -+ -+ if (loopcounter > 3000) -+ msleep(20); -+ else { -+ udelay(100); -+ cond_resched(); -+ } -+ } -+ -+ raw_data = raw_data & TIMER_TACHO_RES_MASK; -+ clk_source = priv->freq; -+ mode = priv->edge_mode; -+ both = (mode == double_edge) ? 1 : 0; -+ tach_div = 1 << both; -+ -+ if (raw_data == 0) -+ return 0; -+ -+ return (clk_source * 60 * raw_data) / 0x2faf080 / tach_div; -+} -+ -+static ssize_t show_rpm(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ int rpm; -+ struct phytium_tacho *priv = dev_get_drvdata(dev); -+ -+ rpm = phytium_get_fan_tach_rpm(priv); -+ if (rpm < 0) -+ return rpm; -+ -+ return sprintf(buf, "%d\n", rpm); -+} -+ -+static SENSOR_DEVICE_ATTR(fan_input, 0444, -+ show_rpm, NULL, 0); -+ -+static struct attribute *tacho_dev_attrs[] = { -+ &sensor_dev_attr_fan_input.dev_attr.attr, -+ NULL -+}; -+ -+static umode_t tacho_dev_is_visible(struct kobject *kobj, -+ struct attribute *a, int index) -+{ -+ return a->mode; -+} -+ -+static const struct attribute_group tacho_group = { -+ .attrs = tacho_dev_attrs, -+ .is_visible = tacho_dev_is_visible, -+}; -+ -+static const struct attribute_group *tacho_groups[] = { -+ &tacho_group, -+ NULL -+}; -+ -+static irqreturn_t capture_irq_handler(int irq, void *dev_id) -+{ -+ struct phytium_tacho *priv = dev_id; -+ u32 status = readl_relaxed(priv->base + TIMER_INT_STAT_REG); -+ -+ if (status & TIMER_INT_CAPTURE_SHIFT) { -+ capture_count++; -+ -+ if (capture_count == 0) -+ dev_err(priv->dev, "Capture counter is overflowed"); -+ -+ writel_relaxed(status, priv->base + TIMER_INT_STAT_REG); -+ return IRQ_HANDLED; -+ } -+ return IRQ_NONE; -+} -+ -+static ssize_t show_capture(struct device *dev, struct device_attribute *attr, -+ char *buf) -+{ -+ int cnt; -+ struct phytium_tacho *priv = dev_get_drvdata(dev); -+ -+ cnt = capture_count * 0x7f + readl_relaxed(priv->base + TIMER_CNT_VALUE_LOW_REG); -+ -+ return sprintf(buf, "%d\n", cnt); -+} -+ -+static SENSOR_DEVICE_ATTR(capture_input, 0444, -+ show_capture, NULL, 0); -+ -+static struct attribute *capture_dev_attrs[] = { -+ &sensor_dev_attr_capture_input.dev_attr.attr, -+ NULL -+}; -+ -+static umode_t capture_dev_is_visible(struct kobject *kobj, -+ struct attribute *a, int index) -+{ -+ return a->mode; -+} -+ -+static const struct attribute_group capture_group = { -+ .attrs = capture_dev_attrs, -+ .is_visible = capture_dev_is_visible, -+}; -+ -+static const struct attribute_group *capture_groups[] = { -+ &capture_group, -+ NULL -+}; -+ -+static int phytium_tacho_get_work_mode(struct phytium_tacho *tacho) -+{ -+ struct device_node *nc = tacho->dev->of_node; -+ struct fwnode_handle *fwn = tacho->dev->fwnode; -+ -+ if (of_property_read_bool(nc, "tacho")) -+ return tacho_mode; -+ else if (has_acpi_companion(tacho->dev) && fwnode_property_read_bool( -+ fwn, "tacho")) -+ return tacho_mode; -+ if (of_property_read_bool(nc, "capture")) -+ return capture_mode; -+ else if (has_acpi_companion(tacho->dev) && fwnode_property_read_bool( -+ fwn, "capture")) -+ return capture_mode; -+ return tacho_mode; -+} -+ -+static int phytium_tacho_get_edge_mode(struct phytium_tacho *tacho) -+{ -+ struct device_node *nc = tacho->dev->of_node; -+ struct fwnode_handle *fwn = tacho->dev->fwnode; -+ -+ if (of_property_read_bool(nc, "up")) -+ return rising_edge; -+ else if (has_acpi_companion(tacho->dev) && fwnode_property_read_bool( -+ fwn, "up")) -+ return rising_edge; -+ if (of_property_read_bool(nc, "down")) -+ return falling_edge; -+ else if (has_acpi_companion(tacho->dev) && fwnode_property_read_bool( -+ fwn, "down")) -+ return falling_edge; -+ if (of_property_read_bool(nc, "double")) -+ return double_edge; -+ else if (has_acpi_companion(tacho->dev) && fwnode_property_read_bool( -+ fwn, "double")) -+ return double_edge; -+ return rising_edge; -+} -+ -+static int phytium_tacho_get_debounce(struct phytium_tacho *tacho) -+{ -+ u32 value; -+ struct device_node *nc = tacho->dev->of_node; -+ struct fwnode_handle *fwn = tacho->dev->fwnode; -+ -+ if (!of_property_read_u32(nc, "debounce-level", &value)) -+ return value; -+ if (has_acpi_companion(tacho->dev)) { -+ if (!fwnode_property_read_u32(fwn, "debounce-level", &value)) -+ return value; -+ } -+ return 0; -+} -+ -+static void phytium_tacho_get_of_data(struct phytium_tacho *tacho) -+{ -+ tacho->work_mode = phytium_tacho_get_work_mode(tacho); -+ tacho->edge_mode = phytium_tacho_get_edge_mode(tacho); -+ tacho->debounce = phytium_tacho_get_debounce(tacho); -+} -+ -+static int phytium_tacho_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct resource *res; -+ struct phytium_tacho *tacho; -+ int ret; -+ -+ tacho = devm_kzalloc(dev, sizeof(*tacho), GFP_KERNEL); -+ if (!tacho) -+ return -ENOMEM; -+ -+ tacho->dev = &pdev->dev; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ if (!res) -+ return -ENOENT; -+ -+ tacho->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(tacho->base)) { -+ dev_err(&pdev->dev, "region map failed\n"); -+ return PTR_ERR(tacho->base); -+ } -+ -+ if (!has_acpi_companion(tacho->dev)) { -+ tacho->clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(tacho->clk)) -+ return PTR_ERR(tacho->clk); -+ ret = clk_prepare_enable(tacho->clk); -+ if (ret) -+ return ret; -+ tacho->freq = clk_get_rate(tacho->clk); -+ } else { -+ u32 fre; -+ -+ ret = clk_prepare_enable(tacho->clk); -+ if (ret) -+ return ret; -+ fwnode_property_read_u32(tacho->dev->fwnode, "clock-frequency", &fre); -+ tacho->freq = fre; -+ } -+ -+ tacho->irq = platform_get_irq(pdev, 0); -+ if (tacho->irq < 0) { -+ dev_err(&pdev->dev, "no irq resource?\n"); -+ return tacho->irq; -+ } -+ -+ ret = devm_request_irq(dev, tacho->irq, capture_irq_handler, -+ 0, "phytium_tacho", tacho); -+ if (ret) { -+ dev_err(&pdev->dev, "Cannot request IRQ\n"); -+ return ret; -+ } -+ -+ phytium_tacho_get_of_data(tacho); -+ -+ phytium_tacho_init(tacho); -+ -+ if (tacho->work_mode == tacho_mode) -+ tacho->hwmon = devm_hwmon_device_register_with_groups(dev, -+ "phytium_tacho", -+ tacho, tacho_groups); -+ else -+ tacho->hwmon = devm_hwmon_device_register_with_groups(dev, -+ "phytium_capture", -+ tacho, capture_groups); -+ -+ platform_set_drvdata(pdev, tacho); -+ -+ return PTR_ERR_OR_ZERO(tacho->hwmon); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int phytium_tacho_suspend(struct device *dev) -+{ -+ return 0; -+} -+ -+static int phytium_tacho_resume(struct device *dev) -+{ -+ struct phytium_tacho *tacho = dev_get_drvdata(dev); -+ -+ phytium_tacho_init(tacho); -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(phytium_tacho_pm, phytium_tacho_suspend, phytium_tacho_resume); -+ -+static const struct of_device_id tacho_of_match[] = { -+ { .compatible = "phytium,tacho", }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, tacho_of_match); -+ -+static const struct acpi_device_id tacho_acpi_match[] = { -+ { "PHYT0033", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(acpi, tacho_acpi_match); -+ -+static struct platform_driver phytium_tacho_driver = { -+ .probe = phytium_tacho_probe, -+ .driver = { -+ .name = "phytium_tacho", -+ .pm = &phytium_tacho_pm, -+ .of_match_table = of_match_ptr(tacho_of_match), -+ .acpi_match_table = ACPI_PTR(tacho_acpi_match), -+ }, -+}; -+ -+module_platform_driver(phytium_tacho_driver); -+ -+MODULE_AUTHOR("Zhang Yiqun <zhangyiqun@phytium.com.cn>"); -+MODULE_DESCRIPTION("Phytium tachometer driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig -index a6ff1b8..160a670 100644 ---- a/drivers/irqchip/Kconfig -+++ b/drivers/irqchip/Kconfig -@@ -58,11 +58,9 @@ config ARM_GIC_V3_ITS_FSL_MC - - config ARM_GIC_PHYTIUM_2500 - bool -- select IRQ_DOMAIN - select IRQ_DOMAIN_HIERARCHY - select PARTITION_PERCPU - select GENERIC_IRQ_EFFECTIVE_AFF_MASK -- select GENERIC_MSI_IRQ_DOMAIN - - config ARM_NVIC - bool -diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile -index 7b04778..8a72dc7 100644 ---- a/drivers/irqchip/Makefile -+++ b/drivers/irqchip/Makefile -@@ -105,7 +105,7 @@ obj-$(CONFIG_LS1X_IRQ) += irq-ls1x.o - obj-$(CONFIG_TI_SCI_INTR_IRQCHIP) += irq-ti-sci-intr.o - obj-$(CONFIG_TI_SCI_INTA_IRQCHIP) += irq-ti-sci-inta.o - obj-$(CONFIG_TI_PRUSS_INTC) += irq-pruss-intc.o --obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o -+obj-$(CONFIG_IRQ_LOONGARCH_CPU) += irq-loongarch-cpu.o irq-loongarch-avec.o - obj-$(CONFIG_LOONGSON_LIOINTC) += irq-loongson-liointc.o - obj-$(CONFIG_LOONGSON_EIOINTC) += irq-loongson-eiointc.o - obj-$(CONFIG_LOONGSON_HTPIC) += irq-loongson-htpic.o -diff --git a/drivers/irqchip/irq-gic-phytium-2500-its.c b/drivers/irqchip/irq-gic-phytium-2500-its.c -index 4f8ee53..8e72c40 100644 ---- a/drivers/irqchip/irq-gic-phytium-2500-its.c -+++ b/drivers/irqchip/irq-gic-phytium-2500-its.c -@@ -1,23 +1,6 @@ - // SPDX-License-Identifier: GPL-2.0 - /* -- * Copyright (C) 2022 Phytium Corporation. -- * Author: -- * Wang Yinfeng <wangyinfeng@phytium.com.cn> -- * Chen Baozi <chenbaozi@phytium.com.cn> -- * Chen Siyu <chensiyu1321@phytium.com.cn> -- * Cui Fulong <cuifulong2112@phytium.com.cn> -- * Li Yuting <liyuting2071@phytium.com.cn> -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License version 2 as -- * published by the Free Software Foundation. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program. If not, see <http://www.gnu.org/licenses/>. -+ * Copyright (C) 2020-2023, Phytium Technology Co., Ltd - */ - - #include <linux/acpi.h> -@@ -27,9 +10,9 @@ - #include <linux/cpu.h> - #include <linux/crash_dump.h> - #include <linux/delay.h> -+#include <linux/iommu.h> - #include <linux/efi.h> - #include <linux/interrupt.h> --#include <linux/iommu.h> - #include <linux/iopoll.h> - #include <linux/irqdomain.h> - #include <linux/list.h> -@@ -58,7 +41,9 @@ - #define ITS_FLAGS_CMDQ_NEEDS_FLUSHING (1ULL << 0) - #define ITS_FLAGS_WORKAROUND_CAVIUM_22375 (1ULL << 1) - #define ITS_FLAGS_WORKAROUND_CAVIUM_23144 (1ULL << 2) --#define ITS_FLAGS_FORCE_NON_SHAREABLE (1ULL << 3) -+ -+#define RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING (1 << 0) -+#define RDIST_FLAGS_RD_TABLES_PREALLOCATED (1 << 1) - - #define RD_LOCAL_LPI_ENABLED BIT(0) - #define RD_LOCAL_PENDTABLE_PREALLOCATED BIT(1) -@@ -196,7 +181,7 @@ struct cpu_lpi_count { - atomic_t unmanaged; - }; - --static DEFINE_PER_CPU(struct cpu_lpi_count, cpu_lpi_count_ft2500); -+static DEFINE_PER_CPU(struct cpu_lpi_count, cpu_lpi_count); - - static LIST_HEAD(its_nodes); - static DEFINE_RAW_SPINLOCK(its_lock); -@@ -286,24 +271,13 @@ static void vpe_to_cpuid_unlock(struct its_vpe *vpe, unsigned long flags) - raw_spin_unlock_irqrestore(&vpe->vpe_lock, flags); - } - --static struct irq_chip its_vpe_irq_chip; -- - static int irq_to_cpuid_lock(struct irq_data *d, unsigned long *flags) - { -- struct its_vpe *vpe = NULL; -+ struct its_vlpi_map *map = get_vlpi_map(d); - int cpu; - -- if (d->chip == &its_vpe_irq_chip) { -- vpe = irq_data_get_irq_chip_data(d); -- } else { -- struct its_vlpi_map *map = get_vlpi_map(d); -- -- if (map) -- vpe = map->vpe; -- } -- -- if (vpe) { -- cpu = vpe_to_cpuid_lock(vpe, flags); -+ if (map) { -+ cpu = vpe_to_cpuid_lock(map->vpe, flags); - } else { - /* Physical LPIs are already locked via the irq_desc lock */ - struct its_device *its_dev = irq_data_get_irq_chip_data(d); -@@ -318,19 +292,10 @@ static int irq_to_cpuid_lock(struct irq_data *d, unsigned long *flags) - - static void irq_to_cpuid_unlock(struct irq_data *d, unsigned long flags) - { -- struct its_vpe *vpe = NULL; -- -- if (d->chip == &its_vpe_irq_chip) { -- vpe = irq_data_get_irq_chip_data(d); -- } else { -- struct its_vlpi_map *map = get_vlpi_map(d); -- -- if (map) -- vpe = map->vpe; -- } -+ struct its_vlpi_map *map = get_vlpi_map(d); - -- if (vpe) -- vpe_to_cpuid_unlock(vpe, flags); -+ if (map) -+ vpe_to_cpuid_unlock(map->vpe, flags); - } - - static struct its_collection *valid_col(struct its_collection *col) -@@ -670,7 +635,10 @@ static struct its_collection *its_build_mapti_cmd(struct its_node *its, - - col = dev_event_to_col(desc->its_mapti_cmd.dev, - desc->its_mapti_cmd.event_id); -- col->col_id = col->col_id % 64; -+ if (is_kdump_kernel()) -+ col->col_id = col->col_id % 65; -+ else -+ col->col_id = col->col_id % 64; - - its_encode_cmd(cmd, GITS_CMD_MAPTI); - its_encode_devid(cmd, desc->its_mapti_cmd.dev->device_id); -@@ -1468,28 +1436,13 @@ static void wait_for_syncr(void __iomem *rdbase) - cpu_relax(); - } - --static void __direct_lpi_inv(struct irq_data *d, u64 val) --{ -- void __iomem *rdbase; -- unsigned long flags; -- int cpu; -- -- /* Target the redistributor this LPI is currently routed to */ -- cpu = irq_to_cpuid_lock(d, &flags); -- raw_spin_lock(&gic_data_rdist_cpu(cpu)->rd_lock); -- -- rdbase = per_cpu_ptr(gic_rdists->rdist, cpu)->rd_base; -- gic_write_lpir(val, rdbase + GICR_INVLPIR); -- wait_for_syncr(rdbase); -- -- raw_spin_unlock(&gic_data_rdist_cpu(cpu)->rd_lock); -- irq_to_cpuid_unlock(d, flags); --} -- - static void direct_lpi_inv(struct irq_data *d) - { - struct its_vlpi_map *map = get_vlpi_map(d); -+ void __iomem *rdbase; -+ unsigned long flags; - u64 val; -+ int cpu; - - if (map) { - struct its_device *its_dev = irq_data_get_irq_chip_data(d); -@@ -1503,7 +1456,15 @@ static void direct_lpi_inv(struct irq_data *d) - val = d->hwirq; - } - -- __direct_lpi_inv(d, val); -+ /* Target the redistributor this LPI is currently routed to */ -+ cpu = irq_to_cpuid_lock(d, &flags); -+ raw_spin_lock(&gic_data_rdist_cpu(cpu)->rd_lock); -+ rdbase = per_cpu_ptr(gic_rdists->rdist, cpu)->rd_base; -+ gic_write_lpir(val, rdbase + GICR_INVLPIR); -+ -+ wait_for_syncr(rdbase); -+ raw_spin_unlock(&gic_data_rdist_cpu(cpu)->rd_lock); -+ irq_to_cpuid_unlock(d, flags); - } - - static void lpi_update_config(struct irq_data *d, u8 clr, u8 set) -@@ -1572,25 +1533,25 @@ static void its_unmask_irq(struct irq_data *d) - static __maybe_unused u32 its_read_lpi_count(struct irq_data *d, int cpu) - { - if (irqd_affinity_is_managed(d)) -- return atomic_read(&per_cpu_ptr(&cpu_lpi_count_ft2500, cpu)->managed); -+ return atomic_read(&per_cpu_ptr(&cpu_lpi_count, cpu)->managed); - -- return atomic_read(&per_cpu_ptr(&cpu_lpi_count_ft2500, cpu)->unmanaged); -+ return atomic_read(&per_cpu_ptr(&cpu_lpi_count, cpu)->unmanaged); - } - - static void its_inc_lpi_count(struct irq_data *d, int cpu) - { - if (irqd_affinity_is_managed(d)) -- atomic_inc(&per_cpu_ptr(&cpu_lpi_count_ft2500, cpu)->managed); -+ atomic_inc(&per_cpu_ptr(&cpu_lpi_count, cpu)->managed); - else -- atomic_inc(&per_cpu_ptr(&cpu_lpi_count_ft2500, cpu)->unmanaged); -+ atomic_inc(&per_cpu_ptr(&cpu_lpi_count, cpu)->unmanaged); - } - - static void its_dec_lpi_count(struct irq_data *d, int cpu) - { - if (irqd_affinity_is_managed(d)) -- atomic_dec(&per_cpu_ptr(&cpu_lpi_count_ft2500, cpu)->managed); -+ atomic_dec(&per_cpu_ptr(&cpu_lpi_count, cpu)->managed); - else -- atomic_dec(&per_cpu_ptr(&cpu_lpi_count_ft2500, cpu)->unmanaged); -+ atomic_dec(&per_cpu_ptr(&cpu_lpi_count, cpu)->unmanaged); - } - - static unsigned int cpumask_pick_least_loaded(struct irq_data *d, -@@ -1688,11 +1649,11 @@ static int its_select_cpu(struct irq_data *d, - return cpu; - } - --#define MAX_MARS3_SKT_COUNT 8 -+#define MAX_MARS3_SKT_COUNT 8 - - static int its_cpumask_select(struct its_device *its_dev, -- const struct cpumask *mask_val, -- const struct cpumask *cpu_mask) -+ const struct cpumask *mask_val, -+ const struct cpumask *cpu_mask) - { - unsigned int skt, skt_id, i; - phys_addr_t its_phys_base; -@@ -1700,18 +1661,22 @@ static int its_cpumask_select(struct its_device *its_dev, - - unsigned int skt_cpu_cnt[MAX_MARS3_SKT_COUNT] = {0}; - -+ its_phys_base = its_dev->its->phys_base; -+ skt_id = (its_phys_base >> 41) & 0x7; -+ - for (i = 0; i < nr_cpu_ids; i++) { - skt = (cpu_logical_map(i) >> 16) & 0xff; -- if ((skt >= 0) && (skt < MAX_MARS3_SKT_COUNT)) -+ if ((skt >= 0) && (skt < MAX_MARS3_SKT_COUNT)) { -+ if ((is_kdump_kernel()) && (skt_id == skt)) -+ return i; -+ - skt_cpu_cnt[skt]++; -- else if (skt != 0xff) -+ } else if (skt != 0xff) { - pr_err("socket address: %d is out of range.", skt); -+ } - } - -- its_phys_base = its_dev->its->phys_base; -- skt_id = (its_phys_base >> 41) & 0x7; -- -- if (skt_id != 0) { -+ if (skt_id) { - for (i = 0; i < skt_id; i++) - cpus += skt_cpu_cnt[i]; - } -@@ -1746,6 +1711,7 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val, - cpu = its_select_cpu(d, mask_val); - else - cpu = cpumask_pick_least_loaded(d, mask_val); -+ - skt_t2 = (cpu_logical_map(cpu) >> 16) & 0xff; - if (skt_t1 != skt_t2) - cpu = cpu_idx; -@@ -2300,7 +2266,7 @@ static bool gic_check_reserved_range(phys_addr_t addr, unsigned long size) - } - - /* Not found, not a good sign... */ -- pr_warn("GIC-2500: Expected reserved range [%pa:%pa], not found\n", -+ pr_warn("GIC-S2500: Expected reserved range [%pa:%pa], not found\n", - &addr, &addr_end); - add_taint(TAINT_CRAP, LOCKDEP_STILL_OK); - return false; -@@ -2345,13 +2311,13 @@ static int __init its_setup_lpi_prop_table(void) - LPI_PROPBASE_SZ)); - } - -- pr_info("GIC-2500: using LPI property table @%pa\n", -+ pr_info("GICv-S2500: using LPI property table @%pa\n", - &gic_rdists->prop_table_pa); - - return its_lpi_init(lpi_id_bits); - } - --static const char * const its_base_type_string[] = { -+static const char *its_base_type_string[] = { - [GITS_BASER_TYPE_DEVICE] = "Devices", - [GITS_BASER_TYPE_VCPU] = "Virtual CPUs", - [GITS_BASER_TYPE_RESERVED3] = "Reserved (3)", -@@ -2445,9 +2411,6 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, - its_write_baser(its, baser, val); - tmp = baser->val; - -- if (its->flags & ITS_FLAGS_FORCE_NON_SHAREABLE) -- tmp &= ~GITS_BASER_SHAREABILITY_MASK; -- - if ((val ^ tmp) & GITS_BASER_SHAREABILITY_MASK) { - /* - * Shareability didn't stick. Just use -@@ -2529,8 +2492,8 @@ static bool its_parse_indirect_baser(struct its_node *its, - * feature is not supported by hardware. - */ - new_order = max_t(u32, get_order(esz << ids), new_order); -- if (new_order > MAX_PAGE_ORDER) { -- new_order = MAX_PAGE_ORDER; -+ if (new_order >= MAX_PAGE_ORDER) { -+ new_order = MAX_PAGE_ORDER - 1; - ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / (int)esz); - pr_warn("ITS@%pa: %s Table too large, reduce ids %llu->%u\n", - &its->phys_base, its_base_type_string[type], -@@ -2700,8 +2663,7 @@ static int its_alloc_tables(struct its_node *its) - struct its_node *sibling; - - WARN_ON(i != 2); -- sibling = find_sibling_its(its); -- if (sibling != NULL) { -+ if ((sibling = find_sibling_its(its))) { - *baser = sibling->tables[2]; - its_write_baser(its, baser, baser->val); - continue; -@@ -3076,7 +3038,7 @@ static int __init allocate_lpi_tables(void) - if ((val & GICR_CTLR_ENABLE_LPIS) && enabled_lpis_allowed()) { - gic_rdists->flags |= (RDIST_FLAGS_RD_TABLES_PREALLOCATED | - RDIST_FLAGS_PROPBASE_NEEDS_FLUSHING); -- pr_info("GIC-2500: Using preallocated redistributor tables\n"); -+ pr_info("GIC-S2500: Using preallocated redistributor tables\n"); - } - - err = its_setup_lpi_prop_table(); -@@ -3103,18 +3065,12 @@ static int __init allocate_lpi_tables(void) - return 0; - } - --static u64 its_clear_vpend_valid(void __iomem *vlpi_base, u64 clr, u64 set) -+static u64 read_vpend_dirty_clear(void __iomem *vlpi_base) - { - u32 count = 1000000; /* 1s! */ - bool clean; - u64 val; - -- val = gicr_read_vpendbaser(vlpi_base + GICR_VPENDBASER); -- val &= ~GICR_VPENDBASER_Valid; -- val &= ~clr; -- val |= set; -- gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER); -- - do { - val = gicr_read_vpendbaser(vlpi_base + GICR_VPENDBASER); - clean = !(val & GICR_VPENDBASER_Dirty); -@@ -3125,10 +3081,26 @@ static u64 its_clear_vpend_valid(void __iomem *vlpi_base, u64 clr, u64 set) - } - } while (!clean && count); - -- if (unlikely(val & GICR_VPENDBASER_Dirty)) { -+ if (unlikely(!clean)) - pr_err_ratelimited("ITS virtual pending table not cleaning\n"); -+ -+ return val; -+} -+ -+static u64 its_clear_vpend_valid(void __iomem *vlpi_base, u64 clr, u64 set) -+{ -+ u64 val; -+ -+ /* Make sure we wait until the RD is done with the initial scan */ -+ val = read_vpend_dirty_clear(vlpi_base); -+ val &= ~GICR_VPENDBASER_Valid; -+ val &= ~clr; -+ val |= set; -+ gicr_write_vpendbaser(val, vlpi_base + GICR_VPENDBASER); -+ -+ val = read_vpend_dirty_clear(vlpi_base); -+ if (unlikely(val & GICR_VPENDBASER_Dirty)) - val |= GICR_VPENDBASER_PendingLast; -- } - - return val; - } -@@ -3176,9 +3148,6 @@ static void its_cpu_init_lpis(void) - gicr_write_propbaser(val, rbase + GICR_PROPBASER); - tmp = gicr_read_propbaser(rbase + GICR_PROPBASER); - -- if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE) -- tmp &= ~GICR_PROPBASER_SHAREABILITY_MASK; -- - if ((tmp ^ val) & GICR_PROPBASER_SHAREABILITY_MASK) { - if (!(tmp & GICR_PROPBASER_SHAREABILITY_MASK)) { - /* -@@ -3203,9 +3172,6 @@ static void its_cpu_init_lpis(void) - gicr_write_pendbaser(val, rbase + GICR_PENDBASER); - tmp = gicr_read_pendbaser(rbase + GICR_PENDBASER); - -- if (gic_rdists->flags & RDIST_FLAGS_FORCE_NON_SHAREABLE) -- tmp &= ~GICR_PENDBASER_SHAREABILITY_MASK; -- - if (!(tmp & GICR_PENDBASER_SHAREABILITY_MASK)) { - /* - * The HW reports non-shareable, we must remove the -@@ -3270,9 +3236,6 @@ static void its_cpu_init_collection(struct its_node *its) - { - int cpu = smp_processor_id(); - u64 target; -- unsigned long mpid; -- phys_addr_t its_phys_base; -- unsigned long skt_id; - - /* avoid cross node collections and its mapping */ - if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) { -@@ -3284,10 +3247,6 @@ static void its_cpu_init_collection(struct its_node *its) - return; - } - -- mpid = cpu_logical_map(cpu); -- its_phys_base = its->phys_base; -- skt_id = (its_phys_base >> 41) & 0x7; -- - /* - * We now have to bind each collection to its target - * redistributor. -@@ -3306,7 +3265,10 @@ static void its_cpu_init_collection(struct its_node *its) - - /* Perform collection mapping */ - its->collections[cpu].target_address = target; -- its->collections[cpu].col_id = cpu % 64; -+ if (is_kdump_kernel()) -+ its->collections[cpu].col_id = cpu % 65; -+ else -+ its->collections[cpu].col_id = cpu % 64; - - its_send_mapc(its, &its->collections[cpu], 1); - its_send_invall(its, &its->collections[cpu]); -@@ -3667,7 +3629,6 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, - irqd = irq_get_irq_data(virq + i); - irqd_set_single_target(irqd); - irqd_set_affinity_on_activate(irqd); -- irqd_set_resend_when_in_progress(irqd); - pr_debug("ID:%d pID:%d vID:%d\n", - (int)(hwirq + i - its_dev->event_map.lpi_base), - (int)(hwirq + i), virq + i); -@@ -3677,28 +3638,32 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, - } - - static int its_cpumask_first(struct its_device *its_dev, -- const struct cpumask *cpu_mask) -+ const struct cpumask *cpu_mask) - { - unsigned int skt, skt_id, i; - phys_addr_t its_phys_base; - unsigned int cpu, cpus = 0; -- - unsigned int skt_cpu_cnt[MAX_MARS3_SKT_COUNT] = {0}; - -+ its_phys_base = its_dev->its->phys_base; -+ skt_id = (its_phys_base >> 41) & 0x7; -+ - for (i = 0; i < nr_cpu_ids; i++) { - skt = (cpu_logical_map(i) >> 16) & 0xff; -- if ((skt >= 0) && (skt < MAX_MARS3_SKT_COUNT)) -+ if ((skt >= 0) && (skt < MAX_MARS3_SKT_COUNT)) { -+ if ((is_kdump_kernel()) && (skt_id == skt)) -+ return i; -+ - skt_cpu_cnt[skt]++; -- else if (skt != 0xff) -+ } else if (skt != 0xff) { - pr_err("socket address: %d is out of range.", skt); -+ } - } - -- its_phys_base = its_dev->its->phys_base; -- skt_id = (its_phys_base >> 41) & 0x7; -- -- if (skt_id != 0) -+ if (skt_id) { - for (i = 0; i < skt_id; i++) - cpus += skt_cpu_cnt[i]; -+ } - - cpu = cpumask_first(cpu_mask); - if ((cpu > cpus) && (cpu < (cpus + skt_cpu_cnt[skt_id]))) -@@ -4068,10 +4033,18 @@ static void its_vpe_send_inv(struct irq_data *d) - { - struct its_vpe *vpe = irq_data_get_irq_chip_data(d); - -- if (gic_rdists->has_direct_lpi) -- __direct_lpi_inv(d, d->parent_data->hwirq); -- else -+ if (gic_rdists->has_direct_lpi) { -+ void __iomem *rdbase; -+ -+ /* Target the redistributor this VPE is currently known on */ -+ raw_spin_lock(&gic_data_rdist_cpu(vpe->col_idx)->rd_lock); -+ rdbase = per_cpu_ptr(gic_rdists->rdist, vpe->col_idx)->rd_base; -+ gic_write_lpir(d->parent_data->hwirq, rdbase + GICR_INVLPIR); -+ wait_for_syncr(rdbase); -+ raw_spin_unlock(&gic_data_rdist_cpu(vpe->col_idx)->rd_lock); -+ } else { - its_vpe_send_cmd(vpe, its_send_inv); -+ } - } - - static void its_vpe_mask_irq(struct irq_data *d) -@@ -4140,7 +4113,7 @@ static struct irq_chip its_vpe_irq_chip = { - - static struct its_node *find_4_1_its(void) - { -- static struct its_node *its; -+ static struct its_node *its = NULL; - - if (!its) { - list_for_each_entry(its, &its_nodes, entry) { -@@ -4631,7 +4604,6 @@ static int its_vpe_irq_domain_alloc(struct irq_domain *domain, unsigned int virq - irq_domain_set_hwirq_and_chip(domain, virq + i, i, - irqchip, vm->vpes[i]); - set_bit(i, bitmap); -- irqd_set_resend_when_in_progress(irq_get_irq_data(virq + i)); - } - - if (err) { -@@ -4830,28 +4802,6 @@ static bool __maybe_unused its_enable_quirk_hip07_161600802(void *data) - return true; - } - --static bool __maybe_unused its_enable_rk3588001(void *data) --{ -- struct its_node *its = data; -- -- if (!of_machine_is_compatible("rockchip,rk3588") && -- !of_machine_is_compatible("rockchip,rk3588s")) -- return false; -- -- its->flags |= ITS_FLAGS_FORCE_NON_SHAREABLE; -- gic_rdists->flags |= RDIST_FLAGS_FORCE_NON_SHAREABLE; -- -- return true; --} -- --static bool its_set_non_coherent(void *data) --{ -- struct its_node *its = data; -- -- its->flags |= ITS_FLAGS_FORCE_NON_SHAREABLE; -- return true; --} -- - static const struct gic_quirk its_quirks[] = { - #ifdef CONFIG_CAVIUM_ERRATUM_22375 - { -@@ -4898,19 +4848,6 @@ static const struct gic_quirk its_quirks[] = { - .init = its_enable_quirk_hip07_161600802, - }, - #endif --#ifdef CONFIG_ROCKCHIP_ERRATUM_3588001 -- { -- .desc = "ITS: Rockchip erratum RK3588001", -- .iidr = 0x0201743b, -- .mask = 0xffffffff, -- .init = its_enable_rk3588001, -- }, --#endif -- { -- .desc = "ITS: non-coherent attribute", -- .property = "dma-noncoherent", -- .init = its_set_non_coherent, -- }, - { - } - }; -@@ -4920,10 +4857,6 @@ static void its_enable_quirks(struct its_node *its) - u32 iidr = readl_relaxed(its->base + GITS_IIDR); - - gic_enable_quirks(iidr, its_quirks, its); -- -- if (is_of_node(its->fwnode_handle)) -- gic_enable_of_quirks(to_of_node(its->fwnode_handle), -- its_quirks, its); - } - - static int its_save_disable(void) -@@ -5059,7 +4992,7 @@ static void __init __iomem *its_map_one(struct resource *res, int *err) - return NULL; - } - --static int its_init_domain(struct its_node *its) -+static int its_init_domain(struct fwnode_handle *handle, struct its_node *its) - { - struct irq_domain *inner_domain; - struct msi_domain_info *info; -@@ -5068,19 +5001,18 @@ static int its_init_domain(struct its_node *its) - if (!info) - return -ENOMEM; - -- info->ops = &its_msi_domain_ops; -- info->data = its; -- -- inner_domain = irq_domain_create_hierarchy(its_parent, -- its->msi_domain_flags, 0, -- its->fwnode_handle, &its_domain_ops, -- info); -+ inner_domain = irq_domain_create_tree(handle, &its_domain_ops, its); - if (!inner_domain) { - kfree(info); - return -ENOMEM; - } - -+ inner_domain->parent = its_parent; - irq_domain_update_bus_token(inner_domain, DOMAIN_BUS_NEXUS); -+ inner_domain->flags |= its->msi_domain_flags; -+ info->ops = &its_msi_domain_ops; -+ info->data = its; -+ inner_domain->host_data = info; - - return 0; - } -@@ -5124,7 +5056,8 @@ static int its_init_vpe_domain(void) - return 0; - } - --static int __init its_compute_its_list_map(struct its_node *its) -+static int __init its_compute_its_list_map(struct resource *res, -+ void __iomem *its_base) - { - int its_number; - u32 ctlr; -@@ -5138,15 +5071,15 @@ static int __init its_compute_its_list_map(struct its_node *its) - its_number = find_first_zero_bit(&its_list_map, GICv4_ITS_LIST_MAX); - if (its_number >= GICv4_ITS_LIST_MAX) { - pr_err("ITS@%pa: No ITSList entry available!\n", -- &its->phys_base); -+ &res->start); - return -EINVAL; - } - -- ctlr = readl_relaxed(its->base + GITS_CTLR); -+ ctlr = readl_relaxed(its_base + GITS_CTLR); - ctlr &= ~GITS_CTLR_ITS_NUMBER; - ctlr |= its_number << GITS_CTLR_ITS_NUMBER_SHIFT; -- writel_relaxed(ctlr, its->base + GITS_CTLR); -- ctlr = readl_relaxed(its->base + GITS_CTLR); -+ writel_relaxed(ctlr, its_base + GITS_CTLR); -+ ctlr = readl_relaxed(its_base + GITS_CTLR); - if ((ctlr & GITS_CTLR_ITS_NUMBER) != (its_number << GITS_CTLR_ITS_NUMBER_SHIFT)) { - its_number = ctlr & GITS_CTLR_ITS_NUMBER; - its_number >>= GITS_CTLR_ITS_NUMBER_SHIFT; -@@ -5154,50 +5087,75 @@ static int __init its_compute_its_list_map(struct its_node *its) - - if (test_and_set_bit(its_number, &its_list_map)) { - pr_err("ITS@%pa: Duplicate ITSList entry %d\n", -- &its->phys_base, its_number); -+ &res->start, its_number); - return -EINVAL; - } - - return its_number; - } - --static int __init its_probe_one(struct its_node *its) -+static int __init its_probe_one(struct resource *res, -+ struct fwnode_handle *handle, int numa_node) - { -- u64 baser, tmp; -+ struct its_node *its; -+ void __iomem *its_base; -+ u64 baser, tmp, typer; - struct page *page; - u32 ctlr; - int err; - -+ its_base = its_map_one(res, &err); -+ if (!its_base) -+ return err; -+ -+ pr_info("ITS %pR\n", res); -+ -+ its = kzalloc(sizeof(*its), GFP_KERNEL); -+ if (!its) { -+ err = -ENOMEM; -+ goto out_unmap; -+ } -+ -+ raw_spin_lock_init(&its->lock); -+ mutex_init(&its->dev_alloc_lock); -+ INIT_LIST_HEAD(&its->entry); -+ INIT_LIST_HEAD(&its->its_device_list); -+ typer = gic_read_typer(its_base + GITS_TYPER); -+ its->typer = typer; -+ its->base = its_base; -+ its->phys_base = res->start; - if (is_v4(its)) { -- if (!(its->typer & GITS_TYPER_VMOVP)) { -- err = its_compute_its_list_map(its); -+ if (!(typer & GITS_TYPER_VMOVP)) { -+ err = its_compute_its_list_map(res, its_base); - if (err < 0) -- goto out; -+ goto out_free_its; - - its->list_nr = err; - - pr_info("ITS@%pa: Using ITS number %d\n", -- &its->phys_base, err); -+ &res->start, err); - } else { -- pr_info("ITS@%pa: Single VMOVP capable\n", &its->phys_base); -+ pr_info("ITS@%pa: Single VMOVP capable\n", &res->start); - } - - if (is_v4_1(its)) { -- u32 svpet = FIELD_GET(GITS_TYPER_SVPET, its->typer); -+ u32 svpet = FIELD_GET(GITS_TYPER_SVPET, typer); - -- its->sgir_base = ioremap(its->phys_base + SZ_128K, SZ_64K); -+ its->sgir_base = ioremap(res->start + SZ_128K, SZ_64K); - if (!its->sgir_base) { - err = -ENOMEM; -- goto out; -+ goto out_free_its; - } - -- its->mpidr = readl_relaxed(its->base + GITS_MPIDR); -+ its->mpidr = readl_relaxed(its_base + GITS_MPIDR); - - pr_info("ITS@%pa: Using GICv4.1 mode %08x %08x\n", -- &its->phys_base, its->mpidr, svpet); -+ &res->start, its->mpidr, svpet); - } - } - -+ its->numa_node = numa_node; -+ - page = alloc_pages_node(its->numa_node, GFP_KERNEL | __GFP_ZERO, - get_order(ITS_CMD_QUEUE_SZ)); - if (!page) { -@@ -5206,6 +5164,11 @@ static int __init its_probe_one(struct its_node *its) - } - its->cmd_base = (void *)page_address(page); - its->cmd_write = its->cmd_base; -+ its->fwnode_handle = handle; -+ its->get_msi_base = its_irq_get_msi_base; -+ its->msi_domain_flags = IRQ_DOMAIN_FLAG_ISOLATED_MSI; -+ -+ its_enable_quirks(its); - - err = its_alloc_tables(its); - if (err) -@@ -5224,9 +5187,6 @@ static int __init its_probe_one(struct its_node *its) - gits_write_cbaser(baser, its->base + GITS_CBASER); - tmp = gits_read_cbaser(its->base + GITS_CBASER); - -- if (its->flags & ITS_FLAGS_FORCE_NON_SHAREABLE) -- tmp &= ~GITS_CBASER_SHAREABILITY_MASK; -- - if ((tmp ^ baser) & GITS_CBASER_SHAREABILITY_MASK) { - if (!(tmp & GITS_CBASER_SHAREABILITY_MASK)) { - /* -@@ -5250,7 +5210,7 @@ static int __init its_probe_one(struct its_node *its) - ctlr |= GITS_CTLR_ImDe; - writel_relaxed(ctlr, its->base + GITS_CTLR); - -- err = its_init_domain(its); -+ err = its_init_domain(handle, its); - if (err) - goto out_free_tables; - -@@ -5267,8 +5227,11 @@ static int __init its_probe_one(struct its_node *its) - out_unmap_sgir: - if (its->sgir_base) - iounmap(its->sgir_base); --out: -- pr_err("ITS@%pa: failed probing (%d)\n", &its->phys_base, err); -+out_free_its: -+ kfree(its); -+out_unmap: -+ iounmap(its_base); -+ pr_err("ITS@%pa: failed probing (%d)\n", &res->start, err); - return err; - } - -@@ -5370,6 +5333,44 @@ static void rdist_memreserve_cpuhp_cleanup_workfn(struct work_struct *work) - static DECLARE_WORK(rdist_memreserve_cpuhp_cleanup_work, - rdist_memreserve_cpuhp_cleanup_workfn); - -+static int its_cpu_memreserve_lpi(unsigned int cpu) -+{ -+ struct page *pend_page; -+ int ret = 0; -+ -+ /* This gets to run exactly once per CPU */ -+ if (gic_data_rdist()->flags & RD_LOCAL_MEMRESERVE_DONE) -+ return 0; -+ -+ pend_page = gic_data_rdist()->pend_page; -+ if (WARN_ON(!pend_page)) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ /* -+ * If the pending table was pre-programmed, free the memory we -+ * preemptively allocated. Otherwise, reserve that memory for -+ * later kexecs. -+ */ -+ if (gic_data_rdist()->flags & RD_LOCAL_PENDTABLE_PREALLOCATED) { -+ its_free_pending_table(pend_page); -+ gic_data_rdist()->pend_page = NULL; -+ } else { -+ phys_addr_t paddr = page_to_phys(pend_page); -+ -+ WARN_ON(gic_reserve_range(paddr, LPI_PENDBASE_SZ)); -+ } -+ -+out: -+ /* Last CPU being brought up gets to issue the cleanup */ -+ if (!IS_ENABLED(CONFIG_SMP) || -+ cpumask_equal(&cpus_booted_once_mask, cpu_possible_mask)) -+ schedule_work(&rdist_memreserve_cpuhp_cleanup_work); -+ -+ gic_data_rdist()->flags |= RD_LOCAL_MEMRESERVE_DONE; -+ return ret; -+} -+ - /* Mark all the BASER registers as invalid before they get reprogrammed */ - static int __init its_reset_one(struct resource *res) - { -@@ -5388,59 +5389,14 @@ static int __init its_reset_one(struct resource *res) - } - - static const struct of_device_id its_device_id[] = { -- { .compatible = "arm,gic-phytium-2500-its", }, -+ { .compatible = "arm,gic-s2500-its", }, - {}, - }; - --static struct its_node __init *its_node_init(struct resource *res, -- struct fwnode_handle *handle, int numa_node) --{ -- void __iomem *its_base; -- struct its_node *its; -- int err; -- -- its_base = its_map_one(res, &err); -- if (!its_base) -- return NULL; -- -- pr_info("ITS %pR\n", res); -- -- its = kzalloc(sizeof(*its), GFP_KERNEL); -- if (!its) -- goto out_unmap; -- -- raw_spin_lock_init(&its->lock); -- mutex_init(&its->dev_alloc_lock); -- INIT_LIST_HEAD(&its->entry); -- INIT_LIST_HEAD(&its->its_device_list); -- -- its->typer = gic_read_typer(its_base + GITS_TYPER); -- its->base = its_base; -- its->phys_base = res->start; -- its->get_msi_base = its_irq_get_msi_base; -- its->msi_domain_flags = IRQ_DOMAIN_FLAG_ISOLATED_MSI; -- -- its->numa_node = numa_node; -- its->fwnode_handle = handle; -- -- return its; -- --out_unmap: -- iounmap(its_base); -- return NULL; --} -- --static void its_node_destroy(struct its_node *its) --{ -- iounmap(its->base); -- kfree(its); --} -- - static int __init its_of_probe(struct device_node *node) - { - struct device_node *np; - struct resource res; -- int err; - - /* - * Make sure *all* the ITS are reset before we probe any, as -@@ -5450,6 +5406,8 @@ static int __init its_of_probe(struct device_node *node) - */ - for (np = of_find_matching_node(node, its_device_id); np; - np = of_find_matching_node(np, its_device_id)) { -+ int err; -+ - if (!of_device_is_available(np) || - !of_property_read_bool(np, "msi-controller") || - of_address_to_resource(np, 0, &res)) -@@ -5462,8 +5420,6 @@ static int __init its_of_probe(struct device_node *node) - - for (np = of_find_matching_node(node, its_device_id); np; - np = of_find_matching_node(np, its_device_id)) { -- struct its_node *its; -- - if (!of_device_is_available(np)) - continue; - if (!of_property_read_bool(np, "msi-controller")) { -@@ -5477,17 +5433,7 @@ static int __init its_of_probe(struct device_node *node) - continue; - } - -- -- its = its_node_init(&res, &np->fwnode, of_node_to_nid(np)); -- if (!its) -- return -ENOMEM; -- -- its_enable_quirks(its); -- err = its_probe_one(its); -- if (err) { -- its_node_destroy(its); -- return err; -- } -+ its_probe_one(&res, &np->fwnode, of_node_to_nid(np)); - } - return 0; - } -@@ -5599,7 +5545,6 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header, - { - struct acpi_madt_generic_translator *its_entry; - struct fwnode_handle *dom_handle; -- struct its_node *its; - struct resource res; - int err; - -@@ -5611,7 +5556,7 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header, - - dom_handle = irq_domain_alloc_fwnode(&res.start); - if (!dom_handle) { -- pr_err("ITS@%pa: Unable to allocate GIC-phytium-2500 ITS domain token\n", -+ pr_err("ITS@%pa: Unable to allocate GIC-phytium-S2500 ITS domain token\n", - &res.start); - return -ENOMEM; - } -@@ -5619,23 +5564,16 @@ static int __init gic_acpi_parse_madt_its(union acpi_subtable_headers *header, - err = iort_register_domain_token(its_entry->translation_id, res.start, - dom_handle); - if (err) { -- pr_err("ITS@%pa: Unable to register GIC-phytium-2500 ITS domain token (ITS ID %d) to IORT\n", -+ pr_err("ITS@%pa: Unable to register GIC-Phytium-S2500 ITS domain token (ITS ID %d) to IORT\n", - &res.start, its_entry->translation_id); - goto dom_err; - } - -- its = its_node_init(&res, dom_handle, -- acpi_get_its_numa_node(its_entry->translation_id)); -- if (!its) { -- err = -ENOMEM; -- goto node_err; -- } -- -- err = its_probe_one(its); -+ err = its_probe_one(&res, dom_handle, -+ acpi_get_its_numa_node(its_entry->translation_id)); - if (!err) - return 0; - --node_err: - iort_deregister_domain_token(its_entry->translation_id); - dom_err: - irq_domain_free_fwnode(dom_handle); -@@ -5677,6 +5615,28 @@ static void __init its_acpi_probe(void) - static void __init its_acpi_probe(void) { } - #endif - -+int __init phytium_its_lpi_memreserve_init(void) -+{ -+ int state; -+ -+ if (!efi_enabled(EFI_CONFIG_TABLES)) -+ return 0; -+ -+ if (list_empty(&its_nodes)) -+ return 0; -+ -+ gic_rdists->cpuhp_memreserve_state = CPUHP_INVALID; -+ state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, -+ "irqchip/arm/gic-2500/memreserve:online", -+ its_cpu_memreserve_lpi, -+ NULL); -+ if (state < 0) -+ return state; -+ -+ gic_rdists->cpuhp_memreserve_state = state; -+ -+ return 0; -+} - int __init phytium_its_init(struct fwnode_handle *handle, struct rdists *rdists, - struct irq_domain *parent_domain) - { -diff --git a/drivers/irqchip/irq-gic-phytium-2500.c b/drivers/irqchip/irq-gic-phytium-2500.c -index 7214f36..1488e7b 100644 ---- a/drivers/irqchip/irq-gic-phytium-2500.c -+++ b/drivers/irqchip/irq-gic-phytium-2500.c -@@ -1,26 +1,8 @@ - // SPDX-License-Identifier: GPL-2.0 - /* -- * Copyright (C) 2022 Phytium Corporation. -- * Author: -- * Wang Yinfeng <wangyinfeng@phytium.com.cn> -- * Chen Baozi <chenbaozi@phytium.com.cn> -- * Chen Siyu <chensiyu1321@phytium.com.cn> -- * Cui Fulong <cuifulong2112@phytium.com.cn> -- * Li Yuting <liyuting2071@phytium.com.cn> -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License version 2 as -- * published by the Free Software Foundation. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * -- * You should have received a copy of the GNU General Public License -- * along with this program. If not, see <http://www.gnu.org/licenses/>. -+ * Copyright (C) 2020-2023, Phytium Technology Co., Ltd - */ - -- - #define pr_fmt(fmt) "GIC-2500: " fmt - - #include <linux/acpi.h> -@@ -29,7 +11,6 @@ - #include <linux/delay.h> - #include <linux/interrupt.h> - #include <linux/irqdomain.h> --#include <linux/kstrtox.h> - #include <linux/of.h> - #include <linux/of_address.h> - #include <linux/of_irq.h> -@@ -41,9 +22,6 @@ - #include <linux/irqchip/arm-gic-common.h> - #include <linux/irqchip/arm-gic-phytium-2500.h> - #include <linux/irqchip/irq-partition-percpu.h> --#include <linux/bitfield.h> --#include <linux/bits.h> --#include <linux/arm-smccc.h> - - #include <asm/cputype.h> - #include <asm/exception.h> -@@ -51,6 +29,7 @@ - #include <asm/virt.h> - - #include "irq-gic-common.h" -+#include <linux/crash_dump.h> - - #define MAX_MARS3_SOC_COUNT 8 - #define MARS3_ADDR_SKTID_SHIFT 41 -@@ -61,18 +40,10 @@ struct gic_dist_desc { - unsigned long size; - }; - --static struct gic_dist_desc mars3_gic_dists[MAX_MARS3_SOC_COUNT] __read_mostly; -- --static unsigned int mars3_sockets_bitmap = 0x1; -- --#define mars3_irq_to_skt(hwirq) (((hwirq) - 32) % 8) -- - #define GICD_INT_NMI_PRI (GICD_INT_DEF_PRI & ~0x80) - - #define FLAGS_WORKAROUND_GICR_WAKER_MSM8996 (1ULL << 0) - #define FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539 (1ULL << 1) --#define FLAGS_WORKAROUND_MTK_GICR_SAVE (1ULL << 2) --#define FLAGS_WORKAROUND_ASR_ERRATUM_8601001 (1ULL << 3) - - #define GIC_IRQ_TYPE_PARTITION (GIC_IRQ_TYPE_LPI + 1) - -@@ -82,9 +53,14 @@ struct redist_region { - bool single_redist; - }; - -+static struct gic_dist_desc mars3_gic_dists[MAX_MARS3_SOC_COUNT] __read_mostly; -+ -+static unsigned int mars3_sockets_bitmap = 0x1; -+ -+#define mars3_irq_to_skt(hwirq) (((hwirq) - 32) % 8) -+ - struct gic_chip_data { - struct fwnode_handle *fwnode; -- phys_addr_t dist_phys_base; - void __iomem *dist_base; - struct redist_region *redist_regions; - struct rdists rdists; -@@ -97,12 +73,6 @@ struct gic_chip_data { - struct partition_desc **ppi_descs; - }; - --#define T241_CHIPS_MAX 4 --static void __iomem *t241_dist_base_alias[T241_CHIPS_MAX] __read_mostly; --static DEFINE_STATIC_KEY_FALSE(gic_nvidia_t241_erratum); -- --static DEFINE_STATIC_KEY_FALSE(gic_arm64_2941627_erratum); -- - static struct gic_chip_data gic_data __read_mostly; - static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); - -@@ -131,9 +101,14 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); - * - Figure 4-7 Secure read of the priority field for a Non-secure Group 1 - * interrupt. - */ --static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis_ft2500); -+static DEFINE_STATIC_KEY_FALSE(supports_pseudo_nmis); - -+#ifndef CONFIG_ARM_GIC_V3 -+DEFINE_STATIC_KEY_FALSE(gic_nonsecure_priorities); -+EXPORT_SYMBOL(gic_nonsecure_priorities); -+#else - extern struct static_key_false gic_nonsecure_priorities; -+#endif - - /* - * When the Non-secure world has access to group 0 interrupts (as a -@@ -160,7 +135,7 @@ extern struct static_key_false gic_nonsecure_priorities; - static refcount_t *ppi_nmi_refs; - - static struct gic_kvm_info gic_v3_kvm_info __initdata; --static DEFINE_PER_CPU(bool, has_rss_ft2500); -+static DEFINE_PER_CPU(bool, has_rss); - - #define MPIDR_RS(mpidr) (((mpidr) & 0xF0UL) >> 4) - #define gic_data_rdist() (this_cpu_ptr(gic_data.rdists.rdist)) -@@ -222,39 +197,6 @@ static inline bool gic_irq_in_rdist(struct irq_data *d) - } - } - --static inline void __iomem *gic_dist_base_alias(struct irq_data *d) --{ -- if (static_branch_unlikely(&gic_nvidia_t241_erratum)) { -- irq_hw_number_t hwirq = irqd_to_hwirq(d); -- u32 chip; -- -- /* -- * For the erratum T241-FABRIC-4, read accesses to GICD_In{E} -- * registers are directed to the chip that owns the SPI. The -- * the alias region can also be used for writes to the -- * GICD_In{E} except GICD_ICENABLERn. Each chip has support -- * for 320 {E}SPIs. Mappings for all 4 chips: -- * Chip0 = 32-351 -- * Chip1 = 352-671 -- * Chip2 = 672-991 -- * Chip3 = 4096-4415 -- */ -- switch (__get_intid_range(hwirq)) { -- case SPI_RANGE: -- chip = (hwirq - 32) / 320; -- break; -- case ESPI_RANGE: -- chip = 3; -- break; -- default: -- unreachable(); -- } -- return t241_dist_base_alias[chip]; -- } -- -- return gic_data.dist_base; --} -- - static inline void __iomem *gic_dist_base(struct irq_data *d) - { - switch (get_intid_range(d)) { -@@ -274,11 +216,11 @@ static inline void __iomem *gic_dist_base(struct irq_data *d) - } - } - --static void gic_do_wait_for_rwp(void __iomem *base) -+static void gic_do_wait_for_rwp(void __iomem *base, u32 bit) - { - u32 count = 1000000; /* 1s! */ - -- while (readl_relaxed(base + GICD_CTLR) & GICD_CTLR_RWP) { -+ while (readl_relaxed(base + GICD_CTLR) & bit) { - count--; - if (!count) { - pr_err_ratelimited("RWP timeout, gone fishing\n"); -@@ -292,13 +234,13 @@ static void gic_do_wait_for_rwp(void __iomem *base) - /* Wait for completion of a distributor change */ - static void gic_dist_wait_for_rwp(void) - { -- gic_do_wait_for_rwp(gic_data.dist_base); -+ gic_do_wait_for_rwp(gic_data.dist_base, GICD_CTLR_RWP); - } - - /* Wait for completion of a redistributor change */ - static void gic_redist_wait_for_rwp(void) - { -- gic_do_wait_for_rwp(gic_data_rdist_rd_base()); -+ gic_do_wait_for_rwp(gic_data_rdist_rd_base(), GICR_CTLR_RWP); - } - - static void gic_enable_redist(bool enable) -@@ -341,24 +283,25 @@ static void gic_enable_redist(bool enable) - - mpidr = (unsigned long)cpu_logical_map(smp_processor_id()); - -- if (mpidr & 0xFFFF) // either Aff1 or Aff0 is not zero -+ /* Either Aff0 or Aff1 is not zero */ -+ if (mpidr & 0xffff) - return; - -- rbase = rbase + 64 * SZ_128K; // skip 64 Redistributors -+ /* Skip 64 Redistributors */ -+ rbase = rbase + 64 * SZ_128K; - - for (i = 0; i < 4; i++) { - val = readl_relaxed(rbase + GICR_WAKER); - if (enable) -- /* Wake up this CPU redistributor */ - val &= ~GICR_WAKER_ProcessorSleep; - else - val |= GICR_WAKER_ProcessorSleep; - writel_relaxed(val, rbase + GICR_WAKER); - -- if (!enable) { /* Check that GICR_WAKER is writeable */ -+ if (!enable) { - val = readl_relaxed(rbase + GICR_WAKER); - if (!(val & GICR_WAKER_ProcessorSleep)) -- return; /* No PM support in this redistributor */ -+ return; - } - - count = 1000000; /* 1s! */ -@@ -369,11 +312,12 @@ static void gic_enable_redist(bool enable) - cpu_relax(); - udelay(1); - }; -+ - if (!count) - pr_err_ratelimited("CPU MPIDR 0x%lx: redistributor %d failed to %s...\n", -- mpidr, 64 + i, enable ? "wakeup" : "sleep"); -+ mpidr, 64 + i, enable ? "wakeup" : "sleep"); - -- rbase = rbase + SZ_128K; // next redistributor -+ rbase = rbase + SZ_128K; - } - } - -@@ -433,7 +377,7 @@ static u32 convert_offset_index(struct irq_data *d, u32 offset, u32 *index) - static int gic_peek_irq(struct irq_data *d, u32 offset) - { - void __iomem *base; -- u32 index, mask; -+ u32 index, mask, skt; - - offset = convert_offset_index(d, offset, &index); - mask = 1 << (index % 32); -@@ -441,8 +385,6 @@ static int gic_peek_irq(struct irq_data *d, u32 offset) - if (gic_irq_in_rdist(d)) - base = gic_data_rdist_sgi_base(); - else { -- unsigned int skt; -- - skt = mars3_irq_to_skt(gic_irq(d)); - base = mars3_gic_dists[skt].dist_base; - } -@@ -452,13 +394,10 @@ static int gic_peek_irq(struct irq_data *d, u32 offset) - - static void gic_poke_irq(struct irq_data *d, u32 offset) - { -- void __iomem *base; -- -+ void __iomem *base, *rbase; - unsigned long mpidr; -- void __iomem *rbase; - int i; -- unsigned int skt; -- u32 index, mask; -+ u32 index, mask, skt; - - offset = convert_offset_index(d, offset, &index); - mask = 1 << (index % 32); -@@ -471,20 +410,20 @@ static void gic_poke_irq(struct irq_data *d, u32 offset) - - mpidr = (unsigned long)cpu_logical_map(smp_processor_id()); - -- if ((mpidr & 0xFFFF) == 0) { // both Aff1 and Aff0 are zero -- rbase = base + 64*SZ_128K; // skip 64 Redistributors -+ if ((mpidr & 0xffff) == 0) { -+ rbase = base + 64*SZ_128K; - - for (i = 0; i < 4; i++) { - writel_relaxed(mask, rbase + offset + (index / 32) * 4); -- gic_do_wait_for_rwp(rbase - SZ_64K); // RD from SGI base -+ gic_do_wait_for_rwp(rbase - SZ_64K, GICR_CTLR_RWP); - rbase = rbase + SZ_128K; - } -- } // core 0 of each socket -+ } - } else { - skt = mars3_irq_to_skt(gic_irq(d)); -- base = mars3_gic_dists[skt].dist_base; -+ base = mars3_gic_dists[skt].dist_base; - writel_relaxed(mask, base + offset + (index / 32) * 4); -- gic_do_wait_for_rwp(base); -+ gic_do_wait_for_rwp(base, GICD_CTLR_RWP); - } - } - -@@ -517,10 +456,10 @@ static void gic_unmask_irq(struct irq_data *d) - gic_poke_irq(d, GICD_ISENABLER); - } - --static inline bool gic_supports_nmi_ft2500(void) -+static inline bool gic_supports_nmi(void) - { - return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) && -- static_branch_likely(&supports_pseudo_nmis_ft2500); -+ static_branch_likely(&supports_pseudo_nmis); - } - - static int gic_irq_set_irqchip_state(struct irq_data *d, -@@ -613,7 +552,7 @@ static int gic_irq_nmi_setup(struct irq_data *d) - { - struct irq_desc *desc = irq_to_desc(d->irq); - -- if (!gic_supports_nmi_ft2500()) -+ if (!gic_supports_nmi()) - return -EINVAL; - - if (gic_peek_irq(d, GICD_ISENABLER)) { -@@ -650,7 +589,7 @@ static void gic_irq_nmi_teardown(struct irq_data *d) - { - struct irq_desc *desc = irq_to_desc(d->irq); - -- if (WARN_ON(!gic_supports_nmi_ft2500())) -+ if (WARN_ON(!gic_supports_nmi())) - return; - - if (gic_peek_irq(d, GICD_ISENABLER)) { -@@ -679,54 +618,21 @@ static void gic_irq_nmi_teardown(struct irq_data *d) - gic_irq_set_prio(d, GICD_INT_DEF_PRI); - } - --static bool gic_arm64_erratum_2941627_needed(struct irq_data *d) --{ -- enum gic_intid_range range; -- -- if (!static_branch_unlikely(&gic_arm64_2941627_erratum)) -- return false; -- -- range = get_intid_range(d); -- -- /* -- * The workaround is needed if the IRQ is an SPI and -- * the target cpu is different from the one we are -- * executing on. -- */ -- return (range == SPI_RANGE || range == ESPI_RANGE) && -- !cpumask_test_cpu(raw_smp_processor_id(), -- irq_data_get_effective_affinity_mask(d)); --} -- - static void gic_eoi_irq(struct irq_data *d) - { - write_gicreg(gic_irq(d), ICC_EOIR1_EL1); - isb(); -- -- if (gic_arm64_erratum_2941627_needed(d)) { -- /* -- * Make sure the GIC stream deactivate packet -- * issued by ICC_EOIR1_EL1 has completed before -- * deactivating through GICD_IACTIVER. -- */ -- dsb(sy); -- gic_poke_irq(d, GICD_ICACTIVER); -- } - } - - static void gic_eoimode1_eoi_irq(struct irq_data *d) - { - /* - * No need to deactivate an LPI, or an interrupt that -- * is is getting forwarded to a vcpu. -+ * is getting forwarded to a vcpu. - */ - if (gic_irq(d) >= 8192 || irqd_is_forwarded_to_vcpu(d)) - return; -- -- if (!gic_arm64_erratum_2941627_needed(d)) -- gic_write_dir(gic_irq(d)); -- else -- gic_poke_irq(d, GICD_ICACTIVER); -+ gic_write_dir(gic_irq(d)); - } - - static int gic_set_type(struct irq_data *d, unsigned int type) -@@ -739,7 +645,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type) - unsigned long mpidr; - - range = get_intid_range(d); -- - /* Interrupt configuration for SGIs can't be changed */ - if (range == SGI_RANGE) - return type != IRQ_TYPE_EDGE_RISING ? -EINVAL : 0; -@@ -754,7 +659,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type) - if (gic_irq_in_rdist(d)) { - base = gic_data_rdist_sgi_base(); - ret = gic_configure_irq(index, type, base + offset, gic_redist_wait_for_rwp); -- - mpidr = (unsigned long)cpu_logical_map(smp_processor_id()); - - if ((mpidr & 0xffff) == 0) { -@@ -762,7 +666,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type) - - for (i = 0; i < 4; i++) { - ret = gic_configure_irq(index, type, rbase + offset, NULL); -- gic_do_wait_for_rwp(rbase - SZ_64K); -+ gic_do_wait_for_rwp(rbase - SZ_64K, GICR_CTLR_RWP); - rbase = rbase + SZ_128K; - } - } -@@ -770,9 +674,10 @@ static int gic_set_type(struct irq_data *d, unsigned int type) - skt = mars3_irq_to_skt(gic_irq(d)); - base = mars3_gic_dists[skt].dist_base; - ret = gic_configure_irq(index, type, base + offset, NULL); -- gic_do_wait_for_rwp(base); -+ gic_do_wait_for_rwp(base, GICD_CTLR_RWP); - } - -+ - if (ret && (range == PPI_RANGE || range == EPPI_RANGE)) { - /* Misconfigured PPIs are usually not fatal */ - pr_warn("GIC: PPI INTID%d is secure or misconfigured\n", irq); -@@ -794,16 +699,10 @@ static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) - return 0; - } - --static u64 gic_cpu_to_affinity(int cpu) -+static u64 gic_mpidr_to_affinity(unsigned long mpidr) - { -- u64 mpidr = cpu_logical_map(cpu); - u64 aff; - -- /* ASR8601 needs to have its affinities shifted down... */ -- if (unlikely(gic_data.flags & FLAGS_WORKAROUND_ASR_ERRATUM_8601001)) -- mpidr = (MPIDR_AFFINITY_LEVEL(mpidr, 1) | -- (MPIDR_AFFINITY_LEVEL(mpidr, 2) << 8)); -- - aff = ((u64)MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 | - MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 | - MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 | -@@ -852,7 +751,7 @@ static inline void gic_complete_ack(u32 irqnr) - - static bool gic_rpr_is_nmi_prio(void) - { -- if (!gic_supports_nmi_ft2500()) -+ if (!gic_supports_nmi()) - return false; - - return unlikely(gic_read_rpr() == GICD_INT_RPR_PRI(GICD_INT_NMI_PRI)); -@@ -962,7 +861,7 @@ static void __gic_handle_irq_from_irqsoff(struct pt_regs *regs) - - static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) - { -- if (unlikely(gic_supports_nmi_ft2500() && !interrupts_enabled(regs))) -+ if (unlikely(gic_supports_nmi() && !interrupts_enabled(regs))) - __gic_handle_irq_from_irqsoff(regs); - else - __gic_handle_irq_from_irqson(regs); -@@ -1021,7 +920,7 @@ static void __init gic_dist_init(void) - - /* Disable the distributor */ - writel_relaxed(0, base + GICD_CTLR); -- gic_do_wait_for_rwp(base); -+ gic_do_wait_for_rwp(base, GICD_CTLR_RWP); - - /* - * Configure SPIs as non-secure Group-1. This will only matter -@@ -1047,9 +946,9 @@ static void __init gic_dist_init(void) - for (i = 0; i < GIC_ESPI_NR; i += 4) - writel_relaxed(GICD_INT_DEF_PRI_X4, base + GICD_IPRIORITYRnE + i); - -- /* Now do the common stuff */ -+ /* Now do the common stuff, and wait for the distributor to drain */ - gic_dist_config(base, GIC_LINE_NR, NULL); -- gic_do_wait_for_rwp(base); -+ gic_do_wait_for_rwp(base, GICD_CTLR_RWP); // do sync outside of gic_dist_config - - val = GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1; - if (gic_data.rdists.gicd_typer2 & GICD_TYPER2_nASSGIcap) { -@@ -1057,15 +956,14 @@ static void __init gic_dist_init(void) - val |= GICD_CTLR_nASSGIreq; - } - -- /* Enable distributor with ARE, Group1, and wait for it to drain */ -+ /* Enable distributor with ARE, Group1 */ - writel_relaxed(val, base + GICD_CTLR); -- gic_dist_wait_for_rwp(); - -- /* -+ /* - * Set all global interrupts to the boot CPU only. ARE must be - * enabled. - */ -- affinity = gic_cpu_to_affinity(smp_processor_id()); -+ affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id())); - for (i = 32; i < GIC_LINE_NR; i++) - gic_write_irouter(affinity, base + GICD_IROUTER + i * 8); - -@@ -1115,25 +1013,21 @@ static int gic_iterate_rdists(int (*fn)(struct redist_region *, void __iomem *)) - - static int __gic_populate_rdist(struct redist_region *region, void __iomem *ptr) - { -- unsigned long mpidr; -+ unsigned long mpidr = cpu_logical_map(smp_processor_id()); - u64 typer; -- u32 aff; -- u32 aff2_skt; -- u32 redist_skt; -+ u32 aff, aff2_skt, rdist_skt; - - /* - * Convert affinity to a 32bit value that can be matched to - * GICR_TYPER bits [63:32]. - */ -- mpidr = gic_cpu_to_affinity(smp_processor_id()); -- - aff = (MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 | -- MPIDR_AFFINITY_LEVEL(mpidr, 0)); -+ MPIDR_AFFINITY_LEVEL(mpidr, 0)); - - aff2_skt = MPIDR_AFFINITY_LEVEL(mpidr, 2) & 0x7; -- redist_skt = (((u64)region->phys_base >> MARS3_ADDR_SKTID_SHIFT) & 0x7); -+ rdist_skt = (((u64)region->phys_base >> MARS3_ADDR_SKTID_SHIFT) & 0x7); - -- if (aff2_skt != redist_skt) -+ if (aff2_skt != rdist_skt) - return 1; - - typer = gic_read_typer(ptr + GICR_TYPER); -@@ -1173,7 +1067,7 @@ static int __gic_update_rdist_properties(struct redist_region *region, - u64 typer = gic_read_typer(ptr + GICR_TYPER); - u32 ctlr = readl_relaxed(ptr + GICR_CTLR); - -- /* Boot-time cleanup */ -+ /* Boot-time cleanip */ - if ((typer & GICR_TYPER_VLPIS) && (typer & GICR_TYPER_RVPEID)) { - u64 val; - -@@ -1224,7 +1118,7 @@ static void gic_update_rdist_properties(void) - gic_iterate_rdists(__gic_update_rdist_properties); - if (WARN_ON(gic_data.ppi_nr == UINT_MAX)) - gic_data.ppi_nr = 0; -- pr_info("GICv3 features: %d PPIs%s%s\n", -+ pr_info("GIC-2500 features: %d PPIs%s%s\n", - gic_data.ppi_nr, - gic_data.has_rss ? ", RSS" : "", - gic_data.rdists.has_direct_lpi ? ", DirectLPI" : ""); -@@ -1245,7 +1139,7 @@ static inline bool gic_dist_security_disabled(void) - static void gic_cpu_sys_reg_init(void) - { - int i, cpu = smp_processor_id(); -- u64 mpidr = gic_cpu_to_affinity(cpu); -+ u64 mpidr = cpu_logical_map(cpu); - u64 need_rss = MPIDR_RS(mpidr); - bool group0; - u32 pribits; -@@ -1267,7 +1161,7 @@ static void gic_cpu_sys_reg_init(void) - /* Set priority mask register */ - if (!gic_prio_masking_enabled()) { - write_gicreg(DEFAULT_PMR_VALUE, ICC_PMR_EL1); -- } else if (gic_supports_nmi_ft2500()) { -+ } else if (gic_supports_nmi()) { - /* - * Mismatch configuration with boot CPU, the system is likely - * to die as interrupt masking will not work properly on all -@@ -1338,17 +1232,17 @@ static void gic_cpu_sys_reg_init(void) - gic_write_grpen1(1); - - /* Keep the RSS capability status in per_cpu variable */ -- per_cpu(has_rss_ft2500, cpu) = !!(gic_read_ctlr() & ICC_CTLR_EL1_RSS); -+ per_cpu(has_rss, cpu) = !!(gic_read_ctlr() & ICC_CTLR_EL1_RSS); - - /* Check all the CPUs have capable of sending SGIs to other CPUs */ - for_each_online_cpu(i) { -- bool have_rss = per_cpu(has_rss_ft2500, i) && per_cpu(has_rss_ft2500, cpu); -+ bool have_rss = per_cpu(has_rss, i) && per_cpu(has_rss, cpu); - -- need_rss |= MPIDR_RS(gic_cpu_to_affinity(i)); -+ need_rss |= MPIDR_RS(cpu_logical_map(i)); - if (need_rss && (!have_rss)) - pr_crit("CPU%d (%lx) can't SGI CPU%d (%lx), no RSS\n", - cpu, (unsigned long)mpidr, -- i, (unsigned long)gic_cpu_to_affinity(i)); -+ i, (unsigned long)cpu_logical_map(i)); - } - - /** -@@ -1366,7 +1260,7 @@ static bool gicv3_nolpi; - - static int __init gicv3_nolpi_cfg(char *buf) - { -- return kstrtobool(buf, &gicv3_nolpi); -+ return strtobool(buf, &gicv3_nolpi); - } - early_param("irqchip.gicv3_nolpi", gicv3_nolpi_cfg); - -@@ -1404,18 +1298,17 @@ static void gic_cpu_init(void) - - mpidr = (unsigned long)cpu_logical_map(smp_processor_id()); - -- if ((mpidr & 0xFFFF) == 0) { // both Aff1 and Aff0 is zero -- rbase = rbase + 64*SZ_128K; // skip 64 Redistributors -+ if ((mpidr & 0xffff) == 0) { -+ rbase = rbase + 64*SZ_128K; - - for (i = 0; i < 4; i++) { - /* Configure SGIs/PPIs as non-secure Group-1 */ - writel_relaxed(~0, rbase + GICR_IGROUPR0); - - gic_cpu_config(rbase, gic_data.ppi_nr + 16, NULL); -- gic_do_wait_for_rwp(rbase - SZ_64K); -+ gic_do_wait_for_rwp(rbase - SZ_64K, GICR_CTLR_RWP); - - rbase = rbase + SZ_128K; -- - } - } - -@@ -1442,11 +1335,9 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask, - unsigned long cluster_id) - { - int next_cpu, cpu = *base_cpu; -- unsigned long mpidr; -+ unsigned long mpidr = cpu_logical_map(cpu); - u16 tlist = 0; - -- mpidr = gic_cpu_to_affinity(cpu); -- - while (cpu < nr_cpu_ids) { - tlist |= 1 << (mpidr & 0xf); - -@@ -1455,7 +1346,7 @@ static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask, - goto out; - cpu = next_cpu; - -- mpidr = gic_cpu_to_affinity(cpu); -+ mpidr = cpu_logical_map(cpu); - - if (cluster_id != MPIDR_TO_SGI_CLUSTER_ID(mpidr)) { - cpu--; -@@ -1500,7 +1391,7 @@ static void gic_ipi_send_mask(struct irq_data *d, const struct cpumask *mask) - dsb(ishst); - - for_each_cpu(cpu, mask) { -- u64 cluster_id = MPIDR_TO_SGI_CLUSTER_ID(gic_cpu_to_affinity(cpu)); -+ u64 cluster_id = MPIDR_TO_SGI_CLUSTER_ID(cpu_logical_map(cpu)); - u16 tlist; - - tlist = gic_compute_target_list(&cpu, mask, cluster_id); -@@ -1520,11 +1411,13 @@ static void __init gic_smp_init(void) - int base_sgi; - - cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING, -- "irqchip/arm/gicv3:starting", -+ "irqchip/arm/gic_phytium_2500:starting", - gic_starting_cpu, NULL); - - /* Register all 8 non-secure SGIs */ -- base_sgi = irq_domain_alloc_irqs(gic_data.domain, 8, NUMA_NO_NODE, &sgi_fwspec); -+ base_sgi = __irq_domain_alloc_irqs(gic_data.domain, -1, 8, -+ NUMA_NO_NODE, &sgi_fwspec, -+ false, NULL); - if (WARN_ON(base_sgi <= 0)) - return; - -@@ -1535,22 +1428,26 @@ static int gic_cpumask_select(struct irq_data *d, const struct cpumask *mask_val - { - unsigned int skt, irq_skt, i; - unsigned int cpu, cpus = 0; -- - unsigned int skt_cpu_cnt[MAX_MARS3_SOC_COUNT] = {0}; - -+ irq_skt = mars3_irq_to_skt(gic_irq(d)); -+ - for (i = 0; i < nr_cpu_ids; i++) { - skt = (cpu_logical_map(i) >> 16) & 0xff; -- if ((skt >= 0) && (skt < MAX_MARS3_SOC_COUNT)) -+ if ((skt >= 0) && (skt < MAX_MARS3_SOC_COUNT)) { -+ if ((is_kdump_kernel()) && (irq_skt == skt)) -+ return i; -+ - skt_cpu_cnt[skt]++; -- else if (skt != 0xff) -+ } else if (skt != 0xff) { - pr_err("socket address: %d is out of range.", skt); -+ } - } - -- irq_skt = mars3_irq_to_skt(gic_irq(d)); -- -- if (irq_skt != 0) -+ if (irq_skt) { - for (i = 0; i < irq_skt; i++) - cpus += skt_cpu_cnt[i]; -+ } - - cpu = cpumask_any_and(mask_val, cpu_online_mask); - cpus = cpus + cpu % skt_cpu_cnt[irq_skt]; -@@ -1561,12 +1458,11 @@ static int gic_cpumask_select(struct irq_data *d, const struct cpumask *mask_val - static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, - bool force) - { -- unsigned int cpu; -+ unsigned int cpu, skt; - u32 offset, index; - void __iomem *reg; - int enabled; - u64 val; -- unsigned int skt; - - if (force) - cpu = cpumask_first(mask_val); -@@ -1587,9 +1483,8 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, - offset = convert_offset_index(d, GICD_IROUTER, &index); - - skt = mars3_irq_to_skt(gic_irq(d)); -- reg = mars3_gic_dists[skt].dist_base + offset + GICD_IROUTER + (index * 8); -- reg = gic_dist_base(d) + offset + (index * 8); -- val = gic_cpu_to_affinity(cpu); -+ reg = mars3_gic_dists[skt].dist_base + offset + (index * 8); -+ val = gic_mpidr_to_affinity(cpu_logical_map(cpu)); - - gic_write_irouter(val, reg); - -@@ -1644,7 +1539,7 @@ static inline void gic_cpu_pm_init(void) { } - #endif /* CONFIG_CPU_PM */ - - static struct irq_chip gic_chip = { -- .name = "GIC-phytium-2500", -+ .name = "GIC-Phytium-2500", - .irq_mask = gic_mask_irq, - .irq_unmask = gic_unmask_irq, - .irq_eoi = gic_eoi_irq, -@@ -1662,7 +1557,7 @@ static struct irq_chip gic_chip = { - }; - - static struct irq_chip gic_eoimode1_chip = { -- .name = "GICv3-phytium-2500", -+ .name = "GIC-Phytium-2500", - .irq_mask = gic_eoimode1_mask_irq, - .irq_unmask = gic_unmask_irq, - .irq_eoi = gic_eoimode1_eoi_irq, -@@ -1925,188 +1820,6 @@ static const struct irq_domain_ops partition_domain_ops = { - .select = gic_irq_domain_select, - }; - --static bool gic_enable_quirk_msm8996(void *data) --{ -- struct gic_chip_data *d = data; -- -- d->flags |= FLAGS_WORKAROUND_GICR_WAKER_MSM8996; -- -- return true; --} -- --static bool gic_enable_quirk_mtk_gicr(void *data) --{ -- struct gic_chip_data *d = data; -- -- d->flags |= FLAGS_WORKAROUND_MTK_GICR_SAVE; -- -- return true; --} -- --static bool gic_enable_quirk_cavium_38539(void *data) --{ -- struct gic_chip_data *d = data; -- -- d->flags |= FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539; -- -- return true; --} -- --static bool gic_enable_quirk_hip06_07(void *data) --{ -- struct gic_chip_data *d = data; -- -- /* -- * HIP06 GICD_IIDR clashes with GIC-600 product number (despite -- * not being an actual ARM implementation). The saving grace is -- * that GIC-600 doesn't have ESPI, so nothing to do in that case. -- * HIP07 doesn't even have a proper IIDR, and still pretends to -- * have ESPI. In both cases, put them right. -- */ -- if (d->rdists.gicd_typer & GICD_TYPER_ESPI) { -- /* Zero both ESPI and the RES0 field next to it... */ -- d->rdists.gicd_typer &= ~GENMASK(9, 8); -- return true; -- } -- -- return false; --} -- --#define T241_CHIPN_MASK GENMASK_ULL(45, 44) --#define T241_CHIP_GICDA_OFFSET 0x1580000 --#define SMCCC_SOC_ID_T241 0x036b0241 -- --static bool gic_enable_quirk_nvidia_t241(void *data) --{ -- s32 soc_id = arm_smccc_get_soc_id_version(); -- unsigned long chip_bmask = 0; -- phys_addr_t phys; -- u32 i; -- -- /* Check JEP106 code for NVIDIA T241 chip (036b:0241) */ -- if ((soc_id < 0) || (soc_id != SMCCC_SOC_ID_T241)) -- return false; -- -- /* Find the chips based on GICR regions PHYS addr */ -- for (i = 0; i < gic_data.nr_redist_regions; i++) { -- chip_bmask |= BIT(FIELD_GET(T241_CHIPN_MASK, -- (u64)gic_data.redist_regions[i].phys_base)); -- } -- -- if (hweight32(chip_bmask) < 3) -- return false; -- -- /* Setup GICD alias regions */ -- for (i = 0; i < ARRAY_SIZE(t241_dist_base_alias); i++) { -- if (chip_bmask & BIT(i)) { -- phys = gic_data.dist_phys_base + T241_CHIP_GICDA_OFFSET; -- phys |= FIELD_PREP(T241_CHIPN_MASK, i); -- t241_dist_base_alias[i] = ioremap(phys, SZ_64K); -- WARN_ON_ONCE(!t241_dist_base_alias[i]); -- } -- } -- static_branch_enable(&gic_nvidia_t241_erratum); -- return true; --} -- --static bool gic_enable_quirk_asr8601(void *data) --{ -- struct gic_chip_data *d = data; -- -- d->flags |= FLAGS_WORKAROUND_ASR_ERRATUM_8601001; -- -- return true; --} -- --static bool gic_enable_quirk_arm64_2941627(void *data) --{ -- static_branch_enable(&gic_arm64_2941627_erratum); -- return true; --} -- --static bool rd_set_non_coherent(void *data) --{ -- struct gic_chip_data *d = data; -- -- d->rdists.flags |= RDIST_FLAGS_FORCE_NON_SHAREABLE; -- return true; --} -- --static const struct gic_quirk gic_quirks[] = { -- { -- .desc = "GICv3: Qualcomm MSM8996 broken firmware", -- .compatible = "qcom,msm8996-gic-v3", -- .init = gic_enable_quirk_msm8996, -- }, -- { -- .desc = "GICv3: ASR erratum 8601001", -- .compatible = "asr,asr8601-gic-v3", -- .init = gic_enable_quirk_asr8601, -- }, -- { -- .desc = "GICv3: Mediatek Chromebook GICR save problem", -- .property = "mediatek,broken-save-restore-fw", -- .init = gic_enable_quirk_mtk_gicr, -- }, -- { -- .desc = "GICv3: HIP06 erratum 161010803", -- .iidr = 0x0204043b, -- .mask = 0xffffffff, -- .init = gic_enable_quirk_hip06_07, -- }, -- { -- .desc = "GICv3: HIP07 erratum 161010803", -- .iidr = 0x00000000, -- .mask = 0xffffffff, -- .init = gic_enable_quirk_hip06_07, -- }, -- { -- /* -- * Reserved register accesses generate a Synchronous -- * External Abort. This erratum applies to: -- * - ThunderX: CN88xx -- * - OCTEON TX: CN83xx, CN81xx -- * - OCTEON TX2: CN93xx, CN96xx, CN98xx, CNF95xx* -- */ -- .desc = "GICv3: Cavium erratum 38539", -- .iidr = 0xa000034c, -- .mask = 0xe8f00fff, -- .init = gic_enable_quirk_cavium_38539, -- }, -- { -- .desc = "GICv3: NVIDIA erratum T241-FABRIC-4", -- .iidr = 0x0402043b, -- .mask = 0xffffffff, -- .init = gic_enable_quirk_nvidia_t241, -- }, -- { -- /* -- * GIC-700: 2941627 workaround - IP variant [0,1] -- * -- */ -- .desc = "GICv3: ARM64 erratum 2941627", -- .iidr = 0x0400043b, -- .mask = 0xff0e0fff, -- .init = gic_enable_quirk_arm64_2941627, -- }, -- { -- /* -- * GIC-700: 2941627 workaround - IP variant [2] -- */ -- .desc = "GICv3: ARM64 erratum 2941627", -- .iidr = 0x0402043b, -- .mask = 0xff0f0fff, -- .init = gic_enable_quirk_arm64_2941627, -- }, -- { -- .desc = "GICv3: non-coherent attribute", -- .property = "dma-noncoherent", -- .init = rd_set_non_coherent, -- }, -- { -- } --}; -- - static void gic_enable_nmi_support(void) - { - int i; -@@ -2114,11 +1827,6 @@ static void gic_enable_nmi_support(void) - if (!gic_prio_masking_enabled()) - return; - -- if (gic_data.flags & FLAGS_WORKAROUND_MTK_GICR_SAVE) { -- pr_warn("Skipping NMI enable due to firmware issues\n"); -- return; -- } -- - ppi_nmi_refs = kcalloc(gic_data.ppi_nr, sizeof(*ppi_nmi_refs), GFP_KERNEL); - if (!ppi_nmi_refs) - return; -@@ -2159,7 +1867,7 @@ static void gic_enable_nmi_support(void) - if (gic_has_group0() && !gic_dist_security_disabled()) - static_branch_enable(&gic_nonsecure_priorities); - -- static_branch_enable(&supports_pseudo_nmis_ft2500); -+ static_branch_enable(&supports_pseudo_nmis); - - if (static_branch_likely(&supports_deactivate_key)) - gic_eoimode1_chip.flags |= IRQCHIP_SUPPORTS_NMI; -@@ -2167,8 +1875,7 @@ static void gic_enable_nmi_support(void) - gic_chip.flags |= IRQCHIP_SUPPORTS_NMI; - } - --static int __init gic_init_bases(phys_addr_t dist_phys_base, -- void __iomem *dist_base, -+static int __init gic_init_bases(void __iomem *dist_base, - struct redist_region *rdist_regs, - u32 nr_redist_regions, - u64 redist_stride, -@@ -2184,7 +1891,6 @@ static int __init gic_init_bases(phys_addr_t dist_phys_base, - pr_info("GIC: Using split EOI/Deactivate mode\n"); - - gic_data.fwnode = handle; -- gic_data.dist_phys_base = dist_phys_base; - gic_data.dist_base = dist_base; - gic_data.redist_regions = rdist_regs; - gic_data.nr_redist_regions = nr_redist_regions; -@@ -2196,29 +1902,18 @@ static int __init gic_init_bases(phys_addr_t dist_phys_base, - typer = readl_relaxed(gic_data.dist_base + GICD_TYPER); - gic_data.rdists.gicd_typer = typer; - -- gic_enable_quirks(readl_relaxed(gic_data.dist_base + GICD_IIDR), -- gic_quirks, &gic_data); -- - pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32); - pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR); - -- /* -- * ThunderX1 explodes on reading GICD_TYPER2, in violation of the -- * architecture spec (which says that reserved registers are RES0). -- */ -- if (!(gic_data.flags & FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539)) -- gic_data.rdists.gicd_typer2 = readl_relaxed(gic_data.dist_base + GICD_TYPER2); -+ gic_data.rdists.gicd_typer2 = readl_relaxed(gic_data.dist_base + GICD_TYPER2); - - gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops, - &gic_data); - gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist)); -- if (!static_branch_unlikely(&gic_nvidia_t241_erratum)) { -- /* Disable GICv4.x features for the erratum T241-FABRIC-4 */ -- gic_data.rdists.has_rvpeid = true; -- gic_data.rdists.has_vlpis = true; -- gic_data.rdists.has_direct_lpi = true; -- gic_data.rdists.has_vpend_valid_dirty = true; -- } -+ gic_data.rdists.has_rvpeid = true; -+ gic_data.rdists.has_vlpis = true; -+ gic_data.rdists.has_direct_lpi = true; -+ gic_data.rdists.has_vpend_valid_dirty = true; - - if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) { - err = -ENOMEM; -@@ -2247,7 +1942,7 @@ static int __init gic_init_bases(phys_addr_t dist_phys_base, - if (gic_dist_supports_lpis()) { - phytium_its_init(handle, &gic_data.rdists, gic_data.domain); - phytium_its_cpu_init(); -- its_lpi_memreserve_init(); -+ phytium_its_lpi_memreserve_init(); - } else { - if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) - gicv2m_init(handle, gic_data.domain); -@@ -2334,13 +2029,13 @@ static void __init gic_populate_ppi_partitions(struct device_node *gic_node) - continue; - } - -- pr_info("%pOF[%d] ", cpu_node, cpu); -+ pr_cont("%pOF[%d] ", cpu_node, cpu); - - cpumask_set_cpu(cpu, &part->mask); - of_node_put(cpu_node); - } - -- pr_info("}\n"); -+ pr_cont("}\n"); - part_idx++; - } - -@@ -2424,13 +2119,12 @@ static void __iomem *gic_of_iomap(struct device_node *node, int idx, - - static int __init gic_of_init(struct device_node *node, struct device_node *parent) - { -- phys_addr_t dist_phys_base; - void __iomem *dist_base; - struct redist_region *rdist_regs; -- struct resource res; - u64 redist_stride; - u32 nr_redist_regions; - int err, i; -+ struct resource res; - unsigned long skt; - - dist_base = gic_of_iomap(node, 0, "GICD", &res); -@@ -2439,8 +2133,6 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare - return PTR_ERR(dist_base); - } - -- dist_phys_base = res.start; -- - err = gic_validate_dist_version(dist_base); - if (err) { - pr_err("%pOF: no distributor detected, giving up\n", node); -@@ -2456,7 +2148,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare - mars3_gic_dists[0].size = resource_size(&res); - mars3_gic_dists[0].dist_base = dist_base; - -- if (of_property_read_u32(node, "#mars3_soc_bitmap", &mars3_sockets_bitmap)) -+ if (of_property_read_u32(node, "#mars3-soc-bitmap", &mars3_sockets_bitmap)) - mars3_sockets_bitmap = 0x1; - - for (skt = 1; skt < MAX_MARS3_SOC_COUNT; skt++) { -@@ -2493,8 +2185,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare - if (of_property_read_u64(node, "redistributor-stride", &redist_stride)) - redist_stride = 0; - -- err = gic_init_bases(dist_phys_base, dist_base, rdist_regs, -- nr_redist_regions, redist_stride, &node->fwnode); -+ err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions, -+ redist_stride, &node->fwnode); - if (err) - goto out_unmap_rdist; - -@@ -2514,7 +2206,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare - return err; - } - --IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); -+IRQCHIP_DECLARE(gic_phyt_2500, "arm,gic-phytium-2500", gic_of_init); - - #ifdef CONFIG_ACPI - static struct -@@ -2533,10 +2225,9 @@ static int gic_mars3_sockets_bitmap(void) - { - unsigned int skt, i; - int skt_bitmap = 0; -- - unsigned int skt_cpu_cnt[MAX_MARS3_SOC_COUNT] = {0}; - -- for (i = 0; i < nr_cpu_ids; i++) { -+ for (i = 0; i < max_t(unsigned int, nr_cpu_ids, NR_CPUS); i++) { - skt = (cpu_logical_map(i) >> 16) & 0xff; - if ((skt >= 0) && (skt < MAX_MARS3_SOC_COUNT)) - skt_cpu_cnt[skt]++; -@@ -2544,9 +2235,10 @@ static int gic_mars3_sockets_bitmap(void) - pr_err("socket address: %d is out of range.", skt); - } - -- for (i = 0; i < MAX_MARS3_SOC_COUNT; i++) -+ for (i = 0; i < MAX_MARS3_SOC_COUNT; i++) { - if (skt_cpu_cnt[i] > 0) - skt_bitmap |= (1 << i); -+ } - - return skt_bitmap; - } -@@ -2554,7 +2246,7 @@ static int gic_mars3_sockets_bitmap(void) - static void __init - gic_acpi_register_redist(phys_addr_t phys_base, void __iomem *redist_base) - { -- static int count; -+ static int count = 0; - - acpi_data.redist_regs[count].phys_base = phys_base; - acpi_data.redist_regs[count].redist_base = redist_base; -@@ -2786,7 +2478,7 @@ static void __init gic_acpi_setup_kvm_info(void) - - static struct fwnode_handle *gsi_domain_handle; - --static struct fwnode_handle *gic_v3_get_gsi_domain_id(u32 gsi) -+static struct fwnode_handle *gic_s2500_get_gsi_domain_id(u32 gsi) - { - return gsi_domain_handle; - } -@@ -2796,8 +2488,7 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end) - { - struct acpi_madt_generic_distributor *dist; - size_t size; -- int i, err; -- int skt; -+ int i, err, skt; - - /* Get distributor base address */ - dist = (struct acpi_madt_generic_distributor *)header; -@@ -2820,24 +2511,22 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end) - mars3_gic_dists[0].size = ACPI_GICV3_DIST_MEM_SIZE; - mars3_gic_dists[0].dist_base = acpi_data.dist_base; - --#ifdef CONFIG_ACPI - mars3_sockets_bitmap = gic_mars3_sockets_bitmap(); - if (mars3_sockets_bitmap == 0) { - mars3_sockets_bitmap = 0x1; -- pr_err("No socket, please check cpus MPIDR_AFFINITY_LEVEL!!!"); -+ pr_err("No socket, please check cpus MPIDR_AFFINITY_LEVEL!"); - } else - pr_info("mars3_sockets_bitmap = 0x%x\n", mars3_sockets_bitmap); --#endif - - for (skt = 1; skt < MAX_MARS3_SOC_COUNT; skt++) { - if (((1U << skt) & mars3_sockets_bitmap) == 0) - continue; - - mars3_gic_dists[skt].phys_base = ((unsigned long)skt << MARS3_ADDR_SKTID_SHIFT) | -- mars3_gic_dists[0].phys_base; -+ mars3_gic_dists[0].phys_base; - mars3_gic_dists[skt].size = mars3_gic_dists[0].size; - mars3_gic_dists[skt].dist_base = ioremap(mars3_gic_dists[skt].phys_base, -- mars3_gic_dists[skt].size); -+ mars3_gic_dists[skt].size); - } - - size = sizeof(*acpi_data.redist_regs) * acpi_data.nr_redist_regions; -@@ -2857,13 +2546,12 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end) - goto out_redist_unmap; - } - -- err = gic_init_bases(dist->base_address, acpi_data.dist_base, -- acpi_data.redist_regs, acpi_data.nr_redist_regions, -- 0, gsi_domain_handle); -+ err = gic_init_bases(acpi_data.dist_base, acpi_data.redist_regs, -+ acpi_data.nr_redist_regions, 0, gsi_domain_handle); - if (err) - goto out_fwhandle_free; - -- acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id); -+ acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_s2500_get_gsi_domain_id); - - if (static_branch_likely(&supports_deactivate_key)) - gic_acpi_setup_kvm_info(); -@@ -2881,7 +2569,7 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end) - iounmap(acpi_data.dist_base); - return err; - } --IRQCHIP_ACPI_DECLARE(gic_phyt_2500, ACPI_MADT_TYPE_PHYTIUM_2500, -+IRQCHIP_ACPI_DECLARE(gic_phyt_2500, ACPI_MADT_TYPE_OEM_RESERVED, - acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V3, - gic_acpi_init); - #endif -diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c -index 2ec66dc..ca81890 100644 ---- a/drivers/irqchip/irq-gic-v3-its.c -+++ b/drivers/irqchip/irq-gic-v3-its.c -@@ -4887,6 +4887,7 @@ static void its_restore_enable(void) - { - struct its_node *its; - int ret; -+ int cpu; - - raw_spin_lock(&its_lock); - list_for_each_entry(its, &its_nodes, entry) { -@@ -4940,6 +4941,23 @@ static void its_restore_enable(void) - GITS_TYPER_HCC(gic_read_typer(base + GITS_TYPER))) - its_cpu_init_collection(its); - } -+ -+ /* -+ * Enable LPIs:firmware just restore GICR_CTLR_ENABLE_LPIs of boot -+ * CPU, the other CPUs also should be restored. -+ */ -+ for_each_possible_cpu(cpu) { -+ void __iomem *rbase = gic_data_rdist_cpu(cpu)->rd_base; -+ u32 val; -+ -+ /* Enable LPIs */ -+ val = readl_relaxed(rbase + GICR_CTLR); -+ if (val & GICR_CTLR_ENABLE_LPIS) -+ continue; -+ -+ val |= GICR_CTLR_ENABLE_LPIS; -+ writel_relaxed(val, rbase + GICR_CTLR); -+ } - raw_spin_unlock(&its_lock); - } - -diff --git a/drivers/irqchip/irq-loongarch-avec.c b/drivers/irqchip/irq-loongarch-avec.c -new file mode 100644 -index 0000000..2f79a53 ---- /dev/null -+++ b/drivers/irqchip/irq-loongarch-avec.c -@@ -0,0 +1,459 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2020-2024 Loongson Technologies, Inc. -+ */ -+ -+#include <linux/cpuhotplug.h> -+#include <linux/init.h> -+#include <linux/interrupt.h> -+#include <linux/irq.h> -+#include <linux/irqchip.h> -+#include <linux/irqchip/chained_irq.h> -+#include <linux/irqdomain.h> -+#include <linux/kernel.h> -+#include <linux/msi.h> -+#include <linux/radix-tree.h> -+#include <linux/spinlock.h> -+ -+#include <asm/loongarch.h> -+#include <asm/setup.h> -+ -+#include "irq-loongson.h" -+ -+#define VECTORS_PER_REG 64 -+#define IRR_VECTOR_MASK 0xffUL -+#define IRR_INVALID_MASK 0x80000000UL -+#define AVEC_MSG_OFFSET 0x100000 -+ -+#ifdef CONFIG_SMP -+struct pending_list { -+ struct list_head head; -+}; -+ -+bool disable_pci_irq_limit; -+static struct cpumask intersect_mask; -+static DEFINE_PER_CPU(struct pending_list, pending_list); -+#endif -+ -+static DEFINE_PER_CPU(struct irq_desc * [NR_VECTORS], irq_map); -+ -+struct avecintc_chip { -+ raw_spinlock_t lock; -+ struct fwnode_handle *fwnode; -+ struct irq_domain *domain; -+ struct irq_matrix *vector_matrix; -+ phys_addr_t msi_base_addr; -+}; -+ -+static struct avecintc_chip loongarch_avec; -+ -+struct avecintc_data { -+ struct list_head entry; -+ unsigned int cpu; -+ unsigned int vec; -+ unsigned int prev_cpu; -+ unsigned int prev_vec; -+ unsigned int moving; -+}; -+ -+static inline void avecintc_ack_irq(struct irq_data *d) -+{ -+} -+ -+static inline void avecintc_mask_irq(struct irq_data *d) -+{ -+} -+ -+static inline void avecintc_unmask_irq(struct irq_data *d) -+{ -+} -+ -+#ifdef CONFIG_SMP -+static inline void pending_list_init(int cpu) -+{ -+ struct pending_list *plist = per_cpu_ptr(&pending_list, cpu); -+ -+ INIT_LIST_HEAD(&plist->head); -+} -+ -+static void avecintc_sync(struct avecintc_data *adata) -+{ -+ struct pending_list *plist; -+ -+ if (cpu_online(adata->prev_cpu)) { -+ plist = per_cpu_ptr(&pending_list, adata->prev_cpu); -+ list_add_tail(&adata->entry, &plist->head); -+ adata->moving = 1; -+ smp_ops.send_ipi_single(adata->prev_cpu, ACTION_CLEAR_VECTOR); -+ } -+} -+ -+static int avecintc_set_affinity(struct irq_data *data, const struct cpumask *dest, bool force) -+{ -+ int cpu, ret, vector; -+ struct avecintc_data *adata; -+ -+ raw_spin_lock(&loongarch_avec.lock); -+ adata = irq_data_get_irq_chip_data(data); -+ -+ if (adata->moving) { -+ raw_spin_unlock(&loongarch_avec.lock); -+ return -EBUSY; -+ } -+ -+ if (adata->vec == UINT_MAX) { -+ raw_spin_unlock(&loongarch_avec.lock); -+ return -EINVAL; -+ } -+ -+ if (cpu_online(adata->cpu) && cpumask_test_cpu(adata->cpu, dest)) { -+ raw_spin_unlock(&loongarch_avec.lock); -+ return 0; -+ } -+ -+ cpumask_and(&intersect_mask, dest, cpu_online_mask); -+ -+ ret = irq_matrix_alloc(loongarch_avec.vector_matrix, &intersect_mask, false, &cpu); -+ if (ret < 0) { -+ raw_spin_unlock(&loongarch_avec.lock); -+ return ret; -+ } -+ -+ vector = ret; -+ adata->cpu = cpu; -+ adata->vec = vector; -+ per_cpu_ptr(irq_map, adata->cpu)[adata->vec] = irq_data_to_desc(data); -+ avecintc_sync(adata); -+ -+ raw_spin_unlock(&loongarch_avec.lock); -+ irq_data_update_effective_affinity(data, cpumask_of(cpu)); -+ -+ return IRQ_SET_MASK_OK; -+} -+ -+static int avecintc_cpu_online(unsigned int cpu) -+{ -+ long value; -+ if (!loongarch_avec.vector_matrix) -+ return 0; -+ -+ raw_spin_lock(&loongarch_avec.lock); -+ -+ irq_matrix_online(loongarch_avec.vector_matrix); -+ -+ pending_list_init(cpu); -+ -+ value = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC); -+ value |= IOCSR_MISC_FUNC_AVEC_EN; -+ iocsr_write64(value, LOONGARCH_IOCSR_MISC_FUNC); -+ -+ raw_spin_unlock(&loongarch_avec.lock); -+ -+ return 0; -+} -+ -+static int avecintc_cpu_offline(unsigned int cpu) -+{ -+ struct pending_list *plist = per_cpu_ptr(&pending_list, cpu); -+ -+ if (!loongarch_avec.vector_matrix) -+ return 0; -+ -+ raw_spin_lock(&loongarch_avec.lock); -+ -+ if (!list_empty(&plist->head)) -+ pr_warn("CPU#%d vector is busy\n", cpu); -+ irq_matrix_offline(loongarch_avec.vector_matrix); -+ -+ raw_spin_unlock(&loongarch_avec.lock); -+ -+ return 0; -+} -+ -+void complete_irq_moving(void) -+{ -+ struct pending_list *plist = this_cpu_ptr(&pending_list); -+ struct avecintc_data *adata, *tdata; -+ int cpu, vector, bias; -+ uint64_t isr; -+ -+ raw_spin_lock(&loongarch_avec.lock); -+ -+ list_for_each_entry_safe(adata, tdata, &plist->head, entry) { -+ cpu = adata->prev_cpu; -+ vector = adata->prev_vec; -+ bias = vector / VECTORS_PER_REG; -+ switch (bias) { -+ case 0: -+ isr = csr_read64(LOONGARCH_CSR_ISR0); -+ break; -+ case 1: -+ isr = csr_read64(LOONGARCH_CSR_ISR1); -+ break; -+ case 2: -+ isr = csr_read64(LOONGARCH_CSR_ISR2); -+ break; -+ case 3: -+ isr = csr_read64(LOONGARCH_CSR_ISR3); -+ break; -+ } -+ -+ if (isr & (1UL << (vector % VECTORS_PER_REG))) { -+ smp_ops.send_ipi_single(cpu, ACTION_CLEAR_VECTOR); -+ continue; -+ } -+ list_del(&adata->entry); -+ irq_matrix_free(loongarch_avec.vector_matrix, cpu, vector, false); -+ this_cpu_write(irq_map[vector], NULL); -+ adata->moving = 0; -+ adata->prev_cpu = adata->cpu; -+ adata->prev_vec = adata->vec; -+ } -+ -+ raw_spin_unlock(&loongarch_avec.lock); -+} -+#endif -+ -+static void avecintc_compose_msi_msg(struct irq_data *d, struct msi_msg *msg) -+{ -+ struct avecintc_data *adata = irq_data_get_irq_chip_data(d); -+ -+ msg->address_hi = 0x0; -+ msg->address_lo = (loongarch_avec.msi_base_addr | (adata->vec & 0xff) << 4) -+ | ((cpu_logical_map(adata->cpu & 0xffff)) << 12); -+ msg->data = 0x0; -+} -+ -+static struct irq_chip avec_irq_controller = { -+ .name = "AVECINTC", -+ .irq_ack = avecintc_ack_irq, -+ .irq_mask = avecintc_mask_irq, -+ .irq_unmask = avecintc_unmask_irq, -+#ifdef CONFIG_SMP -+ .irq_set_affinity = avecintc_set_affinity, -+#endif -+ .irq_compose_msi_msg = avecintc_compose_msi_msg, -+}; -+ -+static void avecintc_irq_dispatch(struct irq_desc *desc) -+{ -+ struct irq_chip *chip = irq_desc_get_chip(desc); -+ struct irq_desc *d; -+ -+ chained_irq_enter(chip, desc); -+ -+ while (true) { -+ unsigned long vector = csr_read64(LOONGARCH_CSR_IRR); -+ -+ if (vector & IRR_INVALID_MASK) -+ break; -+ -+ vector &= IRR_VECTOR_MASK; -+ -+ d = this_cpu_read(irq_map[vector]); -+ if (d) { -+ generic_handle_irq_desc(d); -+ } else { -+ spurious_interrupt(); -+ pr_warn("Unexpected IRQ occurs on CPU#%d [vector %ld]\n", -+ smp_processor_id(), vector); -+ } -+ } -+ -+ chained_irq_exit(chip, desc); -+} -+ -+static int avecintc_alloc_vector(struct irq_data *irqd, struct avecintc_data *adata) -+{ -+ int cpu, ret; -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&loongarch_avec.lock, flags); -+ -+ ret = irq_matrix_alloc(loongarch_avec.vector_matrix, cpu_online_mask, false, &cpu); -+ if (ret < 0) { -+ raw_spin_unlock_irqrestore(&loongarch_avec.lock, flags); -+ return ret; -+ } -+ -+ adata->prev_cpu = adata->cpu = cpu; -+ adata->prev_vec = adata->vec = ret; -+ per_cpu_ptr(irq_map, adata->cpu)[adata->vec] = irq_data_to_desc(irqd); -+ -+ raw_spin_unlock_irqrestore(&loongarch_avec.lock, flags); -+ -+ return 0; -+} -+ -+static int avecintc_domain_alloc(struct irq_domain *domain, -+ unsigned int virq, unsigned int nr_irqs, void *arg) -+{ -+ for (unsigned int i = 0; i < nr_irqs; i++) { -+ struct irq_data *irqd = irq_domain_get_irq_data(domain, virq + i); -+ struct avecintc_data *adata = kzalloc(sizeof(*adata), GFP_KERNEL); -+ int ret; -+ -+ if (!adata) -+ return -ENOMEM; -+ -+ ret = avecintc_alloc_vector(irqd, adata); -+ if (ret < 0) { -+ kfree(adata); -+ return ret; -+ } -+ -+ irq_domain_set_info(domain, virq + i, virq + i, &avec_irq_controller, -+ adata, handle_edge_irq, NULL, NULL); -+ irqd_set_single_target(irqd); -+ irqd_set_affinity_on_activate(irqd); -+ } -+ -+ return 0; -+} -+ -+static void avecintc_free_vector(struct irq_data *irqd, struct avecintc_data *adata) -+{ -+ unsigned long flags; -+ -+ raw_spin_lock_irqsave(&loongarch_avec.lock, flags); -+ -+ per_cpu(irq_map, adata->cpu)[adata->vec] = NULL; -+ irq_matrix_free(loongarch_avec.vector_matrix, adata->cpu, adata->vec, false); -+ -+#ifdef CONFIG_SMP -+ if (!adata->moving) { -+ raw_spin_unlock_irqrestore(&loongarch_avec.lock, flags); -+ return; -+ } -+ -+ per_cpu(irq_map, adata->prev_cpu)[adata->prev_vec] = NULL; -+ irq_matrix_free(loongarch_avec.vector_matrix, adata->prev_cpu, adata->prev_vec, false); -+ list_del_init(&adata->entry); -+#endif -+ raw_spin_unlock_irqrestore(&loongarch_avec.lock, flags); -+} -+ -+static void avecintc_domain_free(struct irq_domain *domain, -+ unsigned int virq, unsigned int nr_irqs) -+{ -+ for (unsigned int i = 0; i < nr_irqs; i++) { -+ struct irq_data *d = irq_domain_get_irq_data(domain, virq + i); -+ -+ if (d) { -+ struct avecintc_data *adata = irq_data_get_irq_chip_data(d); -+ -+ avecintc_free_vector(d, adata); -+ irq_domain_reset_irq_data(d); -+ kfree(adata); -+ } -+ } -+} -+ -+static const struct irq_domain_ops avecintc_domain_ops = { -+ .alloc = avecintc_domain_alloc, -+ .free = avecintc_domain_free, -+}; -+ -+static int __init irq_matrix_init(void) -+{ -+ loongarch_avec.vector_matrix = irq_alloc_matrix(NR_VECTORS, 0, NR_VECTORS); -+ if (!loongarch_avec.vector_matrix) -+ return -ENOMEM; -+ -+ for (int i = 0; i < NR_LEGACY_VECTORS; i++) -+ irq_matrix_assign_system(loongarch_avec.vector_matrix, i, false); -+ -+ irq_matrix_online(loongarch_avec.vector_matrix); -+ -+ return 0; -+} -+ -+static int __init avecintc_init(struct irq_domain *parent) -+{ -+ int ret, parent_irq; -+ unsigned long value; -+ -+ disable_pci_irq_limit = true; -+ raw_spin_lock_init(&loongarch_avec.lock); -+ -+ loongarch_avec.fwnode = irq_domain_alloc_named_fwnode("AVECINTC"); -+ if (!loongarch_avec.fwnode) { -+ pr_err("Unable to allocate domain handle\n"); -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ loongarch_avec.domain = irq_domain_create_tree(loongarch_avec.fwnode, -+ &avecintc_domain_ops, NULL); -+ if (!loongarch_avec.domain) { -+ pr_err("Unable to create IRQ domain\n"); -+ ret = -ENOMEM; -+ goto out_free_handle; -+ } -+ -+ parent_irq = irq_create_mapping(parent, INT_AVEC); -+ if (!parent_irq) { -+ pr_err("Failed to mapping hwirq\n"); -+ ret = -EINVAL; -+ goto out_remove_domain; -+ } -+ -+ ret = irq_matrix_init(); -+ if (ret < 0) { -+ pr_err("Failed to init irq matrix\n"); -+ goto out_remove_domain; -+ } -+ irq_set_chained_handler_and_data(parent_irq, avecintc_irq_dispatch, NULL); -+ -+#ifdef CONFIG_SMP -+ pending_list_init(0); -+ cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_AVECINTC_STARTING, -+ "irqchip/loongarch/avecintc:starting", -+ avecintc_cpu_online, avecintc_cpu_offline); -+#endif -+ value = iocsr_read64(LOONGARCH_IOCSR_MISC_FUNC); -+ value |= IOCSR_MISC_FUNC_AVEC_EN; -+ iocsr_write64(value, LOONGARCH_IOCSR_MISC_FUNC); -+ -+ return ret; -+ -+out_remove_domain: -+ irq_domain_remove(loongarch_avec.domain); -+out_free_handle: -+ irq_domain_free_fwnode(loongarch_avec.fwnode); -+out: -+ return ret; -+} -+ -+static int __init pch_msi_parse_madt(union acpi_subtable_headers *header, -+ const unsigned long end) -+{ -+ struct acpi_madt_msi_pic *pchmsi_entry = (struct acpi_madt_msi_pic *)header; -+ -+ loongarch_avec.msi_base_addr = pchmsi_entry->msg_address - AVEC_MSG_OFFSET; -+ -+ return pch_msi_acpi_init_avec(loongarch_avec.domain); -+} -+ -+static inline int __init acpi_cascade_irqdomain_init(void) -+{ -+ return acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 1); -+} -+ -+int __init avecintc_acpi_init(struct irq_domain *parent) -+{ -+ int ret = avecintc_init(parent); -+ -+ if (ret < 0) { -+ pr_err("Failed to init IRQ domain\n"); -+ return ret; -+ } -+ -+ ret = acpi_cascade_irqdomain_init(); -+ if (ret < 0) { -+ pr_err("Failed to init cascade IRQ domain\n"); -+ return ret; -+ } -+ -+ return ret; -+} -diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c -index 4380b4d..c6e0c98 100644 ---- a/drivers/irqchip/irq-loongarch-cpu.c -+++ b/drivers/irqchip/irq-loongarch-cpu.c -@@ -13,6 +13,8 @@ - #include <asm/loongarch.h> - #include <asm/setup.h> - -+#include "irq-loongson.h" -+ - static struct irq_domain *irq_domain; - struct fwnode_handle *cpuintc_handle; - -@@ -140,7 +142,10 @@ static int __init acpi_cascade_irqdomain_init(void) - if (r < 0) - return r; - -- return 0; -+ if (cpu_has_avecint) -+ r = avecintc_acpi_init(irq_domain); -+ -+ return r; - } - - struct irq_domain *get_cpudomain(void) -diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c -index 7e91362..f9317c9 100644 ---- a/drivers/irqchip/irq-loongson-eiointc.c -+++ b/drivers/irqchip/irq-loongson-eiointc.c -@@ -17,6 +17,8 @@ - #include <linux/syscore_ops.h> - #include <asm/numa.h> - -+#include "irq-loongson.h" -+ - #define EIOINTC_REG_NODEMAP 0x14a0 - #define EIOINTC_REG_IPMAP 0x14c0 - #define EIOINTC_REG_ENABLE 0x1600 -@@ -396,6 +398,9 @@ static int __init acpi_cascade_irqdomain_init(void) - if (r < 0) - return r; - -+ if (cpu_has_avecint) -+ return 0; -+ - r = acpi_table_parse_madt(ACPI_MADT_TYPE_MSI_PIC, pch_msi_parse_madt, 1); - if (r < 0) - return r; -@@ -443,8 +448,8 @@ static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq, - - if (nr_pics == 1) { - register_syscore_ops(&eiointc_syscore_ops); -- cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_LOONGARCH_STARTING, -- "irqchip/loongarch/intc:starting", -+ cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_EIOINTC_STARTING, -+ "irqchip/loongarch/eiointc:starting", - eiointc_router_init, NULL); - } - -diff --git a/drivers/irqchip/irq-loongson-htvec.c b/drivers/irqchip/irq-loongson-htvec.c -index 0bff728..5da02c7 100644 ---- a/drivers/irqchip/irq-loongson-htvec.c -+++ b/drivers/irqchip/irq-loongson-htvec.c -@@ -17,6 +17,8 @@ - #include <linux/of_irq.h> - #include <linux/syscore_ops.h> - -+#include "irq-loongson.h" -+ - /* Registers */ - #define HTVEC_EN_OFF 0x20 - #define HTVEC_MAX_PARENT_IRQ 8 -diff --git a/drivers/irqchip/irq-loongson-liointc.c b/drivers/irqchip/irq-loongson-liointc.c -index 7c4fe7a..2b1bd4a 100644 ---- a/drivers/irqchip/irq-loongson-liointc.c -+++ b/drivers/irqchip/irq-loongson-liointc.c -@@ -22,6 +22,8 @@ - #include <asm/loongson.h> - #endif - -+#include "irq-loongson.h" -+ - #define LIOINTC_CHIP_IRQ 32 - #define LIOINTC_NUM_PARENT 4 - #define LIOINTC_NUM_CORES 4 -diff --git a/drivers/irqchip/irq-loongson-pch-lpc.c b/drivers/irqchip/irq-loongson-pch-lpc.c -index 9b35492..2d4c3ec 100644 ---- a/drivers/irqchip/irq-loongson-pch-lpc.c -+++ b/drivers/irqchip/irq-loongson-pch-lpc.c -@@ -15,6 +15,8 @@ - #include <linux/kernel.h> - #include <linux/syscore_ops.h> - -+#include "irq-loongson.h" -+ - /* Registers */ - #define LPC_INT_CTL 0x00 - #define LPC_INT_ENA 0x04 -diff --git a/drivers/irqchip/irq-loongson-pch-msi.c b/drivers/irqchip/irq-loongson-pch-msi.c -index dd4d699..2c9f585 100644 ---- a/drivers/irqchip/irq-loongson-pch-msi.c -+++ b/drivers/irqchip/irq-loongson-pch-msi.c -@@ -15,6 +15,8 @@ - #include <linux/pci.h> - #include <linux/slab.h> - -+#include "irq-loongson.h" -+ - static int nr_pics; - - struct pch_msi_data { -@@ -266,17 +268,17 @@ IRQCHIP_DECLARE(pch_msi, "loongson,pch-msi-1.0", pch_msi_of_init); - #ifdef CONFIG_ACPI - struct fwnode_handle *get_pch_msi_handle(int pci_segment) - { -- int i; -+ if (cpu_has_avecint) -+ return pch_msi_handle[0]; - -- for (i = 0; i < MAX_IO_PICS; i++) { -+ for (int i = 0; i < MAX_IO_PICS; i++) { - if (msi_group[i].pci_segment == pci_segment) - return pch_msi_handle[i]; - } -- return NULL; -+ return pch_msi_handle[0]; - } - --int __init pch_msi_acpi_init(struct irq_domain *parent, -- struct acpi_madt_msi_pic *acpi_pchmsi) -+int __init pch_msi_acpi_init(struct irq_domain *parent, struct acpi_madt_msi_pic *acpi_pchmsi) - { - int ret; - struct fwnode_handle *domain_handle; -@@ -289,4 +291,36 @@ int __init pch_msi_acpi_init(struct irq_domain *parent, - - return ret; - } -+ -+static struct irq_chip pch_msi_irq_chip_avec = { -+ .name = "PCH PCI MSI", -+ .irq_ack = irq_chip_ack_parent, -+}; -+ -+static struct msi_domain_info pch_msi_domain_info_avec = { -+ .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | -+ MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX, -+ .chip = &pch_msi_irq_chip_avec, -+}; -+ -+int __init pch_msi_acpi_init_avec(struct irq_domain *parent) -+{ -+ struct irq_domain *msi_domain; -+ -+ if (pch_msi_handle[0]) -+ return 0; -+ -+ pch_msi_handle[0] = parent->fwnode; -+ irq_domain_update_bus_token(parent, DOMAIN_BUS_NEXUS); -+ -+ msi_domain = pci_msi_create_irq_domain(pch_msi_handle[0], -+ &pch_msi_domain_info_avec, parent); -+ if (!msi_domain) { -+ pr_err("Failed to create PCI MSI domain\n"); -+ kfree(pch_msi_handle[0]); -+ return -ENOMEM; -+ } -+ -+ return 0; -+} - #endif -diff --git a/drivers/irqchip/irq-loongson-pch-pic.c b/drivers/irqchip/irq-loongson-pch-pic.c -index 3b150b6..075d08a 100644 ---- a/drivers/irqchip/irq-loongson-pch-pic.c -+++ b/drivers/irqchip/irq-loongson-pch-pic.c -@@ -17,6 +17,8 @@ - #include <linux/of_irq.h> - #include <linux/syscore_ops.h> - -+#include "irq-loongson.h" -+ - /* Registers */ - #define PCH_PIC_MASK 0x20 - #define PCH_PIC_HTMSI_EN 0x40 -@@ -33,6 +35,7 @@ - #define PIC_COUNT (PIC_COUNT_PER_REG * PIC_REG_COUNT) - #define PIC_REG_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG) - #define PIC_REG_BIT(irq_id) ((irq_id) % PIC_COUNT_PER_REG) -+#define PIC_UNDEF_VECTOR 255 - #define PIC_COUNT_PER_REG64 64 - #define PIC_REG64_COUNT 1 - #define PIC_REG64_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG64) -@@ -50,6 +53,8 @@ struct pch_pic { - u32 saved_vec_en[PIC_REG_COUNT]; - u32 saved_vec_pol[PIC_REG_COUNT]; - u32 saved_vec_edge[PIC_REG_COUNT]; -+ u8 table[PIC_COUNT]; -+ int inuse; - }; - - static struct pch_pic *pch_pic_priv[MAX_IO_PICS]; -@@ -61,6 +66,11 @@ struct irq_domain *get_pchpic_irq_domain(void) - return pch_pic_priv[0]->pic_domain; - } - -+static inline u8 hwirq_to_bit(struct pch_pic *priv, int hirq) -+{ -+ return priv->table[hirq]; -+} -+ - static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit) - { - u32 reg; -@@ -89,45 +99,47 @@ static void pch_pic_mask_irq(struct irq_data *d) - { - struct pch_pic *priv = irq_data_get_irq_chip_data(d); - -- pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq); -+ pch_pic_bitset(priv, PCH_PIC_MASK, hwirq_to_bit(priv, d->hwirq)); - irq_chip_mask_parent(d); - } - - static void pch_pic_unmask_irq(struct irq_data *d) - { - struct pch_pic *priv = irq_data_get_irq_chip_data(d); -+ int bit = hwirq_to_bit(priv, d->hwirq); - - writeq(BIT(PIC_REG64_BIT(d->hwirq)), -- priv->base + PCH_PIC_CLR + PIC_REG64_IDX(d->hwirq) * 8); -+ priv->base + PCH_PIC_CLR + PIC_REG64_IDX(bit) * 8); - - irq_chip_unmask_parent(d); -- pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq); -+ pch_pic_bitclr(priv, PCH_PIC_MASK, bit); - } - - static int pch_pic_set_type(struct irq_data *d, unsigned int type) - { - struct pch_pic *priv = irq_data_get_irq_chip_data(d); -+ int bit = hwirq_to_bit(priv, d->hwirq); - int ret = 0; - - switch (type) { - case IRQ_TYPE_EDGE_RISING: -- pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq); -- pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq); -+ pch_pic_bitset(priv, PCH_PIC_EDGE, bit); -+ pch_pic_bitclr(priv, PCH_PIC_POL, bit); - irq_set_handler_locked(d, handle_edge_irq); - break; - case IRQ_TYPE_EDGE_FALLING: -- pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq); -- pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq); -+ pch_pic_bitset(priv, PCH_PIC_EDGE, bit); -+ pch_pic_bitset(priv, PCH_PIC_POL, bit); - irq_set_handler_locked(d, handle_edge_irq); - break; - case IRQ_TYPE_LEVEL_HIGH: -- pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq); -- pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq); -+ pch_pic_bitclr(priv, PCH_PIC_EDGE, bit); -+ pch_pic_bitclr(priv, PCH_PIC_POL, bit); - irq_set_handler_locked(d, handle_level_irq); - break; - case IRQ_TYPE_LEVEL_LOW: -- pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq); -- pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq); -+ pch_pic_bitclr(priv, PCH_PIC_EDGE, bit); -+ pch_pic_bitset(priv, PCH_PIC_POL, bit); - irq_set_handler_locked(d, handle_level_irq); - break; - default: -@@ -142,11 +154,12 @@ static void pch_pic_ack_irq(struct irq_data *d) - { - unsigned int reg; - struct pch_pic *priv = irq_data_get_irq_chip_data(d); -+ int bit = hwirq_to_bit(priv, d->hwirq); - -- reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq) * 4); -+ reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(bit) * 4); - if (reg & BIT(PIC_REG_BIT(d->hwirq))) { - writeq(BIT(PIC_REG64_BIT(d->hwirq)), -- priv->base + PCH_PIC_CLR + PIC_REG64_IDX(d->hwirq) * 8); -+ priv->base + PCH_PIC_CLR + PIC_REG64_IDX(bit) * 8); - } - irq_chip_ack_parent(d); - } -@@ -168,6 +181,8 @@ static int pch_pic_domain_translate(struct irq_domain *d, - { - struct pch_pic *priv = d->host_data; - struct device_node *of_node = to_of_node(fwspec->fwnode); -+ unsigned long flags; -+ int i; - - if (of_node) { - if (fwspec->param_count < 2) -@@ -180,12 +195,33 @@ static int pch_pic_domain_translate(struct irq_domain *d, - return -EINVAL; - - *hwirq = fwspec->param[0] - priv->gsi_base; -+ - if (fwspec->param_count > 1) - *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK; - else - *type = IRQ_TYPE_NONE; - } - -+ raw_spin_lock_irqsave(&priv->pic_lock, flags); -+ /* Check pic-table to confirm if the hwirq has been assigned */ -+ for (i = 0; i < priv->inuse; i++) { -+ if (priv->table[i] == *hwirq) { -+ *hwirq = i; -+ break; -+ } -+ } -+ if (i == priv->inuse) { -+ /* Assign a new hwirq in pic-table */ -+ if (priv->inuse >= PIC_COUNT) { -+ pr_err("pch-pic domain has no free vectors\n"); -+ raw_spin_unlock_irqrestore(&priv->pic_lock, flags); -+ return -EINVAL; -+ } -+ priv->table[priv->inuse] = *hwirq; -+ *hwirq = priv->inuse++; -+ } -+ raw_spin_unlock_irqrestore(&priv->pic_lock, flags); -+ - return 0; - } - -@@ -203,6 +239,9 @@ static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq, - if (err) - return err; - -+ /* Write vector ID */ -+ writeb(priv->ht_vec_base + hwirq, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, hwirq))); -+ - parent_fwspec.fwnode = domain->parent->fwnode; - parent_fwspec.param_count = 1; - parent_fwspec.param[0] = hwirq + priv->ht_vec_base; -@@ -231,7 +270,7 @@ static void pch_pic_reset(struct pch_pic *priv) - - for (i = 0; i < PIC_COUNT; i++) { - /* Write vector ID */ -- writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i)); -+ writeb(i, priv->base + PCH_INT_HTVEC(hwirq_to_bit(priv, i))); - /* Hardcode route to HT0 Lo */ - writeb(1, priv->base + PCH_INT_ROUTE(i)); - } -@@ -295,6 +334,7 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, - u32 gsi_base) - { - struct pch_pic *priv; -+ int i; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) -@@ -305,6 +345,10 @@ static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base, - if (!priv->base) - goto free_priv; - -+ priv->inuse = 0; -+ for (i = 0; i < PIC_COUNT; i++) -+ priv->table[i] = PIC_UNDEF_VECTOR; -+ - priv->ht_vec_base = vec_base; - priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1; - priv->gsi_base = gsi_base; -diff --git a/drivers/irqchip/irq-loongson.h b/drivers/irqchip/irq-loongson.h -new file mode 100644 -index 0000000..11fa138 ---- /dev/null -+++ b/drivers/irqchip/irq-loongson.h -@@ -0,0 +1,27 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) 2024 Loongson Technology Corporation Limited -+ */ -+ -+#ifndef _DRIVERS_IRQCHIP_IRQ_LOONGSON_H -+#define _DRIVERS_IRQCHIP_IRQ_LOONGSON_H -+ -+int find_pch_pic(u32 gsi); -+ -+int liointc_acpi_init(struct irq_domain *parent, -+ struct acpi_madt_lio_pic *acpi_liointc); -+int eiointc_acpi_init(struct irq_domain *parent, -+ struct acpi_madt_eio_pic *acpi_eiointc); -+int avecintc_acpi_init(struct irq_domain *parent); -+ -+int htvec_acpi_init(struct irq_domain *parent, -+ struct acpi_madt_ht_pic *acpi_htvec); -+int pch_lpc_acpi_init(struct irq_domain *parent, -+ struct acpi_madt_lpc_pic *acpi_pchlpc); -+int pch_pic_acpi_init(struct irq_domain *parent, -+ struct acpi_madt_bio_pic *acpi_pchpic); -+int pch_msi_acpi_init(struct irq_domain *parent, -+ struct acpi_madt_msi_pic *acpi_pchmsi); -+int pch_msi_acpi_init_avec(struct irq_domain *parent); -+ -+#endif /* _DRIVERS_IRQCHIP_IRQ_LOONGSON_H */ -diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c -index ed4fb64e..c31f510c 100644 ---- a/drivers/md/dm-crypt.c -+++ b/drivers/md/dm-crypt.c -@@ -2513,7 +2513,11 @@ static int set_key_encrypted(struct crypt_config *cc, struct key *key) - { - const struct encrypted_key_payload *ekp; - -+ #ifdef CONFIG_KEYP -+ ekp = ((union key_payload *)(key->name_link.next))->data[0]; -+ #else - ekp = key->payload.data[0]; -+ #endif - if (!ekp) - return -EKEYREVOKED; - -@@ -2529,7 +2533,11 @@ static int set_key_trusted(struct crypt_config *cc, struct key *key) - { - const struct trusted_key_payload *tkp; - -+ #ifdef CONFIG_KEYP -+ tkp = ((union key_payload *)(key->name_link.next))->data[0]; -+ #else - tkp = key->payload.data[0]; -+ #endif - if (!tkp) - return -EKEYREVOKED; - -@@ -2591,17 +2599,29 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string - return PTR_ERR(key); - } - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(key)); -+ #else - down_read(&key->sem); -+ #endif - - ret = set_key(cc, key); - if (ret < 0) { -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - kfree_sensitive(new_key_string); - return ret; - } - -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - - /* clear the flag since following operations may invalidate previously valid key */ -diff --git a/drivers/md/dm-verity-verify-sig.c b/drivers/md/dm-verity-verify-sig.c -index 4836508..d52d5bc 100644 ---- a/drivers/md/dm-verity-verify-sig.c -+++ b/drivers/md/dm-verity-verify-sig.c -@@ -40,7 +40,11 @@ static int verity_verify_get_sig_from_key(const char *key_desc, - if (IS_ERR(key)) - return PTR_ERR(key); - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(key)); -+ #else - down_read(&key->sem); -+ #endif - - ukp = user_key_payload_locked(key); - if (!ukp) { -@@ -58,7 +62,11 @@ static int verity_verify_get_sig_from_key(const char *key_desc, - memcpy(sig_opts->sig, ukp->data, sig_opts->sig_size); - - end: -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - - return ret; -diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index 774b382..4fe91e7 100644 ---- a/drivers/misc/Kconfig -+++ b/drivers/misc/Kconfig -@@ -104,14 +104,6 @@ config PHANTOM - If you choose to build module, its name will be phantom. If unsure, - say N here. - --config PHYTIUM_LPC_SNOOP -- tristate "Phytium HOST LPC snoop support" -- depends on ARCH_PHYTIUM && REGMAP && MFD_SYSCON -- help -- Provides a driver to control the LPC snoop interface which -- allows the BMC to listen on and save the data written by -- the host to an arbitrary LPC I/O port. -- - config TIFM_CORE - tristate "TI Flash Media interface support" - depends on PCI -diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index df2869b..25371ec 100644 ---- a/drivers/misc/Makefile -+++ b/drivers/misc/Makefile -@@ -15,7 +15,6 @@ obj-$(CONFIG_LKDTM) += lkdtm/ - obj-$(CONFIG_TIFM_CORE) += tifm_core.o - obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o - obj-$(CONFIG_PHANTOM) += phantom.o --obj-$(CONFIG_PHYTIUM_LPC_SNOOP) += phytium-lpc-snoop.o - obj-$(CONFIG_QCOM_COINCELL) += qcom-coincell.o - obj-$(CONFIG_QCOM_FASTRPC) += fastrpc.o - obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o -diff --git a/drivers/misc/phytium-lpc-snoop.c b/drivers/misc/phytium-lpc-snoop.c -deleted file mode 100644 -index d7caa93..0000000 ---- a/drivers/misc/phytium-lpc-snoop.c -+++ /dev/null -@@ -1,325 +0,0 @@ --// SPDX-License-Identifier: GPL-2.0 --/* -- * 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. -- * -- * Provides a simple driver to control the PHYTIUM LPC snoop interface which -- * allows the BMC to listen on and save the data written by -- * the host to an arbitrary LPC I/O port. -- * -- * Typically used by the BMC to "watch" host boot progress via port -- * 0x80 writes made by the BIOS during the boot process. -- * -- * Copyright (c) 2019-2023, Phytium Technology Co., Ltd. -- * -- */ -- --#include <linux/bitops.h> --#include <linux/interrupt.h> --#include <linux/fs.h> --#include <linux/kfifo.h> --#include <linux/mfd/syscon.h> --#include <linux/miscdevice.h> --#include <linux/module.h> --#include <linux/of.h> --#include <linux/of_device.h> --#include <linux/platform_device.h> --#include <linux/poll.h> --#include <linux/regmap.h> -- --#define DEVICE_NAME "phytium-lpc-snoop" -- --#define NUM_SNOOP_CHANNELS 2 --#define SNOOP_FIFO_SIZE 2048 -- --#define snp_enable_reg 0x150 --#define snp_enable_reg_snp1_en BIT(0) --#define snp_enable_reg_snp1_int_en BIT(1) --#define snp_enable_reg_snp2_en BIT(2) --#define snp_enable_reg_snp2_int_en BIT(3) -- --#define snp_status_reg 0x154 --#define snp_status_reg_snp1_int BIT(0) --#define snp_status_reg_snp2_int BIT(1) -- --#define snp_addr_reg 0x158 --#define snp_addr_reg_snp1_addr GENMASK(15, 0) --#define snp_addr_reg_snp1_shift 0 --#define snp_addr_reg_snp2_addr GENMASK(31, 16) --#define snp_addr_reg_snp2_shift 16 -- --#define snp_data_reg 0x15c --#define snp_data_reg_snp1_data_reg GENMASK(7, 0) --#define snp_data_reg_snp1_shift 0 --#define snp_data_reg_snp2_data_reg GENMASK(15, 8) --#define snp_data_reg_snp2_shift 8 -- --struct phytium_lpc_snoop_channel { -- struct kfifo fifo; -- wait_queue_head_t wq; -- struct miscdevice miscdev; --}; -- --struct phytium_lpc_snoop { -- struct regmap *regmap; -- int irq; -- struct phytium_lpc_snoop_channel chan[NUM_SNOOP_CHANNELS]; --}; -- --static struct phytium_lpc_snoop_channel *snoop_file_to_chan(struct file *file) --{ -- return container_of(file->private_data, -- struct phytium_lpc_snoop_channel, -- miscdev); --} -- --static ssize_t snoop_file_read(struct file *file, char __user *buffer, -- size_t count, loff_t *ppos) --{ -- struct phytium_lpc_snoop_channel *chan = snoop_file_to_chan(file); -- unsigned int copied; -- int ret = 0; -- -- if (kfifo_is_empty(&chan->fifo)) { -- if (file->f_flags & O_NONBLOCK) -- return -EAGAIN; -- ret = wait_event_interruptible(chan->wq, -- !kfifo_is_empty(&chan->fifo)); -- if (ret == -ERESTARTSYS) -- return -EINTR; -- } -- ret = kfifo_to_user(&chan->fifo, buffer, count, &copied); -- -- return ret ? ret : copied; --} -- --static unsigned int snoop_file_poll(struct file *file, -- struct poll_table_struct *pt) --{ -- struct phytium_lpc_snoop_channel *chan = snoop_file_to_chan(file); -- -- poll_wait(file, &chan->wq, pt); -- return !kfifo_is_empty(&chan->fifo) ? POLLIN : 0; --} -- --static const struct file_operations snoop_fops = { -- .owner = THIS_MODULE, -- .read = snoop_file_read, -- .poll = snoop_file_poll, -- .llseek = noop_llseek, --}; -- --/* Save a byte to a FIFO and discard the oldest byte if FIFO is full */ --static void put_fifo_with_discard(struct phytium_lpc_snoop_channel *chan, u8 val) --{ -- if (!kfifo_initialized(&chan->fifo)) -- return; -- if (kfifo_is_full(&chan->fifo)) -- kfifo_skip(&chan->fifo); -- kfifo_put(&chan->fifo, val); -- wake_up_interruptible(&chan->wq); --} -- --static irqreturn_t phytium_lpc_snoop_irq(int irq, void *arg) --{ -- struct phytium_lpc_snoop *lpc_snoop = arg; -- u32 reg, data; -- -- if (regmap_read(lpc_snoop->regmap, snp_status_reg, ®)) -- return IRQ_NONE; -- -- /* Check if one of the snoop channels is interrupting */ -- reg &= (snp_status_reg_snp1_int | snp_status_reg_snp2_int); -- if (!reg) -- return IRQ_NONE; -- -- /* Ack pending IRQs */ -- regmap_write(lpc_snoop->regmap, snp_status_reg, reg); -- -- /* Read and save most recent snoop'ed data byte to FIFO */ -- regmap_read(lpc_snoop->regmap, snp_data_reg, &data); -- -- if (reg & snp_status_reg_snp1_int) { -- u8 val = (data & snp_data_reg_snp1_data_reg) >> snp_data_reg_snp1_shift; -- -- put_fifo_with_discard(&lpc_snoop->chan[0], val); -- } -- if (reg & snp_status_reg_snp2_int) { -- u8 val = (data & snp_data_reg_snp2_data_reg) >> snp_data_reg_snp2_shift; -- -- put_fifo_with_discard(&lpc_snoop->chan[1], val); -- } -- -- return IRQ_HANDLED; --} -- --static int phytium_lpc_snoop_config_irq(struct phytium_lpc_snoop *lpc_snoop, -- struct platform_device *pdev) --{ -- struct device *dev = &pdev->dev; -- int rc; -- -- lpc_snoop->irq = platform_get_irq(pdev, 0); -- if (!lpc_snoop->irq) -- return -ENODEV; -- -- rc = devm_request_irq(dev, lpc_snoop->irq, -- phytium_lpc_snoop_irq, IRQF_SHARED, -- DEVICE_NAME, lpc_snoop); -- if (rc < 0) { -- dev_warn(dev, "Unable to request IRQ %d\n", lpc_snoop->irq); -- lpc_snoop->irq = 0; -- return rc; -- } -- -- return 0; --} -- --static int phytium_lpc_enable_snoop(struct phytium_lpc_snoop *lpc_snoop, -- struct device *dev, -- int channel, u16 lpc_port) --{ -- int rc = 0; -- u32 snp_enable_reg_en, snp_addr_reg_mask, snp_addr_reg_shift; -- -- init_waitqueue_head(&lpc_snoop->chan[channel].wq); -- /* Create FIFO datastructure */ -- rc = kfifo_alloc(&lpc_snoop->chan[channel].fifo, -- SNOOP_FIFO_SIZE, GFP_KERNEL); -- if (rc) -- return rc; -- -- lpc_snoop->chan[channel].miscdev.minor = MISC_DYNAMIC_MINOR; -- lpc_snoop->chan[channel].miscdev.name = -- devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, channel); -- lpc_snoop->chan[channel].miscdev.fops = &snoop_fops; -- lpc_snoop->chan[channel].miscdev.parent = dev; -- rc = misc_register(&lpc_snoop->chan[channel].miscdev); -- if (rc) -- return rc; -- -- /* Enable LPC snoop channel at requested port */ -- switch (channel) { -- case 0: -- snp_enable_reg_en = snp_enable_reg_snp1_en | snp_enable_reg_snp1_int_en; -- snp_addr_reg_mask = snp_addr_reg_snp1_addr; -- snp_addr_reg_shift = snp_addr_reg_snp1_shift; -- break; -- case 1: -- snp_enable_reg_en = snp_enable_reg_snp2_en | snp_enable_reg_snp2_int_en; -- snp_addr_reg_mask = snp_addr_reg_snp2_addr; -- snp_addr_reg_shift = snp_addr_reg_snp2_shift; -- break; -- default: -- return -EINVAL; -- } -- -- regmap_update_bits(lpc_snoop->regmap, snp_enable_reg, snp_enable_reg_en, snp_enable_reg_en); -- regmap_update_bits(lpc_snoop->regmap, snp_addr_reg, snp_addr_reg_mask, -- lpc_port << snp_addr_reg_shift); -- return rc; --} -- --static void phytium_lpc_disable_snoop(struct phytium_lpc_snoop *lpc_snoop, -- int channel) --{ -- switch (channel) { -- case 0: -- regmap_update_bits(lpc_snoop->regmap, snp_enable_reg, -- snp_enable_reg_snp1_en | snp_enable_reg_snp1_int_en, -- 0); -- break; -- case 1: -- regmap_update_bits(lpc_snoop->regmap, snp_enable_reg, -- snp_enable_reg_snp2_en | snp_enable_reg_snp2_int_en, -- 0); -- break; -- default: -- return; -- } -- -- kfifo_free(&lpc_snoop->chan[channel].fifo); -- misc_deregister(&lpc_snoop->chan[channel].miscdev); --} -- --static int phytium_lpc_snoop_probe(struct platform_device *pdev) --{ -- struct phytium_lpc_snoop *lpc_snoop; -- struct device *dev; -- u32 port; -- int rc; -- -- dev = &pdev->dev; -- -- lpc_snoop = devm_kzalloc(dev, sizeof(*lpc_snoop), GFP_KERNEL); -- if (!lpc_snoop) -- return -ENOMEM; -- -- lpc_snoop->regmap = syscon_node_to_regmap( -- pdev->dev.parent->of_node); -- if (IS_ERR(lpc_snoop->regmap)) { -- dev_err(dev, "Couldn't get regmap\n"); -- return -ENODEV; -- } -- -- dev_set_drvdata(&pdev->dev, lpc_snoop); -- -- rc = of_property_read_u32_index(dev->of_node, "snoop-ports", 0, &port); -- if (rc) { -- dev_err(dev, "no snoop ports configured\n"); -- return -ENODEV; -- } -- -- rc = phytium_lpc_snoop_config_irq(lpc_snoop, pdev); -- if (rc) -- return rc; -- -- rc = phytium_lpc_enable_snoop(lpc_snoop, dev, 0, port); -- if (rc) -- return rc; -- -- /* Configuration of 2nd snoop channel port is optional */ -- if (of_property_read_u32_index(dev->of_node, "snoop-ports", -- 1, &port) == 0) { -- rc = phytium_lpc_enable_snoop(lpc_snoop, dev, 1, port); -- if (rc) -- phytium_lpc_disable_snoop(lpc_snoop, 0); -- } -- -- return rc; --} -- --static int phytium_lpc_snoop_remove(struct platform_device *pdev) --{ -- struct phytium_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev); -- -- /* Disable both snoop channels */ -- phytium_lpc_disable_snoop(lpc_snoop, 0); -- phytium_lpc_disable_snoop(lpc_snoop, 1); -- -- return 0; --} -- -- --static const struct of_device_id phytium_lpc_snoop_match[] = { -- { .compatible = "phytium,lpc-snoop"}, -- { }, --}; -- --static struct platform_driver phytium_lpc_snoop_driver = { -- .driver = { -- .name = DEVICE_NAME, -- .of_match_table = phytium_lpc_snoop_match, -- }, -- .probe = phytium_lpc_snoop_probe, -- .remove = phytium_lpc_snoop_remove, --}; -- --module_platform_driver(phytium_lpc_snoop_driver); -- --MODULE_DEVICE_TABLE(of, phytium_lpc_snoop_match); --MODULE_LICENSE("GPL"); --MODULE_AUTHOR("Lan Hengyu lanhengyu1395@phytium.com.cn"); --MODULE_DESCRIPTION("Driver to control Phytium LPC snoop functionality"); -diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig -index bc7e2ad..a33cddf 100644 ---- a/drivers/mmc/host/Kconfig -+++ b/drivers/mmc/host/Kconfig -@@ -1071,3 +1071,38 @@ config MMC_LITEX - module will be called litex_mmc. - - If unsure, say N. -+ -+config MMC_PHYTIUM_SDCI -+ tristate "Phytium SD Host Controller support" -+ depends on ARM64 -+ help -+ This selects support for the Phytium SD Host Controller on Phytium -+ Px210 chipset. -+ -+ If you have a controller with this interface, say Y or M here. -+ -+ If unsure, say N. -+ -+config MMC_PHYTIUM_MCI_PCI -+ tristate "Phytium PCI MultiMedia Card Interface support" -+ depends on ARCH_PHYTIUM -+ default y if ARCH_PHYTIUM -+ help -+ This selects support for the PCI MultiMedia Card Interface on Phytium -+ Px210 chipset. -+ -+ If you have a controller with this interface, say Y or M here. -+ -+ If unsure, say N. -+ -+config MMC_PHYTIUM_MCI_PLTFM -+ tristate "Phytium MultiMedia Card Interface support" -+ depends on ARCH_PHYTIUM && OF -+ default y if ARCH_PHYTIUM -+ help -+ This selects support for the MultiMedia Card Interface on Phytium -+ Px210 chipset. -+ -+ If you have a controller with this interface, say Y or M here. -+ -+ If unsure, say N. -diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile -index a693fa3..87bfbbe 100644 ---- a/drivers/mmc/host/Makefile -+++ b/drivers/mmc/host/Makefile -@@ -70,6 +70,9 @@ obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o - obj-$(CONFIG_MMC_TOSHIBA_PCI) += toshsd.o - obj-$(CONFIG_MMC_BCM2835) += bcm2835.o - obj-$(CONFIG_MMC_OWL) += owl-mmc.o -+obj-$(CONFIG_MMC_PHYTIUM_SDCI) += phytium-sdci.o -+obj-$(CONFIG_MMC_PHYTIUM_MCI_PCI) += phytium-mci-pci.o phytium-mci.o -+obj-$(CONFIG_MMC_PHYTIUM_MCI_PLTFM) += phytium-mci-plat.o phytium-mci.o - - obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o - obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o -diff --git a/drivers/mmc/host/phytium-mci-pci.c b/drivers/mmc/host/phytium-mci-pci.c -new file mode 100644 -index 0000000..16c32d3 ---- /dev/null -+++ b/drivers/mmc/host/phytium-mci-pci.c -@@ -0,0 +1,175 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Phytium Multimedia Card Interface PCI driver -+ * -+ * Copyright (C) 2020-2023, Phytium Technology Co., Ltd. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/irq.h> -+#include <linux/pm.h> -+#include <linux/pm_runtime.h> -+#include <linux/interrupt.h> -+#include <linux/pci.h> -+#include "phytium-mci.h" -+ -+static u32 sd_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY | -+ MMC_CAP_CMD23 | MMC_CAP_4_BIT_DATA; -+static u32 sd_caps2 = MMC_CAP2_NO_MMC; -+ -+static u32 emmc_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA | MMC_CAP_WAIT_WHILE_BUSY | -+ MMC_CAP_CMD23 | MMC_CAP_HW_RESET | MMC_CAP_MMC_HIGHSPEED | -+ MMC_CAP_NONREMOVABLE; -+static u32 emmc_caps2 = MMC_CAP2_NO_SDIO | MMC_CAP2_NO_SD; -+ -+#define PCI_BAR_NO 0 -+ -+#if defined CONFIG_PM && defined CONFIG_PM_SLEEP -+static const struct dev_pm_ops phytium_mci_dev_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(phytium_mci_suspend, -+ phytium_mci_resume) -+ SET_RUNTIME_PM_OPS(phytium_mci_runtime_suspend, -+ phytium_mci_runtime_resume, NULL) -+}; -+#else -+#define phytium_mci_dev_pm_ops NULL -+#endif -+ -+static int -+phytium_mci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) -+{ -+ struct phytium_mci_host *host; -+ struct mmc_host *mmc; -+ int ret; -+ -+ ret = pcim_enable_device(pdev); -+ -+ if (ret) -+ return ret; -+ pci_set_master(pdev); -+ -+ mmc = mmc_alloc_host(sizeof(struct phytium_mci_host), &pdev->dev); -+ -+ if (!mmc) -+ return -ENOMEM; -+ -+ host = mmc_priv(mmc); -+ -+ pci_enable_msi(pdev); -+ -+ host->irq = pdev->irq; -+ host->irq_flags = IRQF_SHARED; -+ host->dev = &pdev->dev; -+ ret = pcim_iomap_regions(pdev, 1 << PCI_BAR_NO, pci_name(pdev)); -+ -+ if (ret) { -+ dev_err(&pdev->dev, "I/O memory remapping failed\n"); -+ goto host_free; -+ } -+ -+ host->base = pcim_iomap_table(pdev)[PCI_BAR_NO]; -+ host->is_use_dma = 1; -+ host->is_device_x100 = 1; -+ -+ if (pdev->devfn == 2) { -+ host->caps = emmc_caps; -+ host->caps2 = emmc_caps2; -+ } else { -+ host->caps = sd_caps; -+ host->caps2 = sd_caps2; -+ mmc->f_max = 25000000; /* stable frequency */ -+ } -+ -+ host->mmc = mmc; -+ host->clk_rate = MCI_CLK; -+ -+ dev_info(&pdev->dev, "%s %d: [bar %d] addr: 0x%llx size: 0x%llx km: 0x%llx devfn:%d\n", -+ __func__, __LINE__, PCI_BAR_NO, pci_resource_start(pdev, 0), -+ pci_resource_len(pdev, 0), (uint64_t)host->base, pdev->devfn); -+ -+ dev_dbg(&pdev->dev, "%s %d:irq:0x%x\n", __func__, __LINE__, host->irq); -+ -+ ret = phytium_mci_common_probe(host); -+ -+ if (ret == MCI_REALEASE_MEM) { -+ ret = -ENOMEM; -+ goto release_mem; -+ } else if (ret) { -+ goto release; -+ } -+ pci_set_drvdata(pdev, mmc); -+ dev_info(&pdev->dev, "%s %d: probe phytium mci successful.\n", __func__, __LINE__); -+ return 0; -+ -+release: -+ phytium_mci_deinit_hw(host); -+release_mem: -+ -+ if (host->dma.adma_table) { -+ dma_free_coherent(&pdev->dev, -+ MAX_BD_NUM * sizeof(struct phytium_adma2_64_desc), -+ host->dma.adma_table, host->dma.adma_addr); -+ } -+host_free: -+ mmc_free_host(mmc); -+ pci_disable_device(pdev); -+ return ret; -+} -+ -+static void phytium_mci_pci_remove(struct pci_dev *pdev) -+{ -+ struct phytium_mci_host *host; -+ struct mmc_host *mmc; -+ -+ mmc = pci_get_drvdata(pdev); -+ if (!mmc) { -+ dev_info(&pdev->dev, "%s %d: mmc is null.\n", __func__, __LINE__); -+ return; -+ } -+ host = mmc_priv(mmc); -+ if (!host) { -+ dev_info(&pdev->dev, "%s %d: host is null.\n", __func__, __LINE__); -+ mmc_remove_host(mmc); -+ mmc_free_host(mmc); -+ return; -+ } -+ -+ del_timer(&host->hotplug_timer); -+ -+ mmc_remove_host(host->mmc); -+ -+ if (host->dma.adma_table) { -+ dma_free_coherent(&pdev->dev, -+ MAX_BD_NUM * sizeof(struct phytium_adma2_64_desc), -+ host->dma.adma_table, host->dma.adma_addr); -+ } -+ phytium_mci_deinit_hw(host); -+ mmc_free_host(mmc); -+ pci_set_drvdata(pdev, NULL); -+} -+ -+static const struct pci_device_id phytium_mci_pci_tbl[] = { -+ { -+ PCI_DEVICE(PCI_VENDOR_ID_PHYTIUM, 0xdc28), -+ .class = 0x5, -+ .class_mask = 0, -+ }, -+ {} -+}; -+MODULE_DEVICE_TABLE(pci, phytium_mci_pci_tbl); -+ -+static struct pci_driver phytium_mci_pci_driver = { -+ .name = "phytium-mci-pci", -+ .id_table = phytium_mci_pci_tbl, -+ .probe = phytium_mci_pci_probe, -+ .remove = phytium_mci_pci_remove, -+ .driver = { -+ .pm = &phytium_mci_dev_pm_ops, -+ } -+}; -+module_pci_driver(phytium_mci_pci_driver); -+ -+MODULE_DESCRIPTION("Phytium Multimedia Card Interface PCI driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Cheng Quan <chengquan@phytium.com.cn>"); -diff --git a/drivers/mmc/host/phytium-mci-plat.c b/drivers/mmc/host/phytium-mci-plat.c -new file mode 100644 -index 0000000..a774f09 ---- /dev/null -+++ b/drivers/mmc/host/phytium-mci-plat.c -@@ -0,0 +1,194 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Phytium Multimedia Card Interface PCI driver -+ * -+ * Copyright (C) 2021-2023, Phytium Technology Co., Ltd. -+ */ -+ -+#include <linux/module.h> -+#include <linux/clk.h> -+#include <linux/platform_device.h> -+#include <linux/pm.h> -+#include <linux/pm_runtime.h> -+#include <linux/acpi.h> -+#include <linux/dma-mapping.h> -+#include "phytium-mci.h" -+ -+static u32 mci_caps = MMC_CAP_CMD23 | MMC_CAP_WAIT_WHILE_BUSY; -+ -+#if defined CONFIG_PM && defined CONFIG_PM_SLEEP -+ -+static const struct dev_pm_ops phytium_mci_dev_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(phytium_mci_suspend, -+ phytium_mci_resume) -+ SET_RUNTIME_PM_OPS(phytium_mci_runtime_suspend, -+ phytium_mci_runtime_resume, NULL) -+}; -+#else -+#define phytium_mci_dev_pm_ops NULL -+#endif -+ -+static int phytium_mci_probe(struct platform_device *pdev) -+{ -+ struct mmc_host *mmc; -+ struct phytium_mci_host *host; -+ struct resource *res; -+ const struct acpi_device_id *match; -+ struct device *dev = &pdev->dev; -+ int ret; -+ -+ mmc = mmc_alloc_host(sizeof(struct phytium_mci_host), &pdev->dev); -+ if (!mmc) -+ return -ENOMEM; -+ host = mmc_priv(mmc); -+ ret = mmc_of_parse(mmc); -+ if (ret) -+ goto host_free; -+ -+ if (device_property_read_bool(dev, "use-hold")) -+ host->use_hold = 1; -+ -+ if (device_property_read_bool(dev, "clk-set")) -+ host->clk_set = 1; -+ -+ if (host->clk_set) { -+ host->clk_smpl_drv_25m = -1; -+ host->clk_smpl_drv_50m = -1; -+ host->clk_smpl_drv_66m = -1; -+ host->clk_smpl_drv_100m = -1; -+ device_property_read_u32(dev, "clk-smpl-drv-25m", &host->clk_smpl_drv_25m); -+ device_property_read_u32(dev, "clk-smpl-drv-50m", &host->clk_smpl_drv_50m); -+ device_property_read_u32(dev, "clk-smpl-drv-66m", &host->clk_smpl_drv_66m); -+ device_property_read_u32(dev, "clk-smpl-drv-100m", &host->clk_smpl_drv_100m); -+ } -+ dev_info(dev, "mci clk set %d %d 0x%x 0x%x 0x%x 0x%x\n", -+ host->use_hold, host->clk_set, host->clk_smpl_drv_25m, -+ host->clk_smpl_drv_50m, host->clk_smpl_drv_66m, host->clk_smpl_drv_100m); -+ -+ if (dev->of_node) { -+ host->src_clk = devm_clk_get(&pdev->dev, "phytium_mci_clk"); -+ if (IS_ERR(host->src_clk)) { -+ ret = PTR_ERR(host->src_clk); -+ goto host_free; -+ } -+ -+ host->clk_rate = clk_get_rate(host->src_clk); -+ } else if (has_acpi_companion(dev)) { -+ match = acpi_match_device(dev->driver->acpi_match_table, dev); -+ if (!match) { -+ dev_err(dev, "Error ACPI match data is missing\n"); -+ return -ENODEV; -+ } -+ host->clk_rate = 1200000000; -+ } -+ -+ host->is_use_dma = 1; -+ host->is_device_x100 = 0; -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ host->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(host->base)) { -+ ret = PTR_ERR(host->base); -+ goto host_free; -+ } -+ -+ host->irq = platform_get_irq(pdev, 0); -+ -+ if (host->irq < 0) { -+ ret = -EINVAL; -+ goto host_free; -+ } -+ host->irq_flags = IRQF_SHARED; -+ dev_dbg(&pdev->dev, "%s %d:irq:%d\n", __func__, __LINE__, host->irq); -+ host->dev = &pdev->dev; -+ host->caps = mci_caps; -+ host->mmc = mmc; -+ ret = phytium_mci_common_probe(host); -+ if (ret == MCI_REALEASE_MEM) { -+ ret = -ENOMEM; -+ goto release_mem; -+ } else if (ret) { -+ goto release; -+ } -+ platform_set_drvdata(pdev, mmc); -+ dev_info(&pdev->dev, "%s %d: probe phytium mci successful.\n", __func__, __LINE__); -+ return 0; -+ -+release: -+ phytium_mci_deinit_hw(host); -+release_mem: -+ if (host->dma.adma_table) { -+ dma_free_coherent(&pdev->dev, -+ MAX_BD_NUM * sizeof(struct phytium_adma2_64_desc), -+ host->dma.adma_table, host->dma.adma_addr); -+ } -+host_free: -+ mmc_free_host(mmc); -+ return ret; -+} -+ -+static int phytium_mci_remove(struct platform_device *pdev) -+{ -+ struct mmc_host *mmc; -+ struct phytium_mci_host *host; -+ -+ mmc = platform_get_drvdata(pdev); -+ if (!mmc) { -+ dev_info(&pdev->dev, "%s %d: mmc is null.\n", __func__, __LINE__); -+ return -1; -+ } -+ host = mmc_priv(mmc); -+ if (!host) { -+ dev_info(&pdev->dev, "%s %d: host is null.\n", __func__, __LINE__); -+ mmc_remove_host(mmc); -+ mmc_free_host(mmc); -+ return -1; -+ } -+ del_timer(&host->hotplug_timer); -+ mmc_remove_host(host->mmc); -+ -+ if (host->dma.adma_table) { -+ dma_free_coherent(&pdev->dev, -+ MAX_BD_NUM * sizeof(struct phytium_adma2_64_desc), -+ host->dma.adma_table, host->dma.adma_addr); -+ } -+ phytium_mci_deinit_hw(host); -+ mmc_free_host(mmc); -+ platform_set_drvdata(pdev, NULL); -+ return 0; -+} -+ -+static const struct of_device_id phytium_mci_of_ids[] = { -+ { .compatible = "phytium,mci", }, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(of, phytium_mci_of_ids); -+ -+#ifdef CONFIG_ACPI -+static const struct acpi_device_id phytium_mci_acpi_ids[] = { -+ { .id = "PHYT0017" }, -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(acpi, phytium_mci_acpi_ids); -+#else -+#define phytium_mci_acpi_ids NULL -+#endif -+ -+static struct platform_driver phytium_mci_driver = { -+ .probe = phytium_mci_probe, -+ .remove = phytium_mci_remove, -+ .driver = { -+ .name = "phytium-mci-platform", -+ .of_match_table = phytium_mci_of_ids, -+ .acpi_match_table = phytium_mci_acpi_ids, -+ .pm = &phytium_mci_dev_pm_ops, -+ }, -+}; -+ -+module_platform_driver(phytium_mci_driver); -+ -+MODULE_DESCRIPTION("Phytium Multimedia Card Interface driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Cheng Quan <chengquan@phytium.com.cn>"); -diff --git a/drivers/mmc/host/phytium-mci.c b/drivers/mmc/host/phytium-mci.c -new file mode 100644 -index 0000000..852f1f0 ---- /dev/null -+++ b/drivers/mmc/host/phytium-mci.c -@@ -0,0 +1,1530 @@ -+// SPDX-License-Identifier: GPL-2.0+ -+/* -+ * Driver for Phytium Multimedia Card Interface -+ * -+ * Copyright (C) 2021-2023, Phytium Technology Co., Ltd. -+ */ -+ -+#include <linux/moduleparam.h> -+#include <linux/module.h> -+#include <linux/clk.h> -+#include <linux/delay.h> -+#include <linux/dma-mapping.h> -+#include <linux/ioport.h> -+#include <linux/irq.h> -+#include <linux/of_address.h> -+#include <linux/of_device.h> -+#include <linux/of_irq.h> -+#include <linux/of_gpio.h> -+#include <linux/pinctrl/consumer.h> -+#include <linux/platform_device.h> -+#include <linux/pm.h> -+#include <linux/pm_runtime.h> -+#include <linux/regulator/consumer.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+#include <linux/interrupt.h> -+#include <linux/acpi.h> -+#include <linux/timer.h> -+#include <linux/swab.h> -+#include <linux/pci.h> -+#include <linux/mmc/card.h> -+#include <linux/mmc/core.h> -+#include <linux/mmc/host.h> -+#include <linux/mmc/mmc.h> -+#include <linux/mmc/sd.h> -+#include <linux/mmc/sdio.h> -+#include <linux/delay.h> -+#include "phytium-mci.h" -+ -+static const u32 cmd_ints_mask = MCI_INT_MASK_RE | MCI_INT_MASK_CMD | MCI_INT_MASK_RCRC | -+ MCI_INT_MASK_RTO | MCI_INT_MASK_HTO | MCI_RAW_INTS_HLE; -+ -+static const u32 data_ints_mask = MCI_INT_MASK_DTO | MCI_INT_MASK_DCRC | MCI_INT_MASK_DRTO | -+ MCI_INT_MASK_SBE_BCI; -+static const u32 cmd_err_ints_mask = MCI_INT_MASK_RTO | MCI_INT_MASK_RCRC | MCI_INT_MASK_RE | -+ MCI_INT_MASK_DCRC | MCI_INT_MASK_DRTO | -+ MCI_MASKED_INTS_SBE_BCI; -+ -+static const u32 dmac_ints_mask = MCI_DMAC_INT_ENA_FBE | MCI_DMAC_INT_ENA_DU | -+ MCI_DMAC_INT_ENA_NIS | MCI_DMAC_INT_ENA_AIS; -+static const u32 dmac_err_ints_mask = MCI_DMAC_INT_ENA_FBE | MCI_DMAC_INT_ENA_DU | -+ MCI_DMAC_INT_ENA_AIS; -+ -+static void phytium_mci_cmd_next(struct phytium_mci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_command *cmd); -+static void phytium_mci_adma_reset(struct phytium_mci_host *host); -+static void phytium_mci_send_cmd(struct phytium_mci_host *host, u32 cmd, u32 arg); -+static bool phytium_mci_data_xfer_done(struct phytium_mci_host *host, u32 events, -+ struct mmc_request *mrq, struct mmc_data *data); -+static void phytium_mci_init_adma_table(struct phytium_mci_host *host, -+ struct phytium_mci_dma *dma); -+static void phytium_mci_init_hw(struct phytium_mci_host *host); -+static int phytium_mci_get_cd(struct mmc_host *mmc); -+static int phytium_mci_err_irq(struct phytium_mci_host *host, u32 dmac_events, u32 events); -+ -+static void sdr_set_bits(void __iomem *reg, u32 bs) -+{ -+ u32 val = readl(reg); -+ -+ val |= bs; -+ writel(val, reg); -+} -+ -+static void sdr_clr_bits(void __iomem *reg, u32 bs) -+{ -+ u32 val = readl(reg); -+ -+ val &= ~bs; -+ writel(val, reg); -+} -+ -+static void phytium_mci_reset_hw(struct phytium_mci_host *host) -+{ -+ sdr_set_bits(host->base + MCI_CNTRL, MCI_CNTRL_FIFO_RESET | MCI_CNTRL_DMA_RESET); -+ -+ while (readl(host->base + MCI_CNTRL) & (MCI_CNTRL_FIFO_RESET | MCI_CNTRL_DMA_RESET)) -+ cpu_relax(); -+ phytium_mci_send_cmd(host, MCI_CMD_UPD_CLK, 0); -+} -+ -+static void phytium_mci_update_external_clk(struct phytium_mci_host *host, u32 uhs_reg_value) -+{ -+ writel(0, host->base + MCI_UHS_REG_EXT); -+ writel(uhs_reg_value, host->base + MCI_UHS_REG_EXT); -+ while (!(readl(host->base + MCI_CCLK_RDY) & 0x1)) -+ cpu_relax(); -+ -+} -+ -+static void phytium_mci_prepare_data(struct phytium_mci_host *host, -+ struct mmc_request *mrq) -+{ -+ struct mmc_data *data = mrq->data; -+ -+ if (!(data->host_cookie & MCI_PREPARE_FLAG)) { -+ data->host_cookie |= MCI_PREPARE_FLAG; -+ data->sg_count = dma_map_sg(host->dev, data->sg, data->sg_len, -+ mmc_get_dma_dir(data)); -+ } -+} -+ -+static void phytium_mci_unprepare_data(struct phytium_mci_host *host, -+ struct mmc_request *mrq) -+{ -+ struct mmc_data *data = mrq->data; -+ -+ if (data->host_cookie & MCI_ASYNC_FLAG) -+ return; -+ -+ if (data->host_cookie & MCI_PREPARE_FLAG) { -+ dma_unmap_sg(host->dev, data->sg, data->sg_len, mmc_get_dma_dir(data)); -+ data->host_cookie &= ~MCI_PREPARE_FLAG; -+ } -+} -+ -+static void phytium_mci_send_cmd(struct phytium_mci_host *host, u32 cmd, u32 arg) -+{ -+ int rc; -+ u32 data; -+ -+ writel(arg, host->base + MCI_CMDARG); -+ wmb(); /* drain writebuffer */ -+ -+ rc = readl_relaxed_poll_timeout(host->base + MCI_STATUS, -+ data, -+ !(data & MCI_STATUS_CARD_BUSY), -+ 0, 5000 * 1000); -+ if (rc == -ETIMEDOUT) -+ pr_debug("%s %d, timeout mci_status: 0x%08x\n", __func__, __LINE__, data); -+ -+ writel(MCI_CMD_START | cmd, host->base + MCI_CMD); -+ -+ rc = readl_relaxed_poll_timeout(host->base + MCI_CMD, -+ data, -+ !(data & MCI_CMD_START), -+ 0, 5000 * 1000); -+ if (rc == -ETIMEDOUT) -+ pr_debug("%s %d, timeout mci_cmd: 0x%08x\n", __func__, __LINE__, data); -+} -+ -+static void phytium_mci_update_cmd11(struct phytium_mci_host *host, u32 cmd) -+{ -+ writel(MCI_CMD_START | cmd, host->base + MCI_CMD); -+ -+ while (readl(host->base + MCI_CMD) & MCI_CMD_START) -+ cpu_relax(); -+} -+ -+static void phytium_mci_set_clk(struct phytium_mci_host *host, struct mmc_ios *ios) -+{ -+ u32 div = 0xff, drv = 0, sample = 0; -+ unsigned long clk_rate; -+ u32 mci_cmd_bits = MCI_CMD_UPD_CLK; -+ u32 cmd_reg; -+ u32 cur_cmd_index; -+ u32 first_uhs_div, tmp_ext_reg; -+ -+ cmd_reg = readl(host->base + MCI_CMD); -+ cur_cmd_index = cmd_reg & 0x3F; -+ -+ if (cur_cmd_index == SD_SWITCH_VOLTAGE) -+ mci_cmd_bits |= MCI_CMD_VOLT_SWITCH; -+ if (ios->clock) { -+ if (host->current_ios_clk == ios->clock) -+ return; -+ -+ dev_dbg(host->dev, "will change clock, host->clk_rate: %ld, ios->clock: %d\n", -+ host->clk_rate, ios->clock); -+ -+ if (ios->clock >= 25000000) -+ tmp_ext_reg = 0x202; -+ else if (ios->clock == 400000) -+ tmp_ext_reg = 0x502; -+ else -+ tmp_ext_reg = 0x302; -+ -+ phytium_mci_update_external_clk(host, tmp_ext_reg); -+ sdr_clr_bits(host->base + MCI_CLKENA, MCI_CLKENA_CCLK_ENABLE); -+ -+ if (cur_cmd_index == SD_SWITCH_VOLTAGE) -+ phytium_mci_update_cmd11(host, mci_cmd_bits | cmd_reg); -+ else -+ phytium_mci_send_cmd(host, mci_cmd_bits, 0); -+ -+ clk_rate = host->clk_rate; -+ first_uhs_div = 1 + ((tmp_ext_reg >> 8)&0xFF); -+ div = clk_rate / (2 * first_uhs_div * ios->clock); -+ -+ if (host->clk_smpl_drv_25m >= 0 -+ && ios->clock == 25000000 && host->clk_set) { -+ writel((host->clk_smpl_drv_25m << 8) | (div & 0xff), -+ host->base + MCI_CLKDIV); -+ } else if (host->clk_smpl_drv_50m >= 0 -+ && ios->clock == 50000000 && host->clk_set){ -+ writel((host->clk_smpl_drv_50m << 8) | (div & 0xff), -+ host->base + MCI_CLKDIV); -+ } else if (host->clk_smpl_drv_66m >= 0 -+ && ios->clock == 66000000 && host->clk_set){ -+ writel((host->clk_smpl_drv_66m << 8) | (div & 0xff), -+ host->base + MCI_CLKDIV); -+ } else if (host->clk_smpl_drv_100m >= 0 -+ && ios->clock == 100000000 && host->clk_set){ -+ writel((host->clk_smpl_drv_100m << 8) | (div & 0xff), -+ host->base + MCI_CLKDIV); -+ } else { -+ if (div > 2) { -+ sample = div / 2 + 1; -+ drv = sample - 1; -+ writel((sample << 16) | (drv << 8) | (div & 0xff), -+ host->base + MCI_CLKDIV); -+ } else if (div == 2) { -+ drv = 0; -+ sample = 1; -+ writel((drv << 8) | (sample << 16) | (div & 0xff), -+ host->base + MCI_CLKDIV); -+ } -+ } -+ -+ dev_dbg(host->dev, "UHS_REG_EXT ext: %x, CLKDIV: %x\n", -+ readl(host->base + MCI_UHS_REG_EXT), readl(host->base + MCI_CLKDIV)); -+ -+ sdr_set_bits(host->base + MCI_CLKENA, MCI_CLKENA_CCLK_ENABLE); -+ -+ if (cur_cmd_index == SD_SWITCH_VOLTAGE) -+ phytium_mci_update_cmd11(host, mci_cmd_bits | cmd_reg); -+ else -+ phytium_mci_send_cmd(host, mci_cmd_bits, 0); -+ -+ host->current_ios_clk = ios->clock; -+ -+ dev_dbg(host->dev, "host->clk_rate: %ld, ios->clock: %d\n", -+ host->clk_rate, ios->clock); -+ } else { -+ host->current_ios_clk = 0; -+ sdr_clr_bits(host->base + MCI_CLKENA, MCI_CLKENA_CCLK_ENABLE); -+ -+ if (cur_cmd_index == SD_SWITCH_VOLTAGE) -+ phytium_mci_update_cmd11(host, mci_cmd_bits | cmd_reg); -+ else -+ phytium_mci_send_cmd(host, mci_cmd_bits, 0); -+ -+ sdr_clr_bits(host->base + MCI_UHS_REG_EXT, MCI_EXT_CLK_ENABLE); -+ dev_dbg(host->dev, "host->clk_rate: %ld, ios->clock: %d\n", -+ host->clk_rate, ios->clock); -+ } -+} -+ -+static inline u32 -+phytium_mci_cmd_find_resp(struct phytium_mci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_command *cmd) -+{ -+ u32 resp; -+ -+ switch (mmc_resp_type(cmd)) { -+ case MMC_RSP_R1: -+ case MMC_RSP_R1B: -+ resp = 0x5; -+ break; -+ -+ case MMC_RSP_R2: -+ resp = 0x7; -+ break; -+ -+ case MMC_RSP_R3: -+ resp = 0x1; -+ break; -+ -+ case MMC_RSP_NONE: -+ default: -+ resp = 0x0; -+ break; -+ } -+ -+ return resp; -+} -+ -+static inline -+u32 phytium_mci_cmd_prepare_raw_cmd(struct phytium_mci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_command *cmd) -+{ -+ u32 opcode = cmd->opcode; -+ u32 resp = phytium_mci_cmd_find_resp(host, mrq, cmd); -+ u32 rawcmd = ((opcode & 0x3f) | ((resp & 0x7) << 6)); -+ -+ if (opcode == MMC_GO_INACTIVE_STATE || -+ (opcode == SD_IO_RW_DIRECT && ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) -+ rawcmd |= (0x1 << 14); -+ else if (opcode == SD_SWITCH_VOLTAGE) -+ rawcmd |= (0x1 << 28); -+ -+ if (test_and_clear_bit(MCI_CARD_NEED_INIT, &host->flags)) -+ rawcmd |= (0x1 << 15); -+ -+ if (cmd->data) { -+ struct mmc_data *data = cmd->data; -+ -+ rawcmd |= (0x1 << 9); -+ -+ if (data->flags & MMC_DATA_WRITE) -+ rawcmd |= (0x1 << 10); -+ } -+ if (host->use_hold) -+ rawcmd |= (0x1 << 29); -+ -+ return (rawcmd | (0x1 << 31)); -+} -+ -+static inline void -+phytium_mci_adma_write_desc(struct phytium_mci_host *host, -+ struct phytium_adma2_64_desc *desc, -+ dma_addr_t addr, u32 len, u32 attribute) -+{ -+ desc->attribute = attribute; -+ desc->len = len; -+ desc->addr_lo = lower_32_bits(addr); -+ desc->addr_hi = upper_32_bits(addr); -+ dev_dbg(host->dev, "%s %d:addr_lo:0x%x ddr_hi:0x%x\n", __func__, -+ __LINE__, desc->addr_lo, desc->addr_hi); -+ -+ if ((attribute == 0x80000004) || (attribute == 0x8000000c)) { -+ desc->desc_lo = 0; -+ desc->desc_hi = 0; -+ } -+} -+ -+static void -+phytium_mci_data_sg_write_2_admc_table(struct phytium_mci_host *host, struct mmc_data *data) -+{ -+ struct phytium_adma2_64_desc *desc; -+ u32 dma_len, i; -+ dma_addr_t dma_address; -+ struct scatterlist *sg; -+ -+ phytium_mci_init_adma_table(host, &host->dma); -+ -+ desc = host->dma.adma_table; -+ for_each_sg(data->sg, sg, data->sg_count, i) { -+ dma_address = sg_dma_address(sg); -+ dma_len = sg_dma_len(sg); -+ -+ if (i == 0) { -+ if (sg_is_last(sg) || (data->sg_count == 1 && dma_len == SD_BLOCK_SIZE)) -+ phytium_mci_adma_write_desc(host, desc, dma_address, -+ dma_len, 0x8000000c); -+ else -+ phytium_mci_adma_write_desc(host, desc, dma_address, -+ dma_len, 0x8000001a); -+ } else if (sg_is_last(sg)) { -+ phytium_mci_adma_write_desc(host, desc, dma_address, -+ dma_len, 0x80000004); -+ } else { -+ phytium_mci_adma_write_desc(host, desc, dma_address, -+ dma_len, 0x80000012); -+ } -+ -+ desc++; -+ } -+} -+ -+static void -+phytium_mci_data_sg_write_2_fifo(struct phytium_mci_host *host, struct mmc_data *data) -+{ -+ struct scatterlist *sg; -+ u32 dma_len, i, j; -+ u32 *virt_addr; -+ -+ if (mmc_get_dma_dir(data) == DMA_TO_DEVICE) { -+ writel(0x1<<10, host->base + MCI_CMD); -+ for_each_sg(data->sg, sg, data->sg_count, i) { -+ dma_len = sg_dma_len(sg); -+ virt_addr = sg_virt(data->sg); -+ for (j = 0; j < (dma_len / 4); j++) { -+ writel(*virt_addr, host->base + MCI_DATA); -+ virt_addr++; -+ } -+ } -+ } -+} -+ -+static void phytium_mci_restart_clk(struct phytium_mci_host *host) -+{ -+ u32 clk_div, uhs; -+ -+ while (readl(host->base + MCI_CMD) & MCI_CMD_START) -+ cpu_relax(); -+ sdr_clr_bits(host->base + MCI_CLKENA, MCI_CLKENA_CCLK_ENABLE); -+ clk_div = readl(host->base + MCI_CLKDIV); -+ uhs = readl(host->base + MCI_UHS_REG_EXT); -+ writel(0, host->base + MCI_UHS_REG_EXT); -+ writel(uhs, host->base + MCI_UHS_REG_EXT); -+ while (!(readl(host->base + MCI_CCLK_RDY) & 0x1)) -+ cpu_relax(); -+ -+ writel(clk_div, host->base + MCI_CLKDIV); -+ sdr_set_bits(host->base + MCI_CLKENA, MCI_CLKENA_CCLK_ENABLE); -+ writel(MCI_CMD_START | MCI_CMD_UPD_CLK, host->base + MCI_CMD); -+ while (readl(host->base + MCI_CMD) & MCI_CMD_START) -+ cpu_relax(); -+} -+ -+static int -+phytim_mci_start_multiple_write(struct phytium_mci_host *host, -+ struct mmc_request *mrq, u32 cnts, u32 offset) -+{ -+ u32 rawcmd, cmd_status; -+ struct mmc_command *cmd = mrq->cmd; -+ u32 *rsp = cmd->resp; -+ unsigned long deadline_time; -+ -+ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) && readl(host->base + MCI_CARD_DETECT)) -+ return -ESHUTDOWN; -+ -+ while ((readl(host->base + MCI_STATUS) & (MCI_STATUS_CARD_BUSY))) -+ cpu_relax(); -+ -+ writel(0xffffe, host->base + MCI_RAW_INTS); -+ rawcmd = phytium_mci_cmd_prepare_raw_cmd(host, mrq, cmd); -+ writel(mrq->data->blksz, host->base + MCI_BLKSIZ); -+ writel(cnts * mrq->data->blksz, host->base + MCI_BYTCNT); -+ writel(cmd->arg + offset, host->base + MCI_CMDARG); -+ writel(rawcmd, host->base + MCI_CMD); -+ deadline_time = jiffies + msecs_to_jiffies(200); -+ -+ cmd_status = readl(host->base + MCI_RAW_INTS); -+ while (!(cmd_status & MCI_MASKED_INTS_CMD)) { -+ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) && -+ readl(host->base + MCI_CARD_DETECT)) -+ return -ESHUTDOWN; -+ -+ cmd_status = readl(host->base + MCI_RAW_INTS); -+ if (cmd_err_ints_mask & cmd_status) -+ return -ESHUTDOWN; -+ -+ if (cmd_status & MCI_MASKED_INTS_CMD) -+ break; -+ -+ if (time_after(jiffies, deadline_time)) -+ return -ESHUTDOWN; -+ } -+ -+ if (cmd_status & MCI_MASKED_INTS_CMD) { -+ if (cmd->flags & MMC_RSP_136) { -+ rsp[3] = readl(host->base + MCI_RESP0); -+ rsp[2] = readl(host->base + MCI_RESP1); -+ rsp[1] = readl(host->base + MCI_RESP2); -+ rsp[0] = readl(host->base + MCI_RESP3); -+ } else { -+ rsp[0] = readl(host->base + MCI_RESP0); -+ } -+ } -+ deadline_time = jiffies + msecs_to_jiffies(1000); -+ while (!(cmd_status & MCI_MASKED_INTS_DTO)) { -+ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) && -+ readl(host->base + MCI_CARD_DETECT)) -+ return -ESHUTDOWN; -+ cmd_status = readl(host->base + MCI_RAW_INTS); -+ if (cmd_err_ints_mask & cmd_status) -+ return -ESHUTDOWN; -+ if (cmd_status & MCI_MASKED_INTS_DTO) -+ return 0; -+ if (time_after(jiffies, deadline_time)) -+ return -ESHUTDOWN; -+ } -+ return 0; -+} -+ -+static int -+phytium_mci_start_sbc_stop_cmd(struct phytium_mci_host *host, struct mmc_request *mrq, -+ struct mmc_command *cmd, u32 arg) -+{ -+ u32 rawcmd, cmd_status; -+ u32 *rsp = cmd->resp; -+ unsigned long deadline_time; -+ -+ writel(0xffffe, host->base + MCI_RAW_INTS); -+ -+ while ((readl(host->base + MCI_STATUS) & (MCI_STATUS_CARD_BUSY))) -+ cpu_relax(); -+ -+ rawcmd = phytium_mci_cmd_prepare_raw_cmd(host, mrq, cmd); -+ writel(arg, host->base + MCI_CMDARG); -+ writel(rawcmd, host->base + MCI_CMD); -+ -+ deadline_time = jiffies + msecs_to_jiffies(200); -+ cmd_status = readl(host->base + MCI_RAW_INTS); -+ while (!(cmd_status & MCI_MASKED_INTS_CMD)) { -+ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) && -+ readl(host->base + MCI_CARD_DETECT)) -+ return -ENOMEDIUM; -+ -+ cmd_status = readl(host->base + MCI_RAW_INTS); -+ if (cmd_err_ints_mask & cmd_status) -+ return -ETIMEDOUT; -+ -+ if (cmd_status & MCI_MASKED_INTS_CMD) -+ break; -+ -+ if (time_after(jiffies, deadline_time)) -+ return -ETIMEDOUT; -+ } -+ -+ if (cmd_status & MCI_MASKED_INTS_CMD) { -+ if (cmd->flags & MMC_RSP_136) { -+ rsp[3] = readl(host->base + MCI_RESP0); -+ rsp[2] = readl(host->base + MCI_RESP1); -+ rsp[1] = readl(host->base + MCI_RESP2); -+ rsp[0] = readl(host->base + MCI_RESP3); -+ } else { -+ rsp[0] = readl(host->base + MCI_RESP0); -+ } -+ } -+ -+ if (cmd_err_ints_mask & cmd_status) -+ return -ETIMEDOUT; -+ -+ return 0; -+} -+ -+static void -+phytium_mci_start_write_multiple_non_dma(struct mmc_host *mmc, struct mmc_request *mrq) -+{ -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ struct mmc_data *data = mrq->data; -+ u32 write_cnts, last_cnts; -+ u32 i, j, k, send_cnt_one_sg, block_offset; -+ int ret = 0, dma_len; -+ struct scatterlist *sg; -+ u32 *virt_addr = NULL; -+ -+ write_cnts = data->blocks / 4; -+ (data->blocks % 4) ? write_cnts++ : write_cnts; -+ last_cnts = data->blocks % 4; -+ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) && readl(host->base + MCI_CARD_DETECT)) { -+ ret = -ENOMEDIUM; -+ goto write_err; -+ } -+ -+ dev_dbg(host->dev, "%s: cmd:%d, block counts:%d\n", -+ __func__, mrq->cmd->opcode, data->blocks); -+ -+ sdr_clr_bits(host->base + MCI_CNTRL, MCI_CNTRL_USE_INTERNAL_DMAC); -+ sdr_set_bits(host->base + MCI_CNTRL, MCI_CNTRL_FIFO_RESET); -+ while (readl(host->base + MCI_CNTRL) & MCI_CNTRL_FIFO_RESET) -+ cpu_relax(); -+ sdr_clr_bits(host->base + MCI_BUS_MODE, MCI_BUS_MODE_DE); -+ -+ if (mmc_get_dma_dir(data) == DMA_TO_DEVICE) { -+ block_offset = 0; -+ for_each_sg(data->sg, sg, data->sg_count, i) { -+ /* Each SG data transfor starts */ -+ dma_len = sg_dma_len(sg); -+ send_cnt_one_sg = (dma_len / MCI_MAX_FIFO_CNT) + 1; -+ virt_addr = sg_virt(sg); -+ for (k = 0; k < send_cnt_one_sg; k++) { -+ if (dma_len && dma_len >= MCI_MAX_FIFO_CNT) { -+ /*first write sbc cmd*/ -+ ret = phytium_mci_start_sbc_stop_cmd(host, mrq, -+ mrq->sbc, 4); -+ if (ret) -+ goto write_err; -+ writel(0x1 << 10, host->base + MCI_CMD); -+ for (j = 0; j < (MCI_MAX_FIFO_CNT / 4); j++) { -+ writel(*virt_addr, host->base + MCI_DATA); -+ virt_addr++; -+ } -+ -+ /*second write cmd25 here*/ -+ ret = phytim_mci_start_multiple_write(host, mrq, 4, -+ block_offset); -+ if (ret) -+ goto write_err; -+ block_offset += 4; -+ dma_len -= MCI_MAX_FIFO_CNT; -+ } else if (dma_len > 0) { -+ /*first write sbc cmd*/ -+ last_cnts = dma_len / 512; -+ ret = phytium_mci_start_sbc_stop_cmd(host, mrq, mrq->sbc, -+ last_cnts); -+ if (ret) -+ goto write_err; -+ writel(0x1 << 10, host->base + MCI_CMD); -+ for (j = 0; j < (dma_len / 4); j++) { -+ writel(*virt_addr, host->base + MCI_DATA); -+ virt_addr++; -+ } -+ /*second write cmd25 here*/ -+ ret = phytim_mci_start_multiple_write(host, mrq, last_cnts, -+ block_offset); -+ if (ret) -+ goto write_err; -+ block_offset += last_cnts; -+ dma_len = 0; -+ } else { -+ dev_dbg(host->dev, "%s: sg %d end\n", __func__, i); -+ break; -+ } -+ } -+ } -+ } -+ -+write_err: -+ host->data = NULL; -+ host->cmd = NULL; -+ host->mrq = NULL; -+ writel(0xffffe, host->base + MCI_RAW_INTS); -+ if (ret) { -+ data->bytes_xfered = 0; -+ if (ret == -ESHUTDOWN) { -+ sdr_set_bits(host->base + MCI_CNTRL, MCI_CNTRL_FIFO_RESET); -+ while (readl(host->base + MCI_CNTRL) & MCI_CNTRL_FIFO_RESET) -+ cpu_relax(); -+ -+ sdr_set_bits(host->base + MCI_CNTRL, MCI_CNTRL_CONTROLLER_RESET); -+ while (readl(host->base + MCI_STATUS) & MCI_STATUS_CARD_BUSY) -+ sdr_set_bits(host->base + MCI_CNTRL, MCI_CNTRL_CONTROLLER_RESET); -+ phytium_mci_restart_clk(host); -+ phytium_mci_start_sbc_stop_cmd(host, mrq, mrq->stop, mrq->stop->arg); -+ } -+ data->error = -ETIMEDOUT; -+ mrq->cmd->error = -ETIMEDOUT; -+ mmc_request_done(host->mmc, mrq); -+ return; -+ } -+ data->bytes_xfered = data->blocks * data->blksz; -+ mmc_request_done(host->mmc, mrq); -+} -+ -+static void -+phytium_mci_start_data(struct phytium_mci_host *host, struct mmc_request *mrq, -+ struct mmc_command *cmd, struct mmc_data *data) -+{ -+ bool read; -+ u32 rawcmd; -+ unsigned long flags; -+ -+ -+ WARN_ON(host->cmd); -+ host->cmd = cmd; -+ cmd->error = 0; -+ WARN_ON(host->data); -+ host->data = data; -+ read = data->flags & MMC_DATA_READ; -+ -+ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) && readl(host->base + MCI_CARD_DETECT)) { -+ phytium_mci_err_irq(host, 0, MCI_INT_MASK_RTO); -+ return; -+ } -+ /* clear interrupts */ -+ writel(0xffffe, host->base + MCI_RAW_INTS); -+ -+ sdr_set_bits(host->base + MCI_CNTRL, MCI_CNTRL_FIFO_RESET | MCI_CNTRL_DMA_RESET); -+ -+ while (readl(host->base + MCI_CNTRL) & (MCI_CNTRL_FIFO_RESET | MCI_CNTRL_DMA_RESET)) -+ cpu_relax(); -+ -+ if (host->adtc_type == COMMOM_ADTC) -+ sdr_clr_bits(host->base + MCI_CNTRL, MCI_CNTRL_USE_INTERNAL_DMAC); -+ else -+ sdr_set_bits(host->base + MCI_CNTRL, MCI_CNTRL_USE_INTERNAL_DMAC); -+ wmb(); /* drain writebuffer */ -+ sdr_clr_bits(host->base + MCI_CNTRL, MCI_CNTRL_INT_ENABLE); -+ -+ rawcmd = phytium_mci_cmd_prepare_raw_cmd(host, mrq, cmd); -+ if (host->is_use_dma && host->adtc_type == BLOCK_RW_ADTC) -+ phytium_mci_data_sg_write_2_admc_table(host, data); -+ else -+ phytium_mci_data_sg_write_2_fifo(host, data); -+ -+ spin_lock_irqsave(&host->lock, flags); -+ sdr_set_bits(host->base + MCI_INT_MASK, cmd_ints_mask | data_ints_mask); -+ if (host->is_use_dma && host->adtc_type == BLOCK_RW_ADTC) { -+ sdr_set_bits(host->base + MCI_DMAC_INT_ENA, dmac_ints_mask); -+ /* Enable the IDMAC */ -+ sdr_set_bits(host->base + MCI_BUS_MODE, MCI_BUS_MODE_DE); -+ writel((u32)host->dma.adma_addr, host->base + MCI_DESC_LIST_ADDRL); -+ writel((u32)(host->dma.adma_addr >> 32), host->base + MCI_DESC_LIST_ADDRH); -+ } -+ writel(mrq->data->blksz, host->base + MCI_BLKSIZ); -+ writel(mrq->data->blocks * mrq->data->blksz, host->base + MCI_BYTCNT); -+ sdr_set_bits(host->base + MCI_CNTRL, MCI_CNTRL_INT_ENABLE); -+ writel(cmd->arg, host->base + MCI_CMDARG); -+ wmb(); /* drain writebuffer */ -+ writel(rawcmd, host->base + MCI_CMD); -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ -+static void phytium_mci_track_cmd_data(struct phytium_mci_host *host, -+ struct mmc_command *cmd, -+ struct mmc_data *data) -+{ -+ if (host->error) -+ dev_dbg(host->dev, "%s: cmd=%d arg=%08X; host->error=0x%08X\n", -+ __func__, cmd->opcode, cmd->arg, host->error); -+} -+ -+static void phytium_mci_request_done(struct phytium_mci_host *host, struct mmc_request *mrq) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ host->mrq = NULL; -+ if (host->cmd) -+ host->cmd = NULL; -+ spin_unlock_irqrestore(&host->lock, flags); -+ phytium_mci_track_cmd_data(host, mrq->cmd, mrq->data); -+ -+ if (mrq->data) -+ phytium_mci_unprepare_data(host, mrq); -+ -+ mmc_request_done(host->mmc, mrq); -+} -+ -+static bool phytium_mci_cmd_done(struct phytium_mci_host *host, int events, -+ struct mmc_request *mrq, struct mmc_command *cmd) -+{ -+ bool done = false; -+ unsigned long flags; -+ u32 *rsp = cmd->resp; -+ -+ if (!(events & (MCI_RAW_INTS_RCRC | MCI_RAW_INTS_RE | MCI_RAW_INTS_CMD | -+ MCI_RAW_INTS_RTO | MCI_INT_MASK_HTO))) { -+ dev_err(host->dev, "No interrupt generation:h%x\n", events); -+ return done; -+ } -+ -+ spin_lock_irqsave(&host->lock, flags); -+ done = !host->cmd; -+ host->cmd = NULL; -+ if (done) { -+ spin_unlock_irqrestore(&host->lock, flags); -+ return true; -+ } -+ sdr_clr_bits(host->base + MCI_INT_MASK, cmd_ints_mask); -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if (cmd->flags & MMC_RSP_PRESENT) { -+ if (cmd->flags & MMC_RSP_136) { -+ rsp[3] = readl(host->base + MCI_RESP0); -+ rsp[2] = readl(host->base + MCI_RESP1); -+ rsp[1] = readl(host->base + MCI_RESP2); -+ rsp[0] = readl(host->base + MCI_RESP3); -+ } else { -+ rsp[0] = readl(host->base + MCI_RESP0); -+ } -+ -+ if (cmd->opcode == SD_SEND_RELATIVE_ADDR) -+ host->current_rca = rsp[0] & 0xFFFF0000; -+ } -+ if (!(events & (MCI_RAW_INTS_CMD | MCI_INT_MASK_HTO))) { -+ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) && (events & MCI_RAW_INTS_RTO) -+ && readl(host->base + MCI_CARD_DETECT)) { -+ cmd->error = -ENOMEDIUM; -+ rsp[0] = 0; -+ } else if (events & MCI_RAW_INTS_RTO || -+ (cmd->opcode != MMC_SEND_TUNING_BLOCK && -+ cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200)) { -+ cmd->error = -ETIMEDOUT; -+ } else if (events & MCI_RAW_INTS_RCRC) { -+ cmd->error = -EILSEQ; -+ } else { -+ cmd->error = -ETIMEDOUT; -+ } -+ } -+ phytium_mci_cmd_next(host, mrq, cmd); -+ return true; -+} -+ -+static void phytium_mci_start_command(struct phytium_mci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_command *cmd) -+{ -+ u32 rawcmd; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ WARN_ON(host->cmd); -+ host->cmd = cmd; -+ cmd->error = 0; -+ writel(0xffffe, host->base + MCI_RAW_INTS); -+ -+ rawcmd = phytium_mci_cmd_prepare_raw_cmd(host, mrq, cmd); -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) && readl(host->base + MCI_CARD_DETECT)) { -+ phytium_mci_cmd_done(host, MCI_RAW_INTS_RTO, mrq, cmd); -+ return; -+ } -+ -+ spin_lock_irqsave(&host->lock, flags); -+ sdr_set_bits(host->base + MCI_INT_MASK, cmd_ints_mask); -+ writel(cmd->arg, host->base + MCI_CMDARG); -+ writel(rawcmd, host->base + MCI_CMD); -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ -+static void -+phytium_mci_cmd_next(struct phytium_mci_host *host, struct mmc_request *mrq, -+ struct mmc_command *cmd) -+{ -+ if ((cmd->error && !(cmd->opcode == MMC_SEND_TUNING_BLOCK || -+ cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)) || -+ (mrq->sbc && mrq->sbc->error)) { -+ phytium_mci_request_done(host, mrq); -+ } else if (cmd == mrq->sbc) { -+ if ((mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK) || -+ (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) || -+ (mrq->cmd->opcode == MMC_READ_SINGLE_BLOCK) || -+ (mrq->cmd->opcode == MMC_WRITE_BLOCK)) { -+ dev_dbg(host->dev, "%s %d:sbc done and next cmd :%d length:%d\n", -+ __func__, __LINE__, mrq->cmd->opcode, mrq->data->sg->length); -+ phytium_mci_prepare_data(host, mrq); -+ if (host->is_use_dma) -+ host->adtc_type = BLOCK_RW_ADTC; -+ else -+ host->adtc_type = COMMOM_ADTC; -+ phytium_mci_start_data(host, mrq, mrq->cmd, mrq->data); -+ } else { -+ dev_err(host->dev, "%s %d:ERROR: cmd %d followers the SBC\n", -+ __func__, __LINE__, cmd->opcode); -+ } -+ } else if (!cmd->data) { -+ phytium_mci_request_done(host, mrq); -+ } -+} -+ -+static void phytium_mci_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) -+{ -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ u32 data; -+ int rc; -+ -+ host->error = 0; -+ WARN_ON(host->mrq); -+ host->mrq = mrq; -+ -+ rc = readl_relaxed_poll_timeout(host->base + MCI_STATUS, -+ data, -+ !(data & MCI_STATUS_CARD_BUSY), -+ 0, 2000 * 1000); -+ if (rc == -ETIMEDOUT) -+ pr_debug("%s %d, timeout mci_status: 0x%08x\n", __func__, __LINE__, data); -+ -+ dev_dbg(host->dev, "%s %d: cmd:%d arg:0x%x\n", __func__, __LINE__, -+ mrq->cmd->opcode, mrq->cmd->arg); -+ -+ if (host->is_device_x100 && mrq->sbc && mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) { -+ phytium_mci_start_write_multiple_non_dma(mmc, mrq); -+ return; -+ } -+ -+ if (mrq->sbc) { -+ phytium_mci_start_command(host, mrq, mrq->sbc); -+ return; -+ } -+ if (mrq->data) { -+ phytium_mci_prepare_data(host, mrq); -+ -+ if ((mrq->data->sg->length >= 512) && host->is_use_dma && -+ ((mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK) || -+ (mrq->cmd->opcode == MMC_READ_SINGLE_BLOCK) || -+ (mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) || -+ (mrq->cmd->opcode == MMC_WRITE_BLOCK) || -+ (mrq->cmd->opcode == SD_IO_RW_EXTENDED))) -+ -+ host->adtc_type = BLOCK_RW_ADTC; -+ else -+ host->adtc_type = COMMOM_ADTC; -+ -+ phytium_mci_start_data(host, mrq, mrq->cmd, mrq->data); -+ return; -+ } -+ phytium_mci_start_command(host, mrq, mrq->cmd); -+} -+ -+static void phytium_mci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq) -+{ -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ struct mmc_data *data = mrq->data; -+ -+ if (!data) -+ return; -+ -+ phytium_mci_prepare_data(host, mrq); -+ data->host_cookie |= MCI_ASYNC_FLAG; -+} -+ -+static void phytium_mci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, -+ int err) -+{ -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ struct mmc_data *data = mrq->data; -+ -+ if (!data) -+ return; -+ -+ if (data->host_cookie & MCI_ASYNC_FLAG) { -+ data->host_cookie &= ~MCI_ASYNC_FLAG; -+ phytium_mci_unprepare_data(host, mrq); -+ } -+} -+ -+static void phytium_mci_data_read_without_dma(struct phytium_mci_host *host, -+ struct mmc_data *data) -+{ -+ u32 length, i, data_val, dma_len, tmp = 0; -+ u32 *virt_addr; -+ unsigned long flags; -+ struct scatterlist *sg; -+ -+ length = data->blocks * data->blksz; -+ -+ if (mmc_get_dma_dir(data) == DMA_FROM_DEVICE) { -+ spin_lock_irqsave(&host->lock, flags); -+ if (data->host_cookie & MCI_ASYNC_FLAG) { -+ tmp = MCI_ASYNC_FLAG; -+ phytium_mci_post_req(host->mmc, data->mrq, 0); -+ } else { -+ phytium_mci_unprepare_data(host, data->mrq); -+ } -+ -+ for_each_sg(data->sg, sg, data->sg_count, i) { -+ dma_len = sg_dma_len(sg); -+ virt_addr = sg_virt(data->sg); -+ -+ for (i = 0; i < (dma_len / 4); i++) { -+ data_val = readl(host->base + MCI_DATA); -+ memcpy(virt_addr, &data_val, 4); -+ ++virt_addr; -+ } -+ } -+ -+ if (tmp & MCI_ASYNC_FLAG) -+ phytium_mci_pre_req(host->mmc, data->mrq); -+ else -+ phytium_mci_prepare_data(host, data->mrq); -+ -+ spin_unlock_irqrestore(&host->lock, flags); -+ } -+ data->bytes_xfered = length; -+} -+ -+static void phytium_mci_data_xfer_next(struct phytium_mci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_data *data) -+{ -+ if (mmc_op_multi(mrq->cmd->opcode) && mrq->stop && -+ (data->error || !mrq->sbc)) { -+ while ((readl(host->base + MCI_STATUS) & (MCI_STATUS_CARD_BUSY))) -+ cpu_relax(); -+ phytium_mci_start_command(host, mrq, mrq->stop); -+ } else { -+ phytium_mci_request_done(host, mrq); -+ } -+} -+ -+static bool phytium_mci_data_xfer_done(struct phytium_mci_host *host, u32 events, -+ struct mmc_request *mrq, struct mmc_data *data) -+{ -+ unsigned long flags; -+ bool done; -+ -+ unsigned int check_data = events & (MCI_RAW_INTS_DTO | MCI_RAW_INTS_RCRC | -+ MCI_RAW_INTS_DCRC | MCI_RAW_INTS_RE | -+ MCI_RAW_INTS_DRTO | MCI_RAW_INTS_EBE | -+ MCI_DMAC_STATUS_AIS | MCI_DMAC_STATUS_DU | -+ MCI_RAW_INTS_SBE_BCI | MCI_INT_MASK_RTO); -+ -+ spin_lock_irqsave(&host->lock, flags); -+ done = !host->data; -+ -+ if (check_data || host->data) -+ host->data = NULL; -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if (done) -+ return true; -+ if (check_data) { -+ spin_lock_irqsave(&host->lock, flags); -+ sdr_clr_bits(host->base + MCI_DMAC_INT_ENA, dmac_ints_mask); -+ sdr_clr_bits(host->base + MCI_INT_MASK, data_ints_mask); -+ /* Stop the IDMAC running */ -+ sdr_clr_bits(host->base + MCI_BUS_MODE, MCI_BUS_MODE_DE); -+ dev_dbg(host->dev, "DMA stop\n"); -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if (events & MCI_RAW_INTS_DTO) { -+ if (!host->is_use_dma || -+ (host->is_use_dma && host->adtc_type == COMMOM_ADTC && -+ (mrq->cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC)) -+ phytium_mci_data_read_without_dma(host, data); -+ else -+ data->bytes_xfered = data->blocks * data->blksz; -+ } else { -+ data->bytes_xfered = 0; -+ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE) -+ && readl(host->base + MCI_CARD_DETECT) -+ && (events & cmd_err_ints_mask)) { -+ data->error = -ENOMEDIUM; -+ data->mrq->cmd->error = -ENOMEDIUM; -+ } else if (events & (MCI_RAW_INTS_DCRC | MCI_RAW_INTS_EBE | -+ MCI_RAW_INTS_SBE_BCI)) { -+ data->error = -EILSEQ; -+ host->cmd = NULL; -+ } else { -+ data->error = -ETIMEDOUT; -+ host->cmd = NULL; -+ } -+ } -+ -+ phytium_mci_data_xfer_next(host, mrq, data); -+ done = true; -+ } -+ return done; -+} -+ -+static int phytium_mci_card_busy(struct mmc_host *mmc) -+{ -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ u32 status; -+ -+ status = readl(host->base + MCI_STATUS); -+ -+ return !!(status & MCI_STATUS_CARD_BUSY); -+} -+ -+static void __phytium_mci_enable_sdio_irq(struct phytium_mci_host *host, int enable) -+{ -+ if (enable) -+ sdr_set_bits(host->base + MCI_INT_MASK, MCI_INT_MASK_SDIO); -+ else -+ sdr_clr_bits(host->base + MCI_INT_MASK, MCI_INT_MASK_SDIO); -+} -+ -+static void phytium_mci_enable_sdio_irq(struct mmc_host *mmc, int enable) -+{ -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ -+ __phytium_mci_enable_sdio_irq(host, enable); -+} -+ -+static void hotplug_timer_func(struct timer_list *t) -+{ -+ struct phytium_mci_host *host; -+ u32 status; -+ -+ host = from_timer(host, t, hotplug_timer); -+ if (!host) -+ return; -+ -+ status = readl(host->base + MCI_CARD_DETECT); -+ -+ if (status & 0x1) { -+ if (host->mmc->card) { -+ cancel_delayed_work(&host->mmc->detect); -+ mmc_detect_change(host->mmc, msecs_to_jiffies(100)); -+ } -+ } else { -+ cancel_delayed_work(&host->mmc->detect); -+ mmc_detect_change(host->mmc, msecs_to_jiffies(200)); -+ } -+} -+ -+static int phytium_mci_err_irq(struct phytium_mci_host *host, u32 dmac_events, u32 events) -+{ -+ struct mmc_request *mrq; -+ struct mmc_command *cmd; -+ struct mmc_data *data; -+ -+ mrq = host->mrq; -+ cmd = host->cmd; -+ data = host->data; -+ -+ if (cmd && (cmd == mrq->sbc)) { -+ phytium_mci_cmd_done(host, MCI_RAW_INTS_RTO, mrq, mrq->sbc); -+ } else if (cmd && (cmd == mrq->stop)) { -+ phytium_mci_cmd_done(host, MCI_RAW_INTS_RTO, mrq, mrq->stop); -+ } else if (data) { -+ data->error = -ETIMEDOUT; -+ if ((data->flags & MMC_DATA_READ) == MMC_DATA_READ || -+ (data->flags & MMC_DATA_WRITE) == MMC_DATA_WRITE) -+ phytium_mci_data_xfer_done(host, events | dmac_events, mrq, data); -+ } else if (cmd) { -+ phytium_mci_cmd_done(host, MCI_RAW_INTS_RTO, mrq, mrq->cmd); -+ } -+ -+ return 0; -+} -+ -+static irqreturn_t phytium_mci_irq(int irq, void *dev_id) -+{ -+ struct phytium_mci_host *host = (struct phytium_mci_host *) dev_id; -+ unsigned long flags; -+ struct mmc_request *mrq; -+ struct mmc_command *cmd; -+ struct mmc_data *data; -+ u32 events, event_mask, dmac_events, dmac_evt_mask; -+ -+ if (!host) -+ return IRQ_NONE; -+ writel(0, host->base + 0xfd0); -+ -+ spin_lock_irqsave(&host->lock, flags); -+ events = readl(host->base + MCI_RAW_INTS); -+ dmac_events = readl(host->base + MCI_DMAC_STATUS); -+ event_mask = readl(host->base + MCI_INT_MASK); -+ dmac_evt_mask = readl(host->base + MCI_DMAC_INT_ENA); -+ if ((!events) && (!(dmac_events&0x1fff))) { -+ spin_unlock_irqrestore(&host->lock, flags); -+ return IRQ_NONE; -+ } -+ dev_dbg(host->dev, "%s:events:%x,mask:0x%x,dmac_events:%x,dmac_mask:0x%x,cmd:%d\n", -+ __func__, events, event_mask, dmac_events, dmac_evt_mask, -+ host->mrq ? host->mrq->cmd->opcode : 255); -+ -+ mrq = host->mrq; -+ cmd = host->cmd; -+ data = host->data; -+ -+ if ((events & event_mask) & MCI_RAW_INTS_SDIO) -+ __phytium_mci_enable_sdio_irq(host, 0); -+ -+ writel((events & event_mask), host->base + MCI_RAW_INTS); -+ writel(dmac_events, host->base + MCI_DMAC_STATUS); -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if ((events & event_mask) & MCI_RAW_INTS_SDIO) -+ sdio_signal_irq(host->mmc); -+ -+ if (((events & event_mask) == 0) && ((dmac_evt_mask & dmac_events) == 0)) -+ goto irq_out; -+ -+ if (((events & event_mask) & MCI_RAW_INTS_CD) && -+ !(host->mmc->caps & MMC_CAP_NONREMOVABLE)) { -+ mod_timer(&host->hotplug_timer, jiffies + usecs_to_jiffies(20000)); -+ dev_dbg(host->dev, "sd status changed here ! status:[%d] [%s %d]", -+ readl(host->base + MCI_CARD_DETECT), __func__, __LINE__); -+ -+ if ((events & event_mask) == MCI_RAW_INTS_CD) -+ goto irq_out; -+ } -+ -+ if (!mrq) { -+ if (events & MCI_RAW_INTS_HLE) -+ dev_dbg(host->dev, -+ "%s: MRQ=NULL and HW write locked, events=%08x,event_mask=%08x\n", -+ __func__, events, event_mask); -+ else -+ dev_dbg(host->dev, "%s: MRQ=NULL events:%08X evt_mask=%08X,sd_status:%d\n", -+ __func__, events, event_mask, readl(host->base + MCI_CARD_DETECT)); -+ goto irq_out; -+ } -+ -+ if ((dmac_events & dmac_err_ints_mask) || (events & cmd_err_ints_mask)) { -+ dev_dbg(host->dev, "ERR:events:%x,mask:0x%x,dmac_evts:%x,dmac_mask:0x%x,cmd:%d\n", -+ events, event_mask, dmac_events, dmac_evt_mask, mrq->cmd->opcode); -+ phytium_mci_err_irq(host, dmac_events & dmac_err_ints_mask, -+ events & cmd_err_ints_mask); -+ goto irq_out; -+ } -+ -+ if (cmd && (events & MCI_MASKED_INTS_DTO) && (events & MCI_MASKED_INTS_CMD)) { -+ phytium_mci_cmd_done(host, events, mrq, cmd); -+ phytium_mci_data_xfer_done(host, (events & data_ints_mask) | -+ (dmac_events & dmac_ints_mask), mrq, data); -+ } else if (cmd && (events & MCI_MASKED_INTS_CMD || -+ ((events & MCI_INT_MASK_HTO) && (cmd->opcode == SD_SWITCH_VOLTAGE)))) { -+ phytium_mci_cmd_done(host, events, mrq, cmd); -+ } else if (events & MCI_MASKED_INTS_DTO) { -+ phytium_mci_data_xfer_done(host, (events & data_ints_mask) | -+ (dmac_events & dmac_ints_mask), mrq, data); -+ } -+ -+irq_out: -+ return IRQ_HANDLED; -+} -+ -+static void phytium_mci_init_hw(struct phytium_mci_host *host) -+{ -+ u32 val; -+ int uhs_reg_value = 0x502; -+ -+ writel(MCI_SET_FIFOTH(0x2, 0x7, 0x100), host->base + MCI_FIFOTH); -+ writel(0x800001, host->base + MCI_CARD_THRCTL); -+ sdr_clr_bits(host->base + MCI_CLKENA, MCI_CLKENA_CCLK_ENABLE); -+ phytium_mci_update_external_clk(host, uhs_reg_value); -+ -+ sdr_set_bits(host->base + MCI_PWREN, MCI_PWREN_ENABLE); -+ sdr_set_bits(host->base + MCI_CLKENA, MCI_CLKENA_CCLK_ENABLE); -+ sdr_set_bits(host->base + MCI_UHS_REG_EXT, MCI_EXT_CLK_ENABLE); -+ sdr_clr_bits(host->base + MCI_UHS_REG, MCI_UHS_REG_VOLT); -+ -+ phytium_mci_reset_hw(host); -+ -+ if (host->mmc->caps & MMC_CAP_NONREMOVABLE) -+ sdr_set_bits(host->base + MCI_CARD_RESET, MCI_CARD_RESET_ENABLE); -+ else -+ sdr_clr_bits(host->base + MCI_CARD_RESET, MCI_CARD_RESET_ENABLE); -+ -+ writel(0, host->base + MCI_INT_MASK); -+ val = readl(host->base + MCI_RAW_INTS); -+ writel(val, host->base + MCI_RAW_INTS); -+ writel(0, host->base + MCI_DMAC_INT_ENA); -+ val = readl(host->base + MCI_DMAC_STATUS); -+ writel(val, host->base + MCI_DMAC_STATUS); -+ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE)) -+ writel(MCI_INT_MASK_CD, host->base + MCI_INT_MASK); -+ -+ sdr_set_bits(host->base + MCI_CNTRL, MCI_CNTRL_INT_ENABLE | -+ MCI_CNTRL_USE_INTERNAL_DMAC); -+ -+ writel(0xFFFFFFFF, host->base + MCI_TMOUT); -+ dev_info(host->dev, "init hardware done!"); -+ -+} -+ -+void phytium_mci_deinit_hw(struct phytium_mci_host *host) -+{ -+ u32 val; -+ -+ sdr_clr_bits(host->base + MCI_PWREN, MCI_PWREN_ENABLE); -+ sdr_clr_bits(host->base + MCI_CLKENA, MCI_CLKENA_CCLK_ENABLE); -+ sdr_clr_bits(host->base + MCI_UHS_REG_EXT, MCI_EXT_CLK_ENABLE); -+ sdr_clr_bits(host->base + MCI_UHS_REG, MCI_UHS_REG_VOLT); -+ writel(0, host->base + MCI_INT_MASK); -+ val = readl(host->base + MCI_RAW_INTS); -+ writel(val, host->base + MCI_RAW_INTS); -+ writel(0, host->base + MCI_DMAC_INT_ENA); -+ val = readl(host->base + MCI_DMAC_STATUS); -+ writel(val, host->base + MCI_DMAC_STATUS); -+ if (!(host->mmc->caps & MMC_CAP_NONREMOVABLE)) -+ writel(MCI_INT_MASK_CD, host->base + MCI_INT_MASK); -+} -+EXPORT_SYMBOL_GPL(phytium_mci_deinit_hw); -+ -+static void phytium_mci_adma_reset(struct phytium_mci_host *host) -+{ -+ u32 bmod = readl(host->base + MCI_BUS_MODE); -+ -+ bmod |= MCI_BUS_MODE_SWR; -+ writel(bmod, host->base + MCI_BUS_MODE); -+} -+ -+static void phytium_mci_init_adma_table(struct phytium_mci_host *host, -+ struct phytium_mci_dma *dma) -+{ -+ struct phytium_adma2_64_desc *adma_table = dma->adma_table; -+ dma_addr_t dma_addr; -+ int i; -+ -+ memset(adma_table, 0, sizeof(struct phytium_adma2_64_desc) * MAX_BD_NUM); -+ -+ for (i = 0; i < (MAX_BD_NUM - 1); i++) { -+ dma_addr = dma->adma_addr + sizeof(*adma_table) * (i + 1); -+ adma_table[i].desc_lo = lower_32_bits(dma_addr); -+ adma_table[i].desc_hi = upper_32_bits(dma_addr); -+ adma_table[i].attribute = 0; -+ adma_table[i].NON1 = 0; -+ adma_table[i].len = 0; -+ adma_table[i].NON2 = 0; -+ } -+ -+ phytium_mci_adma_reset(host); -+} -+ -+static void phytium_mci_set_buswidth(struct phytium_mci_host *host, u32 width) -+{ -+ u32 val; -+ -+ switch (width) { -+ case MMC_BUS_WIDTH_1: -+ val = MCI_BUS_1BITS; -+ break; -+ -+ case MMC_BUS_WIDTH_4: -+ val = MCI_BUS_4BITS; -+ break; -+ -+ case MMC_BUS_WIDTH_8: -+ val = MCI_BUS_8BITS; -+ break; -+ default: -+ val = MCI_BUS_4BITS; -+ break; -+ } -+ writel(val, host->base + MCI_CTYPE); -+ dev_dbg(host->dev, "Bus Width = %d, set value:0x%x\n", width, val); -+} -+ -+static void phytium_mci_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -+{ -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ -+ if (ios->timing == MMC_TIMING_MMC_DDR52 || ios->timing == MMC_TIMING_UHS_DDR50) -+ sdr_set_bits(host->base + MCI_UHS_REG, MCI_UHS_REG_DDR); -+ else -+ sdr_clr_bits(host->base + MCI_UHS_REG, MCI_UHS_REG_DDR); -+ -+ phytium_mci_set_buswidth(host, ios->bus_width); -+ -+ switch (ios->power_mode) { -+ case MMC_POWER_UP: -+ set_bit(MCI_CARD_NEED_INIT, &host->flags); -+ writel(MCI_POWER_ON, host->base + MCI_PWREN); -+ break; -+ -+ case MMC_POWER_ON: -+ break; -+ -+ case MMC_POWER_OFF: -+ writel(MCI_POWER_OFF, host->base + MCI_PWREN); -+ break; -+ -+ default: -+ break; -+ } -+ phytium_mci_set_clk(host, ios); -+} -+ -+static void phytium_mci_ack_sdio_irq(struct mmc_host *mmc) -+{ -+ unsigned long flags; -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ -+ spin_lock_irqsave(&host->lock, flags); -+ __phytium_mci_enable_sdio_irq(host, 1); -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ -+static int phytium_mci_get_cd(struct mmc_host *mmc) -+{ -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ u32 status; -+ -+ if (mmc->caps & MMC_CAP_NONREMOVABLE) -+ return 1; -+ -+ status = readl(host->base + MCI_CARD_DETECT); -+ -+ if ((status & 0x1) == 0x1) -+ return 0; -+ -+ return 1; -+} -+ -+static int phytium_mci_ops_switch_volt(struct mmc_host *mmc, struct mmc_ios *ios) -+{ -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ unsigned int is_voltage_180 = 0; -+ -+ is_voltage_180 = readl(host->base + MCI_UHS_REG); -+ if ((mmc->caps & MMC_CAP_NONREMOVABLE) && (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180)) -+ return -EINVAL; -+ -+ if ((ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) && (is_voltage_180 & 0x1)) -+ sdr_clr_bits(host->base + MCI_UHS_REG, MCI_UHS_REG_VOLT); -+ else if ((ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) && (!(is_voltage_180 & 0x1))) -+ sdr_set_bits(host->base + MCI_UHS_REG, MCI_UHS_REG_VOLT); -+ else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) -+ return -EINVAL; -+ return 0; -+} -+ -+static void phytium_mci_hw_reset(struct mmc_host *mmc) -+{ -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ u32 reset_flag; -+ -+ if (host->is_use_dma) { -+ reset_flag = MCI_CNTRL_FIFO_RESET | MCI_CNTRL_DMA_RESET; -+ phytium_mci_adma_reset(host); -+ sdr_set_bits(host->base + MCI_CNTRL, reset_flag); -+ } else { -+ reset_flag = MCI_CNTRL_FIFO_RESET; -+ sdr_set_bits(host->base + MCI_CNTRL, reset_flag); -+ } -+ -+ while (readl(host->base + MCI_CNTRL) & reset_flag) -+ cpu_relax(); -+ -+ sdr_clr_bits(host->base + MCI_CARD_RESET, MCI_CARD_RESET_ENABLE); -+ udelay(5); -+ sdr_set_bits(host->base + MCI_CARD_RESET, MCI_CARD_RESET_ENABLE); -+ usleep_range(200, 300); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+int phytium_mci_suspend(struct device *dev) -+{ -+ struct mmc_host *mmc = dev_get_drvdata(dev); -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ -+ phytium_mci_deinit_hw(host); -+ return 0; -+} -+EXPORT_SYMBOL(phytium_mci_suspend); -+ -+int phytium_mci_resume(struct device *dev) -+{ -+ struct mmc_host *mmc = dev_get_drvdata(dev); -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ -+ phytium_mci_init_hw(host); -+ return 0; -+} -+EXPORT_SYMBOL(phytium_mci_resume); -+ -+#endif -+ -+#ifdef CONFIG_PM -+int phytium_mci_runtime_suspend(struct device *dev) -+{ -+ struct mmc_host *mmc = dev_get_drvdata(dev); -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ -+ phytium_mci_deinit_hw(host); -+ return 0; -+} -+EXPORT_SYMBOL(phytium_mci_runtime_suspend); -+ -+int phytium_mci_runtime_resume(struct device *dev) -+{ -+ struct mmc_host *mmc = dev_get_drvdata(dev); -+ struct phytium_mci_host *host = mmc_priv(mmc); -+ -+ phytium_mci_init_hw(host); -+ return 0; -+} -+EXPORT_SYMBOL(phytium_mci_runtime_resume); -+ -+#endif -+ -+static struct mmc_host_ops phytium_mci_ops = { -+ .post_req = phytium_mci_post_req, -+ .pre_req = phytium_mci_pre_req, -+ .request = phytium_mci_ops_request, -+ .set_ios = phytium_mci_ops_set_ios, -+ .get_cd = phytium_mci_get_cd, -+ .enable_sdio_irq = phytium_mci_enable_sdio_irq, -+ .ack_sdio_irq = phytium_mci_ack_sdio_irq, -+ .card_busy = phytium_mci_card_busy, -+ .start_signal_voltage_switch = phytium_mci_ops_switch_volt, -+ .card_hw_reset = phytium_mci_hw_reset, -+}; -+ -+int phytium_mci_common_probe(struct phytium_mci_host *host) -+{ -+ struct mmc_host *mmc = host->mmc; -+ struct device *dev = host->dev; -+ int ret; -+ -+ dma_set_mask(dev, DMA_BIT_MASK(64)); -+ dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); -+ -+ timer_setup(&host->hotplug_timer, hotplug_timer_func, 0); -+ -+ mmc->f_min = MCI_F_MIN; -+ if (!mmc->f_max) -+ mmc->f_max = MCI_F_MAX; -+ -+ mmc->ops = &phytium_mci_ops; -+ mmc->ocr_avail_sdio = MMC_VDD_32_33 | MMC_VDD_33_34; -+ mmc->ocr_avail_sd = MMC_VDD_32_33 | MMC_VDD_33_34; -+ mmc->ocr_avail_mmc = MMC_VDD_165_195; -+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; -+ mmc->caps |= host->caps; -+ -+ if (mmc->caps & MMC_CAP_SDIO_IRQ) { -+ mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; -+ dev_dbg(host->dev, "%s %d: MMC_CAP_SDIO_IRQ\n", __func__, __LINE__); -+ } -+ mmc->caps2 |= host->caps2; -+ if (host->is_use_dma) { -+ /* MMC core transfer sizes tunable parameters */ -+ mmc->max_segs = MAX_BD_NUM; -+ mmc->max_seg_size = 4 * 1024; -+ mmc->max_blk_size = 512; -+ mmc->max_req_size = 512 * 1024; -+ mmc->max_blk_count = mmc->max_req_size / 512; -+ host->dma.adma_table = dma_alloc_coherent(host->dev, -+ MAX_BD_NUM * -+ sizeof(struct phytium_adma2_64_desc), -+ &host->dma.adma_addr, GFP_KERNEL); -+ if (!host->dma.adma_table) -+ return MCI_REALEASE_MEM; -+ -+ host->dma.desc_sz = ADMA2_64_DESC_SZ; -+ phytium_mci_init_adma_table(host, &host->dma); -+ } else { -+ mmc->max_segs = MAX_BD_NUM; -+ mmc->max_seg_size = 4 * 1024; -+ mmc->max_blk_size = 512; -+ mmc->max_req_size = 4 * 512; -+ mmc->max_blk_count = mmc->max_req_size / 512; -+ } -+ -+ spin_lock_init(&host->lock); -+ -+ phytium_mci_init_hw(host); -+ ret = devm_request_irq(host->dev, host->irq, phytium_mci_irq, -+ host->irq_flags, "phytium-mci", host); -+ -+ if (ret) -+ return ret; -+ -+ ret = mmc_add_host(mmc); -+ -+ if (ret) { -+ dev_err(host->dev, "%s %d: mmc add host!\n", __func__, __LINE__); -+ return ret; -+ } -+ return 0; -+} -+EXPORT_SYMBOL(phytium_mci_common_probe); -+ -+MODULE_DESCRIPTION("Phytium Multimedia Card Interface driver"); -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Cheng Quan <chengquan@phytium.com.cn>"); -diff --git a/drivers/mmc/host/phytium-mci.h b/drivers/mmc/host/phytium-mci.h -new file mode 100644 -index 0000000..8006fb4 ---- /dev/null -+++ b/drivers/mmc/host/phytium-mci.h -@@ -0,0 +1,355 @@ -+/* SPDX-License-Identifier: GPL-2.0+ */ -+/* -+ * Driver for Phytium Multimedia Card Interface -+ * -+ * Copyright (C) 2021-2023, Phytium Technology Co., Ltd. -+ */ -+ -+#ifndef __PHYTIUM_MCI_H -+#define __PHYTIUM_MCI_H -+ -+#include <linux/scatterlist.h> -+#include <linux/compiler.h> -+#include <linux/types.h> -+#include <linux/io.h> -+#include <linux/iopoll.h> -+#include <linux/interrupt.h> -+#include <linux/mmc/host.h> -+ -+/*------------------------------------------------------*/ -+/* Common Definition */ -+/*------------------------------------------------------*/ -+#define MAX_BD_NUM 128 -+#define SD_BLOCK_SIZE 512 -+ -+#define MCI_BUS_1BITS 0x0 -+#define MCI_BUS_4BITS 0x1 -+#define MCI_BUS_8BITS (0x1 << 16) -+ -+#define MCI_SD_DRV_VALUE 0 -+#define MCI_SD_SAMP_VALUE_MAX 0 -+#define MCI_SD_SAMP_VALUE_MIN 0 -+ -+#define MCI_TIMEOUT_CMD_VALUE 0xFFFFFFFF -+#define MCI_POWER_ON 1 -+#define MCI_POWER_OFF 0 -+ -+#define MCI_PREPARE_FLAG (0x1 << 0) -+#define MCI_ASYNC_FLAG (0x1 << 1) -+#define MCI_MMAP_FLAG (0x1 << 2) -+ -+#define MCI_CMD_TIMEOUT (HZ/10 * 50) /* 100ms x5 */ -+#define MCI_DATA_TIMEOUT (HZ * 10) /* 1000ms x5 */ -+ -+#define MCI_CMD_TYPE_ADTC 0x2 -+ -+#define MCI_F_MIN 400000 -+#define MCI_F_MAX 50000000 -+ -+#define MCI_CLK 1200000000 -+#define MCI_REALEASE_MEM 0x1 -+#define MCI_MAX_FIFO_CNT 0x800 -+ -+/* FIFOTH register defines */ -+#define MCI_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \ -+ ((r) & 0xFFF) << 16 | ((t) & 0xFFF)) -+/* Card read threshold */ -+#define MCI_SET_THLD(v, x) (((v) & 0xFFF) << 16 | (x)) -+#define MCI_CARD_WR_THR_EN BIT(2) -+#define MCI_CARD_RD_THR_EN BIT(0) -+ -+/*----------------------------------------------------------------------*/ -+/* Register Offset */ -+/*----------------------------------------------------------------------*/ -+#define MCI_CNTRL 0x00 /* the controller config reg */ -+#define MCI_PWREN 0x04 /* the power enable reg */ -+#define MCI_CLKDIV 0x08 /* the clock divider reg */ -+#define MCI_CLKENA 0x10 /* the clock enable reg */ -+#define MCI_TMOUT 0x14 /* the timeout reg */ -+#define MCI_CTYPE 0x18 /* the card type reg */ -+#define MCI_BLKSIZ 0x1C /* the block size reg */ -+#define MCI_BYTCNT 0x20 /* the byte count reg */ -+#define MCI_INT_MASK 0x24 /* the interrupt mask reg */ -+#define MCI_CMDARG 0x28 /* the command argument reg */ -+#define MCI_CMD 0x2C /* the command reg */ -+#define MCI_RESP0 0x30 /* the response reg0 */ -+#define MCI_RESP1 0x34 /* the response reg1 */ -+#define MCI_RESP2 0x38 /* the response reg2 */ -+#define MCI_RESP3 0X3C /* the response reg3 */ -+#define MCI_MASKED_INTS 0x40 /* the masked interrupt status reg */ -+#define MCI_RAW_INTS 0x44 /* the raw interrupt status reg */ -+#define MCI_STATUS 0x48 /* the status reg */ -+#define MCI_FIFOTH 0x4C /* the FIFO threshold watermark reg */ -+#define MCI_CARD_DETECT 0x50 /* the card detect reg */ -+#define MCI_CARD_WRTPRT 0x54 /* the card write protect reg */ -+#define MCI_CCLK_RDY 0x58 /* first div is ready? 1:ready,0:not ready*/ -+#define MCI_TRAN_CARD_CNT 0x5C /* the transferred CIU card byte count reg */ -+#define MCI_TRAN_FIFO_CNT 0x60 /* the transferred host to FIFO byte count reg */ -+#define MCI_DEBNCE 0x64 /* the debounce count reg */ -+#define MCI_UID 0x68 /* the user ID reg */ -+#define MCI_VID 0x6C /* the controller version ID reg */ -+#define MCI_HWCONF 0x70 /* the hardware configuration reg */ -+#define MCI_UHS_REG 0x74 /* the UHS-I reg */ -+#define MCI_CARD_RESET 0x78 /* the card reset reg */ -+#define MCI_BUS_MODE 0x80 /* the bus mode reg */ -+#define MCI_DESC_LIST_ADDRL 0x88 /* the descriptor list low base address reg */ -+#define MCI_DESC_LIST_ADDRH 0x8C /* the descriptor list high base address reg */ -+#define MCI_DMAC_STATUS 0x90 /* the internal DMAC status reg */ -+#define MCI_DMAC_INT_ENA 0x94 /* the internal DMAC interrupt enable reg */ -+#define MCI_CUR_DESC_ADDRL 0x98 /* the current host descriptor low address reg */ -+#define MCI_CUR_DESC_ADDRH 0x9C /* the current host descriptor high address reg */ -+#define MCI_CUR_BUF_ADDRL 0xA0 /* the current buffer low address reg */ -+#define MCI_CUR_BUF_ADDRH 0xA4 /* the current buffer high address reg */ -+#define MCI_CARD_THRCTL 0x100 /* the card threshold control reg */ -+#define MCI_UHS_REG_EXT 0x108 /* the UHS register extension */ -+#define MCI_EMMC_DDR_REG 0x10C /* the EMMC DDR reg */ -+#define MCI_ENABLE_SHIFT 0x110 /* the enable phase shift reg */ -+#define MCI_DATA 0x200 /* the data FIFO access */ -+ -+/* Command register defines */ -+#define MCI_CMD_START BIT(31) -+#define MCI_CMD_USE_HOLD_REG BIT(29) -+#define MCI_CMD_VOLT_SWITCH BIT(28) -+#define MCI_CMD_CCS_EXP BIT(23) -+#define MCI_CMD_CEATA_RD BIT(22) -+#define MCI_CMD_UPD_CLK BIT(21) -+#define MCI_CMD_INIT BIT(15) -+#define MCI_CMD_STOP BIT(14) -+#define MCI_CMD_PRV_DAT_WAIT BIT(13) -+#define MCI_CMD_SEND_STOP BIT(12) -+#define MCI_CMD_STRM_MODE BIT(11) -+#define MCI_CMD_DAT_WR BIT(10) -+#define MCI_CMD_DAT_EXP BIT(9) -+#define MCI_CMD_RESP_CRC BIT(8) -+#define MCI_CMD_RESP_LONG BIT(7) -+#define MCI_CMD_RESP_EXP BIT(6) -+#define MCI_CMD_INDX(n) ((n) & 0x1F) -+ -+/*------------------------------------------------------*/ -+/* Register Mask */ -+/*------------------------------------------------------*/ -+/* MCI_CNTRL mask */ -+#define MCI_CNTRL_CONTROLLER_RESET (0x1 << 0) /* RW */ -+#define MCI_CNTRL_FIFO_RESET (0x1 << 1) /* RW */ -+#define MCI_CNTRL_DMA_RESET (0x1 << 2) /* RW */ -+#define MCI_CNTRL_RES (0x1 << 3) /* */ -+#define MCI_CNTRL_INT_ENABLE (0x1 << 4) /* RW */ -+#define MCI_CNTRL_DMA_ENABLE (0x1 << 5) /* RW */ -+#define MCI_CNTRL_READ_WAIT (0x1 << 6) /* RW */ -+#define MCI_CNTRL_SEND_IRQ_RESPONSE (0x1 << 7) /* RW */ -+#define MCI_CNTRL_ABORT_READ_DATA (0x1 << 8) /* RW */ -+#define MCI_CNTRL_ENDIAN (0x1 << 11) /* RW */ -+//#define MCI_CNTRL_CARD_VOLTAGE_A (0xF << 16) /* RW */ -+//#define MCI_CNTRL_CARD_VOLTAGE_B (0xF << 20) /* RW */ -+#define MCI_CNTRL_ENABLE_OD_PULLUP (0x1 << 24) /* RW */ -+#define MCI_CNTRL_USE_INTERNAL_DMAC (0x1 << 25) /* RW */ -+ -+/* MCI_PWREN mask */ -+#define MCI_PWREN_ENABLE (0x1 << 0) /* RW */ -+ -+/* MCI_CLKENA mask */ -+#define MCI_CLKENA_CCLK_ENABLE (0x1 << 0) /* RW */ -+#define MCI_CLKENA_CCLK_LOW_POWER (0x1 << 16) /* RW */ -+#define MCI_EXT_CLK_ENABLE (0x1 << 1) -+ -+/* MCI_INT_MASK mask */ -+#define MCI_INT_MASK_CD (0x1 << 0) /* RW */ -+#define MCI_INT_MASK_RE (0x1 << 1) /* RW */ -+#define MCI_INT_MASK_CMD (0x1 << 2) /* RW */ -+#define MCI_INT_MASK_DTO (0x1 << 3) /* RW */ -+#define MCI_INT_MASK_TXDR (0x1 << 4) /* RW */ -+#define MCI_INT_MASK_RXDR (0x1 << 5) /* RW */ -+#define MCI_INT_MASK_RCRC (0x1 << 6) /* RW */ -+#define MCI_INT_MASK_DCRC (0x1 << 7) /* RW */ -+#define MCI_INT_MASK_RTO (0x1 << 8) /* RW */ -+#define MCI_INT_MASK_DRTO (0x1 << 9) /* RW */ -+#define MCI_INT_MASK_HTO (0x1 << 10) /* RW */ -+#define MCI_INT_MASK_FRUN (0x1 << 11) /* RW */ -+#define MCI_INT_MASK_HLE (0x1 << 12) /* RW */ -+#define MCI_INT_MASK_SBE_BCI (0x1 << 13) /* RW */ -+#define MCI_INT_MASK_ACD (0x1 << 14) /* RW */ -+#define MCI_INT_MASK_EBE (0x1 << 15) /* RW */ -+#define MCI_INT_MASK_SDIO (0x1 << 16) /* RW */ -+ -+/* MCI_MASKED_INTS mask */ -+#define MCI_MASKED_INTS_CD (0x1 << 0) /* RO */ -+#define MCI_MASKED_INTS_RE (0x1 << 1) /* RO */ -+#define MCI_MASKED_INTS_CMD (0x1 << 2) /* RO */ -+#define MCI_MASKED_INTS_DTO (0x1 << 3) /* RO */ -+#define MCI_MASKED_INTS_TXDR (0x1 << 4) /* RO */ -+#define MCI_MASKED_INTS_RXDR (0x1 << 5) /* RO */ -+#define MCI_MASKED_INTS_RCRC (0x1 << 6) /* RO */ -+#define MCI_MASKED_INTS_DCRC (0x1 << 7) /* RO */ -+#define MCI_MASKED_INTS_RTO (0x1 << 8) /* RO */ -+#define MCI_MASKED_INTS_DRTO (0x1 << 9) /* RO */ -+#define MCI_MASKED_INTS_HTO (0x1 << 10) /* RO */ -+#define MCI_MASKED_INTS_FRUN (0x1 << 11) /* RO */ -+#define MCI_MASKED_INTS_HLE (0x1 << 12) /* RO */ -+#define MCI_MASKED_INTS_SBE_BCI (0x1 << 13) /* RO */ -+#define MCI_MASKED_INTS_ACD (0x1 << 14) /* RO */ -+#define MCI_MASKED_INTS_EBE (0x1 << 15) /* RO */ -+#define MCI_MASKED_INTS_SDIO (0x1 << 16) /* RO */ -+ -+/* MCI_RAW_INTS mask */ -+#define MCI_RAW_INTS_CD (0x1 << 0) /* W1C */ -+#define MCI_RAW_INTS_RE (0x1 << 1) /* W1C */ -+#define MCI_RAW_INTS_CMD (0x1 << 2) /* W1C */ -+#define MCI_RAW_INTS_DTO (0x1 << 3) /* W1C */ -+#define MCI_RAW_INTS_TXDR (0x1 << 4) /* W1C */ -+#define MCI_RAW_INTS_RXDR (0x1 << 5) /* W1C */ -+#define MCI_RAW_INTS_RCRC (0x1 << 6) /* W1C */ -+#define MCI_RAW_INTS_DCRC (0x1 << 7) /* W1C */ -+#define MCI_RAW_INTS_RTO (0x1 << 8) /* W1C */ -+#define MCI_RAW_INTS_DRTO (0x1 << 9) /* W1C */ -+#define MCI_RAW_INTS_HTO (0x1 << 10) /* W1C */ -+#define MCI_RAW_INTS_FRUN (0x1 << 11) /* W1C */ -+#define MCI_RAW_INTS_HLE (0x1 << 12) /* W1C */ -+#define MCI_RAW_INTS_SBE_BCI (0x1 << 13) /* W1C */ -+#define MCI_RAW_INTS_ACD (0x1 << 14) /* W1C */ -+#define MCI_RAW_INTS_EBE (0x1 << 15) /* W1C */ -+#define MCI_RAW_INTS_SDIO (0x1 << 16) /* W1C */ -+ -+/* MCI_STATUS mask */ -+#define MCI_STATUS_FIFO_RX (0x1 << 0) /* RO */ -+#define MCI_STATUS_FIFO_TX (0x1 << 1) /* RO */ -+#define MCI_STATUS_FIFO_EMPTY (0x1 << 2) /* RO */ -+#define MCI_STATUS_FIFO_FULL (0x1 << 3) /* RO */ -+#define MCI_STATUS_CARD_STATUS (0x1 << 8) /* RO */ -+#define MCI_STATUS_CARD_BUSY (0x1 << 9) /* RO */ -+#define MCI_STATUS_DATA_BUSY (0x1 << 10) /* RO */ -+#define MCI_STATUS_DMA_ACK (0x1 << 31) /* RO */ -+#define MCI_STATUS_DMA_REQ (0x1 << 32) /* RO */ -+ -+/* MCI_UHS_REG mask */ -+#define MCI_UHS_REG_VOLT (0x1 << 0) /* RW */ -+#define MCI_UHS_REG_DDR (0x1 << 16) /* RW */ -+ -+/* MCI_CARD_RESET mask */ -+#define MCI_CARD_RESET_ENABLE (0x1 << 0) /* RW */ -+ -+/* MCI_BUS_MODE mask */ -+#define MCI_BUS_MODE_SWR (0x1 << 0) /* RW */ -+#define MCI_BUS_MODE_FB (0x1 << 1) /* RW */ -+#define MCI_BUS_MODE_DE (0x1 << 7) /* RW */ -+ -+/* MCI_DMAC_STATUS mask */ -+#define MCI_DMAC_STATUS_TI (0x1 << 0) /* RW */ -+#define MCI_DMAC_STATUS_RI (0x1 << 1) /* RW */ -+#define MCI_DMAC_STATUS_FBE (0x1 << 2) /* RW */ -+#define MCI_DMAC_STATUS_DU (0x1 << 4) /* RW */ -+#define MCI_DMAC_STATUS_NIS (0x1 << 8) /* RW */ -+#define MCI_DMAC_STATUS_AIS (0x1 << 9) /* RW */ -+ -+/* MCI_DMAC_INT_ENA mask */ -+#define MCI_DMAC_INT_ENA_TI (0x1 << 0) /* RW */ -+#define MCI_DMAC_INT_ENA_RI (0x1 << 1) /* RW */ -+#define MCI_DMAC_INT_ENA_FBE (0x1 << 2) /* RW */ -+#define MCI_DMAC_INT_ENA_DU (0x1 << 4) /* RW */ -+#define MCI_DMAC_INT_ENA_CES (0x1 << 5) /* RW */ -+#define MCI_DMAC_INT_ENA_NIS (0x1 << 8) /* RW */ -+#define MCI_DMAC_INT_ENA_AIS (0x1 << 9) /* RW */ -+ -+/* MCI_CARD_THRCTL mask */ -+#define MCI_CARD_THRCTL_CARDRD (0x1 << 0) /* RW */ -+#define MCI_CARD_THRCTL_BUSY_CLR (0x1 << 1) /* RW */ -+#define MCI_CARD_THRCTL_CARDWR (0x1 << 2) /* RW */ -+ -+/* MCI_UHS_REG_EXT mask */ -+#define MCI_UHS_REG_EXT_MMC_VOLT (0x1 << 0) /* RW */ -+#define MCI_UHS_REG_EXT_CLK_ENA (0x1 << 1) /* RW */ -+ -+/* MCI_EMMC_DDR_REG mask */ -+#define MCI_EMMC_DDR_CYCLE (0x1 << 0) /* RW */ -+ -+/*--------------------------------------*/ -+/* Structure Type */ -+/*--------------------------------------*/ -+/* Maximum segments assuming a 512KiB maximum requisition */ -+/* size and a minimum4KiB page size. */ -+#define MCI_MAX_SEGS 128 -+/* ADMA2 64-bit DMA descriptor size */ -+#define ADMA2_64_DESC_SZ 32 -+ -+/* Each descriptor can transfer up to 4KB of data in chained mode */ -+/*ADMA2 64-bit descriptor.*/ -+struct phytium_adma2_64_desc { -+ u32 attribute; -+#define IDMAC_DES0_DIC BIT(1) -+#define IDMAC_DES0_LD BIT(2) -+#define IDMAC_DES0_FD BIT(3) -+#define IDMAC_DES0_CH BIT(4) -+#define IDMAC_DES0_ER BIT(5) -+#define IDMAC_DES0_CES BIT(30) -+#define IDMAC_DES0_OWN BIT(31) -+ u32 NON1; -+ u32 len; -+ u32 NON2; -+ u32 addr_lo; /* Lower 32-bits of Buffer Address Pointer 1*/ -+ u32 addr_hi; /* Upper 32-bits of Buffer Address Pointer 1*/ -+ u32 desc_lo; /* Lower 32-bits of Next Descriptor Address */ -+ u32 desc_hi; /* Upper 32-bits of Next Descriptor Address */ -+} __packed __aligned(4); -+ -+struct phytium_mci_dma { -+ struct scatterlist *sg; /* I/O scatter list */ -+ /* ADMA descriptor table, pointer to adma_table array */ -+ struct phytium_adma2_64_desc *adma_table; -+ /* Mapped ADMA descr. table, the physical address of adma_table array */ -+ dma_addr_t adma_addr; -+ unsigned int desc_sz; /* ADMA descriptor size */ -+}; -+ -+enum adtc_t { -+ COMMOM_ADTC = 0, -+ BLOCK_RW_ADTC = 1 -+}; -+ -+struct phytium_mci_host { -+ struct device *dev; -+ struct mmc_host *mmc; -+ u32 caps; -+ u32 caps2; -+ spinlock_t lock; -+ struct mmc_request *mrq; -+ struct mmc_command *cmd; -+ struct mmc_data *data; -+ int error; -+ void __iomem *base; /* host base address */ -+ void *adma_table1; -+ dma_addr_t adma_addr1; -+ struct phytium_mci_dma dma_rx; /* dma channel */ -+ struct phytium_mci_dma dma_tx; /* dma channel */ -+ struct phytium_mci_dma dma; /* dma channel */ -+ u64 dma_mask; -+ bool vqmmc_enabled; -+ u32 *sg_virt_addr; -+ enum adtc_t adtc_type; /* 0:common adtc cmd; 1:block r/w adtc cmd;*/ -+ struct timer_list hotplug_timer; -+ struct delayed_work req_timeout; -+ int irq; /* host interrupt */ -+ u32 current_rca; /*the current rca value*/ -+ u32 current_ios_clk; -+ u32 is_use_dma; -+ u32 is_device_x100; -+ struct clk *src_clk; /* phytium_mci source clock */ -+ unsigned long clk_rate; -+ unsigned long clk_div; -+ unsigned long irq_flags; -+ unsigned long flags; -+#define MCI_CARD_NEED_INIT 1 -+ bool use_hold; /*use hold reg*/ -+ bool clk_set; /*clock set function enable*/ -+ s32 clk_smpl_drv_25m; /*25M clk smpl & drv*/ -+ s32 clk_smpl_drv_50m; /*50M clk smpl & drv*/ -+ s32 clk_smpl_drv_66m; /*66M clk smpl & drv*/ -+ s32 clk_smpl_drv_100m; /*100M clk smpl & drv*/ -+}; -+ -+int phytium_mci_common_probe(struct phytium_mci_host *host); -+void phytium_mci_deinit_hw(struct phytium_mci_host *host); -+int phytium_mci_runtime_suspend(struct device *dev); -+int phytium_mci_runtime_resume(struct device *dev); -+int phytium_mci_resume(struct device *dev); -+int phytium_mci_suspend(struct device *dev); -+ -+#endif /* __PHYTIUM_MCI_HW_H */ -diff --git a/drivers/mmc/host/phytium-sdci.c b/drivers/mmc/host/phytium-sdci.c -new file mode 100644 -index 0000000..9453cc9 ---- /dev/null -+++ b/drivers/mmc/host/phytium-sdci.c -@@ -0,0 +1,1440 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Phytium SDCI dirver -+ * -+ * Copyright (C) 2019-2023, Phytium Technology Co., Ltd. -+ * -+ * 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 <linux/module.h> -+#include <linux/clk.h> -+#include <linux/delay.h> -+#include <linux/dma-mapping.h> -+#include <linux/ioport.h> -+#include <linux/irq.h> -+#include <linux/of_address.h> -+#include <linux/of_irq.h> -+#include <linux/of_gpio.h> -+#include <linux/pinctrl/consumer.h> -+#include <linux/platform_device.h> -+#include <linux/pm.h> -+#include <linux/pm_runtime.h> -+#include <linux/regulator/consumer.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+#include <linux/interrupt.h> -+#include <linux/acpi.h> -+#include <linux/timer.h> -+ -+#include <linux/mmc/card.h> -+#include <linux/mmc/core.h> -+#include <linux/mmc/host.h> -+#include <linux/mmc/mmc.h> -+#include <linux/mmc/sd.h> -+#include <linux/mmc/sdio.h> -+ -+#include "phytium-sdci.h" -+ -+static const u32 cmd_ints_mask = SDCI_SDCI_NORMAL_ISER_ECC_EN | SDCI_SDCI_NORMAL_ISER_EEI_EN; -+static const u32 data_ints_mask = SDCI_BD_ISER_ETRS_EN; -+static const u32 err_ints_mask = SDCI_ERROR_ISER_ECTE_EN | SDCI_ERROR_ISR_CCRCE_EN | -+ SDCI_ERROR_ISR_CIR_EN | SDCI_ERROR_ISR_CNR_EN; -+ -+static void hotplug_timer_func(struct timer_list *t); -+static bool phytium_sdci_private_send_cmd(struct phytium_sdci_host *host, -+ u32 cmd, u32 resp_type, u32 arg); -+static bool phytium_sdci_cmd_done(struct phytium_sdci_host *host, int events, -+ struct mmc_request *mrq, -+ struct mmc_command *cmd); -+static bool phytium_sdci_data_xfer_done(struct phytium_sdci_host *host, -+ u32 events, struct mmc_request *mrq, -+ struct mmc_data *data); -+static void phytium_sdci_cmd_next(struct phytium_sdci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_command *cmd); -+ -+static int phytium_sdci_cmd13_process(struct phytium_sdci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_data *data, -+ u32 wait_timeout_ms, -+ u32 send_once_time_ms); -+ -+static int phytium_sd_error(struct phytium_sdci_host *host) -+{ -+ int temp; -+ -+ temp = readl(host->base + SDCI_NORMAL_ISR); -+ dev_err(host->dev, "[%s %d]SDCI_NORMAL_ISR:%x\n", __func__, __LINE__, temp); -+ temp = readl(host->base + SDCI_BD_ISR); -+ temp = readl(host->base + SDCI_ERROR_ISR); -+ dev_err(host->dev, "[%s %d]SDCI_ERROR_ISR:%x\n", __func__, __LINE__, temp); -+ temp = readl(host->base + SDCI_BD_ISR); -+ dev_err(host->dev, "[%s %d]SDCI_BD_ISR:%x\n", __func__, __LINE__, temp); -+ temp = readl(host->base + SDCI_RESP0); -+ dev_err(host->dev, "[%s %d]SDCI_RESP0:%x\n", __func__, __LINE__, temp); -+ -+ return 0; -+} -+ -+static void sdr_set_bits(void __iomem *reg, u32 bs) -+{ -+ u32 val; -+ -+ val = readl(reg); -+ val |= bs; -+ -+ writel(val, reg); -+} -+ -+static void sdr_clr_bits(void __iomem *reg, u32 bs) -+{ -+ u32 val; -+ -+ val = readl(reg); -+ val &= ~bs; -+ -+ writel(val, reg); -+} -+ -+static void phytium_sdci_reset_hw(struct phytium_sdci_host *host) -+{ -+ sdr_set_bits(host->base + SDCI_SOFTWARE, -+ SDCI_SOFTWARE_SRST); -+ sdr_clr_bits(host->base + SDCI_SOFTWARE, -+ SDCI_SOFTWARE_SRST); -+ while (!(readl(host->base + SDCI_STATUS) & SDCI_STATUS_IDIE)) -+ cpu_relax(); -+} -+ -+static void phytium_sdci_prepare_data(struct phytium_sdci_host *host, -+ struct mmc_request *mrq) -+{ -+ struct mmc_data *data = mrq->data; -+ bool read; -+ -+ read = (data->flags & MMC_DATA_READ) != 0; -+ data->sg_count = dma_map_sg(host->dev, data->sg, data->sg_len, -+ read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); -+} -+ -+static void phytium_sdci_unprepare_data(struct phytium_sdci_host *host, -+ struct mmc_request *mrq) -+{ -+ bool read; -+ struct mmc_data *data = mrq->data; -+ -+ read = (data->flags & MMC_DATA_READ) != 0; -+ dma_unmap_sg(host->dev, data->sg, data->sg_len, -+ read ? DMA_FROM_DEVICE : DMA_TO_DEVICE); -+} -+ -+static void phytium_sdci_set_clk(struct phytium_sdci_host *host, -+ struct mmc_ios *ios) -+{ -+ unsigned long clk_rate; -+ u32 div = 0xffffffff, div_reg; -+ -+ if (ios->clock) { -+ clk_rate = host->clk_rate; -+ div = ((clk_rate / (2 * ios->clock)) - 1); -+ div_reg = readl(host->base + SDCI_CLOCK_D); -+ if (div_reg == div) -+ return; -+ writel(div, host->base + SDCI_CLOCK_D); -+ writel(0, host->base + SDCI_SD_DRV); -+ writel(5, host->base + SDCI_SD_SAMP); -+ -+ sdr_set_bits(host->base + SDCI_SOFTWARE, SDCI_SOFTWARE_SRST); -+ sdr_clr_bits(host->base + SDCI_SOFTWARE, SDCI_SOFTWARE_SRST); -+ while (!(readl(host->base + SDCI_STATUS) & SDCI_STATUS_IDIE)) -+ cpu_relax(); -+ dev_dbg(host->dev, "host->clk_rate: %ld, ios->clock: %d\n", -+ host->clk_rate, ios->clock); -+ } -+} -+ -+ -+static inline u32 phytium_sdci_cmd_find_resp(struct phytium_sdci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_command *cmd) -+{ -+ u32 resp; -+ -+ switch (mmc_resp_type(cmd)) { -+ case MMC_RSP_R1: -+ resp = 0x2; -+ break; -+ case MMC_RSP_R1B: -+ resp = 0x2; -+ break; -+ case MMC_RSP_R2: -+ resp = 0x1; -+ break; -+ case MMC_RSP_R3: -+ resp = 0x3; -+ break; -+ case MMC_RSP_NONE: -+ default: -+ resp = 0x0; -+ break; -+ } -+ -+ return resp; -+} -+ -+static inline u32 phytium_sdci_cmd_prepare_raw_cmd(struct phytium_sdci_host *host, -+ struct mmc_request *mrq, struct mmc_command *cmd) -+{ -+ /* -+ * rawcmd : -+ * trty << 14 | opcode << 8 | cmdw << 6 | cice << 4 | crce << 3 | resp -+ */ -+ u32 resp, rawcmd; -+ u32 opcode = cmd->opcode; -+ -+ resp = phytium_sdci_cmd_find_resp(host, mrq, cmd); -+ rawcmd = ((opcode << 8) | resp); -+ -+ if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) -+ rawcmd = (rawcmd | (SDCI_CMD_TYPE_ADTC << 14)); -+ -+ return rawcmd; -+} -+ -+static void -+phytium_sdci_unexpected_error_handler(struct phytium_sdci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_data *data, -+ int err_type) -+{ -+ unsigned long flags; -+ int error; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ host->mrq = NULL; -+ host->cmd = NULL; -+ host->data = NULL; -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if (err_type & ERR_CARD_ABSENT) { -+ host->mmc->detect_change = 1; -+ dev_dbg(host->dev, "SD is absent when send cmd:%d\n", mrq->cmd->opcode); -+ } -+ -+ switch (err_type) { -+ case ERR_CARD_ABSENT: -+ error = -ENOMEDIUM; -+ break; -+ case ERR_TIMEOUT: -+ error = -ETIMEDOUT; -+ break; -+ case ERR_CMD_RESPONED: -+ error = -EIO; -+ break; -+ default: -+ error = -ETIMEDOUT; -+ break; -+ } -+ -+ if (data) { -+ data->error = error; -+ phytium_sdci_unprepare_data(host, mrq); -+ -+ if ((data->flags & MMC_DATA_READ) == MMC_DATA_READ || -+ (data->flags & MMC_DATA_WRITE) == MMC_DATA_WRITE) -+ phytium_sdci_data_xfer_done(host, SDCI_BD_ISR_TRS_R, mrq, data); -+ } else { -+ mrq->cmd->error = error; -+ } -+ -+ mmc_request_done(host->mmc, mrq); -+} -+ -+static bool phytium_sdci_start_data(struct phytium_sdci_host *host, struct mmc_request *mrq, -+ struct mmc_command *cmd, struct mmc_data *data) -+{ -+ bool read, res; -+ u32 sg_dma_addrh, sg_dma_addrl; -+ u32 sd_block_addrh, sd_block_addrl; -+ u32 temp, timeout, sd_status; -+ u32 block_cnt = 0; -+ u32 sd_block_addr = cmd->arg; -+ u32 private_cmd, resp_type, arg; -+ u32 j, dma_len; -+ unsigned long deadline_time; -+ dma_addr_t dma_address; -+ struct scatterlist *sg; -+ int ret; -+ -+ WARN_ON(host->cmd); -+ host->cmd = cmd; -+ -+ WARN_ON(host->data); -+ host->data = data; -+ read = data->flags & MMC_DATA_READ; -+ -+ for_each_sg(data->sg, sg, data->sg_count, j) { -+ writel(0, host->base + SDCI_COMMAND); -+ -+ dma_address = sg_dma_address(sg); -+ sg_dma_addrh = (u32) (dma_address >> 32); -+ sg_dma_addrl = (u32) dma_address; -+ -+ dma_len = sg_dma_len(sg); -+ block_cnt = (dma_len / SD_BLOCK_SIZE); -+ -+ sd_block_addrh = 0; -+ sd_block_addrl = sd_block_addr; -+ -+ sdr_set_bits(host->base + SDCI_SOFTWARE, SDCI_SOFTWARE_BDRST); -+ sdr_clr_bits(host->base + SDCI_SOFTWARE, SDCI_SOFTWARE_BDRST); -+ writel(block_cnt, host->base + SDCI_BLK_CNT); -+ -+ if ((mrq->data->flags & MMC_DATA_READ) == MMC_DATA_READ) { -+ writel(sg_dma_addrl, host->base + SDCI_BD_RX); -+ writel(sg_dma_addrh, host->base + SDCI_BD_RX); -+ writel(sd_block_addrl, host->base + SDCI_BD_RX); -+ writel(sd_block_addrh, host->base + SDCI_BD_RX); -+ timeout = 100 * block_cnt; -+ } else { -+ timeout = 250 * block_cnt; -+ ret = phytium_sdci_cmd13_process(host, mrq, data, timeout, 1); -+ if (ret != SDCI_CMD13_OK) -+ return false; -+ -+ writel(sg_dma_addrl, host->base + SDCI_BD_TX); -+ writel(sg_dma_addrh, host->base + SDCI_BD_TX); -+ writel(sd_block_addrl, host->base + SDCI_BD_TX); -+ writel(sd_block_addrh, host->base + SDCI_BD_TX); -+ } -+ -+ deadline_time = jiffies + msecs_to_jiffies(timeout); -+ -+ temp = readl(host->base + SDCI_BD_ISR); -+ if ((mrq->data->flags & MMC_DATA_READ) == MMC_DATA_READ) { -+ while ((temp & SDCI_BD_ISR_TRS_R) != SDCI_BD_ISR_TRS_R) { -+ sd_status = readl(host->base + SDCI_STATUS); -+ if (sd_status & SDCI_STATUS_CDSL) { -+ phytium_sdci_unexpected_error_handler(host, mrq, data, -+ ERR_CARD_ABSENT); -+ if (temp & SDCI_BD_ISR_DAIS) -+ writel(1, host->base + SDCI_BD_ISR); -+ return false; -+ } -+ -+ temp = readl(host->base + SDCI_BD_ISR); -+ if (time_after(jiffies, deadline_time)) { -+ phytium_sdci_unexpected_error_handler(host, mrq, data, -+ ERR_TIMEOUT); -+ dev_err(host->dev, -+ "Read Data timeout:jiffies:0x%lx,dt_jiffies:0x%lx, BD_isr_reg:0x%x,cmd:%d, REG_D0:0x%x\n", -+ jiffies, jiffies - deadline_time, temp, -+ cmd->opcode, readl(host->base + SDCI_STATUS)); -+ -+ return false; -+ } -+ } -+ } else { -+ while ((temp & SDCI_BD_ISR_TRS_W) != SDCI_BD_ISR_TRS_W) { -+ sd_status = readl(host->base + SDCI_STATUS); -+ if (sd_status & SDCI_STATUS_CDSL) { -+ phytium_sdci_unexpected_error_handler(host, mrq, data, -+ ERR_CARD_ABSENT); -+ dev_err(host->dev, "[%s][%d]: Card absent ! cmd(%d)\n", -+ __func__, __LINE__, mrq->cmd->opcode); -+ return false; -+ } -+ -+ temp = readl(host->base + SDCI_BD_ISR); -+ if (time_after(jiffies, deadline_time)) { -+ phytium_sdci_unexpected_error_handler(host, mrq, data, -+ ERR_TIMEOUT); -+ dev_err(host->dev, -+ "Write Date timeout: jiffies:0x%lx,dt_jiffies:0x%lx,BD_isr_reg:0x%x\n", -+ jiffies, jiffies - deadline_time, temp); -+ return false; -+ } -+ } -+ } -+ writel(1, host->base + SDCI_BD_ISR); -+ writel(1, host->base + SDCI_NORMAL_ISR); -+ sd_block_addr = sd_block_addr + block_cnt; -+ -+ if (j < (data->sg_count - 1) && 1 < block_cnt) { -+ private_cmd = MMC_STOP_TRANSMISSION; -+ resp_type = 0x2; -+ arg = 0; -+ res = phytium_sdci_private_send_cmd(host, private_cmd, -+ resp_type, arg); -+ if (!res) { -+ sd_status = readl(host->base + SDCI_STATUS); -+ if (sd_status & SDCI_STATUS_CDSL) { -+ phytium_sdci_unexpected_error_handler(host, mrq, data, -+ ERR_CARD_ABSENT); -+ writel(1, host->base + SDCI_BD_ISR); -+ dev_err(host->dev, -+ "[%s][%d]:Card absent ! private_cmd(%d)\n", -+ __func__, __LINE__, private_cmd); -+ } else { -+ phytium_sdci_unexpected_error_handler(host, mrq, data, -+ ERR_CMD_RESPONED); -+ dev_err(host->dev, -+ "[%s][%d] cmd(%d) response errored\n", -+ __func__, __LINE__, mrq->cmd->opcode); -+ phytium_sd_error(host); -+ } -+ writel(1, host->base + SDCI_NORMAL_ISR); -+ return false; -+ } -+ writel(1, host->base + SDCI_NORMAL_ISR); -+ } -+ } -+ -+ host->is_multi_rw_only_one_blkcnt = false; -+ -+ if ((cmd->opcode == MMC_READ_MULTIPLE_BLOCK && block_cnt == 1) || -+ (cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK && block_cnt == 1)) -+ host->is_multi_rw_only_one_blkcnt = true; -+ -+ phytium_sdci_cmd_done(host, SDCI_NORMAL_ISR_CC, mrq, cmd); -+ if ((mrq->data->flags & MMC_DATA_READ) == MMC_DATA_READ) -+ phytium_sdci_data_xfer_done(host, SDCI_BD_ISR_TRS_R, -+ mrq, data); -+ else -+ phytium_sdci_data_xfer_done(host, SDCI_BD_ISR_TRS_W, -+ mrq, data); -+ -+ return true; -+} -+ -+static int phytium_sdci_auto_cmd_done(struct phytium_sdci_host *host, -+ int events, struct mmc_command *cmd) -+{ -+ u32 *rsp = cmd->resp; -+ -+ rsp[0] = readl(host->base + SDCI_RESP0); -+ -+ if (events & SDCI_NORMAL_ISR_CC) -+ cmd->error = 0; -+ else { -+ phytium_sdci_reset_hw(host); -+ dev_err(host->dev, -+ "%s: AUTO_CMD%d arg=%08X; rsp %08X; cmd_error=%d\n", -+ __func__, cmd->opcode, cmd->arg, rsp[0], cmd->error); -+ } -+ -+ return cmd->error; -+} -+ -+static void phytium_sdci_track_cmd_data(struct phytium_sdci_host *host, -+ struct mmc_command *cmd, -+ struct mmc_data *data) -+{ -+ if (host->error) -+ dev_dbg(host->dev, "%s: cmd=%d arg=%08X; host->error=0x%08X\n", -+ __func__, cmd->opcode, cmd->arg, host->error); -+} -+ -+static void phytium_sdci_request_done(struct phytium_sdci_host *host, -+ struct mmc_request *mrq) -+{ -+ unsigned long flags; -+ -+ dev_dbg(host->dev, -+ "%s_%d:mrq->cmd->opcode:%d, mrq->cmd->arg:0x%x resp 0x%x 0x%x 0x%x 0x%x\n", -+ __func__, __LINE__, mrq->cmd->opcode, mrq->cmd->arg, -+ mrq->cmd->resp[0], mrq->cmd->resp[1], mrq->cmd->resp[2], -+ mrq->cmd->resp[3]); -+ -+ spin_lock_irqsave(&host->lock, flags); -+ host->mrq = NULL; -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ phytium_sdci_track_cmd_data(host, mrq->cmd, mrq->data); -+ if (mrq->data && host->adtc_type != COMMOM_ADTC) -+ phytium_sdci_unprepare_data(host, mrq); -+ mmc_request_done(host->mmc, mrq); -+} -+ -+static bool -+phytium_sdci_auto_command_done(struct phytium_sdci_host *host, int events, -+ struct mmc_request *mrq, struct mmc_command *cmd) -+{ -+ u32 *rsp = cmd->resp; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ host->cmd = NULL; -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ sdr_clr_bits(host->base + SDCI_NORMAL_ISER, cmd_ints_mask); -+ -+ rsp[0] = 0x900; -+ phytium_sdci_request_done(host, mrq); -+ return true; -+} -+ -+/* returns true if command is fully handled; returns false otherwise */ -+static bool phytium_sdci_cmd_done(struct phytium_sdci_host *host, int events, -+ struct mmc_request *mrq, -+ struct mmc_command *cmd) -+{ -+ bool done = false; -+ bool sbc_error; -+ unsigned long flags; -+ u32 *rsp = cmd->resp; -+ -+ if (mrq->sbc && cmd == mrq->cmd && -+ (events & SDCI_NORMAL_ISR_CC)) -+ phytium_sdci_auto_cmd_done(host, events, mrq->sbc); -+ -+ sbc_error = mrq->sbc && mrq->sbc->error; -+ -+ if (!sbc_error && !(events & (SDCI_NORMAL_ISR_CC | -+ SDCI_NORMAL_ISR_CR | -+ SDCI_NORMAL_ISR_TIMEOUT))) -+ return done; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ done = !host->cmd; -+ host->cmd = NULL; -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if (done) -+ return true; -+ -+ sdr_clr_bits(host->base + SDCI_NORMAL_ISER, cmd_ints_mask); -+ -+ if (cmd->flags & MMC_RSP_PRESENT) { -+ if (cmd->flags & MMC_RSP_136) { -+ rsp[0] = readl(host->base + SDCI_RESP0); -+ rsp[1] = readl(host->base + SDCI_RESP1); -+ rsp[2] = readl(host->base + SDCI_RESP2); -+ rsp[3] = readl(host->base + SDCI_RESP3); -+ } else { -+ rsp[0] = readl(host->base + SDCI_RESP0); -+ } -+ -+ if (cmd->opcode == SD_SEND_RELATIVE_ADDR) -+ host->current_rca = rsp[0] & 0xFFFF0000; -+ } -+ -+ if (!sbc_error && -+ !(events & SDCI_NORMAL_ISR_CC) && -+ (events & SDCI_NORMAL_ISR_TIMEOUT)) -+ cmd->error = -ETIMEDOUT; -+ -+ if (cmd->error) -+ dev_dbg(host->dev, -+ "%s: cmd=%d arg=%08X; rsp %08X; cmd_error=%d\n", -+ __func__, cmd->opcode, cmd->arg, rsp[0], -+ cmd->error); -+ -+ phytium_sdci_cmd_next(host, mrq, cmd); -+ -+ return true; -+} -+ -+static bool set_databus_width(struct phytium_sdci_host *host) -+{ -+ bool res; -+ u32 cmd, resp_type, arg; -+ -+ cmd = SD_APP_SET_BUS_WIDTH; -+ resp_type = 0x2; -+ arg = 0x2; -+ res = phytium_sdci_private_send_cmd(host, cmd, resp_type, arg); -+ if (!res) -+ return false; -+ -+ cmd = MMC_APP_CMD; -+ resp_type = 0x2; -+ arg = host->current_rca; -+ res = phytium_sdci_private_send_cmd(host, cmd, resp_type, arg); -+ if (!res) -+ return false; -+ -+ return true; -+} -+ -+ -+static void phytium_sdci_start_command(struct phytium_sdci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_command *cmd) -+{ -+ u32 rawcmd; -+ struct mmc_data *data = mrq->data; -+ dma_addr_t dma_adtc_buf; -+ u32 dma_bufh, dma_bufl; -+ u32 block_cnt = 0; -+ -+ WARN_ON(host->cmd); -+ host->cmd = cmd; -+ -+ cmd->error = 0; -+ rawcmd = phytium_sdci_cmd_prepare_raw_cmd(host, mrq, cmd); -+ if (cmd->opcode == MMC_STOP_TRANSMISSION || -+ cmd->opcode == MMC_SEND_STATUS) -+ writel(1, host->base + SDCI_ERROR_ISR); -+ sdr_set_bits(host->base + SDCI_NORMAL_ISER, cmd_ints_mask); -+ writel(rawcmd, host->base + SDCI_COMMAND); -+ -+ if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) { -+ WARN_ON(host->data); -+ host->data = data; -+ -+ dma_adtc_buf = host->dma_rx.bd_addr; -+ dma_bufh = (u32) (dma_adtc_buf >> 32); -+ dma_bufl = (u32) dma_adtc_buf; -+ block_cnt = mrq->data->blocks; -+ sdr_set_bits(host->base + SDCI_BD_ISER, data_ints_mask); -+ writel(block_cnt, host->base + SDCI_BLK_CNT); -+ -+ if ((mrq->data->flags & MMC_DATA_READ) == MMC_DATA_READ) { -+ writel(dma_bufl, host->base + SDCI_BD_RX); -+ writel(dma_bufh, host->base + SDCI_BD_RX); -+ writel(cmd->arg, host->base + SDCI_BD_RX); -+ writel(0, host->base + SDCI_BD_RX); -+ } else { -+ writel(dma_bufl, host->base + SDCI_BD_TX); -+ writel(dma_bufh, host->base + SDCI_BD_TX); -+ writel(cmd->arg, host->base + SDCI_BD_TX); -+ writel(0, host->base + SDCI_BD_TX); -+ } -+ } else { -+ writel(cmd->arg, host->base + SDCI_ARGUMENT); -+ } -+} -+ -+static void phytium_sdci_cmd_next(struct phytium_sdci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_command *cmd) -+{ -+ if (cmd->error || (mrq->sbc && mrq->sbc->error)) -+ phytium_sdci_request_done(host, mrq); -+ else if (cmd == mrq->sbc) -+ phytium_sdci_start_command(host, mrq, mrq->cmd); -+ else if (!cmd->data) -+ phytium_sdci_request_done(host, mrq); -+} -+ -+static int phytium_sdci_cmd13_process(struct phytium_sdci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_data *data, -+ u32 wait_timeout_ms, -+ u32 send_once_time_ms) -+{ -+ u32 private_cmd, resp_type, arg, temp, sd_status; -+ unsigned long deadline_time; -+ bool res; -+ -+ deadline_time = jiffies + msecs_to_jiffies(wait_timeout_ms); -+ -+ do { -+ private_cmd = MMC_SEND_STATUS; -+ resp_type = 0x2; -+ arg = host->current_rca; -+ -+ res = phytium_sdci_private_send_cmd(host, private_cmd, resp_type, arg); -+ if (!res) { -+ sd_status = readl(host->base + SDCI_STATUS); -+ if (sd_status & SDCI_STATUS_CDSL) { -+ phytium_sdci_unexpected_error_handler(host, mrq, data, -+ ERR_CARD_ABSENT); -+ dev_err(host->dev, -+ "[%s][%d] Card absent! private_cmd(%d)\n", -+ __func__, __LINE__, private_cmd); -+ } else { -+ phytium_sdci_unexpected_error_handler(host, mrq, data, -+ ERR_CMD_RESPONED); -+ -+ dev_err(host->dev, -+ "[%s][%d] private_cmd(%d) response errored\n", -+ __func__, __LINE__, private_cmd); -+ phytium_sd_error(host); -+ } -+ writel(1, host->base + SDCI_BD_ISR); -+ return SDCI_CMD13_FAILED; -+ } -+ -+ temp = readl(host->base + SDCI_RESP0); -+ -+ if (time_after(jiffies, deadline_time)) { -+ -+ if (mrq->cmd->opcode == MMC_SEND_STATUS) -+ return SDCI_CMD13_OK; -+ -+ dev_err(host->dev, -+ "SD card is not in transfer mode,timeout:%d,rsp[0]:%x\n", -+ wait_timeout_ms, temp); -+ -+ phytium_sdci_unexpected_error_handler(host, mrq, data, -+ ERR_TIMEOUT); -+ phytium_sd_error(host); -+ return SDCI_CMD13_FAILED; -+ } -+ -+ writel(1, host->base + SDCI_NORMAL_ISR); -+ -+ if (CARD_TRAN_STATE != (temp & CARD_CURRENT_STATE) && send_once_time_ms) -+ mdelay(send_once_time_ms); -+ -+ } while (CARD_TRAN_STATE != (temp & CARD_CURRENT_STATE)); -+ -+ return SDCI_CMD13_OK; -+} -+ -+static void phytium_sdci_ops_request(struct mmc_host *mmc, -+ struct mmc_request *mrq) -+{ -+ struct phytium_sdci_host *host = mmc_priv(mmc); -+ unsigned long flags; -+ bool res; -+ u32 status_sd; -+ int res_cmd13; -+ -+ host->error = 0; -+ WARN_ON(host->mrq); -+ host->mrq = mrq; -+ -+ dev_dbg(host->dev, "%s: mrq->cmd->opcode:%d, mrq->cmd->arg:0x%x\n", -+ __func__, mrq->cmd->opcode, mrq->cmd->arg); -+ -+ if (mrq->cmd->opcode == MMC_SEND_STATUS && -+ (mrq->cmd->flags & MMC_CMD_MASK) != MMC_CMD_ADTC) { -+ u32 status = readl(host->base + SDCI_STATUS); -+ -+ if (status & SDCI_STATUS_CDSL) { -+ phytium_sdci_unexpected_error_handler(host, mrq, NULL, -+ ERR_CARD_ABSENT); -+ return; -+ } -+ -+ res_cmd13 = phytium_sdci_cmd13_process(host, mrq, NULL, 400, 5); -+ if (res_cmd13 == SDCI_CMD13_FAILED) -+ return; -+ } else if (mrq->cmd->opcode == MMC_STOP_TRANSMISSION) { -+ status_sd = readl(host->base + SDCI_STATUS); -+ if (status_sd & SDCI_STATUS_CDSL) { -+ phytium_sdci_unexpected_error_handler(host, mrq, NULL, -+ ERR_CARD_ABSENT); -+ return; -+ } -+ } -+ -+ if (mrq->data) { -+ if (mrq->cmd->opcode == MMC_READ_MULTIPLE_BLOCK || -+ mrq->cmd->opcode == MMC_READ_SINGLE_BLOCK || -+ mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK || -+ mrq->cmd->opcode == MMC_WRITE_BLOCK) { -+ host->adtc_type = BLOCK_RW_ADTC; -+ phytium_sdci_prepare_data(host, mrq); -+ phytium_sdci_start_data(host, mrq, -+ mrq->cmd, mrq->data); -+ return; -+ } -+ host->adtc_type = COMMOM_ADTC; -+ } -+ -+ if (mrq->cmd->opcode == SD_IO_RW_DIRECT || -+ mrq->cmd->opcode == SD_IO_SEND_OP_COND) { -+ spin_lock_irqsave(&host->lock, flags); -+ host->mrq = NULL; -+ host->cmd = NULL; -+ spin_unlock_irqrestore(&host->lock, flags); -+ mrq->cmd->error = -EINVAL; -+ mmc_request_done(host->mmc, mrq); -+ -+ return; -+ } -+ -+ if (mrq->cmd->opcode == SD_APP_SEND_SCR) { -+ res = set_databus_width(host); -+ if (!res) { -+ phytium_sdci_unexpected_error_handler(host, mrq, NULL, ERR_CMD_RESPONED); -+ return; -+ } -+ } -+ -+ /* if SBC is required, we have HW option and SW option. -+ * if HW option is enabled, and SBC does not have "special" flags, -+ * use HW option, otherwise use SW option -+ */ -+ if (mrq->sbc && -+ (!mmc_card_mmc(mmc->card) || (mrq->sbc->arg & 0xFFFF0000))) -+ phytium_sdci_start_command(host, mrq, mrq->sbc); -+ else -+ phytium_sdci_start_command(host, mrq, mrq->cmd); -+} -+ -+static void phytium_sdci_data_xfer_next(struct phytium_sdci_host *host, -+ struct mmc_request *mrq, -+ struct mmc_data *data) -+{ -+ if (mmc_op_multi(mrq->cmd->opcode) && -+ mrq->stop && !mrq->stop->error && -+ !mrq->sbc && host->is_multi_rw_only_one_blkcnt) { -+ host->is_multi_rw_only_one_blkcnt = false; -+ phytium_sdci_auto_command_done(host, SDCI_NORMAL_ISR_CC, mrq, mrq->stop); -+ } else if (mmc_op_multi(mrq->cmd->opcode) && -+ mrq->stop && !mrq->stop->error && -+ !mrq->sbc) -+ phytium_sdci_start_command(host, mrq, mrq->stop); -+ else -+ phytium_sdci_request_done(host, mrq); -+} -+ -+static inline void get_data_buffer(struct mmc_data *data, -+ u32 *bytes, u32 **pointer) -+{ -+ struct scatterlist *sg; -+ -+ sg = &data->sg[0]; -+ *bytes = sg->length; -+ *pointer = sg_virt(sg); -+} -+ -+static bool phytium_sdci_data_xfer_done(struct phytium_sdci_host *host, -+ u32 events, struct mmc_request *mrq, -+ struct mmc_data *data) -+{ -+ struct mmc_command *stop = data->stop; -+ unsigned long flags; -+ bool done; -+ unsigned int check_data; -+ u32 sg_length, i; -+ u32 *sg_virt_addr; -+ -+ check_data = events & (SDCI_BD_ISR_TRS_R | SDCI_BD_ISR_TRS_W | SDCI_BD_ISR_EDTE); -+ -+ spin_lock_irqsave(&host->lock, flags); -+ done = !host->data; -+ if (check_data) -+ host->data = NULL; -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if (done) -+ return true; -+ -+ if (check_data || (stop && stop->error)) { -+ sdr_clr_bits(host->base + SDCI_BD_ISER, data_ints_mask); -+ dev_dbg(host->dev, "DMA stop\n"); -+ -+ if (((events & SDCI_BD_ISR_TRS_R) || -+ (events & SDCI_BD_ISR_TRS_W)) && -+ (!stop || !stop->error)) { -+ if ((mrq->cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC && -+ (host->adtc_type == COMMOM_ADTC)) { -+ get_data_buffer(data, &sg_length, -+ &host->sg_virt_addr); -+ sg_virt_addr = host->sg_virt_addr; -+ -+ for (i = 0; i < (sg_length/4); i++) { -+ *sg_virt_addr = host->dma_rx.buf[i]; -+ sg_virt_addr++; -+ } -+ } -+ data->bytes_xfered = data->blocks * data->blksz; -+ } else { -+ dev_dbg(host->dev, "interrupt events: %x\n", events); -+ phytium_sdci_reset_hw(host); -+ data->bytes_xfered = 0; -+ dev_dbg(host->dev, "%s: cmd=%d; blocks=%d", -+ __func__, mrq->cmd->opcode, data->blocks); -+ dev_dbg(host->dev, "data_error=%d xfer_size=%d\n", -+ (int)data->error, data->bytes_xfered); -+ } -+ -+ phytium_sdci_data_xfer_next(host, mrq, data); -+ done = true; -+ } -+ -+ return done; -+} -+ -+ -+static int phytium_sdci_card_busy(struct mmc_host *mmc) -+{ -+ struct phytium_sdci_host *host = mmc_priv(mmc); -+ u32 status; -+ -+ /* check if any pin between dat[0:3] is low */ -+ status = readl(host->base + SDCI_STATUS); -+ if (((status >> 20) & 0xf) != 0xf) -+ return 1; -+ -+ return 0; -+} -+ -+static void phytium_sdci_request_timeout(struct work_struct *work) -+{ -+ struct phytium_sdci_host *host; -+ -+ host = container_of(work, struct phytium_sdci_host, req_timeout.work); -+ dev_err(host->dev, "%s: aborting cmd/data/mrq\n", __func__); -+ if (host->mrq) { -+ dev_err(host->dev, "%s: aborting mrq=%p cmd=%d\n", __func__, -+ host->mrq, host->mrq->cmd->opcode); -+ if (host->cmd) { -+ dev_err(host->dev, "%s: aborting cmd=%d\n", -+ __func__, host->cmd->opcode); -+ phytium_sdci_cmd_done(host, SDCI_NORMAL_ISR_TIMEOUT, -+ host->mrq, host->cmd); -+ } else if (host->data) { -+ dev_err(host->dev, "%s: abort data: cmd%d; %d blocks\n", -+ __func__, host->mrq->cmd->opcode, -+ host->data->blocks); -+ phytium_sdci_data_xfer_done(host, SDCI_BD_ISR_EDTE, -+ host->mrq, host->data); -+ } -+ } -+} -+ -+static void hotplug_timer_func(struct timer_list *t) -+{ -+ struct phytium_sdci_host *host; -+ u32 status; -+ -+ host = from_timer(host, t, hotplug_timer); -+ if (!host) -+ dev_err(host->dev, "%s: Not find host!\n", __func__); -+ status = readl(host->base + SDCI_STATUS); -+ -+ if (status & SDCI_STATUS_CDSL) { /* card absent */ -+ if (host->mmc->card) { -+ cancel_delayed_work(&host->mmc->detect); -+ mmc_detect_change(host->mmc, -+ msecs_to_jiffies(100)); -+ } -+ } else { /* card insert */ -+ cancel_delayed_work(&host->mmc->detect); -+ mmc_detect_change(host->mmc, msecs_to_jiffies(200)); -+ } -+} -+ -+static irqreturn_t phytium_sdci_irq(int irq, void *dev_id) -+{ -+ struct phytium_sdci_host *host = (struct phytium_sdci_host *) dev_id; -+ unsigned long flags; -+ struct mmc_request *mrq; -+ struct mmc_command *cmd; -+ u32 events; -+ -+ if (!host) -+ return IRQ_NONE; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ events = readl(host->base + SDCI_NORMAL_ISR); -+ /* clear interrupts */ -+ writel(1, host->base + SDCI_NORMAL_ISR); -+ -+ mrq = host->mrq; -+ cmd = host->cmd; -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if (events & (SDCI_NORMAL_ISR_CR | SDCI_NORMAL_ISR_CI)) { -+ mod_timer(&host->hotplug_timer, -+ jiffies + usecs_to_jiffies(30000)); -+ goto irq_out; -+ } -+ -+ if (!(events & cmd_ints_mask)) -+ goto irq_out; -+ -+ if (!mrq) { -+ dev_err(host->dev, "%s: MRQ=NULL; events=%08X\n", -+ __func__, events); -+ WARN_ON(1); -+ goto irq_out; -+ } -+ -+ dev_dbg(host->dev, "%s: events=%08X\n", __func__, events); -+ -+ if (cmd) -+ phytium_sdci_cmd_done(host, events, mrq, cmd); -+ -+irq_out: -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t phytium_sdci_dma_irq(int irq, void *dev_id) -+{ -+ struct phytium_sdci_host *host = (struct phytium_sdci_host *) dev_id; -+ unsigned long flags; -+ struct mmc_request *mrq; -+ struct mmc_command *cmd; -+ struct mmc_data *data; -+ u32 events; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ events = readl(host->base + SDCI_BD_ISR); -+ writel(1, host->base + SDCI_BD_ISR); -+ -+ mrq = host->mrq; -+ cmd = host->cmd; -+ data = host->data; -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if (!(events & data_ints_mask)) -+ goto dma_irq_out; -+ -+ if (!mrq) { -+ dev_err(host->dev, -+ "%s: MRQ=NULL; events=%08X\n", -+ __func__, events); -+ goto dma_irq_out; -+ } -+ -+ dev_dbg(host->dev, "%s: events=%08X\n", __func__, events); -+ -+ if (data) -+ phytium_sdci_data_xfer_done(host, events, mrq, data); -+ -+dma_irq_out: -+ return IRQ_HANDLED; -+} -+ -+static irqreturn_t phytium_sdci_err_irq(int irq, void *dev_id) -+{ -+ struct phytium_sdci_host *host = (struct phytium_sdci_host *) dev_id; -+ unsigned long flags; -+ struct mmc_request *mrq; -+ struct mmc_command *cmd; -+ struct mmc_data *data; -+ u32 events; -+ -+ if (!host) -+ return IRQ_NONE; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ events = readl(host->base + SDCI_ERROR_ISR); -+ mrq = host->mrq; -+ cmd = host->cmd; -+ data = host->data; -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ if (!(events&err_ints_mask)) -+ goto err_irq_out; -+ -+ if (!mrq) { -+ sdr_clr_bits(host->base + SDCI_NORMAL_ISER, SDCI_NORMAL_ISR_EI); -+ writel(1, host->base + SDCI_ERROR_ISR); -+ dev_err(host->dev, "%s: MRQ=NULL; events=%08X\n", __func__, events); -+ goto err_irq_out; -+ } -+ sdr_clr_bits(host->base + SDCI_NORMAL_ISER, SDCI_NORMAL_ISR_EI); -+ if (data) { -+ dev_err(host->dev, -+ "[%s][%d]: cmd(%d); %d read blocks, status:%x,flag:%x\n", -+ __func__, __LINE__, mrq->cmd->opcode, data->blocks, events, data->flags); -+ data->error = -ETIMEDOUT; -+ if ((data->flags & MMC_DATA_READ) == MMC_DATA_READ || -+ (data->flags & MMC_DATA_WRITE) == MMC_DATA_WRITE) -+ phytium_sdci_data_xfer_done(host, SDCI_BD_ISR_EDTE | SDCI_BD_ISR_TRS_R, -+ mrq, data); -+ mrq->cmd->error = -ETIMEDOUT; -+ mmc_request_done(host->mmc, mrq); -+ } else if (cmd) { -+ phytium_sdci_cmd_done(host, SDCI_NORMAL_ISR_TIMEOUT, mrq, cmd); -+ } -+ -+ writel(1, host->base + SDCI_NORMAL_ISR); -+ writel(1, host->base + SDCI_ERROR_ISR); -+err_irq_out: -+ return IRQ_HANDLED; -+} -+ -+static void phytium_sdci_init_hw(struct phytium_sdci_host *host) -+{ -+ u32 val; -+ -+ /* Reset */ -+ phytium_sdci_reset_hw(host); -+ -+ val = SDCI_SEN_CREFR_VAL | SDCI_SEN_DEBNCE_VAL; -+ writel(val, host->base + SDCI_SD_SEN); -+ -+ /* Disable and clear all interrupts */ -+ writel(0, host->base + SDCI_NORMAL_ISER); -+ writel(0, host->base + SDCI_ERROR_ISER); -+ writel(0, host->base + SDCI_BD_ISER); -+ -+ writel(1, host->base + SDCI_NORMAL_ISR); -+ writel(1, host->base + SDCI_ERROR_ISR); -+ writel(1, host->base + SDCI_BD_ISR); -+ -+ sdr_set_bits(host->base + SDCI_NORMAL_ISER, -+ SDCI_SDCI_NORMAL_ISER_ECI|SDCI_SDCI_NORMAL_ISER_ECR); -+ /* Configure default cmd timeout to 0.1(s)s = val/25M */ -+ val = SDCI_F_MAX / 10; -+ writel(val, host->base + SDCI_TIMEOUT_CMD); -+ writel(SDCI_TIMEOUT_DATA_VALUE, host->base + SDCI_TIMEOUT_DATA); -+ -+ val = 0x0F00; -+ writel(val, host->base + SDCI_CONTROLLER); -+ -+ dev_dbg(host->dev, "init hardware done!"); -+} -+ -+static void phytium_sdci_deinit_hw(struct phytium_sdci_host *host) -+{ -+ /* Disable and clear all interrupts */ -+ writel(0, host->base + SDCI_NORMAL_ISER); -+ writel(0, host->base + SDCI_ERROR_ISER); -+ writel(0, host->base + SDCI_BD_ISER); -+ -+ writel(0, host->base + SDCI_NORMAL_ISR); -+ writel(0, host->base + SDCI_ERROR_ISR); -+ writel(0, host->base + SDCI_BD_ISR); -+} -+ -+static void phytium_sdci_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -+{ -+ struct phytium_sdci_host *host = mmc_priv(mmc); -+ -+ if (ios->bus_width == MMC_BUS_WIDTH_4) -+ mmc->caps = mmc->caps & (~MMC_CAP_4_BIT_DATA); -+ -+ /* Suspend/Resume will do power off/on */ -+ switch (ios->power_mode) { -+ case MMC_POWER_UP: -+ writel(SDCI_POWER_ON, host->base + SDCI_POWER); -+ break; -+ case MMC_POWER_ON: -+ phytium_sdci_set_clk(host, ios); -+ break; -+ case MMC_POWER_OFF: -+ writel(SDCI_POWER_OFF, host->base + SDCI_POWER); -+ break; -+ default: -+ break; -+ } -+} -+ -+static int phytium_sdci_get_cd(struct mmc_host *mmc) -+{ -+ struct phytium_sdci_host *host = mmc_priv(mmc); -+ u32 status = readl(host->base + SDCI_STATUS); -+ -+ if (((status >> 19) & 0x1) == 0x1) -+ return 0; -+ -+ return 1; -+} -+ -+static void phytium_sdci_hw_reset(struct mmc_host *mmc) -+{ -+ struct phytium_sdci_host *host = mmc_priv(mmc); -+ -+ sdr_set_bits(host->base + SDCI_SOFTWARE, SDCI_SOFTWARE_SRST); -+ sdr_clr_bits(host->base + SDCI_SOFTWARE, SDCI_SOFTWARE_SRST); -+ while (!(readl(host->base + SDCI_STATUS) & SDCI_STATUS_IDIE)) -+ cpu_relax(); -+} -+ -+static struct mmc_host_ops phytium_sdci_ops = { -+ .request = phytium_sdci_ops_request, -+ .set_ios = phytium_sdci_ops_set_ios, -+ .get_cd = phytium_sdci_get_cd, -+ .card_busy = phytium_sdci_card_busy, -+ .card_hw_reset = phytium_sdci_hw_reset, -+}; -+ -+static bool phytium_sdci_private_send_cmd(struct phytium_sdci_host *host, -+ u32 cmd, u32 resp_type, u32 arg) -+{ -+ u32 temp, sd_cmd, sd_arg, sd_status; -+ unsigned long deadline_time; -+ -+ writel(1, host->base + SDCI_NORMAL_ISR); -+ writel(1, host->base + SDCI_ERROR_ISR); -+ -+ sd_cmd = (cmd << 8) | resp_type; -+ sd_arg = arg; -+ writel(sd_cmd, host->base + SDCI_COMMAND); -+ writel(sd_arg, host->base + SDCI_ARGUMENT); -+ -+ if (cmd == MMC_STOP_TRANSMISSION) -+ deadline_time = jiffies + msecs_to_jiffies(1000); -+ else -+ deadline_time = jiffies + msecs_to_jiffies(100); -+ -+ temp = readl(host->base + SDCI_NORMAL_ISR); -+ while ((temp & SDCI_NORMAL_ISR_CC) != SDCI_NORMAL_ISR_CC) { -+ sd_status = readl(host->base + SDCI_STATUS); -+ if (sd_status & SDCI_STATUS_CDSL) -+ return false; -+ -+ temp = readl(host->base + SDCI_NORMAL_ISR); -+ if (time_after(jiffies, deadline_time)) -+ return false; -+ -+ if (cmd == MMC_STOP_TRANSMISSION) -+ mdelay(1); -+ } -+ -+ return true; -+} -+ -+static int phytium_sdci_probe(struct platform_device *pdev) -+{ -+ struct mmc_host *mmc; -+ struct phytium_sdci_host *host; -+ struct resource *res; -+ int ret; -+ const struct acpi_device_id *match; -+ struct device *dev = &pdev->dev; -+ -+ /* Allocate MMC host for this device */ -+ mmc = mmc_alloc_host(sizeof(struct phytium_sdci_host), &pdev->dev); -+ if (!mmc) -+ return -ENOMEM; -+ -+ host = mmc_priv(mmc); -+ ret = mmc_of_parse(mmc); -+ if (ret) -+ goto host_free; -+ -+ if (dev->of_node) { -+ host->src_clk = devm_clk_get(&pdev->dev, "phytium_sdc_clk"); -+ if (IS_ERR(host->src_clk)) { -+ ret = PTR_ERR(host->src_clk); -+ goto host_free; -+ } -+ -+ host->clk_rate = clk_get_rate(host->src_clk); -+ if (device_property_read_bool(dev, "no-dma-coherent")) -+ dev->dma_coherent = false; -+ } else if (has_acpi_companion(dev)) { -+ match = acpi_match_device(dev->driver->acpi_match_table, dev); -+ if (!match) { -+ dev_err(dev, "Error ACPI match data is missing\n"); -+ return -ENODEV; -+ } -+ -+ acpi_dma_configure(dev, DEV_DMA_NON_COHERENT); -+ -+ host->clk_rate = 600000000; -+ } else { -+ dev_err(&pdev->dev, "No DT found\n"); -+ return -EINVAL; -+ } -+ -+ dma_set_mask(dev, DMA_BIT_MASK(40)); -+ dma_set_coherent_mask(dev, DMA_BIT_MASK(40)); -+ -+ timer_setup(&host->hotplug_timer, hotplug_timer_func, 0); -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ host->base = devm_ioremap_resource(&pdev->dev, res); -+ if (IS_ERR(host->base)) { -+ ret = PTR_ERR(host->base); -+ goto host_free; -+ } -+ -+ host->irq = platform_get_irq(pdev, 1); -+ if (host->irq < 0) { -+ ret = -EINVAL; -+ goto host_free; -+ } -+ -+ host->irq_err = platform_get_irq(pdev, 2); -+ if (host->irq_err < 0) { -+ ret = -EINVAL; -+ goto host_free; -+ } -+ -+ host->irq_bd = platform_get_irq(pdev, 0); -+ if (host->irq_bd < 0) { -+ ret = -EINVAL; -+ goto host_free; -+ } -+ -+ host->dev = &pdev->dev; -+ host->mmc = mmc; -+ -+ if ((4 * SDCI_F_MAX) > host->clk_rate) -+ host->clk_div = 1; -+ else -+ host->clk_div = ((host->clk_rate / (2 * SDCI_F_MAX)) - 1); -+ -+ /* Set host parameters to mmc */ -+ mmc->f_min = SDCI_F_MIN; -+ mmc->f_max = (host->clk_rate / ((host->clk_div + 1) * 2)); -+ mmc->ops = &phytium_sdci_ops; -+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; -+ -+ mmc->caps |= host->caps; -+ /* MMC core transfer sizes tunable parameters */ -+ mmc->max_segs = MAX_BD_NUM; -+ mmc->max_seg_size = 512 * 1024; -+ mmc->max_blk_size = 512; -+ mmc->max_req_size = 512 * 1024; -+ mmc->max_blk_count = mmc->max_req_size / 512; -+ -+ host->dma_rx.buf = dma_alloc_coherent(&pdev->dev, -+ MAX_BD_NUM, -+ &host->dma_rx.bd_addr, -+ GFP_KERNEL); -+ if (!host->dma_rx.buf) { -+ ret = -ENOMEM; -+ goto release_mem; -+ } -+ -+ host->cmd_timeout = msecs_to_jiffies(100); -+ host->data_timeout = msecs_to_jiffies(250); -+ -+ INIT_DELAYED_WORK(&host->req_timeout, phytium_sdci_request_timeout); -+ spin_lock_init(&host->lock); -+ -+ platform_set_drvdata(pdev, mmc); -+ phytium_sdci_init_hw(host); -+ -+ ret = devm_request_irq(&pdev->dev, host->irq, phytium_sdci_irq, -+ IRQF_SHARED, pdev->name, host); -+ if (ret) -+ goto release; -+ -+ ret = devm_request_irq(&pdev->dev, host->irq_err, phytium_sdci_err_irq, -+ IRQF_SHARED, pdev->name, host); -+ if (ret) -+ goto release; -+ -+ ret = devm_request_irq(&pdev->dev, host->irq_bd, phytium_sdci_dma_irq, -+ IRQF_SHARED, pdev->name, host); -+ if (ret) -+ goto release; -+ -+ ret = mmc_add_host(mmc); -+ if (ret) -+ goto release; -+ -+ return 0; -+ -+release: -+ platform_set_drvdata(pdev, NULL); -+ phytium_sdci_deinit_hw(host); -+release_mem: -+ if (host->dma_rx.buf) -+ dma_free_coherent(&pdev->dev, MAX_BD_NUM, -+ host->dma_rx.buf, -+ host->dma_rx.bd_addr); -+host_free: -+ mmc_free_host(mmc); -+ -+ return ret; -+} -+ -+static int phytium_sdci_remove(struct platform_device *pdev) -+{ -+ struct mmc_host *mmc; -+ struct phytium_sdci_host *host; -+ -+ mmc = platform_get_drvdata(pdev); -+ host = mmc_priv(mmc); -+ -+ cancel_delayed_work_sync(&host->req_timeout); -+ platform_set_drvdata(pdev, NULL); -+ mmc_remove_host(host->mmc); -+ phytium_sdci_deinit_hw(host); -+ -+ if (host->dma_rx.buf) -+ dma_free_coherent(&pdev->dev, MAX_BD_NUM, -+ host->dma_rx.buf, host->dma_rx.bd_addr); -+ -+ mmc_free_host(host->mmc); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int phytium_sdci_suspend(struct device *dev) -+{ -+ struct mmc_host *mmc = dev_get_drvdata(dev); -+ struct phytium_sdci_host *host = mmc_priv(mmc); -+ -+ phytium_sdci_deinit_hw(host); -+ return 0; -+} -+ -+static int phytium_sdci_resume(struct device *dev) -+{ -+ struct mmc_host *mmc = dev_get_drvdata(dev); -+ struct phytium_sdci_host *host = mmc_priv(mmc); -+ -+ phytium_sdci_init_hw(host); -+ mmc->caps = mmc->caps | MMC_CAP_4_BIT_DATA; -+ -+ return 0; -+} -+#endif -+ -+#ifdef CONFIG_PM -+static int phytium_sdci_runtime_suspend(struct device *dev) -+{ -+ struct mmc_host *mmc = dev_get_drvdata(dev); -+ struct phytium_sdci_host *host = mmc_priv(mmc); -+ -+ phytium_sdci_deinit_hw(host); -+ -+ return 0; -+} -+ -+static int phytium_sdci_runtime_resume(struct device *dev) -+{ -+ struct mmc_host *mmc = dev_get_drvdata(dev); -+ struct phytium_sdci_host *host = mmc_priv(mmc); -+ -+ phytium_sdci_init_hw(host); -+ -+ return 0; -+} -+ -+static const struct dev_pm_ops phytium_sdci_dev_pm_ops = { -+ SET_SYSTEM_SLEEP_PM_OPS(phytium_sdci_suspend, -+ phytium_sdci_resume) -+ SET_RUNTIME_PM_OPS(phytium_sdci_runtime_suspend, -+ phytium_sdci_runtime_resume, NULL) -+}; -+#else -+#define phytium_sdci_dev_pm_ops NULL -+#endif -+ -+static const struct of_device_id phytium_sdci_of_ids[] = { -+ { .compatible = "phytium,sdci", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, phytium_sdci_of_ids); -+ -+#ifdef CONFIG_ACPI -+static const struct acpi_device_id phytium_sdci_acpi_ids[] = { -+ { .id = "PHYT0005" }, -+ { } -+}; -+ -+MODULE_DEVICE_TABLE(acpi, phytium_sdci_acpi_ids); -+#else -+#define phytium_sdci_acpi_ids NULL -+#endif -+ -+static struct platform_driver phytium_sdci_driver = { -+ .probe = phytium_sdci_probe, -+ .remove = phytium_sdci_remove, -+ .driver = { -+ .name = "sdci-phytium", -+ .of_match_table = phytium_sdci_of_ids, -+ .acpi_match_table = phytium_sdci_acpi_ids, -+ .pm = &phytium_sdci_dev_pm_ops, -+ }, -+}; -+ -+module_platform_driver(phytium_sdci_driver); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Cheng Quan <chengquan@phytium.com.cn>"); -+MODULE_AUTHOR("Chen Baozi <chenbaozi@phytium.com.cn>"); -+MODULE_DESCRIPTION("Phytium SD Card Interface driver"); -diff --git a/drivers/mmc/host/phytium-sdci.h b/drivers/mmc/host/phytium-sdci.h -new file mode 100644 -index 0000000..a50cf42 ---- /dev/null -+++ b/drivers/mmc/host/phytium-sdci.h -@@ -0,0 +1,200 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Phytium SDCI dirver -+ * -+ * Copyright (C) 2019-2023, Phytium Technology Co., Ltd. -+ */ -+ -+/*---------------------------------------------------------------------------*/ -+/* Common Definition */ -+/*---------------------------------------------------------------------------*/ -+#define MAX_BD_NUM 0x1000 -+#define SD_BLOCK_SIZE 512 -+ -+/*---------------------------------------------------------------------------*/ -+/* Register Offset */ -+/*---------------------------------------------------------------------------*/ -+#define SDCI_CONTROLLER 0x00 /* controller config reg */ -+#define SDCI_ARGUMENT 0x04 /* argument reg */ -+#define SDCI_COMMAND 0x08 /* command reg */ -+#define SDCI_CLOCK_D 0x0C /* clock divide reg */ -+#define SDCI_SOFTWARE 0x10 /* controller reset reg */ -+#define SDCI_POWER 0X14 /* POWRE CONTROL REG */ -+#define SDCI_TIMEOUT_CMD 0x18 /* cmd timeout config reg */ -+#define SDCI_TIMEOUT_DATA 0x1C /* data timeout reg */ -+#define SDCI_NORMAL_ISER 0x20 /* normal ISR config reg */ -+#define SDCI_ERROR_ISER 0x24 /* erroe ISR config reg */ -+#define SDCI_BD_ISER 0x28 /* BD ISR config reg */ -+#define SDCI_CAPA 0x2C /* BD ISR config reg */ -+#define SDCI_SD_DRV 0x30 /* SD card driving phase position reg */ -+#define SDCI_SD_SAMP 0x34 /* SD card sampling phase position reg */ -+#define SDCI_SD_SEN 0x38 /* SD card detection reg */ -+#define SDCI_HDS_AXI 0x3C /* AXI boundary config reg */ -+#define SDCI_BD_RX 0x40 /* BD rx addr reg */ -+#define SDCI_BD_TX 0x60 /* BD tx addr reg */ -+#define SDCI_BLK_CNT 0x80 /* r/w block num reg */ -+#define SDCI_NORMAL_ISR 0xC0 /* normal ISR status reg */ -+#define SDCI_ERROR_ISR 0xC4 /* error ISR status reg */ -+#define SDCI_BD_ISR 0xC8 /* BD ISR status reg */ -+#define SDCI_BD_STATUS 0xCC /* BD descriptor status reg */ -+#define SDCI_STATUS 0xD0 /* status reg */ -+#define SDCI_BLOCK 0xD4 /* block len reg */ -+#define SDCI_RESP0 0xE0 /* response reg0 */ -+#define SDCI_RESP1 0xE4 /* response reg1 */ -+#define SDCI_RESP2 0xE8 /* response reg2 */ -+#define SDCI_RESP3 0XEC /* response reg3 */ -+ -+/*---------------------------------------------------------------------------*/ -+/* Register Mask */ -+/*---------------------------------------------------------------------------*/ -+/* SDCI_CONTROLLER mask */ -+#define SDCI_CONTROLLER_ECRCWR (0x1 << 0) /* RW */ -+#define SDCI_CONTROLLER_ECRCRD (0x1 << 1) /* RW */ -+#define SDCI_CONTROLLER_RESEDE (0x1 << 2) /* RW */ -+#define SDCI_CONTROLLER_PERMDR (0x3 << 8) /* RW */ -+#define SDCI_CONTROLLER_PERMDX (0x3 << 10) /* RW */ -+ -+/* SDCI_SOFTWARE mask */ -+#define SDCI_SOFTWARE_SRST (0x1 << 0) /* RW */ -+#define SDCI_SOFTWARE_SCRST (0x1 << 1) /* RW */ -+#define SDCI_SOFTWARE_BDRST (0x1 << 2) /* RW */ -+#define SDCI_SOFTWARE_CFCLF (0x1 << 3) /* RW */ -+#define SDCI_SOFTWARE_SDRST (0x1 << 4) /* RW */ -+ -+/* SDCI_NORMAL_ISER mask */ -+#define SDCI_SDCI_NORMAL_ISER_ECC_EN (0x1 << 0) /* RW */ -+#define SDCI_SDCI_NORMAL_ISER_ECR (0x1 << 1) /* RW */ -+#define SDCI_SDCI_NORMAL_ISER_ECI (0x1 << 2) /* RW */ -+#define SDCI_SDCI_NORMAL_ISER_EEI_EN (0x1 << 15) /* RW */ -+ -+/* SDCI_NORMAL_ISR mask */ -+#define SDCI_NORMAL_ISR_CC (0x1 << 0) /* R */ -+#define SDCI_NORMAL_ISR_CR (0x1 << 1) /* R */ -+#define SDCI_NORMAL_ISR_CI (0x1 << 2) /* R */ -+#define SDCI_NORMAL_ISR_TIMEOUT (0x1 << 3) /* R */ -+#define SDCI_NORMAL_ISR_EI (0x1 << 15) /* R */ -+ -+/* SDCI_ERROR_ISER mask */ -+#define SDCI_ERROR_ISER_ECTE_EN (0x1 << 0) /* RW */ -+#define SDCI_ERROR_ISR_CCRCE_EN (0x1 << 1) /* RW */ -+#define SDCI_ERROR_ISR_CIR_EN (0x1 << 3) /* RW */ -+#define SDCI_ERROR_ISR_CNR_EN (0x1 << 4) /* RW */ -+/* SDCI_ERROR_ISR mask */ -+#define SDCI_ERROR_ISR_CTE (0x1 << 0) /* R */ -+#define SDCI_ERROR_ISR_CCRCE (0x1 << 1) /* R */ -+#define SDCI_ERROR_ISR_CIR (0x1 << 3) /* R */ -+#define SDCI_ERROR_ISR_CNR (0x1 << 4) /* R */ -+ -+/* SDCI_BD_ISER mask */ -+#define SDCI_BD_ISER_ETRS_EN (0x1 << 8) /* RW */ -+#define SDCI_BD_ISER_DATFRAX_EN (0x1 << 7) /* RW */ -+ -+/* SDCI_BD_ISR mask */ -+#define SDCI_BD_ISR_TRS_W (0x1 << 0) /* R */ -+#define SDCI_BD_ISR_TRS_R (0x1 << 8) /* R */ -+#define SDCI_BD_ISR_EDTE (0x1 << 3) /* R */ -+#define SDCI_BD_ISR_DAIS (0x1 << 15) /* R */ -+#define SDCI_BD_ISR_DATFRAX (0x1 << 7) /* R */ -+ -+/* SDCI_HDS_AXI mask */ -+#define SDCI_HDS_AXI_AWDOMAIN (0x1 << 0) /* RW */ -+#define SDCI_HDS_AXI_ARDOMAIN (0x1 << 12) /* RW */ -+#define SDCI_HDS_AXI_AWCACHE (0x6 << 24) /* RW */ -+#define SDCI_HDS_AXI_ARCACHE (0xB << 28) /* RW */ -+ -+/* SDCI_STATUS mask */ -+#define SDCI_STATUS_CMD_BUSY (0x0 << 0) /* R */ -+#define SDCI_STATUS_CMD_READY (0x1 << 0) /* R */ -+#define SDCI_STATUS_IDIE (0x1 << 12) /* R */ -+#define SDCI_CARD_BUSY_IN_PRG (0x1 << 20) /* R D0 BUSY:0,IDLE:1 */ -+ -+/* SDCI_STATUS */ -+#define SDCI_STATUS_CDSL (0x1 << 19) /* R */ -+ -+/*---------------------------------------------------------------------------*/ -+/* Register Value */ -+/*---------------------------------------------------------------------------*/ -+#define SDCI_SD_DRV_VALUE 0 -+#define SDCI_SD_SAMP_VALUE_MAX 50 -+#define SDCI_SD_SAMP_VALUE_MIN 0 -+ -+#define SDCI_TIMEOUT_CMD_VALUE 0xFFFFFFFF -+#define SDCI_TIMEOUT_DATA_VALUE 0xFFFFFFFF -+#define SDCI_POWER_ON 1 -+#define SDCI_POWER_OFF 0 -+ -+#define SDCI_CMD_TIMEOUT 10 -+#define SDCI_DAT_TIMEOUT 5000 -+ -+#define SDCI_CMD_TYPE_ADTC 0x2 -+ -+#define SDCI_F_MIN 400000 -+#define SDCI_F_MAX 25000000 -+ -+#define SDCI_SEN_CREFR_VAL (0x1 << 1) -+#define SDCI_SEN_DEBNCE_VAL (0xB << 8) -+ -+#define CARD_CURRENT_STATE (0xF << 9) -+#define CARD_PRG_STATE (0x7 << 9) -+#define CARD_TRAN_STATE (0x4 << 9) -+ -+#define SDCI_CMD13_OK 1 -+#define SDCI_CMD13_FAILED 0 -+ -+#define ERR_TIMEOUT (0x1 << 0) -+#define ERR_CARD_ABSENT (0x1 << 1) -+#define ERR_CMD_RESPONED (0x1 << 2) -+ -+/*---------------------------------------------------------------------------*/ -+/* Structure Type */ -+/*---------------------------------------------------------------------------*/ -+struct phytium_sdci_dma { -+ struct scatterlist *sg; -+ u32 *buf; -+ dma_addr_t bd_addr; -+ size_t bytes; -+}; -+ -+enum adtc_type { -+ COMMOM_ADTC = 0, -+ BLOCK_RW_ADTC = 1 -+}; -+ -+struct phytium_sdci_host { -+ struct device *dev; -+ struct mmc_host *mmc; -+ u32 caps; -+ spinlock_t lock; -+ -+ struct mmc_request *mrq; -+ struct mmc_command *cmd; -+ struct mmc_data *data; -+ int error; -+ -+ void __iomem *base; -+ -+ struct phytium_sdci_dma dma_rx; -+ struct phytium_sdci_dma dma_tx; -+ -+ u32 *sg_virt_addr; -+ enum adtc_type adtc_type; -+ -+ struct timer_list hotplug_timer; -+ -+ struct delayed_work req_timeout; -+ u32 cmd_timeout; -+ u32 data_timeout; -+ -+ int irq; -+ int irq_err; -+ int irq_bd; -+ -+ struct clk *src_clk; -+ unsigned long clk_rate; -+ unsigned long clk_div; -+ unsigned long real_rate; -+ -+ u32 current_rca; -+ bool is_multi_rw_only_one_blkcnt; -+}; -+ -diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c -index 8d2aee8..22e2b65 100644 ---- a/drivers/net/xen-netfront.c -+++ b/drivers/net/xen-netfront.c -@@ -867,7 +867,7 @@ static netdev_tx_t xennet_start_xmit(struct sk_buff *skb, struct net_device *dev - static int xennet_close(struct net_device *dev) - { - struct netfront_info *np = netdev_priv(dev); -- unsigned int num_queues = dev->real_num_tx_queues; -+ unsigned int num_queues = np->queues ? dev->real_num_tx_queues : 0; - unsigned int i; - struct netfront_queue *queue; - netif_tx_stop_all_queues(np->netdev); -@@ -882,6 +882,9 @@ static void xennet_destroy_queues(struct netfront_info *info) - { - unsigned int i; - -+ if (!info->queues) -+ return; -+ - for (i = 0; i < info->netdev->real_num_tx_queues; i++) { - struct netfront_queue *queue = &info->queues[i]; - -diff --git a/drivers/nvdimm/security.c b/drivers/nvdimm/security.c -index a03e3c4..71bccea 100644 ---- a/drivers/nvdimm/security.c -+++ b/drivers/nvdimm/security.c -@@ -28,7 +28,11 @@ static void *key_data(struct key *key) - { - struct encrypted_key_payload *epayload = dereference_key_locked(key); - -+ #ifdef CONFIG_KEYP -+ lockdep_assert_held_read(&KEY_SEM(key)); -+ #else - lockdep_assert_held_read(&key->sem); -+ #endif - - return epayload->decrypted_data; - } -@@ -38,7 +42,11 @@ static void nvdimm_put_key(struct key *key) - if (!key) - return; - -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - } - -@@ -65,10 +73,18 @@ static struct key *nvdimm_request_key(struct nvdimm *nvdimm) - } else { - struct encrypted_key_payload *epayload; - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(key)); -+ #else - down_read(&key->sem); -+ #endif - epayload = dereference_key_locked(key); - if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - key = NULL; - } -@@ -107,10 +123,18 @@ static struct key *nvdimm_lookup_user_key(struct nvdimm *nvdimm, - - dev_dbg(dev, "%s: key found: %#x\n", __func__, key_serial(key)); - -+ #ifdef CONFIG_KEYP -+ down_read_nested(&KEY_SEM(key), subclass); -+ #else - down_read_nested(&key->sem, subclass); -+ #endif - epayload = dereference_key_locked(key); - if (epayload->decrypted_datalen != NVDIMM_PASSPHRASE_LEN) { -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - key = NULL; - } -diff --git a/drivers/pci/msi/msi.c b/drivers/pci/msi/msi.c -index 8566370..d280d06 100644 ---- a/drivers/pci/msi/msi.c -+++ b/drivers/pci/msi/msi.c -@@ -408,12 +408,38 @@ static int msi_capability_init(struct pci_dev *dev, int nvec, - return ret; - } - -+#ifdef CONFIG_LOONGARCH -+#include <asm/setup.h> -+ -+static unsigned int pci_irq_numbers = 32; -+ -+static int __init pci_irq_limit(char *str) -+{ -+ get_option(&str, &pci_irq_numbers); -+ -+ if (pci_irq_numbers == 0) -+ pci_irq_numbers = 32; -+ return 0; -+} -+ -+early_param("pci_irq_limit", pci_irq_limit); -+#endif -+ - int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, - struct irq_affinity *affd) - { - int nvec; - int rc; - -+#ifdef CONFIG_LOONGARCH -+ if (!disable_pci_irq_limit) { -+ if (maxvec > 32) { -+ maxvec = pci_irq_numbers; -+ minvec = min_t(int, pci_irq_numbers, minvec); -+ } -+ } -+#endif -+ - if (!pci_msi_supported(dev, minvec) || dev->current_state != PCI_D0) - return -EINVAL; - -@@ -795,6 +821,15 @@ int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int - { - int hwsize, rc, nvec = maxvec; - -+#ifdef CONFIG_LOONGARCH -+ if (!disable_pci_irq_limit) { -+ if (maxvec > 32) { -+ nvec = pci_irq_numbers; -+ minvec = min_t(int, pci_irq_numbers, minvec); -+ } -+ } -+#endif -+ - if (maxvec < minvec) - return -ERANGE; - -diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c -index 5163923..e8f2f50 100644 ---- a/drivers/pci/pci-driver.c -+++ b/drivers/pci/pci-driver.c -@@ -620,7 +620,11 @@ static void pci_device_shutdown(struct device *dev) - * If it is not a kexec reboot, firmware will hit the PCI - * devices with big hammer and stop their DMA any way. - */ -+#ifdef CONFIG_LOONGARCH -+ if (kexec_in_progress && !pci_is_bridge(pci_dev) && (pci_dev->current_state <= PCI_D3hot)) -+#else - if (kexec_in_progress && (pci_dev->current_state <= PCI_D3hot)) -+#endif - pci_clear_master(pci_dev); - } - -diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c -index 7e46dcb..73c57f7 100644 ---- a/drivers/pci/pci.c -+++ b/drivers/pci/pci.c -@@ -32,6 +32,9 @@ - #include <asm/dma.h> - #include <linux/aer.h> - #include <linux/bitfield.h> -+#ifdef CONFIG_MACH_LOONGSON64 -+#include <linux/suspend.h> -+#endif - #include "pci.h" - - DEFINE_MUTEX(pci_slot_mutex); -@@ -172,6 +175,15 @@ static bool pci_bridge_d3_disable; - /* Force bridge_d3 for all PCIe ports */ - static bool pci_bridge_d3_force; - -+#ifdef CONFIG_MACH_LOONGSON64 -+ -+#ifndef CONFIG_PM_SLEEP -+suspend_state_t pm_suspend_target_state; -+#define pm_suspend_target_state (PM_SUSPEND_ON) -+#endif -+ -+#endif -+ - static int __init pcie_port_pm_setup(char *str) - { - if (!strcmp(str, "off")) -@@ -6206,8 +6218,9 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) - { - u16 v; - int ret; -+#ifdef CONFIG_MACH_LOONGSON64 - struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus); -- -+#endif - if (rq < 128 || rq > 4096 || !is_power_of_2(rq)) - return -EINVAL; - -@@ -6225,7 +6238,9 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) - - v = (ffs(rq) - 8) << 12; - -- if (bridge->no_inc_mrrs) { -+#ifdef CONFIG_MACH_LOONGSON64 -+ if (pm_suspend_target_state == PM_SUSPEND_ON && -+ bridge->no_inc_mrrs) { - int max_mrrs = pcie_get_readrq(dev); - - if (rq > max_mrrs) { -@@ -6233,6 +6248,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq) - return -EINVAL; - } - } -+#endif - - ret = pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_READRQ, v); -diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c -index c05dd37..861aa11 100644 ---- a/drivers/pci/quirks.c -+++ b/drivers/pci/quirks.c -@@ -383,6 +383,20 @@ static void quirk_tigerpoint_bm_sts(struct pci_dev *dev) - DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGP_LPC, quirk_tigerpoint_bm_sts); - #endif - -+static void loongson_pcie_msi_quirk(struct pci_dev *dev) -+{ -+ u16 val; -+ u16 class; -+ -+ class = dev->class >> 8; -+ if (class == PCI_CLASS_BRIDGE_HOST) { -+ pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &val); -+ val |= PCI_MSI_FLAGS_ENABLE; -+ pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, val); -+ } -+} -+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_LOONGSON, 0x7a59, loongson_pcie_msi_quirk); -+ - /* Chipsets where PCI->PCI transfers vanish or hang */ - static void quirk_nopcipci(struct pci_dev *dev) - { -diff --git a/drivers/platform/loongarch/Kconfig b/drivers/platform/loongarch/Kconfig -index 5633e4d..9ec1a86 100644 ---- a/drivers/platform/loongarch/Kconfig -+++ b/drivers/platform/loongarch/Kconfig -@@ -16,6 +16,14 @@ menuconfig LOONGARCH_PLATFORM_DEVICES - - if LOONGARCH_PLATFORM_DEVICES - -+config CPU_HWMON -+ bool "Loongson CPU HWMon Driver" -+ depends on MACH_LOONGSON64 -+ select HWMON -+ default y -+ help -+ Loongson-3A/3B/3C CPU HWMon (temperature sensor) driver. -+ - config LOONGSON_LAPTOP - tristate "Generic Loongson-3 Laptop Driver" - depends on ACPI -diff --git a/drivers/platform/loongarch/Makefile b/drivers/platform/loongarch/Makefile -index f43ab03d..695688b 100644 ---- a/drivers/platform/loongarch/Makefile -+++ b/drivers/platform/loongarch/Makefile -@@ -1 +1,2 @@ - obj-$(CONFIG_LOONGSON_LAPTOP) += loongson-laptop.o -+obj-$(CONFIG_CPU_HWMON) += cpu_hwmon.o -diff --git a/drivers/platform/loongarch/cpu_hwmon.c b/drivers/platform/loongarch/cpu_hwmon.c -new file mode 100644 -index 0000000..c705d08 ---- /dev/null -+++ b/drivers/platform/loongarch/cpu_hwmon.c -@@ -0,0 +1,196 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Copyright (C) 2022 Loongson Technology Corporation Limited -+ */ -+#include <linux/module.h> -+#include <linux/reboot.h> -+#include <linux/jiffies.h> -+#include <linux/hwmon.h> -+#include <linux/hwmon-sysfs.h> -+ -+#include <asm/loongson.h> -+ -+static int nr_packages; -+static struct device *cpu_hwmon_dev; -+ -+static int loongson3_cpu_temp(int cpu) -+{ -+ u32 reg; -+ -+ reg = iocsr_read32(LOONGARCH_IOCSR_CPUTEMP) & 0xff; -+ -+ return (int)((s8)reg) * 1000; -+} -+ -+static ssize_t cpu_temp_label(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ int id = (to_sensor_dev_attr(attr))->index - 1; -+ -+ return sprintf(buf, "CPU %d Temperature\n", id); -+} -+ -+static ssize_t get_cpu_temp(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ int id = (to_sensor_dev_attr(attr))->index - 1; -+ int value = loongson3_cpu_temp(id); -+ -+ return sprintf(buf, "%d\n", value); -+} -+ -+static SENSOR_DEVICE_ATTR(temp1_input, 0444, get_cpu_temp, NULL, 1); -+static SENSOR_DEVICE_ATTR(temp1_label, 0444, cpu_temp_label, NULL, 1); -+static SENSOR_DEVICE_ATTR(temp2_input, 0444, get_cpu_temp, NULL, 2); -+static SENSOR_DEVICE_ATTR(temp2_label, 0444, cpu_temp_label, NULL, 2); -+static SENSOR_DEVICE_ATTR(temp3_input, 0444, get_cpu_temp, NULL, 3); -+static SENSOR_DEVICE_ATTR(temp3_label, 0444, cpu_temp_label, NULL, 3); -+static SENSOR_DEVICE_ATTR(temp4_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp4_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp5_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp5_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp6_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp6_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp7_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp7_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp8_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp8_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp9_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp9_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp10_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp10_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp11_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp11_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp12_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp12_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp13_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp13_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp14_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp14_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp15_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp15_label, 0444, cpu_temp_label, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp16_input, 0444, get_cpu_temp, NULL, 4); -+static SENSOR_DEVICE_ATTR(temp16_label, 0444, cpu_temp_label, NULL, 4); -+ -+static struct attribute *cpu_hwmon_attributes[] = { -+ &sensor_dev_attr_temp1_input.dev_attr.attr, -+ &sensor_dev_attr_temp1_label.dev_attr.attr, -+ &sensor_dev_attr_temp2_input.dev_attr.attr, -+ &sensor_dev_attr_temp2_label.dev_attr.attr, -+ &sensor_dev_attr_temp3_input.dev_attr.attr, -+ &sensor_dev_attr_temp3_label.dev_attr.attr, -+ &sensor_dev_attr_temp4_input.dev_attr.attr, -+ &sensor_dev_attr_temp4_label.dev_attr.attr, -+ &sensor_dev_attr_temp5_input.dev_attr.attr, -+ &sensor_dev_attr_temp5_label.dev_attr.attr, -+ &sensor_dev_attr_temp6_input.dev_attr.attr, -+ &sensor_dev_attr_temp6_label.dev_attr.attr, -+ &sensor_dev_attr_temp7_input.dev_attr.attr, -+ &sensor_dev_attr_temp7_label.dev_attr.attr, -+ &sensor_dev_attr_temp8_input.dev_attr.attr, -+ &sensor_dev_attr_temp8_label.dev_attr.attr, -+ &sensor_dev_attr_temp9_input.dev_attr.attr, -+ &sensor_dev_attr_temp9_label.dev_attr.attr, -+ &sensor_dev_attr_temp10_input.dev_attr.attr, -+ &sensor_dev_attr_temp10_label.dev_attr.attr, -+ &sensor_dev_attr_temp11_input.dev_attr.attr, -+ &sensor_dev_attr_temp11_label.dev_attr.attr, -+ &sensor_dev_attr_temp12_input.dev_attr.attr, -+ &sensor_dev_attr_temp12_label.dev_attr.attr, -+ &sensor_dev_attr_temp13_input.dev_attr.attr, -+ &sensor_dev_attr_temp13_label.dev_attr.attr, -+ &sensor_dev_attr_temp14_input.dev_attr.attr, -+ &sensor_dev_attr_temp14_label.dev_attr.attr, -+ &sensor_dev_attr_temp15_input.dev_attr.attr, -+ &sensor_dev_attr_temp15_label.dev_attr.attr, -+ &sensor_dev_attr_temp16_input.dev_attr.attr, -+ &sensor_dev_attr_temp16_label.dev_attr.attr, -+ NULL -+}; -+static umode_t cpu_hwmon_is_visible(struct kobject *kobj, -+ struct attribute *attr, int i) -+{ -+ int id = i / 2; -+ -+ if (id < nr_packages) -+ return attr->mode; -+ return 0; -+} -+ -+static struct attribute_group cpu_hwmon_group = { -+ .attrs = cpu_hwmon_attributes, -+ .is_visible = cpu_hwmon_is_visible, -+}; -+ -+static const struct attribute_group *cpu_hwmon_groups[] = { -+ &cpu_hwmon_group, -+ NULL -+}; -+ -+static int cpu_initial_threshold = 72000; -+static int cpu_thermal_threshold = 96000; -+module_param(cpu_thermal_threshold, int, 0644); -+MODULE_PARM_DESC(cpu_thermal_threshold, "cpu thermal threshold (96000 (default))"); -+ -+static struct delayed_work thermal_work; -+ -+static void do_thermal_timer(struct work_struct *work) -+{ -+ int i, value, temp_max = 0; -+ -+ for (i = 0; i < nr_packages; i++) { -+ value = loongson3_cpu_temp(i); -+ if (value > temp_max) -+ temp_max = value; -+ } -+ -+ if (temp_max <= cpu_thermal_threshold) -+ schedule_delayed_work(&thermal_work, msecs_to_jiffies(5000)); -+ else -+ orderly_poweroff(true); -+} -+ -+static int __init loongson_hwmon_init(void) -+{ -+ int i, value, temp_max = 0; -+ -+ pr_info("Loongson Hwmon Enter...\n"); -+ -+ nr_packages = loongson_sysconf.nr_cpus / -+ loongson_sysconf.cores_per_package; -+ -+ cpu_hwmon_dev = hwmon_device_register_with_groups(NULL, "cpu_hwmon", -+ NULL, cpu_hwmon_groups); -+ if (IS_ERR(cpu_hwmon_dev)) { -+ pr_err("Hwmon register fail with %ld!\n", PTR_ERR(cpu_hwmon_dev)); -+ return PTR_ERR(cpu_hwmon_dev); -+ } -+ -+ for (i = 0; i < nr_packages; i++) { -+ value = loongson3_cpu_temp(i); -+ if (value > temp_max) -+ temp_max = value; -+ } -+ -+ pr_info("Initial CPU temperature is %d (highest).\n", temp_max); -+ if (temp_max > cpu_initial_threshold) -+ cpu_thermal_threshold += temp_max - cpu_initial_threshold; -+ -+ INIT_DEFERRABLE_WORK(&thermal_work, do_thermal_timer); -+ schedule_delayed_work(&thermal_work, msecs_to_jiffies(20000)); -+ -+ return 0; -+} -+ -+static void __exit loongson_hwmon_exit(void) -+{ -+ cancel_delayed_work_sync(&thermal_work); -+ hwmon_device_unregister(cpu_hwmon_dev); -+} -+ -+module_init(loongson_hwmon_init); -+module_exit(loongson_hwmon_exit); -+ -+MODULE_AUTHOR("Huacai Chen <chenhuacai@loongson.cn>"); -+MODULE_DESCRIPTION("Loongson CPU Hwmon driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig -index 8ebcddf..3bd5561 100644 ---- a/drivers/pwm/Kconfig -+++ b/drivers/pwm/Kconfig -@@ -454,6 +454,16 @@ config PWM_PCA9685 - To compile this driver as a module, choose M here: the module - will be called pwm-pca9685. - -+config PWM_PHYTIUM -+ tristate "Phytium PWM support" -+ depends on ARCH_PHYTIUM -+ help -+ Generic PWM framework driver for the PWM controller found on -+ Phytium SoCs. -+ -+ To compile this driver as a module, choose M here: the module -+ will be called pwm-phytium. -+ - config PWM_PXA - tristate "PXA PWM support" - depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST -diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile -index c822389..e3fb6e9 100644 ---- a/drivers/pwm/Makefile -+++ b/drivers/pwm/Makefile -@@ -41,6 +41,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o - obj-$(CONFIG_PWM_NTXEC) += pwm-ntxec.o - obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o - obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o -+obj-$(CONFIG_PWM_PHYTIUM) += pwm-phytium.o - obj-$(CONFIG_PWM_PXA) += pwm-pxa.o - obj-$(CONFIG_PWM_RASPBERRYPI_POE) += pwm-raspberrypi-poe.o - obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o -diff --git a/drivers/pwm/pwm-phytium.c b/drivers/pwm/pwm-phytium.c -new file mode 100644 -index 0000000..cd64e48 ---- /dev/null -+++ b/drivers/pwm/pwm-phytium.c -@@ -0,0 +1,590 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Phytium PWM driver -+ * -+ * Copyright (C) 2021-2023, Phytium Technology Co., Ltd. -+ */ -+ -+#include <linux/bitops.h> -+#include <linux/clk.h> -+#include <linux/export.h> -+#include <linux/err.h> -+#include <linux/io.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/of.h> -+#include <linux/platform_device.h> -+#include <linux/pwm.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+#include <linux/time.h> -+#include <linux/acpi.h> -+ -+#define REG_TCNT 0x00 -+#define REG_TCTRL 0x04 -+#define REG_STAT 0x08 -+ -+#define REG_TPERIOD 0x0c -+#define REG_PWMCTRL 0x10 -+#define REG_PWMCCR 0x14 -+ -+#define TCTRL_DIV_MASK 0x1ff8 -+#define TCTRL_PWMMOD_MASK 0x4 -+#define TCTRL_CAPMOD_MASK 0x3 -+#define PWM_PERIOD_MASK 0xffff -+#define PWM_DUTY_MASK 0xffff -+#define PWM_MODE_MASK 0x4 -+#define PWM_CTRL_INIT 0xc4 -+ -+#define PWM_NUM 2 -+ -+#define REG_DBCTRL 0x00 -+#define REG_DBCLY 0x04 -+#define PWM_UPDBCLY_MASK 0x3ff -+#define PWM_DWDBCLY_MASK 0xffc00 -+#define PWM_DB_POLARITY_MASK 0xc -+ -+#define PWM_N(x) ((0x400)*(x)) -+#define MAX_PARAMETER 2 -+ -+struct phytium_pwm_state { -+ int rst; -+ int cntmod; -+ int dutymod; -+ unsigned int div; -+ int db_rst; -+ unsigned int updbcly; -+ unsigned int dwdbcly; -+ unsigned int dbpolarity; -+}; -+ -+struct phytium_pwm_param { -+ int cntmod; -+ int dutymod; -+ unsigned int div; -+ unsigned int updbcly; -+ unsigned int dwdbcly; -+ unsigned int dbpolarity; -+}; -+ -+struct phytium_pwm_variant { -+ u8 rst_mask; -+ u8 div; -+ int counter_mode; -+ int periodns; -+ int duty_ns; -+ int pwm_mode; -+ u8 duty_mode; -+ int updbcly; -+ int dwdbcly; -+}; -+ -+struct phytium_pwm_channel { -+ u32 period_ns; -+ u32 duty_ns; -+ u32 tin_ns; -+}; -+ -+struct phytium_pwm_chip { -+ struct pwm_chip chip; -+ struct pwm_state state_pm[PWM_NUM]; -+ struct phytium_pwm_variant variant; -+ struct phytium_pwm_state state; -+ u8 inverter_mask; -+ u8 disabled_mask; -+ int db_init; -+ void __iomem *base; -+ void __iomem *base1; -+ struct phytium_pwm_param parameter[MAX_PARAMETER]; -+ unsigned int num_parameters; -+ -+ struct clk *base_clk; -+}; -+ -+static inline struct phytium_pwm_chip *to_phytium_pwm_chip(struct pwm_chip *chip) -+{ -+ return container_of(chip, struct phytium_pwm_chip, chip); -+} -+ -+ -+static void pwm_phytium_free(struct pwm_chip *chip, struct pwm_device *pwm) -+{ -+ devm_kfree(chip->dev, pwm_get_chip_data(pwm)); -+ pwm_set_chip_data(pwm, NULL); -+} -+ -+static int pwm_phytium_enable(struct pwm_chip *chip, struct pwm_device *pwm, int n) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ u32 reg; -+ -+ reg = readl(our_chip->base + PWM_N(n) + REG_TCTRL); -+ reg |= 0x2; -+ our_chip->state_pm[n].enabled = 1; -+ writel(reg, our_chip->base + PWM_N(n) + REG_TCTRL); -+ -+ return 0; -+} -+ -+static void pwm_phytium_disable(struct pwm_chip *chip, struct pwm_device *pwm, int n) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ u32 reg; -+ -+ reg = readl(our_chip->base + PWM_N(n) + REG_TCTRL); -+ reg &= 0xfffffffd; -+ our_chip->state_pm[n].enabled = 0; -+ writel(reg, our_chip->base + PWM_N(n) + REG_TCTRL); -+} -+ -+static void pwm_phytium_dutymod(struct pwm_chip *chip, int dutymod, int n) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ u32 reg; -+ -+ reg = readl(our_chip->base + PWM_N(n) + REG_PWMCTRL); -+ -+ if (dutymod == 0) -+ reg &= 0xfffffeff; -+ else if (dutymod == 1) -+ reg |= 0x100; -+ -+ writel(reg, our_chip->base + PWM_N(n) + REG_PWMCTRL); -+} -+ -+static void pwm_phytium_set_div(struct pwm_chip *chip, unsigned int div, int n) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ u32 reg; -+ -+ reg = readl(our_chip->base + PWM_N(n) + REG_TCTRL); -+ reg &= 0xffff; -+ reg |= (div<<16); -+ writel(reg, our_chip->base + PWM_N(n) + REG_TCTRL); -+} -+ -+static void pwm_phytium_set_tmode(struct pwm_chip *chip, int tmode, int n) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ u32 reg; -+ -+ reg = readl(our_chip->base + PWM_N(n) + REG_TCTRL); -+ if (tmode == 0) -+ reg &= 0xfffffffb; -+ else if (tmode == 1) -+ reg |= 0x4; -+ -+ writel(reg, our_chip->base + PWM_N(n) + REG_TCTRL); -+} -+ -+static void pwm_phytium_set_periodns(struct pwm_chip *chip, unsigned int periodns, int n) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ u32 reg; -+ int div = our_chip->state.div; -+ u64 cycles; -+ -+ if (has_acpi_companion(chip->dev)) -+ device_property_read_u64(chip->dev, "clock-frequency", &cycles); -+ else -+ cycles = clk_get_rate(our_chip->base_clk); -+ cycles *= (periodns / (div + 1)); -+ do_div(cycles, NSEC_PER_SEC); -+ -+ reg = readl(our_chip->base + PWM_N(n) + REG_TPERIOD); -+ cycles = (cycles & PWM_PERIOD_MASK) - 0x1; -+ our_chip->state_pm[n].period = cycles; -+ -+ writel(cycles, our_chip->base + PWM_N(n) + REG_TPERIOD); -+} -+ -+static void pwm_phytium_set_duty(struct pwm_chip *chip, unsigned int duty, int n) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ u32 reg; -+ int div = our_chip->state.div; -+ u64 cycles; -+ -+ if (has_acpi_companion(chip->dev)) -+ device_property_read_u64(chip->dev, "clock-frequency", &cycles); -+ else -+ cycles = clk_get_rate(our_chip->base_clk); -+ cycles *= (duty / (div + 1)); -+ do_div(cycles, NSEC_PER_SEC); -+ -+ reg = readl(our_chip->base + PWM_N(n) + REG_PWMCCR); -+ cycles = (cycles & PWM_DUTY_MASK) - 0x1; -+ our_chip->state_pm[n].duty_cycle = cycles; -+ -+ writel(cycles, our_chip->base + PWM_N(n) + REG_PWMCCR); -+} -+ -+static int pwm_phytium_set_dbcly(struct pwm_chip *chip, unsigned int updbcly, unsigned int dwdbcly) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ u32 reg; -+ u64 dbcly, cycles, upcycles, dwcycles; -+ -+ reg = readl(our_chip->base + REG_TPERIOD); -+ if (has_acpi_companion(chip->dev)) -+ device_property_read_u64(chip->dev, "clock-frequency", &cycles); -+ else -+ cycles = clk_get_rate(our_chip->base_clk); -+ dbcly &= 0x0; -+ if (updbcly) { -+ upcycles = cycles * updbcly; -+ do_div(upcycles, NSEC_PER_SEC); -+ -+ if (upcycles < reg) -+ dbcly |= (upcycles & PWM_UPDBCLY_MASK); -+ else -+ return -EINVAL; -+ } -+ -+ if (dwdbcly) { -+ dwcycles = cycles * dwdbcly; -+ do_div(dwcycles, NSEC_PER_SEC); -+ -+ if (dwcycles < reg) -+ dbcly |= ((dwcycles << 10) & PWM_DWDBCLY_MASK); -+ else -+ return -EINVAL; -+ } -+ -+ writel(dbcly, our_chip->base1 + REG_DBCLY); -+ -+ reg = readl(our_chip->base1 + REG_DBCTRL); -+ reg |= 0x30; -+ writel(reg, our_chip->base1 + REG_DBCTRL); -+ -+ return 0; -+} -+ -+static void pwm_phytium_set_dbpolarity(struct pwm_chip *chip, unsigned int db_polarity) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ u32 reg; -+ -+ reg = readl(our_chip->base1 + REG_DBCTRL); -+ reg &= 0x33; -+ reg |= ((db_polarity<<2) & PWM_DB_POLARITY_MASK); -+ writel(reg, our_chip->base1 + REG_DBCTRL); -+} -+ -+static int pwm_phytium_init(struct pwm_chip *chip, struct pwm_device *pwm, int n) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ -+ writel(PWM_CTRL_INIT, our_chip->base + PWM_N(n) + REG_PWMCTRL); -+ -+ pwm_phytium_dutymod(chip, our_chip->state.dutymod, n); -+ pwm_phytium_set_div(chip, our_chip->state.div, n); -+ pwm_phytium_set_tmode(chip, our_chip->state.cntmod, n); -+ -+ return 0; -+} -+ -+static int pwm_phytium_db_init(struct pwm_chip *chip, struct pwm_device *pwm) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ -+ pwm_phytium_set_dbcly(chip, our_chip->state.updbcly, our_chip->state.dwdbcly); -+ pwm_phytium_set_dbpolarity(chip, our_chip->state.dbpolarity); -+ -+ return 0; -+} -+ -+static int __pwm_phytium_config(struct pwm_chip *chip, struct pwm_device *pwm) -+{ -+ pwm_phytium_init(chip, pwm, 0); -+ pwm_phytium_init(chip, pwm, 1); -+ return 0; -+} -+ -+static int pwm_phytium_set_polarity(struct pwm_chip *chip, enum pwm_polarity polarity, int n) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ u32 value; -+ -+ value = readl(our_chip->base + PWM_N(n) + REG_PWMCTRL); -+ -+ if (polarity == PWM_POLARITY_INVERSED) { -+ value &= 0xffffff0f; -+ value |= 0x30; -+ } else if (polarity == PWM_POLARITY_NORMAL) { -+ value &= 0xffffff0f; -+ value |= 0x40; -+ } -+ -+ our_chip->state_pm[n].polarity = polarity; -+ writel(value, our_chip->base + PWM_N(n) + REG_PWMCTRL); -+ -+ return 0; -+} -+ -+static int pwm_phytium_apply(struct pwm_chip *chip, struct pwm_device *pwm, -+ const struct pwm_state *state) -+{ -+ struct phytium_pwm_chip *phytium_pwm = to_phytium_pwm_chip(chip); -+ struct pwm_state cstate; -+ u32 reg; -+ int n; -+ -+ pwm_get_state(pwm, &cstate); -+ -+ n = pwm->hwpwm & BIT(0); -+ -+ if ((state->polarity != cstate.polarity) && !state->enabled) -+ pwm_phytium_set_polarity(chip, state->polarity, n); -+ -+ if (state->enabled && !cstate.enabled) -+ pwm_phytium_enable(chip, pwm, n); -+ -+ if (!state->enabled && cstate.enabled) -+ pwm_phytium_disable(chip, pwm, n); -+ -+ if (state->period != cstate.period) { -+ pwm_phytium_set_periodns(chip, state->period, n); -+ if ((phytium_pwm->db_init == 1) && (n == 0)) -+ pwm_phytium_db_init(chip, pwm); -+ } -+ -+ if (state->duty_cycle != cstate.duty_cycle) { -+ if (phytium_pwm->state.dutymod == true) { -+ reg = readl(phytium_pwm->base + PWM_N(n) + REG_STAT); -+ if ((reg & 0x8) != 0x8) -+ pwm_phytium_set_duty(chip, state->duty_cycle, n); -+ } else { -+ pwm_phytium_set_duty(chip, state->duty_cycle, n); -+ } -+ } -+ -+ return 0; -+} -+ -+static int pwm_phytium_request(struct pwm_chip *chip, struct pwm_device *pwm) -+{ -+ struct phytium_pwm_chip *our_chip = to_phytium_pwm_chip(chip); -+ struct phytium_pwm_channel *our_chan; -+ -+ our_chan = devm_kzalloc(chip->dev, sizeof(*our_chan), GFP_KERNEL); -+ if (!our_chan) -+ return -ENOMEM; -+ -+ pwm_set_chip_data(pwm, our_chan); -+ __pwm_phytium_config(&our_chip->chip, our_chip->chip.pwms); -+ -+ return 0; -+} -+ -+static const struct pwm_ops pwm_phytium_ops = { -+ .request = pwm_phytium_request, -+ .free = pwm_phytium_free, -+ .apply = pwm_phytium_apply, -+ .owner = THIS_MODULE, -+}; -+ -+static int phytium_pwm_set_parameter(struct phytium_pwm_chip *priv) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < priv->num_parameters; i++) { -+ if (priv->parameter[i].updbcly > 0 || priv->parameter[i].dwdbcly > 0) { -+ priv->db_init = 1; -+ priv->state.db_rst = 1; -+ } -+ -+ priv->state.cntmod = priv->parameter[i].cntmod; -+ priv->state.dutymod = priv->parameter[i].dutymod; -+ priv->state.div = priv->parameter[i].div; -+ priv->state.updbcly = priv->parameter[i].updbcly; -+ priv->state.dwdbcly = priv->parameter[i].dwdbcly; -+ priv->state.dbpolarity = priv->parameter[i].dbpolarity; -+ } -+ priv->state.rst = 1; -+ -+ return 0; -+} -+ -+static int pwm_phytium_probe_parameter(struct phytium_pwm_chip *priv, -+ struct device_node *np) -+{ -+ int nb, ret, array_size; -+ unsigned int i; -+ -+ if (has_acpi_companion(priv->chip.dev)) { -+ priv->num_parameters = 1; -+ array_size = sizeof(struct phytium_pwm_param) / sizeof(u32); -+ ret = fwnode_property_read_u32_array(dev_fwnode(priv->chip.dev), -+ "phytium,db", (u32 *)priv->parameter, -+ array_size); -+ if (ret < 0) -+ return ret; -+ } else { -+ nb = of_property_count_elems_of_size(np, "phytium,db", -+ sizeof(struct phytium_pwm_param)); -+ if (nb <= 0 || nb > MAX_PARAMETER) -+ return -EINVAL; -+ -+ priv->num_parameters = nb; -+ array_size = nb * sizeof(struct phytium_pwm_param) / sizeof(u32); -+ ret = of_property_read_u32_array(np, "phytium,db", -+ (u32 *)priv->parameter, array_size); -+ if (ret) -+ return ret; -+ } -+ -+ for (i = 0; i < priv->num_parameters; i++) { -+ if (priv->parameter[i].cntmod > 1 || -+ priv->parameter[i].dutymod > 1 || -+ priv->parameter[i].div > 4096 || -+ priv->parameter[i].dbpolarity > 3) -+ return -EINVAL; -+ } -+ -+ return phytium_pwm_set_parameter(priv); -+} -+static int pwm_phytium_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct device_node *np = dev->of_node; -+ struct phytium_pwm_chip *chip; -+ struct resource *res; -+ int ret; -+ -+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); -+ -+ if (chip == NULL) -+ return -ENOMEM; -+ -+ chip->chip.dev = &pdev->dev; -+ chip->chip.ops = &pwm_phytium_ops; -+ chip->chip.base = -1; -+ chip->chip.npwm = PWM_NUM; -+ chip->inverter_mask = BIT(PWM_NUM) - 1; -+ -+ if (pdev->dev.of_node) { -+ chip->chip.of_xlate = of_pwm_xlate_with_flags; -+ chip->chip.of_pwm_n_cells = 3; -+ } -+ -+ ret = pwm_phytium_probe_parameter(chip, np); -+ if (ret) { -+ dev_err(dev, "failed to set parameter\n"); -+ return ret; -+ } -+ -+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ chip->base1 = devm_ioremap_resource(&pdev->dev, res); -+ chip->base = (chip->base1 + 0x400); -+ -+ if (!has_acpi_companion(&pdev->dev)) { -+ if (IS_ERR(chip->base)) { -+ dev_err(dev, "failed to get base_addr\n"); -+ return PTR_ERR(chip->base); -+ } -+ -+ if (pdev->dev.of_node) { -+ chip->base_clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(chip->base_clk)) { -+ dev_err(dev, "failed to get clk\n"); -+ return PTR_ERR(chip->base_clk); -+ } -+ -+ ret = clk_prepare_enable(chip->base_clk); -+ if (ret < 0) { -+ dev_err(dev, "failed to enable clk\n"); -+ return ret; -+ } -+ } -+ } -+ -+ platform_set_drvdata(pdev, chip); -+ -+ ret = pwmchip_add(&chip->chip); -+ -+ if (ret < 0) { -+ dev_err(dev, "failed to register PWM chip\n"); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int pwm_phytium_remove(struct platform_device *pdev) -+{ -+ struct phytium_pwm_chip *chip = platform_get_drvdata(pdev); -+ -+ pwmchip_remove(&chip->chip); -+ -+ clk_disable_unprepare(chip->base_clk); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int pwm_phytium_pm_init(struct phytium_pwm_chip *priv) -+{ -+ int i; -+ -+ __pwm_phytium_config(&priv->chip, priv->chip.pwms); -+ for (i = 0; i < priv->chip.npwm; i++) { -+ writel(priv->state_pm[i].period, priv->base + PWM_N(i) + REG_TPERIOD); -+ if ((priv->db_init == 1) && (i == 0)) -+ pwm_phytium_db_init(&priv->chip, priv->chip.pwms); -+ writel(priv->state_pm[i].duty_cycle, priv->base + PWM_N(i) + REG_PWMCTRL); -+ pwm_phytium_set_polarity(&priv->chip, priv->state_pm[i].polarity, i); -+ if (priv->state_pm[i].enabled) -+ pwm_phytium_enable(&priv->chip, priv->chip.pwms, i); -+ } -+ -+ return 0; -+} -+ -+static int pwm_phytium_suspend(struct device *dev) -+{ -+ return 0; -+} -+ -+static int pwm_phytium_resume(struct device *dev) -+{ -+ struct phytium_pwm_chip *priv = dev_get_drvdata(dev); -+ -+ pwm_phytium_pm_init(priv); -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(phytium_pwm_dev_pm_ops, pwm_phytium_suspend, pwm_phytium_resume); -+ -+static const struct of_device_id phytium_pwm_matches[] = { -+ { .compatible = "phytium,pwm" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, phytium_pwm_matches); -+ -+#ifdef CONFIG_ACPI -+static const struct acpi_device_id phytium_pwm_acpi_matches[] = { -+ { "PHYT0029", 0 }, -+ {} -+}; -+MODULE_DEVICE_TABLE(acpi, phytium_pwm_acpi_matches); -+#endif -+ -+static struct platform_driver pwm_phytium_driver = { -+ .driver = { -+ .name = "phytium-pwm", -+ .pm = &phytium_pwm_dev_pm_ops, -+ .of_match_table = phytium_pwm_matches, -+#ifdef CONFIG_ACPI -+ .acpi_match_table = phytium_pwm_acpi_matches, -+#endif -+ }, -+ .probe = pwm_phytium_probe, -+ .remove = pwm_phytium_remove, -+}; -+module_platform_driver(pwm_phytium_driver); -+ -+MODULE_DESCRIPTION("Phytium SoC PWM driver"); -+MODULE_AUTHOR("Yang Liu <yangliu2021@phytium.com.cn>"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c -index 052ccad..7d19bf0 100644 ---- a/drivers/pwm/sysfs.c -+++ b/drivers/pwm/sysfs.c -@@ -260,8 +260,15 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm) - export->child.parent = parent; - export->child.devt = MKDEV(0, 0); - export->child.groups = pwm_groups; -- dev_set_name(&export->child, "pwm%u", pwm->hwpwm); - -+#ifdef CONFIG_ARCH_PHYTIUM -+ if (read_cpuid_implementor() == ARM_CPU_IMP_PHYTIUM) -+ dev_set_name(&export->child, "pwm%u", pwm->pwm); -+ else -+ dev_set_name(&export->child, "pwm%u", pwm->hwpwm); -+#else -+ dev_set_name(&export->child, "pwm%u", pwm->hwpwm); -+#endif - ret = device_register(&export->child); - if (ret) { - clear_bit(PWMF_EXPORTED, &pwm->flags); -diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c -index 14625e6..9cf5b11b 100644 ---- a/drivers/scsi/qedf/qedf_main.c -+++ b/drivers/scsi/qedf/qedf_main.c -@@ -2737,7 +2737,8 @@ static int qedf_alloc_and_init_sb(struct qedf_ctx *qedf, - sb_id, QED_SB_TYPE_STORAGE); - - if (ret) { -- QEDF_ERR(&qedf->dbg_ctx, -+ dma_free_coherent(&qedf->pdev->dev, sizeof(*sb_virt), sb_virt, sb_phys); -+ QEDF_ERR(&qedf->dbg_ctx, - "Status block initialization failed (0x%x) for id = %d.\n", - ret, sb_id); - return ret; -diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig -index bdc568a..6ddca3e 100644 ---- a/drivers/tty/serial/Kconfig -+++ b/drivers/tty/serial/Kconfig -@@ -85,6 +85,18 @@ config SERIAL_EARLYCON_SEMIHOST - This is enabled with "earlycon=smh" on the kernel command line. - The console is enabled when early_param is processed. - -+config SERIAL_PHYTIUM_PCI -+ tristate "Phytium PCI serial port support" -+ depends on PCI -+ select SERIAL_CORE -+ help -+ This driver supports the Phytium UART controller on PCI/PCIe adapters. -+ If you want to compile this driver into the kernel, say Y here. To -+ compile this driver as a module, choose M here. -+ -+ If unsure, say N. -+ -+ - config SERIAL_EARLYCON_RISCV_SBI - bool "Early console using RISC-V SBI" - depends on RISCV_SBI_V01 -diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile -index 138abbc..cd1d9c7 100644 ---- a/drivers/tty/serial/Makefile -+++ b/drivers/tty/serial/Makefile -@@ -88,6 +88,7 @@ obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o - obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o - obj-$(CONFIG_SERIAL_LITEUART) += liteuart.o - obj-$(CONFIG_SERIAL_SUNPLUS) += sunplus-uart.o -+obj-$(CONFIG_SERIAL_PHYTIUM_PCI) += phytium-uart.o - - # GPIOLIB helpers for modem control lines - obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o -diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c -index a5fbb6e..8142878 100644 ---- a/drivers/tty/serial/earlycon.c -+++ b/drivers/tty/serial/earlycon.c -@@ -40,7 +40,11 @@ static void __iomem * __init earlycon_map(resource_size_t paddr, size_t size) - { - void __iomem *base; - #ifdef CONFIG_FIX_EARLYCON_MEM -+ #ifdef CONFIG_PTP -+ __iee_set_fixmap_pre_init(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK, FIXMAP_PAGE_IO); -+ #else - set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr & PAGE_MASK); -+ #endif - base = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); - base += paddr & ~PAGE_MASK; - #else -diff --git a/drivers/tty/serial/phytium-uart.c b/drivers/tty/serial/phytium-uart.c -new file mode 100644 -index 0000000..1839203 ---- /dev/null -+++ b/drivers/tty/serial/phytium-uart.c -@@ -0,0 +1,927 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* -+ * Driver for Phytium PCI UART controller -+ * -+ * Copyright (c) 2021-2023, Phytium Techonology Co., Ltd. -+ * -+ * Derived from drivers/tty/serial/amba-pl011.c -+ * Copyright 1999 ARM Limited -+ * Copyright (C) 2000 Deep Blue Solutions Ltd. -+ * Copyright (C) 2010 ST-Ericsson SA -+ */ -+ -+#include <linux/console.h> -+#include <linux/delay.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/ioport.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/serial.h> -+#include <linux/serial_core.h> -+#include <linux/tty.h> -+#include <linux/tty_flip.h> -+ -+#define DRV_NAME "phytium_uart" -+ -+#define REG_DR 0x00 -+#define REG_FR 0x18 -+#define REG_IBRD 0x24 -+#define REG_FBRD 0x28 -+#define REG_LCRH_RX 0x2c -+#define REG_LCRH_TX 0x2c -+#define REG_CR 0x30 -+#define REG_IFLS 0x34 -+#define REG_IMSC 0x38 -+#define REG_RIS 0x3c -+#define REG_MIS 0x40 -+#define REG_ICR 0x44 -+ -+#define REG_DR_OE (1 << 11) -+#define REG_DR_BE (1 << 10) -+#define REG_DR_PE (1 << 9) -+#define REG_DR_FE (1 << 8) -+ -+#define REG_LCRH_SPS 0x80 -+#define REG_LCRH_WLEN_8 0x60 -+#define REG_LCRH_WLEN_7 0x40 -+#define REG_LCRH_WLEN_6 0x20 -+#define REG_LCRH_WLEN_5 0x00 -+#define REG_LCRH_FEN 0x10 -+#define REG_LCRH_STP2 0x08 -+#define REG_LCRH_EPS 0x04 -+#define REG_LCRH_PEN 0x02 -+#define REG_LCRH_BRK 0x01 -+ -+#define REG_FR_RI 0x100 -+#define REG_FR_TXFE 0x080 -+#define REG_FR_RXFF 0x040 -+#define REG_FR_TXFF 0x020 -+#define REG_FR_RXFE 0x010 -+#define REG_FR_BUSY 0x008 -+#define REG_FR_DCD 0x004 -+#define REG_FR_DSR 0x002 -+#define REG_FR_CTS 0x001 -+#define REG_FR_TMSK (REG_FR_TXFF + REG_FR_BUSY) -+ -+#define REG_CR_CTSEN 0x8000 /* CTS hardware flow control */ -+#define REG_CR_RTSEN 0x4000 /* RTS hardware flow control */ -+#define REG_CR_OUT2 0x2000 /* OUT2 */ -+#define REG_CR_OUT1 0x1000 /* OUT1 */ -+#define REG_CR_RTS 0x0800 /* RTS */ -+#define REG_CR_DTR 0x0400 /* DTR */ -+#define REG_CR_RXE 0x0200 /* receive enable */ -+#define REG_CR_TXE 0x0100 /* transmit enable */ -+#define REG_CR_LBE 0x0080 /* loopback enable */ -+#define REG_CR_RTIE 0x0040 -+#define REG_CR_TIE 0x0020 -+#define REG_CR_RIE 0x0010 -+#define REG_CR_MSIE 0x0008 -+#define REG_CR_IIRLP 0x0004 /* SIR low power mode */ -+#define REG_CR_SIREN 0x0002 /* SIR enable */ -+#define REG_CR_UARTEN 0x0001 /* UART enable */ -+ -+#define REG_IFLS_RX1_8 (0 << 3) -+#define REG_IFLS_RX2_8 (1 << 3) -+#define REG_IFLS_RX4_8 (2 << 3) -+#define REG_IFLS_RX6_8 (3 << 3) -+#define REG_IFLS_RX7_8 (4 << 3) -+#define REG_IFLS_TX1_8 (0 << 0) -+#define REG_IFLS_TX2_8 (1 << 0) -+#define REG_IFLS_TX4_8 (2 << 0) -+#define REG_IFLS_TX6_8 (3 << 0) -+ -+#define REG_IMSC_OEIM (1 << 10) /* overrun error interrupt mask */ -+#define REG_IMSC_BEIM (1 << 9) /* break error interrupt mask */ -+#define REG_IMSC_PEIM (1 << 8) /* parity error interrupt mask */ -+#define REG_IMSC_FEIM (1 << 7) /* framing error interrupt mask */ -+#define REG_IMSC_RTIM (1 << 6) /* receive timeout interrupt mask */ -+#define REG_IMSC_TXIM (1 << 5) /* transmit interrupt mask */ -+#define REG_IMSC_RXIM (1 << 4) /* receive interrupt mask */ -+#define REG_IMSC_DSRMIM (1 << 3) /* DSR interrupt mask */ -+#define REG_IMSC_DCDMIM (1 << 2) /* DCD interrupt mask */ -+#define REG_IMSC_CTSMIM (1 << 1) /* CTS interrupt mask */ -+#define REG_IMSC_RIMIM (1 << 0) /* RI interrupt mask */ -+ -+#define REG_ICR_OEIS (1 << 10) /* overrun error interrupt status */ -+#define REG_ICR_BEIS (1 << 9) /* break error interrupt status */ -+#define REG_ICR_PEIS (1 << 8) /* parity error interrupt status */ -+#define REG_ICR_FEIS (1 << 7) /* framing error interrupt status */ -+#define REG_ICR_RTIS (1 << 6) /* receive timeout interrupt status */ -+#define REG_ICR_TXIS (1 << 5) /* transmit interrupt status */ -+#define REG_ICR_RXIS (1 << 4) /* receive interrupt status */ -+#define REG_ICR_DSRMIS (1 << 3) /* DSR interrupt status */ -+#define REG_ICR_DCDMIS (1 << 2) /* DCD interrupt status */ -+#define REG_ICR_CTSMIS (1 << 1) /* CTS interrupt status */ -+#define REG_ICR_RIMIS (1 << 0) /* RI interrupt status */ -+ -+#define UART_NR 12 -+ -+#define UART_DR_ERROR (REG_DR_OE|REG_DR_BE|REG_DR_PE|REG_DR_FE) -+#define UART_DUMMY_DR_RX (1 << 16) -+ -+#define DEFAULT_UARTCLK 48000000 /* 48 MHz */ -+ -+/* -+ * We wrap our port structure around the generic uart_port. -+ */ -+struct phytium_uart_port { -+ struct uart_port port; -+ unsigned int im; /* interrupt mask */ -+ unsigned int old_status; -+ unsigned int old_cr; /* state during shutdown */ -+ char type[12]; -+}; -+ -+static unsigned int phytium_uart_read(const struct phytium_uart_port *pup, -+ unsigned int reg) -+{ -+ void __iomem *addr = pup->port.membase + reg; -+ -+ return readl_relaxed(addr); -+} -+ -+static void phytium_uart_write(unsigned int val, const struct phytium_uart_port *pup, -+ unsigned int reg) -+{ -+ void __iomem *addr = pup->port.membase + reg; -+ -+ writel_relaxed(val, addr); -+} -+ -+static int phytium_fifo_to_tty(struct phytium_uart_port *pup) -+{ -+ u16 status; -+ unsigned int ch, flag, fifotaken; -+ -+ for (fifotaken = 0; fifotaken < 256; fifotaken++) { -+ status = phytium_uart_read(pup, REG_FR); -+ if (status & REG_FR_RXFE) -+ break; -+ -+ /* Take chars from the FIFO and update status */ -+ ch = phytium_uart_read(pup, REG_DR) | UART_DUMMY_DR_RX; -+ flag = TTY_NORMAL; -+ pup->port.icount.rx++; -+ -+ if (unlikely(ch & UART_DR_ERROR)) { -+ if (ch & REG_DR_BE) { -+ ch &= ~(REG_DR_FE | REG_DR_PE); -+ pup->port.icount.brk++; -+ if (uart_handle_break(&pup->port)) -+ continue; -+ } else if (ch & REG_DR_PE) -+ pup->port.icount.parity++; -+ else if (ch & REG_DR_FE) -+ pup->port.icount.frame++; -+ if (ch & REG_DR_OE) -+ pup->port.icount.overrun++; -+ -+ ch &= pup->port.read_status_mask; -+ -+ if (ch & REG_DR_BE) -+ flag = TTY_BREAK; -+ else if (ch & REG_DR_PE) -+ flag = TTY_PARITY; -+ else if (ch & REG_DR_FE) -+ flag = TTY_FRAME; -+ } -+ -+ if (uart_handle_sysrq_char(&pup->port, ch & 255)) -+ continue; -+ -+ uart_insert_char(&pup->port, ch, REG_DR_OE, ch, flag); -+ } -+ -+ return fifotaken; -+} -+ -+static void phytium_rx_chars(struct phytium_uart_port *pup) -+__releases(&pup->port.lock) -+__acquires(&pup->port.lock) -+{ -+ phytium_fifo_to_tty(pup); -+ -+ spin_unlock(&pup->port.lock); -+ tty_flip_buffer_push(&pup->port.state->port); -+ spin_lock(&pup->port.lock); -+} -+ -+static void phytium_stop_tx(struct uart_port *port) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ -+ pup->im &= ~REG_IMSC_TXIM; -+ phytium_uart_write(pup->im, pup, REG_IMSC); -+} -+ -+static bool phytium_tx_char(struct phytium_uart_port *pup, unsigned char c, -+ bool from_irq) -+{ -+ -+ if (unlikely(!from_irq) && -+ phytium_uart_read(pup, REG_FR) & REG_FR_TXFF) -+ return false; /* unable to transmit character */ -+ -+ phytium_uart_write(c, pup, REG_DR); -+ pup->port.icount.tx++; -+ -+ return true; -+} -+ -+static bool phytium_tx_chars(struct phytium_uart_port *pup, bool from_irq) -+{ -+ struct circ_buf *xmit = &pup->port.state->xmit; -+ int count = pup->port.fifosize >> 1; -+ -+ if (pup->port.x_char) { -+ if (!phytium_tx_char(pup, pup->port.x_char, from_irq)) -+ return true; -+ pup->port.x_char = 0; -+ --count; -+ } -+ if (uart_circ_empty(xmit) || uart_tx_stopped(&pup->port)) { -+ phytium_stop_tx(&pup->port); -+ return false; -+ } -+ -+ do { -+ if (likely(from_irq) && count-- == 0) -+ break; -+ -+ if (!phytium_tx_char(pup, xmit->buf[xmit->tail], from_irq)) -+ break; -+ -+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -+ } while (!uart_circ_empty(xmit)); -+ -+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -+ uart_write_wakeup(&pup->port); -+ -+ if (uart_circ_empty(xmit)) { -+ phytium_stop_tx(&pup->port); -+ return false; -+ } -+ return true; -+} -+ -+static void phytium_modem_status(struct phytium_uart_port *pup) -+{ -+ unsigned int status, delta; -+ -+ status = phytium_uart_read(pup, REG_FR) & (REG_FR_DCD|REG_FR_DSR|REG_FR_CTS); -+ -+ delta = status ^ pup->old_status; -+ pup->old_status = status; -+ -+ if (!delta) -+ return; -+ -+ if (delta & REG_FR_DCD) -+ uart_handle_dcd_change(&pup->port, status & REG_FR_DCD); -+ -+ if (delta & REG_FR_DSR) -+ pup->port.icount.dsr++; -+ -+ if (delta & REG_FR_CTS) -+ uart_handle_cts_change(&pup->port, status & REG_FR_CTS); -+ -+ wake_up_interruptible(&pup->port.state->port.delta_msr_wait); -+} -+ -+static irqreturn_t phytium_uart_interrupt(int irq, void *dev_id) -+{ -+ struct phytium_uart_port *pup = dev_id; -+ unsigned long flags; -+ unsigned int status, pass_counter = 256; -+ int handled = 0; -+ -+ spin_lock_irqsave(&pup->port.lock, flags); -+ status = phytium_uart_read(pup, REG_RIS) & pup->im; -+ if (status) { -+ do { -+ phytium_uart_write(status & ~(REG_ICR_TXIS|REG_ICR_RTIS|REG_ICR_RXIS), -+ pup, REG_ICR); -+ -+ if (status & (REG_ICR_RTIS|REG_ICR_RXIS)) -+ phytium_rx_chars(pup); -+ -+ if (status & (REG_ICR_DSRMIS|REG_ICR_DCDMIS| -+ REG_ICR_CTSMIS|REG_ICR_RIMIS)) -+ phytium_modem_status(pup); -+ if (status & REG_ICR_TXIS) -+ phytium_tx_chars(pup, true); -+ -+ if (pass_counter-- == 0) -+ break; -+ -+ status = phytium_uart_read(pup, REG_RIS) & pup->im; -+ } while (status != 0); -+ handled = 1; -+ } -+ spin_unlock_irqrestore(&pup->port.lock, flags); -+ -+ return IRQ_RETVAL(handled); -+} -+ -+static unsigned int phytium_tx_empty(struct uart_port *port) -+{ -+ unsigned int status; -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ -+ status = phytium_uart_read(pup, REG_FR) & (REG_FR_BUSY | REG_FR_TXFF); -+ -+ return status ? 0 : TIOCSER_TEMT; -+} -+ -+static void phytium_set_mctrl(struct uart_port *port, unsigned int mctrl) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ unsigned int cr; -+ -+ cr = phytium_uart_read(pup, REG_CR); -+ -+#define TIOCMBIT(tiocmbit, uartbit) \ -+ do { \ -+ if (mctrl & tiocmbit) \ -+ cr |= uartbit; \ -+ else \ -+ cr &= ~uartbit; \ -+ } while (0) -+ -+ TIOCMBIT(TIOCM_RTS, REG_CR_RTS); -+ TIOCMBIT(TIOCM_DTR, REG_CR_DTR); -+ TIOCMBIT(TIOCM_OUT1, REG_CR_OUT1); -+ TIOCMBIT(TIOCM_OUT2, REG_CR_OUT2); -+ TIOCMBIT(TIOCM_LOOP, REG_CR_LBE); -+ -+ if (port->status & UPSTAT_AUTORTS) { -+ /* We need to disable auto-RTS if we want to turn RTS off */ -+ TIOCMBIT(TIOCM_RTS, REG_CR_RTSEN); -+ } -+#undef TIOCMBIT -+ -+ phytium_uart_write(cr, pup, REG_CR); -+} -+ -+static unsigned int phytium_get_mctrl(struct uart_port *port) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ unsigned int cr = 0; -+ unsigned int status = phytium_uart_read(pup, REG_FR); -+ -+#define TIOCMBIT(uartbit, tiocmbit) \ -+ do { \ -+ if (status & uartbit) \ -+ cr |= tiocmbit; \ -+ } while (0) -+ -+ TIOCMBIT(REG_FR_DCD, TIOCM_CAR); -+ TIOCMBIT(REG_FR_DSR, TIOCM_DSR); -+ TIOCMBIT(REG_FR_CTS, TIOCM_CTS); -+ TIOCMBIT(REG_FR_RI, TIOCM_RNG); -+#undef TIOCMBIT -+ return cr; -+} -+ -+static void phytium_start_tx(struct uart_port *port) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ -+ if (phytium_tx_chars(pup, false)) { -+ pup->im |= REG_IMSC_TXIM; -+ phytium_uart_write(pup->im, pup, REG_IMSC); -+ } -+} -+ -+static void phytium_stop_rx(struct uart_port *port) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ -+ pup->im &= ~(REG_IMSC_RXIM|REG_IMSC_RTIM|REG_IMSC_FEIM| -+ REG_IMSC_PEIM|REG_IMSC_BEIM|REG_IMSC_OEIM); -+ phytium_uart_write(pup->im, pup, REG_IMSC); -+} -+ -+static void phytium_enable_ms(struct uart_port *port) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ -+ pup->im |= REG_IMSC_RIMIM|REG_IMSC_CTSMIM|REG_IMSC_DCDMIM|REG_IMSC_DSRMIM; -+ phytium_uart_write(pup->im, pup, REG_IMSC); -+} -+ -+static void phytium_break_ctl(struct uart_port *port, int break_state) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ unsigned long flags; -+ unsigned int lcr_h; -+ -+ spin_lock_irqsave(&pup->port.lock, flags); -+ lcr_h = phytium_uart_read(pup, REG_LCRH_TX); -+ if (break_state == -1) -+ lcr_h |= REG_LCRH_BRK; -+ else -+ lcr_h &= ~REG_LCRH_BRK; -+ phytium_uart_write(lcr_h, pup, REG_LCRH_TX); -+ spin_unlock_irqrestore(&pup->port.lock, flags); -+} -+ -+static int phytium_hwinit(struct uart_port *port) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ -+ /* XXX: more configurable setup method in future */ -+ pup->port.uartclk = DEFAULT_UARTCLK; -+ -+ /* Clear pending error and receive interrupts */ -+ phytium_uart_write(REG_ICR_OEIS | REG_ICR_BEIS | REG_ICR_PEIS | -+ REG_ICR_FEIS | REG_ICR_RTIS | REG_ICR_RXIS, -+ pup, REG_ICR); -+ -+ /* -+ * Save interrupts enable mask, and enable RX interrupts in case if -+ * the interrupt is used for NMI entry. -+ */ -+ pup->im = phytium_uart_read(pup, REG_IMSC); -+ phytium_uart_write(REG_IMSC_RTIM | REG_IMSC_RXIM, pup, REG_IMSC); -+ -+ return 0; -+} -+ -+static int phytium_uart_allocate_irq(struct phytium_uart_port *pup) -+{ -+ phytium_uart_write(pup->im, pup, REG_IMSC); -+ -+ return request_irq(pup->port.irq, phytium_uart_interrupt, IRQF_SHARED, DRV_NAME, pup); -+} -+ -+static void phytium_enable_interrtups(struct phytium_uart_port *pup) -+{ -+ unsigned int i; -+ -+ spin_lock_irq(&pup->port.lock); -+ -+ /* Clear out any spuriously appearing RX interrupts */ -+ phytium_uart_write(REG_ICR_RTIS | REG_ICR_RXIS, pup, REG_ICR); -+ -+ /* -+ * RXIS is asserted only when the RX FIFO transitions from below -+ * to above the trigger threshold. If the RX FIFO is already -+ * full to the threashold this can't happen and RXIS will now be -+ * stuck off. Drain the RX FIFO explicitly to fix this: -+ */ -+ for (i = 0; i < pup->port.fifosize * 2; i++) { -+ if (phytium_uart_read(pup, REG_FR) & REG_FR_RXFE) -+ break; -+ -+ phytium_uart_read(pup, REG_DR); -+ } -+ -+ pup->im = REG_IMSC_RTIM | REG_IMSC_RXIM; -+ phytium_uart_write(pup->im, pup, REG_IMSC); -+ spin_unlock_irq(&pup->port.lock); -+} -+ -+static int phytium_startup(struct uart_port *port) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ unsigned int cr; -+ int ret = 0; -+ -+ ret = phytium_hwinit(port); -+ if (ret) -+ goto out; -+ -+ ret = phytium_uart_allocate_irq(pup); -+ if (ret) -+ goto out; -+ -+ phytium_uart_write(REG_IFLS_RX4_8|REG_IFLS_TX4_8, pup, REG_IFLS); -+ -+ spin_lock_irq(&pup->port.lock); -+ -+ /* restore RTS and DTR */ -+ cr = pup->old_cr & (REG_CR_RTS | REG_CR_DTR); -+ cr |= REG_CR_UARTEN | REG_CR_RXE | REG_CR_TXE; -+ phytium_uart_write(cr, pup, REG_CR); -+ -+ spin_unlock_irq(&pup->port.lock); -+ -+ /* initialise the old status of the modem signals */ -+ pup->old_status = phytium_uart_read(pup, REG_FR) & (REG_FR_DCD|REG_FR_DSR|REG_FR_CTS); -+ -+ phytium_enable_interrtups(pup); -+ -+out: -+ return ret; -+} -+ -+static void phytium_shutdown_channel(struct phytium_uart_port *pup, -+ unsigned int lcrh) -+{ -+ unsigned long val; -+ -+ val = phytium_uart_read(pup, lcrh); -+ val &= ~(REG_LCRH_BRK | REG_LCRH_FEN); -+ phytium_uart_write(val, pup, lcrh); -+} -+ -+static void phytium_disable_uart(struct phytium_uart_port *pup) -+{ -+ unsigned int cr; -+ -+ pup->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); -+ spin_lock_irq(&pup->port.lock); -+ cr = phytium_uart_read(pup, REG_CR); -+ pup->old_cr = cr; -+ cr &= REG_CR_RTS | REG_CR_DTR; -+ cr |= REG_CR_UARTEN | REG_CR_TXE; -+ phytium_uart_write(cr, pup, REG_CR); -+ spin_unlock_irq(&pup->port.lock); -+ -+ /* -+ * disable break condition and fifos -+ */ -+ phytium_shutdown_channel(pup, REG_LCRH_RX); -+} -+ -+static void phytium_disable_interrupts(struct phytium_uart_port *pup) -+{ -+ spin_lock_irq(&pup->port.lock); -+ -+ /* mask all interrupts and clear all pending ones */ -+ pup->im = 0; -+ phytium_uart_write(pup->im, pup, REG_IMSC); -+ phytium_uart_write(0xffff, pup, REG_ICR); -+ -+ spin_unlock_irq(&pup->port.lock); -+} -+ -+static void phytium_shutdown(struct uart_port *port) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ -+ phytium_disable_interrupts(pup); -+ -+ free_irq(pup->port.irq, pup); -+ -+ phytium_disable_uart(pup); -+ -+ if (pup->port.ops->flush_buffer) -+ pup->port.ops->flush_buffer(port); -+} -+ -+static void -+phytium_setup_status_masks(struct uart_port *port, struct ktermios *termios) -+{ -+ port->read_status_mask = REG_DR_OE | 255; -+ if (termios->c_iflag & INPCK) -+ port->read_status_mask |= REG_DR_FE | REG_DR_PE; -+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) -+ port->read_status_mask |= REG_DR_BE; -+ -+ /* -+ * Characters to ignore -+ */ -+ port->ignore_status_mask = 0; -+ if (termios->c_iflag & IGNPAR) -+ port->ignore_status_mask |= REG_DR_FE | REG_DR_PE; -+ if (termios->c_iflag & IGNBRK) { -+ port->ignore_status_mask |= REG_DR_BE; -+ /* -+ * If we're ignoring parity and break indicators, -+ * ignore overruns too (for real raw support). -+ */ -+ if (termios->c_iflag & IGNPAR) -+ port->ignore_status_mask |= REG_DR_OE; -+ } -+ -+ /* -+ * Ignore all characters if CREAD is not set. -+ */ -+ if ((termios->c_cflag & CREAD) == 0) -+ port->ignore_status_mask |= UART_DUMMY_DR_RX; -+} -+ -+static void -+phytium_set_termios(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ unsigned int lcr_h, old_cr; -+ unsigned long flags; -+ unsigned int baud, quot; -+ -+ /* Ask the core to calculate the divisor for us. */ -+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); -+ -+ if (baud > port->uartclk/16) -+ quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud); -+ else -+ quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud); -+ -+ switch (termios->c_cflag & CSIZE) { -+ case CS5: -+ lcr_h = REG_LCRH_WLEN_5; -+ break; -+ case CS6: -+ lcr_h = REG_LCRH_WLEN_6; -+ break; -+ case CS7: -+ lcr_h = REG_LCRH_WLEN_7; -+ break; -+ default: /* CS8 */ -+ lcr_h = REG_LCRH_WLEN_8; -+ break; -+ } -+ if (termios->c_cflag & CSTOPB) -+ lcr_h |= REG_LCRH_STP2; -+ if (termios->c_cflag & PARENB) { -+ lcr_h |= REG_LCRH_PEN; -+ if (!(termios->c_cflag & PARODD)) -+ lcr_h |= REG_LCRH_EPS; -+ if (termios->c_cflag & CMSPAR) -+ lcr_h |= REG_LCRH_SPS; -+ } -+ if (pup->port.fifosize > 1) -+ lcr_h |= REG_LCRH_FEN; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ -+ /* -+ * Update the per-port timeout. -+ */ -+ uart_update_timeout(port, termios->c_cflag, baud); -+ -+ phytium_setup_status_masks(port, termios); -+ -+ if (UART_ENABLE_MS(port, termios->c_cflag)) -+ phytium_enable_ms(port); -+ -+ /* first, disable everything */ -+ old_cr = phytium_uart_read(pup, REG_CR); -+ phytium_uart_write(0, pup, REG_CR); -+ -+ if (termios->c_cflag & CRTSCTS) { -+ if (old_cr & REG_CR_RTS) -+ old_cr |= REG_CR_RTSEN; -+ -+ old_cr |= REG_CR_CTSEN; -+ port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; -+ } else { -+ old_cr &= ~(REG_CR_CTSEN | REG_CR_RTSEN); -+ port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); -+ } -+ -+ /* Set baud rate */ -+ phytium_uart_write(quot & 0x3f, pup, REG_FBRD); -+ phytium_uart_write(quot >> 6, pup, REG_IBRD); -+ -+ phytium_uart_write(lcr_h, pup, REG_LCRH_RX); -+ phytium_uart_write(old_cr, pup, REG_CR); -+ -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static const char *phytium_type(struct uart_port *port) -+{ -+ struct phytium_uart_port *pup = -+ container_of(port, struct phytium_uart_port, port); -+ return pup->port.type == PORT_PHYTIUM ? pup->type : NULL; -+} -+ -+static void phytium_release_port(struct uart_port *port) -+{ -+ /* Nothing to release ... */ -+} -+ -+static int phytium_request_port(struct uart_port *port) -+{ -+ /* UARTs always present */ -+ return 0; -+} -+ -+static void phytium_config_port(struct uart_port *port, int flags) -+{ -+ if (flags & UART_CONFIG_TYPE) { -+ port->type = PORT_PHYTIUM; -+ phytium_request_port(port); -+ } -+} -+ -+static int phytium_verify_port(struct uart_port *port, struct serial_struct *ser) -+{ -+ int ret = 0; -+ -+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_PHYTIUM) -+ ret = -EINVAL; -+ if (ser->irq < 0 || ser->irq >= nr_irqs) -+ ret = -EINVAL; -+ if (ser->baud_base < 9600) -+ ret = -EINVAL; -+ -+ return ret; -+} -+ -+static const struct uart_ops phytium_uart_ops = { -+ .tx_empty = phytium_tx_empty, -+ .set_mctrl = phytium_set_mctrl, -+ .get_mctrl = phytium_get_mctrl, -+ .stop_tx = phytium_stop_tx, -+ .start_tx = phytium_start_tx, -+ .stop_rx = phytium_stop_rx, -+ .enable_ms = phytium_enable_ms, -+ .break_ctl = phytium_break_ctl, -+ .startup = phytium_startup, -+ .shutdown = phytium_shutdown, -+ .set_termios = phytium_set_termios, -+ .type = phytium_type, -+ .release_port = phytium_release_port, -+ .request_port = phytium_request_port, -+ .config_port = phytium_config_port, -+ .verify_port = phytium_verify_port, -+}; -+ -+static struct phytium_uart_port *uart_ports[UART_NR]; -+ -+static struct uart_driver phytium_uart = { -+ .owner = THIS_MODULE, -+ .driver_name = DRV_NAME, -+ .dev_name = "ttyS", -+ .nr = UART_NR, -+}; -+ -+void phytium_unregister_port(struct phytium_uart_port *pup) -+{ -+ int i; -+ bool busy = false; -+ -+ for (i = 0; i < ARRAY_SIZE(uart_ports); i++) { -+ if (uart_ports[i] == pup) -+ uart_ports[i] = NULL; -+ else if (uart_ports[i]) -+ busy = true; -+ } -+ -+ if (!busy) -+ uart_unregister_driver(&phytium_uart); -+} -+ -+static int phytium_find_free_port(void) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(uart_ports); i++) -+ if (uart_ports[i] == NULL) -+ return i; -+ -+ return -EBUSY; -+} -+ -+static int phytium_register_port(struct phytium_uart_port *pup) -+{ -+ int rc; -+ -+ /* Ensure interrupts from this UART are masked and cleared */ -+ phytium_uart_write(0, pup, REG_IMSC); -+ phytium_uart_write(0xffff, pup, REG_ICR); -+ -+ if (!phytium_uart.state) { -+ rc = uart_register_driver(&phytium_uart); -+ if (rc < 0) { -+ dev_err(pup->port.dev, -+ "Failed to register Phytium PCI UART driver\n"); -+ return rc; -+ } -+ } -+ -+ rc = uart_add_one_port(&phytium_uart, &pup->port); -+ if (rc) -+ phytium_unregister_port(pup); -+ -+ return rc; -+} -+ -+static int phytium_uart_probe(struct pci_dev *pdev, -+ const struct pci_device_id *id) -+{ -+ struct phytium_uart_port *pup; -+ int portnr, rc; -+ -+ portnr = phytium_find_free_port(); -+ if (portnr < 0) -+ return portnr; -+ -+ pup = devm_kzalloc(&pdev->dev, sizeof(struct phytium_uart_port), -+ GFP_KERNEL); -+ if (!pup) -+ return -ENOMEM; -+ -+ rc = pcim_enable_device(pdev); -+ if (rc) -+ return rc; -+ -+ rc = pcim_iomap_regions_request_all(pdev, 0x01, pci_name(pdev)); -+ if (rc) -+ return rc; -+ -+ pup->port.iotype = UPIO_MEM32; -+ pup->port.irq = pdev->irq; -+ pup->port.mapbase = pci_resource_start(pdev, 0); -+ pup->port.membase = pcim_iomap_table(pdev)[0]; -+ pup->port.ops = &phytium_uart_ops; -+ pup->port.dev = &pdev->dev; -+ pup->port.fifosize = 32; -+ pup->port.flags = UPF_BOOT_AUTOCONF; -+ pup->port.line = portnr; -+ -+ uart_ports[portnr] = pup; -+ -+ pup->old_cr = 0; -+ snprintf(pup->type, sizeof(pup->type), "pci-uart"); -+ -+ pci_set_drvdata(pdev, pup); -+ -+ return phytium_register_port(pup); -+} -+ -+static void phytium_uart_remove(struct pci_dev *pdev) -+{ -+ struct phytium_uart_port *pup = pci_get_drvdata(pdev); -+ -+ uart_remove_one_port(&phytium_uart, &pup->port); -+ phytium_unregister_port(pup); -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int phytium_uart_suspend(struct device *dev) -+{ -+ struct pci_dev *pdev = to_pci_dev(dev); -+ struct phytium_uart_port *pup = pci_get_drvdata(pdev); -+ -+ if (pup) -+ uart_suspend_port(&phytium_uart, &pup->port); -+ -+ return 0; -+} -+ -+static int phytium_uart_resume(struct device *dev) -+{ -+ struct pci_dev *pdev = to_pci_dev(dev); -+ struct phytium_uart_port *pup = pci_get_drvdata(pdev); -+ -+ if (pup) -+ uart_resume_port(&phytium_uart, &pup->port); -+ -+ return 0; -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(phytium_dev_pm_ops, phytium_uart_suspend, phytium_uart_resume); -+ -+static const struct pci_device_id pci_ids[] = { -+ { PCI_VDEVICE(PHYTIUM, 0xdc2e) }, -+ { 0 } -+}; -+MODULE_DEVICE_TABLE(pci, pci_ids); -+ -+static struct pci_driver phytium_uart_pci_driver = { -+ .name = DRV_NAME, -+ .probe = phytium_uart_probe, -+ .remove = phytium_uart_remove, -+ .driver = { -+ .pm = &phytium_dev_pm_ops, -+ }, -+ .id_table = pci_ids, -+}; -+ -+static int __init phytium_uart_init(void) -+{ -+ pr_info("Serial: Phytium PCI UART driver\n"); -+ -+ return pci_register_driver(&phytium_uart_pci_driver); -+} -+ -+static void __exit phytium_uart_exit(void) -+{ -+ pci_unregister_driver(&phytium_uart_pci_driver); -+} -+ -+module_init(phytium_uart_init); -+module_exit(phytium_uart_exit); -+ -+MODULE_AUTHOR("Chen Baozi <chenbaozi@phytium.com.cn>"); -+MODULE_DESCRIPTION("Phytium PCI serial port driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c -index 45b42d8..b71072d 100644 ---- a/drivers/usb/early/ehci-dbgp.c -+++ b/drivers/usb/early/ehci-dbgp.c -@@ -879,7 +879,11 @@ int __init early_dbgp_init(char *s) - * FIXME I don't have the bar size so just guess PAGE_SIZE is more - * than enough. 1K is the biggest I have seen. - */ -+ #ifdef CONFIG_PTP -+ __iee_set_fixmap_pre_init(FIX_DBGP_BASE, bar_val & PAGE_MASK, FIXMAP_PAGE_NOCACHE); -+ #else - set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK); -+ #endif - ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE); - ehci_bar += bar_val & ~PAGE_MASK; - dbgp_printk("ehci_bar: %p\n", ehci_bar); -diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c -index 051c6da..060f467 100644 ---- a/drivers/usb/musb/musb_gadget.c -+++ b/drivers/usb/musb/musb_gadget.c -@@ -1170,12 +1170,19 @@ struct free_record { - */ - void musb_ep_restart(struct musb *musb, struct musb_request *req) - { -+ u16 csr; -+ void __iomem *epio = req->ep->hw_ep->regs; -+ - trace_musb_req_start(req); - musb_ep_select(musb->mregs, req->epnum); -- if (req->tx) -- txstate(musb, req); -- else -- rxstate(musb, req); -+ if (req->tx) { -+ txstate(musb, req); -+ } else { -+ csr = musb_readw(epio, MUSB_RXCSR); -+ csr |= MUSB_RXCSR_FLUSHFIFO | MUSB_RXCSR_P_WZC_BITS; -+ musb_writew(epio, MUSB_RXCSR, csr); -+ musb_writew(epio, MUSB_RXCSR, csr); -+ } - } - - static int musb_ep_restart_resume_work(struct musb *musb, void *data) -diff --git a/fs/ceph/file.c b/fs/ceph/file.c -index 1e04972..43b2ffe 100644 ---- a/fs/ceph/file.c -+++ b/fs/ceph/file.c -@@ -1025,6 +1025,16 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos, - len = read_off + read_len - off; - more = len < iov_iter_count(to); - -+ op = &req->r_ops[0]; -+ if (sparse) { -+ ret = ceph_alloc_sparse_ext_map(op); -+ if (ret) { -+ ceph_osdc_put_request(req); -+ break; -+ } -+ } -+ -+ - num_pages = calc_pages_for(read_off, read_len); - page_off = offset_in_page(off); - pages = ceph_alloc_page_vector(num_pages, GFP_KERNEL); -@@ -1038,15 +1048,7 @@ ssize_t __ceph_sync_read(struct inode *inode, loff_t *ki_pos, - offset_in_page(read_off), - false, false); - -- op = &req->r_ops[0]; -- if (sparse) { -- ret = ceph_alloc_sparse_ext_map(op); -- if (ret) { -- ceph_osdc_put_request(req); -- break; -- } -- } -- -+ - ceph_osdc_start_request(osdc, req); - ret = ceph_osdc_wait_request(osdc, req); - -@@ -1452,7 +1454,16 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, - ret = PTR_ERR(req); - break; - } -- -+ -+ op = &req->r_ops[0]; -+ if (sparse) { -+ ret = ceph_alloc_sparse_ext_map(op); -+ if (ret) { -+ ceph_osdc_put_request(req); -+ break; -+ } -+ } -+ - len = iter_get_bvecs_alloc(iter, size, &bvecs, &num_pages); - if (len < 0) { - ceph_osdc_put_request(req); -@@ -1462,6 +1473,8 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, - if (len != size) - osd_req_op_extent_update(req, 0, len); - -+ osd_req_op_extent_osd_data_bvecs(req, 0, bvecs, num_pages, len); -+ - /* - * To simplify error handling, allow AIO when IO within i_size - * or IO can be satisfied by single OSD request. -@@ -1493,15 +1506,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, - req->r_mtime = mtime; - } - -- osd_req_op_extent_osd_data_bvecs(req, 0, bvecs, num_pages, len); -- op = &req->r_ops[0]; -- if (sparse) { -- ret = ceph_alloc_sparse_ext_map(op); -- if (ret) { -- ceph_osdc_put_request(req); -- break; -- } -- } -+ - - if (aio_req) { - aio_req->total_len += len; -diff --git a/fs/coredump.c b/fs/coredump.c -index 9d235fa..a519090 100644 ---- a/fs/coredump.c -+++ b/fs/coredump.c -@@ -53,6 +53,10 @@ - - #include <trace/events/sched.h> - -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+ - static bool dump_vma_snapshot(struct coredump_params *cprm); - static void free_vma_snapshot(struct coredump_params *cprm); - -@@ -564,7 +568,11 @@ void do_coredump(const kernel_siginfo_t *siginfo) - */ - if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) { - /* Setuid core dump mode */ -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(cred, GLOBAL_ROOT_UID); -+ #else - cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ -+ #endif - need_suid_safe = true; - } - -diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c -index 7cbb1fd..4232d2e 100644 ---- a/fs/crypto/keyring.c -+++ b/fs/crypto/keyring.c -@@ -590,8 +590,13 @@ static void fscrypt_provisioning_key_describe(const struct key *key, - { - seq_puts(m, key->description); - if (key_is_positive(key)) { -+ #ifdef CONFIG_KEYP -+ const struct fscrypt_provisioning_key_payload *payload = -+ ((union key_payload *)(key->name_link.next))->data[0]; -+ #else - const struct fscrypt_provisioning_key_payload *payload = - key->payload.data[0]; -+ #endif - - seq_printf(m, ": %u [%u]", key->datalen, payload->type); - } -@@ -599,7 +604,11 @@ static void fscrypt_provisioning_key_describe(const struct key *key, - - static void fscrypt_provisioning_key_destroy(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ kfree_sensitive(((union key_payload *)(key->name_link.next))->data[0]); -+ #else - kfree_sensitive(key->payload.data[0]); -+ #endif - } - - static struct key_type key_type_fscrypt_provisioning = { -@@ -641,7 +650,11 @@ static int get_keyring_key(u32 key_id, u32 type, - - if (key->type != &key_type_fscrypt_provisioning) - goto bad_key; -+ #ifdef CONFIG_KEYP -+ payload = ((union key_payload *)(key->name_link.next))->data[0]; -+ #else - payload = key->payload.data[0]; -+ #endif - - /* Don't allow fscrypt v1 keys to be used as v2 keys and vice versa. */ - if (payload->type != type) -@@ -1030,7 +1043,11 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users) - down_write(&mk->mk_sem); - - /* If relevant, remove current user's (or all users) claim to the key */ -+ #ifdef CONFIG_KEYP -+ if (mk->mk_users && ((struct key_struct *)(mk->mk_users->name_link.prev))->keys.nr_leaves_on_tree != 0) { -+ #else - if (mk->mk_users && mk->mk_users->keys.nr_leaves_on_tree != 0) { -+ #endif - if (all_users) - err = keyring_clear(mk->mk_users); - else -@@ -1039,7 +1056,11 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users) - up_write(&mk->mk_sem); - goto out_put_key; - } -+ #ifdef CONFIG_KEYP -+ if (((struct key_struct *)(mk->mk_users->name_link.prev))->keys.nr_leaves_on_tree != 0) { -+ #else - if (mk->mk_users->keys.nr_leaves_on_tree != 0) { -+ #endif - /* - * Other users have still added the key too. We removed - * the current user's claim to the key, but we still -@@ -1162,7 +1183,11 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg) - if (mk->mk_users) { - struct key *mk_user; - -+ #ifdef CONFIG_KEYP -+ arg.user_count = ((struct key_struct *)(mk->mk_users->name_link.prev))->keys.nr_leaves_on_tree; -+ #else - arg.user_count = mk->mk_users->keys.nr_leaves_on_tree; -+ #endif - mk_user = find_master_key_user(mk); - if (!IS_ERR(mk_user)) { - arg.status_flags |= -diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c -index 75dabd9..9d0cc6e 100644 ---- a/fs/crypto/keysetup_v1.c -+++ b/fs/crypto/keysetup_v1.c -@@ -109,7 +109,11 @@ find_and_lock_process_key(const char *prefix, - if (IS_ERR(key)) - return key; - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(key)); -+ #else - down_read(&key->sem); -+ #endif - ukp = user_key_payload_locked(key); - - if (!ukp) /* was the key revoked before we acquired its semaphore? */ -@@ -136,7 +140,11 @@ find_and_lock_process_key(const char *prefix, - return key; - - invalid: -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - return ERR_PTR(-ENOKEY); - } -@@ -315,7 +323,11 @@ int fscrypt_setup_v1_file_key_via_subscribed_keyrings(struct fscrypt_info *ci) - return PTR_ERR(key); - - err = fscrypt_setup_v1_file_key(ci, payload->raw); -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - return err; - } -diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h -index f2ed0c0..1a24f8d 100644 ---- a/fs/ecryptfs/ecryptfs_kernel.h -+++ b/fs/ecryptfs/ecryptfs_kernel.h -@@ -82,7 +82,11 @@ ecryptfs_get_encrypted_key_payload_data(struct key *key) - if (key->type != &key_type_encrypted) - return NULL; - -+ #ifdef CONFIG_KEYP -+ payload = ((union key_payload *)(key->name_link.next))->data[0]; -+ #else - payload = key->payload.data[0]; -+ #endif - if (!payload) - return ERR_PTR(-EKEYREVOKED); - -diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c -index 7f9f68c..a4859a7 100644 ---- a/fs/ecryptfs/keystore.c -+++ b/fs/ecryptfs/keystore.c -@@ -512,7 +512,11 @@ ecryptfs_find_global_auth_tok_for_sig( - goto out_invalid_auth_tok; - } - -+ #ifdef CONFIG_KEYP -+ down_write(&(KEY_SEM(walker->global_auth_tok_key))); -+ #else - down_write(&(walker->global_auth_tok_key->sem)); -+ #endif - rc = ecryptfs_verify_auth_tok_from_key( - walker->global_auth_tok_key, auth_tok); - if (rc) -@@ -525,7 +529,11 @@ ecryptfs_find_global_auth_tok_for_sig( - rc = -ENOENT; - goto out; - out_invalid_auth_tok_unlock: -+ #ifdef CONFIG_KEYP -+ up_write(&(KEY_SEM(walker->global_auth_tok_key))); -+ #else - up_write(&(walker->global_auth_tok_key->sem)); -+ #endif - out_invalid_auth_tok: - printk(KERN_WARNING "Invalidating auth tok with sig = [%s]\n", sig); - walker->flags |= ECRYPTFS_AUTH_TOK_INVALID; -@@ -846,7 +854,11 @@ ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes, - mutex_unlock(s->tfm_mutex); - out: - if (auth_tok_key) { -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(auth_tok_key)); -+ #else - up_write(&(auth_tok_key->sem)); -+ #endif - key_put(auth_tok_key); - } - skcipher_request_free(s->skcipher_req); -@@ -1088,7 +1100,11 @@ ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size, - (*filename) = NULL; - } - if (auth_tok_key) { -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(auth_tok_key)); -+ #else - up_write(&(auth_tok_key->sem)); -+ #endif - key_put(auth_tok_key); - } - skcipher_request_free(s->skcipher_req); -@@ -1625,10 +1641,18 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, - goto out; - } - } -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM((*auth_tok_key))); -+ #else - down_write(&(*auth_tok_key)->sem); -+ #endif - rc = ecryptfs_verify_auth_tok_from_key(*auth_tok_key, auth_tok); - if (rc) { -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM((*auth_tok_key))); -+ #else - up_write(&(*auth_tok_key)->sem); -+ #endif - key_put(*auth_tok_key); - (*auth_tok_key) = NULL; - goto out; -@@ -1901,7 +1925,11 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, - memcpy(&(candidate_auth_tok->token.private_key), - &(matching_auth_tok->token.private_key), - sizeof(struct ecryptfs_private_key)); -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(auth_tok_key)); -+ #else - up_write(&(auth_tok_key->sem)); -+ #endif - key_put(auth_tok_key); - rc = decrypt_pki_encrypted_session_key(candidate_auth_tok, - crypt_stat); -@@ -1909,12 +1937,20 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, - memcpy(&(candidate_auth_tok->token.password), - &(matching_auth_tok->token.password), - sizeof(struct ecryptfs_password)); -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(auth_tok_key)); -+ #else - up_write(&(auth_tok_key->sem)); -+ #endif - key_put(auth_tok_key); - rc = decrypt_passphrase_encrypted_session_key( - candidate_auth_tok, crypt_stat); - } else { -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(auth_tok_key)); -+ #else - up_write(&(auth_tok_key->sem)); -+ #endif - key_put(auth_tok_key); - rc = -EINVAL; - } -@@ -1976,7 +2012,11 @@ pki_encrypt_session_key(struct key *auth_tok_key, - crypt_stat->cipher, - crypt_stat->key_size), - crypt_stat, &payload, &payload_len); -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(auth_tok_key)); -+ #else - up_write(&(auth_tok_key->sem)); -+ #endif - key_put(auth_tok_key); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n"); -@@ -2040,7 +2080,11 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes, - memcpy(key_rec->enc_key, - auth_tok->session_key.encrypted_key, - auth_tok->session_key.encrypted_key_size); -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(auth_tok_key)); -+ #else - up_write(&(auth_tok_key->sem)); -+ #endif - key_put(auth_tok_key); - goto encrypted_session_key_set; - } -@@ -2438,7 +2482,11 @@ ecryptfs_generate_key_packet_set(char *dest_base, - &max, auth_tok, - crypt_stat, key_rec, - &written); -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(auth_tok_key)); -+ #else - up_write(&(auth_tok_key->sem)); -+ #endif - key_put(auth_tok_key); - if (rc) { - ecryptfs_printk(KERN_WARNING, "Error " -@@ -2467,7 +2515,11 @@ ecryptfs_generate_key_packet_set(char *dest_base, - } - (*len) += written; - } else { -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(auth_tok_key)); -+ #else - up_write(&(auth_tok_key->sem)); -+ #endif - key_put(auth_tok_key); - ecryptfs_printk(KERN_WARNING, "Unsupported " - "authentication token type\n"); -diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c -index 2dc927b..39c6f1d 100644 ---- a/fs/ecryptfs/main.c -+++ b/fs/ecryptfs/main.c -@@ -202,7 +202,11 @@ static int ecryptfs_init_global_auth_toks( - goto out; - } else { - global_auth_tok->flags &= ~ECRYPTFS_AUTH_TOK_INVALID; -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(global_auth_tok->global_auth_tok_key)); -+ #else - up_write(&(global_auth_tok->global_auth_tok_key)->sem); -+ #endif - } - } - out: -diff --git a/fs/erofs/super.c b/fs/erofs/super.c -index ef4b948..bfb5f82 100644 ---- a/fs/erofs/super.c -+++ b/fs/erofs/super.c -@@ -618,7 +618,10 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) - errorfc(fc, "unsupported blksize for fscache mode"); - return -EINVAL; - } -- if (!sb_set_blocksize(sb, 1 << sbi->blkszbits)) { -+ if (erofs_is_fileio_mode(sbi)) { -+ sb->s_blocksize = 1 << sbi->blkszbits; -+ sb->s_blocksize_bits = sbi->blkszbits; -+ } else if (!sb_set_blocksize(sb, 1 << sbi->blkszbits)) { - errorfc(fc, "failed to set erofs blksize"); - return -EINVAL; - } -diff --git a/fs/exec.c b/fs/exec.c -index c86b57a6..919da14 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -77,6 +77,13 @@ - - #include <trace/events/sched.h> - -+#ifdef CONFIG_IEE -+#include <asm/iee-token.h> -+#endif -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+ - static int bprm_creds_from_file(struct linux_binprm *bprm); - - int suid_dumpable = 0; -@@ -1006,6 +1013,10 @@ static int exec_mmap(struct mm_struct *mm) - if (!IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM)) - local_irq_enable(); - activate_mm(active_mm, mm); -+ #ifdef CONFIG_IEE -+ /* set token pgd after activate_mm, because we need to check current.token.pgd == read_cr3() */ -+ iee_set_token_pgd(tsk, mm->pgd); -+ #endif - if (IS_ENABLED(CONFIG_ARCH_WANT_IRQS_OFF_ACTIVATE_MM)) - local_irq_enable(); - lru_gen_add_mm(mm); -@@ -1624,12 +1635,20 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file) - - if (mode & S_ISUID) { - bprm->per_clear |= PER_CLEAR_ON_SETID; -+ #ifdef CONFIG_CREDP -+ iee_set_cred_euid(bprm->cred, vfsuid_into_kuid(vfsuid)); -+ #else - bprm->cred->euid = vfsuid_into_kuid(vfsuid); -+ #endif - } - - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { - bprm->per_clear |= PER_CLEAR_ON_SETID; -+ #ifdef CONFIG_CREDP -+ iee_set_cred_egid(bprm->cred, vfsgid_into_kgid(vfsgid)); -+ #else - bprm->cred->egid = vfsgid_into_kgid(vfsgid); -+ #endif - } - } - -diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c -index c765bda..cf2a178 100644 ---- a/fs/f2fs/node.c -+++ b/fs/f2fs/node.c -@@ -905,6 +905,15 @@ static int truncate_node(struct dnode_of_data *dn) - if (err) - return err; - -+ if (ni.blk_addr != NEW_ADDR && -+ !f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC_ENHANCE)){ -+ f2fs_err_ratelimited(sbi, -+ "nat entry is corrupted, run fsck to fix it, ino:%u, " -+ "nid:%u, blkaddr:%u",ni.ino, ni.nid, ni.blk_addr); -+ set_sbi_flag(sbi, SBI_NEED_FSCK); -+ f2fs_handle_error(sbi, ERROR_INCONSISTENT_NAT); -+ return -EFSCORRUPTED; -+ } - /* Deallocate node address */ - f2fs_invalidate_blocks(sbi, ni.blk_addr); - dec_valid_node_count(sbi, dn->inode, dn->nid == dn->inode->i_ino); -diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c -index 3e724cb..7e8abe5 100644 ---- a/fs/nfs/flexfilelayout/flexfilelayout.c -+++ b/fs/nfs/flexfilelayout/flexfilelayout.c -@@ -15,6 +15,10 @@ - - #include <linux/sunrpc/metrics.h> - -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+ - #include "flexfilelayout.h" - #include "../nfs4session.h" - #include "../nfs4idmap.h" -@@ -502,8 +506,13 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh, - rc = -ENOMEM; - if (!kcred) - goto out_err_free; -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(kcred, uid); -+ iee_set_cred_fsgid(kcred, gid); -+ #else - kcred->fsuid = uid; - kcred->fsgid = gid; -+ #endif - cred = RCU_INITIALIZER(kcred); - - if (lgr->range.iomode == IOMODE_READ) -diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c -index 25a7c77..7882c0d 100644 ---- a/fs/nfs/nfs4idmap.c -+++ b/fs/nfs/nfs4idmap.c -@@ -48,6 +48,13 @@ - #include <linux/module.h> - #include <linux/user_namespace.h> - -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif -+ - #include "internal.h" - #include "netns.h" - #include "nfs4idmap.h" -@@ -225,9 +232,18 @@ int nfs_idmap_init(void) - if (ret < 0) - goto failed_reg_legacy; - -+ #ifdef CONFIG_KEYP -+ iee_set_key_flag_bit(keyring, KEY_FLAG_ROOT_CAN_CLEAR, SET_BIT_OP); -+ #else - set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); -+ #endif -+ #ifdef CONFIG_CREDP -+ iee_set_cred_thread_keyring(cred, keyring); -+ iee_set_cred_jit_keyring(cred, KEY_REQKEY_DEFL_THREAD_KEYRING); -+ #else - cred->thread_keyring = keyring; - cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; -+ #endif - id_resolver_cache = cred; - return 0; - -@@ -296,7 +312,11 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen, - mutex_unlock(&idmap->idmap_mutex); - } - if (!IS_ERR(rkey)) -+ #ifdef CONFIG_KEYP -+ iee_set_key_flag_bit(rkey, KEY_FLAG_ROOT_CAN_INVAL, SET_BIT_OP); -+ #else - set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); -+ #endif - - kfree(desc); - return rkey; -@@ -321,7 +341,11 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen, - } - - rcu_read_lock(); -+ #ifdef CONFIG_KEYP -+ iee_set_key_perm(rkey, rkey->perm | KEY_USR_VIEW); -+ #else - rkey->perm |= KEY_USR_VIEW; -+ #endif - - ret = key_validate(rkey); - if (ret < 0) -diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c -index e6beaaf..eda3a9b 100644 ---- a/fs/nfsd/auth.c -+++ b/fs/nfsd/auth.c -@@ -2,6 +2,9 @@ - /* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */ - - #include <linux/sched.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif - #include "nfsd.h" - #include "auth.h" - -@@ -32,22 +35,40 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) - if (!new) - return -ENOMEM; - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(new, rqstp->rq_cred.cr_uid); -+ iee_set_cred_fsgid(new, rqstp->rq_cred.cr_gid); -+ #else - new->fsuid = rqstp->rq_cred.cr_uid; - new->fsgid = rqstp->rq_cred.cr_gid; -+ #endif - - rqgi = rqstp->rq_cred.cr_group_info; - - if (flags & NFSEXP_ALLSQUASH) { -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(new, exp->ex_anon_uid); -+ iee_set_cred_fsgid(new, exp->ex_anon_gid); -+ #else - new->fsuid = exp->ex_anon_uid; - new->fsgid = exp->ex_anon_gid; -+ #endif - gi = groups_alloc(0); - if (!gi) - goto oom; - } else if (flags & NFSEXP_ROOTSQUASH) { - if (uid_eq(new->fsuid, GLOBAL_ROOT_UID)) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(new, exp->ex_anon_uid); -+ #else - new->fsuid = exp->ex_anon_uid; -+ #endif - if (gid_eq(new->fsgid, GLOBAL_ROOT_GID)) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsgid(new, exp->ex_anon_gid); -+ #else - new->fsgid = exp->ex_anon_gid; -+ #endif - - gi = groups_alloc(rqgi->ngroups); - if (!gi) -@@ -67,18 +88,35 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) - } - - if (uid_eq(new->fsuid, INVALID_UID)) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(new, exp->ex_anon_uid); -+ #else - new->fsuid = exp->ex_anon_uid; -+ #endif - if (gid_eq(new->fsgid, INVALID_GID)) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsgid(new, exp->ex_anon_gid); -+ #else - new->fsgid = exp->ex_anon_gid; -+ #endif - - set_groups(new, gi); - put_group_info(gi); - - if (!uid_eq(new->fsuid, GLOBAL_ROOT_UID)) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_effective(new, cap_drop_nfsd_set(new->cap_effective)); -+ #else - new->cap_effective = cap_drop_nfsd_set(new->cap_effective); -+ #endif - else -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_effective(new, cap_raise_nfsd_set(new->cap_effective, -+ new->cap_permitted)); -+ #else - new->cap_effective = cap_raise_nfsd_set(new->cap_effective, - new->cap_permitted); -+ #endif - put_cred(override_creds(new)); - put_cred(new); - return 0; -diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c -index 926c298..07e44b5 100644 ---- a/fs/nfsd/nfs4callback.c -+++ b/fs/nfsd/nfs4callback.c -@@ -36,6 +36,9 @@ - #include <linux/sunrpc/xprt.h> - #include <linux/sunrpc/svc_xprt.h> - #include <linux/slab.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif - #include "nfsd.h" - #include "state.h" - #include "netns.h" -@@ -922,8 +925,13 @@ static const struct cred *get_backchannel_cred(struct nfs4_client *clp, struct r - if (!kcred) - return NULL; - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(kcred, ses->se_cb_sec.uid); -+ iee_set_cred_fsgid(kcred, ses->se_cb_sec.gid); -+ #else - kcred->fsuid = ses->se_cb_sec.uid; - kcred->fsgid = ses->se_cb_sec.gid; -+ #endif - return kcred; - } - } -diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c -index 3509e73..033bdb2 100644 ---- a/fs/nfsd/nfs4recover.c -+++ b/fs/nfsd/nfs4recover.c -@@ -44,6 +44,10 @@ - #include <linux/sunrpc/clnt.h> - #include <linux/nfsd/cld.h> - -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+ - #include "nfsd.h" - #include "state.h" - #include "vfs.h" -@@ -78,8 +82,13 @@ nfs4_save_creds(const struct cred **original_creds) - if (!new) - return -ENOMEM; - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(new, GLOBAL_ROOT_UID); -+ iee_set_cred_fsgid(new, GLOBAL_ROOT_GID); -+ #else - new->fsuid = GLOBAL_ROOT_UID; - new->fsgid = GLOBAL_ROOT_GID; -+ #endif - *original_creds = override_creds(new); - put_cred(new); - return 0; -diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c -index c2495d9..27d6955 100644 ---- a/fs/nfsd/nfsfh.c -+++ b/fs/nfsd/nfsfh.c -@@ -11,6 +11,9 @@ - #include <linux/exportfs.h> - - #include <linux/sunrpc/svcauth_gss.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif - #include "nfsd.h" - #include "vfs.h" - #include "auth.h" -@@ -223,9 +226,14 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) - error = nfserrno(-ENOMEM); - goto out; - } -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_effective(new, cap_raise_nfsd_set(new->cap_effective, -+ new->cap_permitted)); -+ #else - new->cap_effective = - cap_raise_nfsd_set(new->cap_effective, - new->cap_permitted); -+ #endif - put_cred(override_creds(new)); - put_cred(new); - } else { -diff --git a/fs/open.c b/fs/open.c -index 5626ed5..acbee47 100644 ---- a/fs/open.c -+++ b/fs/open.c -@@ -35,6 +35,10 @@ - #include <linux/mnt_idmapping.h> - #include <linux/filelock.h> - -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+ - #include "internal.h" - - int do_truncate(struct mnt_idmap *idmap, struct dentry *dentry, -@@ -414,17 +418,35 @@ static const struct cred *access_override_creds(void) - * routine. - */ - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(override_cred, override_cred->uid); -+ iee_set_cred_fsgid(override_cred, override_cred->gid); -+ #else - override_cred->fsuid = override_cred->uid; - override_cred->fsgid = override_cred->gid; -+ #endif - - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - /* Clear the capabilities if we switch to a non-root user */ - kuid_t root_uid = make_kuid(override_cred->user_ns, 0); - if (!uid_eq(override_cred->uid, root_uid)) -+ #ifdef CONFIG_CREDP -+ do { -+ kernel_cap_t tmp_cap = override_cred->cap_effective; -+ -+ tmp_cap.val = 0; -+ iee_set_cred_cap_effective(override_cred, tmp_cap); -+ } while (0); -+ #else - cap_clear(override_cred->cap_effective); -+ #endif - else -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_effective(override_cred, override_cred->cap_permitted); -+ #else - override_cred->cap_effective = - override_cred->cap_permitted; -+ #endif - } - - /* -@@ -444,7 +466,11 @@ static const struct cred *access_override_creds(void) - * expecting RCU freeing. But normal thread-synchronous - * cred accesses will keep things non-RCY. - */ -+ #ifdef CONFIG_CREDP -+ iee_set_cred_non_rcu(override_cred, 1); -+ #else - override_cred->non_rcu = 1; -+ #endif - - old_cred = override_creds(override_cred); - -diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c -index 54602f0..3b81179 100644 ---- a/fs/overlayfs/dir.c -+++ b/fs/overlayfs/dir.c -@@ -14,6 +14,9 @@ - #include <linux/posix_acl_xattr.h> - #include <linux/atomic.h> - #include <linux/ratelimit.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif - #include "overlayfs.h" - - static unsigned short ovl_redirect_max = 256; -@@ -590,8 +593,13 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, - * create a new inode, so just use the ovl mounter's - * fs{u,g}id. - */ -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(override_cred, inode->i_uid); -+ iee_set_cred_fsgid(override_cred, inode->i_gid); -+ #else - override_cred->fsuid = inode->i_uid; - override_cred->fsgid = inode->i_gid; -+ #endif - err = security_dentry_create_files_as(dentry, - attr->mode, &dentry->d_name, old_cred, - override_cred); -diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c -index 7337fb0..c12511a 100644 ---- a/fs/overlayfs/super.c -+++ b/fs/overlayfs/super.c -@@ -18,6 +18,9 @@ - #include <linux/file.h> - #include <linux/fs_context.h> - #include <linux/fs_parser.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif - #include "overlayfs.h" - #include "params.h" - -@@ -1493,7 +1496,16 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc) - sb->s_export_op = &ovl_export_fid_operations; - - /* Never override disk quota limits or use reserved space */ -+ #ifdef CONFIG_CREDP -+ { -+ kernel_cap_t tmp = cred->cap_effective; -+ -+ cap_lower(tmp, CAP_SYS_RESOURCE); -+ iee_set_cred_cap_effective(cred, tmp); -+ } -+ #else - cap_lower(cred->cap_effective, CAP_SYS_RESOURCE); -+ #endif - - sb->s_magic = OVERLAYFS_SUPER_MAGIC; - sb->s_xattr = ofs->config.userxattr ? ovl_user_xattr_handlers : -diff --git a/fs/smb/client/cifs_spnego.c b/fs/smb/client/cifs_spnego.c -index af7849e..baaedce 100644 ---- a/fs/smb/client/cifs_spnego.c -+++ b/fs/smb/client/cifs_spnego.c -@@ -14,6 +14,12 @@ - #include <linux/key-type.h> - #include <linux/keyctl.h> - #include <linux/inet.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif - #include "cifsglob.h" - #include "cifs_spnego.h" - #include "cifs_debug.h" -@@ -33,7 +39,13 @@ cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep) - goto error; - - /* attach the data */ -+ #ifdef CONFIG_KEYP -+ union key_payload *key_payload = (union key_payload *)(key->name_link.next); -+ -+ key_payload->data[0] = payload; -+ #else - key->payload.data[0] = payload; -+ #endif - ret = 0; - - error: -@@ -43,7 +55,11 @@ cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep) - static void - cifs_spnego_key_destroy(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ kfree(((union key_payload *)(key->name_link.next))->data[0]); -+ #else - kfree(key->payload.data[0]); -+ #endif - } - - -@@ -163,7 +179,11 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo, - - #ifdef CONFIG_CIFS_DEBUG2 - if (cifsFYI && !IS_ERR(spnego_key)) { -+ #ifdef CONFIG_KEYP -+ struct cifs_spnego_msg *msg = ((union key_payload *)(spnego_key->name_link.next))->data[0]; -+ #else - struct cifs_spnego_msg *msg = spnego_key->payload.data[0]; -+ #endif - cifs_dump_mem("SPNEGO reply blob:", msg->data, min(1024U, - msg->secblob_len + msg->sesskey_len)); - } -@@ -211,9 +231,18 @@ init_cifs_spnego(void) - * instruct request_key() to use this special keyring as a cache for - * the results it looks up - */ -+ #ifdef CONFIG_KEYP -+ iee_set_key_flag_bit(keyring, KEY_FLAG_ROOT_CAN_CLEAR, SET_BIT_OP); -+ #else - set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); -+ #endif -+ #ifdef CONFIG_CREDP -+ iee_set_cred_thread_keyring(cred, keyring); -+ iee_set_cred_jit_keyring(cred, KEY_REQKEY_DEFL_THREAD_KEYRING); -+ #else - cred->thread_keyring = keyring; - cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; -+ #endif - spnego_cred = cred; - - cifs_dbg(FYI, "cifs spnego keyring: %d\n", key_serial(keyring)); -diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c -index f5b6df8..ad52d61 100644 ---- a/fs/smb/client/cifsacl.c -+++ b/fs/smb/client/cifsacl.c -@@ -17,6 +17,13 @@ - #include <linux/posix_acl.h> - #include <linux/posix_acl_xattr.h> - #include <keys/user-type.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#include <asm/iee-access.h> -+#endif - #include "cifspdu.h" - #include "cifsglob.h" - #include "cifsacl.h" -@@ -78,16 +85,33 @@ cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep) - * dereference payload.data! - */ - if (prep->datalen <= sizeof(key->payload)) { -+ #ifdef CONFIG_KEYP -+ union key_payload *key_payload = (union key_payload *)(key->name_link.next); -+ -+ key_payload->data[0] = NULL; -+ memcpy(key_payload, prep->data, prep->datalen); -+ #else - key->payload.data[0] = NULL; - memcpy(&key->payload, prep->data, prep->datalen); -+ #endif - } else { - payload = kmemdup(prep->data, prep->datalen, GFP_KERNEL); - if (!payload) - return -ENOMEM; -+ #ifdef CONFIG_KEYP -+ union key_payload *key_payload = (union key_payload *)(key->name_link.next); -+ -+ key_payload->data[0] = payload; -+ #else - key->payload.data[0] = payload; -+ #endif - } - -+ #ifdef CONFIG_KEYP -+ iee_set_key_datalen(key, prep->datalen); -+ #else - key->datalen = prep->datalen; -+ #endif - return 0; - } - -@@ -95,7 +119,11 @@ static inline void - cifs_idmap_key_destroy(struct key *key) - { - if (key->datalen > sizeof(key->payload)) -+ #ifdef CONFIG_KEYP -+ kfree(((union key_payload *)(key->name_link.next))->data[0]); -+ #else - kfree(key->payload.data[0]); -+ #endif - } - - static struct key_type cifs_idmap_key_type = { -@@ -311,9 +339,15 @@ id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid) - * there are no subauthorities and the host has 8-byte pointers, then - * it could be. - */ -+ #ifdef CONFIG_KEYP -+ ksid = sidkey->datalen <= sizeof(sidkey->payload) ? -+ (struct cifs_sid *)(sidkey->name_link.next) : -+ (struct cifs_sid *)((union key_payload *)(sidkey->name_link.next))->data[0]; -+ #else - ksid = sidkey->datalen <= sizeof(sidkey->payload) ? - (struct cifs_sid *)&sidkey->payload : - (struct cifs_sid *)sidkey->payload.data[0]; -+ #endif - - ksid_size = CIFS_SID_BASE_SIZE + (ksid->num_subauth * sizeof(__le32)); - if (ksid_size > sidkey->datalen) { -@@ -422,14 +456,22 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, - if (sidtype == SIDOWNER) { - kuid_t uid; - uid_t id; -+ #ifdef CONFIG_KEYP -+ memcpy(&id, &((union key_payload *)(sidkey->name_link.next))->data[0], sizeof(uid_t)); -+ #else - memcpy(&id, &sidkey->payload.data[0], sizeof(uid_t)); -+ #endif - uid = make_kuid(&init_user_ns, id); - if (uid_valid(uid)) - fuid = uid; - } else { - kgid_t gid; - gid_t id; -+ #ifdef CONFIG_KEYP -+ memcpy(&id, &((union key_payload *)(sidkey->name_link.next))->data[0], sizeof(gid_t)); -+ #else - memcpy(&id, &sidkey->payload.data[0], sizeof(gid_t)); -+ #endif - gid = make_kgid(&init_user_ns, id); - if (gid_valid(gid)) - fgid = gid; -@@ -490,9 +532,18 @@ init_cifs_idmap(void) - - /* instruct request_key() to use this special keyring as a cache for - * the results it looks up */ -+ #ifdef CONFIG_KEYP -+ iee_set_key_flag_bit(keyring, KEY_FLAG_ROOT_CAN_CLEAR, SET_BIT_OP); -+ #else - set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); -+ #endif -+ #ifdef CONFIG_CREDP -+ iee_set_cred_thread_keyring(cred, keyring); -+ iee_set_cred_jit_keyring(cred, KEY_REQKEY_DEFL_THREAD_KEYRING); -+ #else - cred->thread_keyring = keyring; - cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; -+ #endif - root_cred = cred; - - cifs_dbg(FYI, "cifs idmap keyring: %d\n", key_serial(keyring)); -diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c -index d2307162..d6c7a26 100644 ---- a/fs/smb/client/connect.c -+++ b/fs/smb/client/connect.c -@@ -2138,7 +2138,11 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses) - is_domain = 1; - } - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(key)); -+ #else - down_read(&key->sem); -+ #endif - upayload = user_key_payload_locked(key); - if (IS_ERR_OR_NULL(upayload)) { - rc = upayload ? PTR_ERR(upayload) : -EINVAL; -@@ -2216,7 +2220,11 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses) - strscpy(ctx->workstation_name, ses->workstation_name, sizeof(ctx->workstation_name)); - - out_key_put: -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - key_put(key); - out_err: - kfree(desc); -diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c -index 3216f78..3160e70 100644 ---- a/fs/smb/client/sess.c -+++ b/fs/smb/client/sess.c -@@ -1591,7 +1591,11 @@ sess_auth_kerberos(struct sess_data *sess_data) - goto out; - } - -+ #ifdef CONFIG_KEYP -+ msg = ((union key_payload *)(spnego_key->name_link.next))->data[0]; -+ #else - msg = spnego_key->payload.data[0]; -+ #endif - /* - * check version field to make sure that cifs.upcall is - * sending us a response in an expected form -diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c -index 61df8a5..eed66d7 100644 ---- a/fs/smb/client/smb2pdu.c -+++ b/fs/smb/client/smb2pdu.c -@@ -1623,7 +1623,11 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data) - goto out; - } - -+ #ifdef CONFIG_KEYP -+ msg = ((union key_payload *)(spnego_key->name_link.next))->data[0]; -+ #else - msg = spnego_key->payload.data[0]; -+ #endif - /* - * check version field to make sure that cifs.upcall is - * sending us a response in an expected form -diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c -index 474dadf..bb6a022 100644 ---- a/fs/smb/server/smb_common.c -+++ b/fs/smb/server/smb_common.c -@@ -5,6 +5,9 @@ - */ - - #include <linux/user_namespace.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif - - #include "smb_common.h" - #include "server.h" -@@ -752,8 +755,13 @@ int ksmbd_override_fsids(struct ksmbd_work *work) - if (!cred) - return -ENOMEM; - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(cred, make_kuid(&init_user_ns, uid)); -+ iee_set_cred_fsgid(cred, make_kgid(&init_user_ns, gid)); -+ #else - cred->fsuid = make_kuid(&init_user_ns, uid); - cred->fsgid = make_kgid(&init_user_ns, gid); -+ #endif - - gi = groups_alloc(0); - if (!gi) { -@@ -764,7 +772,11 @@ int ksmbd_override_fsids(struct ksmbd_work *work) - put_group_info(gi); - - if (!uid_eq(cred->fsuid, GLOBAL_ROOT_UID)) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_effective(cred, cap_drop_fs_set(cred->cap_effective)); -+ #else - cred->cap_effective = cap_drop_fs_set(cred->cap_effective); -+ #endif - - WARN_ON(work->saved_cred); - work->saved_cred = override_creds(cred); -diff --git a/fs/ubifs/auth.c b/fs/ubifs/auth.c -index e564d5f..2d3ca59 100644 ---- a/fs/ubifs/auth.c -+++ b/fs/ubifs/auth.c -@@ -284,7 +284,11 @@ int ubifs_init_authentication(struct ubifs_info *c) - return PTR_ERR(keyring_key); - } - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(keyring_key)); -+ #else - down_read(&keyring_key->sem); -+ #endif - - if (keyring_key->type != &key_type_logon) { - ubifs_err(c, "key type must be logon"); -@@ -351,7 +355,11 @@ int ubifs_init_authentication(struct ubifs_info *c) - if (err) - crypto_free_shash(c->hash_tfm); - out: -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(keyring_key)); -+ #else - up_read(&keyring_key->sem); -+ #endif - key_put(keyring_key); - - return err; -diff --git a/fs/verity/signature.c b/fs/verity/signature.c -index 90c0757..e076cb6 100644 ---- a/fs/verity/signature.c -+++ b/fs/verity/signature.c -@@ -62,7 +62,11 @@ int fsverity_verify_signature(const struct fsverity_info *vi, - return 0; - } - -+ #ifdef CONFIG_KEYP -+ if (((struct key_struct *)(fsverity_keyring->name_link.prev))->keys.nr_leaves_on_tree == 0) { -+ #else - if (fsverity_keyring->keys.nr_leaves_on_tree == 0) { -+ #endif - /* - * The ".fs-verity" keyring is empty, due to builtin signatures - * being supported by the kernel but not actually being used. -diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h -index 5c0bea9..2b4dd2c 100644 ---- a/include/acpi/actbl2.h -+++ b/include/acpi/actbl2.h -@@ -897,8 +897,7 @@ enum acpi_madt_type { - ACPI_MADT_TYPE_APLIC = 26, - ACPI_MADT_TYPE_PLIC = 27, - ACPI_MADT_TYPE_RESERVED = 28, /* 28 to 0x7F are reserved */ -- ACPI_MADT_TYPE_OEM_RESERVED = 0x80, /* 0x80 to 0xFF are reserved for OEM use */ -- ACPI_MADT_TYPE_PHYTIUM_2500 = 128 -+ ACPI_MADT_TYPE_OEM_RESERVED = 0x80 /* 0x80 to 0xFF are reserved for OEM use */ - }; - - /* -diff --git a/include/asm-generic/fixmap.h b/include/asm-generic/fixmap.h -index 8cc7b09..f406370 100644 ---- a/include/asm-generic/fixmap.h -+++ b/include/asm-generic/fixmap.h -@@ -70,6 +70,24 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr) - __set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR) - #endif - -+#ifdef CONFIG_PTP -+#ifndef clear_fixmap_init -+#define clear_fixmap_init(idx) \ -+ __iee_set_fixmap_pre_init(idx, 0, FIXMAP_PAGE_CLEAR) -+#endif -+ -+#define __iee_set_fixmap_offset_pre_init(idx, phys, flags) \ -+({ \ -+ unsigned long ________addr; \ -+ __iee_set_fixmap_pre_init(idx, phys, flags); \ -+ ________addr = fix_to_virt(idx) + ((phys) & (PAGE_SIZE - 1)); \ -+ ________addr; \ -+}) -+ -+#define iee_set_fixmap_offset_pre_init(idx, phys) \ -+ __iee_set_fixmap_offset_pre_init(idx, phys, FIXMAP_PAGE_NORMAL) -+#endif /* CONFIG_PTP */ -+ - /* Return a pointer with offset calculated */ - #define __set_fixmap_offset(idx, phys, flags) \ - ({ \ -diff --git a/include/asm-generic/pgtable-nop4d.h b/include/asm-generic/pgtable-nop4d.h -index 03b7dae..da1c229 100644 ---- a/include/asm-generic/pgtable-nop4d.h -+++ b/include/asm-generic/pgtable-nop4d.h -@@ -26,6 +26,11 @@ static inline void pgd_clear(pgd_t *pgd) { } - - #define pgd_populate(mm, pgd, p4d) do { } while (0) - #define pgd_populate_safe(mm, pgd, p4d) do { } while (0) -+#ifdef CONFIG_PTP -+#define iee_pgd_populate_pre_init(mm, pgd, p4d) do { } while (0) -+#define iee_pgd_populate_safe_pre_init(mm, pgd, p4d) do { } while (0) -+#endif -+ - /* - * (p4ds are folded into pgds so this doesn't get actually called, - * but the define is needed for a generic inline function.) -diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h -index 46574f6..595435e 100644 ---- a/include/asm-generic/vmlinux.lds.h -+++ b/include/asm-generic/vmlinux.lds.h -@@ -1095,7 +1095,14 @@ - * Definition of the high level *_SECTION macros - * They will fit only a subset of the architectures - */ -- -+#ifdef CONFIG_CREDP -+ #define CRED_DATA \ -+ . = ALIGN(PAGE_SIZE); \ -+ *(.iee.cred) \ -+ . = ALIGN(PAGE_SIZE); -+#else -+ #define CRED_DATA -+#endif - - /* - * Writeable data. -@@ -1113,6 +1120,7 @@ - . = ALIGN(PAGE_SIZE); \ - .data : AT(ADDR(.data) - LOAD_OFFSET) { \ - INIT_TASK_DATA(inittask) \ -+ CRED_DATA \ - NOSAVE_DATA \ - PAGE_ALIGNED_DATA(pagealigned) \ - CACHELINE_ALIGNED_DATA(cacheline) \ -diff --git a/include/drm/drm_cache.h b/include/drm/drm_cache.h -index 08e0e3f..667fb03 100644 ---- a/include/drm/drm_cache.h -+++ b/include/drm/drm_cache.h -@@ -74,7 +74,7 @@ static inline bool drm_arch_can_wc_memory(void) - * cache coherency machanism. This means WUC can only used for write-only - * memory regions. - */ -- return false; -+ return wc_enabled; - #else - return true; - #endif -diff --git a/include/keys/asymmetric-subtype.h b/include/keys/asymmetric-subtype.h -index d55171f..1293c5a 100644 ---- a/include/keys/asymmetric-subtype.h -+++ b/include/keys/asymmetric-subtype.h -@@ -54,7 +54,11 @@ struct asymmetric_key_subtype { - static inline - struct asymmetric_key_subtype *asymmetric_key_subtype(const struct key *key) - { -+ #ifdef CONFIG_KEYP -+ return ((union key_payload *)(key->name_link.next))->data[asym_subtype]; -+ #else - return key->payload.data[asym_subtype]; -+ #endif - } - - #endif /* _KEYS_ASYMMETRIC_SUBTYPE_H */ -diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h -index 69a13e1..6cd556b 100644 ---- a/include/keys/asymmetric-type.h -+++ b/include/keys/asymmetric-type.h -@@ -69,13 +69,21 @@ extern struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1, - static inline - const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key) - { -+ #ifdef CONFIG_KEYP -+ return ((union key_payload *)(key->name_link.next))->data[asym_key_ids]; -+ #else - return key->payload.data[asym_key_ids]; -+ #endif - } - - static inline - const struct public_key *asymmetric_key_public_key(const struct key *key) - { -+ #ifdef CONFIG_KEYP -+ return ((union key_payload *)(key->name_link.next))->data[asym_crypto]; -+ #else - return key->payload.data[asym_crypto]; -+ #endif - } - - extern struct key *find_asymmetric_key(struct key *keyring, -diff --git a/include/keys/request_key_auth-type.h b/include/keys/request_key_auth-type.h -index 36b89a9..63d5d9f 100644 ---- a/include/keys/request_key_auth-type.h -+++ b/include/keys/request_key_auth-type.h -@@ -26,7 +26,11 @@ struct request_key_auth { - - static inline struct request_key_auth *get_request_key_auth(const struct key *key) - { -+ #ifdef CONFIG_KEYP -+ return ((union key_payload *)(key->name_link.next))->data[0]; -+ #else - return key->payload.data[0]; -+ #endif - } - - -diff --git a/include/linux/compiler.h b/include/linux/compiler.h -index df29ddb..266a749 100644 ---- a/include/linux/compiler.h -+++ b/include/linux/compiler.h -@@ -133,7 +133,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, - #define annotate_unreachable() __annotate_unreachable(__COUNTER__) - - /* Annotate a C jump table to allow objtool to follow the code flow */ --#define __annotate_jump_table __section(".rodata..c_jump_table") -+#define __annotate_jump_table __section(".rodata..c_jump_table,\"a\",@progbits #") - - #else /* !CONFIG_OBJTOOL */ - #define annotate_reachable() -diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h -index 837bad9..58e778d 100644 ---- a/include/linux/cpuhotplug.h -+++ b/include/linux/cpuhotplug.h -@@ -151,6 +151,10 @@ enum cpuhp_state { - CPUHP_AP_IRQ_MIPS_GIC_STARTING, - CPUHP_AP_IRQ_RISCV_STARTING, - CPUHP_AP_IRQ_LOONGARCH_STARTING, -+#ifdef CONFIG_LOONGARCH -+ CPUHP_AP_IRQ_EIOINTC_STARTING, -+ CPUHP_AP_IRQ_AVECINTC_STARTING, -+#endif - CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, - CPUHP_AP_ARM_MVEBU_COHERENCY, - CPUHP_AP_MICROCODE_LOADER, -diff --git a/include/linux/cred.h b/include/linux/cred.h -index bb55703..c4a352d 100644 ---- a/include/linux/cred.h -+++ b/include/linux/cred.h -@@ -15,6 +15,9 @@ - #include <linux/uidgid.h> - #include <linux/sched.h> - #include <linux/sched/user.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-def.h> -+#endif - - struct cred; - struct inode; -@@ -145,6 +148,23 @@ struct cred { - }; - } __randomize_layout; - -+#ifdef CONFIG_CREDP -+extern unsigned long long iee_rw_gate(int flag, ...); -+static void iee_set_cred_non_rcu(struct cred *cred, int non_rcu) -+{ -+ iee_rw_gate(IEE_OP_SET_CRED_NON_RCU, cred, non_rcu); -+ *(int *)(&(((struct rcu_head *)(cred->rcu.func))->next)) = non_rcu; -+} -+ -+static bool iee_set_cred_atomic_op_usage(struct cred *cred, int flag, int nr) -+{ -+ bool ret; -+ -+ ret = iee_rw_gate(IEE_OP_SET_CRED_ATOP_USAGE, cred, flag, nr); -+ return ret; -+} -+#endif -+ - extern void __put_cred(struct cred *); - extern void exit_creds(struct task_struct *); - extern int copy_creds(struct task_struct *, unsigned long); -@@ -180,7 +200,11 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred) - */ - static inline struct cred *get_new_cred(struct cred *cred) - { -+ #ifdef CONFIG_CREDP -+ iee_set_cred_atomic_op_usage(cred, AT_ADD, 1); -+ #else - atomic_long_inc(&cred->usage); -+ #endif - return cred; - } - -@@ -202,7 +226,11 @@ static inline const struct cred *get_cred(const struct cred *cred) - struct cred *nonconst_cred = (struct cred *) cred; - if (!cred) - return cred; -+ #ifdef CONFIG_CREDP -+ iee_set_cred_non_rcu(nonconst_cred, 0); -+ #else - nonconst_cred->non_rcu = 0; -+ #endif - return get_new_cred(nonconst_cred); - } - -@@ -211,9 +239,15 @@ static inline const struct cred *get_cred_rcu(const struct cred *cred) - struct cred *nonconst_cred = (struct cred *) cred; - if (!cred) - return NULL; -+ #ifdef CONFIG_CREDP -+ if (!iee_set_cred_atomic_op_usage(nonconst_cred, AT_INC_NOT_ZERO, 0)) -+ return NULL; -+ iee_set_cred_non_rcu(nonconst_cred, 0); -+ #else - if (!atomic_long_inc_not_zero(&nonconst_cred->usage)) - return NULL; - nonconst_cred->non_rcu = 0; -+ #endif - return cred; - } - -@@ -233,8 +267,13 @@ static inline void put_cred(const struct cred *_cred) - struct cred *cred = (struct cred *) _cred; - - if (cred) { -+ #ifdef CONFIG_CREDP -+ if (iee_set_cred_atomic_op_usage(cred, AT_SUB_AND_TEST, 1)) -+ __put_cred(cred); -+ #else - if (atomic_long_dec_and_test(&(cred)->usage)) - __put_cred(cred); -+ #endif - } - } - -diff --git a/include/linux/iee-func.h b/include/linux/iee-func.h -new file mode 100644 -index 0000000..ba73162 ---- /dev/null -+++ b/include/linux/iee-func.h -@@ -0,0 +1,33 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _LINUX_IEE_FUNC_H -+#define _LINUX_IEE_FUNC_H -+#include <linux/sched.h> -+extern void *alloc_low_pages(unsigned int num); -+#define HUGE_PMD_ORDER 9 -+#define TASK_ORDER 4 -+extern unsigned long init_iee_stack_begin[]; -+extern unsigned long init_iee_stack_end[]; -+extern void *init_token_page_vaddr; -+ -+extern void set_iee_page_valid(unsigned long addr); -+extern void set_iee_page_invalid(unsigned long addr); -+extern void iee_set_logical_mem_ro(unsigned long addr); -+extern void set_iee_page(unsigned long addr, int order); -+extern void unset_iee_page(unsigned long addr, int order); -+extern void iee_mark_all_lm_pgtable_ro(void); -+extern void iee_set_token_page_valid(void *token, void *token_page, unsigned int order); -+extern void iee_set_token_page_invalid(void *token, void *token_page, unsigned long order); -+extern void iee_free_token(struct task_struct *tsk); -+extern unsigned long iee_read_token_stack(struct task_struct *tsk); -+extern void *iee_read_tmp_page(struct task_struct *tsk); -+extern void *iee_read_pgd(struct task_struct *tsk); -+extern void iee_set_kernel_upage(unsigned long addr); -+extern void iee_rest_init(void); -+extern void set_iee_stack_page(unsigned long addr, int order); -+extern void unset_iee_stack_page(unsigned long addr, int order); -+extern void *iee_read_freeptr(unsigned long ptr); -+extern void iee_free_slab(struct kmem_cache *s, struct slab *slab, void (*do_free_slab)(struct work_struct *work)); -+ -+extern void iee_free_task_struct_slab(struct work_struct *work); -+extern void iee_free_cred_slab(struct work_struct *work); -+#endif /* _LINUX_IEE_FUNC_H */ -diff --git a/include/linux/irqchip/arm-gic-phytium-2500.h b/include/linux/irqchip/arm-gic-phytium-2500.h -index f212a29..3688d93 100644 ---- a/include/linux/irqchip/arm-gic-phytium-2500.h -+++ b/include/linux/irqchip/arm-gic-phytium-2500.h -@@ -1,8 +1,8 @@ --/* SPDX-License-Identifier: GPL-2.0-only */ -+/* SPDX-License-Identifier: GPL-2.0 */ - /* -- * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved. -- * Author: Marc Zyngier <marc.zyngier@arm.com> -+ * Copyright (C) 2020-2023, Phytium Technology Co., Ltd - */ -+ - #ifndef __LINUX_IRQCHIP_ARM_GIC_PHYTIUM_2500_H - #define __LINUX_IRQCHIP_ARM_GIC_PHYTIUM_2500_H - -@@ -635,7 +635,7 @@ struct rdists { - - struct irq_domain; - struct fwnode_handle; --int __init its_lpi_memreserve_init(void); -+int __init phytium_its_lpi_memreserve_init(void); - int phytium_its_cpu_init(void); - int phytium_its_init(struct fwnode_handle *handle, struct rdists *rdists, - struct irq_domain *domain); -diff --git a/include/linux/key.h b/include/linux/key.h -index 938d7ec..8256ae9 100644 ---- a/include/linux/key.h -+++ b/include/linux/key.h -@@ -280,6 +280,36 @@ struct key { - struct key_restriction *restrict_link; - }; - -+#ifdef CONFIG_KEYP -+struct key_union { -+ union { -+ struct list_head graveyard_link; -+ struct rb_node serial_node; -+ }; -+ struct rw_semaphore sem; -+ struct key *key; -+}; -+ -+struct key_struct { -+ struct { -+ /* Keyring bits */ -+ struct list_head name_link; -+ struct assoc_array keys; -+ }; -+ struct key *key; -+}; -+#define KEY_SEM(KEY) (((struct key_union *)(KEY->graveyard_link.next))->sem) -+#include <asm/iee-def.h> -+extern unsigned long long iee_rw_gate(int flag, ...); -+static bool iee_set_key_usage(struct key *key, int n, int flag) -+{ -+ bool ret; -+ -+ ret = iee_rw_gate(IEE_OP_SET_KEY_USAGE, key, n, flag); -+ return ret; -+} -+#endif -+ - extern struct key *key_alloc(struct key_type *type, - const char *desc, - kuid_t uid, kgid_t gid, -@@ -305,7 +335,11 @@ extern void key_remove_domain(struct key_tag *domain_tag); - - static inline struct key *__key_get(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ iee_set_key_usage(key, 0, REFCOUNT_INC); -+ #else - refcount_inc(&key->usage); -+ #endif - return key; - } - -@@ -478,6 +512,43 @@ static inline bool key_is_negative(const struct key *key) - return key_read_state(key) < 0; - } - -+#ifdef CONFIG_KEYP -+static inline void iee_write_key_payload_rcu_data0(struct key *key, void *rcu_data0) -+{ -+ union key_payload *key_payload = (union key_payload *)(key->name_link.next); -+ -+ WRITE_ONCE(key_payload->rcu_data0, rcu_data0); -+} -+ -+#define dereference_key_rcu(KEY) \ -+ (rcu_dereference(((union key_payload *)(KEY->name_link.next))->rcu_data0)) -+ -+#define dereference_key_locked(KEY) \ -+ (rcu_dereference_protected(((union key_payload *)(KEY->name_link.next))->rcu_data0, \ -+ rwsem_is_locked(&KEY_SEM(((struct key *)(KEY)))))) -+ -+#define iee_smp_store_release(p, v, KEY) \ -+do { \ -+ compiletime_assert_atomic_type(*p); \ -+ barrier(); \ -+ iee_write_key_payload_rcu_data0(KEY, v); \ -+} while (0) -+ -+#define iee_rcu_assign_pointer(p, v, KEY) \ -+do { \ -+ uintptr_t _r_a_p__v = (uintptr_t)(v); \ -+ rcu_check_sparse(p, __rcu); \ -+ \ -+ if (__builtin_constant_p(v) && (_r_a_p__v) == (uintptr_t)NULL) \ -+ iee_write_key_payload_rcu_data0(KEY, (typeof(p))(_r_a_p__v)); \ -+ else \ -+ iee_smp_store_release(&p, RCU_INITIALIZER((typeof(p))_r_a_p__v), KEY); \ -+} while (0) -+ -+#define rcu_assign_keypointer(KEY, PAYLOAD) \ -+ iee_rcu_assign_pointer(((union key_payload *)(KEY->name_link.next))->rcu_data0, (PAYLOAD), KEY) -+ -+#else - #define dereference_key_rcu(KEY) \ - (rcu_dereference((KEY)->payload.rcu_data0)) - -@@ -489,6 +560,7 @@ static inline bool key_is_negative(const struct key *key) - do { \ - rcu_assign_pointer((KEY)->payload.rcu_data0, (PAYLOAD)); \ - } while (0) -+#endif - - /* - * the userspace interface -diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h -index 36545ce..cd0b218 100644 ---- a/include/linux/kvm_host.h -+++ b/include/linux/kvm_host.h -@@ -216,6 +216,7 @@ enum kvm_bus { - KVM_PIO_BUS, - KVM_VIRTIO_CCW_NOTIFY_BUS, - KVM_FAST_MMIO_BUS, -+ KVM_IOCSR_BUS, - KVM_NR_BUSES - }; - -diff --git a/include/linux/mm.h b/include/linux/mm.h -index 6585f54..37f4898 100644 ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -3895,8 +3895,9 @@ void *sparse_buffer_alloc(unsigned long size); - struct page * __populate_section_memmap(unsigned long pfn, - unsigned long nr_pages, int nid, struct vmem_altmap *altmap, - struct dev_pagemap *pgmap); --void pmd_init(void *addr); - void pud_init(void *addr); -+void pmd_init(void *addr); -+void kernel_pte_init(void *addr); - pgd_t *vmemmap_pgd_populate(unsigned long addr, int node); - p4d_t *vmemmap_p4d_populate(pgd_t *pgd, unsigned long addr, int node); - pud_t *vmemmap_pud_populate(p4d_t *p4d, unsigned long addr, int node); -diff --git a/include/linux/pgtable.h b/include/linux/pgtable.h -index bdcc5bf..2bed740 100644 ---- a/include/linux/pgtable.h -+++ b/include/linux/pgtable.h -@@ -1062,6 +1062,38 @@ static inline int pgd_same(pgd_t pgd_a, pgd_t pgd_b) - set_pgd(pgdp, pgd); \ - }) - -+#ifdef CONFIG_PTP -+#define iee_set_pte_safe_pre_init(ptep, pte) \ -+({ \ -+ WARN_ON_ONCE(pte_present(*ptep) && !pte_same(*ptep, pte)); \ -+ iee_set_pte_pre_init(ptep, pte); \ -+}) -+ -+#define iee_set_pmd_safe_pre_init(pmdp, pmd) \ -+({ \ -+ WARN_ON_ONCE(pmd_present(*pmdp) && !pmd_same(*pmdp, pmd)); \ -+ iee_set_pmd_pre_init(pmdp, pmd); \ -+}) -+ -+#define iee_set_pud_safe_pre_init(pudp, pud) \ -+({ \ -+ WARN_ON_ONCE(pud_present(*pudp) && !pud_same(*pudp, pud)); \ -+ iee_set_pud_pre_init(pudp, pud); \ -+}) -+ -+#define iee_set_p4d_safe_pre_init(p4dp, p4d) \ -+({ \ -+ WARN_ON_ONCE(p4d_present(*p4dp) && !p4d_same(*p4dp, p4d)); \ -+ iee_set_p4d_pre_init(p4dp, p4d); \ -+}) -+ -+#define iee_set_pgd_safe_pre_init(pgdp, pgd) \ -+({ \ -+ WARN_ON_ONCE(pgd_present(*pgdp) && !pgd_same(*pgdp, pgd)); \ -+ iee_set_pgd_pre_init(pgdp, pgd); \ -+}) -+#endif -+ - #ifndef __HAVE_ARCH_DO_SWAP_PAGE - /* - * Some architectures support metadata associated with a page. When a -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 35d7d3f..a72f5ce 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -748,6 +748,16 @@ struct kmap_ctrl { - #endif - }; - -+#ifdef CONFIG_IEE -+struct task_token { -+ pgd_t *pgd; /* Logical VA */ -+ void *iee_stack; /* VA */ -+ void *tmp_page; -+ bool valid; -+ void *kernel_stack; /* VA */ -+}; -+#endif /* CONFIG_IEE */ -+ - struct task_struct { - #ifdef CONFIG_THREAD_INFO_IN_TASK - /* -diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h -index 1095290..0e485c5 100644 ---- a/include/uapi/linux/kvm.h -+++ b/include/uapi/linux/kvm.h -@@ -1423,7 +1423,15 @@ enum kvm_device_type { - #define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME - KVM_DEV_TYPE_RISCV_AIA, - #define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA -+ KVM_DEV_TYPE_LA_IOAPIC = 0x100, -+#define KVM_DEV_TYPE_LA_IOAPIC KVM_DEV_TYPE_LA_IOAPIC -+ KVM_DEV_TYPE_LA_IPI, -+#define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI -+ KVM_DEV_TYPE_LA_EXTIOI, -+#define KVM_DEV_TYPE_LA_EXTIOI KVM_DEV_TYPE_LA_EXTIOI -+ - KVM_DEV_TYPE_MAX, -+ - }; - - struct kvm_vfio_spapr_tce { -diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h -index add3498..3db2a19 100644 ---- a/include/uapi/linux/serial_core.h -+++ b/include/uapi/linux/serial_core.h -@@ -245,4 +245,7 @@ - /* Sunplus UART */ - #define PORT_SUNPLUS 123 - -+/* Phytium PCI UART */ -+#define PORT_PHYTIUM 124 -+ - #endif /* _UAPILINUX_SERIAL_CORE_H */ -diff --git a/init/initramfs.c b/init/initramfs.c -index 0e07714..7e09cb1 100644 ---- a/init/initramfs.c -+++ b/init/initramfs.c -@@ -358,6 +358,13 @@ static int __init do_name(void) - { - state = SkipIt; - next_state = Reset; -+ /* name_len > 0 && name_len <= PATH_MAX checked in do_header */ -+ if (collected[name_len - 1] != '\0') { -+ pr_err("initramfs name without nulterm: %.*s\n", -+ (int)name_len, collected); -+ error("malformed archive"); -+ return 1; -+ } - if (strcmp(collected, "TRAILER!!!") == 0) { - free_hash(); - return 0; -@@ -422,6 +429,12 @@ static int __init do_copy(void) - - static int __init do_symlink(void) - { -+ if (collected[name_len - 1] != '\0') { -+ pr_err("initramfs symlink without nulterm: %.*s\n", -+ (int)name_len, collected); -+ error("malformed archive"); -+ return 1; -+ } - collected[N_ALIGN(name_len) + body_len] = '\0'; - clean_path(collected, 0); - init_symlink(collected + N_ALIGN(name_len), collected); -diff --git a/init/main.c b/init/main.c -index fe67a55..3ce56d2 100644 ---- a/init/main.c -+++ b/init/main.c -@@ -113,6 +113,13 @@ - - #include <kunit/test.h> - -+#ifdef CONFIG_IEE -+#include <linux/iee-func.h> -+#include <asm/stack-slab.h> -+#include <asm/set_memory.h> -+#include <asm/iee-si.h> -+#endif -+ - static int kernel_init(void *); - - /* -@@ -873,6 +880,12 @@ static void __init print_unknown_bootoptions(void) - memblock_free(unknown_options, len); - } - -+#ifdef CONFIG_IEE -+void __weak __init iee_rest_init(void) -+{ -+} -+#endif -+ - asmlinkage __visible __init __no_sanitize_address __noreturn __no_stack_protector - void start_kernel(void) - { -@@ -933,6 +946,9 @@ void start_kernel(void) - sort_main_extable(); - trap_init(); - mm_core_init(); -+ #ifdef CONFIG_IEE -+ iee_stack_init(); -+ #endif - poking_init(); - ftrace_init(); - -@@ -1072,6 +1088,20 @@ void start_kernel(void) - arch_post_acpi_subsys_init(); - kcsan_init(); - -+ #ifdef CONFIG_IEE -+ iee_rest_init(); -+ /* Set iee stack pages ro */ -+ set_iee_stack_page((unsigned long)(__va(__pa_symbol(init_iee_stack_begin))), 2); -+ for (int i = 0; i < 4; i++) -+ iee_set_logical_mem_ro((unsigned long)init_iee_stack_begin + PAGE_SIZE * i); -+ -+ set_iee_page((unsigned long)init_token_page_vaddr, 0); -+ #endif -+ #ifdef CONFIG_PTP -+ /* Set the logical va of existing pgtable readonly */ -+ iee_mark_all_lm_pgtable_ro(); -+ #endif -+ - /* Do the rest non-__init'ed, we're now alive */ - arch_call_rest_init(); - -diff --git a/kernel/cred.c b/kernel/cred.c -index 85a200d..0cbbadb 100644 ---- a/kernel/cred.c -+++ b/kernel/cred.c -@@ -19,6 +19,10 @@ - #include <linux/binfmts.h> - #include <linux/cn_proc.h> - #include <linux/uidgid.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#include <linux/iee-func.h> -+#endif - - #if 0 - #define kdebug(FMT, ...) \ -@@ -33,7 +37,12 @@ do { \ - } while (0) - #endif - -+#ifdef CONFIG_CREDP -+struct kmem_cache *cred_jar; -+static struct kmem_cache *rcu_jar; -+#else - static struct kmem_cache *cred_jar; -+#endif - - /* init to 2 - one for init_task, one to ensure it is never freed */ - static struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; -@@ -41,6 +50,32 @@ static struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; - /* - * The initial credentials for the initial task - */ -+#ifdef CONFIG_CREDP -+struct cred init_cred __section(".iee.cred") = { -+ .usage = ATOMIC_INIT(4), -+#ifdef CONFIG_DEBUG_CREDENTIALS -+ .subscribers = ATOMIC_INIT(2), -+ .magic = CRED_MAGIC, -+#endif -+ .uid = GLOBAL_ROOT_UID, -+ .gid = GLOBAL_ROOT_GID, -+ .suid = GLOBAL_ROOT_UID, -+ .sgid = GLOBAL_ROOT_GID, -+ .euid = GLOBAL_ROOT_UID, -+ .egid = GLOBAL_ROOT_GID, -+ .fsuid = GLOBAL_ROOT_UID, -+ .fsgid = GLOBAL_ROOT_GID, -+ .securebits = SECUREBITS_DEFAULT, -+ .cap_inheritable = CAP_EMPTY_SET, -+ .cap_permitted = CAP_FULL_SET, -+ .cap_effective = CAP_FULL_SET, -+ .cap_bset = CAP_FULL_SET, -+ .user = INIT_USER, -+ .user_ns = &init_user_ns, -+ .group_info = &init_groups, -+ .ucounts = &init_ucounts, -+}; -+#else - struct cred init_cred = { - .usage = ATOMIC_INIT(4), - .uid = GLOBAL_ROOT_UID, -@@ -61,13 +96,18 @@ struct cred init_cred = { - .group_info = &init_groups, - .ucounts = &init_ucounts, - }; -+#endif - - /* - * The RCU callback to actually dispose of a set of credentials - */ - static void put_cred_rcu(struct rcu_head *rcu) - { -+ #ifdef CONFIG_CREDP -+ struct cred *cred = *(struct cred **)(rcu + 1); -+ #else - struct cred *cred = container_of(rcu, struct cred, rcu); -+ #endif - - kdebug("put_cred_rcu(%p)", cred); - -@@ -86,6 +126,9 @@ static void put_cred_rcu(struct rcu_head *rcu) - if (cred->ucounts) - put_ucounts(cred->ucounts); - put_user_ns(cred->user_ns); -+ #ifdef CONFIG_CREDP -+ kmem_cache_free(rcu_jar, (struct rcu_head *)(cred->rcu.func)); -+ #endif - kmem_cache_free(cred_jar, cred); - } - -@@ -104,10 +147,17 @@ void __put_cred(struct cred *cred) - BUG_ON(cred == current->cred); - BUG_ON(cred == current->real_cred); - -+ #ifdef CONFIG_CREDP -+ if (*(int *)(&(((struct rcu_head *)(cred->rcu.func))->next))) -+ put_cred_rcu((struct rcu_head *)(cred->rcu.func)); -+ else -+ call_rcu((struct rcu_head *)(cred->rcu.func), put_cred_rcu); -+ #else - if (cred->non_rcu) - put_cred_rcu(&cred->rcu); - else - call_rcu(&cred->rcu, put_cred_rcu); -+ #endif - } - EXPORT_SYMBOL(__put_cred); - -@@ -173,7 +223,13 @@ struct cred *cred_alloc_blank(void) - if (!new) - return NULL; - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_rcu(new, kmem_cache_zalloc(rcu_jar, GFP_KERNEL)); -+ *(struct cred **)(((struct rcu_head *)(new->rcu.func)) + 1) = new; -+ iee_set_cred_atomic_set_usage(new, 1); -+ #else - atomic_long_set(&new->usage, 1); -+ #endif - if (security_cred_alloc_blank(new, GFP_KERNEL_ACCOUNT) < 0) - goto error; - -@@ -208,13 +264,25 @@ struct cred *prepare_creds(void) - if (!new) - return NULL; - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_rcu(new, kmem_cache_alloc(rcu_jar, GFP_KERNEL)); -+ *(struct cred **)(((struct rcu_head *)(new->rcu.func)) + 1) = new; -+ #endif -+ - kdebug("prepare_creds() alloc %p", new); - - old = task->cred; -+ #ifdef CONFIG_CREDP -+ iee_copy_cred(old, new); -+ -+ iee_set_cred_non_rcu(new, 0); -+ iee_set_cred_atomic_set_usage(new, 1); -+ #else - memcpy(new, old, sizeof(struct cred)); - - new->non_rcu = 0; - atomic_long_set(&new->usage, 1); -+ #endif - get_group_info(new->group_info); - get_uid(new->user); - get_user_ns(new->user_ns); -@@ -227,10 +295,18 @@ struct cred *prepare_creds(void) - #endif - - #ifdef CONFIG_SECURITY -+ #ifdef CONFIG_CREDP -+ iee_set_cred_security(new, NULL); -+ #else - new->security = NULL; -+ #endif - #endif - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_ucounts(new, get_ucounts(new->ucounts)); -+ #else - new->ucounts = get_ucounts(new->ucounts); -+ #endif - if (!new->ucounts) - goto error; - -@@ -260,15 +336,30 @@ struct cred *prepare_exec_creds(void) - #ifdef CONFIG_KEYS - /* newly exec'd tasks don't get a thread keyring */ - key_put(new->thread_keyring); -+ #ifdef CONFIG_CREDP -+ iee_set_cred_thread_keyring(new, NULL); -+ #else - new->thread_keyring = NULL; -+ #endif - - /* inherit the session keyring; new process keyring */ - key_put(new->process_keyring); -+ #ifdef CONFIG_CREDP -+ iee_set_cred_process_keyring(new, NULL); -+ #else - new->process_keyring = NULL; -+ #endif - #endif - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(new, new->euid); -+ iee_set_cred_suid(new, new->euid); -+ iee_set_cred_fsgid(new, new->egid); -+ iee_set_cred_sgid(new, new->egid); -+ #else - new->suid = new->fsuid = new->euid; - new->sgid = new->fsgid = new->egid; -+ #endif - - return new; - } -@@ -323,7 +414,11 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) - * had one */ - if (new->thread_keyring) { - key_put(new->thread_keyring); -+ #ifdef CONFIG_CREDP -+ iee_set_cred_thread_keyring(new, NULL); -+ #else - new->thread_keyring = NULL; -+ #endif - if (clone_flags & CLONE_THREAD) - install_thread_keyring_to_cred(new); - } -@@ -333,7 +428,11 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) - */ - if (!(clone_flags & CLONE_THREAD)) { - key_put(new->process_keyring); -+ #ifdef CONFIG_CREDP -+ iee_set_cred_process_keyring(new, NULL); -+ #else - new->process_keyring = NULL; -+ #endif - } - #endif - -@@ -591,7 +690,11 @@ int set_cred_ucounts(struct cred *new) - if (!(new_ucounts = alloc_ucounts(new->user_ns, new->uid))) - return -EAGAIN; - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_ucounts(new, new_ucounts); -+ #else - new->ucounts = new_ucounts; -+ #endif - put_ucounts(old_ucounts); - - return 0; -@@ -603,8 +706,20 @@ int set_cred_ucounts(struct cred *new) - void __init cred_init(void) - { - /* allocate a slab in which we can store credentials */ -+ #ifdef CONFIG_CREDP -+ cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), 0, -+ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT|SLAB_RED_ZONE, NULL); -+ rcu_jar = kmem_cache_create("rcu_jar", sizeof(struct rcu_head) + sizeof(struct cred *), 0, -+ SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL); -+ // Map init_cred -+ *((struct rcu_head **)(&(init_cred.rcu.func))) = (struct rcu_head *)kmem_cache_zalloc(rcu_jar, GFP_KERNEL); -+ *(struct cred **)(((struct rcu_head *)(init_cred.rcu.func)) + 1) = &init_cred; -+ iee_set_logical_mem_ro((unsigned long)&init_cred); -+ set_iee_page((unsigned long)__va(__pa_symbol(&init_cred)), 0); -+ #else - cred_jar = KMEM_CACHE(cred, - SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT); -+ #endif - } - - /** -@@ -635,29 +750,56 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) - if (!new) - return NULL; - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_rcu(new, kmem_cache_alloc(rcu_jar, GFP_KERNEL)); -+ *(struct cred **)(((struct rcu_head *)(new->rcu.func)) + 1) = new; -+ #endif -+ - kdebug("prepare_kernel_cred() alloc %p", new); - - old = get_task_cred(daemon); - -+ #ifdef CONFIG_CREDP -+ iee_copy_cred(old, new); -+ iee_set_cred_non_rcu(new, 0); -+ iee_set_cred_atomic_set_usage(new, 1); -+ #else - *new = *old; - new->non_rcu = 0; - atomic_long_set(&new->usage, 1); -+ #endif - get_uid(new->user); - get_user_ns(new->user_ns); - get_group_info(new->group_info); - - #ifdef CONFIG_KEYS -+#ifdef CONFIG_CREDP -+ iee_set_cred_session_keyring(new, NULL); -+ iee_set_cred_process_keyring(new, NULL); -+ iee_set_cred_thread_keyring(new, NULL); -+ iee_set_cred_request_key_auth(new, NULL); -+ iee_set_cred_jit_keyring(new, KEY_REQKEY_DEFL_THREAD_KEYRING); -+#else - new->session_keyring = NULL; - new->process_keyring = NULL; - new->thread_keyring = NULL; - new->request_key_auth = NULL; - new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; - #endif -+#endif - - #ifdef CONFIG_SECURITY -+ #ifdef CONFIG_CREDP -+ iee_set_cred_security(new, NULL); -+ #else - new->security = NULL; -+ #endif - #endif -+ #ifdef CONFIG_CREDP -+ iee_set_cred_ucounts(new, get_ucounts(new->ucounts)); -+ #else - new->ucounts = get_ucounts(new->ucounts); -+ #endif - if (!new->ucounts) - goto error; - -@@ -724,8 +866,13 @@ int set_create_files_as(struct cred *new, struct inode *inode) - { - if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid)) - return -EINVAL; -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(new, inode->i_uid); -+ iee_set_cred_fsgid(new, inode->i_gid); -+ #else - new->fsuid = inode->i_uid; - new->fsgid = inode->i_gid; -+ #endif - return security_kernel_create_files_as(new, inode); - } - EXPORT_SYMBOL(set_create_files_as); -diff --git a/kernel/exit.c b/kernel/exit.c -index dea9eebf..4273d2e 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -75,6 +75,9 @@ - - #include <asm/unistd.h> - #include <asm/mmu_context.h> -+#ifdef CONFIG_IEE -+#include <asm/iee-token.h> -+#endif - - /* - * The default value should be high enough to not crash a system that randomly -@@ -562,6 +565,9 @@ static void exit_mm(void) - smp_mb__after_spinlock(); - local_irq_disable(); - current->mm = NULL; -+ #ifdef CONFIG_IEE -+ iee_set_token_pgd(current, NULL); -+ #endif - membarrier_update_current_mm(NULL); - enter_lazy_tlb(mm, current); - local_irq_enable(); -diff --git a/kernel/fork.c b/kernel/fork.c -index ae3725f..c1f79a9 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -116,6 +116,10 @@ - #define CREATE_TRACE_POINTS - #include <trace/events/task.h> - -+#ifdef CONFIG_IEE -+#include <asm/iee-token.h> -+#endif -+ - /* - * Minimum number of threads to boot the kernel - */ -@@ -171,7 +175,11 @@ void __weak arch_release_task_struct(struct task_struct *tsk) - } - - #ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR -+#ifdef CONFIG_IEE -+struct kmem_cache *task_struct_cachep; -+#else - static struct kmem_cache *task_struct_cachep; -+#endif - - static inline struct task_struct *alloc_task_struct_node(int node) - { -@@ -628,6 +636,9 @@ void free_task(struct task_struct *tsk) - arch_release_task_struct(tsk); - if (tsk->flags & PF_KTHREAD) - free_kthread_struct(tsk); -+ #ifdef CONFIG_IEE -+ iee_invalidate_token(tsk); -+ #endif - bpf_task_storage_free(tsk); - free_task_struct(tsk); - } -@@ -1073,10 +1084,17 @@ void __init fork_init(void) - - /* create a slab on which task_structs can be allocated */ - task_struct_whitelist(&useroffset, &usersize); -+ #ifdef CONFIG_IEE -+ task_struct_cachep = kmem_cache_create_usercopy("task_struct", -+ arch_task_struct_size, align, -+ SLAB_PANIC|SLAB_ACCOUNT|SLAB_RED_ZONE, -+ useroffset, usersize, NULL); -+ #else - task_struct_cachep = kmem_cache_create_usercopy("task_struct", - arch_task_struct_size, align, - SLAB_PANIC|SLAB_ACCOUNT, - useroffset, usersize, NULL); -+ #endif - #endif - - /* do the arch specific task caches init */ -@@ -1738,6 +1756,9 @@ static int copy_mm(unsigned long clone_flags, struct task_struct *tsk) - #endif - - tsk->mm = NULL; -+ #ifdef CONFIG_IEE -+ iee_set_token_pgd(tsk, NULL); -+ #endif - tsk->active_mm = NULL; - - /* -@@ -1759,6 +1780,9 @@ static int copy_mm(unsigned long clone_flags, struct task_struct *tsk) - } - - tsk->mm = mm; -+ #ifdef CONFIG_IEE -+ iee_set_token_pgd(tsk, mm->pgd); -+ #endif - tsk->active_mm = mm; - sched_mm_cid_fork(tsk); - return 0; -@@ -2238,6 +2262,11 @@ __latent_entropy struct task_struct *copy_process( - p = dup_task_struct(current, node); - if (!p) - goto fork_out; -+ -+ #ifdef CONFIG_IEE -+ iee_validate_token(p); -+ #endif -+ - p->flags &= ~PF_KTHREAD; - if (args->kthread) - p->flags |= PF_KTHREAD; -diff --git a/kernel/groups.c b/kernel/groups.c -index 9aaed2a..83b6fcc 100644 ---- a/kernel/groups.c -+++ b/kernel/groups.c -@@ -11,6 +11,9 @@ - #include <linux/user_namespace.h> - #include <linux/vmalloc.h> - #include <linux/uaccess.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif - - struct group_info *groups_alloc(int gidsetsize) - { -@@ -119,7 +122,11 @@ void set_groups(struct cred *new, struct group_info *group_info) - { - put_group_info(new->group_info); - get_group_info(group_info); -+ #ifdef CONFIG_CREDP -+ iee_set_cred_group_info(new, group_info); -+ #else - new->group_info = group_info; -+ #endif - } - - EXPORT_SYMBOL(set_groups); -diff --git a/kernel/kthread.c b/kernel/kthread.c -index 290cbc8..eaaa8c6 100644 ---- a/kernel/kthread.c -+++ b/kernel/kthread.c -@@ -30,6 +30,9 @@ - #include <linux/sched/isolation.h> - #include <trace/events/sched.h> - -+#ifdef CONFIG_IEE -+#include <asm/iee-token.h> -+#endif - - static DEFINE_SPINLOCK(kthread_create_lock); - static LIST_HEAD(kthread_create_list); -@@ -1447,6 +1450,9 @@ void kthread_use_mm(struct mm_struct *mm) - tsk->active_mm = mm; - tsk->mm = mm; - membarrier_update_current_mm(mm); -+ #ifdef CONFIG_IEE -+ iee_set_token_pgd(tsk, mm->pgd); -+ #endif - switch_mm_irqs_off(active_mm, mm, tsk); - local_irq_enable(); - task_unlock(tsk); -@@ -1491,6 +1497,9 @@ void kthread_unuse_mm(struct mm_struct *mm) - local_irq_disable(); - tsk->mm = NULL; - membarrier_update_current_mm(NULL); -+ #ifdef CONFIG_IEE -+ iee_set_token_pgd(tsk, NULL); -+ #endif - mmgrab_lazy_tlb(mm); - /* active_mm is still 'mm' */ - enter_lazy_tlb(mm, tsk); -diff --git a/kernel/sys.c b/kernel/sys.c -index 44b5759..31d2c52 100644 ---- a/kernel/sys.c -+++ b/kernel/sys.c -@@ -75,6 +75,10 @@ - #include <asm/io.h> - #include <asm/unistd.h> - -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+ - #include "uid16.h" - - #ifndef SET_UNALIGN_CTL -@@ -395,7 +399,11 @@ long __sys_setregid(gid_t rgid, gid_t egid) - if (gid_eq(old->gid, krgid) || - gid_eq(old->egid, krgid) || - ns_capable_setid(old->user_ns, CAP_SETGID)) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_gid(new, krgid); -+ #else - new->gid = krgid; -+ #endif - else - goto error; - } -@@ -404,15 +412,27 @@ long __sys_setregid(gid_t rgid, gid_t egid) - gid_eq(old->egid, kegid) || - gid_eq(old->sgid, kegid) || - ns_capable_setid(old->user_ns, CAP_SETGID)) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_egid(new, kegid); -+ #else - new->egid = kegid; -+ #endif - else - goto error; - } - - if (rgid != (gid_t) -1 || - (egid != (gid_t) -1 && !gid_eq(kegid, old->gid))) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_sgid(new, new->egid); -+ #else - new->sgid = new->egid; -+ #endif -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsgid(new, new->egid); -+ #else - new->fsgid = new->egid; -+ #endif - - retval = security_task_fix_setgid(new, old, LSM_SETID_RE); - if (retval < 0) -@@ -454,9 +474,25 @@ long __sys_setgid(gid_t gid) - - retval = -EPERM; - if (ns_capable_setid(old->user_ns, CAP_SETGID)) -+ #ifdef CONFIG_CREDP -+ { -+ iee_set_cred_fsgid(new, kgid); -+ iee_set_cred_sgid(new, kgid); -+ iee_set_cred_egid(new, kgid); -+ iee_set_cred_gid(new, kgid); -+ } -+ #else - new->gid = new->egid = new->sgid = new->fsgid = kgid; -+ #endif - else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid)) -+ #ifdef CONFIG_CREDP -+ { -+ iee_set_cred_fsgid(new, kgid); -+ iee_set_cred_egid(new, kgid); -+ } -+ #else - new->egid = new->fsgid = kgid; -+ #endif - else - goto error; - -@@ -488,7 +524,11 @@ static int set_user(struct cred *new) - return -EAGAIN; - - free_uid(new->user); -+ #ifdef CONFIG_CREDP -+ iee_set_cred_user(new, new_user); -+ #else - new->user = new_user; -+ #endif - return 0; - } - -@@ -549,7 +589,11 @@ long __sys_setreuid(uid_t ruid, uid_t euid) - - retval = -EPERM; - if (ruid != (uid_t) -1) { -+ #ifdef CONFIG_CREDP -+ iee_set_cred_uid(new, kruid); -+ #else - new->uid = kruid; -+ #endif - if (!uid_eq(old->uid, kruid) && - !uid_eq(old->euid, kruid) && - !ns_capable_setid(old->user_ns, CAP_SETUID)) -@@ -557,7 +601,11 @@ long __sys_setreuid(uid_t ruid, uid_t euid) - } - - if (euid != (uid_t) -1) { -+ #ifdef CONFIG_CREDP -+ iee_set_cred_euid(new, keuid); -+ #else - new->euid = keuid; -+ #endif - if (!uid_eq(old->uid, keuid) && - !uid_eq(old->euid, keuid) && - !uid_eq(old->suid, keuid) && -@@ -572,8 +620,16 @@ long __sys_setreuid(uid_t ruid, uid_t euid) - } - if (ruid != (uid_t) -1 || - (euid != (uid_t) -1 && !uid_eq(keuid, old->uid))) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_suid(new, new->euid); -+ #else - new->suid = new->euid; -+ #endif -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(new, new->euid); -+ #else - new->fsuid = new->euid; -+ #endif - - retval = security_task_fix_setuid(new, old, LSM_SETID_RE); - if (retval < 0) -@@ -626,7 +682,12 @@ long __sys_setuid(uid_t uid) - - retval = -EPERM; - if (ns_capable_setid(old->user_ns, CAP_SETUID)) { -+ #ifdef CONFIG_CREDP -+ iee_set_cred_uid(new, kuid); -+ iee_set_cred_suid(new, kuid); -+ #else - new->suid = new->uid = kuid; -+ #endif - if (!uid_eq(kuid, old->uid)) { - retval = set_user(new); - if (retval < 0) -@@ -636,7 +697,12 @@ long __sys_setuid(uid_t uid) - goto error; - } - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_euid(new, kuid); -+ iee_set_cred_fsuid(new, kuid); -+ #else - new->fsuid = new->euid = kuid; -+ #endif - - retval = security_task_fix_setuid(new, old, LSM_SETID_ID); - if (retval < 0) -@@ -710,7 +776,11 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) - return -ENOMEM; - - if (ruid != (uid_t) -1) { -+ #ifdef CONFIG_CREDP -+ iee_set_cred_uid(new, kruid); -+ #else - new->uid = kruid; -+ #endif - if (!uid_eq(kruid, old->uid)) { - retval = set_user(new); - if (retval < 0) -@@ -718,10 +788,22 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) - } - } - if (euid != (uid_t) -1) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_euid(new, keuid); -+ #else - new->euid = keuid; -+ #endif - if (suid != (uid_t) -1) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_suid(new, ksuid); -+ #else - new->suid = ksuid; -+ #endif -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(new, new->euid); -+ #else - new->fsuid = new->euid; -+ #endif - - retval = security_task_fix_setuid(new, old, LSM_SETID_RES); - if (retval < 0) -@@ -810,12 +892,28 @@ long __sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) - return -ENOMEM; - - if (rgid != (gid_t) -1) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_gid(new, krgid); -+ #else - new->gid = krgid; -+ #endif - if (egid != (gid_t) -1) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_egid(new, kegid); -+ #else - new->egid = kegid; -+ #endif - if (sgid != (gid_t) -1) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_sgid(new, ksgid); -+ #else - new->sgid = ksgid; -+ #endif -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsgid(new, new->egid); -+ #else - new->fsgid = new->egid; -+ #endif - - retval = security_task_fix_setgid(new, old, LSM_SETID_RES); - if (retval < 0) -@@ -882,7 +980,11 @@ long __sys_setfsuid(uid_t uid) - uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || - ns_capable_setid(old->user_ns, CAP_SETUID)) { - if (!uid_eq(kuid, old->fsuid)) { -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(new, kuid); -+ #else - new->fsuid = kuid; -+ #endif - if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) - goto change_okay; - } -@@ -926,7 +1028,11 @@ long __sys_setfsgid(gid_t gid) - gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) || - ns_capable_setid(old->user_ns, CAP_SETGID)) { - if (!gid_eq(kgid, old->fsgid)) { -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsgid(new, kgid); -+ #else - new->fsgid = kgid; -+ #endif - if (security_task_fix_setgid(new,old,LSM_SETID_FS) == 0) - goto change_okay; - } -diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c -index 981a4ad..737786f 100644 ---- a/kernel/trace/bpf_trace.c -+++ b/kernel/trace/bpf_trace.c -@@ -2221,7 +2221,12 @@ void perf_event_detach_bpf_prog(struct perf_event *event) - rcu_assign_pointer(event->tp_event->prog_array, new_array); - bpf_prog_array_free_sleepable(old_array); - } -- -+ /* -+ * It could be that the bpf_prog is not sleepable (and will be freed -+ * via normal RCU), but is called from a point that supports sleepable -+ * programs and uses tasks-trace-RCU. -+ */ -+ synchronize_rcu_tasks_trace(); - bpf_prog_put(event->prog); - event->prog = NULL; - -diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c -index 2461786..10421c0 100644 ---- a/kernel/trace/trace_events_user.c -+++ b/kernel/trace/trace_events_user.c -@@ -22,6 +22,9 @@ - #include <linux/highmem.h> - #include <linux/init.h> - #include <linux/user_events.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif - #include "trace_dynevent.h" - #include "trace_output.h" - #include "trace.h" -@@ -1449,7 +1452,11 @@ static int user_event_set_call_visible(struct user_event *user, bool visible) - * add/remove calls themselves to tracefs. We need to temporarily - * switch to root file permission to allow for this scenario. - */ -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(cred, GLOBAL_ROOT_UID); -+ #else - cred->fsuid = GLOBAL_ROOT_UID; -+ #endif - - old_cred = override_creds(cred); - -diff --git a/kernel/umh.c b/kernel/umh.c -index 1b13c5d..ff35552 100644 ---- a/kernel/umh.c -+++ b/kernel/umh.c -@@ -32,6 +32,10 @@ - - #include <trace/events/module.h> - -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+ - static kernel_cap_t usermodehelper_bset = CAP_FULL_SET; - static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET; - static DEFINE_SPINLOCK(umh_sysctl_lock); -@@ -91,9 +95,15 @@ static int call_usermodehelper_exec_async(void *data) - goto out; - - spin_lock(&umh_sysctl_lock); -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_bset(new, cap_intersect(usermodehelper_bset, new->cap_bset)); -+ iee_set_cred_cap_inheritable(new, cap_intersect(usermodehelper_inheritable, -+ new->cap_inheritable)); -+ #else - new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset); - new->cap_inheritable = cap_intersect(usermodehelper_inheritable, - new->cap_inheritable); -+ #endif - spin_unlock(&umh_sysctl_lock); - - if (sub_info->init) { -diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c -index 1d8e47b..e4ea936 100644 ---- a/kernel/user_namespace.c -+++ b/kernel/user_namespace.c -@@ -21,6 +21,9 @@ - #include <linux/fs_struct.h> - #include <linux/bsearch.h> - #include <linux/sort.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif - - static struct kmem_cache *user_ns_cachep __read_mostly; - static DEFINE_MUTEX(userns_state_mutex); -@@ -45,6 +48,19 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns) - /* Start with the same capabilities as init but useless for doing - * anything as the capabilities are bound to the new user namespace. - */ -+ #ifdef CONFIG_CREDP -+ iee_set_cred_securebits(cred, SECUREBITS_DEFAULT); -+ iee_set_cred_cap_inheritable(cred, CAP_EMPTY_SET); -+ iee_set_cred_cap_permitted(cred, CAP_FULL_SET); -+ iee_set_cred_cap_effective(cred, CAP_FULL_SET); -+ iee_set_cred_cap_ambient(cred, CAP_EMPTY_SET); -+ iee_set_cred_cap_bset(cred, CAP_FULL_SET); -+#ifdef CONFIG_KEYS -+ key_put(cred->request_key_auth); -+ iee_set_cred_request_key_auth(cred, NULL); -+#endif -+ iee_set_cred_user_ns(cred, user_ns); -+ #else - cred->securebits = SECUREBITS_DEFAULT; - cred->cap_inheritable = CAP_EMPTY_SET; - cred->cap_permitted = CAP_FULL_SET; -@@ -57,6 +73,7 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns) - #endif - /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */ - cred->user_ns = user_ns; -+ #endif - } - - static unsigned long enforced_nproc_rlimit(void) -diff --git a/lib/digsig.c b/lib/digsig.c -index 04b5e55..0a10a45 100644 ---- a/lib/digsig.c -+++ b/lib/digsig.c -@@ -81,7 +81,11 @@ static int digsig_verify_rsa(struct key *key, - const struct user_key_payload *ukp; - struct pubkey_hdr *pkh; - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(key)); -+ #else - down_read(&key->sem); -+ #endif - ukp = user_key_payload_locked(key); - - if (!ukp) { -@@ -176,7 +180,11 @@ static int digsig_verify_rsa(struct key *key, - while (--i >= 0) - mpi_free(pkey[i]); - err1: -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - - return err; - } -diff --git a/mm/Kconfig b/mm/Kconfig -index 170e137..8d2ed40 100644 ---- a/mm/Kconfig -+++ b/mm/Kconfig -@@ -490,6 +490,10 @@ config NUMA_KEEP_MEMINFO - config MEMORY_ISOLATION - bool - -+config PTP -+ depends on IEE -+ def_bool y -+ - # IORESOURCE_SYSTEM_RAM regions in the kernel resource tree that are marked - # IORESOURCE_EXCLUSIVE cannot be mapped to user space, for example, via - # /dev/mem. -diff --git a/mm/debug_vm_pgtable.c b/mm/debug_vm_pgtable.c -index 8a6746d..81f86a9 100644 ---- a/mm/debug_vm_pgtable.c -+++ b/mm/debug_vm_pgtable.c -@@ -438,7 +438,11 @@ static void __init pmd_huge_tests(struct pgtable_debug_args *args) - * X86 defined pmd_set_huge() verifies that the given - * PMD is not a populated non-leaf entry. - */ -+ #ifdef CONFIG_PTP -+ set_pmd(args->pmdp, __pmd(0)); -+ #else - WRITE_ONCE(*args->pmdp, __pmd(0)); -+ #endif - WARN_ON(!pmd_set_huge(args->pmdp, __pfn_to_phys(args->fixed_pmd_pfn), args->page_prot)); - WARN_ON(!pmd_clear_huge(args->pmdp)); - pmd = READ_ONCE(*args->pmdp); -@@ -458,7 +462,11 @@ static void __init pud_huge_tests(struct pgtable_debug_args *args) - * X86 defined pud_set_huge() verifies that the given - * PUD is not a populated non-leaf entry. - */ -+ #ifdef CONFIG_PTP -+ set_pud(args->pudp, __pud(0)); -+ #else - WRITE_ONCE(*args->pudp, __pud(0)); -+ #endif - WARN_ON(!pud_set_huge(args->pudp, __pfn_to_phys(args->fixed_pud_pfn), args->page_prot)); - WARN_ON(!pud_clear_huge(args->pudp)); - pud = READ_ONCE(*args->pudp); -diff --git a/mm/early_ioremap.c b/mm/early_ioremap.c -index ce06b28..a039c7a 100644 ---- a/mm/early_ioremap.c -+++ b/mm/early_ioremap.c -@@ -147,7 +147,11 @@ __early_ioremap(resource_size_t phys_addr, unsigned long size, pgprot_t prot) - if (after_paging_init) - __late_set_fixmap(idx, phys_addr, prot); - else -+ #ifdef CONFIG_PTP -+ __iee_set_fixmap_pre_init(idx, phys_addr, prot); -+ #else - __early_set_fixmap(idx, phys_addr, prot); -+ #endif - phys_addr += PAGE_SIZE; - --idx; - --nrpages; -@@ -199,13 +203,66 @@ void __init early_iounmap(void __iomem *addr, unsigned long size) - if (after_paging_init) - __late_clear_fixmap(idx); - else -+ #ifdef CONFIG_PTP -+ __iee_set_fixmap_pre_init(idx, 0, FIXMAP_PAGE_CLEAR); -+ #else - __early_set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR); -+ #endif - --idx; - --nrpages; - } - prev_map[slot] = NULL; - } - -+#ifdef CONFIG_PTP -+void __init early_iounmap_after_init(void __iomem *addr, unsigned long size) -+{ -+ unsigned long virt_addr; -+ unsigned long offset; -+ unsigned int nrpages; -+ enum fixed_addresses idx; -+ int i, slot; -+ -+ slot = -1; -+ for (i = 0; i < FIX_BTMAPS_SLOTS; i++) { -+ if (prev_map[i] == addr) { -+ slot = i; -+ break; -+ } -+ } -+ -+ if (WARN(slot < 0, "early_iounmap(%p, %08lx) not found slot\n", -+ addr, size)) -+ return; -+ -+ if (WARN(prev_size[slot] != size, -+ "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n", -+ addr, size, slot, prev_size[slot])) -+ return; -+ -+ WARN(early_ioremap_debug, "early_iounmap(%p, %08lx) [%d]\n", -+ addr, size, slot); -+ -+ virt_addr = (unsigned long)addr; -+ if (WARN_ON(virt_addr < fix_to_virt(FIX_BTMAP_BEGIN))) -+ return; -+ -+ offset = offset_in_page(virt_addr); -+ nrpages = PAGE_ALIGN(offset + size) >> PAGE_SHIFT; -+ -+ idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot; -+ while (nrpages > 0) { -+ if (after_paging_init) -+ __late_clear_fixmap(idx); -+ else -+ __early_set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR); -+ --idx; -+ --nrpages; -+ } -+ prev_map[slot] = NULL; -+} -+#endif -+ - /* Remap an IO device */ - void __init __iomem * - early_ioremap(resource_size_t phys_addr, unsigned long size) -diff --git a/mm/huge_memory.c b/mm/huge_memory.c -index 545be8c..8caf8ab 100644 ---- a/mm/huge_memory.c -+++ b/mm/huge_memory.c -@@ -41,6 +41,10 @@ - #include <linux/compat.h> - #include <linux/pgalloc_tag.h> - -+#ifdef CONFIG_PTP -+#include <linux/iee-func.h> -+#endif -+ - #include <asm/tlb.h> - #include <asm/pgalloc.h> - #include "internal.h" -@@ -2365,7 +2369,18 @@ static void __split_huge_zero_page_pmd(struct vm_area_struct *vma, - old_pmd = pmdp_huge_clear_flush(vma, haddr, pmd); - - pgtable = pgtable_trans_huge_withdraw(mm, pmd); -+ #ifdef CONFIG_PTP -+ #ifdef CONFIG_X86_64 -+ unsigned long pfn = page_to_pfn(pgtable); -+ -+ paravirt_alloc_pte(mm, pfn); -+ _pmd = __pmd(((pteval_t)pfn << PAGE_SHIFT) | _PAGE_TABLE); -+ #else -+ _pmd = __pmd(__phys_to_pmd_val(page_to_phys(pgtable)) | PMD_TYPE_TABLE); -+ #endif -+ #else - pmd_populate(mm, &_pmd, pgtable); -+ #endif - - pte = pte_offset_map(&_pmd, haddr); - VM_BUG_ON(!pte); -@@ -2537,7 +2552,18 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd, - * This's critical for some architectures (Power). - */ - pgtable = pgtable_trans_huge_withdraw(mm, pmd); -+ #ifdef CONFIG_PTP -+ #ifdef CONFIG_X86_64 -+ unsigned long pfn = page_to_pfn(pgtable); -+ -+ paravirt_alloc_pte(mm, pfn); -+ _pmd = __pmd(((pteval_t)pfn << PAGE_SHIFT) | _PAGE_TABLE); -+ #else -+ _pmd = __pmd(__phys_to_pmd_val(page_to_phys(pgtable)) | PMD_TYPE_TABLE); -+ #endif -+ #else - pmd_populate(mm, &_pmd, pgtable); -+ #endif - - pte = pte_offset_map(&_pmd, haddr); - VM_BUG_ON(!pte); -diff --git a/mm/kasan/init.c b/mm/kasan/init.c -index 89895f3..ac607c3 100644 ---- a/mm/kasan/init.c -+++ b/mm/kasan/init.c -@@ -106,6 +106,10 @@ static void __ref zero_pte_populate(pmd_t *pmd, unsigned long addr, - } - } - -+void __weak __meminit kernel_pte_init(void *addr) -+{ -+} -+ - static int __ref zero_pmd_populate(pud_t *pud, unsigned long addr, - unsigned long end) - { -@@ -126,8 +130,10 @@ static int __ref zero_pmd_populate(pud_t *pud, unsigned long addr, - - if (slab_is_available()) - p = pte_alloc_one_kernel(&init_mm); -- else -+ else { - p = early_alloc(PAGE_SIZE, NUMA_NO_NODE); -+ kernel_pte_init(p); -+ } - if (!p) - return -ENOMEM; - -diff --git a/mm/secretmem.c b/mm/secretmem.c -index 3afb5ad..3995528 100644 ---- a/mm/secretmem.c -+++ b/mm/secretmem.c -@@ -238,7 +238,7 @@ SYSCALL_DEFINE1(memfd_secret, unsigned int, flags) - /* make sure local flags do not confict with global fcntl.h */ - BUILD_BUG_ON(SECRETMEM_FLAGS_MASK & O_CLOEXEC); - -- if (!secretmem_enable) -+ if (!secretmem_enable || !can_set_direct_map()) - return -ENOSYS; - - if (flags & ~(SECRETMEM_FLAGS_MASK | O_CLOEXEC)) -@@ -280,7 +280,7 @@ static struct file_system_type secretmem_fs = { - - static int __init secretmem_init(void) - { -- if (!secretmem_enable) -+ if (!secretmem_enable || !can_set_direct_map()) - return 0; - - secretmem_mnt = kern_mount(&secretmem_fs); -diff --git a/mm/slab.h b/mm/slab.h -index 1343bfa..4426ea4 100644 ---- a/mm/slab.h -+++ b/mm/slab.h -@@ -36,6 +36,25 @@ typedef u64 freelist_full_t; - #undef system_has_freelist_aba - #endif - -+#ifdef CONFIG_IEE -+extern struct kmem_cache *iee_stack_jar; -+extern struct kmem_cache *task_struct_cachep; -+extern void *fixup_red_left(struct kmem_cache *s, void *p); -+extern int iee_get_oo_objects(struct kmem_cache *s); -+#endif -+#ifdef CONFIG_IEE_SELINUX_P -+extern struct kmem_cache *policy_jar; -+#endif -+#ifdef CONFIG_CREDP -+extern struct kmem_cache *cred_jar; -+#endif -+#ifdef CONFIG_KEYP -+extern struct kmem_cache *key_jar; -+extern struct kmem_cache *key_union_jar; -+extern struct kmem_cache *key_struct_jar; -+extern struct kmem_cache *key_payload_jar; -+#endif -+ - /* - * Freelist pointer and counter to cmpxchg together, avoids the typical ABA - * problems with cmpxchg of just a pointer. -@@ -624,6 +643,10 @@ static inline void cache_random_seq_destroy(struct kmem_cache *cachep) { } - - static inline bool slab_want_init_on_alloc(gfp_t flags, struct kmem_cache *c) - { -+ #ifdef CONFIG_IEE -+ if (c == iee_stack_jar) -+ return false; -+ #endif - if (static_branch_maybe(CONFIG_INIT_ON_ALLOC_DEFAULT_ON, - &init_on_alloc)) { - if (c->ctor) -diff --git a/mm/slab_common.c b/mm/slab_common.c -index a970f5a..42ce45b 100644 ---- a/mm/slab_common.c -+++ b/mm/slab_common.c -@@ -144,6 +144,21 @@ int slab_unmergeable(struct kmem_cache *s) - if (s->ctor) - return 1; - -+ #ifdef CONFIG_IEE -+ if (strcmp(s->name, "iee_stack_jar") == 0) -+ return 1; -+ #endif -+ -+ #ifdef CONFIG_IEE_SELINUX_P -+ if (strcmp(s->name, "policy_jar") == 0) -+ return 1; -+ #endif -+ -+ #ifdef CONFIG_KEYP -+ if ((strcmp(s->name, "key_jar") == 0) || (strcmp(s->name, "key_payload_jar") == 0)) -+ return 1; -+ #endif -+ - #ifdef CONFIG_HARDENED_USERCOPY - if (s->usersize) - return 1; -@@ -169,6 +184,21 @@ struct kmem_cache *find_mergeable(unsigned int size, unsigned int align, - if (ctor) - return NULL; - -+ #ifdef CONFIG_IEE -+ if (strcmp(name, "iee_stack_jar") == 0) -+ return NULL; -+ #endif -+ -+ #ifdef CONFIG_IEE_SELINUX_P -+ if (strcmp(name, "policy_jar") == 0) -+ return NULL; -+ #endif -+ -+ #ifdef CONFIG_KEYP -+ if ((strcmp(name, "key_jar") == 0) || (strcmp(name, "key_payload_jar") == 0)) -+ return NULL; -+ #endif -+ - size = ALIGN(size, sizeof(void *)); - align = calculate_alignment(flags, align, size); - size = ALIGN(size, align); -diff --git a/mm/slub.c b/mm/slub.c -index c8da52b..cf7dbce 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -48,6 +48,14 @@ - - #include "internal.h" - -+#ifdef CONFIG_IEE -+#include <asm/stack-slab.h> -+#include <asm/iee-token.h> -+#include <linux/iee-func.h> -+#include <linux/io.h> -+#include <asm/iee-access.h> -+#endif -+ - /* - * Lock order: - * 1. slab_mutex (Global Mutex) -@@ -509,7 +517,14 @@ static inline void *get_freepointer(struct kmem_cache *s, void *object) - - object = kasan_reset_tag(object); - ptr_addr = (unsigned long)object + s->offset; -+ #ifdef CONFIG_IEE -+ if (s == iee_stack_jar) -+ p.v = (unsigned long)iee_read_freeptr(ptr_addr); -+ else -+ p = *(freeptr_t *)(ptr_addr); -+ #else - p = *(freeptr_t *)(ptr_addr); -+ #endif - return freelist_ptr_decode(s, p, ptr_addr); - } - -@@ -554,6 +569,31 @@ static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp) - #endif - - freeptr_addr = (unsigned long)kasan_reset_tag((void *)freeptr_addr); -+ #ifdef CONFIG_IEE -+ if (s == iee_stack_jar) { -+ iee_set_freeptr((void **)freeptr_addr, (void *)freelist_ptr_encode(s, fp, freeptr_addr).v); -+ return; -+ } -+ #endif -+ #ifdef CONFIG_IEE_SELINUX_P -+ if (s == policy_jar) { -+ iee_set_freeptr((void **)freeptr_addr, (void *)freelist_ptr_encode(s, fp, freeptr_addr).v); -+ return; -+ } -+ #endif -+ #ifdef CONFIG_CREDP -+ if (s == cred_jar) { -+ iee_set_freeptr((void **)freeptr_addr, (void *)freelist_ptr_encode(s, fp, freeptr_addr).v); -+ return; -+ } -+ #endif -+ #ifdef CONFIG_KEYP -+ if (s == key_jar) { -+ iee_set_freeptr((void **)freeptr_addr, (void *)freelist_ptr_encode(s, fp, freeptr_addr).v); -+ return; -+ } -+ #endif -+ - *(freeptr_t *)freeptr_addr = freelist_ptr_encode(s, fp, freeptr_addr); - } - -@@ -608,6 +648,13 @@ static inline unsigned int oo_objects(struct kmem_cache_order_objects x) - return x.x & OO_MASK; - } - -+#ifdef CONFIG_IEE -+int iee_get_oo_objects(struct kmem_cache *s) -+{ -+ return oo_objects(s->oo); -+} -+#endif -+ - #ifdef CONFIG_SLUB_CPU_PARTIAL - static void slub_set_cpu_partial(struct kmem_cache *s, unsigned int nr_objects) - { -@@ -894,6 +941,29 @@ static void set_track_update(struct kmem_cache *s, void *object, - { - struct track *p = get_track(s, object, alloc); - -+ #ifdef CONFIG_CREDP -+ struct track tmp; -+ -+ if (s == cred_jar) { -+ tmp = *p; -+ #ifdef CONFIG_STACKDEPOT -+ tmp.handle = handle; -+ #endif -+ tmp.addr = addr; -+ tmp.cpu = smp_processor_id(); -+ tmp.pid = current->pid; -+ tmp.when = jiffies; -+ iee_memcpy(p, &tmp, sizeof(struct track)); -+ } else { -+ #ifdef CONFIG_STACKDEPOT -+ p->handle = handle; -+ #endif -+ p->addr = addr; -+ p->cpu = smp_processor_id(); -+ p->pid = current->pid; -+ p->when = jiffies; -+ } -+ #else - #ifdef CONFIG_STACKDEPOT - p->handle = handle; - #endif -@@ -901,6 +971,7 @@ static void set_track_update(struct kmem_cache *s, void *object, - p->cpu = smp_processor_id(); - p->pid = current->pid; - p->when = jiffies; -+ #endif - } - - static __always_inline void set_track(struct kmem_cache *s, void *object, -@@ -919,7 +990,14 @@ static void init_tracking(struct kmem_cache *s, void *object) - return; - - p = get_track(s, object, TRACK_ALLOC); -+ #ifdef CONFIG_CREDP -+ if (s == cred_jar) -+ iee_memset(p, 0, 2*sizeof(struct track)); -+ else -+ memset(p, 0, 2*sizeof(struct track)); -+ #else - memset(p, 0, 2*sizeof(struct track)); -+ #endif - } - - static void print_track(const char *s, struct track *t, unsigned long pr_time) -@@ -1129,7 +1207,14 @@ static void init_object(struct kmem_cache *s, void *object, u8 val) - unsigned int poison_size = s->object_size; - - if (s->flags & SLAB_RED_ZONE) { -+ #ifdef CONFIG_CREDP -+ if (s == cred_jar) -+ iee_memset(p - s->red_left_pad, val, s->red_left_pad); -+ else -+ memset(p - s->red_left_pad, val, s->red_left_pad); -+ #else - memset(p - s->red_left_pad, val, s->red_left_pad); -+ #endif - - if (slub_debug_orig_size(s) && val == SLUB_RED_ACTIVE) { - /* -@@ -1142,12 +1227,31 @@ static void init_object(struct kmem_cache *s, void *object, u8 val) - } - - if (s->flags & __OBJECT_POISON) { -+ #ifdef CONFIG_CREDP -+ if (s == cred_jar) { -+ iee_memset(p, POISON_FREE, poison_size - 1); -+ iee_memset(&p[poison_size - 1], POISON_END, 1); -+ } else { -+ memset(p, POISON_FREE, poison_size - 1); -+ p[poison_size - 1] = POISON_END; -+ } -+ #else - memset(p, POISON_FREE, poison_size - 1); - p[poison_size - 1] = POISON_END; -+ #endif - } - - if (s->flags & SLAB_RED_ZONE) -+ #ifdef CONFIG_CREDP -+ { -+ if (s == cred_jar) -+ iee_memset(p + poison_size, val, s->inuse - poison_size); -+ else -+ memset(p + poison_size, val, s->inuse - poison_size); -+ } -+ #else - memset(p + poison_size, val, s->inuse - poison_size); -+ #endif - } - - static void restore_bytes(struct kmem_cache *s, char *message, u8 data, -@@ -1509,7 +1613,14 @@ void setup_slab_debug(struct kmem_cache *s, struct slab *slab, void *addr) - return; - - metadata_access_enable(); -+ #ifdef CONFIG_CREDP -+ if (s == cred_jar) -+ iee_memset(kasan_reset_tag(addr), POISON_INUSE, slab_size(slab)); -+ else -+ memset(kasan_reset_tag(addr), POISON_INUSE, slab_size(slab)); -+ #else - memset(kasan_reset_tag(addr), POISON_INUSE, slab_size(slab)); -+ #endif - metadata_access_disable(); - } - -@@ -2467,6 +2578,20 @@ static bool shuffle_freelist(struct kmem_cache *s, struct slab *slab) - cur = setup_object(s, cur); - slab->freelist = cur; - -+ #ifdef CONFIG_IEE -+ if (s == task_struct_cachep) { -+ void *pstack; -+ void *obj; -+ -+ for (int i = 0; i < freelist_count; i++) { -+ pstack = get_iee_stack(); -+ obj = start + s->random_seq[i]; -+ iee_init_token((struct task_struct *)obj, -+ pstack + PAGE_SIZE * 4, (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 0)); -+ } -+ } -+ #endif -+ - for (idx = 1; idx < slab->objects; idx++) { - next = next_freelist_entry(s, &pos, start, page_limit, - freelist_count); -@@ -2531,6 +2656,16 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) - if ((alloc_gfp & __GFP_DIRECT_RECLAIM) && oo_order(oo) > oo_order(s->min)) - alloc_gfp = (alloc_gfp | __GFP_NOMEMALLOC) & ~__GFP_RECLAIM; - -+ #ifdef CONFIG_IEE_SELINUX_P -+ if (s == policy_jar) -+ alloc_gfp |= __GFP_ZERO; -+ #endif -+ -+ #ifdef CONFIG_KEYP -+ if (s == key_jar) -+ alloc_gfp |= __GFP_ZERO; -+ #endif -+ - slab = alloc_slab_page(alloc_gfp, node, oo); - if (unlikely(!slab)) { - oo = s->min; -@@ -2539,6 +2674,14 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) - * Allocation may have failed due to fragmentation. - * Try a lower order alloc if possible - */ -+ #ifdef CONFIG_IEE_SELINUX_P -+ if (s == policy_jar) -+ alloc_gfp |= __GFP_ZERO; -+ #endif -+ #ifdef CONFIG_KEYP -+ if (s == key_jar) -+ alloc_gfp |= __GFP_ZERO; -+ #endif - slab = alloc_slab_page(alloc_gfp, node, oo); - if (unlikely(!slab)) - return NULL; -@@ -2549,6 +2692,33 @@ static struct slab *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) - slab->inuse = 0; - slab->frozen = 0; - -+ #ifdef CONFIG_IEE -+ unsigned int order = oo_order(oo); -+ // If the page belongs to a task_struct, alloc token for it and set iee&lm va. -+ if (s == task_struct_cachep) { -+ void *token_addr = (void *)__phys_to_iee(page_to_phys(folio_page(slab_folio(slab), 0))); -+ void *alloc_token = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order); -+ -+ iee_set_token_page_valid(token_addr, alloc_token, order); -+ } -+ if (s == iee_stack_jar) -+ set_iee_stack_page((unsigned long)page_address(folio_page(slab_folio(slab), 0)), order); -+ #endif -+ #ifdef CONFIG_CREDP -+ if (s == cred_jar) -+ set_iee_page((unsigned long)page_address(folio_page(slab_folio(slab), 0)), order); -+ #endif -+ -+ #ifdef CONFIG_KEYP -+ if (s == key_jar) -+ set_iee_page((unsigned long)page_address(folio_page(slab_folio(slab), 0)), order); -+ #endif -+ -+ #ifdef CONFIG_IEE_SELINUX_P -+ if (s == policy_jar) -+ set_iee_page((unsigned long)page_address(folio_page(slab_folio(slab), 0)), order); -+ #endif -+ - account_slab(slab, oo_order(oo), s, flags); - - slab->slab_cache = s; -@@ -2601,6 +2771,40 @@ static void __free_slab(struct kmem_cache *s, struct slab *slab) - __folio_clear_slab(folio); - mm_account_reclaimed_pages(pages); - unaccount_slab(slab, order, s); -+ -+ #ifdef CONFIG_IEE -+ // If the page containing this token is empty, free it and restore iee&lm va. -+ if (s == task_struct_cachep) { -+ #ifdef CONFIG_X86_64 -+ iee_free_slab(s, slab, iee_free_task_struct_slab); -+ return; -+ #else -+ iee_free_slab(s, slab, NULL); -+ #endif -+ } -+ if (s == iee_stack_jar) -+ unset_iee_stack_page((unsigned long)page_address(folio_page(slab_folio(slab), 0)), order); -+ #endif -+ #ifdef CONFIG_CREDP -+ if (s == cred_jar) { -+ #ifdef CONFIG_X86_64 -+ iee_free_slab(s, slab, iee_free_cred_slab); -+ return; -+ #else -+ unset_iee_page((unsigned long)page_address(folio_page(folio, 0)), order); -+ #endif -+ } -+ #endif -+ #ifdef CONFIG_KEYP -+ if (s == key_jar) -+ unset_iee_page((unsigned long)page_address(folio_page(slab_folio(slab), 0)), order); -+ #endif -+ -+ #ifdef CONFIG_IEE_SELINUX_P -+ if (s == policy_jar) -+ unset_iee_page((unsigned long)page_address(folio_page(slab_folio(slab), 0)), order); -+ #endif -+ - __free_pages(&folio->page, order); - } - -@@ -4076,6 +4280,27 @@ void slab_post_alloc_hook(struct kmem_cache *s, struct obj_cgroup *objcg, - memcg_slab_post_alloc_hook(s, objcg, flags, size, p); - } - -+#ifdef CONFIG_IEE -+static bool is_iee_kmem_cache(struct kmem_cache *s) -+{ -+ if (s == iee_stack_jar) -+ return true; -+#ifdef CONFIG_IEE_SELINUX_P -+ else if (s == policy_jar) -+ return true; -+#endif -+#ifdef CONFIG_CREDP -+ else if (s == cred_jar) -+ return true; -+#endif -+#ifdef CONFIG_KEYP -+ else if (s == key_jar || s == key_payload_jar) -+ return true; -+#endif -+ return false; -+} -+#endif // CONFIG_IEE -+ - /* - * Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc) - * have the fastpath folded into their functions. So no function call -@@ -4097,10 +4322,19 @@ static __fastpath_inline void *slab_alloc_node(struct kmem_cache *s, struct list - if (unlikely(!s)) - return NULL; - -+#ifdef CONFIG_IEE -+ /* Skip kfence_alloc for iee kmem caches. */ -+ if (is_iee_kmem_cache(s)) -+ goto slab_alloc; -+#endif -+ - object = kfence_alloc(s, orig_size, gfpflags); - if (unlikely(object)) - goto out; - -+#ifdef CONFIG_IEE -+slab_alloc: -+#endif - object = __slab_alloc_node(s, gfpflags, node, addr, orig_size); - - maybe_wipe_obj_freeptr(s, object); -@@ -4799,13 +5033,20 @@ int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - local_lock_irqsave(&s->cpu_slab->lock, irqflags); - - for (i = 0; i < size; i++) { -+ #ifdef CONFIG_IEE -+ /* Skip kfence_alloc for iee kmem caches. */ -+ if (is_iee_kmem_cache(s)) -+ goto slab_alloc; -+ #endif - void *object = kfence_alloc(s, s->object_size, flags); - - if (unlikely(object)) { - p[i] = object; - continue; - } -- -+#ifdef CONFIG_IEE -+slab_alloc: -+#endif - object = c->freelist; - if (unlikely(!object)) { - /* -@@ -5327,6 +5568,25 @@ static int calculate_sizes(struct kmem_cache *s) - s->reciprocal_size = reciprocal_value(size); - order = calculate_order(size); - -+ #ifdef CONFIG_IEE -+ if (strcmp(s->name, "task_struct") == 0) -+ order = HUGE_PMD_ORDER; -+ if (strcmp(s->name, "iee_stack_jar") == 0) -+ order = HUGE_PMD_ORDER; -+ #endif -+ #ifdef CONFIG_IEE_SELINUX_P -+ if (strcmp(s->name, "policy_jar") == 0) -+ order = HUGE_PMD_ORDER; -+ #endif -+ #ifdef CONFIG_CREDP -+ if (strcmp(s->name, "cred_jar") == 0) -+ order = HUGE_PMD_ORDER; -+ #endif -+ #ifdef CONFIG_KEYP -+ if (strcmp(s->name, "key_jar") == 0) -+ order = HUGE_PMD_ORDER; -+ #endif -+ - if ((int)order < 0) - return 0; - -@@ -5388,6 +5648,17 @@ static int kmem_cache_open(struct kmem_cache *s, slab_flags_t flags) - s->min_partial = min_t(unsigned long, MAX_PARTIAL, ilog2(s->size) / 2); - s->min_partial = max_t(unsigned long, MIN_PARTIAL, s->min_partial); - -+ #ifdef CONFIG_IEE -+ if (strcmp(s->name, "task_struct") == 0) -+ s->min_partial *= (1 << TASK_ORDER); -+ if (strcmp(s->name, "iee_stack_jar") == 0) -+ s->min_partial *= (1 << TASK_ORDER); -+ #endif -+ #ifdef CONFIG_KEYP -+ if (strcmp(s->name, "key_jar") == 0) -+ s->min_partial = (1 << TASK_ORDER); -+ #endif -+ - set_cpu_partial(s); - - #ifdef CONFIG_NUMA -diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c -index a2cbe44..2628fc0 100644 ---- a/mm/sparse-vmemmap.c -+++ b/mm/sparse-vmemmap.c -@@ -184,6 +184,10 @@ static void * __meminit vmemmap_alloc_block_zero(unsigned long size, int node) - return p; - } - -+void __weak __meminit kernel_pte_init(void *addr) -+{ -+} -+ - pmd_t * __meminit vmemmap_pmd_populate(pud_t *pud, unsigned long addr, int node) - { - pmd_t *pmd = pmd_offset(pud, addr); -@@ -191,6 +195,7 @@ pmd_t * __meminit vmemmap_pmd_populate(pud_t *pud, unsigned long addr, int node) - void *p = vmemmap_alloc_block_zero(PAGE_SIZE, node); - if (!p) - return NULL; -+ kernel_pte_init(p); - pmd_populate_kernel(&init_mm, pmd, p); - } - return pmd; -diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c -index 727f040..f1a96fe 100644 ---- a/net/bluetooth/hci_event.c -+++ b/net/bluetooth/hci_event.c -@@ -5337,19 +5337,16 @@ static void hci_user_confirm_request_evt(struct hci_dev *hdev, void *data, - goto unlock; - } - -- /* If no side requires MITM protection; auto-accept */ -+ /* If no side requires MITM protection; use JUST_CFM method */ - if ((!loc_mitm || conn->remote_cap == HCI_IO_NO_INPUT_OUTPUT) && - (!rem_mitm || conn->io_capability == HCI_IO_NO_INPUT_OUTPUT)) { - -- /* If we're not the initiators request authorization to -- * proceed from user space (mgmt_user_confirm with -- * confirm_hint set to 1). The exception is if neither -- * side had MITM or if the local IO capability is -- * NoInputNoOutput, in which case we do auto-accept -- */ -+ /* If we're not the initiator of request authorization and the -+ * local IO capability is not NoInputNoOutput, use JUST_WORKS -+ * method (mgmt_user_confirm with confirm_hint set to 1). -+ */ - if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && -- conn->io_capability != HCI_IO_NO_INPUT_OUTPUT && -- (loc_mitm || rem_mitm)) { -+ conn->io_capability != HCI_IO_NO_INPUT_OUTPUT) { - bt_dev_dbg(hdev, "Confirming auto-accept as acceptor"); - confirm_hint = 1; - goto confirm; -diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c -index 4c64415..2483f38 100644 ---- a/net/ceph/ceph_common.c -+++ b/net/ceph/ceph_common.c -@@ -385,7 +385,11 @@ static int get_secret(struct ceph_crypto_key *dst, const char *name, - goto out; - } - -+ #ifdef CONFIG_KEYP -+ ckey = ((union key_payload *)(ukey->name_link.next))->data[0]; -+ #else - ckey = ukey->payload.data[0]; -+ #endif - err = ceph_crypto_key_clone(dst, ckey); - if (err) - goto out_key; -diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c -index 051d22c..cd5839e 100644 ---- a/net/ceph/crypto.c -+++ b/net/ceph/crypto.c -@@ -336,7 +336,11 @@ static void ceph_key_free_preparse(struct key_preparsed_payload *prep) - - static void ceph_key_destroy(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ struct ceph_crypto_key *ckey = ((union key_payload *)(key->name_link.next))->data[0]; -+ #else - struct ceph_crypto_key *ckey = key->payload.data[0]; -+ #endif - - ceph_crypto_key_destroy(ckey); - kfree(ckey); -diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c -index c42ddd8..b47607c 100644 ---- a/net/dns_resolver/dns_key.c -+++ b/net/dns_resolver/dns_key.c -@@ -32,6 +32,12 @@ - #include <linux/dns_resolver.h> - #include <keys/dns_resolver-type.h> - #include <keys/user-type.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif - #include "internal.h" - - MODULE_DESCRIPTION("DNS Resolver"); -@@ -295,7 +301,11 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m) - { - seq_puts(m, key->description); - if (key_is_positive(key)) { -+ #ifdef CONFIG_KEYP -+ int err = PTR_ERR(((union key_payload *)(key->name_link.next))->data[dns_key_error]); -+ #else - int err = PTR_ERR(key->payload.data[dns_key_error]); -+ #endif - - if (err) - seq_printf(m, ": %d", err); -@@ -311,7 +321,11 @@ static void dns_resolver_describe(const struct key *key, struct seq_file *m) - static long dns_resolver_read(const struct key *key, - char *buffer, size_t buflen) - { -+ #ifdef CONFIG_KEYP -+ int err = PTR_ERR(((union key_payload *)(key->name_link.next))->data[dns_key_error]); -+ #else - int err = PTR_ERR(key->payload.data[dns_key_error]); -+ #endif - - if (err) - return err; -@@ -364,9 +378,18 @@ static int __init init_dns_resolver(void) - - /* instruct request_key() to use this special keyring as a cache for - * the results it looks up */ -+ #ifdef CONFIG_KEYP -+ iee_set_key_flag_bit(keyring, KEY_FLAG_ROOT_CAN_CLEAR, SET_BIT_OP); -+ #else - set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); -+ #endif -+ #ifdef CONFIG_CREDP -+ iee_set_cred_thread_keyring(cred, keyring); -+ iee_set_cred_jit_keyring(cred, KEY_REQKEY_DEFL_THREAD_KEYRING); -+ #else - cred->thread_keyring = keyring; - cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; -+ #endif - dns_resolver_cache = cred; - - kdebug("DNS resolver keyring: %d\n", key_serial(keyring)); -diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c -index 82b084c..34dc9c7 100644 ---- a/net/dns_resolver/dns_query.c -+++ b/net/dns_resolver/dns_query.c -@@ -45,6 +45,10 @@ - #include <keys/dns_resolver-type.h> - #include <keys/user-type.h> - -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif -+ - #include "internal.h" - - /** -@@ -133,16 +137,26 @@ int dns_query(struct net *net, - goto out; - } - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(rkey)); -+ iee_set_key_flag_bit(rkey, KEY_FLAG_ROOT_CAN_INVAL, SET_BIT_OP); -+ iee_set_key_perm(rkey, rkey->perm | KEY_USR_VIEW); -+ #else - down_read(&rkey->sem); - set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags); - rkey->perm |= KEY_USR_VIEW; -+ #endif - - ret = key_validate(rkey); - if (ret < 0) - goto put; - - /* If the DNS server gave an error, return that to the caller */ -+ #ifdef CONFIG_KEYP -+ ret = PTR_ERR(((union key_payload *)(rkey->name_link.next))->data[dns_key_error]); -+ #else - ret = PTR_ERR(rkey->payload.data[dns_key_error]); -+ #endif - if (ret) - goto put; - -@@ -161,7 +175,11 @@ int dns_query(struct net *net, - - ret = len; - put: -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(rkey)); -+ #else - up_read(&rkey->sem); -+ #endif - if (invalidate) - key_invalidate(rkey); - key_put(rkey); -diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c -index e4fa00a..5988b9b 100644 ---- a/net/netfilter/ipset/ip_set_bitmap_ip.c -+++ b/net/netfilter/ipset/ip_set_bitmap_ip.c -@@ -163,11 +163,8 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], - ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); - if (ret) - return ret; -- if (ip > ip_to) { -+ if (ip > ip_to) - swap(ip, ip_to); -- if (ip < map->first_ip) -- return -IPSET_ERR_BITMAP_RANGE; -- } - } else if (tb[IPSET_ATTR_CIDR]) { - u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); - -@@ -178,7 +175,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], - ip_to = ip; - } - -- if (ip_to > map->last_ip) -+ if (ip < map->first_ip || ip_to > map->last_ip) - return -IPSET_ERR_BITMAP_RANGE; - - for (; !before(ip_to, ip); ip += map->hosts) { -diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c -index fa8aec7..5c2d5ff 100644 ---- a/net/rxrpc/af_rxrpc.c -+++ b/net/rxrpc/af_rxrpc.c -@@ -307,7 +307,11 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock, - - if (!key) - key = rx->key; -+ #ifdef CONFIG_KEYP -+ if (key && !((union key_payload *)key->name_link.next)->data[0]) -+ #else - if (key && !key->payload.data[0]) -+ #endif - key = NULL; /* a no-security key */ - - memset(&p, 0, sizeof(p)); -diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c -index 598b4ee..d703613 100644 ---- a/net/rxrpc/conn_event.c -+++ b/net/rxrpc/conn_event.c -@@ -247,8 +247,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn, - if (ret < 0) - return ret; - -+ #ifdef CONFIG_KEYP -+ ret = conn->security->init_connection_security(conn, -+ ((union key_payload *)(conn->key->name_link.next))->data[0]); -+ #else - ret = conn->security->init_connection_security( - conn, conn->key->payload.data[0]); -+ #endif - if (ret < 0) - return ret; - -diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c -index 33e8302..c4b7557 100644 ---- a/net/rxrpc/key.c -+++ b/net/rxrpc/key.c -@@ -413,7 +413,11 @@ static void rxrpc_free_preparse(struct key_preparsed_payload *prep) - */ - static void rxrpc_destroy(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ rxrpc_free_token_list(((union key_payload *)(key->name_link.next))->data[0]); -+ #else - rxrpc_free_token_list(key->payload.data[0]); -+ #endif - } - - /* -@@ -426,7 +430,11 @@ static void rxrpc_describe(const struct key *key, struct seq_file *m) - - seq_puts(m, key->description); - -+ #ifdef CONFIG_KEYP -+ for (token = ((union key_payload *)(key->name_link.next))->data[0]; token; token = token->next) { -+ #else - for (token = key->payload.data[0]; token; token = token->next) { -+ #endif - seq_puts(m, sep); - - switch (token->security_index) { -@@ -584,7 +592,11 @@ static long rxrpc_read(const struct key *key, - size += 1 * 4; /* token count */ - - ntoks = 0; -+ #ifdef CONFIG_KEYP -+ for (token = ((union key_payload *)(key->name_link.next))->data[0]; token; token = token->next) { -+ #else - for (token = key->payload.data[0]; token; token = token->next) { -+ #endif - toksize = 4; /* sec index */ - - switch (token->security_index) { -@@ -654,7 +666,11 @@ static long rxrpc_read(const struct key *key, - ENCODE(ntoks); - - tok = 0; -+ #ifdef CONFIG_KEYP -+ for (token = ((union key_payload *)(key->name_link.next))->data[0]; token; token = token->next) { -+ #else - for (token = key->payload.data[0]; token; token = token->next) { -+ #endif - toksize = toksizes[tok++]; - ENCODE(toksize); - oldxdr = xdr; -diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c -index ad6c57a..37741c3 100644 ---- a/net/rxrpc/rxkad.c -+++ b/net/rxrpc/rxkad.c -@@ -19,6 +19,9 @@ - #include <net/sock.h> - #include <net/af_rxrpc.h> - #include <keys/rxrpc-type.h> -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif - #include "ar-internal.h" - - #define RXKAD_VERSION 2 -@@ -88,10 +91,19 @@ static void rxkad_free_preparse_server_key(struct key_preparsed_payload *prep) - - static void rxkad_destroy_server_key(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ if (((union key_payload *)key->name_link.next)->data[0]) { -+ crypto_free_skcipher(((union key_payload *)(key->name_link.next))->data[0]); -+ union key_payload *key_payload = (union key_payload *)(key->name_link.next); -+ -+ key_payload->data[0] = NULL; -+ } -+ #else - if (key->payload.data[0]) { - crypto_free_skcipher(key->payload.data[0]); - key->payload.data[0] = NULL; - } -+ #endif - } - - /* -@@ -205,7 +217,11 @@ static int rxkad_prime_packet_security(struct rxrpc_connection *conn, - return -ENOMEM; - } - -+ #ifdef CONFIG_KEYP -+ token = ((union key_payload *)(conn->key->name_link.next))->data[0]; -+ #else - token = conn->key->payload.data[0]; -+ #endif - memcpy(&iv, token->kad->session_key, sizeof(iv)); - - tmpbuf[0] = htonl(conn->proto.epoch); -@@ -317,7 +333,11 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call, - } - - /* encrypt from the session key */ -+ #ifdef CONFIG_KEYP -+ token = ((union key_payload *)(call->conn->key->name_link.next))->data[0]; -+ #else - token = call->conn->key->payload.data[0]; -+ #endif - memcpy(&iv, token->kad->session_key, sizeof(iv)); - - sg_init_one(&sg, txb->data, txb->len); -@@ -507,7 +527,11 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb, - } - - /* decrypt from the session key */ -+ #ifdef CONFIG_KEYP -+ token = ((union key_payload *)(call->conn->key->name_link.next))->data[0]; -+ #else - token = call->conn->key->payload.data[0]; -+ #endif - memcpy(&iv, token->kad->session_key, sizeof(iv)); - - skcipher_request_set_sync_tfm(req, call->conn->rxkad.cipher); -@@ -824,7 +848,11 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn, - return rxrpc_abort_conn(conn, skb, RXKADLEVELFAIL, -EACCES, - rxkad_abort_chall_level); - -+ #ifdef CONFIG_KEYP -+ token = ((union key_payload *)(conn->key->name_link.next))->data[0]; -+ #else - token = conn->key->payload.data[0]; -+ #endif - - /* build the response packet */ - resp = kzalloc(sizeof(struct rxkad_response), GFP_NOFS); -@@ -876,12 +904,24 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn, - - *_expiry = 0; - -+ #ifdef CONFIG_KEYP -+ ASSERT(((union key_payload *)(server_key->name_link.next))->data[0]); -+ #else - ASSERT(server_key->payload.data[0] != NULL); -+ #endif - ASSERTCMP((unsigned long) ticket & 7UL, ==, 0); - -+ #ifdef CONFIG_KEYP -+ memcpy(&iv, &((union key_payload *)(server_key->name_link.next))->data[2], sizeof(iv)); -+ #else - memcpy(&iv, &server_key->payload.data[2], sizeof(iv)); -+ #endif - -+ #ifdef CONFIG_KEYP -+ req = skcipher_request_alloc(((union key_payload *)(server_key->name_link.next))->data[0], GFP_NOFS); -+ #else - req = skcipher_request_alloc(server_key->payload.data[0], GFP_NOFS); -+ #endif - if (!req) - return -ENOMEM; - -diff --git a/net/rxrpc/security.c b/net/rxrpc/security.c -index cb8dd1d..6bffe99 100644 ---- a/net/rxrpc/security.c -+++ b/net/rxrpc/security.c -@@ -79,7 +79,11 @@ int rxrpc_init_client_call_security(struct rxrpc_call *call) - if (ret < 0) - return ret; - -+ #ifdef CONFIG_KEYP -+ for (token = ((union key_payload *)(key->name_link.next))->data[0]; token; token = token->next) { -+ #else - for (token = key->payload.data[0]; token; token = token->next) { -+ #endif - sec = rxrpc_security_lookup(token->security_index); - if (sec) - goto found; -@@ -103,7 +107,11 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn) - - _enter("{%d},{%x}", conn->debug_id, key_serial(key)); - -+ #ifdef CONFIG_KEYP -+ for (token = ((union key_payload *)(key->name_link.next))->data[0]; token; token = token->next) { -+ #else - for (token = key->payload.data[0]; token; token = token->next) { -+ #endif - if (token->security_index == conn->security->security_index) - goto found; - } -diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c -index 8e0b947..b86934a 100644 ---- a/net/rxrpc/sendmsg.c -+++ b/net/rxrpc/sendmsg.c -@@ -585,7 +585,11 @@ rxrpc_new_client_call_for_sendmsg(struct rxrpc_sock *rx, struct msghdr *msg, - } - - key = rx->key; -+ #ifdef CONFIG_KEYP -+ if (key && !((union key_payload *)rx->key->name_link.next)->data[0]) -+ #else - if (key && !rx->key->payload.data[0]) -+ #endif - key = NULL; - - memset(&cp, 0, sizeof(cp)); -diff --git a/net/rxrpc/server_key.c b/net/rxrpc/server_key.c -index e519405..1ea7e51 100644 ---- a/net/rxrpc/server_key.c -+++ b/net/rxrpc/server_key.c -@@ -100,7 +100,11 @@ static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep) - - static void rxrpc_destroy_s(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ const struct rxrpc_security *sec = ((union key_payload *)(key->name_link.next))->data[1]; -+ #else - const struct rxrpc_security *sec = key->payload.data[1]; -+ #endif - - if (sec && sec->destroy_server_key) - sec->destroy_server_key(key); -@@ -108,7 +112,11 @@ static void rxrpc_destroy_s(struct key *key) - - static void rxrpc_describe_s(const struct key *key, struct seq_file *m) - { -+ #ifdef CONFIG_KEYP -+ const struct rxrpc_security *sec = ((union key_payload *)(key->name_link.next))->data[1]; -+ #else - const struct rxrpc_security *sec = key->payload.data[1]; -+ #endif - - seq_puts(m, key->description); - if (sec && sec->describe_server_key) -diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c -index 43f2731..650c012 100644 ---- a/net/sctp/ipv6.c -+++ b/net/sctp/ipv6.c -@@ -684,7 +684,7 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) - struct sock *sk = &sp->inet.sk; - struct net *net = sock_net(sk); - struct net_device *dev = NULL; -- int type; -+ int type, res, bound_dev_if; - - type = ipv6_addr_type(in6); - if (IPV6_ADDR_ANY == type) -@@ -698,14 +698,20 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) - if (!(type & IPV6_ADDR_UNICAST)) - return 0; - -- if (sk->sk_bound_dev_if) { -- dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); -+ rcu_read_lock(); -+ bound_dev_if = READ_ONCE(sk->sk_bound_dev_if); -+ if (bound_dev_if) { -+ res = 0; -+ dev = dev_get_by_index_rcu(net, bound_dev_if); - if (!dev) -- return 0; -+ goto out; - } - -- return ipv6_can_nonlocal_bind(net, &sp->inet) || -- ipv6_chk_addr(net, in6, dev, 0); -+ res = ipv6_can_nonlocal_bind(net, &sp->inet) ||ipv6_chk_addr(net, in6, dev, 0); -+ -+out: -+ rcu_read_unlock(); -+ return res; - } - - /* This function checks if the address is a valid address to be used for -diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c -index 04534ea..0bb5e49 100644 ---- a/net/sunrpc/auth.c -+++ b/net/sunrpc/auth.c -@@ -38,9 +38,13 @@ static const struct rpc_authops __rcu *auth_flavors[RPC_AUTH_MAXFLAVOR] = { - static LIST_HEAD(cred_unused); - static unsigned long number_cred_unused; - -+#ifdef CONFIG_CREDP -+static struct cred *machine_cred; -+#else - static struct cred machine_cred = { - .usage = ATOMIC_INIT(1), - }; -+#endif - - /* - * Return the machine_cred pointer to be used whenever -@@ -48,7 +52,11 @@ static struct cred machine_cred = { - */ - const struct cred *rpc_machine_cred(void) - { -+ #ifdef CONFIG_CREDP -+ return machine_cred; -+ #else - return &machine_cred; -+ #endif - } - EXPORT_SYMBOL_GPL(rpc_machine_cred); - -@@ -659,15 +667,27 @@ rpcauth_bindcred(struct rpc_task *task, const struct cred *cred, int flags) - if (task->tk_op_cred) - /* Task must use exactly this rpc_cred */ - new = get_rpccred(task->tk_op_cred); -+ #ifdef CONFIG_CREDP -+ else if (cred && cred != machine_cred) -+ #else - else if (cred != NULL && cred != &machine_cred) -+ #endif - new = auth->au_ops->lookup_cred(auth, &acred, lookupflags); -+ #ifdef CONFIG_CREDP -+ else if (cred == machine_cred) -+ #else - else if (cred == &machine_cred) -+ #endif - new = rpcauth_bind_machine_cred(task, lookupflags); - - /* If machine cred couldn't be bound, try a root cred */ - if (new) - ; -+ #ifdef CONFIG_CREDP -+ else if (cred == machine_cred) -+ #else - else if (cred == &machine_cred) -+ #endif - new = rpcauth_bind_root_cred(task, lookupflags); - else if (flags & RPC_TASK_NULLCREDS) - new = authnull_ops.lookup_cred(NULL, NULL, 0); -@@ -867,6 +887,9 @@ static struct shrinker *rpc_cred_shrinker; - - int __init rpcauth_init_module(void) - { -+ #ifdef CONFIG_CREDP -+ machine_cred = prepare_kernel_cred(&init_task); -+ #endif - int err; - - err = rpc_init_authunix(); -@@ -892,6 +915,9 @@ int __init rpcauth_init_module(void) - - void rpcauth_remove_module(void) - { -+ #ifdef CONFIG_CREDP -+ abort_creds(machine_cred); -+ #endif - rpc_destroy_authunix(); - shrinker_free(rpc_cred_shrinker); - } -diff --git a/security/commoncap.c b/security/commoncap.c -index bc05211..32e53bf 100644 ---- a/security/commoncap.c -+++ b/security/commoncap.c -@@ -25,6 +25,9 @@ - #include <linux/binfmts.h> - #include <linux/personality.h> - #include <linux/mnt_idmapping.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif - - /* - * If a non-root user executes a setuid-root binary in -@@ -266,6 +269,15 @@ int cap_capset(struct cred *new, - if (!cap_issubset(*effective, *permitted)) - return -EPERM; - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_effective(new, *effective); -+ iee_set_cred_cap_inheritable(new, *inheritable); -+ iee_set_cred_cap_permitted(new, *permitted); -+ -+ iee_set_cred_cap_ambient(new, cap_intersect(new->cap_ambient, -+ cap_intersect(*permitted, -+ *inheritable))); -+ #else - new->cap_effective = *effective; - new->cap_inheritable = *inheritable; - new->cap_permitted = *permitted; -@@ -277,6 +289,7 @@ int cap_capset(struct cred *new, - new->cap_ambient = cap_intersect(new->cap_ambient, - cap_intersect(*permitted, - *inheritable)); -+ #endif - if (WARN_ON(!cap_ambient_invariant_ok(new))) - return -EINVAL; - return 0; -@@ -601,9 +614,17 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps, - * pP' = (X & fP) | (pI & fI) - * The addition of pA' is handled later. - */ -+ #ifdef CONFIG_CREDP -+ kernel_cap_t temp = new->cap_permitted; -+ -+ temp.val = (new->cap_bset.val & caps->permitted.val) | -+ (new->cap_inheritable.val & caps->inheritable.val); -+ iee_set_cred_cap_permitted(new, temp); -+ #else - new->cap_permitted.val = - (new->cap_bset.val & caps->permitted.val) | - (new->cap_inheritable.val & caps->inheritable.val); -+ #endif - - if (caps->permitted.val & ~new->cap_permitted.val) - /* insufficient to execute correctly */ -@@ -726,7 +747,16 @@ static int get_file_caps(struct linux_binprm *bprm, struct file *file, - int rc = 0; - struct cpu_vfs_cap_data vcaps; - -+ #ifdef CONFIG_CREDP -+ do { -+ kernel_cap_t tmp_cap = bprm->cred->cap_permitted; -+ -+ tmp_cap.val = 0; -+ iee_set_cred_cap_permitted(bprm->cred, tmp_cap); -+ } while (0); -+ #else - cap_clear(bprm->cred->cap_permitted); -+ #endif - - if (!file_caps_enabled) - return 0; -@@ -757,7 +787,16 @@ static int get_file_caps(struct linux_binprm *bprm, struct file *file, - - out: - if (rc) -+ #ifdef CONFIG_CREDP -+ do { -+ kernel_cap_t tmp_cap = bprm->cred->cap_permitted; -+ -+ tmp_cap.val = 0; -+ iee_set_cred_cap_permitted(bprm->cred, tmp_cap); -+ } while (0); -+ #else - cap_clear(bprm->cred->cap_permitted); -+ #endif - - return rc; - } -@@ -809,8 +848,13 @@ static void handle_privileged_root(struct linux_binprm *bprm, bool has_fcap, - */ - if (__is_eff(root_uid, new) || __is_real(root_uid, new)) { - /* pP' = (cap_bset & ~0) | (pI & ~0) */ -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_permitted(new, cap_combine(old->cap_bset, -+ old->cap_inheritable)); -+ #else - new->cap_permitted = cap_combine(old->cap_bset, - old->cap_inheritable); -+ #endif - } - /* - * If only the real uid is 0, we do not set the effective bit. -@@ -919,34 +963,73 @@ int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file) - /* downgrade; they get no more than they had, and maybe less */ - if (!ns_capable(new->user_ns, CAP_SETUID) || - (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) { -+ #ifdef CONFIG_CREDP -+ iee_set_cred_euid(new, new->uid); -+ iee_set_cred_egid(new, new->gid); -+ #else - new->euid = new->uid; - new->egid = new->gid; -+ #endif - } -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_permitted(new, cap_intersect(new->cap_permitted, -+ old->cap_permitted)); -+ #else - new->cap_permitted = cap_intersect(new->cap_permitted, - old->cap_permitted); -+ #endif - } - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_fsuid(new, new->euid); -+ iee_set_cred_suid(new, new->euid); -+ iee_set_cred_fsgid(new, new->egid); -+ iee_set_cred_sgid(new, new->egid); -+ #else - new->suid = new->fsuid = new->euid; - new->sgid = new->fsgid = new->egid; -+ #endif - - /* File caps or setid cancels ambient. */ - if (has_fcap || is_setid) -+ #ifdef CONFIG_CREDP -+ do { -+ kernel_cap_t tmp_cap = new->cap_ambient; -+ -+ tmp_cap.val = 0; -+ iee_set_cred_cap_ambient(new, tmp_cap); -+ } while (0); -+ #else - cap_clear(new->cap_ambient); -+ #endif - - /* - * Now that we've computed pA', update pP' to give: - * pP' = (X & fP) | (pI & fI) | pA' - */ -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_permitted(new, -+ cap_combine(new->cap_permitted, new->cap_ambient)); -+ #else - new->cap_permitted = cap_combine(new->cap_permitted, new->cap_ambient); -+ #endif - - /* - * Set pE' = (fE ? pP' : pA'). Because pA' is zero if fE is set, - * this is the same as pE' = (fE ? pP' : 0) | pA'. - */ - if (effective) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_effective(new, new->cap_permitted); -+ #else - new->cap_effective = new->cap_permitted; -+ #endif - else -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_effective(new, new->cap_ambient); -+ #else - new->cap_effective = new->cap_ambient; -+ #endif - - if (WARN_ON(!cap_ambient_invariant_ok(new))) - return -EPERM; -@@ -957,7 +1040,12 @@ int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file) - return ret; - } - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_securebits(new, -+ new->securebits & ~issecure_mask(SECURE_KEEP_CAPS)); -+ #else - new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); -+ #endif - - if (WARN_ON(!cap_ambient_invariant_ok(new))) - return -EPERM; -@@ -1092,8 +1180,23 @@ static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old) - !uid_eq(new->euid, root_uid) && - !uid_eq(new->suid, root_uid))) { - if (!issecure(SECURE_KEEP_CAPS)) { -+ #ifdef CONFIG_CREDP -+ do { -+ kernel_cap_t tmp_cap = new->cap_permitted; -+ -+ tmp_cap.val = 0; -+ iee_set_cred_cap_permitted(new, tmp_cap); -+ } while (0); -+ do { -+ kernel_cap_t tmp_cap = new->cap_effective; -+ -+ tmp_cap.val = 0; -+ iee_set_cred_cap_effective(new, tmp_cap); -+ } while (0); -+ #else - cap_clear(new->cap_permitted); - cap_clear(new->cap_effective); -+ #endif - } - - /* -@@ -1101,12 +1204,34 @@ static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old) - * by exec to drop capabilities. We should make sure that - * this remains the case. - */ -+ #ifdef CONFIG_CREDP -+ do { -+ kernel_cap_t tmp_cap = new->cap_ambient; -+ -+ tmp_cap.val = 0; -+ iee_set_cred_cap_ambient(new, tmp_cap); -+ } while (0); -+ #else - cap_clear(new->cap_ambient); -+ #endif - } - if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid)) -+ #ifdef CONFIG_CREDP -+ do { -+ kernel_cap_t tmp_cap = new->cap_effective; -+ -+ tmp_cap.val = 0; -+ iee_set_cred_cap_effective(new, tmp_cap); -+ } while (0); -+ #else - cap_clear(new->cap_effective); -+ #endif - if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid)) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_effective(new, new->cap_permitted); -+ #else - new->cap_effective = new->cap_permitted; -+ #endif - } - - /** -@@ -1142,13 +1267,22 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags) - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - kuid_t root_uid = make_kuid(old->user_ns, 0); - if (uid_eq(old->fsuid, root_uid) && !uid_eq(new->fsuid, root_uid)) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_effective(new, cap_drop_fs_set(new->cap_effective)); -+ #else - new->cap_effective = - cap_drop_fs_set(new->cap_effective); -+ #endif - - if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid)) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_cap_effective(new, cap_raise_fs_set(new->cap_effective, -+ new->cap_permitted)); -+ #else - new->cap_effective = - cap_raise_fs_set(new->cap_effective, - new->cap_permitted); -+ #endif - } - break; - -@@ -1243,7 +1377,14 @@ static int cap_prctl_drop(unsigned long cap) - new = prepare_creds(); - if (!new) - return -ENOMEM; -+ #ifdef CONFIG_CREDP -+ kernel_cap_t tmp = new->cap_bset; -+ -+ cap_lower(tmp, cap); -+ iee_set_cred_cap_bset(new, tmp); -+ #else - cap_lower(new->cap_bset, cap); -+ #endif - return commit_creds(new); - } - -@@ -1319,7 +1460,11 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, - new = prepare_creds(); - if (!new) - return -ENOMEM; -+ #ifdef CONFIG_CREDP -+ iee_set_cred_securebits(new, arg2); -+ #else - new->securebits = arg2; -+ #endif - return commit_creds(new); - - case PR_GET_SECUREBITS: -@@ -1338,9 +1483,19 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, - if (!new) - return -ENOMEM; - if (arg2) -+ #ifdef CONFIG_CREDP -+ iee_set_cred_securebits(new, -+ new->securebits | issecure_mask(SECURE_KEEP_CAPS)); -+ #else - new->securebits |= issecure_mask(SECURE_KEEP_CAPS); -+ #endif - else -+ #ifdef CONFIG_CREDP -+ iee_set_cred_securebits(new, -+ new->securebits & ~issecure_mask(SECURE_KEEP_CAPS)); -+ #else - new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); -+ #endif - return commit_creds(new); - - case PR_CAP_AMBIENT: -@@ -1351,7 +1506,16 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, - new = prepare_creds(); - if (!new) - return -ENOMEM; -+ #ifdef CONFIG_CREDP -+ do { -+ kernel_cap_t tmp_cap = new->cap_ambient; -+ -+ tmp_cap.val = 0; -+ iee_set_cred_cap_ambient(new, tmp_cap); -+ } while (0); -+ #else - cap_clear(new->cap_ambient); -+ #endif - return commit_creds(new); - } - -@@ -1375,9 +1539,27 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, - if (!new) - return -ENOMEM; - if (arg2 == PR_CAP_AMBIENT_RAISE) -+ #ifdef CONFIG_CREDP -+ { -+ kernel_cap_t tmp = new->cap_ambient; -+ -+ cap_raise(tmp, arg3); -+ iee_set_cred_cap_ambient(new, tmp); -+ } -+ #else - cap_raise(new->cap_ambient, arg3); -+ #endif - else -+ #ifdef CONFIG_CREDP -+ { -+ kernel_cap_t tmp = new->cap_ambient; -+ -+ cap_lower(tmp, arg3); -+ iee_set_cred_cap_ambient(new, tmp); -+ } -+ #else - cap_lower(new->cap_ambient, arg3); -+ #endif - return commit_creds(new); - } - -diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c -index b1ffd4c..2446e11 100644 ---- a/security/integrity/evm/evm_crypto.c -+++ b/security/integrity/evm/evm_crypto.c -@@ -422,14 +422,23 @@ int evm_init_key(void) - if (IS_ERR(evm_key)) - return -ENOENT; - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(evm_key)); -+ ekp = ((union key_payload *)(evm_key->name_link.next))->data[0]; -+ #else - down_read(&evm_key->sem); - ekp = evm_key->payload.data[0]; -+ #endif - - rc = evm_set_key(ekp->decrypted_data, ekp->decrypted_datalen); - - /* burn the original key contents */ - memset(ekp->decrypted_data, 0, ekp->decrypted_datalen); -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(evm_key)); -+ #else - up_read(&evm_key->sem); -+ #endif - key_put(evm_key); - return rc; - } -diff --git a/security/keys/big_key.c b/security/keys/big_key.c -index c336762..bc6a097 100644 ---- a/security/keys/big_key.c -+++ b/security/keys/big_key.c -@@ -164,7 +164,11 @@ void big_key_free_preparse(struct key_preparsed_payload *prep) - */ - void big_key_revoke(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ struct big_key_payload *payload = to_big_key_payload(*((union key_payload *)(key->name_link.next))); -+ #else - struct big_key_payload *payload = to_big_key_payload(key->payload); -+ #endif - - /* clear the quota */ - key_payload_reserve(key, 0); -@@ -177,7 +181,11 @@ void big_key_revoke(struct key *key) - */ - void big_key_destroy(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ struct big_key_payload *payload = to_big_key_payload(*((union key_payload *)(key->name_link.next))); -+ #else - struct big_key_payload *payload = to_big_key_payload(key->payload); -+ #endif - - if (payload->length > BIG_KEY_FILE_THRESHOLD) { - path_put(&payload->path); -@@ -210,7 +218,11 @@ int big_key_update(struct key *key, struct key_preparsed_payload *prep) - */ - void big_key_describe(const struct key *key, struct seq_file *m) - { -+ #ifdef CONFIG_KEYP -+ struct big_key_payload *payload = to_big_key_payload(*((union key_payload *)(key->name_link.next))); -+ #else - struct big_key_payload *payload = to_big_key_payload(key->payload); -+ #endif - - seq_puts(m, key->description); - -@@ -226,7 +238,11 @@ void big_key_describe(const struct key *key, struct seq_file *m) - */ - long big_key_read(const struct key *key, char *buffer, size_t buflen) - { -+ #ifdef CONFIG_KEYP -+ struct big_key_payload *payload = to_big_key_payload(*((union key_payload *)(key->name_link.next))); -+ #else - struct big_key_payload *payload = to_big_key_payload(key->payload); -+ #endif - size_t datalen = payload->length; - long ret; - -diff --git a/security/keys/dh.c b/security/keys/dh.c -index da64c35..f00a3e0 100644 ---- a/security/keys/dh.c -+++ b/security/keys/dh.c -@@ -32,7 +32,11 @@ static ssize_t dh_data_from_key(key_serial_t keyid, const void **data) - - ret = -EOPNOTSUPP; - if (key->type == &key_type_user) { -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(key)); -+ #else - down_read(&key->sem); -+ #endif - status = key_validate(key); - if (status == 0) { - const struct user_key_payload *payload; -@@ -49,7 +53,11 @@ static ssize_t dh_data_from_key(key_serial_t keyid, const void **data) - ret = -ENOMEM; - } - } -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - } - - key_put(key); -diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c -index 1e31398..ef5e8f4 100644 ---- a/security/keys/encrypted-keys/encrypted.c -+++ b/security/keys/encrypted-keys/encrypted.c -@@ -314,11 +314,19 @@ static struct key *request_user_key(const char *master_desc, const u8 **master_k - if (IS_ERR(ukey)) - goto error; - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(ukey)); -+ #else - down_read(&ukey->sem); -+ #endif - upayload = user_key_payload_locked(ukey); - if (!upayload) { - /* key was revoked before we acquired its semaphore */ -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(ukey)); -+ #else - up_read(&ukey->sem); -+ #endif - key_put(ukey); - ukey = ERR_PTR(-EKEYREVOKED); - goto error; -@@ -729,7 +737,11 @@ static int encrypted_key_decrypt(struct encrypted_key_payload *epayload, - if (ret < 0) - pr_err("encrypted_key: failed to decrypt key (%d)\n", ret); - out: -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(mkey)); -+ #else - up_read(&mkey->sem); -+ #endif - key_put(mkey); - memzero_explicit(derived_key, sizeof(derived_key)); - return ret; -@@ -874,7 +886,11 @@ static void encrypted_rcu_free(struct rcu_head *rcu) - */ - static int encrypted_update(struct key *key, struct key_preparsed_payload *prep) - { -+ #ifdef CONFIG_KEYP -+ struct encrypted_key_payload *epayload = ((union key_payload *)(key->name_link.next))->data[0]; -+ #else - struct encrypted_key_payload *epayload = key->payload.data[0]; -+ #endif - struct encrypted_key_payload *new_epayload; - char *buf; - char *new_master_desc = NULL; -@@ -974,7 +990,11 @@ static long encrypted_read(const struct key *key, char *buffer, - goto out; - } - -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(mkey)); -+ #else - up_read(&mkey->sem); -+ #endif - key_put(mkey); - memzero_explicit(derived_key, sizeof(derived_key)); - -@@ -983,7 +1003,11 @@ static long encrypted_read(const struct key *key, char *buffer, - - return asciiblob_len; - out: -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(mkey)); -+ #else - up_read(&mkey->sem); -+ #endif - key_put(mkey); - memzero_explicit(derived_key, sizeof(derived_key)); - return ret; -@@ -994,7 +1018,11 @@ static long encrypted_read(const struct key *key, char *buffer, - */ - static void encrypted_destroy(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ kfree_sensitive(((union key_payload *)(key->name_link.next))->data[0]); -+ #else - kfree_sensitive(key->payload.data[0]); -+ #endif - } - - struct key_type key_type_encrypted = { -diff --git a/security/keys/encrypted-keys/masterkey_trusted.c b/security/keys/encrypted-keys/masterkey_trusted.c -index e6d22ce..13803e0 100644 ---- a/security/keys/encrypted-keys/masterkey_trusted.c -+++ b/security/keys/encrypted-keys/masterkey_trusted.c -@@ -34,8 +34,13 @@ struct key *request_trusted_key(const char *trusted_desc, - if (IS_ERR(tkey)) - goto error; - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(tkey)); -+ tpayload = ((union key_payload *)(tkey->name_link.next))->data[0]; -+ #else - down_read(&tkey->sem); - tpayload = tkey->payload.data[0]; -+ #endif - *master_key = tpayload->key; - *master_keylen = tpayload->key_len; - error: -diff --git a/security/keys/gc.c b/security/keys/gc.c -index eaddace..d138498 100644 ---- a/security/keys/gc.c -+++ b/security/keys/gc.c -@@ -8,6 +8,10 @@ - #include <linux/slab.h> - #include <linux/security.h> - #include <keys/keyring-type.h> -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#include <asm/iee-access.h> -+#endif - #include "internal.h" - - /* -@@ -135,18 +139,30 @@ void key_gc_keytype(struct key_type *ktype) - static noinline void key_gc_unused_keys(struct list_head *keys) - { - while (!list_empty(keys)) { -+ #ifdef CONFIG_KEYP -+ struct key *key = list_entry(keys->next, struct key_union, graveyard_link)->key; -+ #else - struct key *key = - list_entry(keys->next, struct key, graveyard_link); -+ #endif - short state = key->state; - -+ #ifdef CONFIG_KEYP -+ list_del(&(((struct key_union *)(key->graveyard_link.next))->graveyard_link)); -+ #else - list_del(&key->graveyard_link); -+ #endif - - kdebug("- %u", key->serial); - key_check(key); - - #ifdef CONFIG_KEY_NOTIFICATIONS - remove_watch_list(key->watchers, key->serial); -+ #ifdef CONFIG_KEYP -+ iee_set_key_watchers(key, NULL); -+ #else - key->watchers = NULL; -+ #endif - #endif - - /* Throw away the key data if the key is instantiated */ -@@ -171,7 +187,15 @@ static noinline void key_gc_unused_keys(struct list_head *keys) - key_put_tag(key->domain_tag); - kfree(key->description); - -+ #ifdef CONFIG_KEYP -+ kmem_cache_free(key_union_jar, (struct key_union *)(key->graveyard_link.next)); -+ kmem_cache_free(key_struct_jar, (struct key_struct *)(key->name_link.prev)); -+ kmem_cache_free(key_payload_jar, (union key_payload *)(key->name_link.next)); -+ iee_memset(key, 0, sizeof(*key)); -+ barrier_data(key); -+ #else - memzero_explicit(key, sizeof(*key)); -+ #endif - kmem_cache_free(key_jar, key); - } - } -@@ -223,7 +247,11 @@ static void key_garbage_collector(struct work_struct *work) - - continue_scanning: - while (cursor) { -+ #ifdef CONFIG_KEYP -+ key = rb_entry(cursor, struct key_union, serial_node)->key; -+ #else - key = rb_entry(cursor, struct key, serial_node); -+ #endif - cursor = rb_next(cursor); - - if (refcount_read(&key->usage) == 0) -@@ -232,8 +260,13 @@ static void key_garbage_collector(struct work_struct *work) - if (unlikely(gc_state & KEY_GC_REAPING_DEAD_1)) { - if (key->type == key_gc_dead_keytype) { - gc_state |= KEY_GC_FOUND_DEAD_KEY; -+ #ifdef CONFIG_KEYP -+ iee_set_key_flag_bit(key, KEY_FLAG_DEAD, SET_BIT_OP); -+ iee_set_key_perm(key, 0); -+ #else - set_bit(KEY_FLAG_DEAD, &key->flags); - key->perm = 0; -+ #endif - goto skip_dead_key; - } else if (key->type == &key_type_keyring && - key->restrict_link) { -@@ -339,10 +372,18 @@ static void key_garbage_collector(struct work_struct *work) - */ - found_unreferenced_key: - kdebug("unrefd key %d", key->serial); -+ #ifdef CONFIG_KEYP -+ rb_erase(&(((struct key_union *)(key->graveyard_link.next))->serial_node), &key_serial_tree); -+ #else - rb_erase(&key->serial_node, &key_serial_tree); -+ #endif - spin_unlock(&key_serial_lock); - -+ #ifdef CONFIG_KEYP -+ list_add_tail(&(((struct key_union *)(key->graveyard_link.next))->graveyard_link), &graveyard); -+ #else - list_add_tail(&key->graveyard_link, &graveyard); -+ #endif - gc_state |= KEY_GC_REAP_AGAIN; - goto maybe_resched; - -@@ -370,11 +411,21 @@ static void key_garbage_collector(struct work_struct *work) - destroy_dead_key: - spin_unlock(&key_serial_lock); - kdebug("destroy key %d", key->serial); -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(key)); -+ iee_set_key_type(key, &key_type_dead); -+ #else - down_write(&key->sem); - key->type = &key_type_dead; -+ #endif - if (key_gc_dead_keytype->destroy) - key_gc_dead_keytype->destroy(key); -+ #ifdef CONFIG_KEYP -+ iee_memset((key->name_link.next), KEY_DESTROY, sizeof(key->payload)); -+ up_write(&KEY_SEM(key)); -+ #else - memset(&key->payload, KEY_DESTROY, sizeof(key->payload)); - up_write(&key->sem); -+ #endif - goto maybe_resched; - } -diff --git a/security/keys/internal.h b/security/keys/internal.h -index ec2ec33..00d76f8 100644 ---- a/security/keys/internal.h -+++ b/security/keys/internal.h -@@ -83,12 +83,20 @@ extern unsigned key_quota_maxbytes; - - - extern struct kmem_cache *key_jar; -+#ifdef CONFIG_KEYP -+extern struct kmem_cache *key_union_jar; -+extern struct kmem_cache *key_struct_jar; -+extern struct kmem_cache *key_payload_jar; -+#endif - extern struct rb_root key_serial_tree; - extern spinlock_t key_serial_lock; - extern struct mutex key_construction_mutex; - extern wait_queue_head_t request_key_conswq; - - extern void key_set_index_key(struct keyring_index_key *index_key); -+#ifdef CONFIG_KEYP -+extern void iee_key_set_index_key(struct keyring_index_key *index_key); -+#endif - extern struct key_type *key_type_lookup(const char *type); - extern void key_type_put(struct key_type *ktype); - -diff --git a/security/keys/key.c b/security/keys/key.c -index 35db23d..51898cb 100644 ---- a/security/keys/key.c -+++ b/security/keys/key.c -@@ -15,9 +15,19 @@ - #include <linux/random.h> - #include <linux/ima.h> - #include <linux/err.h> -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#include <asm/iee-def.h> -+#include <asm/iee-access.h> -+#endif - #include "internal.h" - - struct kmem_cache *key_jar; -+#ifdef CONFIG_KEYP -+struct kmem_cache *key_union_jar; -+struct kmem_cache *key_struct_jar; -+struct kmem_cache *key_payload_jar; -+#endif - struct rb_root key_serial_tree; /* tree of keys indexed by serial */ - DEFINE_SPINLOCK(key_serial_lock); - -@@ -139,9 +149,17 @@ static inline void key_alloc_serial(struct key *key) - /* propose a random serial number and look for a hole for it in the - * serial number tree */ - do { -+ #ifdef CONFIG_KEYP -+ key_serial_t tmp; -+ -+ get_random_bytes(&tmp, sizeof(key->serial)); -+ -+ iee_set_key_serial(key, tmp >> 1); -+ #else - get_random_bytes(&key->serial, sizeof(key->serial)); - - key->serial >>= 1; /* negative numbers are not permitted */ -+ #endif - } while (key->serial < 3); - - spin_lock(&key_serial_lock); -@@ -152,7 +170,11 @@ static inline void key_alloc_serial(struct key *key) - - while (*p) { - parent = *p; -+ #ifdef CONFIG_KEYP -+ xkey = rb_entry(parent, struct key_union, serial_node)->key; -+ #else - xkey = rb_entry(parent, struct key, serial_node); -+ #endif - - if (key->serial < xkey->serial) - p = &(*p)->rb_left; -@@ -163,8 +185,13 @@ static inline void key_alloc_serial(struct key *key) - } - - /* we've found a suitable hole - arrange for this key to occupy it */ -+ #ifdef CONFIG_KEYP -+ rb_link_node(&(((struct key_union *)(key->graveyard_link.next))->serial_node), parent, p); -+ rb_insert_color(&(((struct key_union *)(key->graveyard_link.next))->serial_node), &key_serial_tree); -+ #else - rb_link_node(&key->serial_node, parent, p); - rb_insert_color(&key->serial_node, &key_serial_tree); -+ #endif - - spin_unlock(&key_serial_lock); - return; -@@ -173,9 +200,19 @@ static inline void key_alloc_serial(struct key *key) - * that point looking for the next unused serial number */ - serial_exists: - for (;;) { -+ #ifdef CONFIG_KEYP -+ key_serial_t tmp = key->serial + 1; -+ -+ iee_set_key_serial(key, tmp); -+ #else - key->serial++; -+ #endif - if (key->serial < 3) { -+ #ifdef CONFIG_KEYP -+ iee_set_key_serial(key, 3); -+ #else - key->serial = 3; -+ #endif - goto attempt_insertion; - } - -@@ -183,7 +220,11 @@ static inline void key_alloc_serial(struct key *key) - if (!parent) - goto attempt_insertion; - -+ #ifdef CONFIG_KEYP -+ xkey = rb_entry(parent, struct key_union, serial_node)->key; -+ #else - xkey = rb_entry(parent, struct key, serial_node); -+ #endif - if (key->serial < xkey->serial) - goto attempt_insertion; - } -@@ -231,6 +272,9 @@ struct key *key_alloc(struct key_type *type, const char *desc, - struct key *key; - size_t desclen, quotalen; - int ret; -+ #ifdef CONFIG_KEYP -+ unsigned long kflags; -+ #endif - - key = ERR_PTR(-EINVAL); - if (!desc || !*desc) -@@ -274,17 +318,75 @@ struct key *key_alloc(struct key_type *type, const char *desc, - } - - /* allocate and initialise the key and its description */ -+ #ifdef CONFIG_KEYP -+ key = kmem_cache_alloc(key_jar, GFP_KERNEL); -+ #else - key = kmem_cache_zalloc(key_jar, GFP_KERNEL); -+ #endif - if (!key) - goto no_memory_2; -+ #ifdef CONFIG_KEYP -+ struct key_union *key_union = kmem_cache_zalloc(key_union_jar, GFP_KERNEL); -+ struct key_struct *key_struct = kmem_cache_zalloc(key_struct_jar, GFP_KERNEL); - -+ key_union->key = key; -+ key_struct->key = key; -+ iee_set_key_union(key, key_union); -+ iee_set_key_struct(key, key_struct); -+ iee_set_key_payload(key, kmem_cache_alloc(key_payload_jar, GFP_KERNEL)); -+ #endif -+ -+ #ifdef CONFIG_KEYP -+ struct keyring_index_key tmp = key->index_key; -+ -+ tmp.desc_len = desclen; -+ tmp.description = kmemdup(desc, desclen + 1, GFP_KERNEL); -+ iee_set_key_index_key(key, &tmp); -+ -+ #else - key->index_key.desc_len = desclen; - key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL); -+ #endif - if (!key->index_key.description) - goto no_memory_3; -+ #ifdef CONFIG_KEYP -+ tmp = key->index_key; -+ tmp.type = type; -+ iee_set_key_index_key(key, &tmp); -+ iee_key_set_index_key(&key->index_key); -+ #else - key->index_key.type = type; - key_set_index_key(&key->index_key); -+ #endif -+ -+ #ifdef CONFIG_KEYP -+ iee_set_key_usage(key, 1, REFCOUNT_SET); -+ init_rwsem(&KEY_SEM(key)); -+ lockdep_set_class(&KEY_SEM(key), &type->lock_class); -+ iee_set_key_user(key, user); -+ iee_set_key_quotalen(key, quotalen); -+ iee_set_key_datalen(key, type->def_datalen); -+ iee_set_key_uid(key, uid); -+ iee_set_key_gid(key, gid); -+ iee_set_key_perm(key, perm); -+ iee_set_key_restrict_link(key, restrict_link); -+ iee_set_key_last_used_at(key, ktime_get_real_seconds()); -+ -+ kflags = key->flags; -+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) -+ kflags |= 1 << KEY_FLAG_IN_QUOTA; -+ if (flags & KEY_ALLOC_BUILT_IN) -+ kflags |= 1 << KEY_FLAG_BUILTIN; -+ if (flags & KEY_ALLOC_UID_KEYRING) -+ kflags |= 1 << KEY_FLAG_UID_KEYRING; -+ if (flags & KEY_ALLOC_SET_KEEP) -+ kflags |= 1 << KEY_FLAG_KEEP; -+ iee_set_key_flags(key, kflags); - -+#ifdef KEY_DEBUGGING -+ iee_set_key_magic(key, KEY_DEBUG_MAGIC); -+#endif -+ #else - refcount_set(&key->usage, 1); - init_rwsem(&key->sem); - lockdep_set_class(&key->sem, &type->lock_class); -@@ -310,6 +412,7 @@ struct key *key_alloc(struct key_type *type, const char *desc, - #ifdef KEY_DEBUGGING - key->magic = KEY_DEBUG_MAGIC; - #endif -+ #endif - - /* let the security module know about the key */ - ret = security_key_alloc(key, cred, flags); -@@ -326,6 +429,12 @@ struct key *key_alloc(struct key_type *type, const char *desc, - - security_error: - kfree(key->description); -+ #ifdef CONFIG_KEYP -+ kmem_cache_free(key_union_jar, (struct key_union *)(key->graveyard_link.next)); -+ kmem_cache_free(key_struct_jar, (struct key_struct *)(key->name_link.prev)); -+ kmem_cache_free(key_payload_jar, (union key_payload *)(key->name_link.next)); -+ iee_memset(key, 0, sizeof(struct key)); -+ #endif - kmem_cache_free(key_jar, key); - if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { - spin_lock(&user->lock); -@@ -338,6 +447,12 @@ struct key *key_alloc(struct key_type *type, const char *desc, - goto error; - - no_memory_3: -+ #ifdef CONFIG_KEYP -+ kmem_cache_free(key_union_jar, (struct key_union *)(key->graveyard_link.next)); -+ kmem_cache_free(key_struct_jar, (struct key_struct *)(key->name_link.prev)); -+ kmem_cache_free(key_payload_jar, (union key_payload *)(key->name_link.next)); -+ iee_memset(key, 0, sizeof(struct key)); -+ #endif - kmem_cache_free(key_jar, key); - no_memory_2: - if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { -@@ -391,14 +506,22 @@ int key_payload_reserve(struct key *key, size_t datalen) - } - else { - key->user->qnbytes += delta; -+ #ifdef CONFIG_KEYP -+ iee_set_key_quotalen(key, key->quotalen + delta); -+ #else - key->quotalen += delta; -+ #endif - } - spin_unlock(&key->user->lock); - } - - /* change the recorded data length if that didn't generate an error */ - if (ret == 0) -+ #ifdef CONFIG_KEYP -+ iee_set_key_datalen(key, datalen); -+ #else - key->datalen = datalen; -+ #endif - - return ret; - } -@@ -412,8 +535,14 @@ static void mark_key_instantiated(struct key *key, int reject_error) - /* Commit the payload before setting the state; barrier versus - * key_read_state(). - */ -+ #ifdef CONFIG_KEYP -+ compiletime_assert_atomic_type(key->state); -+ barrier(); -+ iee_set_key_state(key, (reject_error < 0) ? reject_error : KEY_IS_POSITIVE); -+ #else - smp_store_release(&key->state, - (reject_error < 0) ? reject_error : KEY_IS_POSITIVE); -+ #endif - } - - /* -@@ -449,13 +578,22 @@ static int __key_instantiate_and_link(struct key *key, - mark_key_instantiated(key, 0); - notify_key(key, NOTIFY_KEY_INSTANTIATED, 0); - -+ #ifdef CONFIG_KEYP -+ if (iee_set_key_flag_bit(key, KEY_FLAG_USER_CONSTRUCT, TEST_AND_CLEAR_BIT)) -+ awaken = 1; -+ #else - if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) - awaken = 1; -+ #endif - - /* and link it into the destination keyring */ - if (keyring) { - if (test_bit(KEY_FLAG_KEEP, &keyring->flags)) -+ #ifdef CONFIG_KEYP -+ iee_set_key_flag_bit(key, KEY_FLAG_KEEP, SET_BIT_OP); -+ #else - set_bit(KEY_FLAG_KEEP, &key->flags); -+ #endif - - __key_link(keyring, key, _edit); - } -@@ -465,7 +603,11 @@ static int __key_instantiate_and_link(struct key *key, - key_invalidate(authkey); - - if (prep->expiry != TIME64_MAX) -+ #ifdef CONFIG_KEYP -+ iee_set_key_expiry(key, prep->expiry); -+ #else - key_set_expiry(key, prep->expiry); -+ #endif - } - } - -@@ -605,10 +747,19 @@ int key_reject_and_link(struct key *key, - atomic_inc(&key->user->nikeys); - mark_key_instantiated(key, -error); - notify_key(key, NOTIFY_KEY_INSTANTIATED, -error); -+ #ifdef CONFIG_KEYP -+ iee_set_key_expiry(key, ktime_get_real_seconds() + timeout); -+ #else - key_set_expiry(key, ktime_get_real_seconds() + timeout); -+ #endif - -+ #ifdef CONFIG_KEYP -+ if (iee_set_key_flag_bit(key, KEY_FLAG_USER_CONSTRUCT, TEST_AND_CLEAR_BIT)) -+ awaken = 1; -+ #else - if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) - awaken = 1; -+ #endif - - ret = 0; - -@@ -647,8 +798,13 @@ void key_put(struct key *key) - if (key) { - key_check(key); - -+ #ifdef CONFIG_KEYP -+ if (iee_set_key_usage(key, 0, REFCOUNT_DEC_AND_TEST)) -+ schedule_work(&key_gc_work); -+ #else - if (refcount_dec_and_test(&key->usage)) - schedule_work(&key_gc_work); -+ #endif - } - } - EXPORT_SYMBOL(key_put); -@@ -666,7 +822,11 @@ struct key *key_lookup(key_serial_t id) - /* search the tree for the specified key */ - n = key_serial_tree.rb_node; - while (n) { -+ #ifdef CONFIG_KEYP -+ key = rb_entry(n, struct key_union, serial_node)->key; -+ #else - key = rb_entry(n, struct key, serial_node); -+ #endif - - if (id < key->serial) - n = n->rb_left; -@@ -684,8 +844,13 @@ struct key *key_lookup(key_serial_t id) - /* A key is allowed to be looked up only if someone still owns a - * reference to it - otherwise it's awaiting the gc. - */ -+ #ifdef CONFIG_KEYP -+ if (!iee_set_key_usage(key, 0, REFCOUNT_INC_NOT_ZERO)) -+ goto not_found; -+ #else - if (!refcount_inc_not_zero(&key->usage)) - goto not_found; -+ #endif - - error: - spin_unlock(&key_serial_lock); -@@ -723,13 +888,25 @@ void key_set_timeout(struct key *key, unsigned timeout) - time64_t expiry = TIME64_MAX; - - /* make the changes with the locks held to prevent races */ -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(key)); -+ #else - down_write(&key->sem); -+ #endif - - if (timeout > 0) - expiry = ktime_get_real_seconds() + timeout; -+ #ifdef CONFIG_KEYP -+ iee_set_key_expiry(key, expiry); -+ #else - key_set_expiry(key, expiry); -+ #endif - -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(key)); -+ #else - up_write(&key->sem); -+ #endif - } - EXPORT_SYMBOL_GPL(key_set_timeout); - -@@ -762,7 +939,11 @@ static inline key_ref_t __key_update(key_ref_t key_ref, - if (!key->type->update) - goto error; - -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(key)); -+ #else - down_write(&key->sem); -+ #endif - - ret = key->type->update(key, prep); - if (ret == 0) { -@@ -771,7 +952,11 @@ static inline key_ref_t __key_update(key_ref_t key_ref, - notify_key(key, NOTIFY_KEY_UPDATED, 0); - } - -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(key)); -+ #else - up_write(&key->sem); -+ #endif - - if (ret < 0) - goto error; -@@ -1087,7 +1272,11 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) - goto error; - } - -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(key)); -+ #else - down_write(&key->sem); -+ #endif - - ret = key->type->update(key, &prep); - if (ret == 0) { -@@ -1096,7 +1285,11 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) - notify_key(key, NOTIFY_KEY_UPDATED, 0); - } - -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(key)); -+ #else - up_write(&key->sem); -+ #endif - - error: - if (key->type->preparse) -@@ -1125,6 +1318,23 @@ void key_revoke(struct key *key) - * authorisation key whilst holding the sem on a key we've just - * instantiated - */ -+ #ifdef CONFIG_KEYP -+ down_write_nested(&KEY_SEM(key), 1); -+ if (!iee_set_key_flag_bit(key, KEY_FLAG_REVOKED, TEST_AND_SET_BIT)) { -+ notify_key(key, NOTIFY_KEY_REVOKED, 0); -+ if (key->type->revoke) -+ key->type->revoke(key); -+ -+ /* set the death time to no more than the expiry time */ -+ time = ktime_get_real_seconds(); -+ if (key->revoked_at == 0 || key->revoked_at > time) { -+ iee_set_key_revoked_at(key, time); -+ key_schedule_gc(key->revoked_at + key_gc_delay); -+ } -+ } -+ -+ up_write(&KEY_SEM(key)); -+ #else - down_write_nested(&key->sem, 1); - if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags)) { - notify_key(key, NOTIFY_KEY_REVOKED, 0); -@@ -1140,6 +1350,7 @@ void key_revoke(struct key *key) - } - - up_write(&key->sem); -+ #endif - } - EXPORT_SYMBOL(key_revoke); - -@@ -1157,12 +1368,21 @@ void key_invalidate(struct key *key) - key_check(key); - - if (!test_bit(KEY_FLAG_INVALIDATED, &key->flags)) { -+ #ifdef CONFIG_KEYP -+ down_write_nested(&KEY_SEM(key), 1); -+ if (!iee_set_key_flag_bit(key, KEY_FLAG_INVALIDATED, TEST_AND_SET_BIT)) { -+ notify_key(key, NOTIFY_KEY_INVALIDATED, 0); -+ key_schedule_gc_links(); -+ } -+ up_write(&KEY_SEM(key)); -+ #else - down_write_nested(&key->sem, 1); - if (!test_and_set_bit(KEY_FLAG_INVALIDATED, &key->flags)) { - notify_key(key, NOTIFY_KEY_INVALIDATED, 0); - key_schedule_gc_links(); - } - up_write(&key->sem); -+ #endif - } - } - EXPORT_SYMBOL(key_invalidate); -@@ -1186,9 +1406,17 @@ int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep) - ret = key_payload_reserve(key, prep->quotalen); - if (ret == 0) { - rcu_assign_keypointer(key, prep->payload.data[0]); -+ #ifdef CONFIG_KEYP -+ union key_payload *key_payload = (union key_payload *)(key->name_link.next); -+ -+ key_payload->data[1] = prep->payload.data[1]; -+ key_payload->data[2] = prep->payload.data[2]; -+ key_payload->data[3] = prep->payload.data[3]; -+ #else - key->payload.data[1] = prep->payload.data[1]; - key->payload.data[2] = prep->payload.data[2]; - key->payload.data[3] = prep->payload.data[3]; -+ #endif - prep->payload.data[0] = NULL; - prep->payload.data[1] = NULL; - prep->payload.data[2] = NULL; -@@ -1262,6 +1490,14 @@ void __init key_init(void) - /* allocate a slab in which we can store keys */ - key_jar = kmem_cache_create("key_jar", sizeof(struct key), - 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ #ifdef CONFIG_KEYP -+ key_union_jar = kmem_cache_create("key_union_jar", sizeof(struct key_union), -+ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ key_struct_jar = kmem_cache_create("key_struct_jar", sizeof(struct key_struct), -+ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ key_payload_jar = kmem_cache_create("key_payload_jar", sizeof(union key_payload)*4, -+ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ #endif - - /* add the special key types */ - list_add_tail(&key_type_keyring.link, &key_types_list); -diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c -index aa1dc43..8f5768b 100644 ---- a/security/keys/keyctl.c -+++ b/security/keys/keyctl.c -@@ -22,6 +22,12 @@ - #include <linux/uio.h> - #include <linux/uaccess.h> - #include <keys/request_key_auth-type.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif - #include "internal.h" - - #define KEY_MAX_DESC_SIZE 4096 -@@ -804,11 +810,19 @@ static long __keyctl_read_key(struct key *key, char *buffer, size_t buflen) - { - long ret; - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(key)); -+ #else - down_read(&key->sem); -+ #endif - ret = key_validate(key); - if (ret == 0) - ret = key->type->read(key, buffer, buflen); -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(key)); -+ #else - up_read(&key->sem); -+ #endif - return ret; - } - -@@ -978,7 +992,11 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) - - /* make the changes with the locks held to prevent chown/chown races */ - ret = -EACCES; -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(key)); -+ #else - down_write(&key->sem); -+ #endif - - { - bool is_privileged_op = false; -@@ -1036,19 +1054,32 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) - } - - zapowner = key->user; -+ #ifdef CONFIG_KEYP -+ iee_set_key_user(key, newowner); -+ iee_set_key_uid(key, uid); -+ #else - key->user = newowner; - key->uid = uid; -+ #endif - } - - /* change the GID */ - if (group != (gid_t) -1) -+ #ifdef CONFIG_KEYP -+ iee_set_key_gid(key, gid); -+ #else - key->gid = gid; -+ #endif - - notify_key(key, NOTIFY_KEY_SETATTR, 0); - ret = 0; - - error_put: -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(key)); -+ #else - up_write(&key->sem); -+ #endif - key_put(key); - if (zapowner) - key_user_put(zapowner); -@@ -1090,16 +1121,28 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) - - /* make the changes with the locks held to prevent chown/chmod races */ - ret = -EACCES; -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(key)); -+ #else - down_write(&key->sem); -+ #endif - - /* if we're not the sysadmin, we can only change a key that we own */ - if (uid_eq(key->uid, current_fsuid()) || capable(CAP_SYS_ADMIN)) { -+ #ifdef CONFIG_KEYP -+ iee_set_key_perm(key, perm); -+ #else - key->perm = perm; -+ #endif - notify_key(key, NOTIFY_KEY_SETATTR, 0); - ret = 0; - } - -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(key)); -+ #else - up_write(&key->sem); -+ #endif - key_put(key); - error: - return ret; -@@ -1155,7 +1198,11 @@ static int keyctl_change_reqkey_auth(struct key *key) - return -ENOMEM; - - key_put(new->request_key_auth); -+ #ifdef CONFIG_CREDP -+ iee_set_cred_request_key_auth(new, key_get(key)); -+ #else - new->request_key_auth = key_get(key); -+ #endif - - return commit_creds(new); - } -@@ -1196,7 +1243,11 @@ static long keyctl_instantiate_key_common(key_serial_t id, - if (!instkey) - goto error; - -+ #ifdef CONFIG_KEYP -+ rka = ((union key_payload *)(instkey->name_link.next))->data[0]; -+ #else - rka = instkey->payload.data[0]; -+ #endif - if (rka->target_key->serial != id) - goto error; - -@@ -1358,7 +1409,11 @@ long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error, - if (!instkey) - goto error; - -+ #ifdef CONFIG_KEYP -+ rka = ((union key_payload *)(instkey->name_link.next))->data[0]; -+ #else - rka = instkey->payload.data[0]; -+ #endif - if (rka->target_key->serial != id) - goto error; - -@@ -1432,7 +1487,11 @@ long keyctl_set_reqkey_keyring(int reqkey_defl) - } - - set: -+ #ifdef CONFIG_CREDP -+ iee_set_cred_jit_keyring(new, reqkey_defl); -+ #else - new->jit_keyring = reqkey_defl; -+ #endif - commit_creds(new); - return old_setting; - error: -@@ -1644,9 +1703,14 @@ long keyctl_session_to_parent(void) - cred = cred_alloc_blank(); - if (!cred) - goto error_keyring; -+ #ifdef CONFIG_CREDP -+ newwork = (struct rcu_head *)(cred->rcu.func); -+ iee_set_cred_session_keyring(cred, key_ref_to_ptr(keyring_r)); -+ #else - newwork = &cred->rcu; - - cred->session_keyring = key_ref_to_ptr(keyring_r); -+ #endif - keyring_r = NULL; - init_task_work(newwork, key_change_session_keyring); - -@@ -1705,7 +1769,11 @@ long keyctl_session_to_parent(void) - write_unlock_irq(&tasklist_lock); - rcu_read_unlock(); - if (oldwork) -+ #ifdef CONFIG_CREDP -+ put_cred(*(struct cred **)(oldwork + 1)); -+ #else - put_cred(container_of(oldwork, struct cred, rcu)); -+ #endif - if (newwork) - put_cred(cred); - return ret; -@@ -1814,25 +1882,45 @@ long keyctl_watch_key(key_serial_t id, int watch_queue_fd, int watch_id) - if (ret < 0) - goto err_watch; - -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(key)); -+ #else - down_write(&key->sem); -+ #endif - if (!key->watchers) { -+ #ifdef CONFIG_KEYP -+ iee_set_key_watchers(key, wlist); -+ #else - key->watchers = wlist; -+ #endif - wlist = NULL; - } - - ret = add_watch_to_object(watch, key->watchers); -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(key)); -+ #else - up_write(&key->sem); -+ #endif - - if (ret == 0) - watch = NULL; - } else { - ret = -EBADSLT; - if (key->watchers) { -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(key)); -+ #else - down_write(&key->sem); -+ #endif - ret = remove_watch_from_object(key->watchers, - wqueue, key_serial(key), - false); -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(key)); -+ #else - up_write(&key->sem); -+ #endif - } - } - -diff --git a/security/keys/keyring.c b/security/keys/keyring.c -index 4448758..3474e9b 100644 ---- a/security/keys/keyring.c -+++ b/security/keys/keyring.c -@@ -19,6 +19,10 @@ - #include <linux/assoc_array_priv.h> - #include <linux/uaccess.h> - #include <net/net_namespace.h> -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#include <asm/iee-access.h> -+#endif - #include "internal.h" - - /* -@@ -112,7 +116,11 @@ static void keyring_publish_name(struct key *keyring) - keyring->description[0] && - keyring->description[0] != '.') { - write_lock(&keyring_name_lock); -+ #ifdef CONFIG_KEYP -+ list_add_tail(&(((struct key_struct *)(keyring->name_link.prev))->name_link), &ns->keyring_name_list); -+ #else - list_add_tail(&keyring->name_link, &ns->keyring_name_list); -+ #endif - write_unlock(&keyring_name_lock); - } - } -@@ -140,7 +148,11 @@ static void keyring_free_preparse(struct key_preparsed_payload *prep) - static int keyring_instantiate(struct key *keyring, - struct key_preparsed_payload *prep) - { -+ #ifdef CONFIG_KEYP -+ assoc_array_init(&((struct key_struct *)(keyring->name_link.prev))->keys); -+ #else - assoc_array_init(&keyring->keys); -+ #endif - /* make the keyring available by name if it has one */ - keyring_publish_name(keyring); - return 0; -@@ -207,13 +219,91 @@ static void hash_key_type_and_desc(struct keyring_index_key *index_key) - index_key->hash = hash; - } - -+#ifdef CONFIG_KEYP -+static void iee_hash_key_type_and_desc(struct keyring_index_key *index_key) -+{ -+ const unsigned int level_shift = ASSOC_ARRAY_LEVEL_STEP; -+ const unsigned long fan_mask = ASSOC_ARRAY_FAN_MASK; -+ const char *description = index_key->description; -+ unsigned long hash, type; -+ u32 piece; -+ u64 acc; -+ int n, desc_len = index_key->desc_len; -+ -+ type = (unsigned long)index_key->type; -+ acc = mult_64x32_and_fold(type, desc_len + 13); -+ acc = mult_64x32_and_fold(acc, 9207); -+ piece = (unsigned long)index_key->domain_tag; -+ acc = mult_64x32_and_fold(acc, piece); -+ acc = mult_64x32_and_fold(acc, 9207); -+ -+ for (;;) { -+ n = desc_len; -+ if (n <= 0) -+ break; -+ if (n > 4) -+ n = 4; -+ piece = 0; -+ memcpy(&piece, description, n); -+ description += n; -+ desc_len -= n; -+ acc = mult_64x32_and_fold(acc, piece); -+ acc = mult_64x32_and_fold(acc, 9207); -+ } -+ -+ /* Fold the hash down to 32 bits if need be. */ -+ hash = acc; -+ if (ASSOC_ARRAY_KEY_CHUNK_SIZE == 32) -+ hash ^= acc >> 32; -+ -+ /* Squidge all the keyrings into a separate part of the tree to -+ * ordinary keys by making sure the lowest level segment in the hash is -+ * zero for keyrings and non-zero otherwise. -+ */ -+ if (index_key->type != &key_type_keyring && (hash & fan_mask) == 0) -+ hash |= (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1; -+ else if (index_key->type == &key_type_keyring && (hash & fan_mask) != 0) -+ hash = (hash + (hash << level_shift)) & ~fan_mask; -+ struct keyring_index_key tmp = *index_key; -+ -+ tmp.hash = hash; -+ iee_set_key_index_key(container_of(index_key, struct key, index_key), &tmp); -+} -+ -+static struct key_tag default_domain_tag = { .usage = REFCOUNT_INIT(1), }; -+ -+void iee_key_set_index_key(struct keyring_index_key *index_key) -+{ -+ size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc)); -+ struct keyring_index_key tmp; -+ -+ iee_memcpy(index_key->desc, index_key->description, n); -+ -+ if (!index_key->domain_tag) { -+ if (index_key->type->flags & KEY_TYPE_NET_DOMAIN) { -+ tmp = *index_key; -+ tmp.domain_tag = current->nsproxy->net_ns->key_domain; -+ iee_set_key_index_key(container_of(index_key, struct key, index_key), &tmp); -+ } else { -+ tmp = *index_key; -+ tmp.domain_tag = &default_domain_tag; -+ iee_set_key_index_key(container_of(index_key, struct key, index_key), &tmp); -+ } -+ } -+ -+ iee_hash_key_type_and_desc(index_key); -+} -+#endif -+ - /* - * Finalise an index key to include a part of the description actually in the - * index key, to set the domain tag and to calculate the hash. - */ - void key_set_index_key(struct keyring_index_key *index_key) - { -+ #ifndef CONFIG_KEYP - static struct key_tag default_domain_tag = { .usage = REFCOUNT_INIT(1), }; -+ #endif - size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc)); - - memcpy(index_key->desc, index_key->description, n); -@@ -414,9 +504,15 @@ static void keyring_destroy(struct key *keyring) - if (keyring->description) { - write_lock(&keyring_name_lock); - -+ #ifdef CONFIG_KEYP -+ if (((struct key_struct *)(keyring->name_link.prev))->name_link.next != NULL && -+ !list_empty(&(((struct key_struct *)(keyring->name_link.prev))->name_link))) -+ list_del(&(((struct key_struct *)(keyring->name_link.prev))->name_link)); -+ #else - if (keyring->name_link.next != NULL && - !list_empty(&keyring->name_link)) - list_del(&keyring->name_link); -+ #endif - - write_unlock(&keyring_name_lock); - } -@@ -428,7 +524,11 @@ static void keyring_destroy(struct key *keyring) - kfree(keyres); - } - -+ #ifdef CONFIG_KEYP -+ assoc_array_destroy(&((struct key_struct *)(keyring->name_link.prev))->keys, &keyring_assoc_array_ops); -+ #else - assoc_array_destroy(&keyring->keys, &keyring_assoc_array_ops); -+ #endif - } - - /* -@@ -442,8 +542,14 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m) - seq_puts(m, "[anon]"); - - if (key_is_positive(keyring)) { -+ #ifdef CONFIG_KEYP -+ if (((struct key_struct *)(keyring->name_link.prev))->keys.nr_leaves_on_tree != 0) -+ seq_printf(m, ": %lu", -+ ((struct key_struct *)(keyring->name_link.prev))->keys.nr_leaves_on_tree); -+ #else - if (keyring->keys.nr_leaves_on_tree != 0) - seq_printf(m, ": %lu", keyring->keys.nr_leaves_on_tree); -+ #endif - else - seq_puts(m, ": empty"); - } -@@ -494,8 +600,13 @@ static long keyring_read(const struct key *keyring, - ctx.buffer = (key_serial_t *)buffer; - ctx.buflen = buflen; - ctx.count = 0; -+ #ifdef CONFIG_KEYP -+ ret = assoc_array_iterate(&((struct key_struct *)(keyring->name_link.prev))->keys, -+ keyring_read_iterator, &ctx); -+ #else - ret = assoc_array_iterate(&keyring->keys, - keyring_read_iterator, &ctx); -+ #endif - if (ret < 0) { - kleave(" = %ld [iterate]", ret); - return ret; -@@ -503,7 +614,11 @@ static long keyring_read(const struct key *keyring, - } - - /* Return the size of the buffer needed */ -+ #ifdef CONFIG_KEYP -+ ret = ((struct key_struct *)(keyring->name_link.prev))->keys.nr_leaves_on_tree * sizeof(key_serial_t); -+ #else - ret = keyring->keys.nr_leaves_on_tree * sizeof(key_serial_t); -+ #endif - if (ret <= buflen) - kleave("= %ld [ok]", ret); - else -@@ -648,12 +763,22 @@ static int search_keyring(struct key *keyring, struct keyring_search_context *ct - if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_DIRECT) { - const void *object; - -+ #ifdef CONFIG_KEYP -+ object = assoc_array_find(&((struct key_struct *)(keyring->name_link.prev))->keys, -+ &keyring_assoc_array_ops, -+ &ctx->index_key); -+ #else - object = assoc_array_find(&keyring->keys, - &keyring_assoc_array_ops, - &ctx->index_key); -+ #endif - return object ? ctx->iterator(object, ctx) : 0; - } -+ #ifdef CONFIG_KEYP -+ return assoc_array_iterate(&((struct key_struct *)(keyring->name_link.prev))->keys, ctx->iterator, ctx); -+ #else - return assoc_array_iterate(&keyring->keys, ctx->iterator, ctx); -+ #endif - } - - /* -@@ -729,7 +854,11 @@ static bool search_nested_keyrings(struct key *keyring, - if (!(ctx->flags & KEYRING_SEARCH_RECURSE)) - goto not_this_keyring; - -+ #ifdef CONFIG_KEYP -+ ptr = READ_ONCE(((struct key_struct *)(keyring->name_link.prev))->keys.root); -+ #else - ptr = READ_ONCE(keyring->keys.root); -+ #endif - if (!ptr) - goto not_this_keyring; - -@@ -853,10 +982,17 @@ static bool search_nested_keyrings(struct key *keyring, - key = key_ref_to_ptr(ctx->result); - key_check(key); - if (!(ctx->flags & KEYRING_SEARCH_NO_UPDATE_TIME)) { -+ #ifdef CONFIG_KEYP -+ iee_set_key_last_used_at(key, ctx->now); -+ iee_set_key_last_used_at(keyring, ctx->now); -+ while (sp > 0) -+ iee_set_key_last_used_at(stack[--sp].keyring, ctx->now); -+ #else - key->last_used_at = ctx->now; - keyring->last_used_at = ctx->now; - while (sp > 0) - stack[--sp].keyring->last_used_at = ctx->now; -+ #endif - } - kleave(" = true"); - return true; -@@ -1053,7 +1189,11 @@ int keyring_restrict(key_ref_t keyring_ref, const char *type, - goto error; - } - -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(keyring)); -+ #else - down_write(&keyring->sem); -+ #endif - down_write(&keyring_serialise_restrict_sem); - - if (keyring->restrict_link) { -@@ -1061,12 +1201,20 @@ int keyring_restrict(key_ref_t keyring_ref, const char *type, - } else if (keyring_detect_restriction_cycle(keyring, restrict_link)) { - ret = -EDEADLK; - } else { -+ #ifdef CONFIG_KEYP -+ iee_set_key_restrict_link(keyring, restrict_link); -+ #else - keyring->restrict_link = restrict_link; -+ #endif - notify_key(keyring, NOTIFY_KEY_SETATTR, 0); - } - - up_write(&keyring_serialise_restrict_sem); -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(keyring)); -+ #else - up_write(&keyring->sem); -+ #endif - - if (ret < 0) { - key_put(restrict_link->key); -@@ -1106,8 +1254,13 @@ key_ref_t find_key_to_update(key_ref_t keyring_ref, - kenter("{%d},{%s,%s}", - keyring->serial, index_key->type->name, index_key->description); - -+ #ifdef CONFIG_KEYP -+ object = assoc_array_find(&((struct key_struct *)(keyring->name_link.prev))->keys, &keyring_assoc_array_ops, -+ index_key); -+ #else - object = assoc_array_find(&keyring->keys, &keyring_assoc_array_ops, - index_key); -+ #endif - - if (object) - goto found; -@@ -1151,7 +1304,16 @@ struct key *find_keyring_by_name(const char *name, bool uid_keyring) - /* Search this hash bucket for a keyring with a matching name that - * grants Search permission and that hasn't been revoked - */ -+ #ifdef CONFIG_KEYP -+ for (keyring = list_first_entry(&ns->keyring_name_list, -+ struct key_struct, name_link)->key; -+ !(&(((struct key_struct *)(keyring->name_link.prev))->name_link) == -+ (&ns->keyring_name_list)); -+ keyring = list_entry(((struct key_struct *)(keyring->name_link.prev))->name_link.next, -+ struct key_struct, name_link)->key) { -+ #else - list_for_each_entry(keyring, &ns->keyring_name_list, name_link) { -+ #endif - if (!kuid_has_mapping(ns, keyring->user->uid)) - continue; - -@@ -1174,9 +1336,15 @@ struct key *find_keyring_by_name(const char *name, bool uid_keyring) - /* we've got a match but we might end up racing with - * key_cleanup() if the keyring is currently 'dead' - * (ie. it has a zero usage count) */ -+ #ifdef CONFIG_KEYP -+ if (!iee_set_key_usage(keyring, 0, REFCOUNT_INC_NOT_ZERO)) -+ continue; -+ iee_set_key_last_used_at(keyring, ktime_get_real_seconds()); -+ #else - if (!refcount_inc_not_zero(&keyring->usage)) - continue; - keyring->last_used_at = ktime_get_real_seconds(); -+ #endif - goto out; - } - -@@ -1235,13 +1403,21 @@ static int keyring_detect_cycle(struct key *A, struct key *B) - */ - int __key_link_lock(struct key *keyring, - const struct keyring_index_key *index_key) -+ #ifdef CONFIG_KEYP -+ __acquires(&KEY_SEM(keyring)) -+ #else - __acquires(&keyring->sem) -+ #endif - __acquires(&keyring_serialise_link_lock) - { - if (keyring->type != &key_type_keyring) - return -ENOTDIR; - -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(keyring)); -+ #else - down_write(&keyring->sem); -+ #endif - - /* Serialise link/link calls to prevent parallel calls causing a cycle - * when linking two keyring in opposite orders. -@@ -1257,8 +1433,13 @@ int __key_link_lock(struct key *keyring, - */ - int __key_move_lock(struct key *l_keyring, struct key *u_keyring, - const struct keyring_index_key *index_key) -+ #ifdef CONFIG_KEYP -+ __acquires(&KEY_SEM(l_keyring)) -+ __acquires(&KEY_SEM(u_keyring)) -+ #else - __acquires(&l_keyring->sem) - __acquires(&u_keyring->sem) -+ #endif - __acquires(&keyring_serialise_link_lock) - { - if (l_keyring->type != &key_type_keyring || -@@ -1270,11 +1451,21 @@ int __key_move_lock(struct key *l_keyring, struct key *u_keyring, - * move operation. - */ - if (l_keyring < u_keyring) { -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(l_keyring)); -+ down_write_nested(&KEY_SEM(u_keyring), 1); -+ #else - down_write(&l_keyring->sem); - down_write_nested(&u_keyring->sem, 1); -+ #endif - } else { -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(u_keyring)); -+ down_write_nested(&KEY_SEM(l_keyring), 1); -+ #else - down_write(&u_keyring->sem); - down_write_nested(&l_keyring->sem, 1); -+ #endif - } - - /* Serialise link/link calls to prevent parallel calls causing a cycle -@@ -1311,10 +1502,17 @@ int __key_link_begin(struct key *keyring, - /* Create an edit script that will insert/replace the key in the - * keyring tree. - */ -+ #ifdef CONFIG_KEYP -+ edit = assoc_array_insert(&((struct key_struct *)(keyring->name_link.prev))->keys, -+ &keyring_assoc_array_ops, -+ index_key, -+ NULL); -+ #else - edit = assoc_array_insert(&keyring->keys, - &keyring_assoc_array_ops, - index_key, - NULL); -+ #endif - if (IS_ERR(edit)) { - ret = PTR_ERR(edit); - goto error; -@@ -1382,7 +1580,11 @@ void __key_link(struct key *keyring, struct key *key, - void __key_link_end(struct key *keyring, - const struct keyring_index_key *index_key, - struct assoc_array_edit *edit) -+ #ifdef CONFIG_KEYP -+ __releases(&KEY_SEM(keyring)) -+ #else - __releases(&keyring->sem) -+ #endif - __releases(&keyring_serialise_link_lock) - { - BUG_ON(index_key->type == NULL); -@@ -1395,7 +1597,11 @@ void __key_link_end(struct key *keyring, - } - assoc_array_cancel_edit(edit); - } -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(keyring)); -+ #else - up_write(&keyring->sem); -+ #endif - - if (index_key->type == &key_type_keyring) - mutex_unlock(&keyring_serialise_link_lock); -@@ -1408,8 +1614,13 @@ static int __key_link_check_restriction(struct key *keyring, struct key *key) - { - if (!keyring->restrict_link || !keyring->restrict_link->check) - return 0; -+ #ifdef CONFIG_KEYP -+ return keyring->restrict_link->check(keyring, key->type, ((union key_payload *)(key->name_link.next)), -+ keyring->restrict_link->key); -+ #else - return keyring->restrict_link->check(keyring, key->type, &key->payload, - keyring->restrict_link->key); -+ #endif - } - - /** -@@ -1469,12 +1680,20 @@ EXPORT_SYMBOL(key_link); - * Lock a keyring for unlink. - */ - static int __key_unlink_lock(struct key *keyring) -+ #ifdef CONFIG_KEYP -+ __acquires(&KEY_SEM(keyring)) -+ #else - __acquires(&keyring->sem) -+ #endif - { - if (keyring->type != &key_type_keyring) - return -ENOTDIR; - -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(keyring)); -+ #else - down_write(&keyring->sem); -+ #endif - return 0; - } - -@@ -1488,8 +1707,13 @@ static int __key_unlink_begin(struct key *keyring, struct key *key, - - BUG_ON(*_edit != NULL); - -+ #ifdef CONFIG_KEYP -+ edit = assoc_array_delete(&((struct key_struct *)(keyring->name_link.prev))->keys, &keyring_assoc_array_ops, -+ &key->index_key); -+ #else - edit = assoc_array_delete(&keyring->keys, &keyring_assoc_array_ops, - &key->index_key); -+ #endif - if (IS_ERR(edit)) - return PTR_ERR(edit); - -@@ -1518,11 +1742,19 @@ static void __key_unlink(struct key *keyring, struct key *key, - static void __key_unlink_end(struct key *keyring, - struct key *key, - struct assoc_array_edit *edit) -+ #ifdef CONFIG_KEYP -+ __releases(&KEY_SEM(keyring)) -+ #else - __releases(&keyring->sem) -+ #endif - { - if (edit) - assoc_array_cancel_edit(edit); -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(keyring)); -+ #else - up_write(&keyring->sem); -+ #endif - } - - /** -@@ -1652,9 +1884,15 @@ int keyring_clear(struct key *keyring) - if (keyring->type != &key_type_keyring) - return -ENOTDIR; - -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(keyring)); -+ -+ edit = assoc_array_clear(&((struct key_struct *)(keyring->name_link.prev))->keys, &keyring_assoc_array_ops); -+ #else - down_write(&keyring->sem); - - edit = assoc_array_clear(&keyring->keys, &keyring_assoc_array_ops); -+ #endif - if (IS_ERR(edit)) { - ret = PTR_ERR(edit); - } else { -@@ -1665,7 +1903,11 @@ int keyring_clear(struct key *keyring) - ret = 0; - } - -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(keyring)); -+ #else - up_write(&keyring->sem); -+ #endif - return ret; - } - EXPORT_SYMBOL(keyring_clear); -@@ -1679,7 +1921,11 @@ static void keyring_revoke(struct key *keyring) - { - struct assoc_array_edit *edit; - -+ #ifdef CONFIG_KEYP -+ edit = assoc_array_clear(&((struct key_struct *)(keyring->name_link.prev))->keys, &keyring_assoc_array_ops); -+ #else - edit = assoc_array_clear(&keyring->keys, &keyring_assoc_array_ops); -+ #endif - if (!IS_ERR(edit)) { - if (edit) - assoc_array_apply_edit(edit); -@@ -1725,8 +1971,13 @@ void keyring_gc(struct key *keyring, time64_t limit) - - /* scan the keyring looking for dead keys */ - rcu_read_lock(); -+ #ifdef CONFIG_KEYP -+ result = assoc_array_iterate(&((struct key_struct *)(keyring->name_link.prev))->keys, -+ keyring_gc_check_iterator, &limit); -+ #else - result = assoc_array_iterate(&keyring->keys, - keyring_gc_check_iterator, &limit); -+ #endif - rcu_read_unlock(); - if (result == true) - goto do_gc; -@@ -1736,10 +1987,17 @@ void keyring_gc(struct key *keyring, time64_t limit) - return; - - do_gc: -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(keyring)); -+ assoc_array_gc(&((struct key_struct *)(keyring->name_link.prev))->keys, &keyring_assoc_array_ops, -+ keyring_gc_select_iterator, &limit); -+ up_write(&KEY_SEM(keyring)); -+ #else - down_write(&keyring->sem); - assoc_array_gc(&keyring->keys, &keyring_assoc_array_ops, - keyring_gc_select_iterator, &limit); - up_write(&keyring->sem); -+ #endif - kleave(" [gc]"); - } - -@@ -1778,7 +2036,11 @@ void keyring_restriction_gc(struct key *keyring, struct key_type *dead_type) - } - - /* Lock the keyring to ensure that a link is not in progress */ -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(keyring)); -+ #else - down_write(&keyring->sem); -+ #endif - - keyres = keyring->restrict_link; - -@@ -1788,7 +2050,11 @@ void keyring_restriction_gc(struct key *keyring, struct key_type *dead_type) - keyres->key = NULL; - keyres->keytype = NULL; - -+ #ifdef CONFIG_KEYP -+ up_write(&KEY_SEM(keyring)); -+ #else - up_write(&keyring->sem); -+ #endif - - kleave(" [restriction gc]"); - } -diff --git a/security/keys/proc.c b/security/keys/proc.c -index 4f4e2c1..5f72240 100644 ---- a/security/keys/proc.c -+++ b/security/keys/proc.c -@@ -67,7 +67,11 @@ static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n) - - n = rb_next(n); - while (n) { -+ #ifdef CONFIG_KEYP -+ struct key *key = rb_entry(n, struct key_union, serial_node)->key; -+ #else - struct key *key = rb_entry(n, struct key, serial_node); -+ #endif - if (kuid_has_mapping(user_ns, key->user->uid)) - break; - n = rb_next(n); -@@ -82,7 +86,11 @@ static struct key *find_ge_key(struct seq_file *p, key_serial_t id) - struct key *minkey = NULL; - - while (n) { -+ #ifdef CONFIG_KEYP -+ struct key *key = rb_entry(n, struct key_union, serial_node)->key; -+ #else - struct key *key = rb_entry(n, struct key, serial_node); -+ #endif - if (id < key->serial) { - if (!minkey || minkey->serial > key->serial) - minkey = key; -@@ -102,10 +110,18 @@ static struct key *find_ge_key(struct seq_file *p, key_serial_t id) - for (;;) { - if (kuid_has_mapping(user_ns, minkey->user->uid)) - return minkey; -+ #ifdef CONFIG_KEYP -+ n = rb_next(&(((struct key_union *)(minkey->graveyard_link.next))->serial_node)); -+ #else - n = rb_next(&minkey->serial_node); -+ #endif - if (!n) - return NULL; -+ #ifdef CONFIG_KEYP -+ minkey = rb_entry(n, struct key_union, serial_node)->key; -+ #else - minkey = rb_entry(n, struct key, serial_node); -+ #endif - } - } - -@@ -123,12 +139,20 @@ static void *proc_keys_start(struct seq_file *p, loff_t *_pos) - if (!key) - return NULL; - *_pos = key->serial; -+ #ifdef CONFIG_KEYP -+ return &(((struct key_union *)(key->graveyard_link.next))->serial_node); -+ #else - return &key->serial_node; -+ #endif - } - - static inline key_serial_t key_node_serial(struct rb_node *n) - { -+ #ifdef CONFIG_KEYP -+ struct key *key = rb_entry(n, struct key_union, serial_node)->key; -+ #else - struct key *key = rb_entry(n, struct key, serial_node); -+ #endif - return key->serial; - } - -@@ -153,7 +177,11 @@ static void proc_keys_stop(struct seq_file *p, void *v) - static int proc_keys_show(struct seq_file *m, void *v) - { - struct rb_node *_p = v; -+ #ifdef CONFIG_KEYP -+ struct key *key = rb_entry(_p, struct key_union, serial_node)->key; -+ #else - struct key *key = rb_entry(_p, struct key, serial_node); -+ #endif - unsigned long flags; - key_ref_t key_ref, skey_ref; - time64_t now, expiry; -diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c -index b5d5333..321547e 100644 ---- a/security/keys/process_keys.c -+++ b/security/keys/process_keys.c -@@ -17,6 +17,12 @@ - #include <linux/uaccess.h> - #include <linux/init_task.h> - #include <keys/request_key_auth-type.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif - #include "internal.h" - - /* Session keyring create vs join semaphore */ -@@ -232,7 +238,11 @@ int install_thread_keyring_to_cred(struct cred *new) - if (IS_ERR(keyring)) - return PTR_ERR(keyring); - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_thread_keyring(new, keyring); -+ #else - new->thread_keyring = keyring; -+ #endif - return 0; - } - -@@ -279,7 +289,11 @@ int install_process_keyring_to_cred(struct cred *new) - if (IS_ERR(keyring)) - return PTR_ERR(keyring); - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_process_keyring(new, keyring); -+ #else - new->process_keyring = keyring; -+ #endif - return 0; - } - -@@ -338,7 +352,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) - - /* install the keyring */ - old = cred->session_keyring; -+ #ifdef CONFIG_CREDP -+ iee_set_cred_session_keyring(cred, keyring); -+ #else - cred->session_keyring = keyring; -+ #endif - - if (old) - key_put(old); -@@ -378,9 +396,15 @@ void key_fsuid_changed(struct cred *new_cred) - { - /* update the ownership of the thread keyring */ - if (new_cred->thread_keyring) { -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(new_cred->thread_keyring)); -+ iee_set_key_uid(new_cred->thread_keyring, new_cred->fsuid); -+ up_write(&KEY_SEM(new_cred->thread_keyring)); -+ #else - down_write(&new_cred->thread_keyring->sem); - new_cred->thread_keyring->uid = new_cred->fsuid; - up_write(&new_cred->thread_keyring->sem); -+ #endif - } - } - -@@ -391,9 +415,15 @@ void key_fsgid_changed(struct cred *new_cred) - { - /* update the ownership of the thread keyring */ - if (new_cred->thread_keyring) { -+ #ifdef CONFIG_KEYP -+ down_write(&KEY_SEM(new_cred->thread_keyring)); -+ iee_set_key_gid(new_cred->thread_keyring, new_cred->fsgid); -+ up_write(&KEY_SEM(new_cred->thread_keyring)); -+ #else - down_write(&new_cred->thread_keyring->sem); - new_cred->thread_keyring->gid = new_cred->fsgid; - up_write(&new_cred->thread_keyring->sem); -+ #endif - } - } - -@@ -557,7 +587,11 @@ key_ref_t search_process_keyrings_rcu(struct keyring_search_context *ctx) - const struct cred *cred = ctx->cred; - - if (key_validate(cred->request_key_auth) == 0) { -+ #ifdef CONFIG_KEYP -+ rka = ((union key_payload *)(ctx->cred->request_key_auth->name_link.next))->data[0]; -+ #else - rka = ctx->cred->request_key_auth->payload.data[0]; -+ #endif - - //// was search_process_keyrings() [ie. recursive] - ctx->cred = rka->cred; -@@ -725,17 +759,29 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, - if (!ctx.cred->request_key_auth) - goto error; - -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(ctx.cred->request_key_auth)); -+ #else - down_read(&ctx.cred->request_key_auth->sem); -+ #endif - if (test_bit(KEY_FLAG_REVOKED, - &ctx.cred->request_key_auth->flags)) { - key_ref = ERR_PTR(-EKEYREVOKED); - key = NULL; - } else { -+ #ifdef CONFIG_KEYP -+ rka = ((union key_payload *)(ctx.cred->request_key_auth->name_link.next))->data[0]; -+ #else - rka = ctx.cred->request_key_auth->payload.data[0]; -+ #endif - key = rka->dest_keyring; - __key_get(key); - } -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(ctx.cred->request_key_auth)); -+ #else - up_read(&ctx.cred->request_key_auth->sem); -+ #endif - if (!key) - goto error; - key_ref = make_key_ref(key, 1); -@@ -804,7 +850,11 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, - if (ret < 0) - goto invalid_key; - -+ #ifdef CONFIG_KEYP -+ iee_set_key_last_used_at(key, ktime_get_real_seconds()); -+ #else - key->last_used_at = ktime_get_real_seconds(); -+ #endif - - error: - put_cred(ctx.cred); -@@ -911,7 +961,11 @@ long join_session_keyring(const char *name) - void key_change_session_keyring(struct callback_head *twork) - { - const struct cred *old = current_cred(); -+ #ifdef CONFIG_CREDP -+ struct cred *new = *(struct cred **)(twork + 1); -+ #else - struct cred *new = container_of(twork, struct cred, rcu); -+ #endif - - if (unlikely(current->flags & PF_EXITING)) { - put_cred(new); -@@ -925,6 +979,31 @@ void key_change_session_keyring(struct callback_head *twork) - return; - } - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_uid(new, old->uid); -+ iee_set_cred_euid(new, old->euid); -+ iee_set_cred_suid(new, old->suid); -+ iee_set_cred_fsuid(new, old->fsuid); -+ iee_set_cred_gid(new, old->gid); -+ iee_set_cred_egid(new, old->egid); -+ iee_set_cred_sgid(new, old->sgid); -+ iee_set_cred_fsgid(new, old->fsgid); -+ iee_set_cred_user(new, get_uid(old->user)); -+ iee_set_cred_ucounts(new, old->ucounts); -+ iee_set_cred_user_ns(new, get_user_ns(old->user_ns)); -+ iee_set_cred_group_info(new, get_group_info(old->group_info)); -+ -+ iee_set_cred_securebits(new, old->securebits); -+ iee_set_cred_cap_inheritable(new, old->cap_inheritable); -+ iee_set_cred_cap_permitted(new, old->cap_permitted); -+ iee_set_cred_cap_effective(new, old->cap_effective); -+ iee_set_cred_cap_ambient(new, old->cap_ambient); -+ iee_set_cred_cap_bset(new, old->cap_bset); -+ -+ iee_set_cred_jit_keyring(new, old->jit_keyring); -+ iee_set_cred_thread_keyring(new, key_get(old->thread_keyring)); -+ iee_set_cred_process_keyring(new, key_get(old->process_keyring)); -+ #else - new-> uid = old-> uid; - new-> euid = old-> euid; - new-> suid = old-> suid; -@@ -948,6 +1027,7 @@ void key_change_session_keyring(struct callback_head *twork) - new->jit_keyring = old->jit_keyring; - new->thread_keyring = key_get(old->thread_keyring); - new->process_keyring = key_get(old->process_keyring); -+ #endif - - security_transfer_creds(new, old); - -diff --git a/security/keys/request_key.c b/security/keys/request_key.c -index a7673ad..26c6f60 100644 ---- a/security/keys/request_key.c -+++ b/security/keys/request_key.c -@@ -14,6 +14,9 @@ - #include <linux/keyctl.h> - #include <linux/slab.h> - #include <net/net_namespace.h> -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif - #include "internal.h" - #include <keys/request_key_auth-type.h> - -@@ -285,13 +288,21 @@ static int construct_get_dest_keyring(struct key **_dest_keyring) - case KEY_REQKEY_DEFL_REQUESTOR_KEYRING: - if (cred->request_key_auth) { - authkey = cred->request_key_auth; -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(authkey)); -+ #else - down_read(&authkey->sem); -+ #endif - rka = get_request_key_auth(authkey); - if (!test_bit(KEY_FLAG_REVOKED, - &authkey->flags)) - dest_keyring = - key_get(rka->dest_keyring); -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(authkey)); -+ #else - up_read(&authkey->sem); -+ #endif - if (dest_keyring) { - do_perm_check = false; - break; -@@ -398,7 +409,11 @@ static int construct_alloc_key(struct keyring_search_context *ctx, - if (IS_ERR(key)) - goto alloc_failed; - -+ #ifdef CONFIG_KEYP -+ iee_set_key_flag_bit(key, KEY_FLAG_USER_CONSTRUCT, SET_BIT_OP); -+ #else - set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); -+ #endif - - if (dest_keyring) { - ret = __key_link_lock(dest_keyring, &key->index_key); -diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c -index 8f33cd1..ddf86b3 100644 ---- a/security/keys/request_key_auth.c -+++ b/security/keys/request_key_auth.c -@@ -145,7 +145,11 @@ static void request_key_auth_revoke(struct key *key) - */ - static void request_key_auth_destroy(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ struct request_key_auth *rka = rcu_access_pointer(((union key_payload *)(key->name_link.next))->rcu_data0); -+ #else - struct request_key_auth *rka = rcu_access_pointer(key->payload.rcu_data0); -+ #endif - - kenter("{%d}", key->serial); - if (rka) { -@@ -184,22 +188,38 @@ struct key *request_key_auth_new(struct key *target, const char *op, - * another process */ - if (cred->request_key_auth) { - /* it is - use that instantiation context here too */ -+ #ifdef CONFIG_KEYP -+ down_read(&KEY_SEM(cred->request_key_auth)); -+ #else - down_read(&cred->request_key_auth->sem); -+ #endif - - /* if the auth key has been revoked, then the key we're - * servicing is already instantiated */ - if (test_bit(KEY_FLAG_REVOKED, - &cred->request_key_auth->flags)) { -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(cred->request_key_auth)); -+ #else - up_read(&cred->request_key_auth->sem); -+ #endif - ret = -EKEYREVOKED; - goto error_free_rka; - } - -+ #ifdef CONFIG_KEYP -+ irka = ((union key_payload *)(cred->request_key_auth->name_link.next))->data[0]; -+ #else - irka = cred->request_key_auth->payload.data[0]; -+ #endif - rka->cred = get_cred(irka->cred); - rka->pid = irka->pid; - -+ #ifdef CONFIG_KEYP -+ up_read(&KEY_SEM(cred->request_key_auth)); -+ #else - up_read(&cred->request_key_auth->sem); -+ #endif - } - else { - /* it isn't - use this process as the context */ -diff --git a/security/keys/trusted-keys/trusted_core.c b/security/keys/trusted-keys/trusted_core.c -index fee1ab2..5ef67de 100644 ---- a/security/keys/trusted-keys/trusted_core.c -+++ b/security/keys/trusted-keys/trusted_core.c -@@ -233,7 +233,11 @@ static int trusted_update(struct key *key, struct key_preparsed_payload *prep) - - if (key_is_negative(key)) - return -ENOKEY; -+ #ifdef CONFIG_KEYP -+ p = ((union key_payload *)(key->name_link.next))->data[0]; -+ #else - p = key->payload.data[0]; -+ #endif - if (!p->migratable) - return -EPERM; - if (datalen <= 0 || datalen > 32767 || !prep->data) -@@ -307,7 +311,11 @@ static long trusted_read(const struct key *key, char *buffer, - */ - static void trusted_destroy(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ kfree_sensitive(((union key_payload *)(key->name_link.next))->data[0]); -+ #else - kfree_sensitive(key->payload.data[0]); -+ #endif - } - - struct key_type key_type_trusted = { -diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c -index 749e2a4..830b0f4 100644 ---- a/security/keys/user_defined.c -+++ b/security/keys/user_defined.c -@@ -12,6 +12,9 @@ - #include <linux/err.h> - #include <keys/user-type.h> - #include <linux/uaccess.h> -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif - #include "internal.h" - - static int logon_vet_description(const char *desc); -@@ -109,7 +112,11 @@ int user_update(struct key *key, struct key_preparsed_payload *prep) - return ret; - - /* attach the new data, displacing the old */ -+ #ifdef CONFIG_KEYP -+ iee_set_key_expiry(key, prep->expiry); -+ #else - key->expiry = prep->expiry; -+ #endif - if (key_is_positive(key)) - zap = dereference_key_locked(key); - rcu_assign_keypointer(key, prep->payload.data[0]); -@@ -145,7 +152,11 @@ EXPORT_SYMBOL(user_revoke); - */ - void user_destroy(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ struct user_key_payload *upayload = ((union key_payload *)(key->name_link.next))->data[0]; -+ #else - struct user_key_payload *upayload = key->payload.data[0]; -+ #endif - - kfree_sensitive(upayload); - } -diff --git a/security/security.c b/security/security.c -index b614483..52a829b 100644 ---- a/security/security.c -+++ b/security/security.c -@@ -30,6 +30,9 @@ - #include <linux/string.h> - #include <linux/msg.h> - #include <net/flow.h> -+#ifdef CONFIG_CREDP -+#include <asm/iee-cred.h> -+#endif - - /* How many LSMs were built into the kernel? */ - #define LSM_COUNT (__end_lsm_info - __start_lsm_info) -@@ -570,11 +573,19 @@ EXPORT_SYMBOL(unregister_blocking_lsm_notifier); - static int lsm_cred_alloc(struct cred *cred, gfp_t gfp) - { - if (blob_sizes.lbs_cred == 0) { -+ #ifdef CONFIG_CREDP -+ iee_set_cred_security(cred, NULL); -+ #else - cred->security = NULL; -+ #endif - return 0; - } - -+ #ifdef CONFIG_CREDP -+ iee_set_cred_security(cred, kzalloc(blob_sizes.lbs_cred, gfp)); -+ #else - cred->security = kzalloc(blob_sizes.lbs_cred, gfp); -+ #endif - if (cred->security == NULL) - return -ENOMEM; - return 0; -@@ -2950,7 +2961,11 @@ void security_cred_free(struct cred *cred) - call_void_hook(cred_free, cred); - - kfree(cred->security); -+ #ifdef CONFIG_CREDP -+ iee_set_cred_security(cred, NULL); -+ #else - cred->security = NULL; -+ #endif - } - - /** -diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c -index 13f0087..5f601ed 100644 ---- a/security/selinux/hooks.c -+++ b/security/selinux/hooks.c -@@ -104,10 +104,21 @@ - #include "netlabel.h" - #include "audit.h" - #include "avc_ss.h" -+#ifdef CONFIG_IEE_SELINUX_P -+#include <linux/iee-func.h> -+#include <asm/iee-selinuxp.h> -+#endif -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif - - #define SELINUX_INODE_INIT_XATTRS 1 - -+#ifdef CONFIG_IEE_SELINUX_P -+struct selinux_state selinux_state __section(".iee.selinux"); -+#else - struct selinux_state selinux_state; -+#endif - - /* SECMARK reference count */ - static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); -@@ -6586,7 +6597,11 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred, - else - ksec->sid = tsec->sid; - -+ #ifdef CONFIG_KEYP -+ iee_set_key_security(k, ksec); -+ #else - k->security = ksec; -+ #endif - return 0; - } - -@@ -6594,7 +6609,11 @@ static void selinux_key_free(struct key *k) - { - struct key_security_struct *ksec = k->security; - -+ #ifdef CONFIG_KEYP -+ iee_set_key_security(k, NULL); -+ #else - k->security = NULL; -+ #endif - kfree(ksec); - } - -@@ -7285,15 +7304,52 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { - #endif - }; - -+#ifdef CONFIG_IEE_SELINUX_P -+struct kmem_cache *policy_jar; -+ -+static void policy_cache_init(void) -+{ -+ struct selinux_policy *unused; -+ -+ policy_jar = kmem_cache_create("policy_jar", sizeof(struct selinux_policy), 0, -+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ /* Test this cache */ -+ unused = kmem_cache_alloc(policy_jar, GFP_KERNEL); -+ kmem_cache_free(policy_jar, unused); -+} -+#endif -+ - static __init int selinux_init(void) - { - pr_info("SELinux: Initializing.\n"); - - memset(&selinux_state, 0, sizeof(selinux_state)); -+#ifdef CONFIG_IEE_SELINUX_P -+ WRITE_ONCE(selinux_state.enforcing, selinux_enforcing_boot); -+#else - enforcing_set(selinux_enforcing_boot); -+#endif - selinux_avc_init(); -+ -+#ifdef CONFIG_IEE_SELINUX_P -+ /* Put selinux_status inside IEE. */ -+ /* Prepare mutex lock and write the ptr to mutex->owner. */ -+ struct mutex *status_lock = kzalloc(GFP_KERNEL, sizeof(struct mutex)); -+ struct mutex *policy_mutex = kzalloc(GFP_KERNEL, sizeof(struct mutex)); -+ -+ mutex_init(status_lock); -+ mutex_init(policy_mutex); -+ selinux_state.status_lock.owner.counter = (s64)status_lock; -+ selinux_state.policy_mutex.owner.counter = (s64)policy_mutex; -+ -+ /* Setting lm addr to be RO, IEE addr valid. */ -+ iee_set_logical_mem_ro((unsigned long)&selinux_state); -+ set_iee_page((unsigned long)__va(__pa_symbol(&selinux_state)), 0); -+ policy_cache_init(); -+#else - mutex_init(&selinux_state.status_lock); - mutex_init(&selinux_state.policy_mutex); -+#endif - - /* Set the security state for the initial task. */ - cred_init_security(); -diff --git a/security/selinux/ima.c b/security/selinux/ima.c -index aa34da9..022b3ce 100644 ---- a/security/selinux/ima.c -+++ b/security/selinux/ima.c -@@ -12,6 +12,10 @@ - #include "security.h" - #include "ima.h" - -+#ifdef CONFIG_IEE_SELINUX_P -+#include <asm/iee-selinuxp.h> -+#endif -+ - /* - * selinux_ima_collect_state - Read selinux configuration settings - * -@@ -74,7 +78,11 @@ void selinux_ima_measure_state_locked(void) - size_t policy_len; - int rc = 0; - -+#ifdef CONFIG_IEE_SELINUX_P -+ lockdep_assert_held(iee_get_selinux_policy_lock()); -+#else - lockdep_assert_held(&selinux_state.policy_mutex); -+#endif - - state_str = selinux_ima_collect_state(); - if (!state_str) { -@@ -112,9 +120,21 @@ void selinux_ima_measure_state_locked(void) - */ - void selinux_ima_measure_state(void) - { -+#ifdef CONFIG_IEE_SELINUX_P -+ lockdep_assert_not_held(iee_get_selinux_policy_lock()); -+#else - lockdep_assert_not_held(&selinux_state.policy_mutex); -+#endif - -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_lock(iee_get_selinux_policy_lock()); -+#else - mutex_lock(&selinux_state.policy_mutex); -+#endif - selinux_ima_measure_state_locked(); -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_unlock(iee_get_selinux_policy_lock()); -+#else - mutex_unlock(&selinux_state.policy_mutex); -+#endif - } -diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h -index a9de89a..863cda4 100644 ---- a/security/selinux/include/security.h -+++ b/security/selinux/include/security.h -@@ -113,11 +113,15 @@ static inline bool selinux_initialized(void) - return smp_load_acquire(&selinux_state.initialized); - } - -+#ifdef CONFIG_IEE_SELINUX_P -+extern void selinux_mark_initialized(void); -+#else - static inline void selinux_mark_initialized(void) - { - /* do a synchronized write to avoid race conditions */ - smp_store_release(&selinux_state.initialized, true); - } -+#endif - - #ifdef CONFIG_SECURITY_SELINUX_DEVELOP - static inline bool enforcing_enabled(void) -@@ -125,10 +129,15 @@ static inline bool enforcing_enabled(void) - return READ_ONCE(selinux_state.enforcing); - } - -+#ifdef CONFIG_IEE_SELINUX_P -+extern void enforcing_set(bool value); -+#else - static inline void enforcing_set(bool value) - { - WRITE_ONCE(selinux_state.enforcing, value); - } -+#endif -+ - #else - static inline bool enforcing_enabled(void) - { -diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c -index 2c23a5a..a7007c5 100644 ---- a/security/selinux/selinuxfs.c -+++ b/security/selinux/selinuxfs.c -@@ -32,6 +32,10 @@ - #include <linux/kobject.h> - #include <linux/ctype.h> - -+#ifdef CONFIG_IEE_SELINUX_P -+#include <asm/iee-selinuxp.h> -+#endif -+ - /* selinuxfs pseudo filesystem for exporting the security policy API. - Based on the proc code and the fs/nfsd/nfsctl.c code. */ - -@@ -371,7 +375,11 @@ static int sel_open_policy(struct inode *inode, struct file *filp) - - BUG_ON(filp->private_data); - -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_lock(iee_get_selinux_policy_lock()); -+#else - mutex_lock(&selinux_state.policy_mutex); -+#endif - - rc = avc_has_perm(current_sid(), SECINITSID_SECURITY, - SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL); -@@ -401,11 +409,19 @@ static int sel_open_policy(struct inode *inode, struct file *filp) - - filp->private_data = plm; - -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_unlock(iee_get_selinux_policy_lock()); -+#else - mutex_unlock(&selinux_state.policy_mutex); -+#endif - - return 0; - err: -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_unlock(iee_get_selinux_policy_lock()); -+#else - mutex_unlock(&selinux_state.policy_mutex); -+#endif - - if (plm) - vfree(plm->data); -@@ -587,7 +603,11 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, - ssize_t length; - void *data = NULL; - -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_lock(iee_get_selinux_policy_lock()); -+#else - mutex_lock(&selinux_state.policy_mutex); -+#endif - - length = avc_has_perm(current_sid(), SECINITSID_SECURITY, - SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL); -@@ -630,7 +650,11 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, - from_kuid(&init_user_ns, audit_get_loginuid(current)), - audit_get_sessionid(current)); - out: -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_unlock(iee_get_selinux_policy_lock()); -+#else - mutex_unlock(&selinux_state.policy_mutex); -+#endif - vfree(data); - return length; - } -@@ -1214,7 +1238,11 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, - unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK; - const char *name = filep->f_path.dentry->d_name.name; - -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_lock(iee_get_selinux_policy_lock()); -+#else - mutex_lock(&selinux_state.policy_mutex); -+#endif - - ret = -EINVAL; - if (index >= fsi->bool_num || strcmp(name, -@@ -1233,14 +1261,22 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, - } - length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, - fsi->bool_pending_values[index]); -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_unlock(iee_get_selinux_policy_lock()); -+#else - mutex_unlock(&selinux_state.policy_mutex); -+#endif - ret = simple_read_from_buffer(buf, count, ppos, page, length); - out_free: - free_page((unsigned long)page); - return ret; - - out_unlock: -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_unlock(iee_get_selinux_policy_lock()); -+#else - mutex_unlock(&selinux_state.policy_mutex); -+#endif - goto out_free; - } - -@@ -1265,7 +1301,11 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, - if (IS_ERR(page)) - return PTR_ERR(page); - -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_lock(iee_get_selinux_policy_lock()); -+#else - mutex_lock(&selinux_state.policy_mutex); -+#endif - - length = avc_has_perm(current_sid(), SECINITSID_SECURITY, - SECCLASS_SECURITY, SECURITY__SETBOOL, -@@ -1289,7 +1329,11 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, - length = count; - - out: -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_unlock(iee_get_selinux_policy_lock()); -+#else - mutex_unlock(&selinux_state.policy_mutex); -+#endif - kfree(page); - return length; - } -@@ -1320,7 +1364,11 @@ static ssize_t sel_commit_bools_write(struct file *filep, - if (IS_ERR(page)) - return PTR_ERR(page); - -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_lock(iee_get_selinux_policy_lock()); -+#else - mutex_lock(&selinux_state.policy_mutex); -+#endif - - length = avc_has_perm(current_sid(), SECINITSID_SECURITY, - SECCLASS_SECURITY, SECURITY__SETBOOL, -@@ -1341,7 +1389,11 @@ static ssize_t sel_commit_bools_write(struct file *filep, - length = count; - - out: -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_unlock(iee_get_selinux_policy_lock()); -+#else - mutex_unlock(&selinux_state.policy_mutex); -+#endif - kfree(page); - return length; - } -diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c -index 379ac7b..0b5638a 100644 ---- a/security/selinux/ss/services.c -+++ b/security/selinux/ss/services.c -@@ -68,6 +68,10 @@ - #include "policycap_names.h" - #include "ima.h" - -+#ifdef CONFIG_IEE_SELINUX_P -+#include <asm/iee-selinuxp.h> -+#endif -+ - struct selinux_policy_convert_data { - struct convert_context_args args; - struct sidtab_convert_params sidtab_params; -@@ -2108,9 +2112,14 @@ static void security_load_policycaps(struct selinux_policy *policy) - - p = &policy->policydb; - -+#ifdef CONFIG_IEE_SELINUX_P -+ for (i = 0; i < ARRAY_SIZE(selinux_state.policycap); i++) -+ iee_set_sel_policy_cap(i, ebitmap_get_bit(&p->policycaps, i)); -+#else - for (i = 0; i < ARRAY_SIZE(selinux_state.policycap); i++) - WRITE_ONCE(selinux_state.policycap[i], - ebitmap_get_bit(&p->policycaps, i)); -+#endif - - for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++) - pr_info("SELinux: policy capability %s=%d\n", -@@ -2173,6 +2182,9 @@ void selinux_policy_commit(struct selinux_load_state *load_state) - { - struct selinux_state *state = &selinux_state; - struct selinux_policy *oldpolicy, *newpolicy = load_state->policy; -+#ifdef CONFIG_IEE_SELINUX_P -+ struct selinux_policy *temppolicy; -+#endif - unsigned long flags; - u32 seqno; - -@@ -2197,10 +2209,20 @@ void selinux_policy_commit(struct selinux_load_state *load_state) - /* Install the new policy. */ - if (oldpolicy) { - sidtab_freeze_begin(oldpolicy->sidtab, &flags); -+#ifdef CONFIG_IEE_SELINUX_P -+ iee_sel_rcu_assign_policy(newpolicy, kmem_cache_alloc(policy_jar, GFP_KERNEL)); -+ kfree(newpolicy); -+#else - rcu_assign_pointer(state->policy, newpolicy); -+#endif - sidtab_freeze_end(oldpolicy->sidtab, &flags); - } else { -+#ifdef CONFIG_IEE_SELINUX_P -+ iee_sel_rcu_assign_policy(newpolicy, kmem_cache_alloc(policy_jar, GFP_KERNEL)); -+ kfree(newpolicy); -+#else - rcu_assign_pointer(state->policy, newpolicy); -+#endif - } - - /* Load the policycaps from the new policy */ -@@ -2218,7 +2240,20 @@ void selinux_policy_commit(struct selinux_load_state *load_state) - - /* Free the old policy */ - synchronize_rcu(); -+#ifdef CONFIG_IEE_SELINUX_P -+ /* -+ * Normal free process includes setting freed objects pointers to be NULL, however it -+ * would be hard as old policy is already inside IEE. So Make a kernel copy of the old -+ * policy to free objects it points to. -+ */ -+ if (oldpolicy) { -+ temppolicy = kmemdup(oldpolicy, sizeof(*temppolicy), GFP_KERNEL); -+ selinux_policy_free(temppolicy); -+ kfree(oldpolicy); -+ } -+#else - selinux_policy_free(oldpolicy); -+#endif - kfree(load_state->convert_data); - - /* Notify others of the policy change */ -@@ -3016,6 +3051,9 @@ int security_set_bools(u32 len, int *values) - { - struct selinux_state *state = &selinux_state; - struct selinux_policy *newpolicy, *oldpolicy; -+#ifdef CONFIG_IEE_SELINUX_P -+ struct selinux_policy *temppolicy; -+#endif - int rc; - u32 i, seqno = 0; - -@@ -3069,7 +3107,13 @@ int security_set_bools(u32 len, int *values) - seqno = newpolicy->latest_granting; - - /* Install the new policy */ -+#ifdef CONFIG_IEE_SELINUX_P -+ iee_sel_rcu_assign_policy(newpolicy, kmem_cache_alloc(policy_jar, GFP_KERNEL)); -+ kfree(newpolicy); -+#else -+ /* Install the new policy */ - rcu_assign_pointer(state->policy, newpolicy); -+#endif - - /* - * Free the conditional portions of the old policydb -@@ -3077,7 +3121,20 @@ int security_set_bools(u32 len, int *values) - * structure itself but not what it references. - */ - synchronize_rcu(); -+#ifdef CONFIG_IEE_SELINUX_P -+ /* -+ * Normal free process includes setting freed objects pointers to be NULL, however it -+ * would be hard as old policy is already inside IEE. So Make a kernel copy of the old -+ * policy to free objects it points to. -+ */ -+ temppolicy = kmemdup(oldpolicy, sizeof(*temppolicy), GFP_KERNEL); -+ if (!temppolicy) -+ return -ENOMEM; -+ selinux_policy_cond_free(temppolicy); -+ kfree(oldpolicy); -+#else - selinux_policy_cond_free(oldpolicy); -+#endif - - /* Notify others of the policy change */ - selinux_notify_policy_change(seqno); -diff --git a/security/selinux/status.c b/security/selinux/status.c -index dffca22..6429656 100644 ---- a/security/selinux/status.c -+++ b/security/selinux/status.c -@@ -13,6 +13,10 @@ - #include "avc.h" - #include "security.h" - -+#ifdef CONFIG_IEE_SELINUX_P -+#include <asm/iee-selinuxp.h> -+#endif -+ - /* - * The selinux_status_page shall be exposed to userspace applications - * using mmap interface on /selinux/status. -@@ -44,9 +48,17 @@ struct page *selinux_kernel_status_page(void) - struct selinux_kernel_status *status; - struct page *result = NULL; - -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_lock(iee_get_selinux_status_lock()); -+#else - mutex_lock(&selinux_state.status_lock); -+#endif - if (!selinux_state.status_page) { -+ #ifdef CONFIG_IEE_SELINUX_P -+ iee_set_selinux_status_pg(alloc_page(GFP_KERNEL|__GFP_ZERO)); -+ #else - selinux_state.status_page = alloc_page(GFP_KERNEL|__GFP_ZERO); -+ #endif - - if (selinux_state.status_page) { - status = page_address(selinux_state.status_page); -@@ -66,7 +78,11 @@ struct page *selinux_kernel_status_page(void) - } - } - result = selinux_state.status_page; -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_unlock(iee_get_selinux_status_lock()); -+#else - mutex_unlock(&selinux_state.status_lock); -+#endif - - return result; - } -@@ -80,7 +96,11 @@ void selinux_status_update_setenforce(bool enforcing) - { - struct selinux_kernel_status *status; - -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_lock(iee_get_selinux_status_lock()); -+#else - mutex_lock(&selinux_state.status_lock); -+#endif - if (selinux_state.status_page) { - status = page_address(selinux_state.status_page); - -@@ -92,7 +112,11 @@ void selinux_status_update_setenforce(bool enforcing) - smp_wmb(); - status->sequence++; - } -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_unlock(iee_get_selinux_status_lock()); -+#else - mutex_unlock(&selinux_state.status_lock); -+#endif - } - - /* -@@ -105,7 +129,11 @@ void selinux_status_update_policyload(u32 seqno) - { - struct selinux_kernel_status *status; - -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_lock(iee_get_selinux_status_lock()); -+#else - mutex_lock(&selinux_state.status_lock); -+#endif - if (selinux_state.status_page) { - status = page_address(selinux_state.status_page); - -@@ -118,5 +146,9 @@ void selinux_status_update_policyload(u32 seqno) - smp_wmb(); - status->sequence++; - } -+#ifdef CONFIG_IEE_SELINUX_P -+ mutex_unlock(iee_get_selinux_status_lock()); -+#else - mutex_unlock(&selinux_state.status_lock); -+#endif - } -diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c -index 54d84aa..2d308d8 100644 ---- a/security/smack/smack_lsm.c -+++ b/security/smack/smack_lsm.c -@@ -44,6 +44,9 @@ - #include <linux/fs_parser.h> - #include <linux/watch_queue.h> - #include <linux/io_uring.h> -+#ifdef CONFIG_KEYP -+#include <asm/iee-key.h> -+#endif - #include "smack.h" - - #define TRANS_TRUE "TRUE" -@@ -4406,7 +4409,11 @@ static int smack_key_alloc(struct key *key, const struct cred *cred, - { - struct smack_known *skp = smk_of_task(smack_cred(cred)); - -+ #ifdef CONFIG_KEYP -+ iee_set_key_security(key, skp); -+ #else - key->security = skp; -+ #endif - return 0; - } - -@@ -4418,7 +4425,11 @@ static int smack_key_alloc(struct key *key, const struct cred *cred, - */ - static void smack_key_free(struct key *key) - { -+ #ifdef CONFIG_KEYP -+ iee_set_key_security(key, NULL); -+ #else - key->security = NULL; -+ #endif - } - - /** -diff --git a/tools/include/uapi/asm/bitsperlong.h b/tools/include/uapi/asm/bitsperlong.h -index c65267a..4be3d00 100644 ---- a/tools/include/uapi/asm/bitsperlong.h -+++ b/tools/include/uapi/asm/bitsperlong.h -@@ -13,6 +13,8 @@ - #include "../../../arch/ia64/include/uapi/asm/bitsperlong.h" - #elif defined(__alpha__) - #include "../../../arch/alpha/include/uapi/asm/bitsperlong.h" -+#elif defined(__loongarch__) -+#include "../../../arch/loongarch/include/uapi/asm/bitsperlong.h" - #else - #include <asm-generic/bitsperlong.h> - #endif -diff --git a/tools/objtool/arch/loongarch/decode.c b/tools/objtool/arch/loongarch/decode.c -index aee479d..69b6699 100644 ---- a/tools/objtool/arch/loongarch/decode.c -+++ b/tools/objtool/arch/loongarch/decode.c -@@ -122,7 +122,7 @@ static bool decode_insn_reg2i12_fomat(union loongarch_instruction inst, - switch (inst.reg2i12_format.opcode) { - case addid_op: - if ((inst.reg2i12_format.rd == CFI_SP) || (inst.reg2i12_format.rj == CFI_SP)) { -- /* addi.d sp,sp,si12 or addi.d fp,sp,si12 */ -+ /* addi.d sp,sp,si12 or addi.d fp,sp,si12 or addi.d sp,fp,si12 */ - insn->immediate = sign_extend64(inst.reg2i12_format.immediate, 11); - ADD_OP(op) { - op->src.type = OP_SRC_ADD; -@@ -132,6 +132,15 @@ static bool decode_insn_reg2i12_fomat(union loongarch_instruction inst, - op->dest.reg = inst.reg2i12_format.rd; - } - } -+ if ((inst.reg2i12_format.rd == CFI_SP) && (inst.reg2i12_format.rj == CFI_FP)) { -+ /* addi.d sp,fp,si12 */ -+ struct symbol *func = find_func_containing(insn->sec, insn->offset); -+ -+ if (!func) -+ return false; -+ -+ func->frame_pointer = true; -+ } - break; - case ldd_op: - if (inst.reg2i12_format.rj == CFI_SP) { -diff --git a/tools/objtool/arch/x86/Build b/tools/objtool/arch/x86/Build -index 9f7869b..3dedb2f 100644 ---- a/tools/objtool/arch/x86/Build -+++ b/tools/objtool/arch/x86/Build -@@ -1,5 +1,6 @@ - objtool-y += special.o - objtool-y += decode.o -+objtool-y += orc.o - - inat_tables_script = ../arch/x86/tools/gen-insn-attr-x86.awk - inat_tables_maps = ../arch/x86/lib/x86-opcode-map.txt -diff --git a/tools/objtool/arch/x86/orc.c b/tools/objtool/arch/x86/orc.c -new file mode 100644 -index 0000000..b6cd943 ---- /dev/null -+++ b/tools/objtool/arch/x86/orc.c -@@ -0,0 +1,188 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+#include <linux/objtool_types.h> -+#include <asm/orc_types.h> -+ -+#include <objtool/check.h> -+#include <objtool/orc.h> -+#include <objtool/warn.h> -+#include <objtool/endianness.h> -+ -+int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn) -+{ -+ struct cfi_reg *bp = &cfi->regs[CFI_BP]; -+ -+ memset(orc, 0, sizeof(*orc)); -+ -+ if (!cfi) { -+ /* -+ * This is usually either unreachable nops/traps (which don't -+ * trigger unreachable instruction warnings), or -+ * STACK_FRAME_NON_STANDARD functions. -+ */ -+ orc->type = ORC_TYPE_UNDEFINED; -+ return 0; -+ } -+ -+ switch (cfi->type) { -+ case UNWIND_HINT_TYPE_UNDEFINED: -+ orc->type = ORC_TYPE_UNDEFINED; -+ return 0; -+ case UNWIND_HINT_TYPE_END_OF_STACK: -+ orc->type = ORC_TYPE_END_OF_STACK; -+ return 0; -+ case UNWIND_HINT_TYPE_CALL: -+ orc->type = ORC_TYPE_CALL; -+ break; -+ case UNWIND_HINT_TYPE_REGS: -+ orc->type = ORC_TYPE_REGS; -+ break; -+ case UNWIND_HINT_TYPE_REGS_PARTIAL: -+ orc->type = ORC_TYPE_REGS_PARTIAL; -+ break; -+ default: -+ WARN_INSN(insn, "unknown unwind hint type %d", cfi->type); -+ return -1; -+ } -+ -+ orc->signal = cfi->signal; -+ -+ switch (cfi->cfa.base) { -+ case CFI_SP: -+ orc->sp_reg = ORC_REG_SP; -+ break; -+ case CFI_SP_INDIRECT: -+ orc->sp_reg = ORC_REG_SP_INDIRECT; -+ break; -+ case CFI_BP: -+ orc->sp_reg = ORC_REG_BP; -+ break; -+ case CFI_BP_INDIRECT: -+ orc->sp_reg = ORC_REG_BP_INDIRECT; -+ break; -+ case CFI_R10: -+ orc->sp_reg = ORC_REG_R10; -+ break; -+ case CFI_R13: -+ orc->sp_reg = ORC_REG_R13; -+ break; -+ case CFI_DI: -+ orc->sp_reg = ORC_REG_DI; -+ break; -+ case CFI_DX: -+ orc->sp_reg = ORC_REG_DX; -+ break; -+ default: -+ WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); -+ return -1; -+ } -+ -+ switch (bp->base) { -+ case CFI_UNDEFINED: -+ orc->bp_reg = ORC_REG_UNDEFINED; -+ break; -+ case CFI_CFA: -+ orc->bp_reg = ORC_REG_PREV_SP; -+ break; -+ case CFI_BP: -+ orc->bp_reg = ORC_REG_BP; -+ break; -+ default: -+ WARN_INSN(insn, "unknown BP base reg %d", bp->base); -+ return -1; -+ } -+ -+ orc->sp_offset = cfi->cfa.offset; -+ orc->bp_offset = bp->offset; -+ -+ return 0; -+} -+ -+int write_orc_entry(struct elf *elf, struct section *orc_sec, -+ struct section *ip_sec, unsigned int idx, -+ struct section *insn_sec, unsigned long insn_off, -+ struct orc_entry *o) -+{ -+ struct orc_entry *orc; -+ -+ /* populate ORC data */ -+ orc = (struct orc_entry *)orc_sec->data->d_buf + idx; -+ memcpy(orc, o, sizeof(*orc)); -+ orc->sp_offset = bswap_if_needed(elf, orc->sp_offset); -+ orc->bp_offset = bswap_if_needed(elf, orc->bp_offset); -+ -+ /* populate reloc for ip */ -+ if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx, -+ insn_sec, insn_off)) -+ return -1; -+ -+ return 0; -+} -+ -+static const char *reg_name(unsigned int reg) -+{ -+ switch (reg) { -+ case ORC_REG_PREV_SP: -+ return "prevsp"; -+ case ORC_REG_DX: -+ return "dx"; -+ case ORC_REG_DI: -+ return "di"; -+ case ORC_REG_BP: -+ return "bp"; -+ case ORC_REG_SP: -+ return "sp"; -+ case ORC_REG_R10: -+ return "r10"; -+ case ORC_REG_R13: -+ return "r13"; -+ case ORC_REG_BP_INDIRECT: -+ return "bp(ind)"; -+ case ORC_REG_SP_INDIRECT: -+ return "sp(ind)"; -+ default: -+ return "?"; -+ } -+} -+ -+static const char *orc_type_name(unsigned int type) -+{ -+ switch (type) { -+ case ORC_TYPE_UNDEFINED: -+ return "(und)"; -+ case ORC_TYPE_END_OF_STACK: -+ return "end"; -+ case ORC_TYPE_CALL: -+ return "call"; -+ case ORC_TYPE_REGS: -+ return "regs"; -+ case ORC_TYPE_REGS_PARTIAL: -+ return "regs (partial)"; -+ default: -+ return "?"; -+ } -+} -+ -+static void print_reg(unsigned int reg, int offset) -+{ -+ if (reg == ORC_REG_BP_INDIRECT) -+ printf("(bp%+d)", offset); -+ else if (reg == ORC_REG_SP_INDIRECT) -+ printf("(sp)%+d", offset); -+ else if (reg == ORC_REG_UNDEFINED) -+ printf("(und)"); -+ else -+ printf("%s%+d", reg_name(reg), offset); -+} -+ -+void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i) -+{ -+ printf("type:%s", orc_type_name(orc[i].type)); -+ -+ printf(" sp:"); -+ print_reg(orc[i].sp_reg, bswap_if_needed(dummy_elf, orc[i].sp_offset)); -+ -+ printf(" bp:"); -+ print_reg(orc[i].bp_reg, bswap_if_needed(dummy_elf, orc[i].bp_offset)); -+ -+ printf(" signal:%d\n", orc[i].signal); -+} -diff --git a/tools/objtool/check.c b/tools/objtool/check.c -index e255ac8..1d3be9c 100644 ---- a/tools/objtool/check.c -+++ b/tools/objtool/check.c -@@ -20,6 +20,7 @@ - #include <linux/hashtable.h> - #include <linux/kernel.h> - #include <linux/static_call_types.h> -+#include <linux/string.h> - - struct alternative { - struct alternative *next; -@@ -584,7 +585,7 @@ static int add_dead_ends(struct objtool_file *file) - struct section *rsec; - struct reloc *reloc; - struct instruction *insn; -- s64 addend; -+ unsigned long offset; - - /* - * Check for manually annotated dead ends. -@@ -594,27 +595,28 @@ static int add_dead_ends(struct objtool_file *file) - goto reachable; - - for_each_reloc(rsec, reloc) { -- -- if (reloc->sym->type != STT_SECTION) { -+ if (reloc->sym->type == STT_SECTION) { -+ offset = reloc_addend(reloc); -+ } else if (reloc->sym->local_label) { -+ offset = reloc->sym->offset; -+ } else { - WARN("unexpected relocation symbol type in %s", rsec->name); - return -1; - } - -- addend = reloc_addend(reloc); -- -- insn = find_insn(file, reloc->sym->sec, addend); -+ insn = find_insn(file, reloc->sym->sec, offset); - if (insn) - insn = prev_insn_same_sec(file, insn); -- else if (addend == reloc->sym->sec->sh.sh_size) { -+ else if (offset == reloc->sym->sec->sh.sh_size) { - insn = find_last_insn(file, reloc->sym->sec); - if (!insn) { - WARN("can't find unreachable insn at %s+0x%" PRIx64, -- reloc->sym->sec->name, addend); -+ reloc->sym->sec->name, offset); - return -1; - } - } else { - WARN("can't find unreachable insn at %s+0x%" PRIx64, -- reloc->sym->sec->name, addend); -+ reloc->sym->sec->name, offset); - return -1; - } - -@@ -633,27 +635,28 @@ static int add_dead_ends(struct objtool_file *file) - return 0; - - for_each_reloc(rsec, reloc) { -- -- if (reloc->sym->type != STT_SECTION) { -+ if (reloc->sym->type == STT_SECTION) { -+ offset = reloc_addend(reloc); -+ } else if (reloc->sym->local_label) { -+ offset = reloc->sym->offset; -+ } else { - WARN("unexpected relocation symbol type in %s", rsec->name); - return -1; - } - -- addend = reloc_addend(reloc); -- -- insn = find_insn(file, reloc->sym->sec, addend); -+ insn = find_insn(file, reloc->sym->sec, offset); - if (insn) - insn = prev_insn_same_sec(file, insn); -- else if (addend == reloc->sym->sec->sh.sh_size) { -+ else if (offset == reloc->sym->sec->sh.sh_size) { - insn = find_last_insn(file, reloc->sym->sec); - if (!insn) { - WARN("can't find reachable insn at %s+0x%" PRIx64, -- reloc->sym->sec->name, addend); -+ reloc->sym->sec->name, offset); - return -1; - } - } else { - WARN("can't find reachable insn at %s+0x%" PRIx64, -- reloc->sym->sec->name, addend); -+ reloc->sym->sec->name, offset); - return -1; - } - -@@ -2208,6 +2211,7 @@ static int read_unwind_hints(struct objtool_file *file) - struct unwind_hint *hint; - struct instruction *insn; - struct reloc *reloc; -+ unsigned long offset; - int i; - - sec = find_section_by_name(file->elf, ".discard.unwind_hints"); -@@ -2235,7 +2239,16 @@ static int read_unwind_hints(struct objtool_file *file) - return -1; - } - -- insn = find_insn(file, reloc->sym->sec, reloc_addend(reloc)); -+ if (reloc->sym->type == STT_SECTION) { -+ offset = reloc_addend(reloc); -+ } else if (reloc->sym->local_label) { -+ offset = reloc->sym->offset; -+ } else { -+ WARN("unexpected relocation symbol type in %s", sec->rsec->name); -+ return -1; -+ } -+ -+ insn = find_insn(file, reloc->sym->sec, offset); - if (!insn) { - WARN("can't find insn for unwind_hints[%d]", i); - return -1; -@@ -2506,6 +2519,9 @@ static int classify_symbols(struct objtool_file *file) - struct symbol *func; - - for_each_sym(file, func) { -+ if (func->type == STT_NOTYPE && strstarts(func->name, ".L")) -+ func->local_label = true; -+ - if (func->bind != STB_GLOBAL) - continue; - -@@ -2959,10 +2975,27 @@ static int update_cfi_state(struct instruction *insn, - break; - } - -- if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) { -+ if (op->dest.reg == CFI_BP && op->src.reg == CFI_SP && -+ insn->sym->frame_pointer) { -+ /* addi.d fp,sp,imm on LoongArch */ -+ if (cfa->base == CFI_SP && cfa->offset == op->src.offset) { -+ cfa->base = CFI_BP; -+ cfa->offset = 0; -+ } -+ break; -+ } - -- /* lea disp(%rbp), %rsp */ -- cfi->stack_size = -(op->src.offset + regs[CFI_BP].offset); -+ if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) { -+ /* addi.d sp,fp,imm on LoongArch */ -+ if (cfa->base == CFI_BP && cfa->offset == 0) { -+ if (insn->sym->frame_pointer) { -+ cfa->base = CFI_SP; -+ cfa->offset = -op->src.offset; -+ } -+ } else { -+ /* lea disp(%rbp), %rsp */ -+ cfi->stack_size = -(op->src.offset + regs[CFI_BP].offset); -+ } - break; - } - -diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h -index 9f71e98..d7e815c 100644 ---- a/tools/objtool/include/objtool/elf.h -+++ b/tools/objtool/include/objtool/elf.h -@@ -67,6 +67,8 @@ struct symbol { - u8 profiling_func : 1; - u8 warned : 1; - u8 embedded_insn : 1; -+ u8 local_label : 1; -+ u8 frame_pointer : 1; - struct list_head pv_target; - struct reloc *relocs; - }; -diff --git a/tools/objtool/include/objtool/orc.h b/tools/objtool/include/objtool/orc.h -new file mode 100644 -index 0000000..15a32de ---- /dev/null -+++ b/tools/objtool/include/objtool/orc.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+#ifndef _OBJTOOL_ORC_H -+#define _OBJTOOL_ORC_H -+ -+#include <objtool/check.h> -+ -+int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruction *insn); -+void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i); -+int write_orc_entry(struct elf *elf, struct section *orc_sec, -+ struct section *ip_sec, unsigned int idx, -+ struct section *insn_sec, unsigned long insn_off, -+ struct orc_entry *o); -+ -+#endif /* _OBJTOOL_ORC_H */ -diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c -index 0e183bb..a62247ef 100644 ---- a/tools/objtool/orc_dump.c -+++ b/tools/objtool/orc_dump.c -@@ -6,65 +6,10 @@ - #include <unistd.h> - #include <asm/orc_types.h> - #include <objtool/objtool.h> -+#include <objtool/orc.h> - #include <objtool/warn.h> - #include <objtool/endianness.h> - --static const char *reg_name(unsigned int reg) --{ -- switch (reg) { -- case ORC_REG_PREV_SP: -- return "prevsp"; -- case ORC_REG_DX: -- return "dx"; -- case ORC_REG_DI: -- return "di"; -- case ORC_REG_BP: -- return "bp"; -- case ORC_REG_SP: -- return "sp"; -- case ORC_REG_R10: -- return "r10"; -- case ORC_REG_R13: -- return "r13"; -- case ORC_REG_BP_INDIRECT: -- return "bp(ind)"; -- case ORC_REG_SP_INDIRECT: -- return "sp(ind)"; -- default: -- return "?"; -- } --} -- --static const char *orc_type_name(unsigned int type) --{ -- switch (type) { -- case ORC_TYPE_UNDEFINED: -- return "(und)"; -- case ORC_TYPE_END_OF_STACK: -- return "end"; -- case ORC_TYPE_CALL: -- return "call"; -- case ORC_TYPE_REGS: -- return "regs"; -- case ORC_TYPE_REGS_PARTIAL: -- return "regs (partial)"; -- default: -- return "?"; -- } --} -- --static void print_reg(unsigned int reg, int offset) --{ -- if (reg == ORC_REG_BP_INDIRECT) -- printf("(bp%+d)", offset); -- else if (reg == ORC_REG_SP_INDIRECT) -- printf("(sp)%+d", offset); -- else if (reg == ORC_REG_UNDEFINED) -- printf("(und)"); -- else -- printf("%s%+d", reg_name(reg), offset); --} -- - int orc_dump(const char *_objname) - { - int fd, nr_entries, i, *orc_ip = NULL, orc_size = 0; -@@ -205,17 +150,7 @@ int orc_dump(const char *_objname) - printf("%llx:", (unsigned long long)(orc_ip_addr + (i * sizeof(int)) + orc_ip[i])); - } - -- printf("type:%s", orc_type_name(orc[i].type)); -- -- printf(" sp:"); -- -- print_reg(orc[i].sp_reg, bswap_if_needed(&dummy_elf, orc[i].sp_offset)); -- -- printf(" bp:"); -- -- print_reg(orc[i].bp_reg, bswap_if_needed(&dummy_elf, orc[i].bp_offset)); -- -- printf(" signal:%d\n", orc[i].signal); -+ orc_print_dump(&dummy_elf, orc, i); - } - - elf_end(elf); -diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c -index bae3439..922e6aa 100644 ---- a/tools/objtool/orc_gen.c -+++ b/tools/objtool/orc_gen.c -@@ -10,121 +10,10 @@ - #include <asm/orc_types.h> - - #include <objtool/check.h> -+#include <objtool/orc.h> - #include <objtool/warn.h> - #include <objtool/endianness.h> - --static int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, -- struct instruction *insn) --{ -- struct cfi_reg *bp = &cfi->regs[CFI_BP]; -- -- memset(orc, 0, sizeof(*orc)); -- -- if (!cfi) { -- /* -- * This is usually either unreachable nops/traps (which don't -- * trigger unreachable instruction warnings), or -- * STACK_FRAME_NON_STANDARD functions. -- */ -- orc->type = ORC_TYPE_UNDEFINED; -- return 0; -- } -- -- switch (cfi->type) { -- case UNWIND_HINT_TYPE_UNDEFINED: -- orc->type = ORC_TYPE_UNDEFINED; -- return 0; -- case UNWIND_HINT_TYPE_END_OF_STACK: -- orc->type = ORC_TYPE_END_OF_STACK; -- return 0; -- case UNWIND_HINT_TYPE_CALL: -- orc->type = ORC_TYPE_CALL; -- break; -- case UNWIND_HINT_TYPE_REGS: -- orc->type = ORC_TYPE_REGS; -- break; -- case UNWIND_HINT_TYPE_REGS_PARTIAL: -- orc->type = ORC_TYPE_REGS_PARTIAL; -- break; -- default: -- WARN_INSN(insn, "unknown unwind hint type %d", cfi->type); -- return -1; -- } -- -- orc->signal = cfi->signal; -- -- switch (cfi->cfa.base) { -- case CFI_SP: -- orc->sp_reg = ORC_REG_SP; -- break; -- case CFI_SP_INDIRECT: -- orc->sp_reg = ORC_REG_SP_INDIRECT; -- break; -- case CFI_BP: -- orc->sp_reg = ORC_REG_BP; -- break; -- case CFI_BP_INDIRECT: -- orc->sp_reg = ORC_REG_BP_INDIRECT; -- break; -- case CFI_R10: -- orc->sp_reg = ORC_REG_R10; -- break; -- case CFI_R13: -- orc->sp_reg = ORC_REG_R13; -- break; -- case CFI_DI: -- orc->sp_reg = ORC_REG_DI; -- break; -- case CFI_DX: -- orc->sp_reg = ORC_REG_DX; -- break; -- default: -- WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); -- return -1; -- } -- -- switch (bp->base) { -- case CFI_UNDEFINED: -- orc->bp_reg = ORC_REG_UNDEFINED; -- break; -- case CFI_CFA: -- orc->bp_reg = ORC_REG_PREV_SP; -- break; -- case CFI_BP: -- orc->bp_reg = ORC_REG_BP; -- break; -- default: -- WARN_INSN(insn, "unknown BP base reg %d", bp->base); -- return -1; -- } -- -- orc->sp_offset = cfi->cfa.offset; -- orc->bp_offset = bp->offset; -- -- return 0; --} -- --static int write_orc_entry(struct elf *elf, struct section *orc_sec, -- struct section *ip_sec, unsigned int idx, -- struct section *insn_sec, unsigned long insn_off, -- struct orc_entry *o) --{ -- struct orc_entry *orc; -- -- /* populate ORC data */ -- orc = (struct orc_entry *)orc_sec->data->d_buf + idx; -- memcpy(orc, o, sizeof(*orc)); -- orc->sp_offset = bswap_if_needed(elf, orc->sp_offset); -- orc->bp_offset = bswap_if_needed(elf, orc->bp_offset); -- -- /* populate reloc for ip */ -- if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx, -- insn_sec, insn_off)) -- return -1; -- -- return 0; --} -- - struct orc_list_entry { - struct list_head list; - struct orc_entry orc; -diff --git a/virt/kvm/dirty_ring.c b/virt/kvm/dirty_ring.c -index 86d267d..7bc7496 100644 ---- a/virt/kvm/dirty_ring.c -+++ b/virt/kvm/dirty_ring.c -@@ -55,6 +55,9 @@ static void kvm_reset_dirty_gfn(struct kvm *kvm, u32 slot, u64 offset, u64 mask) - struct kvm_memory_slot *memslot; - int as_id, id; - -+ if (!mask) -+ return; -+ - as_id = slot >> 16; - id = (u16)slot; - diff -Nru linux-6.6.0/debian/patches/0021-build-ok11.patch linux-6.6.0/debian/patches/0021-build-ok11.patch --- linux-6.6.0/debian/patches/0021-build-ok11.patch 2025-01-17 14:59:51.000000000 +0800 +++ linux-6.6.0/debian/patches/0021-build-ok11.patch 1970-01-01 08:00:00.000000000 +0800 @@ -1,685 +0,0 @@ -From: root <root@localhost> -Date: Thu, 16 Jan 2025 17:57:28 +0800 -Subject: build ok11 - ---- - arch/arm64/configs/openkylin_generic_defconfig | 2 +- - arch/loongarch/include/asm/kvm_para.h | 11 + - arch/loongarch/include/asm/paravirt.h | 1 + - arch/loongarch/kernel/paravirt.c | 40 ++-- - arch/loongarch/kvm/exit.c | 2 + - arch/x86/kernel/iee/Makefile | 2 +- - debian.master/changelog | 17 ++ - drivers/gpio/gpio-loongson-64bit.c | 298 +++++++++++++++++++++---- - drivers/i2c/busses/i2c-ls2x.c | 12 +- - sound/pci/hda/hda_phytium.c | 1 + - 10 files changed, 320 insertions(+), 66 deletions(-) - -diff --git a/arch/arm64/configs/openkylin_generic_defconfig b/arch/arm64/configs/openkylin_generic_defconfig -index 8292291..8bdb538 100644 ---- a/arch/arm64/configs/openkylin_generic_defconfig -+++ b/arch/arm64/configs/openkylin_generic_defconfig -@@ -1239,7 +1239,7 @@ CONFIG_LOGO=y - # CONFIG_LOGO_LINUX_VGA16 is not set - CONFIG_SOUND=m - CONFIG_SND=m --CONFIG_SND_HDA_PHYTIUM=m -+CONFIG_SND_HDA_PHYTIUM=y - CONFIG_SND_HDA_INTEL=m - CONFIG_SND_HDA_HWDEP=y - CONFIG_SND_HDA_INPUT_BEEP=y -diff --git a/arch/loongarch/include/asm/kvm_para.h b/arch/loongarch/include/asm/kvm_para.h -index d0f0878..9f2e33c 100644 ---- a/arch/loongarch/include/asm/kvm_para.h -+++ b/arch/loongarch/include/asm/kvm_para.h -@@ -156,10 +156,21 @@ static __always_inline long kvm_hypercall5(u64 fid, - return ret; - } - -+#ifdef CONFIG_PARAVIRT -+ -+bool kvm_para_available(void); -+unsigned int kvm_arch_para_features(void); -+#else -+static inline bool kvm_para_available(void) -+{ -+ return false; -+} -+ - static inline unsigned int kvm_arch_para_features(void) - { - return 0; - } -+#endif - - static inline unsigned int kvm_arch_para_hints(void) - { -diff --git a/arch/loongarch/include/asm/paravirt.h b/arch/loongarch/include/asm/paravirt.h -index 6375467..3f43236 100644 ---- a/arch/loongarch/include/asm/paravirt.h -+++ b/arch/loongarch/include/asm/paravirt.h -@@ -19,6 +19,7 @@ static inline u64 paravirt_steal_clock(int cpu) - - int __init pv_ipi_init(void); - int __init pv_time_init(void); -+int __init pv_spinlock_init(void); - - #else - -diff --git a/arch/loongarch/kernel/paravirt.c b/arch/loongarch/kernel/paravirt.c -index 38bbd62..9cc27c3 100644 ---- a/arch/loongarch/kernel/paravirt.c -+++ b/arch/loongarch/kernel/paravirt.c -@@ -106,7 +106,7 @@ static void pv_send_ipi_mask(const struct cpumask *mask, unsigned int action) - - if (bitmap) - kvm_hypercall3(KVM_HCALL_FUNC_IPI, (unsigned long)bitmap, -- (unsigned long)(bitmap >> BITS_PER_LONG), min); -+ (unsigned long)(bitmap >> BITS_PER_LONG), min); - } - - static irqreturn_t pv_ipi_interrupt(int irq, void *dev) -@@ -146,11 +146,14 @@ static void pv_init_ipi(void) - } - #endif - --static bool kvm_para_available(void) -+bool kvm_para_available(void) - { - int config; - static int hypervisor_type; - -+ if (!cpu_has_hypervisor) -+ return false; -+ - if (!hypervisor_type) { - config = read_cpucfg(CPUCFG_KVM_SIG); - if (!memcmp(&config, KVM_SIGNATURE, 4)) -@@ -160,23 +163,28 @@ static bool kvm_para_available(void) - return hypervisor_type == HYPERVISOR_KVM; - } - --int __init pv_ipi_init(void) -+unsigned int kvm_arch_para_features(void) - { -- int feature; -+ static unsigned int feature; - -- if (!cpu_has_hypervisor) -- return 0; -- if (!(feature & BIT(KVM_FEATURE_IPI))) -+ if (!kvm_para_available()) - return 0; - -- feature = read_cpucfg(CPUCFG_KVM_FEATURE); -- if (!(feature & KVM_FEATURE_IPI)) -+ if (!feature) -+ feature = read_cpucfg(CPUCFG_KVM_FEATURE); -+ -+ return feature; -+} -+ -+int __init pv_ipi_init(void) -+{ -+ if (!kvm_para_has_feature(KVM_FEATURE_IPI)) - return 0; - - #ifdef CONFIG_SMP - smp_ops.init_ipi = pv_init_ipi; -- smp_ops.send_ipi_single = pv_send_ipi_single; -- smp_ops.send_ipi_mask = pv_send_ipi_mask; -+ smp_ops.send_ipi_single = pv_send_ipi_single; -+ smp_ops.send_ipi_mask = pv_send_ipi_mask; - #endif - - return 0; -@@ -253,15 +261,9 @@ static struct notifier_block pv_reboot_nb = { - - int __init pv_time_init(void) - { -- int r, feature; -- -- if (!cpu_has_hypervisor) -- return 0; -- if (!kvm_para_available()) -- return 0; -+ int r; - -- feature = read_cpucfg(CPUCFG_KVM_FEATURE); -- if (!(feature & BIT(KVM_FEATURE_STEAL_TIME))) -+ if (!kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) - return 0; - - has_steal_clock = 1; -diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c -index 7b40b01..0e91ca7 100644 ---- a/arch/loongarch/kvm/exit.c -+++ b/arch/loongarch/kvm/exit.c -@@ -44,6 +44,8 @@ static int kvm_emu_cpucfg(struct kvm_vcpu *vcpu, larch_inst inst) - switch (index) { - case 0 ... (KVM_MAX_CPUCFG_REGS - 1): - vcpu->arch.gprs[rd] = vcpu->arch.cpucfg[index]; -+ if (cpu_has_ptw && (index == LOONGARCH_CPUCFG2)) -+ vcpu->arch.gprs[rd] |= CPUCFG2_PTW; - break; - case CPUCFG_KVM_SIG: - /* CPUCFG emulation between 0x40000000 -- 0x400000ff */ -diff --git a/arch/x86/kernel/iee/Makefile b/arch/x86/kernel/iee/Makefile -index fbdbb00..877c552 100644 ---- a/arch/x86/kernel/iee/Makefile -+++ b/arch/x86/kernel/iee/Makefile -@@ -1,4 +1,4 @@ - obj-$(CONFIG_IEE) += iee.o iee-gate.o iee-func.o stack-slab.o page-slab.o - ccflags-y += -I$(srctree)/mm - obj-$(CONFIG_IEE_SELINUX_P) += iee-selinuxp.o --ccflags-$(CONFIG_IEE_SELINUX_P) += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include -+ccflags-$(CONFIG_IEE_SELINUX_P) += -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include -I$(objtree)/security/selinux -diff --git a/debian.master/changelog b/debian.master/changelog -index 9d9f81a..113cd5c 100644 ---- a/debian.master/changelog -+++ b/debian.master/changelog -@@ -1,3 +1,20 @@ -+linux (6.6.0-15.0ok11) nile; urgency=medium -+ -+ [ wangdicheng ] -+ * ALSA: hda: Resolving the issue of the ALC662 sound card failing to load. -+ -+ [ Xianglai Li ] -+ * LoongArch: fix compile error when enable CONFIG_PARAVIRT -+ * LoongArch: KVM: enable ptw for kvm -+ -+ [ Kanglong Wang ] -+ * LoongArch: Fix the problem that the touchpad couldn't work -+ -+ [ Jiajia Liu ] -+ * Fix build error for IEE_SELINUX_P -+ -+ -- XieWei <xiewei@kylinos.cn> Thu, 16 Jan 2025 17:54:55 +0800 -+ - linux (6.6.0-15.0ok10) nile; urgency=medium - - * rebase linux-6.6-next, build ok10 -diff --git a/drivers/gpio/gpio-loongson-64bit.c b/drivers/gpio/gpio-loongson-64bit.c -index 06213bb..f916a5a 100644 ---- a/drivers/gpio/gpio-loongson-64bit.c -+++ b/drivers/gpio/gpio-loongson-64bit.c -@@ -26,6 +26,7 @@ struct loongson_gpio_chip_data { - unsigned int conf_offset; - unsigned int out_offset; - unsigned int in_offset; -+ unsigned int inten_offset; - }; - - struct loongson_gpio_chip { -@@ -33,6 +34,8 @@ struct loongson_gpio_chip { - struct fwnode_handle *fwnode; - spinlock_t lock; - void __iomem *reg_base; -+ u16 *gsi_idx_map; -+ u16 mapsize; - const struct loongson_gpio_chip_data *chip_data; - }; - -@@ -41,15 +44,40 @@ static inline struct loongson_gpio_chip *to_loongson_gpio_chip(struct gpio_chip - return container_of(chip, struct loongson_gpio_chip, chip); - } - --static inline void loongson_commit_direction(struct loongson_gpio_chip *lgpio, unsigned int pin, -- int input) -+static inline void loongson_commit_direction_bit(struct loongson_gpio_chip *lgpio, -+ unsigned int pin, int input) -+{ -+ u64 temp; -+ -+ temp = readq(lgpio->reg_base + lgpio->chip_data->conf_offset); -+ if (input) -+ temp |= 1ULL << pin; -+ else -+ temp &= ~(1ULL << pin); -+ writeq(temp, lgpio->reg_base + lgpio->chip_data->conf_offset); -+} -+ -+static inline void loongson_commit_direction_byte(struct loongson_gpio_chip *lgpio, -+ unsigned int pin, int input) - { - u8 bval = input ? 1 : 0; - - writeb(bval, lgpio->reg_base + lgpio->chip_data->conf_offset + pin); - } - --static void loongson_commit_level(struct loongson_gpio_chip *lgpio, unsigned int pin, int high) -+static void loongson_commit_level_bit(struct loongson_gpio_chip *lgpio, unsigned int pin, int high) -+{ -+ u64 temp; -+ -+ temp = readq(lgpio->reg_base + lgpio->chip_data->out_offset); -+ if (high) -+ temp |= 1ULL << pin; -+ else -+ temp &= ~(1ULL << pin); -+ writeq(temp, lgpio->reg_base + lgpio->chip_data->out_offset); -+} -+ -+static void loongson_commit_level_byte(struct loongson_gpio_chip *lgpio, unsigned int pin, int high) - { - u8 bval = high ? 1 : 0; - -@@ -62,7 +90,10 @@ static int loongson_gpio_direction_input(struct gpio_chip *chip, unsigned int pi - struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); - - spin_lock_irqsave(&lgpio->lock, flags); -- loongson_commit_direction(lgpio, pin, 1); -+ if (lgpio->chip_data->mode == BIT_CTRL_MODE) -+ loongson_commit_direction_bit(lgpio, pin, 1); -+ else -+ loongson_commit_direction_byte(lgpio, pin, 1); - spin_unlock_irqrestore(&lgpio->lock, flags); - - return 0; -@@ -74,8 +105,13 @@ static int loongson_gpio_direction_output(struct gpio_chip *chip, unsigned int p - struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); - - spin_lock_irqsave(&lgpio->lock, flags); -- loongson_commit_level(lgpio, pin, value); -- loongson_commit_direction(lgpio, pin, 0); -+ if (lgpio->chip_data->mode == BIT_CTRL_MODE) { -+ loongson_commit_level_bit(lgpio, pin, value); -+ loongson_commit_direction_bit(lgpio, pin, 0); -+ } else { -+ loongson_commit_level_byte(lgpio, pin, value); -+ loongson_commit_direction_byte(lgpio, pin, 0); -+ } - spin_unlock_irqrestore(&lgpio->lock, flags); - - return 0; -@@ -84,11 +120,17 @@ static int loongson_gpio_direction_output(struct gpio_chip *chip, unsigned int p - static int loongson_gpio_get(struct gpio_chip *chip, unsigned int pin) - { - u8 bval; -+ u64 qval; - int val; - struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); - -- bval = readb(lgpio->reg_base + lgpio->chip_data->in_offset + pin); -- val = bval & 1; -+ if (lgpio->chip_data->mode == BIT_CTRL_MODE) { -+ qval = readq(lgpio->reg_base + lgpio->chip_data->in_offset); -+ val = ((qval & (1ULL << pin)) != 0); -+ } else { -+ bval = readb(lgpio->reg_base + lgpio->chip_data->in_offset + pin); -+ val = (bval & 1); -+ } - - return val; - } -@@ -96,13 +138,22 @@ static int loongson_gpio_get(struct gpio_chip *chip, unsigned int pin) - static int loongson_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) - { - u8 bval; -+ u64 qval; -+ int val; - struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); - -- bval = readb(lgpio->reg_base + lgpio->chip_data->conf_offset + pin); -- if (bval & 1) -- return GPIO_LINE_DIRECTION_IN; -+ if (lgpio->chip_data->mode == BIT_CTRL_MODE) { -+ qval = readq(lgpio->reg_base + lgpio->chip_data->conf_offset); -+ val = ((qval & (1ULL << pin)) != 0); -+ } else { -+ bval = readb(lgpio->reg_base + lgpio->chip_data->conf_offset + pin); -+ val = bval & 1; -+ } -+ -+ if (val) -+ return 1; - -- return GPIO_LINE_DIRECTION_OUT; -+ return 0; - } - - static void loongson_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) -@@ -111,52 +162,73 @@ static void loongson_gpio_set(struct gpio_chip *chip, unsigned int pin, int valu - struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); - - spin_lock_irqsave(&lgpio->lock, flags); -- loongson_commit_level(lgpio, pin, value); -+ if (lgpio->chip_data->mode == BIT_CTRL_MODE) -+ loongson_commit_level_bit(lgpio, pin, value); -+ else -+ loongson_commit_level_byte(lgpio, pin, value); - spin_unlock_irqrestore(&lgpio->lock, flags); - } - - static int loongson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset) - { -+ unsigned int u; - struct platform_device *pdev = to_platform_device(chip->parent); -+ struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip); -+ -+ if (lgpio->chip_data->mode == BIT_CTRL_MODE) { -+ /* Get the register index from offset then multiply by bytes per register */ -+ u = readl(lgpio->reg_base + lgpio->chip_data->inten_offset + (offset / 32) * 4); -+ u |= BIT(offset % 32); -+ writel(u, lgpio->reg_base + lgpio->chip_data->inten_offset + (offset / 32) * 4); -+ } else { -+ writeb(1, lgpio->reg_base + lgpio->chip_data->inten_offset + offset); -+ } -+ -+ if ((lgpio->gsi_idx_map != NULL) && (offset < lgpio->mapsize)) -+ offset = lgpio->gsi_idx_map[offset]; - - return platform_get_irq(pdev, offset); - } - - static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgpio, -- struct device_node *np, void __iomem *reg_base) -+ void __iomem *reg_base) - { -- int ret; - u32 ngpios; -+ u32 gpio_base; -+ int rval; - - lgpio->reg_base = reg_base; -- -- if (lgpio->chip_data->mode == BIT_CTRL_MODE) { -- ret = bgpio_init(&lgpio->chip, dev, 8, -- lgpio->reg_base + lgpio->chip_data->in_offset, -- lgpio->reg_base + lgpio->chip_data->out_offset, -- NULL, NULL, -- lgpio->reg_base + lgpio->chip_data->conf_offset, -- 0); -- if (ret) { -- dev_err(dev, "unable to init generic GPIO\n"); -- return ret; -+ lgpio->chip.direction_input = loongson_gpio_direction_input; -+ lgpio->chip.get = loongson_gpio_get; -+ lgpio->chip.get_direction = loongson_gpio_get_direction; -+ lgpio->chip.direction_output = loongson_gpio_direction_output; -+ lgpio->chip.set = loongson_gpio_set; -+ lgpio->chip.parent = dev; -+ device_property_read_u32(dev, "gpio_base", &gpio_base); -+ if (!gpio_base) -+ gpio_base = -1; -+ lgpio->chip.base = gpio_base; -+ device_property_read_u32(dev, "ngpios", &ngpios); -+ lgpio->chip.ngpio = ngpios; -+ rval = device_property_read_u16_array(dev, "gsi_idx_map", NULL, 0); -+ if (rval > 0) { -+ lgpio->gsi_idx_map = -+ kmalloc_array(rval, sizeof(*lgpio->gsi_idx_map), -+ GFP_KERNEL); -+ if (unlikely(!lgpio->gsi_idx_map)) { -+ dev_err(dev, "Alloc gsi_idx_map fail!\n"); -+ } else { -+ lgpio->mapsize = rval; -+ device_property_read_u16_array(dev, "gsi_idx_map", -+ lgpio->gsi_idx_map, lgpio->mapsize); - } -- } else { -- lgpio->chip.direction_input = loongson_gpio_direction_input; -- lgpio->chip.get = loongson_gpio_get; -- lgpio->chip.get_direction = loongson_gpio_get_direction; -- lgpio->chip.direction_output = loongson_gpio_direction_output; -- lgpio->chip.set = loongson_gpio_set; -- lgpio->chip.parent = dev; -- spin_lock_init(&lgpio->lock); - } -+ spin_lock_init(&lgpio->lock); - -- device_property_read_u32(dev, "ngpios", &ngpios); -- -- lgpio->chip.can_sleep = 0; -- lgpio->chip.ngpio = ngpios; - lgpio->chip.label = lgpio->chip_data->label; -- lgpio->chip.to_irq = loongson_gpio_to_irq; -+ lgpio->chip.can_sleep = false; -+ if (lgpio->chip_data->inten_offset) -+ lgpio->chip.to_irq = loongson_gpio_to_irq; - - return devm_gpiochip_add_data(dev, &lgpio->chip, lgpio); - } -@@ -165,7 +237,6 @@ static int loongson_gpio_probe(struct platform_device *pdev) - { - void __iomem *reg_base; - struct loongson_gpio_chip *lgpio; -- struct device_node *np = pdev->dev.of_node; - struct device *dev = &pdev->dev; - - lgpio = devm_kzalloc(dev, sizeof(*lgpio), GFP_KERNEL); -@@ -178,7 +249,7 @@ static int loongson_gpio_probe(struct platform_device *pdev) - if (IS_ERR(reg_base)) - return PTR_ERR(reg_base); - -- return loongson_gpio_init(dev, lgpio, np, reg_base); -+ return loongson_gpio_init(dev, lgpio, reg_base); - } - - static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = { -@@ -187,6 +258,60 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = { - .conf_offset = 0x0, - .in_offset = 0x20, - .out_offset = 0x10, -+ .inten_offset = 0x30, -+}; -+ -+static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data0 = { -+ .label = "ls2k0500_gpio", -+ .mode = BIT_CTRL_MODE, -+ .conf_offset = 0x0, -+ .in_offset = 0x8, -+ .out_offset = 0x10, -+ .inten_offset = 0xb0, -+}; -+ -+static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data1 = { -+ .label = "ls2k0500_gpio", -+ .mode = BIT_CTRL_MODE, -+ .conf_offset = 0x0, -+ .in_offset = 0x8, -+ .out_offset = 0x10, -+ .inten_offset = 0x98, -+}; -+ -+static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data0 = { -+ .label = "ls2k2000_gpio", -+ .mode = BIT_CTRL_MODE, -+ .conf_offset = 0x0, -+ .in_offset = 0xc, -+ .out_offset = 0x8, -+ .inten_offset = 0x14, -+}; -+ -+static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data1 = { -+ .label = "ls2k2000_gpio", -+ .mode = BIT_CTRL_MODE, -+ .conf_offset = 0x0, -+ .in_offset = 0x20, -+ .out_offset = 0x10, -+ .inten_offset = 0x30, -+}; -+ -+static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data2 = { -+ .label = "ls2k2000_gpio", -+ .mode = BIT_CTRL_MODE, -+ .conf_offset = 0x4, -+ .in_offset = 0x8, -+ .out_offset = 0x0, -+}; -+ -+static const struct loongson_gpio_chip_data loongson_gpio_ls3a5000_data = { -+ .label = "ls3a5000_gpio", -+ .mode = BIT_CTRL_MODE, -+ .conf_offset = 0x0, -+ .in_offset = 0xc, -+ .out_offset = 0x8, -+ .inten_offset = 0x14, - }; - - static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = { -@@ -195,6 +320,33 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = { - .conf_offset = 0x800, - .in_offset = 0xa00, - .out_offset = 0x900, -+ .inten_offset = 0xb00, -+}; -+ -+static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data0 = { -+ .label = "ls7a2000_gpio", -+ .mode = BYTE_CTRL_MODE, -+ .conf_offset = 0x800, -+ .in_offset = 0xa00, -+ .out_offset = 0x900, -+ .inten_offset = 0xb00, -+}; -+ -+static const struct loongson_gpio_chip_data loongson_gpio_ls7a2000_data1 = { -+ .label = "ls7a2000_gpio", -+ .mode = BYTE_CTRL_MODE, -+ .conf_offset = 0x84, -+ .in_offset = 0x88, -+ .out_offset = 0x80, -+}; -+ -+static const struct loongson_gpio_chip_data loongson_gpio_ls3a6000_data = { -+ .label = "ls3a6000_gpio", -+ .mode = BIT_CTRL_MODE, -+ .conf_offset = 0x0, -+ .in_offset = 0xc, -+ .out_offset = 0x8, -+ .inten_offset = 0x14, - }; - - static const struct of_device_id loongson_gpio_of_match[] = { -@@ -202,10 +354,46 @@ static const struct of_device_id loongson_gpio_of_match[] = { - .compatible = "loongson,ls2k-gpio", - .data = &loongson_gpio_ls2k_data, - }, -+ { -+ .compatible = "loongson,ls2k0500-gpio0", -+ .data = &loongson_gpio_ls2k0500_data0, -+ }, -+ { -+ .compatible = "loongson,ls2k0500-gpio1", -+ .data = &loongson_gpio_ls2k0500_data1, -+ }, -+ { -+ .compatible = "loongson,ls2k2000-gpio0", -+ .data = &loongson_gpio_ls2k2000_data0, -+ }, -+ { -+ .compatible = "loongson,ls2k2000-gpio1", -+ .data = &loongson_gpio_ls2k2000_data1, -+ }, -+ { -+ .compatible = "loongson,ls2k2000-gpio2", -+ .data = &loongson_gpio_ls2k2000_data2, -+ }, -+ { -+ .compatible = "loongson,ls3a5000-gpio", -+ .data = &loongson_gpio_ls3a5000_data, -+ }, - { - .compatible = "loongson,ls7a-gpio", - .data = &loongson_gpio_ls7a_data, - }, -+ { -+ .compatible = "loongson,ls7a2000-gpio1", -+ .data = &loongson_gpio_ls7a2000_data0, -+ }, -+ { -+ .compatible = "loongson,ls7a2000-gpio2", -+ .data = &loongson_gpio_ls7a2000_data1, -+ }, -+ { -+ .compatible = "loongson,ls3a6000-gpio", -+ .data = &loongson_gpio_ls3a6000_data, -+ }, - {} - }; - MODULE_DEVICE_TABLE(of, loongson_gpio_of_match); -@@ -215,6 +403,34 @@ static const struct acpi_device_id loongson_gpio_acpi_match[] = { - .id = "LOON0002", - .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a_data, - }, -+ { -+ .id = "LOON0007", -+ .driver_data = (kernel_ulong_t)&loongson_gpio_ls3a5000_data, -+ }, -+ { -+ .id = "LOON000A", -+ .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data0, -+ }, -+ { -+ .id = "LOON000B", -+ .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data1, -+ }, -+ { -+ .id = "LOON000C", -+ .driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data2, -+ }, -+ { -+ .id = "LOON000D", -+ .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a2000_data0, -+ }, -+ { -+ .id = "LOON000E", -+ .driver_data = (kernel_ulong_t)&loongson_gpio_ls7a2000_data1, -+ }, -+ { -+ .id = "LOON000F", -+ .driver_data = (kernel_ulong_t)&loongson_gpio_ls3a6000_data, -+ }, - {} - }; - MODULE_DEVICE_TABLE(acpi, loongson_gpio_acpi_match); -diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c -index ebae603..871ceed 100644 ---- a/drivers/i2c/busses/i2c-ls2x.c -+++ b/drivers/i2c/busses/i2c-ls2x.c -@@ -26,7 +26,8 @@ - #include <linux/units.h> - - /* I2C Registers */ --#define I2C_LS2X_PRER 0x0 /* Freq Division Register(16 bits) */ -+#define I2C_LS2X_PRER_LO 0x0 /* Freq Division Register Lo(8 bits) */ -+#define I2C_LS2X_PRER_HI 0x1 /* Freq Division Register Hi(8 bits) */ - #define I2C_LS2X_CTR 0x2 /* Control Register */ - #define I2C_LS2X_TXR 0x3 /* Transport Data Register */ - #define I2C_LS2X_RXR 0x3 /* Receive Data Register */ -@@ -96,6 +97,7 @@ static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv) - struct i2c_timings *t = &priv->i2c_t; - struct device *dev = priv->adapter.dev.parent; - u32 acpi_speed = i2c_acpi_find_bus_speed(dev); -+ u16 prer_val; - - i2c_parse_fw_timings(dev, t, false); - -@@ -104,9 +106,11 @@ static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv) - else - t->bus_freq_hz = LS2X_I2C_FREQ_STD; - -- /* Calculate and set i2c frequency. */ -- writew(LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1, -- priv->base + I2C_LS2X_PRER); -+ prer_val = LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1; -+ -+ /* set i2c frequency. */ -+ writeb(prer_val & 0xFF, priv->base + I2C_LS2X_PRER_LO); -+ writeb((prer_val & 0xFF00) >> 8, priv->base + I2C_LS2X_PRER_HI); - } - - static void ls2x_i2c_init(struct ls2x_i2c_priv *priv) -diff --git a/sound/pci/hda/hda_phytium.c b/sound/pci/hda/hda_phytium.c -index 652163f..709c2d8 100644 ---- a/sound/pci/hda/hda_phytium.c -+++ b/sound/pci/hda/hda_phytium.c -@@ -1061,6 +1061,7 @@ MODULE_DEVICE_TABLE(of, hda_ft_of_match); - #ifdef CONFIG_ACPI - static const struct acpi_device_id hda_ft_acpi_match[] = { - { .id = "PHYT0006" }, -+ { .id = "FTHD0001" }, - {} - }; - MODULE_DEVICE_TABLE(acpi, hda_ft_acpi_match); diff -Nru linux-6.6.0/debian/patches/0022-build-ok12.patch linux-6.6.0/debian/patches/0022-build-ok12.patch --- linux-6.6.0/debian/patches/0022-build-ok12.patch 2025-01-17 14:59:51.000000000 +0800 +++ linux-6.6.0/debian/patches/0022-build-ok12.patch 1970-01-01 08:00:00.000000000 +0800 @@ -1,40 +0,0 @@ -From: root <root@localhost> -Date: Fri, 17 Jan 2025 15:03:12 +0800 -Subject: build ok12 - ---- - debian.master/changelog | 7 +++++++ - fs/erofs/super.c | 5 +---- - 2 files changed, 8 insertions(+), 4 deletions(-) - -diff --git a/debian.master/changelog b/debian.master/changelog -index 113cd5c..aa8939c 100644 ---- a/debian.master/changelog -+++ b/debian.master/changelog -@@ -1,3 +1,10 @@ -+linux (6.6.0-15.0ok12) nile; urgency=medium -+ -+ [ Yongzhen Zhang ] -+ * Revert "update fs/erofs/super.c." -+ -+ -- XieWei <xiewei@kylinos.cn> Fri, 17 Jan 2025 14:59:51 +0800 -+ - linux (6.6.0-15.0ok11) nile; urgency=medium - - [ wangdicheng ] -diff --git a/fs/erofs/super.c b/fs/erofs/super.c -index bfb5f82..ef4b948 100644 ---- a/fs/erofs/super.c -+++ b/fs/erofs/super.c -@@ -618,10 +618,7 @@ static int erofs_fc_fill_super(struct super_block *sb, struct fs_context *fc) - errorfc(fc, "unsupported blksize for fscache mode"); - return -EINVAL; - } -- if (erofs_is_fileio_mode(sbi)) { -- sb->s_blocksize = 1 << sbi->blkszbits; -- sb->s_blocksize_bits = sbi->blkszbits; -- } else if (!sb_set_blocksize(sb, 1 << sbi->blkszbits)) { -+ if (!sb_set_blocksize(sb, 1 << sbi->blkszbits)) { - errorfc(fc, "failed to set erofs blksize"); - return -EINVAL; - } diff -Nru linux-6.6.0/debian/patches/revert-to-ok9.patch linux-6.6.0/debian/patches/revert-to-ok9.patch --- linux-6.6.0/debian/patches/revert-to-ok9.patch 1970-01-01 08:00:00.000000000 +0800 +++ linux-6.6.0/debian/patches/revert-to-ok9.patch 2025-01-24 11:03:02.000000000 +0800 @@ -0,0 +1,14 @@ +Index: linux-6.6.0/debian.master/changelog +=================================================================== +--- linux-6.6.0.orig/debian.master/changelog ++++ linux-6.6.0/debian.master/changelog +@@ -1,3 +1,9 @@ ++linux (6.6.0-15.0ok13) nile; urgency=medium ++ ++ * 回退ok10到ok12的改动 ++ ++ -- XieWei <xiewei@kylinos.cn> Fri, 24 Jan 2025 11:03:02 +0800 ++ + linux (6.6.0-15.0ok9) nile; urgency=medium + + [ user ] diff -Nru linux-6.6.0/debian/patches/series linux-6.6.0/debian/patches/series --- linux-6.6.0/debian/patches/series 2025-01-17 14:59:51.000000000 +0800 +++ linux-6.6.0/debian/patches/series 2025-01-24 11:03:02.000000000 +0800 @@ -17,6 +17,4 @@ 0017-build-new-version.patch 0018-build-ok8.patch 0019-build-ok9.patch -0020-rebase-linux-6.6-next-build-ok10.patch -0021-build-ok11.patch -0022-build-ok12.patch +revert-to-ok9.patch