#include #include #include #ifndef COMPAT typedef long ret_t; #endif ret_t pci_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) { ret_t ret; switch ( cmd ) { case PHYSDEVOP_pci_device_add: { struct physdev_pci_device_add add; struct pci_dev_info pdev_info; nodeid_t node = NUMA_NO_NODE; if ( !is_pci_passthrough_enabled() ) return -EOPNOTSUPP; ret = -EFAULT; if ( copy_from_guest(&add, arg, 1) != 0 ) break; pdev_info.is_extfn = (add.flags & XEN_PCI_DEV_EXTFN); if ( add.flags & XEN_PCI_DEV_VIRTFN ) { pdev_info.is_virtfn = true; pdev_info.physfn.bus = add.physfn.bus; pdev_info.physfn.devfn = add.physfn.devfn; } else pdev_info.is_virtfn = false; #ifdef CONFIG_NUMA if ( add.flags & XEN_PCI_DEV_PXM ) { uint32_t pxm; size_t optarr_off = offsetof(struct physdev_pci_device_add, optarr) / sizeof(add.optarr[0]); if ( copy_from_guest_offset(&pxm, arg, optarr_off, 1) ) break; node = pxm_to_node(pxm); } #endif ret = pci_add_device(add.seg, add.bus, add.devfn, &pdev_info, node); break; } case PHYSDEVOP_pci_device_remove: { struct physdev_pci_device dev; if ( !is_pci_passthrough_enabled() ) return -EOPNOTSUPP; ret = -EFAULT; if ( copy_from_guest(&dev, arg, 1) != 0 ) break; ret = pci_remove_device(dev.seg, dev.bus, dev.devfn); break; } default: ret = -ENOSYS; break; } return ret; } /* * Local variables: * mode: C * c-file-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */