From a19517f55f53a8ffb22f3ff77cb19073062ae508 Mon Sep 17 00:00:00 2001 From: almalinux-bot-kernel Date: Mon, 8 Jun 2026 05:56:49 +0000 Subject: [PATCH] Import of kernel-5.14.0-687.12.1.el9_8 --- ...687.5.4.el9 => COPYING-5.14.0-687.12.1.el9 | 0 .../gcc-check-fpatchable-function-entry.sh | 1 - arch/s390/pci/pci_event.c | 4 +- arch/x86/boot/compressed/Makefile | 1 + arch/x86/kvm/mmu/mmu.c | 14 +- arch/x86/mm/init_64.c | 4 + arch/x86/mm/pat/set_memory.c | 5 + arch/x86/mm/pgtable.c | 6 + configs/kernel-5.14.0-ppc64le-debug.config | 11 +- configs/kernel-5.14.0-s390x-debug.config | 2 +- configs/kernel-5.14.0-s390x-zfcpdump.config | 2 +- configs/kernel-5.14.0-s390x.config | 2 +- crypto/Kconfig | 2 + crypto/af_alg.c | 6 +- crypto/algif_aead.c | 92 ++- crypto/algif_skcipher.c | 8 +- crypto/asymmetric_keys/asymmetric_type.c | 12 +- crypto/authenc.c | 32 +- crypto/authencesn.c | 57 +- crypto/scatterwalk.c | 94 --- drivers/block/nbd.c | 3 +- drivers/crypto/tegra/tegra-se-aes.c | 9 + drivers/crypto/tegra/tegra-se-hash.c | 3 + drivers/dpll/dpll_netlink.c | 10 + drivers/dpll/dpll_netlink.h | 2 - drivers/dpll/zl3073x/core.c | 7 +- drivers/dpll/zl3073x/core.h | 58 ++ drivers/dpll/zl3073x/dpll.c | 46 +- drivers/dpll/zl3073x/out.h | 17 + drivers/dpll/zl3073x/prop.c | 32 +- drivers/dpll/zl3073x/ref.c | 25 +- drivers/dpll/zl3073x/ref.h | 2 + drivers/dpll/zl3073x/regs.h | 1 + drivers/gpu/drm/i915/display/icl_dsi.c | 2 +- drivers/gpu/drm/i915/display/intel_display.c | 2 +- .../drm/i915/display/intel_display_types.h | 11 + drivers/gpu/drm/i915/display/intel_dp.c | 34 +- drivers/gpu/drm/i915/display/intel_dp.h | 2 + drivers/gpu/drm/i915/display/intel_dp_mst.c | 31 +- drivers/gpu/drm/i915/display/intel_link_bw.c | 17 +- drivers/gpu/drm/i915/display/intel_link_bw.h | 2 +- drivers/gpu/drm/i915/display/intel_psr.c | 93 ++- drivers/gpu/drm/i915/display/intel_vdsc.c | 16 + drivers/gpu/drm/i915/display/intel_vdsc.h | 2 + drivers/gpu/drm/mgag200/mgag200_bmc.c | 31 +- drivers/gpu/drm/mgag200/mgag200_drv.h | 6 + drivers/hid/wacom_wac.c | 10 + drivers/i2c/busses/i2c-i801.c | 14 +- drivers/infiniband/core/umem_dmabuf.c | 4 +- drivers/infiniband/hw/bnxt_re/bnxt_re.h | 2 + drivers/infiniband/hw/bnxt_re/debugfs.c | 223 +++++- drivers/infiniband/hw/bnxt_re/debugfs.h | 15 + drivers/infiniband/hw/bnxt_re/ib_verbs.c | 2 +- drivers/infiniband/hw/bnxt_re/qplib_fp.c | 30 +- drivers/infiniband/hw/bnxt_re/qplib_fp.h | 3 + drivers/infiniband/hw/bnxt_re/qplib_rcfw.c | 2 +- drivers/infiniband/hw/bnxt_re/qplib_sp.c | 9 +- drivers/infiniband/hw/bnxt_re/qplib_sp.h | 1 + drivers/iommu/iommu-sva.c | 144 ++++ drivers/md/md-bitmap.c | 3 +- drivers/md/persistent-data/dm-btree-remove.c | 8 + .../net/ethernet/intel/ice/devlink/devlink.c | 2 + drivers/net/ethernet/intel/ice/ice_common.c | 2 - drivers/net/ethernet/intel/ice/ice_dpll.c | 146 +++- drivers/net/ethernet/intel/ice/ice_main.c | 2 + drivers/net/ethernet/intel/ice/ice_ptp.c | 71 +- drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 253 ++++++- drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 5 + drivers/net/ethernet/intel/ice/ice_txrx.c | 16 +- drivers/net/ethernet/intel/ice/ice_txrx.h | 1 + drivers/net/ethernet/intel/ice/ice_vf_lib.c | 7 +- .../net/ethernet/pensando/ionic/ionic_lif.c | 17 +- drivers/net/hyperv/netvsc_drv.c | 3 + .../broadcom/brcm80211/brcmfmac/fweh.c | 5 + drivers/scsi/lpfc/lpfc.h | 54 +- drivers/scsi/lpfc/lpfc_ct.c | 64 +- drivers/scsi/lpfc/lpfc_debugfs.c | 650 ++++++++++++------ drivers/scsi/lpfc/lpfc_debugfs.h | 16 +- drivers/scsi/lpfc/lpfc_disc.h | 3 +- drivers/scsi/lpfc/lpfc_els.c | 245 ++----- drivers/scsi/lpfc/lpfc_hbadisc.c | 23 +- drivers/scsi/lpfc/lpfc_hw.h | 28 +- drivers/scsi/lpfc/lpfc_hw4.h | 20 +- drivers/scsi/lpfc/lpfc_init.c | 108 +-- drivers/scsi/lpfc/lpfc_nportdisc.c | 46 +- drivers/scsi/lpfc/lpfc_nvme.c | 8 +- drivers/scsi/lpfc/lpfc_scsi.c | 23 +- drivers/scsi/lpfc/lpfc_sli.c | 114 +-- drivers/scsi/lpfc/lpfc_sli4.h | 4 +- drivers/scsi/lpfc/lpfc_version.h | 2 +- drivers/scsi/lpfc/lpfc_vport.c | 2 +- drivers/scsi/qla2xxx/qla_nvme.c | 2 +- drivers/scsi/storvsc_drv.c | 32 +- drivers/usb/usbip/usbip_common.c | 12 + fs/nfs/pnfs.c | 3 +- fs/nfsd/nfs4xdr.c | 9 +- fs/nfsd/state.h | 17 +- fs/proc/generic.c | 37 +- fs/proc/inode.c | 2 +- fs/proc/internal.h | 5 + fs/smb/client/cifsacl.c | 150 +++- fs/smb/client/connect.c | 4 + fs/smb/client/fs_context.c | 2 +- fs/xfs/libxfs/xfs_attr_leaf.c | 49 +- include/crypto/scatterwalk.h | 32 - include/linux/dpll.h | 1 + include/linux/iommu.h | 3 + include/linux/proc_fs.h | 1 + include/linux/sched.h | 3 + include/linux/skbuff.h | 12 + include/net/act_api.h | 1 + include/net/gro.h | 1 + kernel.sbat | 4 +- kernel/exit.c | 1 + kernel/ptrace.c | 23 +- mm/page_alloc.c | 3 +- net/bluetooth/mgmt.c | 3 + net/bluetooth/sco.c | 40 +- net/can/raw.c | 11 +- net/ceph/messenger_v2.c | 2 + net/ceph/osd_client.c | 3 + net/ceph/osdmap.c | 120 ++-- net/core/gro.c | 29 + net/core/rtnetlink.c | 3 + net/core/skbuff.c | 5 +- net/ipv4/ip_output.c | 1 + net/ipv4/udp_offload.c | 29 - net/ipv6/netfilter/ip6t_eui64.c | 3 +- net/netfilter/nf_conntrack_h323_asn1.c | 2 + net/netfilter/nf_conntrack_helper.c | 2 +- net/netfilter/nf_tables_api.c | 1 + net/netfilter/xt_tcpmss.c | 2 +- net/rxrpc/io_thread.c | 18 +- net/sched/act_csum.c | 6 +- net/sched/act_ct.c | 6 + net/sched/cls_api.c | 7 + net/sched/cls_u32.c | 13 +- net/sched/sch_cake.c | 54 +- .../rhel/generic/s390x/CONFIG_SCLP_OFB | 2 +- security/integrity/ima/ima_appraise.c | 23 +- 140 files changed, 2697 insertions(+), 1326 deletions(-) rename COPYING-5.14.0-687.5.4.el9 => COPYING-5.14.0-687.12.1.el9 (100%) diff --git a/COPYING-5.14.0-687.5.4.el9 b/COPYING-5.14.0-687.12.1.el9 similarity index 100% rename from COPYING-5.14.0-687.5.4.el9 rename to COPYING-5.14.0-687.12.1.el9 diff --git a/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh b/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh index 0670690350..baed467a01 100755 --- a/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh +++ b/arch/powerpc/tools/gcc-check-fpatchable-function-entry.sh @@ -2,7 +2,6 @@ # SPDX-License-Identifier: GPL-2.0 set -e -set -o pipefail # To debug, uncomment the following line # set -x diff --git a/arch/s390/pci/pci_event.c b/arch/s390/pci/pci_event.c index d930416d4c..da0de34d2e 100644 --- a/arch/s390/pci/pci_event.c +++ b/arch/s390/pci/pci_event.c @@ -187,7 +187,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) * is unbound or probed and that userspace can't access its * configuration space while we perform recovery. */ - pci_dev_lock(pdev); + device_lock(&pdev->dev); if (pdev->error_state == pci_channel_io_perm_failure) { ers_res = PCI_ERS_RESULT_DISCONNECT; goto out_unlock; @@ -254,7 +254,7 @@ static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev) if (driver->err_handler->resume) driver->err_handler->resume(pdev); out_unlock: - pci_dev_unlock(pdev); + device_unlock(&pdev->dev); zpci_report_status(zdev, "recovery", status_str); return ers_res; diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index b294f0a7ac..77e3bd5d39 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -122,6 +122,7 @@ vmlinux-objs-$(CONFIG_EFI_SBAT) += $(obj)/sbat.o ifdef CONFIG_EFI_SBAT # Strip quotes $(obj)/sbat.o: $(strip $(subst ",,$(CONFIG_EFI_SBAT_FILE))) +AFLAGS_sbat.o += -I $(srctree) endif $(obj)/vmlinux: $(vmlinux-objs-y) FORCE diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index c542b26546..8895c98f00 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -2892,12 +2892,6 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot, bool prefetch = !fault || fault->prefetch; bool write_fault = fault && fault->write; - if (unlikely(is_noslot_pfn(pfn))) { - vcpu->stat.pf_mmio_spte_created++; - mark_mmio_spte(vcpu, sptep, gfn, pte_access); - return RET_PF_EMULATE; - } - if (is_shadow_present_pte(*sptep)) { if (prefetch) return RET_PF_SPURIOUS; @@ -2920,6 +2914,14 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot, was_rmapped = 1; } + if (unlikely(is_noslot_pfn(pfn))) { + vcpu->stat.pf_mmio_spte_created++; + mark_mmio_spte(vcpu, sptep, gfn, pte_access); + if (flush) + kvm_flush_remote_tlbs_gfn(vcpu->kvm, gfn, level); + return RET_PF_EMULATE; + } + wrprot = make_spte(vcpu, sp, slot, pte_access, gfn, pfn, *sptep, prefetch, true, host_writable, &spte); diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index dc4fcf3d80..f05d65446d 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -1017,6 +1018,9 @@ static void __meminit free_pagetable(struct page *page, int order) unsigned long magic; unsigned int nr_pages = 1 << order; + /* Flush IOMMU paging structure caches before freeing PT page */ + iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL); + /* bootmem page has reserved flag */ if (PageReserved(page)) { __ClearPageReserved(page); diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c index 77dca29d82..63cafe9f76 100644 --- a/arch/x86/mm/pat/set_memory.c +++ b/arch/x86/mm/pat/set_memory.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -1204,6 +1205,8 @@ static bool try_to_free_pte_page(pte_t *pte) if (!pte_none(pte[i])) return false; + /* Flush IOMMU paging structure caches before freeing PT page */ + iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL); free_page((unsigned long)pte); return true; } @@ -1216,6 +1219,8 @@ static bool try_to_free_pmd_page(pmd_t *pmd) if (!pmd_none(pmd[i])) return false; + /* Flush IOMMU paging structure caches before freeing PT page */ + iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL); free_page((unsigned long)pmd); return true; } diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index d28d84f7d5..e7ed6a69e7 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -832,6 +833,9 @@ int pud_free_pmd_page(pud_t *pud, unsigned long addr) /* INVLPG to clear all paging-structure caches */ flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1); + /* Flush IOMMU paging structure caches before freeing PT pages */ + iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL); + for (i = 0; i < PTRS_PER_PMD; i++) { if (!pmd_none(pmd_sv[i])) { pte = (pte_t *)pmd_page_vaddr(pmd_sv[i]); @@ -865,6 +869,8 @@ int pmd_free_pte_page(pmd_t *pmd, unsigned long addr) /* INVLPG to clear all paging-structure caches */ flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1); + /* Flush IOMMU paging structure caches before freeing PT page */ + iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL); free_page((unsigned long)pte); return 1; diff --git a/configs/kernel-5.14.0-ppc64le-debug.config b/configs/kernel-5.14.0-ppc64le-debug.config index 698066bc5c..9f7f188211 100644 --- a/configs/kernel-5.14.0-ppc64le-debug.config +++ b/configs/kernel-5.14.0-ppc64le-debug.config @@ -473,6 +473,9 @@ CONFIG_HZ=100 CONFIG_SCHED_HRTICK=y CONFIG_PPC_TRANSACTIONAL_MEM=y CONFIG_MPROFILE_KERNEL=y +CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY=y +CONFIG_PPC_FTRACE_OUT_OF_LINE=y +CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE=32768 CONFIG_HOTPLUG_CPU=y CONFIG_PPC_QUEUED_SPINLOCKS=y CONFIG_ARCH_CPU_PROBE_RELEASE=y @@ -663,6 +666,7 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y CONFIG_HAVE_GCC_PLUGINS=y # CONFIG_GCC_PLUGINS is not set CONFIG_FUNCTION_ALIGNMENT=0 +CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX=y # end of General architecture-dependent options CONFIG_RT_MUTEXES=y @@ -4860,6 +4864,7 @@ CONFIG_HID_KUNIT_TEST=m # # HID-BPF support # +CONFIG_HID_BPF=y # end of HID-BPF support CONFIG_I2C_HID=y @@ -6814,6 +6819,8 @@ CONFIG_HAVE_FUNCTION_TRACER=y CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y CONFIG_HAVE_DYNAMIC_FTRACE=y CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS=y CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_SYSCALL_TRACEPOINTS=y @@ -6833,6 +6840,8 @@ CONFIG_FUNCTION_TRACER=y CONFIG_FUNCTION_GRAPH_TRACER=y CONFIG_DYNAMIC_FTRACE=y CONFIG_DYNAMIC_FTRACE_WITH_REGS=y +CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y +CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS=y CONFIG_DYNAMIC_FTRACE_WITH_ARGS=y CONFIG_FPROBE=y CONFIG_FUNCTION_PROFILER=y @@ -6856,7 +6865,7 @@ CONFIG_DYNAMIC_EVENTS=y CONFIG_PROBE_EVENTS=y # CONFIG_BPF_KPROBE_OVERRIDE is not set CONFIG_FTRACE_MCOUNT_RECORD=y -CONFIG_FTRACE_MCOUNT_USE_CC=y +CONFIG_FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY=y CONFIG_TRACING_MAP=y CONFIG_SYNTH_EVENTS=y CONFIG_HIST_TRIGGERS=y diff --git a/configs/kernel-5.14.0-s390x-debug.config b/configs/kernel-5.14.0-s390x-debug.config index 6575cde21c..58262f5454 100644 --- a/configs/kernel-5.14.0-s390x-debug.config +++ b/configs/kernel-5.14.0-s390x-debug.config @@ -2345,7 +2345,7 @@ CONFIG_SCLP_CONSOLE=y CONFIG_SCLP_VT220_TTY=y CONFIG_SCLP_VT220_CONSOLE=y CONFIG_HMC_DRV=m -# CONFIG_SCLP_OFB is not set +CONFIG_SCLP_OFB=y CONFIG_S390_UV_UAPI=y CONFIG_S390_TAPE=m diff --git a/configs/kernel-5.14.0-s390x-zfcpdump.config b/configs/kernel-5.14.0-s390x-zfcpdump.config index b0307b7e4d..d62e651c2a 100644 --- a/configs/kernel-5.14.0-s390x-zfcpdump.config +++ b/configs/kernel-5.14.0-s390x-zfcpdump.config @@ -961,7 +961,7 @@ CONFIG_SCLP_CONSOLE=y CONFIG_SCLP_VT220_TTY=y CONFIG_SCLP_VT220_CONSOLE=y CONFIG_HMC_DRV=y -# CONFIG_SCLP_OFB is not set +CONFIG_SCLP_OFB=y # CONFIG_S390_UV_UAPI is not set # CONFIG_S390_TAPE is not set # CONFIG_VMCP is not set diff --git a/configs/kernel-5.14.0-s390x.config b/configs/kernel-5.14.0-s390x.config index c8a3d5f1ea..2b75e563fb 100644 --- a/configs/kernel-5.14.0-s390x.config +++ b/configs/kernel-5.14.0-s390x.config @@ -2368,7 +2368,7 @@ CONFIG_SCLP_CONSOLE=y CONFIG_SCLP_VT220_TTY=y CONFIG_SCLP_VT220_CONSOLE=y CONFIG_HMC_DRV=m -# CONFIG_SCLP_OFB is not set +CONFIG_SCLP_OFB=y CONFIG_S390_UV_UAPI=y CONFIG_S390_TAPE=m diff --git a/crypto/Kconfig b/crypto/Kconfig index ffe490215a..79056212e9 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -221,6 +221,7 @@ config CRYPTO_AUTHENC select CRYPTO_SKCIPHER select CRYPTO_MANAGER select CRYPTO_HASH + select CRYPTO_NULL help Authenc: Combined mode wrapper for IPsec. This is required for IPSec. @@ -2131,6 +2132,7 @@ config CRYPTO_USER_API_AEAD depends on NET select CRYPTO_AEAD select CRYPTO_SKCIPHER + select CRYPTO_NULL select CRYPTO_USER_API help This option enables the user-spaces interface for AEAD diff --git a/crypto/af_alg.c b/crypto/af_alg.c index f530f3c8fb..567e9f234b 100644 --- a/crypto/af_alg.c +++ b/crypto/af_alg.c @@ -513,8 +513,10 @@ static int af_alg_alloc_tsgl(struct sock *sk) sg_init_table(sgl->sg, MAX_SGL_ENTS + 1); sgl->cur = 0; - if (sg) + if (sg) { + sg_unmark_end(sg + MAX_SGL_ENTS - 1); sg_chain(sg, MAX_SGL_ENTS + 1, sgl->sg); + } list_add_tail(&sgl->list, &ctx->tsgl_list); } @@ -1133,6 +1135,8 @@ int af_alg_get_rsgl(struct sock *sk, struct msghdr *msg, int flags, seglen = min_t(size_t, (maxsize - len), msg_data_left(msg)); + /* Never pin more pages than the remaining RX accounting budget. */ + seglen = min_t(size_t, seglen, af_alg_rcvbuf(sk)); if (list_empty(&areq->rsgl_list)) { rsgl = &areq->first_rsgl; diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c index 4a285994d1..9b589ab1af 100644 --- a/crypto/algif_aead.c +++ b/crypto/algif_aead.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,13 +36,19 @@ #include #include +struct aead_tfm { + struct crypto_aead *aead; + struct crypto_sync_skcipher *null_tfm; +}; + static inline bool aead_sufficient_data(struct sock *sk) { struct alg_sock *ask = alg_sk(sk); struct sock *psk = ask->parent; struct alg_sock *pask = alg_sk(psk); struct af_alg_ctx *ctx = ask->private; - struct crypto_aead *tfm = pask->private; + struct aead_tfm *aeadc = pask->private; + struct crypto_aead *tfm = aeadc->aead; unsigned int as = crypto_aead_authsize(tfm); /* @@ -56,12 +64,27 @@ static int aead_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) struct alg_sock *ask = alg_sk(sk); struct sock *psk = ask->parent; struct alg_sock *pask = alg_sk(psk); - struct crypto_aead *tfm = pask->private; + struct aead_tfm *aeadc = pask->private; + struct crypto_aead *tfm = aeadc->aead; unsigned int ivsize = crypto_aead_ivsize(tfm); return af_alg_sendmsg(sock, msg, size, ivsize); } +static int crypto_aead_copy_sgl(struct crypto_sync_skcipher *null_tfm, + struct scatterlist *src, + struct scatterlist *dst, unsigned int len) +{ + SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, null_tfm); + + skcipher_request_set_sync_tfm(skreq, null_tfm); + skcipher_request_set_callback(skreq, CRYPTO_TFM_REQ_MAY_SLEEP, + NULL, NULL); + skcipher_request_set_crypt(skreq, src, dst, len, NULL); + + return crypto_skcipher_encrypt(skreq); +} + static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, size_t ignored, int flags) { @@ -70,7 +93,9 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, struct sock *psk = ask->parent; struct alg_sock *pask = alg_sk(psk); struct af_alg_ctx *ctx = ask->private; - struct crypto_aead *tfm = pask->private; + struct aead_tfm *aeadc = pask->private; + struct crypto_aead *tfm = aeadc->aead; + struct crypto_sync_skcipher *null_tfm = aeadc->null_tfm; unsigned int as = crypto_aead_authsize(tfm); unsigned int ivsize = crypto_aead_ivsize(tfm); struct af_alg_async_req *areq; @@ -189,7 +214,10 @@ static int _aead_recvmsg(struct socket *sock, struct msghdr *msg, /* Use the RX SGL as source (and destination) for crypto op. */ rsgl_src = areq->first_rsgl.sgl.sg; - memcpy_sglist(rsgl_src, tsgl_src, ctx->aead_assoclen); + err = crypto_aead_copy_sgl(null_tfm, tsgl_src, rsgl_src, + ctx->aead_assoclen); + if (err) + goto free; /* Initialize the crypto operation */ aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, @@ -293,7 +321,7 @@ static int aead_check_key(struct socket *sock) int err = 0; struct sock *psk; struct alg_sock *pask; - struct crypto_aead *tfm; + struct aead_tfm *tfm; struct sock *sk = sock->sk; struct alg_sock *ask = alg_sk(sk); @@ -307,7 +335,7 @@ static int aead_check_key(struct socket *sock) err = -ENOKEY; lock_sock_nested(psk, SINGLE_DEPTH_NESTING); - if (crypto_aead_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) + if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY) goto unlock; atomic_dec(&pask->nokey_refcnt); @@ -381,22 +409,54 @@ static struct proto_ops algif_aead_ops_nokey = { static void *aead_bind(const char *name, u32 type, u32 mask) { - return crypto_alloc_aead(name, type, mask); + struct aead_tfm *tfm; + struct crypto_aead *aead; + struct crypto_sync_skcipher *null_tfm; + + tfm = kzalloc(sizeof(*tfm), GFP_KERNEL); + if (!tfm) + return ERR_PTR(-ENOMEM); + + aead = crypto_alloc_aead(name, type, mask); + if (IS_ERR(aead)) { + kfree(tfm); + return ERR_CAST(aead); + } + + null_tfm = crypto_get_default_null_skcipher(); + if (IS_ERR(null_tfm)) { + crypto_free_aead(aead); + kfree(tfm); + return ERR_CAST(null_tfm); + } + + tfm->aead = aead; + tfm->null_tfm = null_tfm; + + return tfm; } static void aead_release(void *private) { - crypto_free_aead(private); + struct aead_tfm *tfm = private; + + crypto_free_aead(tfm->aead); + crypto_put_default_null_skcipher(); + kfree(tfm); } static int aead_setauthsize(void *private, unsigned int authsize) { - return crypto_aead_setauthsize(private, authsize); + struct aead_tfm *tfm = private; + + return crypto_aead_setauthsize(tfm->aead, authsize); } static int aead_setkey(void *private, const u8 *key, unsigned int keylen) { - return crypto_aead_setkey(private, key, keylen); + struct aead_tfm *tfm = private; + + return crypto_aead_setkey(tfm->aead, key, keylen); } static void aead_sock_destruct(struct sock *sk) @@ -405,7 +465,8 @@ static void aead_sock_destruct(struct sock *sk) struct af_alg_ctx *ctx = ask->private; struct sock *psk = ask->parent; struct alg_sock *pask = alg_sk(psk); - struct crypto_aead *tfm = pask->private; + struct aead_tfm *aeadc = pask->private; + struct crypto_aead *tfm = aeadc->aead; unsigned int ivlen = crypto_aead_ivsize(tfm); af_alg_pull_tsgl(sk, ctx->used, NULL); @@ -418,9 +479,10 @@ static int aead_accept_parent_nokey(void *private, struct sock *sk) { struct af_alg_ctx *ctx; struct alg_sock *ask = alg_sk(sk); - struct crypto_aead *tfm = private; + struct aead_tfm *tfm = private; + struct crypto_aead *aead = tfm->aead; unsigned int len = sizeof(*ctx); - unsigned int ivlen = crypto_aead_ivsize(tfm); + unsigned int ivlen = crypto_aead_ivsize(aead); ctx = sock_kmalloc(sk, len, GFP_KERNEL); if (!ctx) @@ -447,9 +509,9 @@ static int aead_accept_parent_nokey(void *private, struct sock *sk) static int aead_accept_parent(void *private, struct sock *sk) { - struct crypto_aead *tfm = private; + struct aead_tfm *tfm = private; - if (crypto_aead_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) + if (crypto_aead_get_flags(tfm->aead) & CRYPTO_TFM_NEED_KEY) return -ENOKEY; return aead_accept_parent_nokey(private, sk); diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c index 8b31426092..edbdc19cdb 100644 --- a/crypto/algif_skcipher.c +++ b/crypto/algif_skcipher.c @@ -82,8 +82,14 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, * If more buffers are to be expected to be processed, process only * full block size buffers. */ - if (ctx->more || len < ctx->used) + if (ctx->more || len < ctx->used) { + if (len < bs) { + err = -EINVAL; + goto free; + } + len -= len % bs; + } /* * Create a per request TX SGL for this request which tracks the diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index ad8af3d70a..2e3fa520d6 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -138,12 +139,17 @@ struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1, size_t len_2) { struct asymmetric_key_id *kid; + size_t kid_sz; + size_t len; - kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2, - GFP_KERNEL); + if (check_add_overflow(len_1, len_2, &len)) + return ERR_PTR(-EOVERFLOW); + if (check_add_overflow(sizeof(struct asymmetric_key_id), len, &kid_sz)) + return ERR_PTR(-EOVERFLOW); + kid = kmalloc(kid_sz, GFP_KERNEL); if (!kid) return ERR_PTR(-ENOMEM); - kid->len = len_1 + len_2; + kid->len = len; memcpy(kid->data, val_1, len_1); memcpy(kid->data + len_1, val_2, len_2); return kid; diff --git a/crypto/authenc.c b/crypto/authenc.c index 206642e91b..670bf1a01d 100644 --- a/crypto/authenc.c +++ b/crypto/authenc.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ struct authenc_instance_ctx { struct crypto_authenc_ctx { struct crypto_ahash *auth; struct crypto_skcipher *enc; + struct crypto_sync_skcipher *null; }; struct authenc_request_ctx { @@ -172,6 +174,21 @@ out: authenc_request_complete(areq, err); } +static int crypto_authenc_copy_assoc(struct aead_request *req) +{ + struct crypto_aead *authenc = crypto_aead_reqtfm(req); + struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc); + SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); + + skcipher_request_set_sync_tfm(skreq, ctx->null); + skcipher_request_set_callback(skreq, aead_request_flags(req), + NULL, NULL); + skcipher_request_set_crypt(skreq, req->src, req->dst, req->assoclen, + NULL); + + return crypto_skcipher_encrypt(skreq); +} + static int crypto_authenc_encrypt(struct aead_request *req) { struct crypto_aead *authenc = crypto_aead_reqtfm(req); @@ -190,7 +207,10 @@ static int crypto_authenc_encrypt(struct aead_request *req) dst = src; if (req->src != req->dst) { - memcpy_sglist(req->dst, req->src, req->assoclen); + err = crypto_authenc_copy_assoc(req); + if (err) + return err; + dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, req->assoclen); } @@ -291,6 +311,7 @@ static int crypto_authenc_init_tfm(struct crypto_aead *tfm) struct crypto_authenc_ctx *ctx = crypto_aead_ctx(tfm); struct crypto_ahash *auth; struct crypto_skcipher *enc; + struct crypto_sync_skcipher *null; int err; auth = crypto_spawn_ahash(&ictx->auth); @@ -302,8 +323,14 @@ static int crypto_authenc_init_tfm(struct crypto_aead *tfm) if (IS_ERR(enc)) goto err_free_ahash; + null = crypto_get_default_null_skcipher(); + err = PTR_ERR(null); + if (IS_ERR(null)) + goto err_free_skcipher; + ctx->auth = auth; ctx->enc = enc; + ctx->null = null; crypto_aead_set_reqsize( tfm, @@ -317,6 +344,8 @@ static int crypto_authenc_init_tfm(struct crypto_aead *tfm) return 0; +err_free_skcipher: + crypto_free_skcipher(enc); err_free_ahash: crypto_free_ahash(auth); return err; @@ -328,6 +357,7 @@ static void crypto_authenc_exit_tfm(struct crypto_aead *tfm) crypto_free_ahash(ctx->auth); crypto_free_skcipher(ctx->enc); + crypto_put_default_null_skcipher(); } static void crypto_authenc_free(struct aead_instance *inst) diff --git a/crypto/authencesn.c b/crypto/authencesn.c index 2154d4ab5c..b0f40fe03b 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,7 @@ struct crypto_authenc_esn_ctx { unsigned int reqoff; struct crypto_ahash *auth; struct crypto_skcipher *enc; + struct crypto_sync_skcipher *null; }; struct authenc_esn_request_ctx { @@ -162,6 +164,28 @@ static void crypto_authenc_esn_encrypt_done(struct crypto_async_request *req, authenc_esn_request_complete(areq, err); } +static int crypto_authenc_esn_copy_sg(struct aead_request *req, + struct scatterlist *src, + struct scatterlist *dst, + unsigned int len) +{ + struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); + struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(authenc_esn); + SYNC_SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); + + skcipher_request_set_sync_tfm(skreq, ctx->null); + skcipher_request_set_callback(skreq, aead_request_flags(req), + NULL, NULL); + skcipher_request_set_crypt(skreq, src, dst, len, NULL); + + return crypto_skcipher_encrypt(skreq); +} + +static int crypto_authenc_esn_copy(struct aead_request *req, unsigned int len) +{ + return crypto_authenc_esn_copy_sg(req, req->src, req->dst, len); +} + static int crypto_authenc_esn_encrypt(struct aead_request *req) { struct crypto_aead *authenc_esn = crypto_aead_reqtfm(req); @@ -183,7 +207,10 @@ static int crypto_authenc_esn_encrypt(struct aead_request *req) dst = src; if (req->src != req->dst) { - memcpy_sglist(req->dst, req->src, assoclen); + err = crypto_authenc_esn_copy(req, assoclen); + if (err) + return err; + sg_init_table(areq_ctx->dst, 2); dst = scatterwalk_ffwd(areq_ctx->dst, req->dst, assoclen); } @@ -218,6 +245,7 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req, struct scatterlist *dst = req->dst; u8 *ihash = ohash + crypto_ahash_digestsize(auth); u32 tmp[2]; + int err; if (!authsize) goto decrypt; @@ -227,8 +255,11 @@ static int crypto_authenc_esn_decrypt_tail(struct aead_request *req, scatterwalk_map_and_copy(tmp, dst, 4, 4, 0); scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 0); scatterwalk_map_and_copy(tmp, dst, 0, 8, 1); - } else - memcpy_sglist(dst, src, assoclen); + } else { + err = crypto_authenc_esn_copy(req, assoclen); + if (err) + return err; + } if (crypto_memneq(ihash, ohash, authsize)) return -EBADMSG; @@ -298,7 +329,10 @@ static int crypto_authenc_esn_decrypt(struct aead_request *req) src = scatterwalk_ffwd(areq_ctx->src, src, 8); dst = scatterwalk_ffwd(areq_ctx->dst, dst, 4); - memcpy_sglist(dst, src, assoclen + cryptlen - 8); + err = crypto_authenc_esn_copy_sg(req, src, dst, + assoclen + cryptlen - 8); + if (err) + return err; dst = req->dst; } @@ -322,6 +356,7 @@ static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm) struct crypto_authenc_esn_ctx *ctx = crypto_aead_ctx(tfm); struct crypto_ahash *auth; struct crypto_skcipher *enc; + struct crypto_sync_skcipher *null; int err; auth = crypto_spawn_ahash(&ictx->auth); @@ -333,8 +368,14 @@ static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm) if (IS_ERR(enc)) goto err_free_ahash; + null = crypto_get_default_null_skcipher(); + err = PTR_ERR(null); + if (IS_ERR(null)) + goto err_free_skcipher; + ctx->auth = auth; ctx->enc = enc; + ctx->null = null; ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth), crypto_ahash_alignmask(auth) + 1); @@ -351,6 +392,8 @@ static int crypto_authenc_esn_init_tfm(struct crypto_aead *tfm) return 0; +err_free_skcipher: + crypto_free_skcipher(enc); err_free_ahash: crypto_free_ahash(auth); return err; @@ -362,6 +405,7 @@ static void crypto_authenc_esn_exit_tfm(struct crypto_aead *tfm) crypto_free_ahash(ctx->auth); crypto_free_skcipher(ctx->enc); + crypto_put_default_null_skcipher(); } static void crypto_authenc_esn_free(struct aead_instance *inst) @@ -400,6 +444,11 @@ static int crypto_authenc_esn_create(struct crypto_template *tmpl, auth = crypto_spawn_ahash_alg(&ctx->auth); auth_base = &auth->base; + if (auth->digestsize > 0 && auth->digestsize < 4) { + err = -EINVAL; + goto err_free_inst; + } + err = crypto_grab_skcipher(&ctx->enc, aead_crypto_instance(inst), crypto_attr_alg_name(tb[2]), 0, mask); if (err) diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c index 9f0b270051..16f6ba896f 100644 --- a/crypto/scatterwalk.c +++ b/crypto/scatterwalk.c @@ -69,100 +69,6 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, } EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy); -/** - * memcpy_sglist() - Copy data from one scatterlist to another - * @dst: The destination scatterlist. Can be NULL if @nbytes == 0. - * @src: The source scatterlist. Can be NULL if @nbytes == 0. - * @nbytes: Number of bytes to copy - * - * The scatterlists can describe exactly the same memory, in which case this - * function is a no-op. No other overlaps are supported. - * - * Context: Any context - */ -void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src, - unsigned int nbytes) -{ - unsigned int src_offset, dst_offset; - - if (unlikely(nbytes == 0)) /* in case src and/or dst is NULL */ - return; - - src_offset = src->offset; - dst_offset = dst->offset; - for (;;) { - /* Compute the length to copy this step. */ - unsigned int len = min3(src->offset + src->length - src_offset, - dst->offset + dst->length - dst_offset, - nbytes); - struct page *src_page = sg_page(src); - struct page *dst_page = sg_page(dst); - const void *src_virt; - void *dst_virt; - - if (IS_ENABLED(CONFIG_HIGHMEM)) { - /* HIGHMEM: we may have to actually map the pages. */ - const unsigned int src_oip = offset_in_page(src_offset); - const unsigned int dst_oip = offset_in_page(dst_offset); - const unsigned int limit = PAGE_SIZE; - - /* Further limit len to not cross a page boundary. */ - len = min3(len, limit - src_oip, limit - dst_oip); - - /* Compute the source and destination pages. */ - src_page += src_offset / PAGE_SIZE; - dst_page += dst_offset / PAGE_SIZE; - - if (src_page != dst_page) { - /* Copy between different pages. */ - memcpy_page(dst_page, dst_oip, - src_page, src_oip, len); - flush_dcache_page(dst_page); - } else if (src_oip != dst_oip) { - /* Copy between different parts of same page. */ - dst_virt = kmap_local_page(dst_page); - memcpy(dst_virt + dst_oip, dst_virt + src_oip, - len); - kunmap_local(dst_virt); - flush_dcache_page(dst_page); - } /* Else, it's the same memory. No action needed. */ - } else { - /* - * !HIGHMEM: no mapping needed. Just work in the linear - * buffer of each sg entry. Note that we can cross page - * boundaries, as they are not significant in this case. - */ - src_virt = page_address(src_page) + src_offset; - dst_virt = page_address(dst_page) + dst_offset; - if (src_virt != dst_virt) { - memcpy(dst_virt, src_virt, len); - if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE) - __scatterwalk_flush_dcache_pages( - dst_page, dst_offset, len); - } /* Else, it's the same memory. No action needed. */ - } - nbytes -= len; - if (nbytes == 0) /* No more to copy? */ - break; - - /* - * There's more to copy. Advance the offsets by the length - * copied this step, and advance the sg entries as needed. - */ - src_offset += len; - if (src_offset >= src->offset + src->length) { - src = sg_next(src); - src_offset = src->offset; - } - dst_offset += len; - if (dst_offset >= dst->offset + dst->length) { - dst = sg_next(dst); - dst_offset = dst->offset; - } - } -} -EXPORT_SYMBOL_GPL(memcpy_sglist); - struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2], struct scatterlist *src, unsigned int len) diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index a7743cc65d..9c60a7c7cb 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -2235,12 +2235,13 @@ again: ret = nbd_start_device(nbd); out: - mutex_unlock(&nbd->config_lock); if (!ret) { set_bit(NBD_RT_HAS_CONFIG_REF, &config->runtime_flags); refcount_inc(&nbd->config_refs); nbd_connect_reply(info, nbd->index); } + mutex_unlock(&nbd->config_lock); + nbd_config_put(nbd); if (put_dev) nbd_put(nbd); diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c index 0e07d05232..8b91f00b9c 100644 --- a/drivers/crypto/tegra/tegra-se-aes.c +++ b/drivers/crypto/tegra/tegra-se-aes.c @@ -4,6 +4,7 @@ * Crypto driver to handle block cipher algorithms using NVIDIA Security Engine. */ +#include #include #include #include @@ -333,7 +334,9 @@ out: tegra_key_invalidate_reserved(ctx->se, key2_id, ctx->alg); out_finalize: + local_bh_disable(); crypto_finalize_skcipher_request(se->engine, req, ret); + local_bh_enable(); return 0; } @@ -1261,7 +1264,9 @@ out_free_inbuf: tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); out_finalize: + local_bh_disable(); crypto_finalize_aead_request(ctx->se->engine, req, ret); + local_bh_enable(); return 0; } @@ -1347,7 +1352,9 @@ out_free_inbuf: tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); out_finalize: + local_bh_disable(); crypto_finalize_aead_request(ctx->se->engine, req, ret); + local_bh_enable(); return 0; } @@ -1745,7 +1752,9 @@ out: if (tegra_key_is_reserved(rctx->key_id)) tegra_key_invalidate_reserved(ctx->se, rctx->key_id, ctx->alg); + local_bh_disable(); crypto_finalize_hash_request(se->engine, req, ret); + local_bh_enable(); return 0; } diff --git a/drivers/crypto/tegra/tegra-se-hash.c b/drivers/crypto/tegra/tegra-se-hash.c index 42d007b7af..90bf34eb35 100644 --- a/drivers/crypto/tegra/tegra-se-hash.c +++ b/drivers/crypto/tegra/tegra-se-hash.c @@ -4,6 +4,7 @@ * Crypto driver to handle HASH algorithms using NVIDIA Security Engine. */ +#include #include #include #include @@ -543,7 +544,9 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq) } out: + local_bh_disable(); crypto_finalize_hash_request(se->engine, req, ret); + local_bh_enable(); return 0; } diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 83cbd64abf..95ae786e98 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -842,11 +842,21 @@ int dpll_pin_delete_ntf(struct dpll_pin *pin) return dpll_pin_event_send(DPLL_CMD_PIN_DELETE_NTF, pin); } +/** + * __dpll_pin_change_ntf - notify that the pin has been changed + * @pin: registered pin pointer + * + * Context: caller must hold dpll_lock. Suitable for use inside pin + * callbacks which are already invoked under dpll_lock. + * Return: 0 if succeeds, error code otherwise. + */ int __dpll_pin_change_ntf(struct dpll_pin *pin) { + lockdep_assert_held(&dpll_lock); dpll_pin_notify(pin, DPLL_PIN_CHANGED); return dpll_pin_event_send(DPLL_CMD_PIN_CHANGE_NTF, pin); } +EXPORT_SYMBOL_GPL(__dpll_pin_change_ntf); /** * dpll_pin_change_ntf - notify that the pin has been changed diff --git a/drivers/dpll/dpll_netlink.h b/drivers/dpll/dpll_netlink.h index dd28b56d27..a9cfd55f57 100644 --- a/drivers/dpll/dpll_netlink.h +++ b/drivers/dpll/dpll_netlink.h @@ -11,5 +11,3 @@ int dpll_device_delete_ntf(struct dpll_device *dpll); int dpll_pin_create_ntf(struct dpll_pin *pin); int dpll_pin_delete_ntf(struct dpll_pin *pin); - -int __dpll_pin_change_ntf(struct dpll_pin *pin); diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c index 60bf70f3c2..179fff5e7d 100644 --- a/drivers/dpll/zl3073x/core.c +++ b/drivers/dpll/zl3073x/core.c @@ -983,11 +983,7 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls) } /* Add devres action to release DPLL related resources */ - rc = devm_add_action_or_reset(zldev->dev, zl3073x_dev_dpll_fini, zldev); - if (rc) - goto error; - - return 0; + return devm_add_action_or_reset(zldev->dev, zl3073x_dev_dpll_fini, zldev); error: zl3073x_dev_dpll_fini(zldev); @@ -1028,6 +1024,7 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev, "Unknown or non-match chip ID: 0x%0x\n", id); } + zldev->chip_id = id; /* Read revision, firmware version and custom config version */ rc = zl3073x_read_u16(zldev, ZL_REG_REVISION, &revision); diff --git a/drivers/dpll/zl3073x/core.h b/drivers/dpll/zl3073x/core.h index 09bca2d092..fd2af3c62a 100644 --- a/drivers/dpll/zl3073x/core.h +++ b/drivers/dpll/zl3073x/core.h @@ -35,6 +35,7 @@ struct zl3073x_dpll; * @dev: pointer to device * @regmap: regmap to access device registers * @multiop_lock: to serialize multiple register operations + * @chip_id: chip ID read from hardware * @ref: array of input references' invariants * @out: array of outs' invariants * @synth: array of synths' invariants @@ -48,6 +49,7 @@ struct zl3073x_dev { struct device *dev; struct regmap *regmap; struct mutex multiop_lock; + u16 chip_id; /* Invariants */ struct zl3073x_ref ref[ZL3073X_NUM_REFS]; @@ -144,6 +146,32 @@ int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev, int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel); +/** + * zl3073x_dev_is_ref_phase_comp_32bit - check ref phase comp register size + * @zldev: pointer to zl3073x device + * + * Some chip IDs have a 32-bit wide ref_phase_offset_comp register instead + * of the default 48-bit. + * + * Return: true if the register is 32-bit, false if 48-bit + */ +static inline bool +zl3073x_dev_is_ref_phase_comp_32bit(struct zl3073x_dev *zldev) +{ + switch (zldev->chip_id) { + case 0x0E30: + case 0x0E93: + case 0x0E94: + case 0x0E95: + case 0x0E96: + case 0x0E97: + case 0x1F60: + return true; + default: + return false; + } +} + static inline bool zl3073x_is_n_pin(u8 id) { @@ -301,6 +329,36 @@ u8 zl3073x_dev_out_dpll_get(struct zl3073x_dev *zldev, u8 index) return zl3073x_synth_dpll_get(synth); } +/** + * zl3073x_dev_output_pin_freq_get - get output pin frequency + * @zldev: pointer to zl3073x device + * @id: output pin id + * + * Computes the output pin frequency based on the synth frequency, output + * divisor, and signal format. For N-div formats, N-pin frequency is + * additionally divided by esync_n_period. + * + * Return: frequency of the given output pin in Hz + */ +static inline u32 +zl3073x_dev_output_pin_freq_get(struct zl3073x_dev *zldev, u8 id) +{ + const struct zl3073x_synth *synth; + const struct zl3073x_out *out; + u8 out_id; + u32 freq; + + out_id = zl3073x_output_pin_out_get(id); + out = zl3073x_out_state_get(zldev, out_id); + synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out)); + freq = zl3073x_synth_freq_get(synth) / out->div; + + if (zl3073x_out_is_ndiv(out) && zl3073x_is_n_pin(id)) + freq /= out->esync_n_period; + + return freq; +} + /** * zl3073x_dev_out_is_diff - check if the given output is differential * @zldev: pointer to zl3073x device diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c index 897ed682db..8ffbede117 100644 --- a/drivers/dpll/zl3073x/dpll.c +++ b/drivers/dpll/zl3073x/dpll.c @@ -475,8 +475,11 @@ zl3073x_dpll_input_pin_phase_adjust_get(const struct dpll_pin *dpll_pin, ref_id = zl3073x_input_pin_ref_get(pin->id); ref = zl3073x_ref_state_get(zldev, ref_id); - /* Perform sign extension for 48bit signed value */ - phase_comp = sign_extend64(ref->phase_comp, 47); + /* Perform sign extension based on register width */ + if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) + phase_comp = sign_extend64(ref->phase_comp, 31); + else + phase_comp = sign_extend64(ref->phase_comp, 47); /* Reverse two's complement negation applied during set and convert * to 32bit signed int @@ -916,46 +919,9 @@ zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin, struct netlink_ext_ack *extack) { struct zl3073x_dpll *zldpll = dpll_priv; - struct zl3073x_dev *zldev = zldpll->dev; struct zl3073x_dpll_pin *pin = pin_priv; - const struct zl3073x_synth *synth; - const struct zl3073x_out *out; - u32 synth_freq; - u8 out_id; - out_id = zl3073x_output_pin_out_get(pin->id); - out = zl3073x_out_state_get(zldev, out_id); - - /* Get attached synth frequency */ - synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out)); - synth_freq = zl3073x_synth_freq_get(synth); - - switch (zl3073x_out_signal_format_get(out)) { - case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: - case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: - /* In case of divided format we have to distiguish between - * given output pin type. - * - * For P-pin the resulting frequency is computed as simple - * division of synth frequency and output divisor. - * - * For N-pin we have to divide additionally by divisor stored - * in esync_n_period output mailbox register that is used as - * N-pin divisor for these modes. - */ - *frequency = synth_freq / out->div; - - if (!zl3073x_dpll_is_p_pin(pin)) - *frequency = (u32)*frequency / out->esync_n_period; - - break; - default: - /* In other modes the resulting frequency is computed as - * division of synth frequency and output divisor. - */ - *frequency = synth_freq / out->div; - break; - } + *frequency = zl3073x_dev_output_pin_freq_get(zldpll->dev, pin->id); return 0; } diff --git a/drivers/dpll/zl3073x/out.h b/drivers/dpll/zl3073x/out.h index e8ea7a0e0f..318f9bb8da 100644 --- a/drivers/dpll/zl3073x/out.h +++ b/drivers/dpll/zl3073x/out.h @@ -79,6 +79,23 @@ static inline bool zl3073x_out_is_enabled(const struct zl3073x_out *out) return !!FIELD_GET(ZL_OUTPUT_CTRL_EN, out->ctrl); } +/** + * zl3073x_out_is_ndiv - check if the given output is in N-div mode + * @out: pointer to out state + * + * Return: true if output is in N-div mode, false otherwise + */ +static inline bool zl3073x_out_is_ndiv(const struct zl3073x_out *out) +{ + switch (zl3073x_out_signal_format_get(out)) { + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: + case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: + return true; + default: + return false; + } +} + /** * zl3073x_out_synth_get - get synth connected to given output * @out: pointer to out state diff --git a/drivers/dpll/zl3073x/prop.c b/drivers/dpll/zl3073x/prop.c index ad1f099cbe..8523dc8c22 100644 --- a/drivers/dpll/zl3073x/prop.c +++ b/drivers/dpll/zl3073x/prop.c @@ -193,9 +193,10 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, { struct dpll_pin_frequency *ranges; struct zl3073x_pin_props *props; - int i, j, num_freqs, rc; + int i, j, num_freqs = 0, rc; + u64 *freqs = NULL; const char *type; - u64 *freqs; + u32 curr_freq; props = kzalloc(sizeof(*props), GFP_KERNEL); if (!props) @@ -207,6 +208,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, props->dpll_props.capabilities = DPLL_PIN_CAPABILITIES_PRIORITY_CAN_CHANGE | DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE; + curr_freq = zl3073x_dev_ref_freq_get(zldev, index); } else { u8 out, synth; u32 f; @@ -220,6 +222,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, synth = zl3073x_dev_out_synth_get(zldev, out); f = 2 * zl3073x_dev_synth_freq_get(zldev, synth); props->dpll_props.phase_gran = f ? div_u64(PSEC_PER_SEC, f) : 1; + curr_freq = zl3073x_dev_output_pin_freq_get(zldev, index); } props->dpll_props.phase_range.min = S32_MIN; @@ -230,7 +233,7 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, /* Get firmware node for the given pin */ rc = zl3073x_prop_pin_fwnode_get(zldev, props, dir, index); if (rc) - return props; /* Return if it does not exist */ + goto skip_fwnode_props; /* Look for label property and store the value as board label */ fwnode_property_read_string(props->fwnode, "label", @@ -264,9 +267,10 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, /* Read supported frequencies property if it is specified */ num_freqs = fwnode_property_count_u64(props->fwnode, "supported-frequencies-hz"); - if (num_freqs <= 0) - /* Return if the property does not exist or number is 0 */ - return props; + if (num_freqs <= 0) { + num_freqs = 0; + goto skip_fwnode_props; + } /* The firmware node specifies list of supported frequencies while * DPLL core pin properties requires list of frequency ranges. @@ -283,19 +287,25 @@ struct zl3073x_pin_props *zl3073x_pin_props_get(struct zl3073x_dev *zldev, "supported-frequencies-hz", freqs, num_freqs); - /* Allocate frequency ranges list and fill it */ - ranges = kcalloc(num_freqs, sizeof(*ranges), GFP_KERNEL); +skip_fwnode_props: + /* Allocate frequency ranges list - extra slot for current frequency */ + ranges = kcalloc(num_freqs + 1, sizeof(*ranges), GFP_KERNEL); if (!ranges) { rc = -ENOMEM; goto err_alloc_ranges; } - /* Convert list of frequencies to list of frequency ranges but - * filter-out frequencies that are not representable by device + /* Start with current frequency at index 0 */ + ranges[0] = (struct dpll_pin_frequency)DPLL_PIN_FREQUENCY(curr_freq); + + /* Add frequencies from firmware node, skipping current frequency + * and filtering out frequencies not representable by device */ - for (i = 0, j = 0; i < num_freqs; i++) { + for (i = 0, j = 1; i < num_freqs; i++) { struct dpll_pin_frequency freq = DPLL_PIN_FREQUENCY(freqs[i]); + if (freqs[i] == curr_freq) + continue; if (zl3073x_pin_check_freq(zldev, dir, index, freqs[i])) { ranges[j] = freq; j++; diff --git a/drivers/dpll/zl3073x/ref.c b/drivers/dpll/zl3073x/ref.c index aa2de13eff..6b65e61039 100644 --- a/drivers/dpll/zl3073x/ref.c +++ b/drivers/dpll/zl3073x/ref.c @@ -121,8 +121,16 @@ int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index) return rc; /* Read phase compensation register */ - rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, - &ref->phase_comp); + if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) { + u32 val; + + rc = zl3073x_read_u32(zldev, ZL_REG_REF_PHASE_OFFSET_COMP_32, + &val); + ref->phase_comp = val; + } else { + rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, + &ref->phase_comp); + } if (rc) return rc; @@ -179,9 +187,16 @@ int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, if (!rc && dref->sync_ctrl != ref->sync_ctrl) rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL, ref->sync_ctrl); - if (!rc && dref->phase_comp != ref->phase_comp) - rc = zl3073x_write_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, - ref->phase_comp); + if (!rc && dref->phase_comp != ref->phase_comp) { + if (zl3073x_dev_is_ref_phase_comp_32bit(zldev)) + rc = zl3073x_write_u32(zldev, + ZL_REG_REF_PHASE_OFFSET_COMP_32, + ref->phase_comp); + else + rc = zl3073x_write_u48(zldev, + ZL_REG_REF_PHASE_OFFSET_COMP, + ref->phase_comp); + } if (rc) return rc; diff --git a/drivers/dpll/zl3073x/ref.h b/drivers/dpll/zl3073x/ref.h index efc7f59cd9..0d8618f5ce 100644 --- a/drivers/dpll/zl3073x/ref.h +++ b/drivers/dpll/zl3073x/ref.h @@ -91,6 +91,8 @@ zl3073x_ref_freq_set(struct zl3073x_ref *ref, u32 freq) ref->freq_base = base; ref->freq_mult = mult; + ref->freq_ratio_m = 1; + ref->freq_ratio_n = 1; return 0; } diff --git a/drivers/dpll/zl3073x/regs.h b/drivers/dpll/zl3073x/regs.h index d837bee72b..5573d71884 100644 --- a/drivers/dpll/zl3073x/regs.h +++ b/drivers/dpll/zl3073x/regs.h @@ -194,6 +194,7 @@ #define ZL_REF_CONFIG_DIFF_EN BIT(2) #define ZL_REG_REF_PHASE_OFFSET_COMP ZL_REG(10, 0x28, 6) +#define ZL_REG_REF_PHASE_OFFSET_COMP_32 ZL_REG(10, 0x28, 4) #define ZL_REG_REF_SYNC_CTRL ZL_REG(10, 0x2e, 1) #define ZL_REF_SYNC_CTRL_MODE GENMASK(2, 0) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index 37faa8f19f..297368ff42 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1655,7 +1655,7 @@ static int gen11_dsi_dsc_compute_config(struct intel_encoder *encoder, if (ret) return ret; - crtc_state->dsc.compression_enable = true; + intel_dsc_enable_on_crtc(crtc_state); return 0; } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 0d527cf228..f150cb802e 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4639,7 +4639,7 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, if (ret) return ret; - crtc_state->fec_enable = limits->force_fec_pipes & BIT(crtc->pipe); + crtc_state->dsc.compression_enabled_on_link = limits->link_dsc_pipes & BIT(crtc->pipe); crtc_state->max_link_bpp_x16 = limits->max_bpp_x16[crtc->pipe]; if (crtc_state->pipe_bpp > fxp_q4_to_int(crtc_state->max_link_bpp_x16)) { diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 358ab922d7..999566309f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -946,6 +946,12 @@ struct intel_csc_matrix { u16 postoff[3]; }; +enum intel_panel_replay_dsc_support { + INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED, + INTEL_DP_PANEL_REPLAY_DSC_FULL_FRAME_ONLY, + INTEL_DP_PANEL_REPLAY_DSC_SELECTIVE_UPDATE, +}; + struct intel_crtc_state { /* * uapi (drm) state. This is the software state shown to userspace. @@ -1124,6 +1130,8 @@ struct intel_crtc_state { bool has_panel_replay; bool wm_level_disabled; bool pkg_c_latency_used; + /* Only used for state verification. */ + enum intel_panel_replay_dsc_support panel_replay_dsc_support; u32 dc3co_exitline; u16 su_y_granularity; u8 active_non_psr_pipes; @@ -1268,6 +1276,8 @@ struct intel_crtc_state { /* Display Stream compression state */ struct { + /* Only used for state computation, not read out from the HW. */ + bool compression_enabled_on_link; bool compression_enable; int num_streams; /* Compressed Bpp in U6.4 format (first 4 bits for fractional part) */ @@ -1679,6 +1689,7 @@ struct intel_psr { bool source_panel_replay_support; bool sink_panel_replay_support; bool sink_panel_replay_su_support; + enum intel_panel_replay_dsc_support sink_panel_replay_dsc_support; bool panel_replay_enabled; u32 dc3co_exitline; u32 dc3co_exit_delay; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 2eab591a8e..7f3bfe22b7 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -2340,24 +2340,29 @@ static int intel_edp_dsc_compute_pipe_bpp(struct intel_dp *intel_dp, return 0; } -static void intel_dp_fec_compute_config(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state) +/* + * Return whether FEC must be enabled for 8b10b SST or MST links. On 128b132b + * links FEC is always enabled implicitly by the HW, so this function returns + * false for that case. + */ +bool intel_dp_needs_8b10b_fec(const struct intel_crtc_state *crtc_state, + bool dsc_enabled_on_crtc) { + if (intel_dp_is_uhbr(crtc_state)) + return false; + if (crtc_state->fec_enable) - return; + return true; /* * Though eDP v1.5 supports FEC with DSC, unlike DP, it is optional. * Since, FEC is a bandwidth overhead, continue to not enable it for * eDP. Until, there is a good reason to do so. */ - if (intel_dp_is_edp(intel_dp)) - return; + if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return false; - if (intel_dp_is_uhbr(crtc_state)) - return; - - crtc_state->fec_enable = true; + return dsc_enabled_on_crtc || intel_dsc_enabled_on_link(crtc_state); } int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, @@ -2375,7 +2380,11 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, bool is_mst = intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST); int ret; - intel_dp_fec_compute_config(intel_dp, pipe_config); + /* + * FIXME: set the FEC enabled state once pipe_config->port_clock is + * already known, so the UHBR/non-UHBR mode can be determined. + */ + pipe_config->fec_enable = intel_dp_needs_8b10b_fec(pipe_config, true); if (!intel_dp_dsc_supports_format(connector, pipe_config->output_format)) return -EINVAL; @@ -2450,7 +2459,8 @@ int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, return ret; } - pipe_config->dsc.compression_enable = true; + intel_dsc_enable_on_crtc(pipe_config); + drm_dbg_kms(display->drm, "DP DSC computed with Input Bpp = %d " "Compressed Bpp = " FXP_Q4_FMT " Slice Count = %d\n", pipe_config->pipe_bpp, @@ -5921,6 +5931,8 @@ intel_dp_detect(struct drm_connector *_connector, memset(connector->dp.dsc_dpcd, 0, sizeof(connector->dp.dsc_dpcd)); intel_dp->psr.sink_panel_replay_support = false; intel_dp->psr.sink_panel_replay_su_support = false; + intel_dp->psr.sink_panel_replay_dsc_support = + INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED; intel_dp_mst_disconnect(intel_dp); diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index f90cfd1dbb..1a5ef798fd 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -72,6 +72,8 @@ void intel_dp_encoder_flush_work(struct drm_encoder *encoder); int intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state); +bool intel_dp_needs_8b10b_fec(const struct intel_crtc_state *crtc_state, + bool dsc_enabled_on_crtc); int intel_dp_dsc_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state, diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 352f7ef29c..877bf47312 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -293,12 +293,15 @@ int intel_dp_mtp_tu_compute_config(struct intel_dp *intel_dp, mst_stream_update_slots(crtc_state, mst_state); } - if (dsc) { - if (!intel_dp_supports_fec(intel_dp, connector, crtc_state)) - return -EINVAL; - - crtc_state->fec_enable = !intel_dp_is_uhbr(crtc_state); - } + /* + * NOTE: The following must reset crtc_state->fec_enable for UHBR/DSC + * after it was set by intel_dp_dsc_compute_config() -> + * intel_dp_needs_8b10b_fec(). + */ + crtc_state->fec_enable = intel_dp_needs_8b10b_fec(crtc_state, dsc); + if (crtc_state->fec_enable && + !intel_dp_supports_fec(intel_dp, connector, crtc_state)) + return -EINVAL; max_dpt_bpp_x16 = fxp_q4_from_int(intel_dp_mst_max_dpt_bpp(crtc_state, dsc)); if (max_dpt_bpp_x16 && max_bpp_x16 > max_dpt_bpp_x16) { @@ -811,14 +814,14 @@ static u8 get_pipes_downstream_of_mst_port(struct intel_atomic_state *state, return mask; } -static int intel_dp_mst_check_fec_change(struct intel_atomic_state *state, +static int intel_dp_mst_check_dsc_change(struct intel_atomic_state *state, struct drm_dp_mst_topology_mgr *mst_mgr, struct intel_link_bw_limits *limits) { struct intel_display *display = to_intel_display(state); struct intel_crtc *crtc; u8 mst_pipe_mask; - u8 fec_pipe_mask = 0; + u8 dsc_pipe_mask = 0; int ret; mst_pipe_mask = get_pipes_downstream_of_mst_port(state, mst_mgr, NULL); @@ -831,16 +834,16 @@ static int intel_dp_mst_check_fec_change(struct intel_atomic_state *state, if (drm_WARN_ON(display->drm, !crtc_state)) return -EINVAL; - if (crtc_state->fec_enable) - fec_pipe_mask |= BIT(crtc->pipe); + if (intel_dsc_enabled_on_link(crtc_state)) + dsc_pipe_mask |= BIT(crtc->pipe); } - if (!fec_pipe_mask || mst_pipe_mask == fec_pipe_mask) + if (!dsc_pipe_mask || mst_pipe_mask == dsc_pipe_mask) return 0; - limits->force_fec_pipes |= mst_pipe_mask; + limits->link_dsc_pipes |= mst_pipe_mask; - ret = intel_modeset_pipes_in_mask_early(state, "MST FEC", + ret = intel_modeset_pipes_in_mask_early(state, "MST DSC", mst_pipe_mask); return ret ? : -EAGAIN; @@ -894,7 +897,7 @@ int intel_dp_mst_atomic_check_link(struct intel_atomic_state *state, int i; for_each_new_mst_mgr_in_state(&state->base, mgr, mst_state, i) { - ret = intel_dp_mst_check_fec_change(state, mgr, limits); + ret = intel_dp_mst_check_dsc_change(state, mgr, limits); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.c b/drivers/gpu/drm/i915/display/intel_link_bw.c index f52dee0ea4..d2862de894 100644 --- a/drivers/gpu/drm/i915/display/intel_link_bw.c +++ b/drivers/gpu/drm/i915/display/intel_link_bw.c @@ -20,6 +20,7 @@ #include "intel_dp_tunnel.h" #include "intel_fdi.h" #include "intel_link_bw.h" +#include "intel_vdsc.h" static int get_forced_link_bpp_x16(struct intel_atomic_state *state, const struct intel_crtc *crtc) @@ -55,7 +56,7 @@ void intel_link_bw_init_limits(struct intel_atomic_state *state, struct intel_display *display = to_intel_display(state); enum pipe pipe; - limits->force_fec_pipes = 0; + limits->link_dsc_pipes = 0; limits->bpp_limit_reached_pipes = 0; for_each_pipe(display, pipe) { struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe); @@ -65,8 +66,8 @@ void intel_link_bw_init_limits(struct intel_atomic_state *state, if (state->base.duplicated && crtc_state) { limits->max_bpp_x16[pipe] = crtc_state->max_link_bpp_x16; - if (crtc_state->fec_enable) - limits->force_fec_pipes |= BIT(pipe); + if (intel_dsc_enabled_on_link(crtc_state)) + limits->link_dsc_pipes |= BIT(pipe); } else { limits->max_bpp_x16[pipe] = INT_MAX; } @@ -265,10 +266,10 @@ assert_link_limit_change_valid(struct intel_display *display, bool bpps_changed = false; enum pipe pipe; - /* FEC can't be forced off after it was forced on. */ + /* DSC can't be disabled after it was enabled. */ if (drm_WARN_ON(display->drm, - (old_limits->force_fec_pipes & new_limits->force_fec_pipes) != - old_limits->force_fec_pipes)) + (old_limits->link_dsc_pipes & new_limits->link_dsc_pipes) != + old_limits->link_dsc_pipes)) return false; for_each_pipe(display, pipe) { @@ -286,8 +287,8 @@ assert_link_limit_change_valid(struct intel_display *display, /* At least one limit must change. */ if (drm_WARN_ON(display->drm, !bpps_changed && - new_limits->force_fec_pipes == - old_limits->force_fec_pipes)) + new_limits->link_dsc_pipes == + old_limits->link_dsc_pipes)) return false; return true; diff --git a/drivers/gpu/drm/i915/display/intel_link_bw.h b/drivers/gpu/drm/i915/display/intel_link_bw.h index 95ab7c50c6..cb18e17103 100644 --- a/drivers/gpu/drm/i915/display/intel_link_bw.h +++ b/drivers/gpu/drm/i915/display/intel_link_bw.h @@ -15,7 +15,7 @@ struct intel_connector; struct intel_crtc_state; struct intel_link_bw_limits { - u8 force_fec_pipes; + u8 link_dsc_pipes; u8 bpp_limit_reached_pipes; /* in 1/16 bpp units */ int max_bpp_x16[I915_MAX_PIPES]; diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index 6d9c95e5c0..5adbf7a4f2 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -29,6 +29,7 @@ #include #include "i915_reg.h" +#include "i915_utils.h" #include "intel_alpm.h" #include "intel_atomic.h" #include "intel_crtc.h" @@ -50,6 +51,7 @@ #include "intel_snps_phy.h" #include "intel_step.h" #include "intel_vblank.h" +#include "intel_vdsc.h" #include "intel_vrr.h" #include "skl_universal_plane.h" @@ -580,6 +582,44 @@ exit: intel_dp->psr.su_y_granularity = y; } +static enum intel_panel_replay_dsc_support +compute_pr_dsc_support(struct intel_dp *intel_dp) +{ + u8 pr_dsc_mode; + u8 val; + + val = intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_CAPABILITY)]; + pr_dsc_mode = REG_FIELD_GET8(DP_PANEL_REPLAY_DSC_DECODE_CAPABILITY_IN_PR_MASK, val); + + switch (pr_dsc_mode) { + case DP_DSC_DECODE_CAPABILITY_IN_PR_FULL_FRAME_ONLY: + return INTEL_DP_PANEL_REPLAY_DSC_FULL_FRAME_ONLY; + case DP_DSC_DECODE_CAPABILITY_IN_PR_SUPPORTED: + return INTEL_DP_PANEL_REPLAY_DSC_SELECTIVE_UPDATE; + default: + MISSING_CASE(pr_dsc_mode); + fallthrough; + case DP_DSC_DECODE_CAPABILITY_IN_PR_NOT_SUPPORTED: + case DP_DSC_DECODE_CAPABILITY_IN_PR_RESERVED: + return INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED; + } +} + +static const char *panel_replay_dsc_support_str(enum intel_panel_replay_dsc_support dsc_support) +{ + switch (dsc_support) { + case INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED: + return "not supported"; + case INTEL_DP_PANEL_REPLAY_DSC_FULL_FRAME_ONLY: + return "full frame only"; + case INTEL_DP_PANEL_REPLAY_DSC_SELECTIVE_UPDATE: + return "selective update"; + default: + MISSING_CASE(dsc_support); + return "n/a"; + }; +} + static void _panel_replay_init_dpcd(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); @@ -619,10 +659,13 @@ static void _panel_replay_init_dpcd(struct intel_dp *intel_dp) DP_PANEL_REPLAY_SU_SUPPORT) intel_dp->psr.sink_panel_replay_su_support = true; + intel_dp->psr.sink_panel_replay_dsc_support = compute_pr_dsc_support(intel_dp); + drm_dbg_kms(display->drm, - "Panel replay %sis supported by panel\n", + "Panel replay %sis supported by panel (in DSC mode: %s)\n", intel_dp->psr.sink_panel_replay_su_support ? - "selective_update " : ""); + "selective_update " : "", + panel_replay_dsc_support_str(intel_dp->psr.sink_panel_replay_dsc_support)); } static void _psr_init_dpcd(struct intel_dp *intel_dp) @@ -1534,9 +1577,21 @@ static bool intel_sel_update_config_valid(struct intel_dp *intel_dp, goto unsupported; } - if (crtc_state->has_panel_replay && (DISPLAY_VER(display) < 14 || - !intel_dp->psr.sink_panel_replay_su_support)) - goto unsupported; + if (crtc_state->has_panel_replay) { + if (DISPLAY_VER(display) < 14) + goto unsupported; + + if (!intel_dp->psr.sink_panel_replay_su_support) + goto unsupported; + + if (intel_dsc_enabled_on_link(crtc_state) && + intel_dp->psr.sink_panel_replay_dsc_support != + INTEL_DP_PANEL_REPLAY_DSC_SELECTIVE_UPDATE) { + drm_dbg_kms(display->drm, + "Selective update with Panel Replay not enabled because it's not supported with DSC\n"); + goto unsupported; + } + } if (crtc_state->crc_enabled) { drm_dbg_kms(display->drm, @@ -1613,6 +1668,14 @@ _panel_replay_compute_config(struct intel_dp *intel_dp, return false; } + if (intel_dsc_enabled_on_link(crtc_state) && + intel_dp->psr.sink_panel_replay_dsc_support == + INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED) { + drm_dbg_kms(display->drm, + "Panel Replay not enabled because it's not supported with DSC\n"); + return false; + } + if (!intel_dp_is_edp(intel_dp)) return true; @@ -1693,6 +1756,8 @@ void intel_psr_compute_config(struct intel_dp *intel_dp, return; } + /* Only used for state verification. */ + crtc_state->panel_replay_dsc_support = intel_dp->psr.sink_panel_replay_dsc_support; crtc_state->has_panel_replay = _panel_replay_compute_config(intel_dp, crtc_state, conn_state); @@ -2950,6 +3015,20 @@ void intel_psr_pre_plane_update(struct intel_atomic_state *state, } } +static void +verify_panel_replay_dsc_state(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + if (!crtc_state->has_panel_replay) + return; + + drm_WARN_ON(display->drm, + intel_dsc_enabled_on_link(crtc_state) && + crtc_state->panel_replay_dsc_support == + INTEL_DP_PANEL_REPLAY_DSC_NOT_SUPPORTED); +} + void intel_psr_post_plane_update(struct intel_atomic_state *state, struct intel_crtc *crtc) { @@ -2961,6 +3040,8 @@ void intel_psr_post_plane_update(struct intel_atomic_state *state, if (!crtc_state->has_psr) return; + verify_panel_replay_dsc_state(crtc_state); + for_each_intel_encoder_mask_with_psr(state->base.dev, encoder, crtc_state->uapi.encoder_mask) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -3990,6 +4071,8 @@ static void intel_psr_sink_capability(struct intel_dp *intel_dp, seq_printf(m, ", Panel Replay = %s", str_yes_no(psr->sink_panel_replay_support)); seq_printf(m, ", Panel Replay Selective Update = %s", str_yes_no(psr->sink_panel_replay_su_support)); + seq_printf(m, ", Panel Replay DSC support = %s", + panel_replay_dsc_support_str(psr->sink_panel_replay_dsc_support)); if (intel_dp->pr_dpcd[INTEL_PR_DPCD_INDEX(DP_PANEL_REPLAY_CAP_SUPPORT)] & DP_PANEL_REPLAY_EARLY_TRANSPORT_SUPPORT) seq_printf(m, " (Early Transport)"); diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.c b/drivers/gpu/drm/i915/display/intel_vdsc.c index 8e799e225a..316753205a 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.c +++ b/drivers/gpu/drm/i915/display/intel_vdsc.c @@ -372,6 +372,22 @@ int intel_dsc_compute_params(struct intel_crtc_state *pipe_config) return 0; } +void intel_dsc_enable_on_crtc(struct intel_crtc_state *crtc_state) +{ + crtc_state->dsc.compression_enabled_on_link = true; + crtc_state->dsc.compression_enable = true; +} + +bool intel_dsc_enabled_on_link(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + + drm_WARN_ON(display->drm, crtc_state->dsc.compression_enable && + !crtc_state->dsc.compression_enabled_on_link); + + return crtc_state->dsc.compression_enabled_on_link; +} + enum intel_display_power_domain intel_dsc_power_domain(struct intel_crtc *crtc, enum transcoder cpu_transcoder) { diff --git a/drivers/gpu/drm/i915/display/intel_vdsc.h b/drivers/gpu/drm/i915/display/intel_vdsc.h index 9e2812f99d..9c52ece002 100644 --- a/drivers/gpu/drm/i915/display/intel_vdsc.h +++ b/drivers/gpu/drm/i915/display/intel_vdsc.h @@ -20,6 +20,8 @@ void intel_uncompressed_joiner_enable(const struct intel_crtc_state *crtc_state) void intel_dsc_enable(const struct intel_crtc_state *crtc_state); void intel_dsc_disable(const struct intel_crtc_state *crtc_state); int intel_dsc_compute_params(struct intel_crtc_state *pipe_config); +void intel_dsc_enable_on_crtc(struct intel_crtc_state *crtc_state); +bool intel_dsc_enabled_on_link(const struct intel_crtc_state *crtc_state); void intel_dsc_get_config(struct intel_crtc_state *crtc_state); enum intel_display_power_domain intel_dsc_power_domain(struct intel_crtc *crtc, enum transcoder cpu_transcoder); diff --git a/drivers/gpu/drm/mgag200/mgag200_bmc.c b/drivers/gpu/drm/mgag200/mgag200_bmc.c index a689c71ff1..bbdeb791c5 100644 --- a/drivers/gpu/drm/mgag200/mgag200_bmc.c +++ b/drivers/gpu/drm/mgag200/mgag200_bmc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include +#include #include #include @@ -12,7 +13,7 @@ void mgag200_bmc_stop_scanout(struct mga_device *mdev) { u8 tmp; - int iter_max; + int ret; /* * 1 - The first step is to inform the BMC of an upcoming mode @@ -42,30 +43,22 @@ void mgag200_bmc_stop_scanout(struct mga_device *mdev) /* * 3a- The third step is to verify if there is an active scan. - * We are waiting for a 0 on remhsyncsts ). + * We are waiting for a 0 on remhsyncsts (). */ - iter_max = 300; - while (!(tmp & 0x1) && iter_max) { - WREG8(DAC_INDEX, MGA1064_SPAREREG); - tmp = RREG8(DAC_DATA); - udelay(1000); - iter_max--; - } + ret = read_poll_timeout(RREG_DAC, tmp, !(tmp & 0x1), + 1000, 300000, false, + MGA1064_SPAREREG); + if (ret == -ETIMEDOUT) + return; /* - * 3b- This step occurs only if the remove is actually + * 3b- This step occurs only if the remote BMC is actually * scanning. We are waiting for the end of the frame which is * a 1 on remvsyncsts (XSPAREREG<1>) */ - if (iter_max) { - iter_max = 300; - while ((tmp & 0x2) && iter_max) { - WREG8(DAC_INDEX, MGA1064_SPAREREG); - tmp = RREG8(DAC_DATA); - udelay(1000); - iter_max--; - } - } + (void)read_poll_timeout(RREG_DAC, tmp, (tmp & 0x2), + 1000, 300000, false, + MGA1064_SPAREREG); } void mgag200_bmc_start_scanout(struct mga_device *mdev) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index f4bf40cd7c..a875c4bf8c 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -111,6 +111,12 @@ #define DAC_INDEX 0x3c00 #define DAC_DATA 0x3c0a +#define RREG_DAC(reg) \ + ({ \ + WREG8(DAC_INDEX, reg); \ + RREG8(DAC_DATA); \ + }) \ + #define WREG_DAC(reg, v) \ do { \ WREG8(DAC_INDEX, reg); \ diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 955b39d225..da6e7410ee 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1207,10 +1207,20 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len) switch (data[0]) { case 0x04: + if (len < 32) { + dev_warn(wacom->pen_input->dev.parent, + "Report 0x04 too short: %zu bytes\n", len); + break; + } wacom_intuos_bt_process_data(wacom, data + i); i += 10; fallthrough; case 0x03: + if (i == 1 && len < 22) { + dev_warn(wacom->pen_input->dev.parent, + "Report 0x03 too short: %zu bytes\n", len); + break; + } wacom_intuos_bt_process_data(wacom, data + i); i += 10; wacom_intuos_bt_process_data(wacom, data + i); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 171d29d277..b6a32c7c4a 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -303,9 +303,10 @@ struct i801_priv { /* * If set to true the host controller registers are reserved for - * ACPI AML use. + * ACPI AML use. Needs extra protection by acpi_lock. */ bool acpi_reserved; + struct mutex acpi_lock; }; #define FEATURE_SMBUS_PEC BIT(0) @@ -893,8 +894,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, int hwpec, ret; struct i801_priv *priv = i2c_get_adapdata(adap); - if (priv->acpi_reserved) + mutex_lock(&priv->acpi_lock); + if (priv->acpi_reserved) { + mutex_unlock(&priv->acpi_lock); return -EBUSY; + } pm_runtime_get_sync(&priv->pci_dev->dev); @@ -935,6 +939,7 @@ out: pm_runtime_mark_last_busy(&priv->pci_dev->dev); pm_runtime_put_autosuspend(&priv->pci_dev->dev); + mutex_unlock(&priv->acpi_lock); return ret; } @@ -1462,7 +1467,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, * further access from the driver itself. This device is now owned * by the system firmware. */ - i2c_lock_bus(&priv->adapter, I2C_LOCK_SEGMENT); + mutex_lock(&priv->acpi_lock); if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) { priv->acpi_reserved = true; @@ -1482,7 +1487,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, else status = acpi_os_write_port(address, (u32)*value, bits); - i2c_unlock_bus(&priv->adapter, I2C_LOCK_SEGMENT); + mutex_unlock(&priv->acpi_lock); return status; } @@ -1542,6 +1547,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->adapter.dev.parent = &dev->dev; acpi_use_parent_companion(&priv->adapter.dev); priv->adapter.retries = 3; + mutex_init(&priv->acpi_lock); priv->pci_dev = dev; priv->features = id->driver_data; diff --git a/drivers/infiniband/core/umem_dmabuf.c b/drivers/infiniband/core/umem_dmabuf.c index 2023a735de..8d64302780 100644 --- a/drivers/infiniband/core/umem_dmabuf.c +++ b/drivers/infiniband/core/umem_dmabuf.c @@ -220,13 +220,11 @@ ib_umem_dmabuf_get_pinned_with_dma_device(struct ib_device *device, err = ib_umem_dmabuf_map_pages(umem_dmabuf); if (err) - goto err_unpin; + goto err_release; dma_resv_unlock(umem_dmabuf->attach->dmabuf->resv); return umem_dmabuf; -err_unpin: - dma_buf_unpin(umem_dmabuf->attach); err_release: dma_resv_unlock(umem_dmabuf->attach->dmabuf->resv); ib_umem_release(&umem_dmabuf->umem); diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h index b758705e20..6df5a2738c 100644 --- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h +++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h @@ -225,6 +225,8 @@ struct bnxt_re_dev { unsigned long event_bitmap; struct bnxt_qplib_cc_param cc_param; struct workqueue_struct *dcb_wq; + struct dentry *cc_config; + struct bnxt_re_dbg_cc_config_params *cc_config_params; }; #define to_bnxt_re_dev(ptr, member) \ diff --git a/drivers/infiniband/hw/bnxt_re/debugfs.c b/drivers/infiniband/hw/bnxt_re/debugfs.c index 7c47039044..e632f1661b 100644 --- a/drivers/infiniband/hw/bnxt_re/debugfs.c +++ b/drivers/infiniband/hw/bnxt_re/debugfs.c @@ -22,6 +22,23 @@ static struct dentry *bnxt_re_debugfs_root; +static const char * const bnxt_re_cc_gen0_name[] = { + "enable_cc", + "run_avg_weight_g", + "num_phase_per_state", + "init_cr", + "init_tr", + "tos_ecn", + "tos_dscp", + "alt_vlan_pcp", + "alt_vlan_dscp", + "rtt", + "cc_mode", + "tcp_cp", + "tx_queue", + "inactivity_cp", +}; + static inline const char *bnxt_re_qp_state_str(u8 state) { switch (state) { @@ -110,19 +127,223 @@ void bnxt_re_debug_rem_qpinfo(struct bnxt_re_dev *rdev, struct bnxt_re_qp *qp) debugfs_remove(qp->dentry); } +static int map_cc_config_offset_gen0_ext0(u32 offset, struct bnxt_qplib_cc_param *ccparam, u32 *val) +{ + u64 map_offset; + + map_offset = BIT(offset); + + switch (map_offset) { + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ENABLE_CC: + *val = ccparam->enable; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_G: + *val = ccparam->g; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_NUMPHASEPERSTATE: + *val = ccparam->nph_per_state; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_CR: + *val = ccparam->init_cr; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_TR: + *val = ccparam->init_tr; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_ECN: + *val = ccparam->tos_ecn; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_DSCP: + *val = ccparam->tos_dscp; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_VLAN_PCP: + *val = ccparam->alt_vlan_pcp; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_TOS_DSCP: + *val = ccparam->alt_tos_dscp; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_RTT: + *val = ccparam->rtt; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_CC_MODE: + *val = ccparam->cc_mode; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TCP_CP: + *val = ccparam->tcp_cp; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INACTIVITY_CP: + *val = ccparam->inact_th; + break; + default: + return -EINVAL; + } + + return 0; +} + +static ssize_t bnxt_re_cc_config_get(struct file *filp, char __user *buffer, + size_t usr_buf_len, loff_t *ppos) +{ + struct bnxt_re_cc_param *dbg_cc_param = filp->private_data; + struct bnxt_re_dev *rdev = dbg_cc_param->rdev; + struct bnxt_qplib_cc_param ccparam = {}; + u32 offset = dbg_cc_param->offset; + char buf[16]; + u32 val; + int rc; + + rc = bnxt_qplib_query_cc_param(&rdev->qplib_res, &ccparam); + if (rc) + return rc; + + rc = map_cc_config_offset_gen0_ext0(offset, &ccparam, &val); + if (rc) + return rc; + + rc = snprintf(buf, sizeof(buf), "%d\n", val); + if (rc < 0) + return rc; + + return simple_read_from_buffer(buffer, usr_buf_len, ppos, (u8 *)(buf), rc); +} + +static int bnxt_re_fill_gen0_ext0(struct bnxt_qplib_cc_param *ccparam, u32 offset, u32 val) +{ + u32 modify_mask; + + modify_mask = BIT(offset); + + switch (modify_mask) { + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ENABLE_CC: + ccparam->enable = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_G: + ccparam->g = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_NUMPHASEPERSTATE: + ccparam->nph_per_state = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_CR: + ccparam->init_cr = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INIT_TR: + ccparam->init_tr = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_ECN: + ccparam->tos_ecn = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TOS_DSCP: + ccparam->tos_dscp = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_VLAN_PCP: + ccparam->alt_vlan_pcp = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_ALT_TOS_DSCP: + ccparam->alt_tos_dscp = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_RTT: + ccparam->rtt = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_CC_MODE: + ccparam->cc_mode = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TCP_CP: + ccparam->tcp_cp = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TX_QUEUE: + return -EOPNOTSUPP; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_INACTIVITY_CP: + ccparam->inact_th = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_TIME_PER_PHASE: + ccparam->time_pph = val; + break; + case CMDQ_MODIFY_ROCE_CC_MODIFY_MASK_PKTS_PER_PHASE: + ccparam->pkts_pph = val; + break; + } + + ccparam->mask = modify_mask; + return 0; +} + +static int bnxt_re_configure_cc(struct bnxt_re_dev *rdev, u32 gen_ext, u32 offset, u32 val) +{ + struct bnxt_qplib_cc_param ccparam = { }; + int rc; + + if (gen_ext != CC_CONFIG_GEN0_EXT0) + return -EOPNOTSUPP; + + rc = bnxt_re_fill_gen0_ext0(&ccparam, offset, val); + if (rc) + return rc; + + bnxt_qplib_modify_cc(&rdev->qplib_res, &ccparam); + return 0; +} + +static ssize_t bnxt_re_cc_config_set(struct file *filp, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct bnxt_re_cc_param *dbg_cc_param = filp->private_data; + struct bnxt_re_dev *rdev = dbg_cc_param->rdev; + u32 offset = dbg_cc_param->offset; + u8 cc_gen = dbg_cc_param->cc_gen; + char buf[16]; + u32 val; + int rc; + + if (count >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, buffer, count)) + return -EFAULT; + + buf[count] = '\0'; + if (kstrtou32(buf, 0, &val)) + return -EINVAL; + + rc = bnxt_re_configure_cc(rdev, cc_gen, offset, val); + return rc ? rc : count; +} + +static const struct file_operations bnxt_re_cc_config_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = bnxt_re_cc_config_get, + .write = bnxt_re_cc_config_set, +}; + void bnxt_re_debugfs_add_pdev(struct bnxt_re_dev *rdev) { struct pci_dev *pdev = rdev->en_dev->pdev; + struct bnxt_re_dbg_cc_config_params *cc_params; + int i; rdev->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), bnxt_re_debugfs_root); rdev->qp_debugfs = debugfs_create_dir("QPs", rdev->dbg_root); + rdev->cc_config = debugfs_create_dir("cc_config", rdev->dbg_root); + + rdev->cc_config_params = kzalloc(sizeof(*cc_params), GFP_KERNEL); + + for (i = 0; i < BNXT_RE_CC_PARAM_GEN0; i++) { + struct bnxt_re_cc_param *tmp_params = &rdev->cc_config_params->gen0_parms[i]; + + tmp_params->rdev = rdev; + tmp_params->offset = i; + tmp_params->cc_gen = CC_CONFIG_GEN0_EXT0; + tmp_params->dentry = debugfs_create_file(bnxt_re_cc_gen0_name[i], 0400, + rdev->cc_config, tmp_params, + &bnxt_re_cc_config_ops); + } } void bnxt_re_debugfs_rem_pdev(struct bnxt_re_dev *rdev) { debugfs_remove_recursive(rdev->qp_debugfs); - + debugfs_remove_recursive(rdev->cc_config); + kfree(rdev->cc_config_params); debugfs_remove_recursive(rdev->dbg_root); rdev->dbg_root = NULL; } diff --git a/drivers/infiniband/hw/bnxt_re/debugfs.h b/drivers/infiniband/hw/bnxt_re/debugfs.h index cd3be0a9ec..8f101df4e8 100644 --- a/drivers/infiniband/hw/bnxt_re/debugfs.h +++ b/drivers/infiniband/hw/bnxt_re/debugfs.h @@ -18,4 +18,19 @@ void bnxt_re_debugfs_rem_pdev(struct bnxt_re_dev *rdev); void bnxt_re_register_debugfs(void); void bnxt_re_unregister_debugfs(void); +#define CC_CONFIG_GEN_EXT(x, y) (((x) << 16) | (y)) +#define CC_CONFIG_GEN0_EXT0 CC_CONFIG_GEN_EXT(0, 0) + +#define BNXT_RE_CC_PARAM_GEN0 14 + +struct bnxt_re_cc_param { + struct bnxt_re_dev *rdev; + struct dentry *dentry; + u32 offset; + u8 cc_gen; +}; + +struct bnxt_re_dbg_cc_config_params { + struct bnxt_re_cc_param gen0_parms[BNXT_RE_CC_PARAM_GEN0]; +}; #endif diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index da5a0e3041..37c2bc3bdb 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -4746,7 +4746,7 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_TOGGLE_MEM)(struct uverbs_attr_bund return err; err = uverbs_copy_to(attrs, BNXT_RE_TOGGLE_MEM_MMAP_OFFSET, - &offset, sizeof(length)); + &offset, sizeof(offset)); if (err) return err; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c index 457eecb99f..dfe3177123 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c @@ -1113,7 +1113,7 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp) qp_flags |= CMDQ_CREATE_QP_QP_FLAGS_FORCE_COMPLETION; if (qp->wqe_mode == BNXT_QPLIB_WQE_MODE_VARIABLE) qp_flags |= CMDQ_CREATE_QP_QP_FLAGS_VARIABLE_SIZED_WQE_ENABLED; - if (_is_ext_stats_supported(res->dattr->dev_cap_flags) && !res->is_vf) + if (bnxt_ext_stats_supported(res->cctx, res->dattr->dev_cap_flags, res->is_vf)) qp_flags |= CMDQ_CREATE_QP_QP_FLAGS_EXT_STATS_ENABLED; req.qp_flags = cpu_to_le32(qp_flags); @@ -1750,9 +1750,9 @@ static void bnxt_qplib_fill_psn_search(struct bnxt_qplib_qp *qp, } } -static int bnxt_qplib_put_inline(struct bnxt_qplib_qp *qp, - struct bnxt_qplib_swqe *wqe, - u16 *idx) +static unsigned int bnxt_qplib_put_inline(struct bnxt_qplib_qp *qp, + struct bnxt_qplib_swqe *wqe, + u32 *idx) { struct bnxt_qplib_hwq *hwq; int len, t_len, offt; @@ -1769,7 +1769,7 @@ static int bnxt_qplib_put_inline(struct bnxt_qplib_qp *qp, il_src = (void *)wqe->sg_list[indx].addr; t_len += len; if (t_len > qp->max_inline_data) - return -ENOMEM; + return BNXT_RE_INVAL_MSG_SIZE; while (len) { if (pull_dst) { pull_dst = false; @@ -1795,9 +1795,9 @@ static int bnxt_qplib_put_inline(struct bnxt_qplib_qp *qp, return t_len; } -static u32 bnxt_qplib_put_sges(struct bnxt_qplib_hwq *hwq, - struct bnxt_qplib_sge *ssge, - u16 nsge, u16 *idx) +static unsigned int bnxt_qplib_put_sges(struct bnxt_qplib_hwq *hwq, + struct bnxt_qplib_sge *ssge, + u32 nsge, u32 *idx) { struct sq_sge *dsge; int indx, len = 0; @@ -1878,14 +1878,12 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, struct bnxt_qplib_hwq *hwq; struct bnxt_qplib_swq *swq; bool sch_handler = false; + u32 wqe_idx, slots, idx; u16 wqe_sz, qdf = 0; bool msn_update; void *base_hdr; void *ext_hdr; __le32 temp32; - u32 wqe_idx; - u32 slots; - u16 idx; hwq = &sq->hwq; if (qp->state != CMDQ_MODIFY_QP_NEW_STATE_RTS && @@ -1937,8 +1935,10 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp, else data_len = bnxt_qplib_put_sges(hwq, wqe->sg_list, wqe->num_sge, &idx); - if (data_len < 0) - goto queue_err; + if (data_len > BNXT_RE_MAX_MSG_SIZE) { + rc = -EINVAL; + goto done; + } /* Make sure we update MSN table only for wired wqes */ msn_update = true; /* Specifics */ @@ -2139,8 +2139,8 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp, struct bnxt_qplib_hwq *hwq; struct bnxt_qplib_swq *swq; bool sch_handler = false; - u16 wqe_sz, idx; - u32 wqe_idx; + u32 wqe_idx, idx; + u16 wqe_sz; int rc = 0; hwq = &rq->hwq; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h index 0d9487c889..ab125f1d94 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h @@ -346,6 +346,9 @@ struct bnxt_qplib_qp { u8 tos_dscp; }; +#define BNXT_RE_MAX_MSG_SIZE 0x80000000 +#define BNXT_RE_INVAL_MSG_SIZE 0xFFFFFFFF + #define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE sizeof(struct cq_base) #define CQE_CNT_PER_PG (PAGE_SIZE / BNXT_QPLIB_MAX_CQE_ENTRY_SIZE) diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index d230743834..804bc773b4 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -160,7 +160,7 @@ static int __wait_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie) wait_event_timeout(cmdq->waitq, !crsqe->is_in_used || test_bit(ERR_DEVICE_DETACHED, &cmdq->flags), - msecs_to_jiffies(rcfw->max_timeout * 1000)); + secs_to_jiffies(rcfw->max_timeout)); if (!crsqe->is_in_used) return 0; diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c index f231e886ad..6898139959 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c @@ -674,7 +674,7 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr, req.log2_pbl_pg_size = cpu_to_le16(((ilog2(PAGE_SIZE) << CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_SFT) & CMDQ_REGISTER_MR_LOG2_PBL_PG_SIZE_MASK)); - req.access = (mr->access_flags & 0xFFFF); + req.access = (mr->access_flags & BNXT_QPLIB_MR_ACCESS_MASK); req.va = cpu_to_le64(mr->va); req.key = cpu_to_le32(mr->lkey); if (_is_alloc_mr_unified(res->dattr->dev_cap_flags)) @@ -846,7 +846,12 @@ int bnxt_qplib_qext_stat(struct bnxt_qplib_rcfw *rcfw, u32 fid, req.resp_size = sbuf.size / BNXT_QPLIB_CMDQE_UNITS; req.resp_addr = cpu_to_le64(sbuf.dma_addr); - req.function_id = cpu_to_le32(fid); + if (bnxt_qplib_is_chip_gen_p7(rcfw->res->cctx) && rcfw->res->is_vf) + req.function_id = + cpu_to_le32(CMDQ_QUERY_ROCE_STATS_EXT_VF_VALID | + (fid << CMDQ_QUERY_ROCE_STATS_EXT_VF_NUM_SFT)); + else + req.function_id = cpu_to_le32(fid); req.flags = cpu_to_le16(CMDQ_QUERY_ROCE_STATS_EXT_FLAGS_FUNCTION_ID); bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, &sbuf, sizeof(req), diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.h b/drivers/infiniband/hw/bnxt_re/qplib_sp.h index e626b05038..09faf4a1e8 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_sp.h +++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.h @@ -111,6 +111,7 @@ struct bnxt_qplib_mrw { struct bnxt_qplib_pd *pd; int type; u32 access_flags; +#define BNXT_QPLIB_MR_ACCESS_MASK 0xFF #define BNXT_QPLIB_FR_PMR 0x80000000 u32 lkey; u32 rkey; diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c index 1a51cfd828..f2267d22af 100644 --- a/drivers/iommu/iommu-sva.c +++ b/drivers/iommu/iommu-sva.c @@ -6,12 +6,21 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include "iommu-priv.h" static DEFINE_MUTEX(iommu_sva_lock); static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev, struct mm_struct *mm); +static int iommu_sva_track_mm(struct mm_struct *mm); +static void iommu_sva_untrack_mm(struct mm_struct *mm); /* Allocate a PASID for the mm within range (inclusive) */ static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct device *dev) @@ -136,10 +145,20 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm out: refcount_set(&handle->users, 1); + ret = iommu_sva_track_mm(mm); + if (ret) + goto out_unwind; mutex_unlock(&iommu_sva_lock); handle->dev = dev; return handle; +out_unwind: + iommu_detach_device_pasid(domain, dev, iommu_mm->pasid); + if (--domain->users == 0) { + list_del(&domain->next); + iommu_domain_free(domain); + } + goto out_free_handle; out_free_domain: iommu_domain_free(domain); out_free_handle: @@ -170,6 +189,7 @@ void iommu_sva_unbind_device(struct iommu_sva *handle) return; } + iommu_sva_untrack_mm(domain->mm); iommu_detach_device_pasid(domain, dev, iommu_mm->pasid); if (--domain->users == 0) { list_del(&domain->next); @@ -312,3 +332,127 @@ static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev, return domain; } + +/* + * Track mm_structs with active SVA bindings so we can flush IOMMU + * cached translations when kernel page table pages are freed. + */ +struct sva_mm { + struct mm_struct *mm; + struct list_head list; + struct rcu_head rcu; + int refcount; +}; + +static DEFINE_SPINLOCK(sva_mm_lock); +static LIST_HEAD(sva_mm_list); +static atomic_t sva_mm_count = ATOMIC_INIT(0); + +/** + * iommu_sva_track_mm - Start tracking an mm for kernel PT change notification + * @mm: the mm_struct to track + * + * Called when SVA is bound for this mm. If the mm is already tracked, + * increments the refcount. Otherwise allocates a new tracking entry. + * + * Returns 0 on success, -ENOMEM on allocation failure. + */ +static int iommu_sva_track_mm(struct mm_struct *mm) +{ + struct sva_mm *smm; + unsigned long flags; + + spin_lock_irqsave(&sva_mm_lock, flags); + list_for_each_entry(smm, &sva_mm_list, list) { + if (smm->mm == mm) { + smm->refcount++; + spin_unlock_irqrestore(&sva_mm_lock, flags); + return 0; + } + } + spin_unlock_irqrestore(&sva_mm_lock, flags); + + smm = kzalloc(sizeof(*smm), GFP_KERNEL); + if (!smm) + return -ENOMEM; + + smm->mm = mm; + smm->refcount = 1; + + spin_lock_irqsave(&sva_mm_lock, flags); + { + struct sva_mm *existing; + + list_for_each_entry(existing, &sva_mm_list, list) { + if (existing->mm == mm) { + existing->refcount++; + spin_unlock_irqrestore(&sva_mm_lock, flags); + kfree(smm); + return 0; + } + } + } + list_add_rcu(&smm->list, &sva_mm_list); + atomic_inc(&sva_mm_count); + spin_unlock_irqrestore(&sva_mm_lock, flags); + return 0; +} + +/** + * iommu_sva_untrack_mm - Stop tracking an mm for kernel PT change notification + * @mm: the mm_struct to untrack + * + * Called when SVA is unbound for this mm. Decrements the refcount and + * removes the tracking entry when it reaches zero. + */ +static void iommu_sva_untrack_mm(struct mm_struct *mm) +{ + struct sva_mm *smm; + unsigned long flags; + + spin_lock_irqsave(&sva_mm_lock, flags); + list_for_each_entry(smm, &sva_mm_list, list) { + if (smm->mm == mm) { + if (--smm->refcount == 0) { + list_del_rcu(&smm->list); + atomic_dec(&sva_mm_count); + spin_unlock_irqrestore(&sva_mm_lock, flags); + kfree_rcu(smm, rcu); + return; + } + spin_unlock_irqrestore(&sva_mm_lock, flags); + return; + } + } + spin_unlock_irqrestore(&sva_mm_lock, flags); + WARN(1, "iommu_sva_untrack_mm: mm %px not found\n", mm); +} + +/** + * iommu_sva_invalidate_kva_range - Flush IOMMU caches before kernel PT free + * @start: Start of kernel virtual address range + * @end: End of kernel virtual address range + * + * Called from x86 mm code before freeing kernel page table pages. + * Iterates all tracked SVA-bound mm_structs and calls + * mmu_notifier_arch_invalidate_secondary_tlbs() for each, triggering + * IOTLB flushes via the drivers' invalidate_range callbacks. + * + * Fast path: atomic_read() returns 0 when no SVA is active. + */ +void iommu_sva_invalidate_kva_range(unsigned long start, unsigned long end) +{ + struct sva_mm *smm; + + if (!atomic_read(&sva_mm_count)) + return; + + rcu_read_lock(); + list_for_each_entry_rcu(smm, &sva_mm_list, list) { + if (mmget_not_zero(smm->mm)) { + mmu_notifier_arch_invalidate_secondary_tlbs(smm->mm, start, end); + mmput_async(smm->mm); + } + } + rcu_read_unlock(); +} diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c index 994cc22ebe..71025c5ef5 100644 --- a/drivers/md/md-bitmap.c +++ b/drivers/md/md-bitmap.c @@ -2476,6 +2476,7 @@ static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks, memcpy(page_address(store.sb_page), page_address(bitmap->storage.sb_page), sizeof(bitmap_super_t)); + mutex_lock(&bitmap->mddev->bitmap_info.mutex); spin_lock_irq(&bitmap->counts.lock); md_bitmap_file_unmap(&bitmap->storage); bitmap->storage = store; @@ -2583,7 +2584,7 @@ static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks, set_page_attr(bitmap, i, BITMAP_PAGE_DIRTY); } spin_unlock_irq(&bitmap->counts.lock); - + mutex_unlock(&bitmap->mddev->bitmap_info.mutex); if (!init) { __bitmap_unplug(bitmap); bitmap->mddev->pers->quiesce(bitmap->mddev, 0); diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c index 942cd47eb5..aeec5b9a1d 100644 --- a/drivers/md/persistent-data/dm-btree-remove.c +++ b/drivers/md/persistent-data/dm-btree-remove.c @@ -490,12 +490,20 @@ static int rebalance_children(struct shadow_spine *s, if (le32_to_cpu(n->header.nr_entries) == 1) { struct dm_block *child; + int is_shared; dm_block_t b = value64(n, 0); + r = dm_tm_block_is_shared(info->tm, b, &is_shared); + if (r) + return r; + r = dm_tm_read_lock(info->tm, b, &btree_node_validator, &child); if (r) return r; + if (is_shared) + inc_children(info->tm, dm_block_data(child), vt); + memcpy(n, dm_block_data(child), dm_bm_block_size(dm_tm_get_bm(info->tm))); diff --git a/drivers/net/ethernet/intel/ice/devlink/devlink.c b/drivers/net/ethernet/intel/ice/devlink/devlink.c index ac071c5b4c..cbd6de027e 100644 --- a/drivers/net/ethernet/intel/ice/devlink/devlink.c +++ b/drivers/net/ethernet/intel/ice/devlink/devlink.c @@ -1243,6 +1243,8 @@ static int ice_devlink_reinit_up(struct ice_pf *pf) return err; } + ice_init_dev_hw(pf); + /* load MSI-X values */ ice_set_min_max_msix(pf); diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c index 785bf5cc1b..94a1687212 100644 --- a/drivers/net/ethernet/intel/ice/ice_common.c +++ b/drivers/net/ethernet/intel/ice/ice_common.c @@ -1162,8 +1162,6 @@ int ice_init_hw(struct ice_hw *hw) if (status) goto err_unroll_fltr_mgmt_struct; - ice_init_dev_hw(hw->back); - mutex_init(&hw->tnl_lock); ice_init_chk_recipe_reuse_support(hw); diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index 0fff87dd31..900ace62d7 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -1154,6 +1154,32 @@ ice_dpll_input_state_get(const struct dpll_pin *pin, void *pin_priv, extack, ICE_DPLL_PIN_TYPE_INPUT); } +/** + * ice_dpll_sw_pin_notify_peer - notify the paired SW pin after a state change + * @d: pointer to dplls struct + * @changed: the SW pin that was explicitly changed (already notified by dpll core) + * + * SMA and U.FL pins share physical signal paths in pairs (SMA1/U.FL1 and + * SMA2/U.FL2). When one pin's routing changes via the PCA9575 GPIO + * expander, the paired pin's state may also change. Send a change + * notification for the peer pin so userspace consumers monitoring the + * peer via dpll netlink learn about the update. + * + * Context: Called from dpll_pin_ops callbacks after pf->dplls.lock is + * released. Uses __dpll_pin_change_ntf() because dpll_lock is + * still held by the dpll netlink layer. + */ +static void ice_dpll_sw_pin_notify_peer(struct ice_dplls *d, + struct ice_dpll_pin *changed) +{ + struct ice_dpll_pin *peer; + + peer = (changed >= d->sma && changed < d->sma + ICE_DPLL_PIN_SW_NUM) ? + &d->ufl[changed->idx] : &d->sma[changed->idx]; + if (peer->pin) + __dpll_pin_change_ntf(peer->pin); +} + /** * ice_dpll_sma_direction_set - set direction of SMA pin * @p: pointer to a pin @@ -1171,6 +1197,8 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, enum dpll_pin_direction direction, struct netlink_ext_ack *extack) { + struct ice_dplls *d = &p->pf->dplls; + struct ice_dpll_pin *peer; u8 data; int ret; @@ -1189,8 +1217,9 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, case ICE_DPLL_PIN_SW_2_IDX: if (direction == DPLL_PIN_DIRECTION_INPUT) { data &= ~ICE_SMA2_DIR_EN; + data |= ICE_SMA2_UFL2_RX_DIS; } else { - data &= ~ICE_SMA2_TX_EN; + data &= ~(ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS); data |= ICE_SMA2_DIR_EN; } break; @@ -1202,6 +1231,34 @@ static int ice_dpll_sma_direction_set(struct ice_dpll_pin *p, ret = ice_dpll_pin_state_update(p->pf, p, ICE_DPLL_PIN_TYPE_SOFTWARE, extack); + if (ret) + return ret; + + /* When a direction change activates the paired U.FL pin, enable + * its backing CGU pin so the pin reports as connected. Without + * this the U.FL routing is correct but the CGU pin stays disabled + * and userspace sees the pin as disconnected. Do not disable the + * backing pin when U.FL becomes inactive because the SMA pin may + * still be using it. + */ + peer = &d->ufl[p->idx]; + if (peer->active) { + struct ice_dpll_pin *target; + enum ice_dpll_pin_type type; + + if (peer->output) { + target = peer->output; + type = ICE_DPLL_PIN_TYPE_OUTPUT; + } else { + target = peer->input; + type = ICE_DPLL_PIN_TYPE_INPUT; + } + ret = ice_dpll_pin_enable(&p->pf->hw, target, + d->eec.dpll_idx, type, extack); + if (!ret) + ret = ice_dpll_pin_state_update(p->pf, target, + type, extack); + } return ret; } @@ -1253,6 +1310,14 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, data &= ~ICE_SMA1_MASK; enable = true; } else if (state == DPLL_PIN_STATE_DISCONNECTED) { + /* Skip if U.FL1 is not active, setting TX_EN + * while DIR_EN is set would also deactivate + * the paired SMA1 output. + */ + if (data & (ICE_SMA1_DIR_EN | ICE_SMA1_TX_EN)) { + ret = 0; + goto unlock; + } data |= ICE_SMA1_TX_EN; enable = false; } else { @@ -1267,6 +1332,15 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, data &= ~ICE_SMA2_UFL2_RX_DIS; enable = true; } else if (state == DPLL_PIN_STATE_DISCONNECTED) { + /* Skip if U.FL2 is not active, setting + * UFL2_RX_DIS could also disable the paired + * SMA2 input. + */ + if (!(data & ICE_SMA2_DIR_EN) || + (data & ICE_SMA2_UFL2_RX_DIS)) { + ret = 0; + goto unlock; + } data |= ICE_SMA2_UFL2_RX_DIS; enable = false; } else { @@ -1296,6 +1370,8 @@ ice_dpll_ufl_pin_state_set(const struct dpll_pin *pin, void *pin_priv, unlock: mutex_unlock(&pf->dplls.lock); + if (!ret) + ice_dpll_sw_pin_notify_peer(&pf->dplls, p); return ret; } @@ -1414,6 +1490,8 @@ ice_dpll_sma_pin_state_set(const struct dpll_pin *pin, void *pin_priv, unlock: mutex_unlock(&pf->dplls.lock); + if (!ret) + ice_dpll_sw_pin_notify_peer(&pf->dplls, sma); return ret; } @@ -1609,6 +1687,8 @@ ice_dpll_pin_sma_direction_set(const struct dpll_pin *pin, void *pin_priv, mutex_lock(&pf->dplls.lock); ret = ice_dpll_sma_direction_set(p, direction, extack); mutex_unlock(&pf->dplls.lock); + if (!ret) + ice_dpll_sw_pin_notify_peer(&pf->dplls, p); return ret; } @@ -1915,7 +1995,10 @@ ice_dpll_phase_offset_get(const struct dpll_pin *pin, void *pin_priv, d->active_input == p->input->pin)) *phase_offset = d->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; else if (d->phase_offset_monitor_period) - *phase_offset = p->phase_offset * ICE_DPLL_PHASE_OFFSET_FACTOR; + *phase_offset = (p->input && + p->direction == DPLL_PIN_DIRECTION_INPUT ? + p->input->phase_offset : + p->phase_offset) * ICE_DPLL_PHASE_OFFSET_FACTOR; else *phase_offset = 0; mutex_unlock(&pf->dplls.lock); @@ -2614,6 +2697,27 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) return pci_get_dsn(pf->pdev); } +/** + * ice_dpll_pin_ntf - notify pin change including any SW pin wrappers + * @dplls: pointer to dplls struct + * @pin: the dpll_pin that changed + * + * Send a change notification for @pin and for any registered SMA/U.FL pin + * whose backing CGU input matches @pin. + */ +static void ice_dpll_pin_ntf(struct ice_dplls *dplls, struct dpll_pin *pin) +{ + dpll_pin_change_ntf(pin); + for (int i = 0; i < ICE_DPLL_PIN_SW_NUM; i++) { + if (dplls->sma[i].pin && dplls->sma[i].input && + dplls->sma[i].input->pin == pin) + dpll_pin_change_ntf(dplls->sma[i].pin); + if (dplls->ufl[i].pin && dplls->ufl[i].input && + dplls->ufl[i].input->pin == pin) + dpll_pin_change_ntf(dplls->ufl[i].pin); + } +} + /** * ice_dpll_notify_changes - notify dpll subsystem about changes * @d: pointer do dpll @@ -2622,6 +2726,7 @@ static u64 ice_generate_clock_id(struct ice_pf *pf) */ static void ice_dpll_notify_changes(struct ice_dpll *d) { + struct ice_dplls *dplls = &d->pf->dplls; bool pin_notified = false; if (d->prev_dpll_state != d->dpll_state) { @@ -2630,17 +2735,17 @@ static void ice_dpll_notify_changes(struct ice_dpll *d) } if (d->prev_input != d->active_input) { if (d->prev_input) - dpll_pin_change_ntf(d->prev_input); + ice_dpll_pin_ntf(dplls, d->prev_input); d->prev_input = d->active_input; if (d->active_input) { - dpll_pin_change_ntf(d->active_input); + ice_dpll_pin_ntf(dplls, d->active_input); pin_notified = true; } } if (d->prev_phase_offset != d->phase_offset) { d->prev_phase_offset = d->phase_offset; if (!pin_notified && d->active_input) - dpll_pin_change_ntf(d->active_input); + ice_dpll_pin_ntf(dplls, d->active_input); } } @@ -2669,6 +2774,7 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf) /** * ice_dpll_pins_notify_mask - notify dpll subsystem about bulk pin changes + * @dplls: pointer to dplls struct * @pins: array of ice_dpll_pin pointers registered within dpll subsystem * @pin_num: number of pins * @phase_offset_ntf_mask: bitmask of pin indexes to notify @@ -2678,15 +2784,14 @@ static bool ice_dpll_is_pps_phase_monitor(struct ice_pf *pf) * * Context: Must be called while pf->dplls.lock is released. */ -static void ice_dpll_pins_notify_mask(struct ice_dpll_pin *pins, +static void ice_dpll_pins_notify_mask(struct ice_dplls *dplls, + struct ice_dpll_pin *pins, u8 pin_num, u32 phase_offset_ntf_mask) { - int i = 0; - - for (i = 0; i < pin_num; i++) - if (phase_offset_ntf_mask & (1 << i)) - dpll_pin_change_ntf(pins[i].pin); + for (int i = 0; i < pin_num; i++) + if (phase_offset_ntf_mask & BIT(i)) + ice_dpll_pin_ntf(dplls, pins[i].pin); } /** @@ -2862,7 +2967,7 @@ static void ice_dpll_periodic_work(struct kthread_work *work) ice_dpll_notify_changes(de); ice_dpll_notify_changes(dp); if (phase_offset_ntf) - ice_dpll_pins_notify_mask(d->inputs, d->num_inputs, + ice_dpll_pins_notify_mask(d, d->inputs, d->num_inputs, phase_offset_ntf); resched: @@ -4019,6 +4124,7 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) struct ice_dpll_pin *pin; u32 phase_adj_max, caps; int i, ret; + u8 data; if (pf->hw.device_id == ICE_DEV_ID_E810C_QSFP) input_idx_offset = ICE_E810_RCLK_PINS_NUM; @@ -4078,6 +4184,22 @@ static int ice_dpll_init_info_sw_pins(struct ice_pf *pf) } ice_dpll_phase_range_set(&pin->prop.phase_range, phase_adj_max); } + + /* Initialize the SMA control register to a known-good default state. + * Without this write the PCA9575 GPIO expander retains its power-on + * default (all outputs high) which makes all SW pins appear inactive. + * Set SMA1 and SMA2 as active inputs, disable U.FL1 output and + * U.FL2 input. + */ + ret = ice_read_sma_ctrl(&pf->hw, &data); + if (ret) + return ret; + data &= ~ICE_ALL_SMA_MASK; + data |= ICE_SMA1_TX_EN | ICE_SMA2_TX_EN | ICE_SMA2_UFL2_RX_DIS; + ret = ice_write_sma_ctrl(&pf->hw, data); + if (ret) + return ret; + ret = ice_dpll_pin_state_update(pf, pin, ICE_DPLL_PIN_TYPE_SOFTWARE, NULL); if (ret) diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index b6dbdc3439..6b1e6eeeda 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -5339,6 +5339,8 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) return err; } + ice_init_dev_hw(pf); + adapter = ice_adapter_get(pdev); if (IS_ERR(adapter)) { err = PTR_ERR(adapter); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 3abed53c51..78c1d1ecab 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -1296,12 +1296,10 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup) if (pf->hw.reset_ongoing) return; - if (hw->mac_type == ICE_MAC_GENERIC_3K_E825) { + if (hw->mac_type == ICE_MAC_GENERIC_3K_E825 && + test_bit(ICE_FLAG_DPLL, pf->flags)) { int pin, err; - if (!test_bit(ICE_FLAG_DPLL, pf->flags)) - return; - mutex_lock(&pf->dplls.lock); for (pin = 0; pin < ICE_SYNCE_CLK_NUM; pin++) { enum ice_synce_clk clk_pin; @@ -1314,15 +1312,19 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup) port_num, &active, clk_pin); - if (WARN_ON_ONCE(err)) { - mutex_unlock(&pf->dplls.lock); - return; + if (err) { + dev_err_once(ice_pf_to_dev(pf), + "Failed to read SyncE bypass mux for pin %d, err %d\n", + pin, err); + break; } err = ice_tspll_cfg_synce_ethdiv_e825c(hw, clk_pin); - if (active && WARN_ON_ONCE(err)) { - mutex_unlock(&pf->dplls.lock); - return; + if (active && err) { + dev_err_once(ice_pf_to_dev(pf), + "Failed to configure SyncE ETH divider for pin %d, err %d\n", + pin, err); + break; } } mutex_unlock(&pf->dplls.lock); @@ -1334,9 +1336,12 @@ void ice_ptp_link_change(struct ice_pf *pf, bool linkup) /* Do not reconfigure E810 or E830 PHY */ return; case ICE_MAC_GENERIC: - case ICE_MAC_GENERIC_3K_E825: ice_ptp_port_phy_restart(ptp_port); return; + case ICE_MAC_GENERIC_3K_E825: + if (linkup) + ice_ptp_port_phy_restart(ptp_port); + return; default: dev_warn(ice_pf_to_dev(pf), "%s: Unknown PHY type\n", __func__); } @@ -2705,7 +2710,7 @@ static bool ice_any_port_has_timestamps(struct ice_pf *pf) bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf) { struct ice_hw *hw = &pf->hw; - unsigned int i; + int ret; /* Check software indicator */ switch (pf->ptp.tx_interrupt_mode) { @@ -2726,16 +2731,19 @@ bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf) } /* Check hardware indicator */ - for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) { - u64 tstamp_ready = 0; - int err; - - err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); - if (err || tstamp_ready) - return true; + ret = ice_check_phy_tx_tstamp_ready(hw); + if (ret < 0) { + dev_dbg(ice_pf_to_dev(pf), "Unable to read PHY Tx timestamp ready bitmap, err %d\n", + ret); + /* Stop triggering IRQs if we're unable to read PHY */ + return false; } - return false; + /* ice_check_phy_tx_tstamp_ready() returns 1 if there are timestamps + * available, 0 if there are no waiting timestamps, and a negative + * value if there was an error (which we checked for above). + */ + return ret > 0; } /** @@ -2819,8 +2827,7 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf) { struct device *dev = ice_pf_to_dev(pf); struct ice_hw *hw = &pf->hw; - bool trigger_oicr = false; - unsigned int i; + int ret; if (!pf->ptp.port.tx.has_ready_bitmap) return; @@ -2828,21 +2835,11 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf) if (!ice_pf_src_tmr_owned(pf)) return; - for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) { - u64 tstamp_ready; - int err; - - err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); - if (!err && tstamp_ready) { - trigger_oicr = true; - break; - } - } - - if (trigger_oicr) { - /* Trigger a software interrupt, to ensure this data - * gets processed. - */ + ret = ice_check_phy_tx_tstamp_ready(hw); + if (ret < 0) { + dev_dbg(dev, "PTP periodic task unable to read PHY timestamp ready bitmap, err %d\n", + ret); + } else if (ret) { dev_dbg(dev, "PTP periodic task detected waiting timestamps. Triggering Tx timestamp interrupt now.\n"); wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c index 61c0a0d93e..d362b2bb5f 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.c @@ -377,6 +377,31 @@ static void ice_ptp_cfg_sync_delay(const struct ice_hw *hw, u32 delay) * The following functions operate on devices with the ETH 56G PHY. */ +/** + * ice_ptp_init_phc_e825c - Perform E825C specific PHC initialization + * @hw: pointer to HW struct + * + * Perform E825C-specific PTP hardware clock initialization steps. + * + * Return: 0 on success, or a negative error value on failure. + */ +static int ice_ptp_init_phc_e825c(struct ice_hw *hw) +{ + int err; + + /* Soft reset all ports, to ensure everything is at a clean state */ + for (int port = 0; port < hw->ptp.num_lports; port++) { + err = ice_ptp_phy_soft_reset_eth56g(hw, port); + if (err) { + ice_debug(hw, ICE_DBG_PTP, "Failed to soft reset port %d, err %d\n", + port, err); + return err; + } + } + + return 0; +} + /** * ice_ptp_get_dest_dev_e825 - get destination PHY for given port number * @hw: pointer to the HW struct @@ -1847,6 +1872,8 @@ static int ice_phy_cfg_mac_eth56g(struct ice_hw *hw, u8 port) * @ena: enable or disable interrupt * @threshold: interrupt threshold * + * The threshold cannot be 0 while the interrupt is enabled. + * * Configure TX timestamp interrupt for the specified port * * Return: @@ -1858,19 +1885,45 @@ int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold) int err; u32 val; + if (ena && !threshold) + return -EINVAL; + err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); if (err) return err; + val &= ~PHY_TS_INT_CONFIG_ENA_M; if (ena) { - val |= PHY_TS_INT_CONFIG_ENA_M; val &= ~PHY_TS_INT_CONFIG_THRESHOLD_M; val |= FIELD_PREP(PHY_TS_INT_CONFIG_THRESHOLD_M, threshold); - } else { - val &= ~PHY_TS_INT_CONFIG_ENA_M; + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, + val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, + "Failed to update 'threshold' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", + port, !!ena, threshold); + return err; + } + val |= PHY_TS_INT_CONFIG_ENA_M; } - return ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, + "Failed to update 'ena' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", + port, !!ena, threshold); + return err; + } + + err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, + "Failed to read PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", + port, !!ena, threshold); + return err; + } + + return 0; } /** @@ -2115,6 +2168,35 @@ int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port) return 0; } +/** + * ice_check_phy_tx_tstamp_ready_eth56g - Check Tx memory status for all ports + * @hw: pointer to the HW struct + * + * Check the PHY_REG_TX_MEMORY_STATUS for all ports. A set bit indicates + * a waiting timestamp. + * + * Return: 1 if any port has at least one timestamp ready bit set, + * 0 otherwise, and a negative error code if unable to read the bitmap. + */ +static int ice_check_phy_tx_tstamp_ready_eth56g(struct ice_hw *hw) +{ + int port; + + for (port = 0; port < hw->ptp.num_lports; port++) { + u64 tstamp_ready; + int err; + + err = ice_get_phy_tx_tstamp_ready(hw, port, &tstamp_ready); + if (err) + return err; + + if (tstamp_ready) + return 1; + } + + return 0; +} + /** * ice_ptp_read_tx_hwtstamp_status_eth56g - Get TX timestamp status * @hw: pointer to the HW struct @@ -2137,13 +2219,19 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) *ts_status = 0; for (phy = 0; phy < params->num_phys; phy++) { + u8 port; int err; - err = ice_read_phy_eth56g(hw, phy, PHY_PTP_INT_STATUS, &status); + /* ice_read_phy_eth56g expects a port index, so use the first + * port of the PHY + */ + port = phy * hw->ptp.ports_per_phy; + + err = ice_read_phy_eth56g(hw, port, PHY_PTP_INT_STATUS, &status); if (err) return err; - *ts_status |= (status & mask) << (phy * hw->ptp.ports_per_phy); + *ts_status |= (status & mask) << port; } ice_debug(hw, ICE_DBG_PTP, "PHY interrupt err: %x\n", *ts_status); @@ -2151,6 +2239,69 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) return 0; } +/** + * ice_ptp_phy_soft_reset_eth56g - Perform a PHY soft reset on ETH56G + * @hw: pointer to the HW structure + * @port: PHY port number + * + * Trigger a soft reset of the ETH56G PHY by toggling the soft reset + * bit in the PHY global register. The reset sequence consists of: + * 1. Clearing the soft reset bit + * 2. Asserting the soft reset bit + * 3. Clearing the soft reset bit again + * + * Short delays are inserted between each step to allow the hardware + * to settle. This provides a controlled way to reinitialize the PHY + * without requiring a full device reset. + * + * Return: 0 on success, or a negative error code on failure when + * reading or writing the PHY register. + */ +int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port) +{ + u32 global_val; + int err; + + err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, &global_val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, "Failed to read PHY_REG_GLOBAL for port %d, err %d\n", + port, err); + return err; + } + + global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M; + ice_debug(hw, ICE_DBG_PTP, "Clearing soft reset bit for port %d, val: 0x%x\n", + port, global_val); + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", + port, err); + return err; + } + + usleep_range(5000, 6000); + + global_val |= PHY_REG_GLOBAL_SOFT_RESET_M; + ice_debug(hw, ICE_DBG_PTP, "Set soft reset bit for port %d, val: 0x%x\n", + port, global_val); + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); + if (err) { + ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", + port, err); + return err; + } + usleep_range(5000, 6000); + + global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M; + ice_debug(hw, ICE_DBG_PTP, "Clear soft reset bit for port %d, val: 0x%x\n", + port, global_val); + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); + if (err) + ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", + port, err); + return err; +} + /** * ice_get_phy_tx_tstamp_ready_eth56g - Read the Tx memory status register * @hw: pointer to the HW struct @@ -4202,6 +4353,35 @@ ice_get_phy_tx_tstamp_ready_e82x(struct ice_hw *hw, u8 quad, u64 *tstamp_ready) return 0; } +/** + * ice_check_phy_tx_tstamp_ready_e82x - Check Tx memory status for all quads + * @hw: pointer to the HW struct + * + * Check the Q_REG_TX_MEMORY_STATUS for all quads. A set bit indicates + * a waiting timestamp. + * + * Return: 1 if any quad has at least one timestamp ready bit set, + * 0 otherwise, and a negative error value if unable to read the bitmap. + */ +static int ice_check_phy_tx_tstamp_ready_e82x(struct ice_hw *hw) +{ + int quad; + + for (quad = 0; quad < ICE_GET_QUAD_NUM(hw->ptp.num_lports); quad++) { + u64 tstamp_ready; + int err; + + err = ice_get_phy_tx_tstamp_ready(hw, quad, &tstamp_ready); + if (err) + return err; + + if (tstamp_ready) + return 1; + } + + return 0; +} + /** * ice_phy_cfg_intr_e82x - Configure TX timestamp interrupt * @hw: pointer to the HW struct @@ -4755,6 +4935,23 @@ ice_get_phy_tx_tstamp_ready_e810(struct ice_hw *hw, u8 port, u64 *tstamp_ready) return 0; } +/** + * ice_check_phy_tx_tstamp_ready_e810 - Check Tx memory status register + * @hw: pointer to the HW struct + * + * The E810 devices do not have a Tx memory status register. Note this is + * intentionally different behavior from ice_get_phy_tx_tstamp_ready_e810 + * which always says that all bits are ready. This function is called in cases + * where code will trigger interrupts if timestamps are waiting, and should + * not be called for E810 hardware. + * + * Return: 0. + */ +static int ice_check_phy_tx_tstamp_ready_e810(struct ice_hw *hw) +{ + return 0; +} + /* E810 SMA functions * * The following functions operate specifically on E810 hardware and are used @@ -5009,6 +5206,21 @@ static void ice_get_phy_tx_tstamp_ready_e830(const struct ice_hw *hw, u8 port, *tstamp_ready |= rd32(hw, E830_PRTMAC_TS_TX_MEM_VALID_L); } +/** + * ice_check_phy_tx_tstamp_ready_e830 - Check Tx memory status register + * @hw: pointer to the HW struct + * + * Return: 1 if the device has waiting timestamps, 0 otherwise. + */ +static int ice_check_phy_tx_tstamp_ready_e830(struct ice_hw *hw) +{ + u64 tstamp_ready; + + ice_get_phy_tx_tstamp_ready_e830(hw, 0, &tstamp_ready); + + return !!tstamp_ready; +} + /** * ice_ptp_init_phy_e830 - initialize PHY parameters * @ptp: pointer to the PTP HW struct @@ -5564,7 +5776,7 @@ int ice_ptp_init_phc(struct ice_hw *hw) case ICE_MAC_GENERIC: return ice_ptp_init_phc_e82x(hw); case ICE_MAC_GENERIC_3K_E825: - return 0; + return ice_ptp_init_phc_e825c(hw); default: return -EOPNOTSUPP; } @@ -5601,6 +5813,33 @@ int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready) } } +/** + * ice_check_phy_tx_tstamp_ready - Check PHY Tx timestamp memory status + * @hw: pointer to the HW struct + * + * Check the PHY for Tx timestamp memory status on all ports. If you need to + * see individual timestamp status for each index, use + * ice_get_phy_tx_tstamp_ready() instead. + * + * Return: 1 if any port has timestamps available, 0 if there are no timestamps + * available, and a negative error code on failure. + */ +int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw) +{ + switch (hw->mac_type) { + case ICE_MAC_E810: + return ice_check_phy_tx_tstamp_ready_e810(hw); + case ICE_MAC_E830: + return ice_check_phy_tx_tstamp_ready_e830(hw); + case ICE_MAC_GENERIC: + return ice_check_phy_tx_tstamp_ready_e82x(hw); + case ICE_MAC_GENERIC_3K_E825: + return ice_check_phy_tx_tstamp_ready_eth56g(hw); + default: + return -EOPNOTSUPP; + } +} + /** * ice_cgu_get_pin_desc_e823 - get pin description array * @hw: pointer to the hw struct diff --git a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h index 5896b346e5..1b58b054f4 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp_hw.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp_hw.h @@ -300,6 +300,7 @@ void ice_ptp_reset_ts_memory(struct ice_hw *hw); int ice_ptp_init_phc(struct ice_hw *hw); void ice_ptp_init_hw(struct ice_hw *hw); int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready); +int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw); int ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port, enum ice_ptp_tmr_cmd configured_cmd); @@ -374,6 +375,7 @@ int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset); int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port); int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold); int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port); +int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port); #define ICE_ETH56G_NOMINAL_INCVAL 0x140000000ULL #define ICE_ETH56G_NOMINAL_PCS_REF_TUS 0x100000000ULL @@ -676,6 +678,9 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw) #define ICE_P0_GNSS_PRSNT_N BIT(4) /* ETH56G PHY register addresses */ +#define PHY_REG_GLOBAL 0x0 +#define PHY_REG_GLOBAL_SOFT_RESET_M BIT(11) + /* Timestamp PHY incval registers */ #define PHY_REG_TIMETUS_L 0x8 #define PHY_REG_TIMETUS_U 0xC diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 499269f03c..2712ad743d 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -1081,6 +1081,7 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size, if (!size) { rx_buf->pagecnt_bias--; + rx_buf->has_data = false; return rx_buf; } /* we are reusing so sync this buffer for CPU use */ @@ -1090,6 +1091,7 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size, /* We have pulled a buffer for use, so decrement pagecnt_bias */ rx_buf->pagecnt_bias--; + rx_buf->has_data = true; return rx_buf; } @@ -1302,25 +1304,15 @@ static void ice_put_rx_mbuf(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, u32 idx = rx_ring->first_desc; u32 cnt = rx_ring->count; struct ice_rx_buf *buf; - u32 xdp_frags = 0; - int i = 0; - - if (unlikely(xdp_buff_has_frags(xdp))) - xdp_frags = xdp_get_shared_info_from_buff(xdp)->nr_frags; while (idx != ntc) { buf = &rx_ring->rx_buf[idx]; if (++idx == cnt) idx = 0; - /* An XDP program could release fragments from the end of the - * buffer. For these, we need to keep the pagecnt_bias as-is. - * To do this, only adjust pagecnt_bias for fragments up to - * the total remaining after the XDP program has run. - */ - if (verdict != ICE_XDP_CONSUMED) + if (verdict != ICE_XDP_CONSUMED && buf->has_data) ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz); - else if (i++ <= xdp_frags) + else buf->pagecnt_bias++; ice_put_rx_buf(rx_ring, buf); diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index 841a07bfba..70f40a5ec3 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -203,6 +203,7 @@ struct ice_rx_buf { unsigned int page_offset; unsigned int pgcnt; unsigned int pagecnt_bias; + bool has_data; }; struct ice_q_stats { diff --git a/drivers/net/ethernet/intel/ice/ice_vf_lib.c b/drivers/net/ethernet/intel/ice/ice_vf_lib.c index de9e81ccee..e53a1e4247 100644 --- a/drivers/net/ethernet/intel/ice/ice_vf_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_vf_lib.c @@ -804,7 +804,12 @@ void ice_reset_all_vfs(struct ice_pf *pf) ice_vf_ctrl_invalidate_vsi(vf); ice_vf_pre_vsi_rebuild(vf); - ice_vf_rebuild_vsi(vf); + if (ice_vf_rebuild_vsi(vf)) { + dev_err(dev, "VF %u VSI rebuild failed, leaving VF disabled\n", + vf->vf_id); + mutex_unlock(&vf->cfg_lock); + continue; + } ice_vf_post_vsi_rebuild(vf); ice_eswitch_attach_vf(pf, vf); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 93e2d253ac..23f411e3cc 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1719,13 +1719,18 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa) if (ether_addr_equal(netdev->dev_addr, mac)) return 0; - err = ionic_program_mac(lif, mac); - if (err < 0) - return err; + /* Only program macs for virtual functions to avoid losing the permanent + * Mac across warm reset/reboot. + */ + if (lif->ionic->pdev->is_virtfn) { + err = ionic_program_mac(lif, mac); + if (err < 0) + return err; - if (err > 0) - netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n", - __func__); + if (err > 0) + netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n", + __func__); + } err = eth_prepare_mac_addr_change(netdev, addr); if (err) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 229e29498e..6cfef8b22c 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -1756,6 +1756,9 @@ static int netvsc_set_rxfh(struct net_device *dev, rxfh->hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; + if (!ndc->rx_table_sz) + return -EOPNOTSUPP; + rndis_dev = ndev->extension; if (rxfh->indir) { for (i = 0; i < ndc->rx_table_sz; i++) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c index c2d98ee665..1d25dc9ebc 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c @@ -153,6 +153,11 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, bphy_err(drvr, "invalid interface index: %u\n", ifevent->ifidx); return; } + if (ifevent->bsscfgidx >= BRCMF_MAX_IFS) { + bphy_err(drvr, "invalid bsscfg index: %u\n", + ifevent->bsscfgidx); + return; + } ifp = drvr->iflist[ifevent->bsscfgidx]; diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index ef83b8e0e9..bf8ec461c0 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -312,6 +312,7 @@ struct lpfc_defer_flogi_acc { u16 rx_id; u16 ox_id; struct lpfc_nodelist *ndlp; + }; #define LPFC_VMID_TIMER 300 /* timer interval in seconds */ @@ -634,7 +635,6 @@ struct lpfc_vport { #define FC_CT_RSPN_ID 0x8 /* RSPN_ID accepted by switch */ #define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */ #define FC_CT_RPRT_DEFER 0x20 /* Defer issuing FDMI RPRT */ -#define FC_CT_RSPNI_PNI 0x40 /* RSPNI_PNI accepted by switch */ struct list_head fc_nodes; spinlock_t fc_nodes_list_lock; /* spinlock for fc_nodes list */ @@ -662,12 +662,15 @@ struct lpfc_vport { uint32_t num_disc_nodes; /* in addition to hba_state */ uint32_t gidft_inp; /* cnt of outstanding GID_FTs */ + uint32_t fc_nlp_cnt; /* outstanding NODELIST requests */ uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */ uint32_t fc_rscn_flush; /* flag use of fc_rscn_id_list */ struct lpfc_dmabuf *fc_rscn_id_list[FC_MAX_HOLD_RSCN]; struct lpfc_name fc_nodename; /* fc nodename */ struct lpfc_name fc_portname; /* fc portname */ + struct lpfc_work_evt disc_timeout_evt; + struct timer_list fc_disctmo; /* Discovery rescue timer */ uint8_t fc_ns_retry; /* retries for fabric nameserver */ uint32_t fc_prli_sent; /* cntr for outstanding PRLIs */ @@ -742,6 +745,12 @@ struct lpfc_vport { struct lpfc_vmid_priority_info vmid_priority; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS + struct dentry *debug_disc_trc; + struct dentry *debug_nodelist; + struct dentry *debug_nvmestat; + struct dentry *debug_scsistat; + struct dentry *debug_ioktime; + struct dentry *debug_hdwqstat; struct dentry *vport_debugfs_root; struct lpfc_debugfs_trc *disc_trc; atomic_t disc_trc_cnt; @@ -759,6 +768,7 @@ struct lpfc_vport { /* There is a single nvme instance per vport. */ struct nvme_fc_local_port *localport; uint8_t nvmei_support; /* driver supports NVME Initiator */ + uint32_t last_fcp_wqidx; uint32_t rcv_flogi_cnt; /* How many unsol FLOGIs ACK'd. */ }; @@ -1051,6 +1061,8 @@ struct lpfc_hba { struct lpfc_dmabuf hbqslimp; + uint16_t pci_cfg_value; + uint8_t fc_linkspeed; /* Link speed after last READ_LA */ uint32_t fc_eventTag; /* event tag for link attention */ @@ -1077,10 +1089,9 @@ struct lpfc_hba { struct lpfc_stats fc_stat; + struct lpfc_nodelist fc_fcpnodev; /* nodelist entry for no device */ uint32_t nport_event_cnt; /* timestamp for nlplist entry */ - unsigned long pni; /* 64-bit Platform Name Identifier */ - uint8_t wwnn[8]; uint8_t wwpn[8]; uint32_t RandomData[7]; @@ -1219,6 +1230,9 @@ struct lpfc_hba { uint32_t hbq_count; /* Count of configured HBQs */ struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */ + atomic_t fcp_qidx; /* next FCP WQ (RR Policy) */ + atomic_t nvme_qidx; /* next NVME WQ (RR Policy) */ + phys_addr_t pci_bar0_map; /* Physical address for PCI BAR0 */ phys_addr_t pci_bar1_map; /* Physical address for PCI BAR1 */ phys_addr_t pci_bar2_map; /* Physical address for PCI BAR2 */ @@ -1335,9 +1349,30 @@ struct lpfc_hba { unsigned long last_ramp_down_time; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS struct dentry *hba_debugfs_root; - unsigned int debugfs_vport_count; + atomic_t debugfs_vport_count; + struct dentry *debug_multixri_pools; + struct dentry *debug_hbqinfo; + struct dentry *debug_dumpHostSlim; + struct dentry *debug_dumpHBASlim; + struct dentry *debug_InjErrLBA; /* LBA to inject errors at */ + struct dentry *debug_InjErrNPortID; /* NPortID to inject errors at */ + struct dentry *debug_InjErrWWPN; /* WWPN to inject errors at */ + struct dentry *debug_writeGuard; /* inject write guard_tag errors */ + struct dentry *debug_writeApp; /* inject write app_tag errors */ + struct dentry *debug_writeRef; /* inject write ref_tag errors */ + struct dentry *debug_readGuard; /* inject read guard_tag errors */ + struct dentry *debug_readApp; /* inject read app_tag errors */ + struct dentry *debug_readRef; /* inject read ref_tag errors */ + struct dentry *debug_nvmeio_trc; struct lpfc_debugfs_nvmeio_trc *nvmeio_trc; + struct dentry *debug_hdwqinfo; +#ifdef LPFC_HDWQ_LOCK_STAT + struct dentry *debug_lockstat; +#endif + struct dentry *debug_cgn_buffer; + struct dentry *debug_rx_monitor; + struct dentry *debug_ras_log; atomic_t nvmeio_trc_cnt; uint32_t nvmeio_trc_size; uint32_t nvmeio_trc_output_idx; @@ -1354,10 +1389,19 @@ struct lpfc_hba { sector_t lpfc_injerr_lba; #define LPFC_INJERR_LBA_OFF (sector_t)(-1) + struct dentry *debug_slow_ring_trc; struct lpfc_debugfs_trc *slow_ring_trc; atomic_t slow_ring_trc_cnt; /* iDiag debugfs sub-directory */ struct dentry *idiag_root; + struct dentry *idiag_pci_cfg; + struct dentry *idiag_bar_acc; + struct dentry *idiag_que_info; + struct dentry *idiag_que_acc; + struct dentry *idiag_drb_acc; + struct dentry *idiag_ctl_acc; + struct dentry *idiag_mbx_acc; + struct dentry *idiag_ext_acc; uint8_t lpfc_idiag_last_eq; #endif uint16_t nvmeio_trc_on; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 9aaf5cf930..3f59120c54 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -264,9 +264,9 @@ ct_free_mpvirt: ct_free_mp: kfree(mp); ct_exit: - lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS, - "6440 Unsol CT: Rsp err %d Data: x%lx\n", - rc, vport->fc_flag); + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "6440 Unsol CT: Rsp err %d Data: x%lx\n", + rc, vport->fc_flag); } /** @@ -313,7 +313,7 @@ lpfc_ct_handle_mibreq(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocbq) mi_cmd = be16_to_cpu(ct_req->CommandResponse.bits.CmdRsp); lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS, - "6442 MI Cmd: x%x Not Supported\n", mi_cmd); + "6442 MI Cmd : x%x Not Supported\n", mi_cmd); lpfc_ct_reject_event(ndlp, ct_req, bf_get(wqe_ctxt_tag, &ctiocbq->wqe.xmit_els_rsp.wqe_com), @@ -1742,28 +1742,6 @@ lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, return; } -static void -lpfc_cmpl_ct_cmd_rspni_pni(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport; - struct lpfc_dmabuf *outp; - struct lpfc_sli_ct_request *ctrsp; - u32 ulp_status; - - vport = cmdiocb->vport; - ulp_status = get_job_ulpstatus(phba, rspiocb); - - if (ulp_status == IOSTAT_SUCCESS) { - outp = cmdiocb->rsp_dmabuf; - ctrsp = (struct lpfc_sli_ct_request *)outp->virt; - if (be16_to_cpu(ctrsp->CommandResponse.bits.CmdRsp) == - SLI_CT_RESPONSE_FS_ACC) - vport->ct_flags |= FC_CT_RSPNI_PNI; - } - lpfc_cmpl_ct(phba, cmdiocb, rspiocb); -} - static void lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb) @@ -1978,8 +1956,6 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, bpl->tus.f.bdeSize = RSPN_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RSNN_NN) bpl->tus.f.bdeSize = RSNN_REQUEST_SZ; - else if (cmdcode == SLI_CTNS_RSPNI_PNI) - bpl->tus.f.bdeSize = RSPNI_REQUEST_SZ; else if (cmdcode == SLI_CTNS_DA_ID) bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ; else if (cmdcode == SLI_CTNS_RFF_ID) @@ -2101,18 +2077,6 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, CtReq->un.rsnn.symbname, size); cmpl = lpfc_cmpl_ct_cmd_rsnn_nn; break; - case SLI_CTNS_RSPNI_PNI: - vport->ct_flags &= ~FC_CT_RSPNI_PNI; - CtReq->CommandResponse.bits.CmdRsp = - cpu_to_be16(SLI_CTNS_RSPNI_PNI); - CtReq->un.rspni.pni = cpu_to_be64(phba->pni); - scnprintf(CtReq->un.rspni.symbname, - sizeof(CtReq->un.rspni.symbname), "OS Host Name::%s", - phba->os_host_name); - CtReq->un.rspni.len = strnlen(CtReq->un.rspni.symbname, - sizeof(CtReq->un.rspni.symbname)); - cmpl = lpfc_cmpl_ct_cmd_rspni_pni; - break; case SLI_CTNS_DA_ID: /* Implement DA_ID Nameserver request */ CtReq->CommandResponse.bits.CmdRsp = @@ -2265,6 +2229,21 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* Look for a retryable error */ if (ulp_status == IOSTAT_LOCAL_REJECT) { switch ((ulp_word4 & IOERR_PARAM_MASK)) { + case IOERR_SLI_ABORTED: + case IOERR_SLI_DOWN: + /* Driver aborted this IO. No retry as error + * is likely Offline->Online or some adapter + * error. Recovery will try again, but if port + * is not active there's no point to continue + * issuing follow up FDMI commands. + */ + if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) { + free_ndlp = cmdiocb->ndlp; + lpfc_ct_free_iocb(phba, cmdiocb); + lpfc_nlp_put(free_ndlp); + return; + } + break; case IOERR_ABORT_IN_PROGRESS: case IOERR_SEQUENCE_TIMEOUT: case IOERR_ILLEGAL_FRAME: @@ -2290,9 +2269,6 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_ct_free_iocb(phba, cmdiocb); lpfc_nlp_put(free_ndlp); - if (ulp_status != IOSTAT_SUCCESS) - return; - ndlp = lpfc_findnode_did(vport, FDMI_DID); if (!ndlp) return; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index a4378c6642..e5a31bc0f6 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2007-2015 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -2373,117 +2373,93 @@ out: static ssize_t lpfc_debugfs_dif_err_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) + size_t nbytes, loff_t *ppos) { + struct dentry *dent = file->f_path.dentry; struct lpfc_hba *phba = file->private_data; - int kind = debugfs_get_aux_num(file); - char cbuf[32] = {0}; + char cbuf[32]; + uint64_t tmp = 0; int cnt = 0; - switch (kind) { - case writeGuard: - cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", - phba->lpfc_injerr_wgrd_cnt); - break; - case writeApp: - cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", - phba->lpfc_injerr_wapp_cnt); - break; - case writeRef: - cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", - phba->lpfc_injerr_wref_cnt); - break; - case readGuard: - cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", - phba->lpfc_injerr_rgrd_cnt); - break; - case readApp: - cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", - phba->lpfc_injerr_rapp_cnt); - break; - case readRef: - cnt = scnprintf(cbuf, sizeof(cbuf), "%u\n", - phba->lpfc_injerr_rref_cnt); - break; - case InjErrNPortID: - cnt = scnprintf(cbuf, sizeof(cbuf), "0x%06x\n", + if (dent == phba->debug_writeGuard) + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt); + else if (dent == phba->debug_writeApp) + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt); + else if (dent == phba->debug_writeRef) + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt); + else if (dent == phba->debug_readGuard) + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt); + else if (dent == phba->debug_readApp) + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt); + else if (dent == phba->debug_readRef) + cnt = scnprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt); + else if (dent == phba->debug_InjErrNPortID) + cnt = scnprintf(cbuf, 32, "0x%06x\n", phba->lpfc_injerr_nportid); - break; - case InjErrWWPN: - cnt = scnprintf(cbuf, sizeof(cbuf), "0x%016llx\n", - be64_to_cpu(phba->lpfc_injerr_wwpn.u.wwn_be)); - break; - case InjErrLBA: - if (phba->lpfc_injerr_lba == LPFC_INJERR_LBA_OFF) - cnt = scnprintf(cbuf, sizeof(cbuf), "off\n"); + else if (dent == phba->debug_InjErrWWPN) { + memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name)); + tmp = cpu_to_be64(tmp); + cnt = scnprintf(cbuf, 32, "0x%016llx\n", tmp); + } else if (dent == phba->debug_InjErrLBA) { + if (phba->lpfc_injerr_lba == (sector_t)(-1)) + cnt = scnprintf(cbuf, 32, "off\n"); else - cnt = scnprintf(cbuf, sizeof(cbuf), "0x%llx\n", - (uint64_t)phba->lpfc_injerr_lba); - break; - default: - lpfc_log_msg(phba, KERN_WARNING, LOG_INIT, - "0547 Unknown debugfs error injection entry\n"); - break; - } + cnt = scnprintf(cbuf, 32, "0x%llx\n", + (uint64_t) phba->lpfc_injerr_lba); + } else + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0547 Unknown debugfs error injection entry\n"); return simple_read_from_buffer(buf, nbytes, ppos, &cbuf, cnt); } static ssize_t lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) + size_t nbytes, loff_t *ppos) { + struct dentry *dent = file->f_path.dentry; struct lpfc_hba *phba = file->private_data; - int kind = debugfs_get_aux_num(file); - char dstbuf[33] = {0}; - unsigned long long tmp; - unsigned long size; + char dstbuf[33]; + uint64_t tmp = 0; + int size; - size = (nbytes < (sizeof(dstbuf) - 1)) ? nbytes : (sizeof(dstbuf) - 1); + memset(dstbuf, 0, 33); + size = (nbytes < 32) ? nbytes : 32; if (copy_from_user(dstbuf, buf, size)) return -EFAULT; - if (kstrtoull(dstbuf, 0, &tmp)) { - if (kind != InjErrLBA || !strstr(dstbuf, "off")) - return -EINVAL; + if (dent == phba->debug_InjErrLBA) { + if ((dstbuf[0] == 'o') && (dstbuf[1] == 'f') && + (dstbuf[2] == 'f')) + tmp = (uint64_t)(-1); } - switch (kind) { - case writeGuard: + if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp))) + return -EINVAL; + + if (dent == phba->debug_writeGuard) phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp; - break; - case writeApp: + else if (dent == phba->debug_writeApp) phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp; - break; - case writeRef: + else if (dent == phba->debug_writeRef) phba->lpfc_injerr_wref_cnt = (uint32_t)tmp; - break; - case readGuard: + else if (dent == phba->debug_readGuard) phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp; - break; - case readApp: + else if (dent == phba->debug_readApp) phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp; - break; - case readRef: + else if (dent == phba->debug_readRef) phba->lpfc_injerr_rref_cnt = (uint32_t)tmp; - break; - case InjErrLBA: - if (strstr(dstbuf, "off")) - phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; - else - phba->lpfc_injerr_lba = (sector_t)tmp; - break; - case InjErrNPortID: + else if (dent == phba->debug_InjErrLBA) + phba->lpfc_injerr_lba = (sector_t)tmp; + else if (dent == phba->debug_InjErrNPortID) phba->lpfc_injerr_nportid = (uint32_t)(tmp & Mask_DID); - break; - case InjErrWWPN: - phba->lpfc_injerr_wwpn.u.wwn_be = cpu_to_be64(tmp); - break; - default: - lpfc_log_msg(phba, KERN_WARNING, LOG_INIT, - "0548 Unknown debugfs error injection entry\n"); - break; - } + else if (dent == phba->debug_InjErrWWPN) { + tmp = cpu_to_be64(tmp); + memcpy(&phba->lpfc_injerr_wwpn, &tmp, sizeof(struct lpfc_name)); + } else + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0548 Unknown debugfs error injection entry\n"); + return nbytes; } @@ -5752,7 +5728,7 @@ static const struct file_operations lpfc_debugfs_op_slow_ring_trc = { }; static struct dentry *lpfc_debugfs_root = NULL; -static unsigned int lpfc_debugfs_hba_count; +static atomic_t lpfc_debugfs_hba_count; /* * File operations for the iDiag debugfs @@ -6074,12 +6050,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) /* Setup lpfc root directory */ if (!lpfc_debugfs_root) { lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL); - lpfc_debugfs_hba_count = 0; - if (IS_ERR(lpfc_debugfs_root)) { - lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT, - "0527 Cannot create debugfs lpfc\n"); - return; - } + atomic_set(&lpfc_debugfs_hba_count, 0); } if (!lpfc_debugfs_start_time) lpfc_debugfs_start_time = jiffies; @@ -6090,96 +6061,159 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) pport_setup = true; phba->hba_debugfs_root = debugfs_create_dir(name, lpfc_debugfs_root); - phba->debugfs_vport_count = 0; - if (IS_ERR(phba->hba_debugfs_root)) { - lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT, - "0528 Cannot create debugfs %s\n", name); - return; - } - lpfc_debugfs_hba_count++; + atomic_inc(&lpfc_debugfs_hba_count); + atomic_set(&phba->debugfs_vport_count, 0); /* Multi-XRI pools */ - debugfs_create_file("multixripools", 0644, - phba->hba_debugfs_root, phba, - &lpfc_debugfs_op_multixripools); + snprintf(name, sizeof(name), "multixripools"); + phba->debug_multixri_pools = + debugfs_create_file(name, S_IFREG | 0644, + phba->hba_debugfs_root, + phba, + &lpfc_debugfs_op_multixripools); + if (IS_ERR(phba->debug_multixri_pools)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0527 Cannot create debugfs multixripools\n"); + goto debug_failed; + } /* Congestion Info Buffer */ - debugfs_create_file("cgn_buffer", 0644, phba->hba_debugfs_root, - phba, &lpfc_cgn_buffer_op); + scnprintf(name, sizeof(name), "cgn_buffer"); + phba->debug_cgn_buffer = + debugfs_create_file(name, S_IFREG | 0644, + phba->hba_debugfs_root, + phba, &lpfc_cgn_buffer_op); + if (IS_ERR(phba->debug_cgn_buffer)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "6527 Cannot create debugfs " + "cgn_buffer\n"); + goto debug_failed; + } /* RX Monitor */ - debugfs_create_file("rx_monitor", 0644, phba->hba_debugfs_root, - phba, &lpfc_rx_monitor_op); + scnprintf(name, sizeof(name), "rx_monitor"); + phba->debug_rx_monitor = + debugfs_create_file(name, S_IFREG | 0644, + phba->hba_debugfs_root, + phba, &lpfc_rx_monitor_op); + if (IS_ERR(phba->debug_rx_monitor)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "6528 Cannot create debugfs " + "rx_monitor\n"); + goto debug_failed; + } /* RAS log */ - debugfs_create_file("ras_log", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_ras_log); + snprintf(name, sizeof(name), "ras_log"); + phba->debug_ras_log = + debugfs_create_file(name, 0644, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_ras_log); + if (IS_ERR(phba->debug_ras_log)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "6148 Cannot create debugfs" + " ras_log\n"); + goto debug_failed; + } /* Setup hbqinfo */ - debugfs_create_file("hbqinfo", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_hbqinfo); + snprintf(name, sizeof(name), "hbqinfo"); + phba->debug_hbqinfo = + debugfs_create_file(name, S_IFREG | 0644, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_hbqinfo); #ifdef LPFC_HDWQ_LOCK_STAT /* Setup lockstat */ - debugfs_create_file("lockstat", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_lockstat); + snprintf(name, sizeof(name), "lockstat"); + phba->debug_lockstat = + debugfs_create_file(name, S_IFREG | 0644, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_lockstat); + if (IS_ERR(phba->debug_lockstat)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "4610 Can't create debugfs lockstat\n"); + goto debug_failed; + } #endif - if (phba->sli_rev < LPFC_SLI_REV4) { - /* Setup dumpHBASlim */ - debugfs_create_file("dumpHBASlim", 0644, - phba->hba_debugfs_root, phba, - &lpfc_debugfs_op_dumpHBASlim); - } + /* Setup dumpHBASlim */ if (phba->sli_rev < LPFC_SLI_REV4) { - /* Setup dumpHostSlim */ - debugfs_create_file("dumpHostSlim", 0644, - phba->hba_debugfs_root, phba, - &lpfc_debugfs_op_dumpHostSlim); - } + snprintf(name, sizeof(name), "dumpHBASlim"); + phba->debug_dumpHBASlim = + debugfs_create_file(name, + S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dumpHBASlim); + } else + phba->debug_dumpHBASlim = NULL; + + /* Setup dumpHostSlim */ + if (phba->sli_rev < LPFC_SLI_REV4) { + snprintf(name, sizeof(name), "dumpHostSlim"); + phba->debug_dumpHostSlim = + debugfs_create_file(name, + S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dumpHostSlim); + } else + phba->debug_dumpHostSlim = NULL; /* Setup DIF Error Injections */ - debugfs_create_file_aux_num("InjErrLBA", 0644, - phba->hba_debugfs_root, phba, - InjErrLBA, - &lpfc_debugfs_op_dif_err); + snprintf(name, sizeof(name), "InjErrLBA"); + phba->debug_InjErrLBA = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dif_err); phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; - debugfs_create_file_aux_num("InjErrNPortID", 0644, - phba->hba_debugfs_root, phba, - InjErrNPortID, - &lpfc_debugfs_op_dif_err); + snprintf(name, sizeof(name), "InjErrNPortID"); + phba->debug_InjErrNPortID = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dif_err); - debugfs_create_file_aux_num("InjErrWWPN", 0644, - phba->hba_debugfs_root, phba, - InjErrWWPN, - &lpfc_debugfs_op_dif_err); + snprintf(name, sizeof(name), "InjErrWWPN"); + phba->debug_InjErrWWPN = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dif_err); - debugfs_create_file_aux_num("writeGuardInjErr", 0644, - phba->hba_debugfs_root, phba, - writeGuard, - &lpfc_debugfs_op_dif_err); + snprintf(name, sizeof(name), "writeGuardInjErr"); + phba->debug_writeGuard = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dif_err); - debugfs_create_file_aux_num("writeAppInjErr", 0644, - phba->hba_debugfs_root, phba, - writeApp, &lpfc_debugfs_op_dif_err); + snprintf(name, sizeof(name), "writeAppInjErr"); + phba->debug_writeApp = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dif_err); - debugfs_create_file_aux_num("writeRefInjErr", 0644, - phba->hba_debugfs_root, phba, - writeRef, &lpfc_debugfs_op_dif_err); + snprintf(name, sizeof(name), "writeRefInjErr"); + phba->debug_writeRef = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dif_err); - debugfs_create_file_aux_num("readGuardInjErr", 0644, - phba->hba_debugfs_root, phba, - readGuard, - &lpfc_debugfs_op_dif_err); + snprintf(name, sizeof(name), "readGuardInjErr"); + phba->debug_readGuard = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dif_err); - debugfs_create_file_aux_num("readAppInjErr", 0644, - phba->hba_debugfs_root, phba, - readApp, &lpfc_debugfs_op_dif_err); + snprintf(name, sizeof(name), "readAppInjErr"); + phba->debug_readApp = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dif_err); - debugfs_create_file_aux_num("readRefInjErr", 0644, - phba->hba_debugfs_root, phba, - readRef, &lpfc_debugfs_op_dif_err); + snprintf(name, sizeof(name), "readRefInjErr"); + phba->debug_readRef = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_dif_err); /* Setup slow ring trace */ if (lpfc_debugfs_max_slow_ring_trc) { @@ -6193,15 +6227,16 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) i++; } lpfc_debugfs_max_slow_ring_trc = (1 << i); - pr_info("lpfc_debugfs_max_slow_ring_trc " - "changed to %d\n", - lpfc_debugfs_max_slow_ring_trc); + pr_err("lpfc_debugfs_max_disc_trc changed to " + "%d\n", lpfc_debugfs_max_disc_trc); } } - debugfs_create_file("slow_ring_trace", 0644, - phba->hba_debugfs_root, phba, - &lpfc_debugfs_op_slow_ring_trc); + snprintf(name, sizeof(name), "slow_ring_trace"); + phba->debug_slow_ring_trc = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_slow_ring_trc); if (!phba->slow_ring_trc) { phba->slow_ring_trc = kcalloc( lpfc_debugfs_max_slow_ring_trc, @@ -6211,18 +6246,21 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "0416 Cannot create debugfs " "slow_ring buffer\n"); - goto out; + goto debug_failed; } atomic_set(&phba->slow_ring_trc_cnt, 0); } - debugfs_create_file("nvmeio_trc", 0644, phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_nvmeio_trc); + snprintf(name, sizeof(name), "nvmeio_trc"); + phba->debug_nvmeio_trc = + debugfs_create_file(name, 0644, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_op_nvmeio_trc); atomic_set(&phba->nvmeio_trc_cnt, 0); if (lpfc_debugfs_max_nvmeio_trc) { num = lpfc_debugfs_max_nvmeio_trc - 1; - if (num & lpfc_debugfs_max_nvmeio_trc) { + if (num & lpfc_debugfs_max_disc_trc) { /* Change to be a power of 2 */ num = lpfc_debugfs_max_nvmeio_trc; i = 0; @@ -6231,9 +6269,10 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) i++; } lpfc_debugfs_max_nvmeio_trc = (1 << i); - pr_info("lpfc_debugfs_max_nvmeio_trc changed " - "to %d\n", - lpfc_debugfs_max_nvmeio_trc); + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0575 lpfc_debugfs_max_nvmeio_trc " + "changed to %d\n", + lpfc_debugfs_max_nvmeio_trc); } phba->nvmeio_trc_size = lpfc_debugfs_max_nvmeio_trc; @@ -6250,6 +6289,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) } phba->nvmeio_trc_on = 1; phba->nvmeio_trc_output_idx = 0; + phba->nvmeio_trc = NULL; } else { nvmeio_off: phba->nvmeio_trc_size = 0; @@ -6263,12 +6303,7 @@ nvmeio_off: if (!vport->vport_debugfs_root) { vport->vport_debugfs_root = debugfs_create_dir(name, phba->hba_debugfs_root); - if (IS_ERR(vport->vport_debugfs_root)) { - lpfc_vlog_msg(vport, KERN_WARNING, LOG_INIT, - "0529 Cannot create debugfs %s\n", name); - return; - } - phba->debugfs_vport_count++; + atomic_inc(&phba->debugfs_vport_count); } if (lpfc_debugfs_max_disc_trc) { @@ -6282,8 +6317,8 @@ nvmeio_off: i++; } lpfc_debugfs_max_disc_trc = (1 << i); - pr_info("lpfc_debugfs_max_disc_trc changed to %d\n", - lpfc_debugfs_max_disc_trc); + pr_err("lpfc_debugfs_max_disc_trc changed to %d\n", + lpfc_debugfs_max_disc_trc); } } @@ -6295,27 +6330,54 @@ nvmeio_off: lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "0418 Cannot create debugfs disc trace " "buffer\n"); - goto out; + goto debug_failed; } atomic_set(&vport->disc_trc_cnt, 0); - debugfs_create_file("discovery_trace", 0644, vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_disc_trc); + snprintf(name, sizeof(name), "discovery_trace"); + vport->debug_disc_trc = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + vport->vport_debugfs_root, + vport, &lpfc_debugfs_op_disc_trc); + snprintf(name, sizeof(name), "nodelist"); + vport->debug_nodelist = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + vport->vport_debugfs_root, + vport, &lpfc_debugfs_op_nodelist); - debugfs_create_file("nodelist", 0644, vport->vport_debugfs_root, vport, - &lpfc_debugfs_op_nodelist); + snprintf(name, sizeof(name), "nvmestat"); + vport->debug_nvmestat = + debugfs_create_file(name, 0644, + vport->vport_debugfs_root, + vport, &lpfc_debugfs_op_nvmestat); - debugfs_create_file("nvmestat", 0644, vport->vport_debugfs_root, vport, - &lpfc_debugfs_op_nvmestat); + snprintf(name, sizeof(name), "scsistat"); + vport->debug_scsistat = + debugfs_create_file(name, 0644, + vport->vport_debugfs_root, + vport, &lpfc_debugfs_op_scsistat); + if (IS_ERR(vport->debug_scsistat)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "4611 Cannot create debugfs scsistat\n"); + goto debug_failed; + } - debugfs_create_file("scsistat", 0644, vport->vport_debugfs_root, vport, - &lpfc_debugfs_op_scsistat); + snprintf(name, sizeof(name), "ioktime"); + vport->debug_ioktime = + debugfs_create_file(name, 0644, + vport->vport_debugfs_root, + vport, &lpfc_debugfs_op_ioktime); + if (IS_ERR(vport->debug_ioktime)) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "0815 Cannot create debugfs ioktime\n"); + goto debug_failed; + } - debugfs_create_file("ioktime", 0644, vport->vport_debugfs_root, vport, - &lpfc_debugfs_op_ioktime); - - debugfs_create_file("hdwqstat", 0644, vport->vport_debugfs_root, vport, - &lpfc_debugfs_op_hdwqstat); + snprintf(name, sizeof(name), "hdwqstat"); + vport->debug_hdwqstat = + debugfs_create_file(name, 0644, + vport->vport_debugfs_root, + vport, &lpfc_debugfs_op_hdwqstat); /* * The following section is for additional directories/files for the @@ -6323,58 +6385,93 @@ nvmeio_off: */ if (!pport_setup) - return; + goto debug_failed; /* * iDiag debugfs root entry points for SLI4 device only */ if (phba->sli_rev < LPFC_SLI_REV4) - return; + goto debug_failed; + snprintf(name, sizeof(name), "iDiag"); if (!phba->idiag_root) { phba->idiag_root = - debugfs_create_dir("iDiag", phba->hba_debugfs_root); + debugfs_create_dir(name, phba->hba_debugfs_root); /* Initialize iDiag data structure */ memset(&idiag, 0, sizeof(idiag)); } /* iDiag read PCI config space */ - debugfs_create_file("pciCfg", 0644, phba->idiag_root, phba, - &lpfc_idiag_op_pciCfg); - idiag.offset.last_rd = 0; + snprintf(name, sizeof(name), "pciCfg"); + if (!phba->idiag_pci_cfg) { + phba->idiag_pci_cfg = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->idiag_root, phba, &lpfc_idiag_op_pciCfg); + idiag.offset.last_rd = 0; + } /* iDiag PCI BAR access */ - debugfs_create_file("barAcc", 0644, phba->idiag_root, phba, - &lpfc_idiag_op_barAcc); - idiag.offset.last_rd = 0; + snprintf(name, sizeof(name), "barAcc"); + if (!phba->idiag_bar_acc) { + phba->idiag_bar_acc = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->idiag_root, phba, &lpfc_idiag_op_barAcc); + idiag.offset.last_rd = 0; + } /* iDiag get PCI function queue information */ - debugfs_create_file("queInfo", 0444, phba->idiag_root, phba, - &lpfc_idiag_op_queInfo); + snprintf(name, sizeof(name), "queInfo"); + if (!phba->idiag_que_info) { + phba->idiag_que_info = + debugfs_create_file(name, S_IFREG|S_IRUGO, + phba->idiag_root, phba, &lpfc_idiag_op_queInfo); + } /* iDiag access PCI function queue */ - debugfs_create_file("queAcc", 0644, phba->idiag_root, phba, - &lpfc_idiag_op_queAcc); + snprintf(name, sizeof(name), "queAcc"); + if (!phba->idiag_que_acc) { + phba->idiag_que_acc = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->idiag_root, phba, &lpfc_idiag_op_queAcc); + } /* iDiag access PCI function doorbell registers */ - debugfs_create_file("drbAcc", 0644, phba->idiag_root, phba, - &lpfc_idiag_op_drbAcc); + snprintf(name, sizeof(name), "drbAcc"); + if (!phba->idiag_drb_acc) { + phba->idiag_drb_acc = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->idiag_root, phba, &lpfc_idiag_op_drbAcc); + } /* iDiag access PCI function control registers */ - debugfs_create_file("ctlAcc", 0644, phba->idiag_root, phba, - &lpfc_idiag_op_ctlAcc); + snprintf(name, sizeof(name), "ctlAcc"); + if (!phba->idiag_ctl_acc) { + phba->idiag_ctl_acc = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc); + } /* iDiag access mbox commands */ - debugfs_create_file("mbxAcc", 0644, phba->idiag_root, phba, - &lpfc_idiag_op_mbxAcc); + snprintf(name, sizeof(name), "mbxAcc"); + if (!phba->idiag_mbx_acc) { + phba->idiag_mbx_acc = + debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, + phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc); + } /* iDiag extents access commands */ if (phba->sli4_hba.extents_in_use) { - debugfs_create_file("extAcc", 0644, phba->idiag_root, phba, - &lpfc_idiag_op_extAcc); + snprintf(name, sizeof(name), "extAcc"); + if (!phba->idiag_ext_acc) { + phba->idiag_ext_acc = + debugfs_create_file(name, + S_IFREG|S_IRUGO|S_IWUSR, + phba->idiag_root, phba, + &lpfc_idiag_op_extAcc); + } } -out: - /* alloc'ed items are kfree'd in lpfc_debugfs_terminate */ + +debug_failed: return; #endif } @@ -6399,26 +6496,145 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) kfree(vport->disc_trc); vport->disc_trc = NULL; + debugfs_remove(vport->debug_disc_trc); /* discovery_trace */ + vport->debug_disc_trc = NULL; + + debugfs_remove(vport->debug_nodelist); /* nodelist */ + vport->debug_nodelist = NULL; + + debugfs_remove(vport->debug_nvmestat); /* nvmestat */ + vport->debug_nvmestat = NULL; + + debugfs_remove(vport->debug_scsistat); /* scsistat */ + vport->debug_scsistat = NULL; + + debugfs_remove(vport->debug_ioktime); /* ioktime */ + vport->debug_ioktime = NULL; + + debugfs_remove(vport->debug_hdwqstat); /* hdwqstat */ + vport->debug_hdwqstat = NULL; + if (vport->vport_debugfs_root) { debugfs_remove(vport->vport_debugfs_root); /* vportX */ vport->vport_debugfs_root = NULL; - phba->debugfs_vport_count--; + atomic_dec(&phba->debugfs_vport_count); } - if (!phba->debugfs_vport_count) { + if (atomic_read(&phba->debugfs_vport_count) == 0) { + + debugfs_remove(phba->debug_multixri_pools); /* multixripools*/ + phba->debug_multixri_pools = NULL; + + debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */ + phba->debug_hbqinfo = NULL; + + debugfs_remove(phba->debug_cgn_buffer); + phba->debug_cgn_buffer = NULL; + + debugfs_remove(phba->debug_rx_monitor); + phba->debug_rx_monitor = NULL; + + debugfs_remove(phba->debug_ras_log); + phba->debug_ras_log = NULL; + +#ifdef LPFC_HDWQ_LOCK_STAT + debugfs_remove(phba->debug_lockstat); /* lockstat */ + phba->debug_lockstat = NULL; +#endif + debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */ + phba->debug_dumpHBASlim = NULL; + + debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */ + phba->debug_dumpHostSlim = NULL; + + debugfs_remove(phba->debug_InjErrLBA); /* InjErrLBA */ + phba->debug_InjErrLBA = NULL; + + debugfs_remove(phba->debug_InjErrNPortID); + phba->debug_InjErrNPortID = NULL; + + debugfs_remove(phba->debug_InjErrWWPN); /* InjErrWWPN */ + phba->debug_InjErrWWPN = NULL; + + debugfs_remove(phba->debug_writeGuard); /* writeGuard */ + phba->debug_writeGuard = NULL; + + debugfs_remove(phba->debug_writeApp); /* writeApp */ + phba->debug_writeApp = NULL; + + debugfs_remove(phba->debug_writeRef); /* writeRef */ + phba->debug_writeRef = NULL; + + debugfs_remove(phba->debug_readGuard); /* readGuard */ + phba->debug_readGuard = NULL; + + debugfs_remove(phba->debug_readApp); /* readApp */ + phba->debug_readApp = NULL; + + debugfs_remove(phba->debug_readRef); /* readRef */ + phba->debug_readRef = NULL; + kfree(phba->slow_ring_trc); phba->slow_ring_trc = NULL; + /* slow_ring_trace */ + debugfs_remove(phba->debug_slow_ring_trc); + phba->debug_slow_ring_trc = NULL; + + debugfs_remove(phba->debug_nvmeio_trc); + phba->debug_nvmeio_trc = NULL; + kfree(phba->nvmeio_trc); phba->nvmeio_trc = NULL; + /* + * iDiag release + */ + if (phba->sli_rev == LPFC_SLI_REV4) { + /* iDiag extAcc */ + debugfs_remove(phba->idiag_ext_acc); + phba->idiag_ext_acc = NULL; + + /* iDiag mbxAcc */ + debugfs_remove(phba->idiag_mbx_acc); + phba->idiag_mbx_acc = NULL; + + /* iDiag ctlAcc */ + debugfs_remove(phba->idiag_ctl_acc); + phba->idiag_ctl_acc = NULL; + + /* iDiag drbAcc */ + debugfs_remove(phba->idiag_drb_acc); + phba->idiag_drb_acc = NULL; + + /* iDiag queAcc */ + debugfs_remove(phba->idiag_que_acc); + phba->idiag_que_acc = NULL; + + /* iDiag queInfo */ + debugfs_remove(phba->idiag_que_info); + phba->idiag_que_info = NULL; + + /* iDiag barAcc */ + debugfs_remove(phba->idiag_bar_acc); + phba->idiag_bar_acc = NULL; + + /* iDiag pciCfg */ + debugfs_remove(phba->idiag_pci_cfg); + phba->idiag_pci_cfg = NULL; + + /* Finally remove the iDiag debugfs root */ + debugfs_remove(phba->idiag_root); + phba->idiag_root = NULL; + } + if (phba->hba_debugfs_root) { debugfs_remove(phba->hba_debugfs_root); /* fnX */ phba->hba_debugfs_root = NULL; - lpfc_debugfs_hba_count--; + atomic_dec(&lpfc_debugfs_hba_count); } - if (!lpfc_debugfs_hba_count) { + if (atomic_read(&lpfc_debugfs_hba_count) == 0) { debugfs_remove(lpfc_debugfs_root); /* lpfc */ lpfc_debugfs_root = NULL; } diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h index a1464f8ac3..8d2e8d05bb 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.h +++ b/drivers/scsi/lpfc/lpfc_debugfs.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2007-2011 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -44,9 +44,6 @@ /* hbqinfo output buffer size */ #define LPFC_HBQINFO_SIZE 8192 -/* hdwqinfo output buffer size */ -#define LPFC_HDWQINFO_SIZE 8192 - /* nvmestat output buffer size */ #define LPFC_NVMESTAT_SIZE 8192 #define LPFC_IOKTIME_SIZE 8192 @@ -325,17 +322,6 @@ enum { * discovery */ #endif /* H_LPFC_DEBUG_FS */ -enum { - writeGuard = 1, - writeApp, - writeRef, - readGuard, - readApp, - readRef, - InjErrLBA, - InjErrNPortID, - InjErrWWPN, -}; /* * Driver debug utility routines outside of debugfs. The debug utility diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index 51cb8571c0..3d47dc7458 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2013 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -208,7 +208,6 @@ enum lpfc_nlp_flag { NPR list */ NLP_RM_DFLT_RPI = 26, /* need to remove leftover dflt RPI */ NLP_NODEV_REMOVE = 27, /* Defer removal till discovery ends */ - NLP_FLOGI_DFR_ACC = 28, /* FLOGI LS_ACC was Deferred */ NLP_SC_REQ = 29, /* Target requires authentication */ NLP_FIRSTBURST = 30, /* Target supports FirstBurst */ NLP_RPI_REGISTERED = 31 /* nlp_rpi is valid */ diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index f769dc29b0..97dee0e34f 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -650,6 +650,8 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_class_sup |= FC_COS_CLASS2; if (sp->cls3.classValid) ndlp->nlp_class_sup |= FC_COS_CLASS3; + if (sp->cls4.classValid) + ndlp->nlp_class_sup |= FC_COS_CLASS4; ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; @@ -1354,14 +1356,6 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Can't do SLI4 class2 without support sequence coalescing */ sp->cls2.classValid = 0; sp->cls2.seqDelivery = 0; - - /* Fill out Auxiliary Parameter Data */ - if (phba->pni) { - sp->aux.flags = - AUX_PARM_DATA_VALID | AUX_PARM_PNI_VALID; - sp->aux.pni = cpu_to_be64(phba->pni); - sp->aux.npiv_cnt = cpu_to_be16(phba->max_vpi - 1); - } } else { /* Historical, setting sequential-delivery bit for SLI3 */ sp->cls2.seqDelivery = (sp->cls2.classValid) ? 1 : 0; @@ -1441,12 +1435,11 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->defer_flogi_acc.ox_id; } - /* The LS_ACC completion needs to drop the initial reference. - * This is a special case for Pt2Pt because both FLOGIs need - * to complete and lpfc defers the LS_ACC when the remote - * FLOGI arrives before the driver's FLOGI. - */ - set_bit(NLP_FLOGI_DFR_ACC, &ndlp->nlp_flag); + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3354 Xmit deferred FLOGI ACC: rx_id: x%x," + " ox_id: x%x, hba_flag x%lx\n", + phba->defer_flogi_acc.rx_id, + phba->defer_flogi_acc.ox_id, phba->hba_flag); /* Send deferred FLOGI ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, &defer_flogi_acc, @@ -1462,14 +1455,6 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, phba->defer_flogi_acc.ndlp = NULL; } - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "3354 Xmit deferred FLOGI ACC: rx_id: x%x," - " ox_id: x%x, ndlp x%px hba_flag x%lx\n", - phba->defer_flogi_acc.rx_id, - phba->defer_flogi_acc.ox_id, - phba->defer_flogi_acc.ndlp, - phba->hba_flag); - vport->fc_myDID = did; } @@ -2285,8 +2270,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) sp->cmn.valid_vendor_ver_level = 0; memset(sp->un.vendorVersion, 0, sizeof(sp->un.vendorVersion)); - if (!test_bit(FC_PT2PT, &vport->fc_flag)) - sp->cmn.bbRcvSizeMsb &= 0xF; + sp->cmn.bbRcvSizeMsb &= 0xF; /* Check if the destination port supports VMID */ ndlp->vmid_support = 0; @@ -2405,7 +2389,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, mode = KERN_INFO; /* Warn PRLI status */ - lpfc_vlog_msg(vport, mode, LOG_ELS, + lpfc_printf_vlog(vport, mode, LOG_ELS, "2754 PRLI DID:%06X Status:x%x/x%x, " "data: x%x x%x x%lx\n", ndlp->nlp_DID, ulp_status, @@ -3062,7 +3046,6 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ndlp->nlp_DID, ulp_status, ulp_word4); - /* Call NLP_EVT_DEVICE_RM if link is down or LOGO is aborted */ if (lpfc_error_lost_link(vport, ulp_status, ulp_word4)) skip_recovery = 1; } @@ -3301,7 +3284,7 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp) return -ENOMEM; } rc = lpfc_reg_rpi(phba, vport->vpi, fc_ndlp->nlp_DID, - (u8 *)&ns_ndlp->fc_sparam, mbox, fc_ndlp->nlp_rpi); + (u8 *)&vport->fc_sparam, mbox, fc_ndlp->nlp_rpi); if (rc) { rc = -EACCES; goto out; @@ -3345,8 +3328,7 @@ lpfc_reg_fab_ctrl_node(struct lpfc_vport *vport, struct lpfc_nodelist *fc_ndlp) * * This routine is a generic completion callback function for Discovery ELS cmd. * Currently used by the ELS command issuing routines for the ELS State Change - * Request (SCR), lpfc_issue_els_scr(), Exchange Diagnostic Capabilities (EDC), - * lpfc_issue_els_edc() and the ELS RDF, lpfc_issue_els_rdf(). + * Request (SCR), lpfc_issue_els_scr() and the ELS RDF, lpfc_issue_els_rdf(). * These commands will be retried once only for ELS timeout errors. **/ static void @@ -3419,21 +3401,11 @@ lpfc_cmpl_els_disc_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_cmpl_els_edc(phba, cmdiocb, rspiocb); return; } - if (ulp_status) { /* ELS discovery cmd completes with error */ lpfc_printf_vlog(vport, KERN_WARNING, LOG_ELS | LOG_CGN_MGMT, "4203 ELS cmd x%x error: x%x x%X\n", cmd, ulp_status, ulp_word4); - - /* In the case where the ELS cmd completes with an error and - * the node does not have RPI registered, the node is - * outstanding and should put its initial reference. - */ - if ((cmd == ELS_CMD_SCR || cmd == ELS_CMD_RDF) && - !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD) && - !test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) - lpfc_nlp_put(ndlp); goto out; } @@ -3502,7 +3474,6 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) uint8_t *pcmd; uint16_t cmdsize; struct lpfc_nodelist *ndlp; - bool node_created = false; cmdsize = (sizeof(uint32_t) + sizeof(SCR)); @@ -3512,21 +3483,21 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) if (!ndlp) return 1; lpfc_enqueue_node(vport, ndlp); - node_created = true; } elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_SCR); if (!elsiocb) - goto out_node_created; + return 1; if (phba->sli_rev == LPFC_SLI_REV4) { rc = lpfc_reg_fab_ctrl_node(vport, ndlp); if (rc) { + lpfc_els_free_iocb(phba, elsiocb); lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, "0937 %s: Failed to reg fc node, rc %d\n", __func__, rc); - goto out_free_iocb; + return 1; } } pcmd = (uint8_t *)elsiocb->cmd_dmabuf->virt; @@ -3545,27 +3516,23 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint8_t retry) phba->fc_stat.elsXmitSCR++; elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd; elsiocb->ndlp = lpfc_nlp_get(ndlp); - if (!elsiocb->ndlp) - goto out_free_iocb; + if (!elsiocb->ndlp) { + lpfc_els_free_iocb(phba, elsiocb); + return 1; + } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, "Issue SCR: did:x%x refcnt %d", ndlp->nlp_DID, kref_read(&ndlp->kref), 0); rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) - goto out_iocb_error; + if (rc == IOCB_ERROR) { + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + return 1; + } return 0; - -out_iocb_error: - lpfc_nlp_put(ndlp); -out_free_iocb: - lpfc_els_free_iocb(phba, elsiocb); -out_node_created: - if (node_created) - lpfc_nlp_put(ndlp); - return 1; } /** @@ -3652,8 +3619,8 @@ lpfc_issue_els_rscn(struct lpfc_vport *vport, uint8_t retry) } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue RSCN: did:x%x refcnt %d", - ndlp->nlp_DID, kref_read(&ndlp->kref), 0); + "Issue RSCN: did:x%x", + ndlp->nlp_DID, 0, 0); rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { @@ -3760,7 +3727,10 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) lpfc_nlp_put(ndlp); return 1; } - + /* This will cause the callback-function lpfc_cmpl_els_cmd to + * trigger the release of the node. + */ + /* Don't release reference count as RDF is likely outstanding */ return 0; } @@ -3778,12 +3748,7 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) * * Return code * 0 - Successfully issued rdf command - * < 0 - Failed to issue rdf command - * -EACCES - RDF not required for NPIV_PORT - * -ENODEV - No fabric controller device available - * -ENOMEM - No available memory - * -EIO - The mailbox failed to complete successfully. - * + * 1 - Failed to issue rdf command **/ int lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) @@ -3794,30 +3759,25 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) struct lpfc_nodelist *ndlp; uint16_t cmdsize; int rc; - bool node_created = false; - int err; cmdsize = sizeof(*prdf); - /* RDF ELS is not required on an NPIV VN_Port. */ - if (vport->port_type == LPFC_NPIV_PORT) - return -EACCES; - ndlp = lpfc_findnode_did(vport, Fabric_Cntl_DID); if (!ndlp) { ndlp = lpfc_nlp_init(vport, Fabric_Cntl_DID); if (!ndlp) return -ENODEV; lpfc_enqueue_node(vport, ndlp); - node_created = true; } + /* RDF ELS is not required on an NPIV VN_Port. */ + if (vport->port_type == LPFC_NPIV_PORT) + return -EACCES; + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_RDF); - if (!elsiocb) { - err = -ENOMEM; - goto out_node_created; - } + if (!elsiocb) + return -ENOMEM; /* Configure the payload for the supported FPIN events. */ prdf = (struct lpfc_els_rdf_req *)elsiocb->cmd_dmabuf->virt; @@ -3843,8 +3803,8 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) elsiocb->cmd_cmpl = lpfc_cmpl_els_disc_cmd; elsiocb->ndlp = lpfc_nlp_get(ndlp); if (!elsiocb->ndlp) { - err = -EIO; - goto out_free_iocb; + lpfc_els_free_iocb(phba, elsiocb); + return -EIO; } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, @@ -3853,19 +3813,11 @@ lpfc_issue_els_rdf(struct lpfc_vport *vport, uint8_t retry) rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { - err = -EIO; - goto out_iocb_error; + lpfc_els_free_iocb(phba, elsiocb); + lpfc_nlp_put(ndlp); + return -EIO; } return 0; - -out_iocb_error: - lpfc_nlp_put(ndlp); -out_free_iocb: - lpfc_els_free_iocb(phba, elsiocb); -out_node_created: - if (node_created) - lpfc_nlp_put(ndlp); - return err; } /** @@ -3886,23 +3838,19 @@ static int lpfc_els_rcv_rdf(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, struct lpfc_nodelist *ndlp) { - int rc; - - rc = lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL); /* Send LS_ACC */ - if (rc) { + if (lpfc_els_rsp_acc(vport, ELS_CMD_RDF, cmdiocb, ndlp, NULL)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, - "1623 Failed to RDF_ACC from x%x for x%x Data: %d\n", - ndlp->nlp_DID, vport->fc_myDID, rc); + "1623 Failed to RDF_ACC from x%x for x%x\n", + ndlp->nlp_DID, vport->fc_myDID); return -EIO; } - rc = lpfc_issue_els_rdf(vport, 0); /* Issue new RDF for reregistering */ - if (rc) { + if (lpfc_issue_els_rdf(vport, 0)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS | LOG_CGN_MGMT, - "2623 Failed to re register RDF for x%x Data: %d\n", - vport->fc_myDID, rc); + "2623 Failed to re register RDF for x%x\n", + vport->fc_myDID); return -EIO; } @@ -4373,7 +4321,7 @@ lpfc_issue_els_edc(struct lpfc_vport *vport, uint8_t retry) rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); if (rc == IOCB_ERROR) { /* The additional lpfc_nlp_put will cause the following - * lpfc_els_free_iocb routine to trigger the release of + * lpfc_els_free_iocb routine to trigger the rlease of * the node. */ lpfc_els_free_iocb(phba, elsiocb); @@ -5201,7 +5149,7 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) { struct lpfc_dmabuf *buf_ptr, *buf_ptr1; - /* The I/O iocb is complete. Clear the node and first dmabuf */ + /* The I/O iocb is complete. Clear the node and first dmbuf */ elsiocb->ndlp = NULL; /* cmd_dmabuf = cmd, cmd_dmabuf->next = rsp, bpl_dmabuf = bpl */ @@ -5234,12 +5182,14 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) } else { buf_ptr1 = elsiocb->cmd_dmabuf; lpfc_els_free_data(phba, buf_ptr1); + elsiocb->cmd_dmabuf = NULL; } } if (elsiocb->bpl_dmabuf) { buf_ptr = elsiocb->bpl_dmabuf; lpfc_els_free_bpl(phba, buf_ptr); + elsiocb->bpl_dmabuf = NULL; } lpfc_sli_release_iocbq(phba, elsiocb); return 0; @@ -5377,12 +5327,11 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp; LPFC_MBOXQ_t *mbox = NULL; u32 ulp_status, ulp_word4, tmo, did, iotag; - u32 cmd; if (!vport) { lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, "3177 null vport in ELS rsp\n"); - goto release; + goto out; } if (cmdiocb->context_un.mbox) mbox = cmdiocb->context_un.mbox; @@ -5412,12 +5361,12 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, ulp_status, ulp_word4, did); /* ELS response tag completes */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0110 ELS response tag x%x completes fc_flag x%lx" + "0110 ELS response tag x%x completes " "Data: x%x x%x x%x x%x x%lx x%x x%x x%x %p %p\n", - iotag, vport->fc_flag, ulp_status, ulp_word4, tmo, + iotag, ulp_status, ulp_word4, tmo, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi, kref_read(&ndlp->kref), mbox, ndlp); - if (mbox && !test_bit(FC_PT2PT, &vport->fc_flag)) { + if (mbox) { if (ulp_status == 0 && test_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag)) { if (!lpfc_unreg_rpi(vport, ndlp) && @@ -5476,10 +5425,6 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } out_free_mbox: lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); - } else if (mbox && test_bit(FC_PT2PT, &vport->fc_flag) && - test_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag)) { - lpfc_mbx_cmpl_reg_login(phba, mbox); - clear_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag); } out: if (ndlp && shost) { @@ -5492,7 +5437,7 @@ out: * these conditions because it doesn't need the login. */ if (phba->sli_rev == LPFC_SLI_REV4 && - vport->port_type == LPFC_NPIV_PORT && + vport && vport->port_type == LPFC_NPIV_PORT && !(ndlp->fc4_xpt_flags & SCSI_XPT_REGD)) { if (ndlp->nlp_state != NLP_STE_PLOGI_ISSUE && ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE && @@ -5508,27 +5453,6 @@ out: } } - /* The driver's unsolicited deferred FLOGI ACC in Pt2Pt needs to - * release the initial reference because the put after the free_iocb - * call removes only the reference from the defer logic. This FLOGI - * is never registered with the SCSI transport. - */ - if (test_bit(FC_PT2PT, &vport->fc_flag) && - test_and_clear_bit(NLP_FLOGI_DFR_ACC, &ndlp->nlp_flag)) { - lpfc_printf_vlog(vport, KERN_INFO, - LOG_ELS | LOG_NODE | LOG_DISCOVERY, - "3357 Pt2Pt Defer FLOGI ACC ndlp x%px, " - "nflags x%lx, fc_flag x%lx\n", - ndlp, ndlp->nlp_flag, - vport->fc_flag); - cmd = *((u32 *)cmdiocb->cmd_dmabuf->virt); - if (cmd == ELS_CMD_ACC) { - if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) - lpfc_nlp_put(ndlp); - } - } - -release: /* Release the originating I/O reference. */ lpfc_els_free_iocb(phba, cmdiocb); lpfc_nlp_put(ndlp); @@ -5663,6 +5587,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, sp->cls1.classValid = 0; sp->cls2.classValid = 0; sp->cls3.classValid = 0; + sp->cls4.classValid = 0; /* Copy our worldwide names */ memcpy(&sp->portName, &vport->fc_sparam.portName, @@ -5676,8 +5601,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, sp->cmn.valid_vendor_ver_level = 0; memset(sp->un.vendorVersion, 0, sizeof(sp->un.vendorVersion)); - if (!test_bit(FC_PT2PT, &vport->fc_flag)) - sp->cmn.bbRcvSizeMsb &= 0xF; + sp->cmn.bbRcvSizeMsb &= 0xF; /* If our firmware supports this feature, convey that * info to the target using the vendor specific field. @@ -7959,13 +7883,6 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) /* Move all affected nodes by pending RSCNs to NPR state. */ list_for_each_entry_safe(ndlp, n, &vport->fc_nodes, nlp_listp) { - if (test_bit(FC_UNLOADING, &vport->load_flag)) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "1000 %s Unloading set\n", - __func__); - return 0; - } - if ((ndlp->nlp_state == NLP_STE_UNUSED_NODE) || !lpfc_rscn_payload_check(vport, ndlp->nlp_DID)) continue; @@ -8475,9 +8392,9 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, clear_bit(FC_PUBLIC_LOOP, &vport->fc_flag); lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "3311 Rcv Flogi PS x%x new PS x%x " - "fc_flag x%lx new fc_flag x%lx, hba_flag x%lx\n", + "fc_flag x%lx new fc_flag x%lx\n", port_state, vport->port_state, - fc_flag, vport->fc_flag, phba->hba_flag); + fc_flag, vport->fc_flag); /* * We temporarily set fc_myDID to make it look like we are @@ -8497,6 +8414,13 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, &wqe->xmit_els_rsp.wqe_com); vport->fc_myDID = did; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3344 Deferring FLOGI ACC: rx_id: x%x," + " ox_id: x%x, hba_flag x%lx\n", + phba->defer_flogi_acc.rx_id, + phba->defer_flogi_acc.ox_id, phba->hba_flag); + phba->defer_flogi_acc.flag = true; /* This nlp_get is paired with nlp_puts that reset the @@ -8505,14 +8429,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, * processed or cancelled. */ phba->defer_flogi_acc.ndlp = lpfc_nlp_get(ndlp); - - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "3344 Deferring FLOGI ACC: rx_id: x%x," - " ox_id: x%x, ndlp x%px, hba_flag x%lx\n", - phba->defer_flogi_acc.rx_id, - phba->defer_flogi_acc.ox_id, - phba->defer_flogi_acc.ndlp, - phba->hba_flag); return 0; } @@ -8830,7 +8746,7 @@ reject_out: * @cmdiocb: pointer to lpfc command iocb data structure. * @ndlp: pointer to a node-list data structure. * - * This routine processes Read Timeout Value (RTV) IOCB received as an + * This routine processes Read Timout Value (RTV) IOCB received as an * ELS unsolicited event. It first checks the remote port state. If the * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE * state, it invokes the lpfc_els_rsl_reject() routine to send the reject @@ -10458,8 +10374,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, * Do not process any unsolicited ELS commands * if the ndlp is in DEV_LOSS */ - if (test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) + if (test_bit(NLP_IN_DEV_LOSS, &ndlp->nlp_flag)) { + if (newnode) + lpfc_nlp_put(ndlp); goto dropit; + } elsiocb->ndlp = lpfc_nlp_get(ndlp); if (!elsiocb->ndlp) @@ -10941,7 +10860,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_els_unsol_buffer(phba, pring, vport, elsiocb); /* * The different unsolicited event handlers would tell us - * if they are done with "mp" by setting cmd_dmabuf/bpl_dmabuf to NULL. + * if they are done with "mp" by setting cmd_dmabuf to NULL. */ if (elsiocb->cmd_dmabuf) { lpfc_in_buf_free(phba, elsiocb->cmd_dmabuf); @@ -11361,11 +11280,6 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_vlog_msg(vport, KERN_WARNING, LOG_ELS, "0126 FDISC cmpl status: x%x/x%x)\n", ulp_status, ulp_word4); - - /* drop initial reference */ - if (!test_and_set_bit(NLP_DROPPED, &ndlp->nlp_flag)) - lpfc_nlp_put(ndlp); - goto fdisc_failed; } @@ -11521,13 +11435,6 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, sp->cls2.seqDelivery = 1; sp->cls3.seqDelivery = 1; - /* Fill out Auxiliary Parameter Data */ - if (phba->pni) { - sp->aux.flags = - AUX_PARM_DATA_VALID | AUX_PARM_PNI_VALID; - sp->aux.pni = cpu_to_be64(phba->pni); - } - pcmd += sizeof(uint32_t); /* CSP Word 2 */ pcmd += sizeof(uint32_t); /* CSP Word 3 */ pcmd += sizeof(uint32_t); /* CSP Word 4 */ @@ -12122,11 +12029,7 @@ lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, sglq_entry->state = SGL_FREED; spin_unlock_irqrestore(&phba->sli4_hba.sgl_list_lock, iflag); - lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI | - LOG_DISCOVERY | LOG_NODE, - "0732 ELS XRI ABORT on Node: ndlp=x%px " - "xri=x%x\n", - ndlp, xri); + if (ndlp) { lpfc_set_rrq_active(phba, ndlp, sglq_entry->sli4_lxritag, diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index b4ae899d27..a7064fdedb 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -183,8 +183,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) /* Don't schedule a worker thread event if the vport is going down. */ if (test_bit(FC_UNLOADING, &vport->load_flag) || - (phba->sli_rev == LPFC_SLI_REV4 && - !test_bit(HBA_SETUP, &phba->hba_flag))) { + !test_bit(HBA_SETUP, &phba->hba_flag)) { spin_lock_irqsave(&ndlp->lock, iflags); ndlp->rport = NULL; @@ -1269,10 +1268,6 @@ lpfc_linkdown(struct lpfc_hba *phba) } phba->defer_flogi_acc.flag = false; - /* reinitialize initial HBA flag */ - clear_bit(HBA_FLOGI_ISSUED, &phba->hba_flag); - clear_bit(HBA_RHBA_CMPL, &phba->hba_flag); - /* Clear external loopback plug detected flag */ phba->link_flag &= ~LS_EXTERNAL_LOOPBACK; @@ -1443,6 +1438,10 @@ lpfc_linkup(struct lpfc_hba *phba) phba->pport->rcv_flogi_cnt = 0; spin_unlock_irq(shost->host_lock); + /* reinitialize initial HBA flag */ + clear_bit(HBA_FLOGI_ISSUED, &phba->hba_flag); + clear_bit(HBA_RHBA_CMPL, &phba->hba_flag); + return 0; } @@ -4373,8 +4372,6 @@ out: lpfc_ns_cmd(vport, SLI_CTNS_RNN_ID, 0, 0); lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0); lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0); - if (phba->pni) - lpfc_ns_cmd(vport, SLI_CTNS_RSPNI_PNI, 0, 0); lpfc_ns_cmd(vport, SLI_CTNS_RFT_ID, 0, 0); if ((vport->cfg_enable_fc4_type == LPFC_ENABLE_BOTH) || @@ -6600,11 +6597,6 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp) unsigned long flags; if (ndlp) { - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node get: did:x%x flg:x%lx refcnt:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, - kref_read(&ndlp->kref)); - /* The check of ndlp usage to prevent incrementing the * ndlp reference count that is in the process of being * released. @@ -6612,9 +6604,8 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp) spin_lock_irqsave(&ndlp->lock, flags); if (!kref_get_unless_zero(&ndlp->kref)) { spin_unlock_irqrestore(&ndlp->lock, flags); - lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0276 %s: ndlp:x%px refcnt:%d\n", - __func__, (void *)ndlp, kref_read(&ndlp->kref)); + pr_info("0276 %s: NDLP has zero reference count. " + "Exiting\n", __func__); return NULL; } spin_unlock_irqrestore(&ndlp->lock, flags); diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index b2e353590e..32298285ea 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -168,11 +168,6 @@ struct lpfc_sli_ct_request { uint8_t len; uint8_t symbname[255]; } rspn; - struct rspni { /* For RSPNI_PNI requests */ - __be64 pni; - u8 len; - u8 symbname[255]; - } rspni; struct gff { uint32_t PortId; } gff; @@ -218,8 +213,6 @@ struct lpfc_sli_ct_request { sizeof(struct da_id)) #define RSPN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ sizeof(struct rspn)) -#define RSPNI_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ - sizeof(struct rspni)) /* * FsType Definitions @@ -316,7 +309,6 @@ struct lpfc_sli_ct_request { #define SLI_CTNS_RIP_NN 0x0235 #define SLI_CTNS_RIPA_NN 0x0236 #define SLI_CTNS_RSNN_NN 0x0239 -#define SLI_CTNS_RSPNI_PNI 0x0240 #define SLI_CTNS_DA_ID 0x0300 /* @@ -374,7 +366,6 @@ struct lpfc_name { } s; uint8_t wwn[8]; uint64_t name __packed __aligned(4); - __be64 wwn_be __packed __aligned(4); } u; }; @@ -520,21 +511,6 @@ struct class_parms { uint8_t word3Reserved2; /* Fc Word 3, bit 0: 7 */ }; -enum aux_parm_flags { - AUX_PARM_PNI_VALID = 0x20, /* FC Word 0, bit 29 */ - AUX_PARM_DATA_VALID = 0x40, /* FC Word 0, bit 30 */ -}; - -struct aux_parm { - u8 flags; /* FC Word 0, bit 31:24 */ - u8 ext_feat[3]; /* FC Word 0, bit 23:0 */ - - __be64 pni; /* FC Word 1 and 2, platform name identifier */ - - __be16 rsvd; /* FC Word 3, bit 31:16 */ - __be16 npiv_cnt; /* FC Word 3, bit 15:0 */ -} __packed; - struct serv_parm { /* Structure is in Big Endian format */ struct csp cmn; struct lpfc_name portName; @@ -542,7 +518,7 @@ struct serv_parm { /* Structure is in Big Endian format */ struct class_parms cls1; struct class_parms cls2; struct class_parms cls3; - struct aux_parm aux; + struct class_parms cls4; union { uint8_t vendorVersion[16]; struct { diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index bc709786e6..2dedb273b0 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -1328,9 +1328,6 @@ struct cq_context { #define LPFC_CQ_CNT_512 0x1 #define LPFC_CQ_CNT_1024 0x2 #define LPFC_CQ_CNT_WORD7 0x3 -#define lpfc_cq_context_cqe_sz_SHIFT 25 -#define lpfc_cq_context_cqe_sz_MASK 0x00000003 -#define lpfc_cq_context_cqe_sz_WORD word0 #define lpfc_cq_context_autovalid_SHIFT 15 #define lpfc_cq_context_autovalid_MASK 0x00000001 #define lpfc_cq_context_autovalid_WORD word0 @@ -1386,9 +1383,9 @@ struct lpfc_mbx_cq_create_set { #define lpfc_mbx_cq_create_set_valid_SHIFT 29 #define lpfc_mbx_cq_create_set_valid_MASK 0x00000001 #define lpfc_mbx_cq_create_set_valid_WORD word1 -#define lpfc_mbx_cq_create_set_cqecnt_SHIFT 27 -#define lpfc_mbx_cq_create_set_cqecnt_MASK 0x00000003 -#define lpfc_mbx_cq_create_set_cqecnt_WORD word1 +#define lpfc_mbx_cq_create_set_cqe_cnt_SHIFT 27 +#define lpfc_mbx_cq_create_set_cqe_cnt_MASK 0x00000003 +#define lpfc_mbx_cq_create_set_cqe_cnt_WORD word1 #define lpfc_mbx_cq_create_set_cqe_size_SHIFT 25 #define lpfc_mbx_cq_create_set_cqe_size_MASK 0x00000003 #define lpfc_mbx_cq_create_set_cqe_size_WORD word1 @@ -1401,16 +1398,13 @@ struct lpfc_mbx_cq_create_set { #define lpfc_mbx_cq_create_set_clswm_SHIFT 12 #define lpfc_mbx_cq_create_set_clswm_MASK 0x00000003 #define lpfc_mbx_cq_create_set_clswm_WORD word1 -#define lpfc_mbx_cq_create_set_cqe_cnt_hi_SHIFT 0 -#define lpfc_mbx_cq_create_set_cqe_cnt_hi_MASK 0x0000001F -#define lpfc_mbx_cq_create_set_cqe_cnt_hi_WORD word1 uint32_t word2; #define lpfc_mbx_cq_create_set_arm_SHIFT 31 #define lpfc_mbx_cq_create_set_arm_MASK 0x00000001 #define lpfc_mbx_cq_create_set_arm_WORD word2 -#define lpfc_mbx_cq_create_set_cqe_cnt_lo_SHIFT 16 -#define lpfc_mbx_cq_create_set_cqe_cnt_lo_MASK 0x00007FFF -#define lpfc_mbx_cq_create_set_cqe_cnt_lo_WORD word2 +#define lpfc_mbx_cq_create_set_cq_cnt_SHIFT 16 +#define lpfc_mbx_cq_create_set_cq_cnt_MASK 0x00007FFF +#define lpfc_mbx_cq_create_set_cq_cnt_WORD word2 #define lpfc_mbx_cq_create_set_num_cq_SHIFT 0 #define lpfc_mbx_cq_create_set_num_cq_MASK 0x0000FFFF #define lpfc_mbx_cq_create_set_num_cq_WORD word2 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index dc225c33e2..e935ac6af4 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2627,33 +2627,27 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_BMID: - m = (typeof(m)){"LP1150", "PCI-X2", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LP1150", "PCI-X2", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_BSMB: m = (typeof(m)){"LP111", "PCI-X2", "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZEPHYR: - m = (typeof(m)){"LPe11000", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZEPHYR_SCSP: - m = (typeof(m)){"LPe11000", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZEPHYR_DCSP: - m = (typeof(m)){"LP2105", "PCIe", - "Obsolete, Unsupported FCoE Adapter"}; + m = (typeof(m)){"LP2105", "PCIe", "FCoE Adapter"}; GE = 1; break; case PCI_DEVICE_ID_ZMID: - m = (typeof(m)){"LPe1150", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LPe1150", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_ZSMB: - m = (typeof(m)){"LPe111", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LPe111", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LP101: m = (typeof(m)){"LP101", "PCI-X", @@ -2672,28 +2666,22 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT: - m = (typeof(m)){"LPe12000", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LPe12000", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_MID: - m = (typeof(m)){"LPe1250", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LPe1250", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_SMB: - m = (typeof(m)){"LPe121", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LPe121", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_DCSP: - m = (typeof(m)){"LPe12002-SP", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LPe12002-SP", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_SCSP: - m = (typeof(m)){"LPe12000-SP", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LPe12000-SP", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_SAT_S: - m = (typeof(m)){"LPe12000-S", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LPe12000-S", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_PROTEUS_VF: m = (typeof(m)){"LPev12000", "PCIe IOV", @@ -2709,25 +2697,22 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) break; case PCI_DEVICE_ID_TIGERSHARK: oneConnect = 1; - m = (typeof(m)){"OCe10100", "PCIe", - "Obsolete, Unsupported FCoE Adapter"}; + m = (typeof(m)){"OCe10100", "PCIe", "FCoE"}; break; case PCI_DEVICE_ID_TOMCAT: oneConnect = 1; - m = (typeof(m)){"OCe11100", "PCIe", - "Obsolete, Unsupported FCoE Adapter"}; + m = (typeof(m)){"OCe11100", "PCIe", "FCoE"}; break; case PCI_DEVICE_ID_FALCON: m = (typeof(m)){"LPSe12002-ML1-E", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + "EmulexSecure Fibre"}; break; case PCI_DEVICE_ID_BALIUS: m = (typeof(m)){"LPVe12002", "PCIe Shared I/O", "Obsolete, Unsupported Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LANCER_FC: - m = (typeof(m)){"LPe16000", "PCIe", - "Obsolete, Unsupported Fibre Channel Adapter"}; + m = (typeof(m)){"LPe16000", "PCIe", "Fibre Channel Adapter"}; break; case PCI_DEVICE_ID_LANCER_FC_VF: m = (typeof(m)){"LPe16000", "PCIe", @@ -2735,13 +2720,12 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) break; case PCI_DEVICE_ID_LANCER_FCOE: oneConnect = 1; - m = (typeof(m)){"OCe15100", "PCIe", - "Obsolete, Unsupported FCoE Adapter"}; + m = (typeof(m)){"OCe15100", "PCIe", "FCoE"}; break; case PCI_DEVICE_ID_LANCER_FCOE_VF: oneConnect = 1; m = (typeof(m)){"OCe15100", "PCIe", - "Obsolete, Unsupported FCoE Adapter"}; + "Obsolete, Unsupported FCoE"}; break; case PCI_DEVICE_ID_LANCER_G6_FC: m = (typeof(m)){"LPe32000", "PCIe", "Fibre Channel Adapter"}; @@ -2755,8 +2739,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) case PCI_DEVICE_ID_SKYHAWK: case PCI_DEVICE_ID_SKYHAWK_VF: oneConnect = 1; - m = (typeof(m)){"OCe14000", "PCIe", - "Obsolete, Unsupported FCoE Adapter"}; + m = (typeof(m)){"OCe14000", "PCIe", "FCoE"}; break; default: m = (typeof(m)){"Unknown", "", ""}; @@ -3057,6 +3040,19 @@ lpfc_cleanup(struct lpfc_vport *vport) lpfc_vmid_vport_cleanup(vport); list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (vport->port_type != LPFC_PHYSICAL_PORT && + ndlp->nlp_DID == Fabric_DID) { + /* Just free up ndlp with Fabric_DID for vports */ + lpfc_nlp_put(ndlp); + continue; + } + + if (ndlp->nlp_DID == Fabric_Cntl_DID && + ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + lpfc_nlp_put(ndlp); + continue; + } + /* Fabric Ports not in UNMAPPED state are cleaned up in the * DEVICE_RM event. */ @@ -7921,6 +7917,8 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) int longs; int extra; uint64_t wwn; + u32 if_type; + u32 if_fam; phba->sli4_hba.num_present_cpu = lpfc_present_cpu; phba->sli4_hba.num_possible_cpu = cpumask_last(cpu_possible_mask) + 1; @@ -8181,11 +8179,28 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) */ rc = lpfc_get_sli4_parameters(phba, mboxq); if (rc) { - lpfc_log_msg(phba, KERN_WARNING, LOG_INIT, - "2999 Could not get SLI4 parameters\n"); - rc = -EIO; - mempool_free(mboxq, phba->mbox_mem_pool); - goto out_free_bsmbx; + if_type = bf_get(lpfc_sli_intf_if_type, + &phba->sli4_hba.sli_intf); + if_fam = bf_get(lpfc_sli_intf_sli_family, + &phba->sli4_hba.sli_intf); + if (phba->sli4_hba.extents_in_use && + phba->sli4_hba.rpi_hdrs_in_use) { + lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, + "2999 Unsupported SLI4 Parameters " + "Extents and RPI headers enabled.\n"); + if (if_type == LPFC_SLI_INTF_IF_TYPE_0 && + if_fam == LPFC_SLI_INTF_FAMILY_BE2) { + mempool_free(mboxq, phba->mbox_mem_pool); + rc = -EIO; + goto out_free_bsmbx; + } + } + if (!(if_type == LPFC_SLI_INTF_IF_TYPE_0 && + if_fam == LPFC_SLI_INTF_FAMILY_BE2)) { + mempool_free(mboxq, phba->mbox_mem_pool); + rc = -EIO; + goto out_free_bsmbx; + } } /* @@ -8286,7 +8301,10 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->cfg_total_seg_cnt, phba->cfg_scsi_seg_cnt, phba->cfg_nvme_seg_cnt); - i = min(phba->cfg_sg_dma_buf_size, SLI4_PAGE_SIZE); + if (phba->cfg_sg_dma_buf_size < SLI4_PAGE_SIZE) + i = phba->cfg_sg_dma_buf_size; + else + i = SLI4_PAGE_SIZE; phba->lpfc_sg_dma_buf_pool = dma_pool_create("lpfc_sg_dma_buf_pool", @@ -9072,9 +9090,9 @@ lpfc_setup_fdmi_mask(struct lpfc_vport *vport) vport->fdmi_port_mask = LPFC_FDMI2_PORT_ATTR; } - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "6077 Setup FDMI mask: hba x%x port x%x\n", - vport->fdmi_hba_mask, vport->fdmi_port_mask); + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, + "6077 Setup FDMI mask: hba x%x port x%x\n", + vport->fdmi_hba_mask, vport->fdmi_port_mask); } /** diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 9e785bbf67..5aa21c683a 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -326,14 +326,8 @@ lpfc_defer_plogi_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *login_mbox) /* Now that REG_RPI completed successfully, * we can now proceed with sending the PLOGI ACC. */ - if (test_bit(FC_PT2PT, &ndlp->vport->fc_flag)) { - rc = lpfc_els_rsp_acc(login_mbox->vport, ELS_CMD_PLOGI, - save_iocb, ndlp, login_mbox); - } else { - rc = lpfc_els_rsp_acc(login_mbox->vport, ELS_CMD_PLOGI, - save_iocb, ndlp, NULL); - } - + rc = lpfc_els_rsp_acc(login_mbox->vport, ELS_CMD_PLOGI, + save_iocb, ndlp, NULL); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "4576 PLOGI ACC fails pt2pt discovery: " @@ -341,16 +335,9 @@ lpfc_defer_plogi_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *login_mbox) } } - /* If this is a fabric topology, complete the reg_rpi and prli now. - * For Pt2Pt, the reg_rpi and PRLI are deferred until after the LS_ACC - * completes. This ensures, in Pt2Pt, that the PLOGI LS_ACC is sent - * before the PRLI. - */ - if (!test_bit(FC_PT2PT, &ndlp->vport->fc_flag)) { - /* Now process the REG_RPI cmpl */ - lpfc_mbx_cmpl_reg_login(phba, login_mbox); - clear_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag); - } + /* Now process the REG_RPI cmpl */ + lpfc_mbx_cmpl_reg_login(phba, login_mbox); + clear_bit(NLP_ACC_REGLOGIN, &ndlp->nlp_flag); kfree(save_iocb); } @@ -432,6 +419,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_class_sup |= FC_COS_CLASS2; if (sp->cls3.classValid) ndlp->nlp_class_sup |= FC_COS_CLASS3; + if (sp->cls4.classValid) + ndlp->nlp_class_sup |= FC_COS_CLASS4; ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; /* if already logged in, do implicit logout */ @@ -450,7 +439,18 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ if (!(ndlp->nlp_type & NLP_FABRIC) && !(phba->nvmet_support)) { - break; + /* Clear ndlp info, since follow up PRLI may have + * updated ndlp information + */ + ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); + ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); + ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; + ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; + clear_bit(NLP_FIRSTBURST, &ndlp->nlp_flag); + + lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, + ndlp, NULL); + return 1; } if (nlp_portwwn != 0 && nlp_portwwn != wwn_to_u64(sp->portName.u.wwn)) @@ -472,9 +472,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); break; } - /* Clear ndlp info, since follow up processes may have - * updated ndlp information - */ + ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR); ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; @@ -1415,6 +1413,8 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, ndlp->nlp_class_sup |= FC_COS_CLASS2; if (sp->cls3.classValid) ndlp->nlp_class_sup |= FC_COS_CLASS3; + if (sp->cls4.classValid) + ndlp->nlp_class_sup |= FC_COS_CLASS4; ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 47818cf5b2..d539ee15a8 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -1234,8 +1234,12 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, if ((phba->cfg_nvme_enable_fb) && test_bit(NLP_FIRSTBURST, &pnode->nlp_flag)) { req_len = lpfc_ncmd->nvmeCmd->payload_length; - wqe->fcp_iwrite.initial_xfer_len = min(req_len, - pnode->nvme_fb_size); + if (req_len < pnode->nvme_fb_size) + wqe->fcp_iwrite.initial_xfer_len = + req_len; + else + wqe->fcp_iwrite.initial_xfer_len = + pnode->nvme_fb_size; } else { wqe->fcp_iwrite.initial_xfer_len = 0; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 786cde16c7..15395e3493 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -390,10 +390,6 @@ lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport) if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_FCP)) return; - /* may be called before queues established if hba_setup fails */ - if (!phba->sli4_hba.hdwq) - return; - spin_lock_irqsave(&phba->hbalock, iflag); for (idx = 0; idx < phba->cfg_hdw_queue; idx++) { qp = &phba->sli4_hba.hdwq[idx]; @@ -536,8 +532,7 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, psb = container_of(iocbq, struct lpfc_io_buf, cur_iocbq); psb->flags &= ~LPFC_SBUF_XBUSY; spin_unlock_irqrestore(&phba->hbalock, iflag); - if (test_bit(HBA_SETUP, &phba->hba_flag) && - !list_empty(&pring->txq)) + if (!list_empty(&pring->txq)) lpfc_worker_wake_up(phba); return; } @@ -5943,7 +5938,7 @@ lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct fc_rport *rport) /** * lpfc_reset_flush_io_context - * @vport: The virtual port (scsi_host) for the flush context - * @tgt_id: If aborting by Target context - specifies the target id + * @tgt_id: If aborting by Target contect - specifies the target id * @lun_id: If aborting by Lun context - specifies the lun id * @context: specifies the context level to flush at. * @@ -6117,14 +6112,8 @@ lpfc_target_reset_handler(struct scsi_cmnd *cmnd) pnode->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; spin_unlock_irqrestore(&pnode->lock, flags); } - status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, - LPFC_CTX_TGT); - if (status != SUCCESS) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0726 Target Reset flush status x%x\n", - status); - return status; - } + lpfc_reset_flush_io_context(vport, tgt_id, lun_id, + LPFC_CTX_TGT); return FAST_IO_FAIL; } @@ -6217,7 +6206,7 @@ lpfc_host_reset_handler(struct scsi_cmnd *cmnd) int rc, ret = SUCCESS; lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "3172 SCSI layer issued Host Reset\n"); + "3172 SCSI layer issued Host Reset Data:\n"); lpfc_offline_prep(phba, LPFC_MBX_WAIT); lpfc_offline(phba); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 79688d3e83..22f5326572 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -27,8 +27,6 @@ #include #include #include -#include -#include #include #include @@ -5172,6 +5170,7 @@ lpfc_sli4_brdreset(struct lpfc_hba *phba) phba->link_events = 0; phba->pport->fc_myDID = 0; phba->pport->fc_prevDID = 0; + clear_bit(HBA_SETUP, &phba->hba_flag); spin_lock_irq(&phba->hbalock); psli->sli_flag &= ~(LPFC_PROCESS_LA); @@ -5288,7 +5287,6 @@ lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) "0296 Restart HBA Data: x%x x%x\n", phba->pport->port_state, psli->sli_flag); - clear_bit(HBA_SETUP, &phba->hba_flag); lpfc_sli4_queue_unset(phba); rc = lpfc_sli4_brdreset(phba); @@ -8451,70 +8449,6 @@ lpfc_set_host_tm(struct lpfc_hba *phba) return rc; } -/** - * lpfc_get_platform_uuid - Attempts to extract a platform uuid - * @phba: pointer to lpfc hba data structure. - * - * This routine attempts to first read SMBIOS DMI data for the System - * Information structure offset 08h called System UUID. Else, no platform - * UUID will be advertised. - **/ -static void -lpfc_get_platform_uuid(struct lpfc_hba *phba) -{ - int rc; - const char *uuid; - char pni[17] = {0}; /* 16 characters + '\0' */ - bool is_ff = true, is_00 = true; - u8 i; - - /* First attempt SMBIOS DMI */ - uuid = dmi_get_system_info(DMI_PRODUCT_UUID); - if (uuid) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2088 SMBIOS UUID %s\n", - uuid); - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2099 Could not extract UUID\n"); - } - - if (uuid && uuid_is_valid(uuid)) { - /* Generate PNI from UUID format. - * - * 1.) Extract lower 64 bits from UUID format. - * 2.) Set 3h for NAA Locally Assigned Name Identifier format. - * - * e.g. xxxxxxxx-xxxx-xxxx-yyyy-yyyyyyyyyyyy - * - * extract the yyyy-yyyyyyyyyyyy portion - * final PNI 3yyyyyyyyyyyyyyy - */ - scnprintf(pni, sizeof(pni), "3%c%c%c%s", - uuid[20], uuid[21], uuid[22], &uuid[24]); - - /* Sanitize the converted PNI */ - for (i = 1; i < 16 && (is_ff || is_00); i++) { - if (pni[i] != '0') - is_00 = false; - if (pni[i] != 'f' && pni[i] != 'F') - is_ff = false; - } - - /* Convert from char* to unsigned long */ - rc = kstrtoul(pni, 16, &phba->pni); - if (!rc && !is_ff && !is_00) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2100 PNI 0x%016lx\n", phba->pni); - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2101 PNI %s generation status %d\n", - pni, rc); - phba->pni = 0; - } - } -} - /** * lpfc_sli4_hba_setup - SLI4 device initialization PCI function * @phba: Pointer to HBA context object. @@ -8598,10 +8532,6 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) clear_bit(HBA_FCOE_MODE, &phba->hba_flag); } - /* Obtain platform UUID, only for SLI4 FC adapters */ - if (!test_bit(HBA_FCOE_MODE, &phba->hba_flag)) - lpfc_get_platform_uuid(phba); - if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) == LPFC_DCBX_CEE_MODE) set_bit(HBA_FIP_SUPPORT, &phba->hba_flag); @@ -8893,7 +8823,7 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) if (unlikely(rc)) { lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0381 Error %d during queue setup.\n", rc); - goto out_destroy_queue; + goto out_stop_timers; } /* Initialize the driver internal SLI layer lists. */ lpfc_sli4_setup(phba); @@ -9176,6 +9106,7 @@ out_free_iocblist: lpfc_free_iocb_list(phba); out_destroy_queue: lpfc_sli4_queue_destroy(phba); +out_stop_timers: lpfc_stop_hba_timers(phba); out_free_mbox: mempool_free(mboxq, phba->mbox_mem_pool); @@ -12515,11 +12446,19 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, } /* - * Always abort the outstanding WQE and set the IA bit correctly - * for the context. This is necessary for correctly removing - * outstanding ndlp reference counts when the CQE completes with - * the XB bit set. + * If we're unloading, don't abort iocb on the ELS ring, but change + * the callback so that nothing happens when it finishes. */ + if (test_bit(FC_UNLOADING, &vport->load_flag) && + pring->ringno == LPFC_ELS_RING) { + if (cmdiocb->cmd_flag & LPFC_IO_FABRIC) + cmdiocb->fabric_cmd_cmpl = lpfc_ignore_els_cmpl; + else + cmdiocb->cmd_cmpl = lpfc_ignore_els_cmpl; + return retval; + } + + /* issue ABTS for this IOCB based on iotag */ abtsiocbp = __lpfc_sli_get_iocbq(phba); if (abtsiocbp == NULL) return IOCB_NORESOURCE; @@ -16547,10 +16486,10 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, case 4096: if (phba->sli4_hba.pc_sli4_params.cqv == LPFC_Q_CREATE_VERSION_2) { - bf_set(lpfc_mbx_cq_create_set_cqe_cnt_lo, + bf_set(lpfc_mbx_cq_create_set_cqe_cnt, &cq_set->u.request, - cq->entry_count); - bf_set(lpfc_mbx_cq_create_set_cqecnt, + cq->entry_count); + bf_set(lpfc_mbx_cq_create_set_cqe_cnt, &cq_set->u.request, LPFC_CQ_CNT_WORD7); break; @@ -16566,15 +16505,15 @@ lpfc_cq_create_set(struct lpfc_hba *phba, struct lpfc_queue **cqp, } fallthrough; /* otherwise default to smallest */ case 256: - bf_set(lpfc_mbx_cq_create_set_cqecnt, + bf_set(lpfc_mbx_cq_create_set_cqe_cnt, &cq_set->u.request, LPFC_CQ_CNT_256); break; case 512: - bf_set(lpfc_mbx_cq_create_set_cqecnt, + bf_set(lpfc_mbx_cq_create_set_cqe_cnt, &cq_set->u.request, LPFC_CQ_CNT_512); break; case 1024: - bf_set(lpfc_mbx_cq_create_set_cqecnt, + bf_set(lpfc_mbx_cq_create_set_cqe_cnt, &cq_set->u.request, LPFC_CQ_CNT_1024); break; } @@ -19937,15 +19876,13 @@ lpfc_sli4_remove_rpis(struct lpfc_hba *phba) } /** - * lpfc_sli4_resume_rpi - Resume traffic relative to an RPI + * lpfc_sli4_resume_rpi - Remove the rpi bitmask region * @ndlp: pointer to lpfc nodelist data structure. * @cmpl: completion call-back. * @iocbq: data to load as mbox ctx_u information * - * Return codes - * 0 - successful - * -ENOMEM - No available memory - * -EIO - The mailbox failed to complete successfully. + * This routine is invoked to remove the memory region that + * provided rpi via a bitmask. **/ int lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp, @@ -19975,6 +19912,7 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp, return -EIO; } + /* Post all rpi memory regions to the port. */ lpfc_resume_rpi(mboxq, ndlp); if (cmpl) { mboxq->mbox_cmpl = cmpl; @@ -21444,7 +21382,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, struct lpfc_sglq *sglq; struct lpfc_sli_ring *pring; unsigned long iflags; - int ret = 0; + uint32_t ret = 0; /* NVME_LS and NVME_LS ABTS requests. */ if (pwqe->cmd_flag & LPFC_IO_NVME_LS) { diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index fd6dab1578..9be3da91c9 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2024 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2009-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -575,10 +575,8 @@ struct lpfc_pc_sli4_params { #define LPFC_CQ_4K_PAGE_SZ 0x1 #define LPFC_CQ_16K_PAGE_SZ 0x4 -#define LPFC_CQ_32K_PAGE_SZ 0x8 #define LPFC_WQ_4K_PAGE_SZ 0x1 #define LPFC_WQ_16K_PAGE_SZ 0x4 -#define LPFC_WQ_32K_PAGE_SZ 0x8 struct lpfc_iov { uint32_t pf_number; diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index f3dada5bf7..749688aa8a 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.4.0.12" +#define LPFC_DRIVER_VERSION "14.4.0.9" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 8653839ee7..3d70cc5175 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -666,7 +666,7 @@ lpfc_vport_delete(struct fc_vport *fc_vport) * Take early refcount for outstanding I/O requests we schedule during * delete processing for unreg_vpi. Always keep this before * scsi_remove_host() as we can no longer obtain a reference through - * scsi_host_get() after scsi_remove_host as shost is set to SHOST_DEL. + * scsi_host_get() after scsi_host_remove as shost is set to SHOST_DEL. */ if (!scsi_host_get(shost)) return VPORT_INVAL; diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 8ee2e337c9..6ecf3da765 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -1292,7 +1292,7 @@ void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp) a.reason = FCNVME_RJT_RC_LOGIC; a.explanation = FCNVME_RJT_EXP_NONE; xmt_reject = true; - kfree(item); + qla24xx_free_purex_item(item); goto out; } diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index c66cfdb5eb..9b3a964edc 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1131,6 +1131,26 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request, kfree(payload); } +/* + * The current SCSI handling on the host side does not correctly handle: + * INQUIRY with page code 0x80, MODE_SENSE / MODE_SENSE_10 with cmd[2] == 0x1c, + * and (for FC) MAINTENANCE_IN / PERSISTENT_RESERVE_IN passthrough. + */ +static bool storvsc_host_mishandles_cmd(u8 opcode, struct hv_device *device) +{ + switch (opcode) { + case INQUIRY: + case MODE_SENSE: + case MODE_SENSE_10: + return true; + case MAINTENANCE_IN: + case PERSISTENT_RESERVE_IN: + return hv_dev_is_fc(device); + default: + return false; + } +} + static void storvsc_on_io_completion(struct storvsc_device *stor_device, struct vstor_packet *vstor_packet, struct storvsc_cmd_request *request) @@ -1141,22 +1161,12 @@ static void storvsc_on_io_completion(struct storvsc_device *stor_device, stor_pkt = &request->vstor_packet; /* - * The current SCSI handling on the host side does - * not correctly handle: - * INQUIRY command with page code parameter set to 0x80 - * MODE_SENSE and MODE_SENSE_10 command with cmd[2] == 0x1c - * MAINTENANCE_IN is not supported by HyperV FC passthrough - * * Setup srb and scsi status so this won't be fatal. * We do this so we can distinguish truly fatal failues * (srb status == 0x4) and off-line the device in that case. */ - if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || - (stor_pkt->vm_srb.cdb[0] == MODE_SENSE) || - (stor_pkt->vm_srb.cdb[0] == MODE_SENSE_10) || - (stor_pkt->vm_srb.cdb[0] == MAINTENANCE_IN && - hv_dev_is_fc(device))) { + if (storvsc_host_mishandles_cmd(stor_pkt->vm_srb.cdb[0], device)) { vstor_packet->vm_srb.scsi_status = 0; vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; } diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c index a2b2da1255..ba9e7c616e 100644 --- a/drivers/usb/usbip/usbip_common.c +++ b/drivers/usb/usbip/usbip_common.c @@ -470,6 +470,18 @@ static void usbip_pack_ret_submit(struct usbip_header *pdu, struct urb *urb, urb->status = rpdu->status; urb->actual_length = rpdu->actual_length; urb->start_frame = rpdu->start_frame; + /* + * The number_of_packets field determines the length of + * iso_frame_desc[], which is a flexible array allocated + * at URB creation time. A response must never claim more + * packets than originally submitted; doing so would cause + * an out-of-bounds write in usbip_recv_iso() and + * usbip_pad_iso(). Clamp to zero on violation so both + * functions safely return early. + */ + if (rpdu->number_of_packets < 0 || + rpdu->number_of_packets > urb->number_of_packets) + rpdu->number_of_packets = 0; urb->number_of_packets = rpdu->number_of_packets; urb->error_count = rpdu->error_count; } diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 04423ebe8f..263b9e4855 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -465,7 +465,8 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, }; struct pnfs_layout_segment *lseg, *next; - set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); + if (test_and_set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) + return !list_empty(&lo->plh_segs); clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) pnfs_clear_lseg_state(lseg, lseg_list); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 7b60ffc919..10429b6d8f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -5815,9 +5815,14 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) int len = xdr->buf->len - (op_status_offset + XDR_UNIT); so->so_replay.rp_status = op->status; - so->so_replay.rp_buflen = len; - read_bytes_from_xdr_buf(xdr->buf, op_status_offset + XDR_UNIT, + if (len <= NFSD4_REPLAY_ISIZE) { + so->so_replay.rp_buflen = len; + read_bytes_from_xdr_buf(xdr->buf, + op_status_offset + XDR_UNIT, so->so_replay.rp_buf, len); + } else { + so->so_replay.rp_buflen = 0; + } } status: op->status = nfsd4_map_status(op->status, diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index df345896a7..66fa4b5a38 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -472,11 +472,18 @@ struct nfs4_client_reclaim { struct xdr_netobj cr_princhash; }; -/* A reasonable value for REPLAY_ISIZE was estimated as follows: - * The OPEN response, typically the largest, requires - * 4(status) + 8(stateid) + 20(changeinfo) + 4(rflags) + 8(verifier) + - * 4(deleg. type) + 8(deleg. stateid) + 4(deleg. recall flag) + - * 20(deleg. space limit) + ~32(deleg. ace) = 112 bytes +/* + * REPLAY_ISIZE is sized for an OPEN response with delegation: + * 4(status) + 8(stateid) + 20(changeinfo) + 4(rflags) + + * 8(verifier) + 4(deleg. type) + 8(deleg. stateid) + + * 4(deleg. recall flag) + 20(deleg. space limit) + + * ~32(deleg. ace) = 112 bytes + * + * Some responses can exceed this. A LOCK denial includes the conflicting + * lock owner, which can be up to 1024 bytes (NFS4_OPAQUE_LIMIT). Responses + * larger than REPLAY_ISIZE are not cached in rp_ibuf; only rp_status is + * saved. Enlarging this constant increases the size of every + * nfs4_stateowner. */ #define NFSD4_REPLAY_ISIZE 112 diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 24ceced87c..ec49e7ac9c 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -363,6 +363,25 @@ static const struct inode_operations proc_dir_inode_operations = { .setattr = proc_notify_change, }; +static void pde_set_flags(struct proc_dir_entry *pde) +{ + const struct proc_ops *proc_ops = pde->proc_ops; + + if (!proc_ops) + return; + + if (proc_ops->proc_flags & PROC_ENTRY_PERMANENT) + pde->flags |= PROC_ENTRY_PERMANENT; + if (proc_ops->proc_read_iter) + pde->flags |= PROC_ENTRY_proc_read_iter; +#ifdef CONFIG_COMPAT + if (proc_ops->proc_compat_ioctl) + pde->flags |= PROC_ENTRY_proc_compat_ioctl; +#endif + if (proc_ops->proc_lseek) + pde->flags |= PROC_ENTRY_proc_lseek; +} + /* returns the registered entry, or frees dp and returns NULL on failure */ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, struct proc_dir_entry *dp) @@ -370,6 +389,9 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, if (proc_alloc_inum(&dp->low_ino)) goto out_free_entry; + if (!S_ISDIR(dp->mode)) + pde_set_flags(dp); + write_lock(&proc_subdir_lock); dp->parent = dir; if (pde_subdir_insert(dir, dp) == false) { @@ -558,18 +580,6 @@ struct proc_dir_entry *proc_create_reg(const char *name, umode_t mode, return p; } -static void pde_set_flags(struct proc_dir_entry *pde) -{ - if (pde->proc_ops->proc_flags & PROC_ENTRY_PERMANENT) - pde->flags |= PROC_ENTRY_PERMANENT; - if (pde->proc_ops->proc_read_iter) - pde->flags |= PROC_ENTRY_proc_read_iter; -#ifdef CONFIG_COMPAT - if (pde->proc_ops->proc_compat_ioctl) - pde->flags |= PROC_ENTRY_proc_compat_ioctl; -#endif -} - struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct proc_ops *proc_ops, void *data) @@ -580,7 +590,6 @@ struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, if (!p) return NULL; p->proc_ops = proc_ops; - pde_set_flags(p); return proc_register(parent, p); } EXPORT_SYMBOL(proc_create_data); @@ -631,7 +640,6 @@ struct proc_dir_entry *proc_create_seq_private(const char *name, umode_t mode, p->proc_ops = &proc_seq_ops; p->seq_ops = ops; p->state_size = state_size; - pde_set_flags(p); return proc_register(parent, p); } EXPORT_SYMBOL(proc_create_seq_private); @@ -662,7 +670,6 @@ struct proc_dir_entry *proc_create_single_data(const char *name, umode_t mode, return NULL; p->proc_ops = &proc_single_ops; p->single_show = show; - pde_set_flags(p); return proc_register(parent, p); } EXPORT_SYMBOL(proc_create_single_data); diff --git a/fs/proc/inode.c b/fs/proc/inode.c index f005a3e067..32cf53d701 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -487,7 +487,7 @@ static int proc_reg_open(struct inode *inode, struct file *file) typeof_member(struct proc_ops, proc_release) release; struct pde_opener *pdeo; - if (!pde->proc_ops->proc_lseek) + if (!pde_has_proc_lseek(pde)) file->f_mode &= ~FMODE_LSEEK; if (pde_is_permanent(pde)) { diff --git a/fs/proc/internal.h b/fs/proc/internal.h index a2ff84c996..e85c531ec1 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -93,6 +93,11 @@ static inline bool pde_has_proc_compat_ioctl(const struct proc_dir_entry *pde) #endif } +static inline bool pde_has_proc_lseek(const struct proc_dir_entry *pde) +{ + return pde->flags & PROC_ENTRY_proc_lseek; +} + extern struct kmem_cache *proc_dir_entry_cache; void pde_free(struct proc_dir_entry *pde); diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c index 345d788b1c..2206506c2e 100644 --- a/fs/smb/client/cifsacl.c +++ b/fs/smb/client/cifsacl.c @@ -757,6 +757,77 @@ static void dump_ace(struct smb_ace *pace, char *end_of_acl) } #endif +static int validate_dacl(struct smb_acl *pdacl, char *end_of_acl) +{ + int i, ace_hdr_size, ace_size, min_ace_size; + u16 dacl_size, num_aces; + char *acl_base, *end_of_dacl; + struct smb_ace *pace; + + if (!pdacl) + return 0; + + if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl)) { + cifs_dbg(VFS, "ACL too small to parse DACL\n"); + return -EINVAL; + } + + dacl_size = le16_to_cpu(pdacl->size); + if (dacl_size < sizeof(struct smb_acl) || + end_of_acl < (char *)pdacl + dacl_size) { + cifs_dbg(VFS, "ACL too small to parse DACL\n"); + return -EINVAL; + } + + num_aces = le16_to_cpu(pdacl->num_aces); + if (!num_aces) + return 0; + + ace_hdr_size = offsetof(struct smb_ace, sid) + + offsetof(struct smb_sid, sub_auth); + min_ace_size = ace_hdr_size + sizeof(__le32); + if (num_aces > (dacl_size - sizeof(struct smb_acl)) / min_ace_size) { + cifs_dbg(VFS, "ACL too small to parse DACL\n"); + return -EINVAL; + } + + end_of_dacl = (char *)pdacl + dacl_size; + acl_base = (char *)pdacl; + ace_size = sizeof(struct smb_acl); + + for (i = 0; i < num_aces; ++i) { + if (end_of_dacl - acl_base < ace_size) { + cifs_dbg(VFS, "ACL too small to parse ACE\n"); + return -EINVAL; + } + + pace = (struct smb_ace *)(acl_base + ace_size); + acl_base = (char *)pace; + + if (end_of_dacl - acl_base < ace_hdr_size || + pace->sid.num_subauth == 0 || + pace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) { + cifs_dbg(VFS, "ACL too small to parse ACE\n"); + return -EINVAL; + } + + ace_size = ace_hdr_size + sizeof(__le32) * pace->sid.num_subauth; + if (end_of_dacl - acl_base < ace_size || + le16_to_cpu(pace->size) < ace_size) { + cifs_dbg(VFS, "ACL too small to parse ACE\n"); + return -EINVAL; + } + + ace_size = le16_to_cpu(pace->size); + if (end_of_dacl - acl_base < ace_size) { + cifs_dbg(VFS, "ACL too small to parse ACE\n"); + return -EINVAL; + } + } + + return 0; +} + static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, struct smb_sid *pownersid, struct smb_sid *pgrpsid, struct cifs_fattr *fattr, bool mode_from_special_sid) @@ -776,12 +847,8 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, return; } - /* validate that we do not go past end of acl */ - if (end_of_acl < (char *)pdacl + sizeof(struct smb_acl) || - end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { - cifs_dbg(VFS, "ACL too small to parse DACL\n"); + if (validate_dacl(pdacl, end_of_acl)) return; - } cifs_dbg(NOISY, "DACL revision %d size %d num aces %d\n", le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), @@ -799,38 +866,20 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, if (num_aces > 0) { umode_t denied_mode = 0; - if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) / - (offsetof(struct smb_ace, sid) + - offsetof(struct smb_sid, sub_auth) + sizeof(__le16))) - return; - ppace = kmalloc_array(num_aces, sizeof(struct smb_ace *), GFP_KERNEL); if (!ppace) return; for (i = 0; i < num_aces; ++i) { - if (end_of_acl - acl_base < acl_size) - break; - ppace[i] = (struct smb_ace *) (acl_base + acl_size); - acl_base = (char *)ppace[i]; - acl_size = offsetof(struct smb_ace, sid) + - offsetof(struct smb_sid, sub_auth); - - if (end_of_acl - acl_base < acl_size || - ppace[i]->sid.num_subauth == 0 || - ppace[i]->sid.num_subauth > SID_MAX_SUB_AUTHORITIES || - (end_of_acl - acl_base < - acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth) || - (le16_to_cpu(ppace[i]->size) < - acl_size + sizeof(__le32) * ppace[i]->sid.num_subauth)) - break; #ifdef CONFIG_CIFS_DEBUG2 - dump_ace(ppace[i], end_of_acl); + dump_ace(ppace[i], + (char *)pdacl + le16_to_cpu(pdacl->size)); #endif if (mode_from_special_sid && + ppace[i]->sid.num_subauth >= 3 && (compare_sids(&(ppace[i]->sid), &sid_unix_NFS_mode) == 0)) { /* @@ -870,6 +919,7 @@ static void parse_dacl(struct smb_acl *pdacl, char *end_of_acl, (void *)ppace[i], sizeof(struct smb_ace)); */ + acl_base = (char *)ppace[i]; acl_size = le16_to_cpu(ppace[i]->size); } @@ -1214,6 +1264,17 @@ static int parse_sid(struct smb_sid *psid, char *end_of_acl) return 0; } +static bool dacl_offset_valid(unsigned int acl_len, __u32 dacloffset) +{ + if (acl_len < sizeof(struct smb_acl)) + return false; + + if (dacloffset < sizeof(struct smb_ntsd)) + return false; + + return dacloffset <= acl_len - sizeof(struct smb_acl); +} + /* Convert CIFS ACL to POSIX form */ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, @@ -1234,7 +1295,6 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, group_sid_ptr = (struct smb_sid *)((char *)pntsd + le32_to_cpu(pntsd->gsidoffset)); dacloffset = le32_to_cpu(pntsd->dacloffset); - dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n", pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), le32_to_cpu(pntsd->gsidoffset), @@ -1265,11 +1325,18 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, return rc; } - if (dacloffset) + if (dacloffset) { + if (!dacl_offset_valid(acl_len, dacloffset)) { + cifs_dbg(VFS, "Server returned illegal DACL offset\n"); + return -EINVAL; + } + + dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr, fattr, get_mode_from_special_sid); - else + } else { cifs_dbg(FYI, "no ACL\n"); /* BB grant all or default perms? */ + } return rc; } @@ -1292,11 +1359,15 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd, dacloffset = le32_to_cpu(pntsd->dacloffset); if (dacloffset) { - dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); - if (end_of_acl < (char *)dacl_ptr + le16_to_cpu(dacl_ptr->size)) { - cifs_dbg(VFS, "Server returned illegal ACL size\n"); + if (!dacl_offset_valid(secdesclen, dacloffset)) { + cifs_dbg(VFS, "Server returned illegal DACL offset\n"); return -EINVAL; } + + dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); + rc = validate_dacl(dacl_ptr, end_of_acl); + if (rc) + return rc; } owner_sid_ptr = (struct smb_sid *)((char *)pntsd + @@ -1668,7 +1739,19 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2); dacloffset = le32_to_cpu(pntsd->dacloffset); if (dacloffset) { + if (!dacl_offset_valid(secdesclen, dacloffset)) { + cifs_dbg(VFS, "Server returned illegal DACL offset\n"); + rc = -EINVAL; + goto id_mode_to_cifs_acl_exit; + } + dacl_ptr = (struct smb_acl *)((char *)pntsd + dacloffset); + rc = validate_dacl(dacl_ptr, (char *)pntsd + secdesclen); + if (rc) { + kfree(pntsd); + cifs_put_tlink(tlink); + return rc; + } if (mode_from_sid) nsecdesclen += le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace); @@ -1684,7 +1767,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, * descriptor parameters, and security descriptor itself */ nsecdesclen = max_t(u32, nsecdesclen, DEFAULT_SEC_DESC_LEN); - pnntsd = kmalloc(nsecdesclen, GFP_KERNEL); + pnntsd = kzalloc(nsecdesclen, GFP_KERNEL); if (!pnntsd) { kfree(pntsd); cifs_put_tlink(tlink); @@ -1704,6 +1787,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode, rc = ops->set_acl(pnntsd, nsecdesclen, inode, path, aclflag); cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc); } +id_mode_to_cifs_acl_exit: cifs_put_tlink(tlink); kfree(pnntsd); diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 3e06f59ba8..0c2dea2557 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -1954,6 +1954,10 @@ static int match_session(struct cifs_ses *ses, case Kerberos: if (!uid_eq(ctx->cred_uid, ses->cred_uid)) return 0; + if (strncmp(ses->user_name ?: "", + ctx->username ?: "", + CIFS_MAX_USERNAME_LEN)) + return 0; break; case NTLMv2: case RawNTLMSSP: diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index 21338c06e0..296a231e8f 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -2015,7 +2015,7 @@ int smb3_init_fs_context(struct fs_context *fc) ctx->backupuid_specified = false; /* no backup intent for a user */ ctx->backupgid_specified = false; /* no backup intent for a group */ - ctx->retrans = 1; + ctx->retrans = 0; ctx->reparse_type = CIFS_REPARSE_TYPE_DEFAULT; ctx->symlink_type = CIFS_SYMLINK_TYPE_DEFAULT; ctx->nonativesocket = 0; diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c index fddb55605e..bfcac9036c 100644 --- a/fs/xfs/libxfs/xfs_attr_leaf.c +++ b/fs/xfs/libxfs/xfs_attr_leaf.c @@ -1489,6 +1489,7 @@ xfs_attr3_leaf_add_work( struct xfs_attr_leaf_name_local *name_loc; struct xfs_attr_leaf_name_remote *name_rmt; struct xfs_mount *mp; + int old_end, new_end; int tmp; int i; @@ -1581,17 +1582,49 @@ xfs_attr3_leaf_add_work( if (be16_to_cpu(entry->nameidx) < ichdr->firstused) ichdr->firstused = be16_to_cpu(entry->nameidx); - ASSERT(ichdr->firstused >= ichdr->count * sizeof(xfs_attr_leaf_entry_t) - + xfs_attr3_leaf_hdr_size(leaf)); - tmp = (ichdr->count - 1) * sizeof(xfs_attr_leaf_entry_t) - + xfs_attr3_leaf_hdr_size(leaf); + new_end = ichdr->count * sizeof(struct xfs_attr_leaf_entry) + + xfs_attr3_leaf_hdr_size(leaf); + old_end = new_end - sizeof(struct xfs_attr_leaf_entry); + + ASSERT(ichdr->firstused >= new_end); for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { - if (ichdr->freemap[i].base == tmp) { - ichdr->freemap[i].base += sizeof(xfs_attr_leaf_entry_t); + int diff = 0; + + if (ichdr->freemap[i].base == old_end) { + /* + * This freemap entry starts at the old end of the + * leaf entry array, so we need to adjust its base + * upward to accomodate the larger array. + */ + diff = sizeof(struct xfs_attr_leaf_entry); + } else if (ichdr->freemap[i].size > 0 && + ichdr->freemap[i].base < new_end) { + /* + * This freemap entry starts in the space claimed by + * the new leaf entry. Adjust its base upward to + * reflect that. + */ + diff = new_end - ichdr->freemap[i].base; + } + + if (diff) { + ichdr->freemap[i].base += diff; ichdr->freemap[i].size -= - min_t(uint16_t, ichdr->freemap[i].size, - sizeof(xfs_attr_leaf_entry_t)); + min_t(uint16_t, ichdr->freemap[i].size, diff); + } + + /* + * Don't leave zero-length freemaps with nonzero base lying + * around, because we don't want the code in _remove that + * matches on base address to get confused and create + * overlapping freemaps. If we end up with no freemap entries + * then the next _add will compact the leaf block and + * regenerate the freemaps. + */ + if (ichdr->freemap[i].size == 0 && ichdr->freemap[i].base > 0) { + ichdr->freemap[i].base = 0; + ichdr->holes = 1; } } ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index); diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h index db0140a04b..6407b4b613 100644 --- a/include/crypto/scatterwalk.h +++ b/include/crypto/scatterwalk.h @@ -89,35 +89,6 @@ static inline void scatterwalk_pagedone(struct scatter_walk *walk, int out, scatterwalk_start(walk, sg_next(walk->sg)); } -/* - * Flush the dcache of any pages that overlap the region - * [offset, offset + nbytes) relative to base_page. - * - * This should be called only when ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE, to ensure - * that all relevant code (including the call to sg_page() in the caller, if - * applicable) gets fully optimized out when !ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE. - */ -static inline void __scatterwalk_flush_dcache_pages(struct page *base_page, - unsigned int offset, - unsigned int nbytes) -{ - unsigned int num_pages; - unsigned int i; - - base_page += offset / PAGE_SIZE; - offset %= PAGE_SIZE; - - /* - * This is an overflow-safe version of - * num_pages = DIV_ROUND_UP(offset + nbytes, PAGE_SIZE). - */ - num_pages = nbytes / PAGE_SIZE; - num_pages += DIV_ROUND_UP(offset + (nbytes % PAGE_SIZE), PAGE_SIZE); - - for (i = 0; i < num_pages; i++) - flush_dcache_page(base_page + i); -} - static inline void scatterwalk_done(struct scatter_walk *walk, int out, int more) { @@ -130,9 +101,6 @@ void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out); void *scatterwalk_map(struct scatter_walk *walk); -void memcpy_sglist(struct scatterlist *dst, struct scatterlist *src, - unsigned int nbytes); - void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, unsigned int start, unsigned int nbytes, int out); diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 8862389ed5..6961f6e95d 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -306,6 +306,7 @@ int dpll_pin_ref_sync_pair_add(struct dpll_pin *pin, int dpll_device_change_ntf(struct dpll_device *dpll); +int __dpll_pin_change_ntf(struct dpll_pin *pin); int dpll_pin_change_ntf(struct dpll_pin *pin); int register_dpll_notifier(struct notifier_block *nb); diff --git a/include/linux/iommu.h b/include/linux/iommu.h index c30d12e164..cf266c0e4f 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -1615,6 +1615,7 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm); void iommu_sva_unbind_device(struct iommu_sva *handle); u32 iommu_sva_get_pasid(struct iommu_sva *handle); +void iommu_sva_invalidate_kva_range(unsigned long start, unsigned long end); #else static inline struct iommu_sva * iommu_sva_bind_device(struct device *dev, struct mm_struct *mm) @@ -1630,6 +1631,8 @@ static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle) { return IOMMU_PASID_INVALID; } +static inline void iommu_sva_invalidate_kva_range(unsigned long start, + unsigned long end) {} static inline void mm_pasid_init(struct mm_struct *mm) {} static inline bool mm_valid_pasid(struct mm_struct *mm) { return false; } diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 6f7b89b520..b71392fe84 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -27,6 +27,7 @@ enum { PROC_ENTRY_proc_read_iter = 1U << 1, PROC_ENTRY_proc_compat_ioctl = 1U << 2, + PROC_ENTRY_proc_lseek = 1U << 3, }; struct proc_ops { diff --git a/include/linux/sched.h b/include/linux/sched.h index 066ab5f31e..0ecc26623b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -936,6 +936,9 @@ struct task_struct { unsigned sched_migrated:1; unsigned sched_task_hot:1; + /* Save user-dumpable when mm goes away */ + RH_KABI_FILL_HOLE(unsigned user_dumpable:1) + /* Force alignment to the next boundary: */ unsigned :0; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 3f4decc985..574edaeaeb 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -4043,6 +4043,18 @@ skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer) skb_headlen(skb), buffer); } +/* Variant of skb_header_pointer() where @offset is user-controlled + * and potentially negative. + */ +static inline void * __must_check +skb_header_pointer_careful(const struct sk_buff *skb, int offset, + int len, void *buffer) +{ + if (unlikely(offset < 0 && -offset > skb_headroom(skb))) + return NULL; + return skb_header_pointer(skb, offset, len, buffer); +} + /** * skb_needs_linearize - check if we need to linearize a given skb * depending on the given device features. diff --git a/include/net/act_api.h b/include/net/act_api.h index 404df8557f..e7f76ba488 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -68,6 +68,7 @@ struct tc_action { #define TCA_ACT_FLAGS_REPLACE (1U << (TCA_ACT_FLAGS_USER_BITS + 2)) #define TCA_ACT_FLAGS_NO_RTNL (1U << (TCA_ACT_FLAGS_USER_BITS + 3)) #define TCA_ACT_FLAGS_AT_INGRESS (1U << (TCA_ACT_FLAGS_USER_BITS + 4)) +#define TCA_ACT_FLAGS_AT_INGRESS_OR_CLSACT (1U << (TCA_ACT_FLAGS_USER_BITS + 5)) /* Update lastuse only if needed, to avoid dirtying a cache line. * We use a temp variable to avoid fetching jiffies twice. diff --git a/include/net/gro.h b/include/net/gro.h index 5c7beea9ee..17c76446d8 100644 --- a/include/net/gro.h +++ b/include/net/gro.h @@ -419,6 +419,7 @@ static inline __wsum ip6_gro_compute_pseudo(struct sk_buff *skb, int proto) } int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb); +int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb); /* Pass the currently batched GRO_NORMAL SKBs up to the stack. */ static inline void gro_normal_list(struct napi_struct *napi) diff --git a/kernel.sbat b/kernel.sbat index c2c4d2c484..d11bc6926d 100644 --- a/kernel.sbat +++ b/kernel.sbat @@ -1,3 +1,3 @@ sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md -kernel.rhel,1,Red Hat,kernel-core,5.14.0-687.5.4.el9.x86_64,mailto:secalert@redhat.com -kernel.almalinux,1,AlmaLinux,kernel-core,5.14.0-687.5.4.el9.x86_64,mailto:security@almalinux.org +kernel.rhel,1,Red Hat,kernel-core,5.14.0-687.12.1.el9.x86_64,mailto:secalert@redhat.com +kernel.almalinux,1,AlmaLinux,kernel-core,5.14.0-687.12.1.el9.x86_64,mailto:security@almalinux.org diff --git a/kernel/exit.c b/kernel/exit.c index 8782a6b628..aa08b46879 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -534,6 +534,7 @@ static void exit_mm(void) */ smp_mb__after_spinlock(); local_irq_disable(); + current->user_dumpable = (get_dumpable(mm) == SUID_DUMP_USER); current->mm = NULL; membarrier_update_current_mm(NULL); enter_lazy_tlb(mm, current); diff --git a/kernel/ptrace.c b/kernel/ptrace.c index ea8d8a222a..495fde1ff9 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -282,11 +282,24 @@ static bool ptrace_has_cap(struct user_namespace *ns, unsigned int mode) return ns_capable(ns, CAP_SYS_PTRACE); } +static bool task_still_dumpable(struct task_struct *task, unsigned int mode) +{ + struct mm_struct *mm = task->mm; + if (mm) { + if (get_dumpable(mm) == SUID_DUMP_USER) + return true; + return ptrace_has_cap(mm->user_ns, mode); + } + + if (task->user_dumpable) + return true; + return ptrace_has_cap(&init_user_ns, mode); +} + /* Returns 0 on success, -errno on denial. */ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) { const struct cred *cred = current_cred(), *tcred; - struct mm_struct *mm; kuid_t caller_uid; kgid_t caller_gid; @@ -347,14 +360,8 @@ ok: * Pairs with a write barrier in commit_creds(). */ smp_rmb(); - mm = task->mm; - if (mm) { - if ((get_dumpable(mm) != SUID_DUMP_USER) && - !ptrace_has_cap(mm->user_ns, mode)) - return -EPERM; - } else if (!ptrace_has_cap(&init_user_ns, mode)) { + if (!task_still_dumpable(task, mode)) return -EPERM; - } return security_ptrace_access_check(task, mode); } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 4e8615398f..85587366d3 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1152,6 +1152,7 @@ static __always_inline bool free_pages_prepare(struct page *page, page_cpupid_reset_last(page); page->flags &= ~PAGE_FLAGS_CHECK_AT_PREP; + page->private = 0; reset_page_owner(page, order); page_table_check_free(page, order); @@ -2476,7 +2477,7 @@ static void free_unref_page_commit(struct zone *zone, struct per_cpu_pages *pcp, * stops will be drained from vmstat refresh context. */ if (order && order <= PAGE_ALLOC_COSTLY_ORDER) { - free_high = (pcp->free_count >= (batch + pcp->high_min / 2) && + free_high = (pcp->free_count >= batch && (pcp->flags & PCPF_PREV_FREE_HIGH_ORDER) && (!(pcp->flags & PCPF_FREE_HIGH_BATCH) || pcp->count >= batch)); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a758452e49..3756c2a152 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -7163,6 +7163,9 @@ static bool ltk_is_valid(struct mgmt_ltk_info *key) if (key->initiator != 0x00 && key->initiator != 0x01) return false; + if (key->enc_size > sizeof(key->val)) + return false; + switch (key->addr.type) { case BDADDR_LE_PUBLIC: return true; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 5f6fb2c361..ec3ae5fce5 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -298,7 +298,7 @@ static int sco_chan_add(struct sco_conn *conn, struct sock *sk, int err = 0; sco_conn_lock(conn); - if (conn->sk) + if (conn->sk || sco_pi(sk)->conn) err = -EBUSY; else __sco_chan_add(conn, sk, parent); @@ -353,9 +353,20 @@ static int sco_connect(struct sock *sk) lock_sock(sk); + /* Recheck state after reacquiring the socket lock, as another + * thread may have changed it (e.g., closed the socket). + */ + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) { + release_sock(sk); + hci_conn_drop(hcon); + err = -EBADFD; + goto unlock; + } + err = sco_chan_add(conn, sk, NULL); if (err) { release_sock(sk); + hci_conn_drop(hcon); goto unlock; } @@ -399,7 +410,7 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) struct sock *sk; sco_conn_lock(conn); - sk = conn->sk; + sk = sco_sock_hold(conn); sco_conn_unlock(conn); if (!sk) @@ -408,11 +419,15 @@ static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) BT_DBG("sk %p len %u", sk, skb->len); if (sk->sk_state != BT_CONNECTED) - goto drop; + goto drop_put; - if (!sock_queue_rcv_skb(sk, skb)) + if (!sock_queue_rcv_skb(sk, skb)) { + sock_put(sk); return; + } +drop_put: + sock_put(sk); drop: kfree_skb(skb); } @@ -649,13 +664,18 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen addr->sa_family != AF_BLUETOOTH) return -EINVAL; - if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) - return -EBADFD; - - if (sk->sk_type != SOCK_SEQPACKET) - err = -EINVAL; - lock_sock(sk); + + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) { + release_sock(sk); + return -EBADFD; + } + + if (sk->sk_type != SOCK_SEQPACKET) { + release_sock(sk); + return -EINVAL; + } + /* Set destination address and psm */ bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr); release_sock(sk); diff --git a/net/can/raw.c b/net/can/raw.c index e657c9bd8e..ef2033b15c 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -360,6 +360,14 @@ static int raw_notifier(struct notifier_block *nb, unsigned long msg, return NOTIFY_DONE; } +static void raw_sock_destruct(struct sock *sk) +{ + struct raw_sock *ro = raw_sk(sk); + + free_percpu(ro->uniq); + can_sock_destruct(sk); +} + static int raw_init(struct sock *sk) { struct raw_sock *ro = raw_sk(sk); @@ -386,6 +394,8 @@ static int raw_init(struct sock *sk) if (unlikely(!ro->uniq)) return -ENOMEM; + sk->sk_destruct = raw_sock_destruct; + /* set notifier */ spin_lock(&raw_notifier_lock); list_add_tail(&ro->notifier, &raw_notifier_list); @@ -433,7 +443,6 @@ static int raw_release(struct socket *sock) ro->bound = 0; ro->dev = NULL; ro->count = 0; - free_percpu(ro->uniq); sock_orphan(sk); sock->sk = NULL; diff --git a/net/ceph/messenger_v2.c b/net/ceph/messenger_v2.c index b7440a6c76..1b5a0bf36f 100644 --- a/net/ceph/messenger_v2.c +++ b/net/ceph/messenger_v2.c @@ -2412,7 +2412,9 @@ static int process_auth_done(struct ceph_connection *con, void *p, void *end) ceph_decode_64_safe(&p, end, global_id, bad); ceph_decode_32_safe(&p, end, con->v2.con_mode, bad); + ceph_decode_32_safe(&p, end, payload_len, bad); + ceph_decode_need(&p, end, payload_len, bad); dout("%s con %p global_id %llu con_mode %d payload_len %d\n", __func__, con, global_id, con->v2.con_mode, payload_len); diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 9b28b1f2c2..870881b7ea 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -4304,6 +4304,9 @@ static void osd_fault(struct ceph_connection *con) goto out_unlock; } + osd->o_sparse_op_idx = -1; + ceph_init_sparse_read(&osd->o_sparse_read); + if (!reopen_osd(osd)) kick_osd_requests(osd); maybe_request_map(osdc); diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 2950988738..bab6fe4f33 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -806,51 +806,49 @@ static int decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi) ceph_decode_need(p, end, len, bad); pool_end = *p + len; + ceph_decode_need(p, end, 4 + 4 + 4, bad); pi->type = ceph_decode_8(p); pi->size = ceph_decode_8(p); pi->crush_ruleset = ceph_decode_8(p); pi->object_hash = ceph_decode_8(p); - pi->pg_num = ceph_decode_32(p); pi->pgp_num = ceph_decode_32(p); - *p += 4 + 4; /* skip lpg* */ - *p += 4; /* skip last_change */ - *p += 8 + 4; /* skip snap_seq, snap_epoch */ + /* lpg*, last_change, snap_seq, snap_epoch */ + ceph_decode_skip_n(p, end, 8 + 4 + 8 + 4, bad); /* skip snaps */ - num = ceph_decode_32(p); + ceph_decode_32_safe(p, end, num, bad); while (num--) { - *p += 8; /* snapid key */ - *p += 1 + 1; /* versions */ - len = ceph_decode_32(p); - *p += len; + /* snapid key, pool snap (with versions) */ + ceph_decode_skip_n(p, end, 8 + 2, bad); + ceph_decode_skip_string(p, end, bad); } - /* skip removed_snaps */ - num = ceph_decode_32(p); - *p += num * (8 + 8); + /* removed_snaps */ + ceph_decode_skip_map(p, end, 64, 64, bad); + ceph_decode_need(p, end, 8 + 8 + 4, bad); *p += 8; /* skip auid */ pi->flags = ceph_decode_64(p); *p += 4; /* skip crash_replay_interval */ if (ev >= 7) - pi->min_size = ceph_decode_8(p); + ceph_decode_8_safe(p, end, pi->min_size, bad); else pi->min_size = pi->size - pi->size / 2; if (ev >= 8) - *p += 8 + 8; /* skip quota_max_* */ + /* quota_max_* */ + ceph_decode_skip_n(p, end, 8 + 8, bad); if (ev >= 9) { - /* skip tiers */ - num = ceph_decode_32(p); - *p += num * 8; + /* tiers */ + ceph_decode_skip_set(p, end, 64, bad); + ceph_decode_need(p, end, 8 + 1 + 8 + 8, bad); *p += 8; /* skip tier_of */ *p += 1; /* skip cache_mode */ - pi->read_tier = ceph_decode_64(p); pi->write_tier = ceph_decode_64(p); } else { @@ -858,86 +856,76 @@ static int decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi) pi->write_tier = -1; } - if (ev >= 10) { - /* skip properties */ - num = ceph_decode_32(p); - while (num--) { - len = ceph_decode_32(p); - *p += len; /* key */ - len = ceph_decode_32(p); - *p += len; /* val */ - } - } + if (ev >= 10) + /* properties */ + ceph_decode_skip_map(p, end, string, string, bad); if (ev >= 11) { - /* skip hit_set_params */ - *p += 1 + 1; /* versions */ - len = ceph_decode_32(p); - *p += len; + /* hit_set_params (with versions) */ + ceph_decode_skip_n(p, end, 2, bad); + ceph_decode_skip_string(p, end, bad); - *p += 4; /* skip hit_set_period */ - *p += 4; /* skip hit_set_count */ + /* hit_set_period, hit_set_count */ + ceph_decode_skip_n(p, end, 4 + 4, bad); } if (ev >= 12) - *p += 4; /* skip stripe_width */ + /* stripe_width */ + ceph_decode_skip_32(p, end, bad); - if (ev >= 13) { - *p += 8; /* skip target_max_bytes */ - *p += 8; /* skip target_max_objects */ - *p += 4; /* skip cache_target_dirty_ratio_micro */ - *p += 4; /* skip cache_target_full_ratio_micro */ - *p += 4; /* skip cache_min_flush_age */ - *p += 4; /* skip cache_min_evict_age */ - } + if (ev >= 13) + /* target_max_*, cache_target_*, cache_min_* */ + ceph_decode_skip_n(p, end, 16 + 8 + 8, bad); - if (ev >= 14) { - /* skip erasure_code_profile */ - len = ceph_decode_32(p); - *p += len; - } + if (ev >= 14) + /* erasure_code_profile */ + ceph_decode_skip_string(p, end, bad); /* * last_force_op_resend_preluminous, will be overridden if the * map was encoded with RESEND_ON_SPLIT */ if (ev >= 15) - pi->last_force_request_resend = ceph_decode_32(p); + ceph_decode_32_safe(p, end, pi->last_force_request_resend, bad); else pi->last_force_request_resend = 0; if (ev >= 16) - *p += 4; /* skip min_read_recency_for_promote */ + /* min_read_recency_for_promote */ + ceph_decode_skip_32(p, end, bad); if (ev >= 17) - *p += 8; /* skip expected_num_objects */ + /* expected_num_objects */ + ceph_decode_skip_64(p, end, bad); if (ev >= 19) - *p += 4; /* skip cache_target_dirty_high_ratio_micro */ + /* cache_target_dirty_high_ratio_micro */ + ceph_decode_skip_32(p, end, bad); if (ev >= 20) - *p += 4; /* skip min_write_recency_for_promote */ + /* min_write_recency_for_promote */ + ceph_decode_skip_32(p, end, bad); if (ev >= 21) - *p += 1; /* skip use_gmt_hitset */ + /* use_gmt_hitset */ + ceph_decode_skip_8(p, end, bad); if (ev >= 22) - *p += 1; /* skip fast_read */ + /* fast_read */ + ceph_decode_skip_8(p, end, bad); - if (ev >= 23) { - *p += 4; /* skip hit_set_grade_decay_rate */ - *p += 4; /* skip hit_set_search_last_n */ - } + if (ev >= 23) + /* hit_set_grade_decay_rate, hit_set_search_last_n */ + ceph_decode_skip_n(p, end, 4 + 4, bad); if (ev >= 24) { - /* skip opts */ - *p += 1 + 1; /* versions */ - len = ceph_decode_32(p); - *p += len; + /* opts (with versions) */ + ceph_decode_skip_n(p, end, 2, bad); + ceph_decode_skip_string(p, end, bad); } if (ev >= 25) - pi->last_force_request_resend = ceph_decode_32(p); + ceph_decode_32_safe(p, end, pi->last_force_request_resend, bad); /* ignore the rest */ @@ -1987,11 +1975,13 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, bool msgr2, sizeof(u64) + sizeof(u32), e_inval); ceph_decode_copy(p, &fsid, sizeof(fsid)); epoch = ceph_decode_32(p); - BUG_ON(epoch != map->epoch+1); ceph_decode_copy(p, &modified, sizeof(modified)); new_pool_max = ceph_decode_64(p); new_flags = ceph_decode_32(p); + if (epoch != map->epoch + 1) + goto e_inval; + /* full map? */ ceph_decode_32_safe(p, end, len, e_inval); if (len > 0) { diff --git a/net/core/gro.c b/net/core/gro.c index cbfb58bfa3..a1b6faeb2e 100644 --- a/net/core/gro.c +++ b/net/core/gro.c @@ -233,6 +233,35 @@ done: return 0; } +int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb) +{ + if (unlikely(p->len + skb->len >= 65536)) + return -E2BIG; + + if (NAPI_GRO_CB(p)->last == p) + skb_shinfo(p)->frag_list = skb; + else + NAPI_GRO_CB(p)->last->next = skb; + + skb_pull(skb, skb_gro_offset(skb)); + + NAPI_GRO_CB(p)->last = skb; + NAPI_GRO_CB(p)->count++; + p->data_len += skb->len; + + /* sk ownership - if any - completely transferred to the aggregated packet */ + skb->destructor = NULL; + skb->sk = NULL; + p->truesize += skb->truesize; + p->len += skb->len; + + skb_shinfo(p)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; + + NAPI_GRO_CB(skb)->same_flow = 1; + + return 0; +} + static void napi_gro_complete(struct napi_struct *napi, struct sk_buff *skb) { diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e586048914..cf61b887c5 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1005,6 +1005,9 @@ static inline int rtnl_vfinfo_size(const struct net_device *dev, /* IFLA_VF_STATS_TX_DROPPED */ nla_total_size_64bit(sizeof(__u64))); } + if (dev->netdev_ops->ndo_get_vf_guid) + size += num_vfs * 2 * + nla_total_size(sizeof(struct ifla_vf_guid)); return size; } else return 0; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 1206164fb3..799c2e8f77 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -4608,7 +4608,7 @@ normal: skb_put(nskb, hsize), hsize); skb_shinfo(nskb)->flags |= (skb_shinfo(head_skb)->flags | - skb_shinfo(frag_skb)->flags) & + skb_shinfo(frag_skb)->flags) & SKBFL_SHARED_FRAG; if (skb_zerocopy_clone(nskb, frag_skb, GFP_ATOMIC)) @@ -4626,8 +4626,7 @@ normal: frag = skb_shinfo(list_skb)->frags; frag_skb = list_skb; - skb_shinfo(nskb)->flags |= skb_shinfo(frag_skb)->flags & - SKBFL_SHARED_FRAG; + skb_shinfo(nskb)->flags |= skb_shinfo(frag_skb)->flags & SKBFL_SHARED_FRAG; if (!skb_headlen(list_skb)) { BUG_ON(!nfrags); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index a92c54d6d4..a6506a81b8 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1467,6 +1467,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, err = -EMSGSIZE; goto error; } + if (!(flags & MSG_NO_SHARED_FRAGS)) skb_shinfo(skb)->flags |= SKBFL_SHARED_FRAG; diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index dd48b6ed2c..cac03f4b8f 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -465,35 +465,6 @@ out: return segs; } -static int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb) -{ - if (unlikely(p->len + skb->len >= 65536)) - return -E2BIG; - - if (NAPI_GRO_CB(p)->last == p) - skb_shinfo(p)->frag_list = skb; - else - NAPI_GRO_CB(p)->last->next = skb; - - skb_pull(skb, skb_gro_offset(skb)); - - NAPI_GRO_CB(p)->last = skb; - NAPI_GRO_CB(p)->count++; - p->data_len += skb->len; - - /* sk ownership - if any - completely transferred to the aggregated packet */ - skb->destructor = NULL; - skb->sk = NULL; - p->truesize += skb->truesize; - p->len += skb->len; - - skb_shinfo(p)->flags |= skb_shinfo(skb)->flags & SKBFL_SHARED_FRAG; - - NAPI_GRO_CB(skb)->same_flow = 1; - - return 0; -} - #define UDP_GRO_CNT_MAX 64 static struct sk_buff *udp_gro_receive_segment(struct list_head *head, diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c index d704f7ed30..da69a27e83 100644 --- a/net/ipv6/netfilter/ip6t_eui64.c +++ b/net/ipv6/netfilter/ip6t_eui64.c @@ -22,8 +22,7 @@ eui64_mt6(const struct sk_buff *skb, struct xt_action_param *par) unsigned char eui64[8]; if (!(skb_mac_header(skb) >= skb->head && - skb_mac_header(skb) + ETH_HLEN <= skb->data) && - par->fragoff != 0) { + skb_mac_header(skb) + ETH_HLEN <= skb->data)) { par->hotdrop = true; return false; } diff --git a/net/netfilter/nf_conntrack_h323_asn1.c b/net/netfilter/nf_conntrack_h323_asn1.c index 540d97715b..ca103c9461 100644 --- a/net/netfilter/nf_conntrack_h323_asn1.c +++ b/net/netfilter/nf_conntrack_h323_asn1.c @@ -922,6 +922,8 @@ int DecodeQ931(unsigned char *buf, size_t sz, Q931 *q931) break; p++; len--; + if (len <= 0) + break; return DecodeH323_UserInformation(buf, p, len, &q931->UUIE); } diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index b0ac160460..cc44b8f443 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -468,7 +468,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) */ synchronize_rcu(); - nf_ct_expect_iterate_destroy(expect_iter_me, NULL); + nf_ct_expect_iterate_destroy(expect_iter_me, me); nf_ct_iterate_destroy(unhelp, me); } EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister); diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 3193d8cada..9b55eaa221 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -8411,6 +8411,7 @@ static int nf_tables_newflowtable(struct sk_buff *skb, return 0; err_flowtable_hooks: + synchronize_rcu(); nft_trans_destroy(trans); err_flowtable_trans: nft_flowtable_hooks_destroy(&flowtable->hook_list); diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c index 37704ab017..0d32d4841c 100644 --- a/net/netfilter/xt_tcpmss.c +++ b/net/netfilter/xt_tcpmss.c @@ -61,7 +61,7 @@ tcpmss_mt(const struct sk_buff *skb, struct xt_action_param *par) return (mssval >= info->mss_min && mssval <= info->mss_max) ^ info->invert; } - if (op[i] < 2) + if (op[i] < 2 || i == optlen - 1) i++; else i += op[i+1] ? : 1; diff --git a/net/rxrpc/io_thread.c b/net/rxrpc/io_thread.c index c65c258f8d..af78c90e4d 100644 --- a/net/rxrpc/io_thread.c +++ b/net/rxrpc/io_thread.c @@ -225,18 +225,16 @@ static bool rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff **_skb) * decryption. */ if (sp->hdr.securityIndex != 0) { - if (skb_cloned(skb) || skb->data_len) { - struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); - - if (!nskb) { - rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem); - return just_discard; - } + skb = skb_unshare(skb, GFP_ATOMIC); + if (!skb) { + rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare_nomem); + *_skb = NULL; + return just_discard; + } + if (skb != *_skb) { rxrpc_eaten_skb(*_skb, rxrpc_skb_eaten_by_unshare); - consume_skb(*_skb); - *_skb = nskb; - skb = nskb; + *_skb = skb; rxrpc_new_skb(skb, rxrpc_skb_new_unshared); sp = rxrpc_skb(skb); } diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index 5cc8e407e7..8ea37c2c3c 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -603,8 +603,12 @@ again: protocol = skb->protocol; orig_vlan_tag_present = true; } else { - struct vlan_hdr *vlan = (struct vlan_hdr *)skb->data; + struct vlan_hdr *vlan; + if (!pskb_may_pull(skb, VLAN_HLEN)) + goto drop; + + vlan = (struct vlan_hdr *)skb->data; protocol = vlan->h_vlan_encapsulated_proto; skb_pull(skb, VLAN_HLEN); skb_reset_network_header(skb); diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c index 2197eb6256..945b64be4c 100644 --- a/net/sched/act_ct.c +++ b/net/sched/act_ct.c @@ -1358,6 +1358,12 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla, return -EINVAL; } + if (bind && !(flags & TCA_ACT_FLAGS_AT_INGRESS_OR_CLSACT)) { + NL_SET_ERR_MSG_MOD(extack, + "Attaching ct to a non ingress/clsact qdisc is unsupported"); + return -EOPNOTSUPP; + } + err = nla_parse_nested(tb, TCA_CT_MAX, nla, ct_policy, extack); if (err < 0) return err; diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 5399a46f58..0d76e69171 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -2228,6 +2228,11 @@ static bool is_qdisc_ingress(__u32 classid) return (TC_H_MIN(classid) == TC_H_MIN(TC_H_MIN_INGRESS)); } +static bool is_ingress_or_clsact(struct tcf_block *block, struct Qdisc *q) +{ + return tcf_block_shared(block) || (q && !!(q->flags & TCQ_F_INGRESS)); +} + static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n, struct netlink_ext_ack *extack) { @@ -2420,6 +2425,8 @@ replay: flags |= TCA_ACT_FLAGS_NO_RTNL; if (is_qdisc_ingress(parent)) flags |= TCA_ACT_FLAGS_AT_INGRESS; + if (is_ingress_or_clsact(block, q)) + flags |= TCA_ACT_FLAGS_AT_INGRESS_OR_CLSACT; err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh, flags, extack); if (err == 0) { diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 2a1c00048f..58e849c0ac 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -161,10 +161,8 @@ next_knode: int toff = off + key->off + (off2 & key->offmask); __be32 *data, hdata; - if (skb_headroom(skb) + toff > INT_MAX) - goto out; - - data = skb_header_pointer(skb, toff, 4, &hdata); + data = skb_header_pointer_careful(skb, toff, 4, + &hdata); if (!data) goto out; if ((*data ^ key->val) & key->mask) { @@ -214,8 +212,9 @@ check_terminal: if (ht->divisor) { __be32 *data, hdata; - data = skb_header_pointer(skb, off + n->sel.hoff, 4, - &hdata); + data = skb_header_pointer_careful(skb, + off + n->sel.hoff, + 4, &hdata); if (!data) goto out; sel = ht->divisor & u32_hash_fold(*data, &n->sel, @@ -229,7 +228,7 @@ check_terminal: if (n->sel.flags & TC_U32_VAROFFSET) { __be16 *data, hdata; - data = skb_header_pointer(skb, + data = skb_header_pointer_careful(skb, off + n->sel.offoff, 2, &hdata); if (!data) diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c index 48dd8c8890..ef51a9e0f6 100644 --- a/net/sched/sch_cake.c +++ b/net/sched/sch_cake.c @@ -1594,7 +1594,6 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free) qdisc_drop_reason(skb, sch, to_free, SKB_DROP_REASON_QDISC_OVERLIMIT); sch->q.qlen--; - qdisc_tree_reduce_backlog(sch, 1, len); cake_heapify(q, 0); @@ -1740,14 +1739,14 @@ static void cake_reconfigure(struct Qdisc *sch); static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free) { + u32 idx, tin, prev_qlen, prev_backlog, drop_id; struct cake_sched_data *q = qdisc_priv(sch); - int len = qdisc_pkt_len(skb); - int ret; + int len = qdisc_pkt_len(skb), ret; struct sk_buff *ack = NULL; ktime_t now = ktime_get(); struct cake_tin_data *b; struct cake_flow *flow; - u32 idx; + bool same_flow = false; /* choose flow to insert into */ idx = cake_classify(sch, &b, skb, q->flow_mode, &ret); @@ -1757,6 +1756,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, __qdisc_drop(skb, to_free); return ret; } + tin = (u32)(b - q->tins); idx--; flow = &b->flows[idx]; @@ -1819,6 +1819,8 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, consume_skb(skb); } else { /* not splitting */ + int ack_pkt_len = 0; + cobalt_set_enqueue_time(skb, now); get_cobalt_cb(skb)->adjusted_len = cake_overhead(q, skb); flow_queue_add(flow, skb); @@ -1829,13 +1831,13 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (ack) { b->ack_drops++; sch->qstats.drops++; - b->bytes += qdisc_pkt_len(ack); - len -= qdisc_pkt_len(ack); + ack_pkt_len = qdisc_pkt_len(ack); + b->bytes += ack_pkt_len; q->buffer_used += skb->truesize - ack->truesize; if (q->rate_flags & CAKE_FLAG_INGRESS) cake_advance_shaper(q, b, ack, now, true); - qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(ack)); + qdisc_tree_reduce_backlog(sch, 1, ack_pkt_len); consume_skb(ack); } else { sch->q.qlen++; @@ -1844,11 +1846,11 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, /* stats */ b->packets++; - b->bytes += len; - b->backlogs[idx] += len; - b->tin_backlog += len; - sch->qstats.backlog += len; - q->avg_window_bytes += len; + b->bytes += len - ack_pkt_len; + b->backlogs[idx] += len - ack_pkt_len; + b->tin_backlog += len - ack_pkt_len; + sch->qstats.backlog += len - ack_pkt_len; + q->avg_window_bytes += len - ack_pkt_len; } if (q->overflow_timeout) @@ -1923,15 +1925,29 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch, if (q->buffer_used > q->buffer_max_used) q->buffer_max_used = q->buffer_used; - if (q->buffer_used > q->buffer_limit) { - u32 dropped = 0; + if (q->buffer_used <= q->buffer_limit) + return NET_XMIT_SUCCESS; - while (q->buffer_used > q->buffer_limit) { - dropped++; - cake_drop(sch, to_free); - } - b->drop_overlimit += dropped; + prev_qlen = sch->q.qlen; + prev_backlog = sch->qstats.backlog; + + while (q->buffer_used > q->buffer_limit) { + drop_id = cake_drop(sch, to_free); + if ((drop_id >> 16) == tin && + (drop_id & 0xFFFF) == idx) + same_flow = true; } + + prev_qlen -= sch->q.qlen; + prev_backlog -= sch->qstats.backlog; + b->drop_overlimit += prev_qlen; + + if (same_flow) { + qdisc_tree_reduce_backlog(sch, prev_qlen - 1, + prev_backlog - len); + return NET_XMIT_CN; + } + qdisc_tree_reduce_backlog(sch, prev_qlen, prev_backlog); return NET_XMIT_SUCCESS; } diff --git a/redhat/configs/rhel/generic/s390x/CONFIG_SCLP_OFB b/redhat/configs/rhel/generic/s390x/CONFIG_SCLP_OFB index 9861bafbcf..62cca9859d 100644 --- a/redhat/configs/rhel/generic/s390x/CONFIG_SCLP_OFB +++ b/redhat/configs/rhel/generic/s390x/CONFIG_SCLP_OFB @@ -1 +1 @@ -# CONFIG_SCLP_OFB is not set +CONFIG_SCLP_OFB=y diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 4d88e03381..146268b885 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -560,6 +560,15 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name, return 0; } +/* + * ima_reset_appraise_flags - reset ima_iint_cache flags + * + * @digsig: whether to clear/set IMA_DIGSIG flag, tristate values + * 0: clear IMA_DIGSIG + * 1: set IMA_DIGSIG + * -1: don't change IMA_DIGSIG + * + */ static void ima_reset_appraise_flags(struct inode *inode, int digsig) { struct integrity_iint_cache *iint; @@ -572,9 +581,9 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig) return; iint->measured_pcrs = 0; set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags); - if (digsig) + if (digsig == 1) set_bit(IMA_DIGSIG, &iint->atomic_flags); - else + else if (digsig == 0) clear_bit(IMA_DIGSIG, &iint->atomic_flags); } @@ -653,6 +662,8 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG); } else if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0) { digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG); + } else { + digsig = -1; } if (result == 1 || evm_revalidate_status(xattr_name)) { result = validate_hash_algo(dentry, xvalue, xattr_value_len); @@ -668,18 +679,20 @@ int ima_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name, struct posix_acl *kacl) { if (evm_revalidate_status(acl_name)) - ima_reset_appraise_flags(d_backing_inode(dentry), 0); + ima_reset_appraise_flags(d_backing_inode(dentry), -1); return 0; } int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) { - int result; + int result, digsig = -1; result = ima_protect_xattr(dentry, xattr_name, NULL, 0); if (result == 1 || evm_revalidate_status(xattr_name)) { - ima_reset_appraise_flags(d_backing_inode(dentry), 0); + if (!strcmp(xattr_name, XATTR_NAME_IMA)) + digsig = 0; + ima_reset_appraise_flags(d_backing_inode(dentry), digsig); if (result == 1) result = 0; }