RE: [PATCH 1/2] KVM/userspace: Support for assigning PCI devicesto guest

Han, Weidong
2008-07-22T12:45:27Z

Ben-Ami Yassour wrote:
> On Thu, 2008-07-17 at 15:52 +0800, Han, Weidong wrote:
>> Ben-Ami Yassour wrote:
>>> From: Or Sagi <ors@tutis.com>
>>>
>>> From: Nir Peleg <nir@tutis.com>
>>> From: Amit Shah <amit.shah@qumranet.com>
>>> From: Glauber de Oliveira Costa <gcosta@redhat.com>
>>>
>>> We can assign a device from the host machine to a guest. The
>>> original code comes from Neocleus.
>>>
>>> A new command-line option, -pcidevice is added.
>>> For example, to invoke it for an Ethernet device sitting at
>>> PCI bus:dev.fn 04:08.0 with host IRQ 18, use this:
>>>
>>> -pcidevice Ethernet/04:08.0
>>>
>>> The host ethernet driver is to be removed before doing the
>>> passthrough. If not, the device assignment fails but the
>>> guest continues without the assignment.
>>>
>>> If kvm uses the in-kernel irqchip, interrupts are routed to the
>>> guest via the kvm module (accompanied kernel changes are necessary).
>>>
>>> If -no-kvm-irqchip is used, the 'irqhook' module, available
>>> separately, is to be used for interrupt injection into the guest. In
>>> this case, an extra parameter, -<intr-number> is to be appended to
>>> the above-mentioned pcidevice parameter.
>>>
>>> Signed-off-by: Amit Shah <amit.shah@qumranet.com>
>>> ---
>>> +static pt_dev_t *register_real_device(PCIBus *e_bus, const char
>>> *e_dev_name, + int e_devfn,
>> uint8_t r_bus, uint8_t r_dev,
>>> + uint8_t r_func)
>>> +{
>>> + int rc;
>>> + pt_dev_t *pci_dev;
>>> + uint8_t e_device, e_intx;
>>> +
>>> + DEBUG("register_real_device: Registering real physical "
>>> + "device %s (devfn=0x%x)\n", e_dev_name, e_devfn); +
>>> + pci_dev = (pt_dev_t *) pci_register_device(e_bus, e_dev_name,
>>> + sizeof(pt_dev_t),
>> e_devfn,
>>> + pt_pci_read_config,
>>> + pt_pci_write_config);
>>> +
>>> + if (NULL == pci_dev) {
>>> + fprintf(stderr, "register_real_device: Error: Couldn't "
>>> + "register real device %s\n", e_dev_name);
>>> + return NULL;
>>> + }
>>> + if (pt_get_real_device(pci_dev, r_bus, r_dev, r_func)) {
>>> + fprintf(stderr, "register_real_device: Error: Couldn't
get "
>>> + "real device (%s)!\n", e_dev_name);
>>> + return NULL;
>>> + }
>>> +
>>> + /* handle real device's MMIO/PIO BARs */
>>> + if (pt_register_regions(pci_dev->real_device.regions,
>>> + pci_dev->real_device.region_number,
pci_dev))
>>> + return NULL;
>>> +
>>> + /* handle interrupt routing */
>>> + e_device = (pci_dev->dev.devfn >> 3) & 0x1f;
>>> + e_intx = pci_dev->dev.config[0x3d] - 1;
>>> + pci_dev->intpin = e_intx;
>>> + pci_dev->run = 0;
>>> + pci_dev->girq = 0;
>>> + pci_dev->h_busnr = r_bus;
>>> + pci_dev->h_devfn = PCI_DEVFN(r_dev, r_func);
>>> +
>>> +#ifdef KVM_CAP_PCI_PASSTHROUGH
>>> + if (kvm_enabled()) {
>>> + struct kvm_pci_passthrough_dev pci_pt_dev;
>>> +
>>> + memset(&pci_pt_dev, 0, sizeof(pci_pt_dev));
>>> + pci_pt_dev.guest.busnr = pci_bus_num(e_bus);
>>> + pci_pt_dev.guest.devfn = PCI_DEVFN(e_device, r_func);
>>
>> Why combine e_device and r_func? The guest devfn is e_devfn.
> the current assumption is that e_func and r_func are identical.

But you can find they are not the same in guest. Why do we need such
assumption?

Randy (Weidong)

>
>>
>>> + pci_pt_dev.host.busnr = pci_dev->h_busnr;
>>> + pci_pt_dev.host.devfn = pci_dev->h_devfn;
>>> +
>>> + /* We'll set the value of the guest irq as and when
>>> + * the piix config gets updated. See pci_pt_update_irq.
>>> + * The host irq field never gets used anyway
>>> + */
>>> +
>>> + rc = kvm_update_pci_pt_device(kvm_context, &pci_pt_dev);
+ if
>>> (rc < 0) { + fprintf(stderr, "Could not
notify kernel about "
>>> + "passthrough device\n"); +
perror("pt-ioctl");
>>> + return NULL;
>>> + }
>>> + }
>>> +#endif
>>> +
>>> + fprintf(logfile, "Registered host PCI device %02x:%02x.%1x "
>>> + "as guest device %02x:%02x.%1x\n",
>>> + r_bus, r_dev, r_func,
>>> + pci_bus_num(e_bus), e_device, r_func);
>>
>> Second "r_func" should replaced by e_devfn & 0x7. same as above.
>
>>
>> Randy (Weidong)