From: Ross Philipson Date: Wed, 25 Mar 2009 13:25:01 +0000 (-0400) Subject: FLR - intermediate checkin 2 3/25 - unified ID lists, fixed flr X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=058d39aae30b3d004983a7861eac24557c9ccddb;p=xenclient%2Fkernel.git FLR - intermediate checkin 2 3/25 - unified ID lists, fixed flr logic routine. Changes to be committed: modified: drivers/xen/pciback/pci_stub.c modified: drivers/xen/pciback/pciback.h modified: drivers/xen/pciback/pciback_ops.c --- diff --git a/drivers/xen/pciback/pci_stub.c b/drivers/xen/pciback/pci_stub.c index bc6af30b..55932a42 100644 --- a/drivers/xen/pciback/pci_stub.c +++ b/drivers/xen/pciback/pci_stub.c @@ -26,8 +26,16 @@ module_param_named(sbr, pci_devs_use_sbr, charp, S_IRUGO); static char *pci_devs_use_d3r = NULL; module_param_named(d3r, pci_devs_use_d3r, charp, S_IRUGO); +/* Device id list holding different device type listings + * for hiding devices and reset logic. + */ +#define PCIBACK_ID_TYPE_HIDE 1 +#define PCIBACK_ID_TYPE_SBR 2 +#define PCIBACK_ID_TYPE_D3R 3 + struct pcistub_device_id { struct list_head slot_list; + int type; int domain; unsigned char bus; unsigned int devfn; @@ -35,11 +43,6 @@ struct pcistub_device_id { static LIST_HEAD(pcistub_device_ids); static DEFINE_SPINLOCK(device_ids_lock); -/* reset usage lists */ -static LIST_HEAD(pcistub_sbr_device_ids); -static LIST_HEAD(pcistub_d3r_device_ids); -static DEFINE_SPINLOCK(device_reset_ids_lock); - struct pcistub_device { struct kref kref; struct list_head dev_list; @@ -315,26 +318,22 @@ static int __devinit pcistub_match_one(struct pci_dev *dev, return 0; } -static int __devinit pcistub_match(struct pci_dev *dev, struct list_head *list) +static int __devinit pcistub_match(struct pci_dev *dev, int type) { struct pcistub_device_id *pdev_id; unsigned long flags; int found = 0; - spinlock_t *lock; - if (list == &pcistub_device_ids) - lock = &device_ids_lock; - else - lock = &device_reset_ids_lock; - - spin_lock_irqsave(lock, flags); - list_for_each_entry(pdev_id, list, slot_list) { + spin_lock_irqsave(&device_ids_lock, flags); + list_for_each_entry(pdev_id, &pcistub_device_ids, slot_list) { + if (pdev_id->type != type) + continue; if (pcistub_match_one(dev, pdev_id)) { found = 1; break; } } - spin_unlock_irqrestore(lock, flags); + spin_unlock_irqrestore(&device_ids_lock, flags); return found; } @@ -385,8 +384,8 @@ static int __devinit pcistub_init_device(struct pci_dev *dev) * values if SBR/D3R reset logic was requested. */ pciback_classify_device(dev); - dev_data->use_sbr = pcistub_match(dev, &pcistub_sbr_device_ids); - dev_data->use_d3r = pcistub_match(dev, &pcistub_d3r_device_ids); + dev_data->use_sbr = pcistub_match(dev, PCIBACK_ID_TYPE_SBR); + dev_data->use_d3r = pcistub_match(dev, PCIBACK_ID_TYPE_D3R); /* Store the config space here where the device is off and ready to be * exported before any FLRs or other resets are done @@ -490,7 +489,7 @@ static int __devinit pcistub_probe(struct pci_dev *dev, dev_dbg(&dev->dev, "probing...\n"); - if (pcistub_match(dev, &pcistub_device_ids)) { + if (pcistub_match(dev, PCIBACK_ID_TYPE_HIDE)) { if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { @@ -614,7 +613,7 @@ static inline int str_to_quirk(const char *buf, int *domain, int *bus, int return -EINVAL; } -static int pcistub_device_id_add(int domain, int bus, int slot, int func) +static int pcistub_device_id_add(int domain, int bus, int slot, int func, int type) { struct pcistub_device_id *pci_dev_id; unsigned long flags; @@ -623,12 +622,13 @@ static int pcistub_device_id_add(int domain, int bus, int slot, int func) if (!pci_dev_id) return -ENOMEM; + pci_dev_id->type = type; pci_dev_id->domain = domain; pci_dev_id->bus = bus; pci_dev_id->devfn = PCI_DEVFN(slot, func); - pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n", - domain, bus, slot, func); + pr_debug("pciback: adding device ID type: %d for %04x:%02x:%02x.%01x\n", + type, domain, bus, slot, func); spin_lock_irqsave(&device_ids_lock, flags); list_add_tail(&pci_dev_id->slot_list, &pcistub_device_ids); @@ -724,52 +724,6 @@ out: return err; } -static int pcistub_device_id_sbr_add(int domain, int bus, int slot, int func) -{ - struct pcistub_device_id *pci_dev_id; - unsigned long flags; - - pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); - if (!pci_dev_id) - return -ENOMEM; - - pci_dev_id->domain = domain; - pci_dev_id->bus = bus; - pci_dev_id->devfn = PCI_DEVFN(slot, func); - - pr_debug("pciback: adding sbr device %04x:%02x:%02x.%01x\n", - domain, bus, slot, func); - - spin_lock_irqsave(&device_reset_ids_lock, flags); - list_add_tail(&pci_dev_id->slot_list, &pcistub_sbr_device_ids); - spin_unlock_irqrestore(&device_reset_ids_lock, flags); - - return 0; -} - -static int pcistub_device_id_d3r_add(int domain, int bus, int slot, int func) -{ - struct pcistub_device_id *pci_dev_id; - unsigned long flags; - - pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL); - if (!pci_dev_id) - return -ENOMEM; - - pci_dev_id->domain = domain; - pci_dev_id->bus = bus; - pci_dev_id->devfn = PCI_DEVFN(slot, func); - - pr_debug("pciback: adding d3r device %04x:%02x:%02x.%01x\n", - domain, bus, slot, func); - - spin_lock_irqsave(&device_reset_ids_lock, flags); - list_add_tail(&pci_dev_id->slot_list, &pcistub_d3r_device_ids); - spin_unlock_irqrestore(&device_reset_ids_lock, flags); - - return 0; -} - static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf, size_t count) { @@ -780,7 +734,7 @@ static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf, if (err) goto out; - err = pcistub_device_id_add(domain, bus, slot, func); + err = pcistub_device_id_add(domain, bus, slot, func, PCIBACK_ID_TYPE_HIDE); out: if (!err) @@ -989,14 +943,14 @@ static ssize_t pcistub_resets(struct device_driver *drv, const char *buf, size_t count) { int domain, bus, slot, func; - int is_sbr, err; + int type, err; /* string begins with reset type specifier sbr=|dr3= */ if (!strncmp(buf, "sbr=", 4)) { - is_sbr = 1; + type = PCIBACK_ID_TYPE_SBR; buf += 4; } else if (!strncmp(buf, "d3r=", 4)) { - is_sbr = 0; + type = PCIBACK_ID_TYPE_D3R; buf += 4; } else { err = -EINVAL; @@ -1007,10 +961,7 @@ static ssize_t pcistub_resets(struct device_driver *drv, const char *buf, if (err) goto out; - if (is_sbr) - err = pcistub_device_id_sbr_add(domain, bus, slot, func); - else - err = pcistub_device_id_d3r_add(domain, bus, slot, func); + err = pcistub_device_id_add(domain, bus, slot, func, type); out: if (!err) @@ -1056,15 +1007,15 @@ static int __init pcistub_init(void) int err = 0; /* Parse device lists for hide, sbr, and d3r */ - err = pciback_parse_device_params(pci_devs_to_hide, pcistub_device_id_add); + err = pciback_parse_device_params(pci_devs_to_hide, PCIBACK_ID_TYPE_HIDE, pcistub_device_id_add); if (err) goto out; - err = pciback_parse_device_params(pci_devs_use_sbr, pcistub_device_id_sbr_add); + err = pciback_parse_device_params(pci_devs_use_sbr, PCIBACK_ID_TYPE_SBR, pcistub_device_id_add); if (err) goto out; - err = pciback_parse_device_params(pci_devs_use_d3r, pcistub_device_id_d3r_add); + err = pciback_parse_device_params(pci_devs_use_d3r, PCIBACK_ID_TYPE_D3R, pcistub_device_id_add); if (err) goto out; diff --git a/drivers/xen/pciback/pciback.h b/drivers/xen/pciback/pciback.h index e908e7fa..7086ca6f 100644 --- a/drivers/xen/pciback/pciback.h +++ b/drivers/xen/pciback/pciback.h @@ -108,10 +108,10 @@ int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev, void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev); struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev, unsigned int domain, unsigned int bus, - unsigned int devfn); + unsigned int devfn); int pciback_init_devices(struct pciback_device *pdev); int pciback_publish_pci_roots(struct pciback_device *pdev, - publish_pci_root_cb cb); + publish_pci_root_cb cb); void pciback_release_devices(struct pciback_device *pdev); /* Handles events from front-end */ @@ -119,7 +119,8 @@ irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs); void pciback_do_op(void *data); /* Parse and load device specific module parameters */ -int pciback_parse_device_params(const char *device_args, int (*add_func) (int domain, int bus, int slot, int func)); +int pciback_parse_device_params(const char *device_args, int type, + int (*add_func) (int domain, int bus, int slot, int func, int type)); int pciback_xenbus_register(void); void pciback_xenbus_unregister(void); diff --git a/drivers/xen/pciback/pciback_ops.c b/drivers/xen/pciback/pciback_ops.c index 09a027cb..07fae104 100644 --- a/drivers/xen/pciback/pciback_ops.c +++ b/drivers/xen/pciback/pciback_ops.c @@ -248,7 +248,7 @@ static int pciback_do_secondary_bus_reset(struct pci_dev *dev) goto cleanup; failed: - err = -ENXIO + err = -ENXIO; dev_warn(&dev->dev, "secondary bus reset failed for device - all functions need to be co-assigned!\n"); @@ -260,74 +260,61 @@ cleanup: return err; } -/* This function is used to do a function level reset on a singe device/function. - * FLRs must be done on devices before they are unassigned from one domain and - * passed through to another. The preferred method is to do an actual FLR on the - * device but the functionality may not be present or exposed. In the later case - * we attempt to locate the capability even though it is not chained into the - * capabilities list. +/* This function is used to do a function level reset on a singe + * device/function. FLRs must be done on devices before they are + * unassigned from one domain and passed through to another. The + * preferred method is to do an actual FLR on the device but the + * functionality may not be present or exposed. In the later case + * we attempt to locate the capability even though it is not + * chained into the capabilities list. * - * In some cases, there are no TODO... + * In some cases, there is no way to perform the actual FLR so we + * fall back to some alternate methods (which are not as effective + * or useful). */ void pciback_flr_device(struct pci_dev *dev) { struct pciback_dev_data *dev_data = pci_get_drvdata(dev); int err = 0; - if (dev_data->dev_type == PCIBACK_TYPE_PCIe_ENDPOINT) { - if (dev_data->exp_flr_offset != 0) { + do { + /* First, always try to do an FLR */ + if (dev_data->dev_type == PCIBACK_TYPE_PCIe_ENDPOINT && + dev_data->exp_flr_offset != 0) { pciback_do_pcie_flr(dev, dev_data->exp_flr_offset); - goto out; + break; } - - if (dev->bus->number == 0) { - err = pciback_do_vendor_specific_reset(dev); - if (err && dev_data->use_d3r) - err = pciback_do_dstate_transition_reset(dev); - if (err) { - dev_warn(&dev->dev, "FLR functionality not supported; " - "attempts to use vendor specific FLR and D-state transitions failed; " - "FLR not performed for device\n"); - } - - } - else if (dev_data->use_sbr) { - err = pciback_do_dstate_transition_reset(dev); - if (err) { - dev_warn(&dev->dev, "FLR functionality not supported; " - "attempts to use secondary bus reset failed; " - "FLR not performed for device\n"); - } - } - } - else if (dev_data->dev_type == PCIBACK_TYPE_PCI) { - if (dev_data->af_flr_offset != 0) { + if (dev_data->dev_type == PCIBACK_TYPE_PCI && + dev_data->af_flr_offset != 0) { pciback_do_pci_flr(dev, dev_data->af_flr_offset); - goto out; + break; } + + /* Next for integrated devices on the host bus 0, try some other methods */ if (dev->bus->number == 0) { err = pciback_do_vendor_specific_reset(dev); if (err && dev_data->use_d3r) err = pciback_do_dstate_transition_reset(dev); - if (err) { + if (err) dev_warn(&dev->dev, "FLR functionality not supported; " - "attempts to use vendor specific FLR and D-state transitions failed; " - "FLR not performed for device\n"); - } + "attempts to use vendor FLR or D-states failed\n"); + break; } - else { - dev_warn(&dev->dev, "FLR functionality not supported; " - "no secondary bus reset functionality available; " - "FLR not performed for device\n"); + + /* Else for PCIe devices behind root port, attempt a secondary bus reset */ + if (dev_data->dev_type == PCIBACK_TYPE_PCIe_ENDPOINT && dev_data->use_sbr) { + err = pciback_do_secondary_bus_reset(dev); + if (err) + dev_warn(&dev->dev, "FLR functionality not supported; " + "attempts to use secondary bus reset failed;\n"); + break; } - } - else { - dev_warn(&dev->dev, - "FLR not being used for bridge devices.\n"); - } - - /* no return, trace warning about activity */ -out: + + err = -ENODEV; + } while (0); + + if (err) + dev_warn(&dev->dev, "FLR not performed for device\n"); } /* Helper used to location the FLR capabilities for a PCIe device. @@ -515,7 +502,7 @@ irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs) return IRQ_HANDLED; } -int pciback_parse_device_params(const char *device_args, int (*add_func) (int domain, int bus, int slot, int func)) +int pciback_parse_device_params(const char *device_args, int type, int (*add_func) (int domain, int bus, int slot, int func, int type)) { int pos = 0; int err = 0; @@ -538,7 +525,7 @@ int pciback_parse_device_params(const char *device_args, int (*add_func) (int do goto parse_error; } - err = add_func(domain, bus, slot, func); + err = add_func(domain, bus, slot, func, type); if (err) goto out;