Index: head/sys/x86/include/bus_dma.h =================================================================== --- head/sys/x86/include/bus_dma.h +++ head/sys/x86/include/bus_dma.h @@ -191,5 +191,7 @@ return (tc->impl->map_complete(dmat, map, segs, nsegs, error)); } +bool bus_dma_dmar_set_buswide(device_t dev); + #endif /* !_X86_BUS_DMA_H_ */ Index: head/sys/x86/iommu/busdma_dmar.c =================================================================== --- head/sys/x86/iommu/busdma_dmar.c +++ head/sys/x86/iommu/busdma_dmar.c @@ -289,6 +289,34 @@ return (res); } +bool +bus_dma_dmar_set_buswide(device_t dev) +{ + struct dmar_unit *dmar; + device_t parent; + u_int busno, slot, func; + + parent = device_get_parent(dev); + if (device_get_devclass(parent) != devclass_find("pci")) + return (false); + dmar = dmar_find(dev, bootverbose); + if (dmar == NULL) + return (false); + busno = pci_get_bus(dev); + slot = pci_get_slot(dev); + func = pci_get_function(dev); + if (slot != 0 || func != 0) { + if (bootverbose) { + device_printf(dev, + "dmar%d pci%d:%d:%d requested buswide busdma\n", + dmar->unit, busno, slot, func); + } + return (false); + } + dmar_set_buswide_ctx(dmar, busno); + return (true); +} + static MALLOC_DEFINE(M_DMAR_DMAMAP, "dmar_dmamap", "Intel DMAR DMA Map"); static void dmar_bus_schedule_dmamap(struct dmar_unit *unit, Index: head/sys/x86/iommu/intel_ctx.c =================================================================== --- head/sys/x86/iommu/intel_ctx.c +++ head/sys/x86/iommu/intel_ctx.c @@ -67,8 +67,8 @@ #include #include #include -#include #include +#include #include static MALLOC_DEFINE(M_DMAR_CTX, "dmar_ctx", "Intel DMAR Context"); @@ -141,20 +141,9 @@ } static void -ctx_id_entry_init(struct dmar_ctx *ctx, dmar_ctx_entry_t *ctxp, bool move) +ctx_id_entry_init_one(dmar_ctx_entry_t *ctxp, struct dmar_domain *domain, + vm_page_t ctx_root) { - struct dmar_unit *unit; - struct dmar_domain *domain; - vm_page_t ctx_root; - - domain = ctx->domain; - unit = domain->dmar; - KASSERT(move || (ctxp->ctx1 == 0 && ctxp->ctx2 == 0), - ("dmar%d: initialized ctx entry %d:%d:%d 0x%jx 0x%jx", - unit->unit, pci_get_bus(ctx->ctx_tag.owner), - pci_get_slot(ctx->ctx_tag.owner), - pci_get_function(ctx->ctx_tag.owner), - ctxp->ctx1, ctxp->ctx2)); /* * For update due to move, the store is not atomic. It is * possible that DMAR read upper doubleword, while low @@ -166,17 +155,49 @@ */ dmar_pte_store1(&ctxp->ctx2, DMAR_CTX2_DID(domain->domain) | domain->awlvl); + if (ctx_root == NULL) { + dmar_pte_store1(&ctxp->ctx1, DMAR_CTX1_T_PASS | DMAR_CTX1_P); + } else { + dmar_pte_store1(&ctxp->ctx1, DMAR_CTX1_T_UNTR | + (DMAR_CTX1_ASR_MASK & VM_PAGE_TO_PHYS(ctx_root)) | + DMAR_CTX1_P); + } +} + +static void +ctx_id_entry_init(struct dmar_ctx *ctx, dmar_ctx_entry_t *ctxp, bool move, + int busno) +{ + struct dmar_unit *unit; + struct dmar_domain *domain; + vm_page_t ctx_root; + int i; + + domain = ctx->domain; + unit = domain->dmar; + KASSERT(move || (ctxp->ctx1 == 0 && ctxp->ctx2 == 0), + ("dmar%d: initialized ctx entry %d:%d:%d 0x%jx 0x%jx", + unit->unit, busno, pci_get_slot(ctx->ctx_tag.owner), + pci_get_function(ctx->ctx_tag.owner), + ctxp->ctx1, ctxp->ctx2)); + if ((domain->flags & DMAR_DOMAIN_IDMAP) != 0 && (unit->hw_ecap & DMAR_ECAP_PT) != 0) { KASSERT(domain->pgtbl_obj == NULL, ("ctx %p non-null pgtbl_obj", ctx)); - dmar_pte_store1(&ctxp->ctx1, DMAR_CTX1_T_PASS | DMAR_CTX1_P); + ctx_root = NULL; } else { ctx_root = dmar_pgalloc(domain->pgtbl_obj, 0, DMAR_PGF_NOALLOC); - dmar_pte_store1(&ctxp->ctx1, DMAR_CTX1_T_UNTR | - (DMAR_CTX1_ASR_MASK & VM_PAGE_TO_PHYS(ctx_root)) | - DMAR_CTX1_P); } + + if (dmar_is_buswide_ctx(unit, busno)) { + MPASS(!move); + for (i = 0; i <= PCI_BUSMAX; i++) { + ctx_id_entry_init_one(&ctxp[i], domain, ctx_root); + } + } else { + ctx_id_entry_init_one(ctxp, domain, ctx_root); + } dmar_flush_ctx_to_ram(unit, ctxp); } @@ -444,6 +465,9 @@ enable = false; TD_PREP_PINNED_ASSERT; DMAR_LOCK(dmar); + KASSERT(!dmar_is_buswide_ctx(dmar, bus) || (slot == 0 && func == 0), + ("dmar%d pci%d:%d:%d get_ctx for buswide", dmar->unit, bus, + slot, func)); ctx = dmar_find_ctx_locked(dmar, rid); error = 0; if (ctx == NULL) { @@ -492,7 +516,7 @@ if (LIST_EMPTY(&dmar->domains)) enable = true; LIST_INSERT_HEAD(&dmar->domains, domain, link); - ctx_id_entry_init(ctx, ctxp, false); + ctx_id_entry_init(ctx, ctxp, false, bus); if (dev != NULL) { device_printf(dev, "dmar%d pci%d:%d:%d:%d rid %x domain %d mgaw %d " @@ -597,7 +621,7 @@ dmar_ctx_unlink(ctx); ctx->domain = domain; dmar_ctx_link(ctx); - ctx_id_entry_init(ctx, ctxp, true); + ctx_id_entry_init(ctx, ctxp, true, PCI_BUSMAX + 100); dmar_unmap_pgtbl(sf); error = dmar_flush_for_ctx_entry(dmar, true); /* If flush failed, rolling back would not work as well. */ Index: head/sys/x86/iommu/intel_dmar.h =================================================================== --- head/sys/x86/iommu/intel_dmar.h +++ head/sys/x86/iommu/intel_dmar.h @@ -239,6 +239,15 @@ struct taskqueue *delayed_taskqueue; int dma_enabled; + + /* + * Bitmap of buses for which context must ignore slot:func, + * duplicating the page table pointer into all context table + * entries. This is a client-controlled quirk to support some + * NTBs. + */ + uint32_t buswide_ctxs[(PCI_BUSMAX + 1) / NBBY / sizeof(uint32_t)]; + }; #define DMAR_LOCK(dmar) mtx_lock(&(dmar)->lock) @@ -376,6 +385,9 @@ int dmar_init_irt(struct dmar_unit *unit); void dmar_fini_irt(struct dmar_unit *unit); + +void dmar_set_buswide_ctx(struct dmar_unit *unit, u_int busno); +bool dmar_is_buswide_ctx(struct dmar_unit *unit, u_int busno); #define DMAR_GM_CANWAIT 0x0001 #define DMAR_GM_CANSPLIT 0x0002 Index: head/sys/x86/iommu/intel_drv.c =================================================================== --- head/sys/x86/iommu/intel_drv.c +++ head/sys/x86/iommu/intel_drv.c @@ -69,9 +69,9 @@ #include #include #include -#include #include #include +#include #ifdef DEV_APIC #include "pcib_if.h" @@ -594,6 +594,26 @@ DRIVER_MODULE(dmar, acpi, dmar_driver, dmar_devclass, 0, 0); MODULE_DEPEND(dmar, acpi, 1, 1, 1); + +void +dmar_set_buswide_ctx(struct dmar_unit *unit, u_int busno) +{ + + MPASS(busno <= PCI_BUSMAX); + DMAR_LOCK(unit); + unit->buswide_ctxs[busno / NBBY / sizeof(uint32_t)] |= + 1 << (busno % (NBBY * sizeof(uint32_t))); + DMAR_UNLOCK(unit); +} + +bool +dmar_is_buswide_ctx(struct dmar_unit *unit, u_int busno) +{ + + MPASS(busno <= PCI_BUSMAX); + return ((unit->buswide_ctxs[busno / NBBY / sizeof(uint32_t)] & + (1U << (busno % (NBBY * sizeof(uint32_t))))) != 0); +} static void dmar_print_path(int busno, int depth, const ACPI_DMAR_PCI_PATH *path) Index: head/sys/x86/iommu/intel_gas.c =================================================================== --- head/sys/x86/iommu/intel_gas.c +++ head/sys/x86/iommu/intel_gas.c @@ -67,6 +67,7 @@ #include #include #include +#include #include /* Index: head/sys/x86/iommu/intel_idpgtbl.c =================================================================== --- head/sys/x86/iommu/intel_idpgtbl.c +++ head/sys/x86/iommu/intel_idpgtbl.c @@ -66,6 +66,7 @@ #include #include #include +#include #include static int domain_unmap_buf_locked(struct dmar_domain *domain, Index: head/sys/x86/iommu/intel_intrmap.c =================================================================== --- head/sys/x86/iommu/intel_intrmap.c +++ head/sys/x86/iommu/intel_intrmap.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include Index: head/sys/x86/iommu/intel_qi.c =================================================================== --- head/sys/x86/iommu/intel_qi.c +++ head/sys/x86/iommu/intel_qi.c @@ -58,6 +58,7 @@ #include #include #include +#include #include static bool Index: head/sys/x86/iommu/intel_quirks.c =================================================================== --- head/sys/x86/iommu/intel_quirks.c +++ head/sys/x86/iommu/intel_quirks.c @@ -60,6 +60,7 @@ #include #include #include +#include #include #include Index: head/sys/x86/iommu/intel_utils.c =================================================================== --- head/sys/x86/iommu/intel_utils.c +++ head/sys/x86/iommu/intel_utils.c @@ -66,6 +66,7 @@ #include #include #include +#include #include u_int Index: head/sys/x86/x86/busdma_machdep.c =================================================================== --- head/sys/x86/x86/busdma_machdep.c +++ head/sys/x86/x86/busdma_machdep.c @@ -33,6 +33,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_acpi.h" + #include #include #include @@ -245,3 +247,10 @@ return (tc->impl->tag_destroy(dmat)); } +#ifndef ACPI_DMAR +bool +bus_dma_dmar_set_buswide(device_t dev) +{ + return (false); +} +#endif