Signed-off-by: Simon Horman <horms@xxxxxxxxxxx>
---
Fri, 13 Feb 2009 13:50:13 +1100
* Account for vslot supplied for hotplug insert
Fri, 13 Feb 2009 15:22:10 +1100
* Rebased
from "Restore xenfb.h and atkbd_ translation tables for * xenfbfront"
to "fix memory/fd leak in pt_msix_init()"
Index: ioemu-remote/hw/pass-through.c
===================================================================
--- ioemu-remote.orig/hw/pass-through.c 2009-02-17 17:55:37.000000000 +0900
+++ ioemu-remote/hw/pass-through.c 2009-02-17 17:56:46.000000000 +0900
@@ -34,6 +34,7 @@ struct php_dev {
uint8_t r_bus;
uint8_t r_dev;
uint8_t r_func;
+ uint8_t v_devfn;
char *opt;
};
static struct dpci_infos {
@@ -726,37 +727,65 @@ static const struct pt_reg_grp_info_tbl
},
};
+static int cmp_php_dev(const struct php_dev *a, const struct php_dev *b)
+{
+ if (a->r_bus != b->r_bus)
+ {
+ return a->r_bus - b->r_bus;
+ }
+ if (a->r_dev != b->r_dev)
+ {
+ return a->r_dev - b->r_dev;
+ }
+ if (a->r_func != b->r_func)
+ {
+ return a->r_func - b->r_func;
+ }
+
+ return 0;
+}
+
+static void cpy_php_dev(struct php_dev *dst, const struct php_dev *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+
static int token_value(char *token)
{
return strtol(token, NULL, 16);
}
-static int next_bdf(char **str, int *seg, int *bus, int *dev, int *func, char
**opt)
+static struct php_dev next_bdf(char **str)
{
char *token;
const char *delim = ":.-";
+ struct php_dev bdf;
+
+ memset(&bdf, 0, sizeof(bdf));
if ( !(*str) ||
( !strchr(*str, ':') && !strchr(*str, '.')) )
- return 0;
+ return bdf;
token = strsep(str, delim);
- *seg = token_value(token);
+ /* segment */
token = strsep(str, delim);
- *bus = token_value(token);
+ bdf.r_bus = token_value(token);
token = strsep(str, delim);
- *dev = token_value(token);
+ bdf.r_dev = token_value(token);
token = strsep(str, delim);
- *opt = strchr(token, ',');
- if (*opt)
- *(*opt)++ = '\0';
+ bdf.opt = strchr(token, ',');
+ if (bdf.opt)
+ *(bdf.opt)++ = '\0';
- *func = token_value(token);
+ bdf.r_func = token_value(token);
- return 1;
+ bdf.valid = 1;
+
+ return bdf;
}
static int get_next_keyval(char **option, char **key, char **val)
@@ -802,31 +831,31 @@ static void msi_set_enable(struct pt_dev
* 0: no free hotplug slots, but normal slot should okay
* >0: the new hotplug devfn
*/
-static int insert_to_php_devfn(int bus, int dev, int func, int devfn,
- char *opt)
+static int insert_to_php_devfn(const struct php_dev *bdf)
{
int php_slot, php_func, php_devfn, php_devfn_match;
/* preferred virt pci slot */
- if ( devfn >= PHP_DEVFN_START && devfn < PHP_DEVFN_END )
+ if ( bdf->v_devfn >= PHP_DEVFN_START && bdf->v_devfn < PHP_DEVFN_END )
{
- php_devfn = PCI_TO_PHP_DEVFN(devfn);
- if ( !dpci_infos.php_devs[php_devfn].valid )
+ php_devfn = PCI_TO_PHP_DEVFN(bdf->v_devfn);
+ if ( !dpci_infos.php_devs[php_devfn].valid ||
+ !cmp_php_dev(&dpci_infos.php_devs[php_devfn], bdf) )
goto found;
}
- if ( devfn != 0 )
+ if ( bdf->v_devfn != 0 )
return -1;
/* Co-locate functions for the same device in the same slot */
for ( php_slot = 0; php_slot < PHP_SLOT_LEN; php_slot++ )
{
- php_devfn = PCI_DEVFN(php_slot, func);
+ php_devfn = PCI_DEVFN(php_slot, bdf->r_func);
for ( php_func = 0; php_func < 8; php_func++ )
{
php_devfn_match = PCI_DEVFN(php_slot, php_func);
if ( dpci_infos.php_devs[php_devfn_match].valid &&
- dpci_infos.php_devs[php_devfn_match].r_bus == bus &&
- dpci_infos.php_devs[php_devfn_match].r_dev == dev &&
+ dpci_infos.php_devs[php_devfn_match].r_bus == bdf->r_bus &&
+ dpci_infos.php_devs[php_devfn_match].r_dev == bdf->r_dev &&
!dpci_infos.php_devs[php_devfn].valid )
goto found;
}
@@ -844,12 +873,9 @@ static int insert_to_php_devfn(int bus,
return 0;
found:
- dpci_infos.php_devs[php_devfn].valid = 1;
- dpci_infos.php_devs[php_devfn].r_bus = bus;
- dpci_infos.php_devs[php_devfn].r_dev = dev;
- dpci_infos.php_devs[php_devfn].r_func = func;
- dpci_infos.php_devs[php_devfn].opt = opt;
- return PHP_TO_PCI_DEVFN(php_devfn);
+ cpy_php_dev(&dpci_infos.php_devs[php_devfn], bdf);
+ dpci_infos.php_devs[php_devfn].v_devfn = PHP_TO_PCI_DEVFN(php_devfn);
+ return dpci_infos.php_devs[php_devfn].v_devfn;
}
/* Insert a new pass-through device into function 0 of a specific pci slot.
@@ -857,7 +883,8 @@ found:
*/
int insert_bdf_to_php_devfn(char *bdf_slt)
{
- int seg, bus, dev, func, slot;
+ int slot;
+ struct php_dev bdf;
char *bdf_str, *slt_str, *opt;
const char *delim="@";
@@ -865,12 +892,15 @@ int insert_bdf_to_php_devfn(char *bdf_sl
slt_str = bdf_slt;
slot = token_value(slt_str);
- if ( !next_bdf(&bdf_str, &seg, &bus, &dev, &func, &opt))
+ bdf = next_bdf(&bdf_str);
+ if (!bdf.valid)
{
return -1;
}
- return insert_to_php_devfn(bus, dev, func, PCI_DEVFN(slot, 0), opt);
+ bdf.v_devfn = PCI_DEVFN(slot, 0);
+
+ return insert_to_php_devfn(&bdf);
}
@@ -896,22 +926,22 @@ int test_php_devfn(int devfn)
/* find the pci slot for pass-through dev with specified BDF */
int bdf_to_php_devfn(char *bdf_str)
{
- int seg, bus, dev, func, i;
- char *opt;
+ int i;
+ struct php_dev bdf;
- if ( !next_bdf(&bdf_str, &seg, &bus, &dev, &func, &opt))
+ bdf = next_bdf(&bdf_str);
+ if (!bdf.valid)
{
return -1;
}
- PT_LOG("%s: bdf: %04x:%02x.%x\n", __func__, bus, dev, func);
+ PT_LOG("%s: bdf: %04x:%02x.%x\n", __func__, bdf.r_bus, bdf.r_dev,
+ bdf.r_func);
/* locate the virtual pci slot for this VTd device */
for ( i = 0; i < PHP_DEVFN_LEN; i++ )
{
if ( dpci_infos.php_devs[i].valid &&
- dpci_infos.php_devs[i].r_bus == bus &&
- dpci_infos.php_devs[i].r_dev == dev &&
- dpci_infos.php_devs[i].r_func == func )
+ cmp_php_dev(&dpci_infos.php_devs[i], &bdf) )
{
return PHP_TO_PCI_DEVFN(i);
}
@@ -3093,9 +3123,8 @@ static int pt_msixctrl_reg_write(struct
}
static struct pt_dev * 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, uint32_t machine_irq, struct pci_access *pci_access,
- char *opt)
+ const char *e_dev_name, struct php_dev *bdf,
+ uint32_t machine_irq, struct pci_access *pci_access)
{
int rc = -1, i;
struct pt_dev *assigned_device = NULL;
@@ -3107,14 +3136,14 @@ static struct pt_dev * register_real_dev
int msi_translate;
PT_LOG("Assigning real physical device %02x:%02x.%x ...\n",
- r_bus, r_dev, r_func);
+ bdf->r_bus, bdf->r_dev, bdf->r_func);
/* Find real device structure */
for (pci_dev = pci_access->devices; pci_dev != NULL;
pci_dev = pci_dev->next)
{
- if ((r_bus == pci_dev->bus) && (r_dev == pci_dev->dev)
- && (r_func == pci_dev->func))
+ if ((bdf->r_bus == pci_dev->bus) && (bdf->r_dev == pci_dev->dev)
+ && (bdf->r_func == pci_dev->func))
break;
}
if ( pci_dev == NULL )
@@ -3125,19 +3154,16 @@ static struct pt_dev * register_real_dev
pci_fill_info(pci_dev, PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE |
PCI_FILL_SIZES);
pt_libpci_fixup(pci_dev);
- if ( e_devfn == PCI_DEVFN_AUTO ) {
- /*indicate a static assignment(not hotplug), so find a free PCI hot
plug slot */
- free_devfn = insert_to_php_devfn(r_bus, r_dev, r_func, 0, NULL);
- if ( free_devfn > 0 )
- e_devfn = free_devfn;
- else
- PT_LOG("Error: no free virtual PCI hot plug slot, thus no live
migration.\n");
- }
+ free_devfn = insert_to_php_devfn(bdf);
+ if ( free_devfn <= 0 )
+ PT_LOG("Error: no free virtual PCI hot plug slot, "
+ "thus no live migration.\n");
msi_translate = direct_pci_msitranslate;
- while (opt) {
- if (get_next_keyval(&opt, &key, &val)) {
- PT_LOG("Error: unrecognized PCI assignment option \"%s\"\n", opt);
+ while (bdf->opt) {
+ if (get_next_keyval(&bdf->opt, &key, &val)) {
+ PT_LOG("Error: unrecognized PCI assignment option \"%s\"\n",
+ bdf->opt);
break;
}
@@ -3164,7 +3190,7 @@ static struct pt_dev * register_real_dev
/* Register device */
assigned_device = (struct pt_dev *) pci_register_device(e_bus, e_dev_name,
- sizeof(struct pt_dev), e_devfn,
+ sizeof(struct pt_dev), free_devfn,
pt_pci_read_config, pt_pci_write_config);
if ( assigned_device == NULL )
{
@@ -3181,9 +3207,9 @@ static struct pt_dev * register_real_dev
/* Assign device */
machine_bdf.reg = 0;
- machine_bdf.bus = r_bus;
- machine_bdf.dev = r_dev;
- machine_bdf.func = r_func;
+ machine_bdf.bus = bdf->r_bus;
+ machine_bdf.dev = bdf->r_dev;
+ machine_bdf.func = bdf->r_func;
rc = xc_assign_device(xc_handle, domid, machine_bdf.value);
if ( rc < 0 )
PT_LOG("Error: xc_assign_device error %d\n", rc);
@@ -3273,7 +3299,7 @@ static struct pt_dev * register_real_dev
out:
PT_LOG("Real physical device %02x:%02x.%x registered successfuly!\n"
- "IRQ type = %s\n", r_bus, r_dev, r_func,
+ "IRQ type = %s\n", bdf->r_bus, bdf->r_dev, bdf->r_func,
assigned_device->msi_trans_en? "MSI-INTx":"INTx");
return assigned_device;
@@ -3353,18 +3379,11 @@ static int unregister_real_device(int ph
int power_on_php_devfn(int php_devfn)
{
struct php_dev *php_dev = &dpci_infos.php_devs[php_devfn];
- int pci_devfn = PHP_TO_PCI_DEVFN(php_devfn);
struct pt_dev *pt_dev;
- pt_dev =
- register_real_device(dpci_infos.e_bus,
- "DIRECT PCI",
- pci_devfn,
- php_dev->r_bus,
- php_dev->r_dev,
- php_dev->r_func,
- PT_MACHINE_IRQ_AUTO,
- dpci_infos.pci_access,
- php_dev->opt);
+
+ pt_dev = register_real_device(dpci_infos.e_bus, "DIRECT PCI",
+ php_dev, PT_MACHINE_IRQ_AUTO,
+ dpci_infos.pci_access);
php_dev->opt = NULL;
@@ -3381,14 +3400,14 @@ int power_off_php_devfn(int php_devfn)
int pt_init(PCIBus *e_bus, const char *direct_pci)
{
- int seg, b, d, f, status = -1;
+ int status = -1;
struct pt_dev *pt_dev;
struct pci_access *pci_access;
char *vslots;
char slot_str[8];
char *direct_pci_head = NULL;
char *direct_pci_p = NULL;
- char *opt;
+ struct php_dev bdf;
/* Initialize libpci */
pci_access = pci_alloc();
@@ -3417,14 +3436,20 @@ int pt_init(PCIBus *e_bus, const char *d
vslots = qemu_mallocz ( strlen(direct_pci) / 3 );
/* Assign given devices to guest */
- while ( next_bdf(&direct_pci_p, &seg, &b, &d, &f, &opt) )
+ while (1)
{
+ bdf = next_bdf(&direct_pci_p);
+ if (!bdf.valid)
+ {
+ break;
+ }
/* Register real device with the emulated bus */
- pt_dev = register_real_device(e_bus, "DIRECT PCI", PCI_DEVFN_AUTO,
- b, d, f, PT_MACHINE_IRQ_AUTO, pci_access, opt);
+ pt_dev = register_real_device(e_bus, "DIRECT PCI",
+ &bdf, PT_MACHINE_IRQ_AUTO, pci_access);
if ( pt_dev == NULL )
{
- PT_LOG("Error: Registration failed (%02x:%02x.%x)\n", b, d, f);
+ PT_LOG("Error: Registration failed (%02x:%02x.%x)\n",
+ bdf.r_bus, bdf.r_dev, bdf.r_func);
goto err;
}
--
--
Simon Horman
VA Linux Systems Japan K.K., Sydney, Australia Satellite Office
H: www.vergenet.net/~horms/ W: www.valinux.co.jp/en
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|