From 3819a926c0d8eabceb14559dd3b89326d1b14a6a Mon Sep 17 00:00:00 2001 From: kettenis Date: Mon, 13 May 2024 10:01:53 +0000 Subject: [PATCH] Implement hardware masking for MSI and MSI-X on amd64. Note that masking MSIs can only be done for PCI devices that implement per-vector masking, which a lot of hardware doesn't implement. ok mlarkin@ --- sys/arch/amd64/pci/pci_machdep.c | 86 +++++++++++++++++++++++++++++++- sys/dev/pci/pcireg.h | 5 +- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/sys/arch/amd64/pci/pci_machdep.c b/sys/arch/amd64/pci/pci_machdep.c index 16d2362f410..30257ab7d82 100644 --- a/sys/arch/amd64/pci/pci_machdep.c +++ b/sys/arch/amd64/pci/pci_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pci_machdep.c,v 1.79 2024/02/02 21:13:35 kettenis Exp $ */ +/* $OpenBSD: pci_machdep.c,v 1.80 2024/05/13 10:01:53 kettenis Exp $ */ /* $NetBSD: pci_machdep.c,v 1.3 2003/05/07 21:33:58 fvdl Exp $ */ /*- @@ -349,11 +349,55 @@ struct pic msi_pic = { void msi_hwmask(struct pic *pic, int pin) { + pci_chipset_tag_t pc = NULL; /* XXX */ + pcitag_t tag = PCI_MSI_TAG(pin); + int vec = PCI_MSI_VEC(pin); + pcireg_t reg, mask; + int off; + + if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, ®) == 0) + return; + + /* We can't mask if per-vector masking isn't implemented. */ + if ((reg & PCI_MSI_MC_PVMASK) == 0) + return; + + if (reg & PCI_MSI_MC_C64) { + mask = pci_conf_read(pc, tag, off + PCI_MSI_MASK64); + pci_conf_write(pc, tag, off + PCI_MSI_MASK64, + mask | (1U << vec)); + } else { + mask = pci_conf_read(pc, tag, off + PCI_MSI_MASK32); + pci_conf_write(pc, tag, off + PCI_MSI_MASK32, + mask | (1U << vec)); + } } void msi_hwunmask(struct pic *pic, int pin) { + pci_chipset_tag_t pc = NULL; /* XXX */ + pcitag_t tag = PCI_MSI_TAG(pin); + int vec = PCI_MSI_VEC(pin); + pcireg_t reg, mask; + int off; + + if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &off, ®) == 0) + return; + + /* We can't mask if per-vector masking isn't implemented. */ + if ((reg & PCI_MSI_MC_PVMASK) == 0) + return; + + if (reg & PCI_MSI_MC_C64) { + mask = pci_conf_read(pc, tag, off + PCI_MSI_MASK64); + pci_conf_write(pc, tag, off + PCI_MSI_MASK64, + mask & ~(1U << vec)); + } else { + mask = pci_conf_read(pc, tag, off + PCI_MSI_MASK32); + pci_conf_write(pc, tag, off + PCI_MSI_MASK32, + mask & ~(1U << vec)); + } } void @@ -531,11 +575,51 @@ struct pic msix_pic = { void msix_hwmask(struct pic *pic, int pin) { + pci_chipset_tag_t pc = NULL; /* XXX */ + bus_space_tag_t memt = X86_BUS_SPACE_MEM; /* XXX */ + bus_space_handle_t memh; + pcitag_t tag = PCI_MSI_TAG(pin); + int entry = PCI_MSI_VEC(pin); + pcireg_t reg; + uint32_t ctrl; + + if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, ®) == 0) + return; + + KASSERT(entry <= PCI_MSIX_MC_TBLSZ(reg)); + + if (pci_msix_table_map(pc, tag, memt, &memh)) + panic("%s: cannot map registers", __func__); + + ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(entry)); + bus_space_write_4(memt, memh, PCI_MSIX_VC(entry), + ctrl | PCI_MSIX_VC_MASK); + + pci_msix_table_unmap(pc, tag, memt, memh); } void msix_hwunmask(struct pic *pic, int pin) { + pci_chipset_tag_t pc = NULL; /* XXX */ + bus_space_tag_t memt = X86_BUS_SPACE_MEM; /* XXX */ + bus_space_handle_t memh; + pcitag_t tag = PCI_MSI_TAG(pin); + int entry = PCI_MSI_VEC(pin); + pcireg_t reg; + uint32_t ctrl; + + if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, ®) == 0) + return; + + if (pci_msix_table_map(pc, tag, memt, &memh)) + panic("%s: cannot map registers", __func__); + + ctrl = bus_space_read_4(memt, memh, PCI_MSIX_VC(entry)); + bus_space_write_4(memt, memh, PCI_MSIX_VC(entry), + ctrl & ~PCI_MSIX_VC_MASK); + + pci_msix_table_unmap(pc, tag, memt, memh); } void diff --git a/sys/dev/pci/pcireg.h b/sys/dev/pci/pcireg.h index b839bee9112..1eb8cc950d6 100644 --- a/sys/dev/pci/pcireg.h +++ b/sys/dev/pci/pcireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pcireg.h,v 1.62 2024/01/19 18:38:16 kettenis Exp $ */ +/* $OpenBSD: pcireg.h,v 1.63 2024/05/13 10:01:53 kettenis Exp $ */ /* $NetBSD: pcireg.h,v 1.26 2000/05/10 16:58:42 thorpej Exp $ */ /* @@ -515,6 +515,7 @@ typedef u_int8_t pci_revision_t; * Message Signaled Interrupts; access via capability pointer. */ #define PCI_MSI_MC 0x00 +#define PCI_MSI_MC_PVMASK 0x01000000 #define PCI_MSI_MC_C64 0x00800000 #define PCI_MSI_MC_MME_MASK 0x00700000 #define PCI_MSI_MC_MME_SHIFT 20 @@ -525,6 +526,8 @@ typedef u_int8_t pci_revision_t; #define PCI_MSI_MAU32 0x08 #define PCI_MSI_MD32 0x08 #define PCI_MSI_MD64 0x0c +#define PCI_MSI_MASK32 0x0c +#define PCI_MSI_MASK64 0x10 /* * Power Management Control Status Register; access via capability pointer. -- 2.20.1