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(&current_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);
-+	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, &param);
-+			ddr3_init(ast, &param);
-+		} else {
-+			get_ddr2_info(ast, &param);
-+			ddr2_init(ast, &param);
-+		}
-+
-+		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, &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