void iommu_init(void) { int error, bus, slot, func; vm_paddr_t maxaddr; const char *name; device_t dev; if (vmm_is_intel()) ops = &iommu_ops_intel; else if (vmm_is_amd()) ops = &iommu_ops_amd; else ops = NULL; error = IOMMU_INIT(); if (error) return; iommu_avail = 1; /* * Create a domain for the devices owned by the host */ maxaddr = vmm_mem_maxaddr(); host_domain = IOMMU_CREATE_DOMAIN(maxaddr); if (host_domain == NULL) panic("iommu_init: unable to create a host domain"); /* * Create 1:1 mappings from '0' to 'maxaddr' for devices assigned to * the host */ iommu_create_mapping(host_domain, 0, 0, maxaddr); for (bus = 0; bus <= PCI_BUSMAX; bus++) { for (slot = 0; slot <= PCI_SLOTMAX; slot++) { for (func = 0; func <= PCI_FUNCMAX; func++) { dev = pci_find_dbsf(0, bus, slot, func); if (dev == NULL) continue; /* skip passthrough devices */ name = device_get_name(dev); if (name != NULL && strcmp(name, "ppt") == 0) continue; /* everything else belongs to the host domain */ iommu_add_device(host_domain, bus, slot, func); } } } IOMMU_ENABLE(); }
static void pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev) { struct iommu_table *tbl = phb->p5ioc2.table_group.tables[0]; if (!tbl->it_map) { tbl->it_ops = &pnv_p5ioc2_iommu_ops; iommu_init_table(tbl, phb->hose->node); iommu_register_group(&phb->p5ioc2.table_group, pci_domain_nr(phb->hose->bus), phb->opal_id); INIT_LIST_HEAD_RCU(&tbl->it_group_list); pnv_pci_link_table_and_group(phb->hose->node, 0, tbl, &phb->p5ioc2.table_group); } set_iommu_table_base(&pdev->dev, tbl); iommu_add_device(&pdev->dev); }
int ppt_assign_device(struct vm *vm, int bus, int slot, int func) { struct pptdev *ppt; ppt = ppt_find(bus, slot, func); if (ppt != NULL) { /* * If this device is owned by a different VM then we * cannot change its owner. */ if (ppt->vm != NULL && ppt->vm != vm) return (EBUSY); ppt->vm = vm; iommu_add_device(vm_iommu_domain(vm), bus, slot, func); return (0); } return (ENOENT); }