};
struct dpci_infos {
- struct php_dev php_devs[NR_PCI_DEV];
+ struct php_dev php_devs[NR_PCI_DEVFN];
PCIBus *e_bus;
struct pci_access *pci_access;
}
else
{
- *vslot = AUTO_PHP_SLOT;
+ *vslot = AUTO_PHP_DEVFN;
*opt = token;
}
}
/* Insert a new pass-through device into a specific pci slot.
- * input dom:bus:dev.func@slot, chose free one if slot == AUTO_PHP_SLOT
+ * input dom:bus:dev.func@slot, chose free one if slot == AUTO_PHP_DEVFN
* return -2: requested slot not available
* -1: no free slots
* >=0: the new hotplug slot
*/
-static int __insert_to_pci_slot(int bus, int dev, int func, int slot,
+static int __insert_to_pci_slot(int bus, int dev, int func, int devfn,
char *opt)
{
PCIBus *e_bus = dpci_infos.e_bus;
+ int slot;
- /* preferred virt pci slot */
- if ( slot != AUTO_PHP_SLOT)
+ /* preferred virt pci devfn */
+ if ( devfn != AUTO_PHP_DEVFN )
{
- if ( !test_pci_slot(slot) &&
- !pci_devfn_in_use(e_bus, PCI_DEVFN(slot, 0)) )
+ if ( !test_pci_slot(devfn) && !pci_devfn_in_use(e_bus, devfn) )
goto found;
return -2;
}
- /* slot == 0, pick up a free one */
+ /* pick a free slot */
for ( slot = 0; slot < NR_PCI_DEV; slot++ )
{
- if ( !test_pci_slot(slot) &&
- !pci_devfn_in_use(e_bus, PCI_DEVFN(slot, 0)) )
+ devfn = PCI_DEVFN(slot, 0);
+ if ( !test_pci_slot(devfn) && !pci_devfn_in_use(e_bus, devfn) )
goto found;
}
return -1;
found:
- dpci_infos.php_devs[slot].valid = 1;
- dpci_infos.php_devs[slot].r_bus = bus;
- dpci_infos.php_devs[slot].r_dev = dev;
- dpci_infos.php_devs[slot].r_func = func;
- dpci_infos.php_devs[slot].opt = opt;
- return slot;
+ dpci_infos.php_devs[devfn].valid = 1;
+ dpci_infos.php_devs[devfn].r_bus = bus;
+ dpci_infos.php_devs[devfn].r_dev = dev;
+ dpci_infos.php_devs[devfn].r_func = func;
+ dpci_infos.php_devs[devfn].opt = opt;
+ return devfn;
}
/* Insert a new pass-through device into a specific pci slot.
*/
int test_pci_slot(int slot)
{
- if ( slot < 0 || slot >= NR_PCI_DEV )
+ if ( slot < 0 || slot >= NR_PCI_DEVFN )
return -1;
if ( dpci_infos.php_devs[slot].valid )
}
/* locate the virtual pci slot for this VTd device */
- for ( i = 0; i < NR_PCI_DEV; i++ )
+ for ( i = 0; i < NR_PCI_DEVFN; i++ )
{
if ( pci_slot_match(bus, dev, func, i) )
return i;
/* Register device */
assigned_device = (struct pt_dev *) pci_register_device(e_bus, e_dev_name,
- sizeof(struct pt_dev), PCI_DEVFN(e_slot, 0),
+ sizeof(struct pt_dev), e_slot,
pt_pci_read_config, pt_pci_write_config);
if ( assigned_device == NULL )
{
#include <xen/hvm/ioreq.h>
#include <xen/hvm/params.h>
+#include <pci/header.h>
+
/* PM1a_CNT bits, as defined in the ACPI specification. */
#define SCI_EN (1 << 0)
#define GBL_RLS (1 << 2)
hotplug_slots->plug_slot = 0;
/* power off the slot */
- power_off_php_slot(slot);
+ power_off_php_slot(PCI_DEVFN(slot, 0));
/* signal the CP ACPI hot remove done. */
xenstore_record_dm_state("pci-removed");
}
}
-void acpi_php_del(int slot)
+void acpi_php_del(int devfn)
{
GPEState *s = &gpe_state;
+ int slot, func;
+
+ slot = PCI_SLOT(devfn);
+ func = PCI_FUNC(devfn);
- if ( test_pci_slot(slot) < 0 ) {
- fprintf(logfile, "hot remove: pci slot %d "
- "is not used by a hotplug device.\n", slot);
+ if ( test_pci_slot(devfn) < 0 ) {
+ fprintf(logfile, "hot remove: pci slot 0x%02x, function 0x%x "
+ "is not used by a hotplug device.\n", slot, func);
return;
}
+ /* ACPI PHP can only work on slots
+ * So only remove zero-functions -
+ * which will remove all other fucntions of the same device in the
+ * guest.
+ */
+ if ( func ) {
+ fprintf(logfile, "hot remove: Attempt to remove non-zero function "
+ "slot=0x%02x func=0x%0x.\n", slot, func);
+ return;
+ }
+
/* update the php controller status */
php_slots.plug_evt = PHP_EVT_REMOVE;
php_slots.plug_slot = slot;
acpi_sci_intr(s);
}
-void acpi_php_add(int slot)
+void acpi_php_add(int devfn)
{
GPEState *s = &gpe_state;
char ret_str[30];
+ int slot, func;
- if ( slot < 0 ) {
- fprintf(logfile, "hot add pci slot %d exceed.\n", slot);
+ if ( devfn < 0 ) {
+ fprintf(logfile, "hot add pci devfn %d exceed.\n", devfn);
- if ( slot == -1 )
- sprintf(ret_str, "no free hotplug slots");
- else if ( slot == -2 )
- sprintf(ret_str, "wrong bdf or vslot");
+ if ( devfn == -1 )
+ sprintf(ret_str, "no free hotplug devfn");
+ else if ( devfn == -2 )
+ sprintf(ret_str, "wrong bdf or vdevfn");
if ( strlen(ret_str) > 0 )
xenstore_record_dm("parameter", ret_str);
return;
}
- /* update the php controller status */
- php_slots.plug_evt = PHP_EVT_ADD;
- php_slots.plug_slot = slot;
+ /* ACPI PHP can only work on slots
+ * For function 0 we do a full hot-add.
+ * For other functions we just register the device with the hypervisor.
+ * Assuming that function 0 is added after non-zero functions,
+ * its ACPI PHP event will cause all previously registered functions
+ * to be added to the guest.
+ */
- /* update the slot status as present */
- php_slots.status[slot] = 0xf;
+ slot = PCI_SLOT(devfn);
+ func = PCI_FUNC(devfn);
- /* power on the slot */
- power_on_php_slot(slot);
+ if ( !func )
+ {
+ /* update the php controller status */
+ php_slots.plug_evt = PHP_EVT_ADD;
+ php_slots.plug_slot = slot;
+
+ /* update the slot status as present */
+ php_slots.status[slot] = 0xf;
+ }
+
+ /* power on the function */
+ power_on_php_slot(devfn);
/* tell Control panel which slot for the new pass-throgh dev */
- sprintf(ret_str, "0x%02x", slot);
+ sprintf(ret_str, "0x%02x", devfn);
xenstore_record_dm("parameter", ret_str);
/* signal the CP ACPI hot insert done */
xenstore_record_dm_state("pci-inserted");
/* generate a SCI interrupt */
- acpi_sci_intr(s);
+ if ( !func )
+ acpi_sci_intr(s);
}
#endif /* CONFIG_PASSTHROUGH */