diff options
Diffstat (limited to 'drivers/pci')
| -rw-r--r-- | drivers/pci/hotplug/acpi_pcihp.c | 6 | ||||
| -rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 2 | ||||
| -rw-r--r-- | drivers/pci/hotplug/cpci_hotplug_core.c | 2 | ||||
| -rw-r--r-- | drivers/pci/hotplug/cpqphp_core.c | 17 | ||||
| -rw-r--r-- | drivers/pci/hotplug/pciehp_ctrl.c | 3 | ||||
| -rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 11 | ||||
| -rw-r--r-- | drivers/pci/hotplug/pcihp_slot.c | 47 | ||||
| -rw-r--r-- | drivers/pci/of.c | 2 | ||||
| -rw-r--r-- | drivers/pci/pci-label.c | 2 | ||||
| -rw-r--r-- | drivers/pci/pci.c | 78 | ||||
| -rw-r--r-- | drivers/pci/pci.h | 4 | ||||
| -rw-r--r-- | drivers/pci/pcie/aer/aerdrv_core.c | 76 | ||||
| -rw-r--r-- | drivers/pci/pcie/aer/aerdrv_errprint.c | 3 | ||||
| -rw-r--r-- | drivers/pci/probe.c | 234 | ||||
| -rw-r--r-- | drivers/pci/setup-bus.c | 169 | ||||
| -rw-r--r-- | drivers/pci/setup-irq.c | 4 | ||||
| -rw-r--r-- | drivers/pci/setup-res.c | 153 | ||||
| -rw-r--r-- | drivers/pci/xen-pcifront.c | 2 | 
18 files changed, 572 insertions, 243 deletions
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index 8f3faf343f7..095f29e1373 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -408,7 +408,7 @@ got_one:  }  EXPORT_SYMBOL(acpi_get_hp_hw_control_from_firmware); -static int is_ejectable(acpi_handle handle) +static int pcihp_is_ejectable(acpi_handle handle)  {  	acpi_status status;  	acpi_handle tmp; @@ -442,7 +442,7 @@ int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle)  		return 0;  	if (bridge_handle != parent_handle)  		return 0; -	return is_ejectable(handle); +	return pcihp_is_ejectable(handle);  }  EXPORT_SYMBOL_GPL(acpi_pci_check_ejectable); @@ -450,7 +450,7 @@ static acpi_status  check_hotplug(acpi_handle handle, u32 lvl, void *context, void **rv)  {  	int *found = (int *)context; -	if (is_ejectable(handle)) { +	if (pcihp_is_ejectable(handle)) {  		*found = 1;  		return AE_CTRL_TERMINATE;  	} diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a70fa89f76f..220285760b6 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -110,7 +110,7 @@ static int post_dock_fixups(struct notifier_block *nb, unsigned long val,  } -static struct acpi_dock_ops acpiphp_dock_ops = { +static const struct acpi_dock_ops acpiphp_dock_ops = {  	.handler = handle_hotplug_event_func,  }; diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index d703e73fffa..3fadf2f135e 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -32,7 +32,7 @@  #include <linux/pci_hotplug.h>  #include <linux/init.h>  #include <linux/interrupt.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include <linux/delay.h>  #include <linux/kthread.h>  #include "cpci_hotplug.h" diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 4952c3b9379..f1ce99cceac 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -840,8 +840,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	/* Need to read VID early b/c it's used to differentiate CPQ and INTC  	 * discovery  	 */ -	rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); -	if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { +	vendor_id = pdev->vendor; +	if ((vendor_id != PCI_VENDOR_ID_COMPAQ) && +	    (vendor_id != PCI_VENDOR_ID_INTEL)) {  		err(msg_HPC_non_compaq_or_intel);  		rc = -ENODEV;  		goto err_disable_device; @@ -868,11 +869,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	/* TODO: This code can be made to support non-Compaq or Intel  	 * subsystem IDs  	 */ -	rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); -	if (rc) { -		err("%s : pci_read_config_word failed\n", __func__); -		goto err_disable_device; -	} +	subsystem_vid = pdev->subsystem_vendor;  	dbg("Subsystem Vendor ID: %x\n", subsystem_vid);  	if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) {  		err(msg_HPC_non_compaq_or_intel); @@ -887,11 +884,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  		goto err_disable_device;  	} -	rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); -	if (rc) { -		err("%s : pci_read_config_word failed\n", __func__); -		goto err_free_ctrl; -	} +	subsystem_deviceid = pdev->subsystem_device;  	info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 085dbb5fc16..1e9c9aacc3a 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -213,6 +213,9 @@ static int board_added(struct slot *p_slot)  		goto err_exit;  	} +	/* Wait for 1 second after checking link training status */ +	msleep(1000); +  	/* Check for a power fault */  	if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) {  		ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 50a23da5d24..96dc4734e4a 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -275,16 +275,9 @@ int pciehp_check_link_status(struct controller *ctrl)           * hot-plug capable downstream port. But old controller might           * not implement it. In this case, we wait for 1000 ms.           */ -        if (ctrl->link_active_reporting){ -                /* Wait for Data Link Layer Link Active bit to be set */ +        if (ctrl->link_active_reporting)                  pcie_wait_link_active(ctrl); -                /* -                 * We must wait for 100 ms after the Data Link Layer -                 * Link Active bit reads 1b before initiating a -                 * configuration access to the hot added device. -                 */ -                msleep(100); -        } else +        else                  msleep(1000);  	retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c index 749fdf07031..3ffd9c1acc0 100644 --- a/drivers/pci/hotplug/pcihp_slot.c +++ b/drivers/pci/hotplug/pcihp_slot.c @@ -158,47 +158,6 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)  	 */  } -/* Program PCIE MaxPayload setting on device: ensure parent maxpayload <= device */ -static int pci_set_payload(struct pci_dev *dev) -{ -       int pos, ppos; -       u16 pctl, psz; -       u16 dctl, dsz, dcap, dmax; -       struct pci_dev *parent; - -       parent = dev->bus->self; -       pos = pci_find_capability(dev, PCI_CAP_ID_EXP); -       if (!pos) -               return 0; - -       /* Read Device MaxPayload capability and setting */ -       pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &dctl); -       pci_read_config_word(dev, pos + PCI_EXP_DEVCAP, &dcap); -       dsz = (dctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5; -       dmax = (dcap & PCI_EXP_DEVCAP_PAYLOAD); - -       /* Read Parent MaxPayload setting */ -       ppos = pci_find_capability(parent, PCI_CAP_ID_EXP); -       if (!ppos) -               return 0; -       pci_read_config_word(parent, ppos + PCI_EXP_DEVCTL, &pctl); -       psz = (pctl &  PCI_EXP_DEVCTL_PAYLOAD) >> 5; - -       /* If parent payload > device max payload -> error -        * If parent payload > device payload -> set speed -        * If parent payload <= device payload -> do nothing -        */ -       if (psz > dmax) -               return -1; -       else if (psz > dsz) { -               dev_info(&dev->dev, "Setting MaxPayload to %d\n", 128 << psz); -               pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, -                                     (dctl & ~PCI_EXP_DEVCTL_PAYLOAD) + -                                     (psz << 5)); -       } -       return 0; -} -  void pci_configure_slot(struct pci_dev *dev)  {  	struct pci_dev *cdev; @@ -210,9 +169,9 @@ void pci_configure_slot(struct pci_dev *dev)  			(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))  		return; -       ret = pci_set_payload(dev); -       if (ret) -               dev_warn(&dev->dev, "could not set device max payload\n"); +	if (dev->bus && dev->bus->self) +		pcie_bus_configure_settings(dev->bus, +					    dev->bus->self->pcie_mpss);  	memset(&hpp, 0, sizeof(hpp));  	ret = pci_get_hp_params(dev, &hpp); diff --git a/drivers/pci/of.c b/drivers/pci/of.c index c94d37ec55c..f0929934bb7 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -55,7 +55,7 @@ struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus)  	 */  	if (bus->bridge->of_node)  		return of_node_get(bus->bridge->of_node); -	if (bus->bridge->parent->of_node) +	if (bus->bridge->parent && bus->bridge->parent->of_node)  		return of_node_get(bus->bridge->parent->of_node);  	return NULL;  } diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index 77cb2a14c89..81525ae5d86 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -55,7 +55,7 @@ enum smbios_attr_enum {  	SMBIOS_ATTR_INSTANCE_SHOW,  }; -static mode_t +static size_t  find_smbios_instance_string(struct pci_dev *pdev, char *buf,  			    enum smbios_attr_enum attribute)  { diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 692671b1166..4e84fd4a431 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -77,6 +77,8 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;  unsigned long pci_hotplug_io_size  = DEFAULT_HOTPLUG_IO_SIZE;  unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE; +enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_SAFE; +  /*   * The default CLS is used if arch didn't set CLS explicitly and not   * all pci devices agree on the same value.  Arch can override either @@ -1905,7 +1907,7 @@ void pci_enable_ari(struct pci_dev *dev)  {  	int pos;  	u32 cap; -	u16 ctrl; +	u16 flags, ctrl;  	struct pci_dev *bridge;  	if (!pci_is_pcie(dev) || dev->devfn) @@ -1923,6 +1925,11 @@ void pci_enable_ari(struct pci_dev *dev)  	if (!pos)  		return; +	/* ARI is a PCIe v2 feature */ +	pci_read_config_word(bridge, pos + PCI_EXP_FLAGS, &flags); +	if ((flags & PCI_EXP_FLAGS_VERS) < 2) +		return; +  	pci_read_config_dword(bridge, pos + PCI_EXP_DEVCAP2, &cap);  	if (!(cap & PCI_EXP_DEVCAP2_ARI))  		return; @@ -3186,7 +3193,7 @@ EXPORT_SYMBOL(pcie_get_readrq);   * @rq: maximum memory read count in bytes   *    valid values are 128, 256, 512, 1024, 2048, 4096   * - * If possible sets maximum read byte count + * If possible sets maximum memory read request in bytes   */  int pcie_set_readrq(struct pci_dev *dev, int rq)  { @@ -3209,7 +3216,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)  	if ((ctl & PCI_EXP_DEVCTL_READRQ) != v) {  		ctl &= ~PCI_EXP_DEVCTL_READRQ;  		ctl |= v; -		err = pci_write_config_dword(dev, cap + PCI_EXP_DEVCTL, ctl); +		err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl);  	}  out: @@ -3218,6 +3225,67 @@ out:  EXPORT_SYMBOL(pcie_set_readrq);  /** + * pcie_get_mps - get PCI Express maximum payload size + * @dev: PCI device to query + * + * Returns maximum payload size in bytes + *    or appropriate error value. + */ +int pcie_get_mps(struct pci_dev *dev) +{ +	int ret, cap; +	u16 ctl; + +	cap = pci_pcie_cap(dev); +	if (!cap) +		return -EINVAL; + +	ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl); +	if (!ret) +		ret = 128 << ((ctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); + +	return ret; +} + +/** + * pcie_set_mps - set PCI Express maximum payload size + * @dev: PCI device to query + * @mps: maximum payload size in bytes + *    valid values are 128, 256, 512, 1024, 2048, 4096 + * + * If possible sets maximum payload size + */ +int pcie_set_mps(struct pci_dev *dev, int mps) +{ +	int cap, err = -EINVAL; +	u16 ctl, v; + +	if (mps < 128 || mps > 4096 || !is_power_of_2(mps)) +		goto out; + +	v = ffs(mps) - 8; +	if (v > dev->pcie_mpss)  +		goto out; +	v <<= 5; + +	cap = pci_pcie_cap(dev); +	if (!cap) +		goto out; + +	err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl); +	if (err) +		goto out; + +	if ((ctl & PCI_EXP_DEVCTL_PAYLOAD) != v) { +		ctl &= ~PCI_EXP_DEVCTL_PAYLOAD; +		ctl |= v; +		err = pci_write_config_word(dev, cap + PCI_EXP_DEVCTL, ctl); +	} +out: +	return err; +} + +/**   * pci_select_bars - Make BAR mask from the type of resource   * @dev: the PCI device for which BAR mask is made   * @flags: resource type mask to be selected @@ -3500,6 +3568,10 @@ static int __init pci_setup(char *str)  				pci_hotplug_io_size = memparse(str + 9, &str);  			} else if (!strncmp(str, "hpmemsize=", 10)) {  				pci_hotplug_mem_size = memparse(str + 10, &str); +			} else if (!strncmp(str, "pcie_bus_safe", 13)) { +				pcie_bus_config = PCIE_BUS_SAFE; +			} else if (!strncmp(str, "pcie_bus_perf", 13)) { +				pcie_bus_config = PCIE_BUS_PERFORMANCE;  			} else {  				printk(KERN_ERR "PCI: Unknown option `%s'\n",  						str); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index c8cee764b0d..b74084e9ca1 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -283,6 +283,8 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)  #endif /* CONFIG_PCI_IOV */ +extern unsigned long pci_cardbus_resource_alignment(struct resource *); +  static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,  					 struct resource *res)  { @@ -292,6 +294,8 @@ static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,  	if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END)  		return pci_sriov_resource_alignment(dev, resno);  #endif +	if (dev->class >> 8  == PCI_CLASS_BRIDGE_CARDBUS) +		return pci_cardbus_resource_alignment(res);  	return resource_alignment(res);  } diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index 43421fbe080..9674e9f30d4 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -24,6 +24,7 @@  #include <linux/suspend.h>  #include <linux/delay.h>  #include <linux/slab.h> +#include <linux/kfifo.h>  #include "aerdrv.h"  static int forceload; @@ -445,8 +446,7 @@ static struct pcie_port_service_driver *find_aer_service(struct pci_dev *dev)  	return drv;  } -static pci_ers_result_t reset_link(struct pcie_device *aerdev, -		struct pci_dev *dev) +static pci_ers_result_t reset_link(struct pci_dev *dev)  {  	struct pci_dev *udev;  	pci_ers_result_t status; @@ -486,7 +486,6 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev,  /**   * do_recovery - handle nonfatal/fatal error recovery process - * @aerdev: pointer to a pcie_device data structure of root port   * @dev: pointer to a pci_dev data structure of agent detecting an error   * @severity: error severity type   * @@ -494,8 +493,7 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev,   * error detected message to all downstream drivers within a hierarchy in   * question and return the returned code.   */ -static void do_recovery(struct pcie_device *aerdev, struct pci_dev *dev, -		int severity) +static void do_recovery(struct pci_dev *dev, int severity)  {  	pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED;  	enum pci_channel_state state; @@ -511,7 +509,7 @@ static void do_recovery(struct pcie_device *aerdev, struct pci_dev *dev,  			report_error_detected);  	if (severity == AER_FATAL) { -		result = reset_link(aerdev, dev); +		result = reset_link(dev);  		if (result != PCI_ERS_RESULT_RECOVERED)  			goto failed;  	} @@ -576,9 +574,73 @@ static void handle_error_source(struct pcie_device *aerdev,  			pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,  					info->status);  	} else -		do_recovery(aerdev, dev, info->severity); +		do_recovery(dev, info->severity);  } +#ifdef CONFIG_ACPI_APEI_PCIEAER +static void aer_recover_work_func(struct work_struct *work); + +#define AER_RECOVER_RING_ORDER		4 +#define AER_RECOVER_RING_SIZE		(1 << AER_RECOVER_RING_ORDER) + +struct aer_recover_entry +{ +	u8	bus; +	u8	devfn; +	u16	domain; +	int	severity; +}; + +static DEFINE_KFIFO(aer_recover_ring, struct aer_recover_entry, +		    AER_RECOVER_RING_SIZE); +/* + * Mutual exclusion for writers of aer_recover_ring, reader side don't + * need lock, because there is only one reader and lock is not needed + * between reader and writer. + */ +static DEFINE_SPINLOCK(aer_recover_ring_lock); +static DECLARE_WORK(aer_recover_work, aer_recover_work_func); + +void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, +		       int severity) +{ +	unsigned long flags; +	struct aer_recover_entry entry = { +		.bus		= bus, +		.devfn		= devfn, +		.domain		= domain, +		.severity	= severity, +	}; + +	spin_lock_irqsave(&aer_recover_ring_lock, flags); +	if (kfifo_put(&aer_recover_ring, &entry)) +		schedule_work(&aer_recover_work); +	else +		pr_err("AER recover: Buffer overflow when recovering AER for %04x:%02x:%02x:%x\n", +		       domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); +	spin_unlock_irqrestore(&aer_recover_ring_lock, flags); +} +EXPORT_SYMBOL_GPL(aer_recover_queue); + +static void aer_recover_work_func(struct work_struct *work) +{ +	struct aer_recover_entry entry; +	struct pci_dev *pdev; + +	while (kfifo_get(&aer_recover_ring, &entry)) { +		pdev = pci_get_domain_bus_and_slot(entry.domain, entry.bus, +						   entry.devfn); +		if (!pdev) { +			pr_err("AER recover: Can not find pci_dev for %04x:%02x:%02x:%x\n", +			       entry.domain, entry.bus, +			       PCI_SLOT(entry.devfn), PCI_FUNC(entry.devfn)); +			continue; +		} +		do_recovery(pdev, entry.severity); +	} +} +#endif +  /**   * get_device_error_info - read error status from dev and store it to info   * @dev: pointer to the device expected to have a error record diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c index b07a42e0b35..3ea51736f18 100644 --- a/drivers/pci/pcie/aer/aerdrv_errprint.c +++ b/drivers/pci/pcie/aer/aerdrv_errprint.c @@ -204,7 +204,7 @@ void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info)  }  #ifdef CONFIG_ACPI_APEI_PCIEAER -static int cper_severity_to_aer(int cper_severity) +int cper_severity_to_aer(int cper_severity)  {  	switch (cper_severity) {  	case CPER_SEV_RECOVERABLE: @@ -215,6 +215,7 @@ static int cper_severity_to_aer(int cper_severity)  		return AER_CORRECTABLE;  	}  } +EXPORT_SYMBOL_GPL(cper_severity_to_aer);  void cper_print_aer(const char *prefix, int cper_severity,  		    struct aer_capability_regs *aer) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 9ab492f21f8..f3f94a5c068 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -68,21 +68,6 @@ static int __init pcibus_class_init(void)  }  postcore_initcall(pcibus_class_init); -/* - * Translate the low bits of the PCI base - * to the resource type - */ -static inline unsigned int pci_calc_resource_flags(unsigned int flags) -{ -	if (flags & PCI_BASE_ADDRESS_SPACE_IO) -		return IORESOURCE_IO; - -	if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) -		return IORESOURCE_MEM | IORESOURCE_PREFETCH; - -	return IORESOURCE_MEM; -} -  static u64 pci_size(u64 base, u64 maxbase, u64 mask)  {  	u64 size = mask & maxbase;	/* Find the significant bits */ @@ -101,18 +86,39 @@ static u64 pci_size(u64 base, u64 maxbase, u64 mask)  	return size;  } -static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar) +static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar)  { +	u32 mem_type; +	unsigned long flags; +  	if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { -		res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK; -		return pci_bar_io; +		flags = bar & ~PCI_BASE_ADDRESS_IO_MASK; +		flags |= IORESOURCE_IO; +		return flags;  	} -	res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK; +	flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK; +	flags |= IORESOURCE_MEM; +	if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) +		flags |= IORESOURCE_PREFETCH; -	if (res->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) -		return pci_bar_mem64; -	return pci_bar_mem32; +	mem_type = bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK; +	switch (mem_type) { +	case PCI_BASE_ADDRESS_MEM_TYPE_32: +		break; +	case PCI_BASE_ADDRESS_MEM_TYPE_1M: +		dev_info(&dev->dev, "1M mem BAR treated as 32-bit BAR\n"); +		break; +	case PCI_BASE_ADDRESS_MEM_TYPE_64: +		flags |= IORESOURCE_MEM_64; +		break; +	default: +		dev_warn(&dev->dev, +			 "mem unknown type %x treated as 32-bit BAR\n", +			 mem_type); +		break; +	} +	return flags;  }  /** @@ -165,9 +171,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,  		l = 0;  	if (type == pci_bar_unknown) { -		type = decode_bar(res, l); -		res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; -		if (type == pci_bar_io) { +		res->flags = decode_bar(dev, l); +		res->flags |= IORESOURCE_SIZEALIGN; +		if (res->flags & IORESOURCE_IO) {  			l &= PCI_BASE_ADDRESS_IO_MASK;  			mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT;  		} else { @@ -180,7 +186,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,  		mask = (u32)PCI_ROM_ADDRESS_MASK;  	} -	if (type == pci_bar_mem64) { +	if (res->flags & IORESOURCE_MEM_64) {  		u64 l64 = l;  		u64 sz64 = sz;  		u64 mask64 = mask | (u64)~0 << 32; @@ -204,7 +210,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,  			goto fail;  		} -		res->flags |= IORESOURCE_MEM_64;  		if ((sizeof(resource_size_t) < 8) && l) {  			/* Address above 32-bit boundary; disable the BAR */  			pci_write_config_dword(dev, pos, 0); @@ -230,7 +235,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,  	}   out: -	return (type == pci_bar_mem64) ? 1 : 0; +	return (res->flags & IORESOURCE_MEM_64) ? 1 : 0;   fail:  	res->flags = 0;  	goto out; @@ -284,10 +289,6 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)  		if (!res->end)  			res->end = limit + 0xfff;  		dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res); -	} else { -		dev_printk(KERN_DEBUG, &dev->dev, -			 "  bridge window [io  %#06lx-%#06lx] (disabled)\n", -				 base, limit);  	}  } @@ -308,10 +309,6 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)  		res->start = base;  		res->end = limit + 0xfffff;  		dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res); -	} else { -		dev_printk(KERN_DEBUG, &dev->dev, -			"  bridge window [mem %#010lx-%#010lx] (disabled)\n", -					 base, limit + 0xfffff);  	}  } @@ -359,10 +356,6 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)  		res->start = base;  		res->end = limit + 0xfffff;  		dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res); -	} else { -		dev_printk(KERN_DEBUG, &dev->dev, -		     "  bridge window [mem %#010lx-%#010lx pref] (disabled)\n", -					 base, limit + 0xfffff);  	}  } @@ -725,12 +718,14 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,  		pci_write_config_word(dev, PCI_STATUS, 0xffff);  		/* Prevent assigning a bus number that already exists. -		 * This can happen when a bridge is hot-plugged */ -		if (pci_find_bus(pci_domain_nr(bus), max+1)) -			goto out; -		child = pci_add_new_bus(bus, dev, ++max); -		if (!child) -			goto out; +		 * This can happen when a bridge is hot-plugged, so in +		 * this case we only re-scan this bus. */ +		child = pci_find_bus(pci_domain_nr(bus), max+1); +		if (!child) { +			child = pci_add_new_bus(bus, dev, ++max); +			if (!child) +				goto out; +		}  		buses = (buses & 0xff000000)  		      | ((unsigned int)(child->primary)     <<  0)  		      | ((unsigned int)(child->secondary)   <<  8) @@ -861,6 +856,8 @@ void set_pcie_port_type(struct pci_dev *pdev)  	pdev->pcie_cap = pos;  	pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16);  	pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4; +	pci_read_config_word(pdev, pos + PCI_EXP_DEVCAP, ®16); +	pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;  }  void set_pcie_hotplug_bridge(struct pci_dev *pdev) @@ -1331,6 +1328,151 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)  	return nr;  } +static int pcie_find_smpss(struct pci_dev *dev, void *data) +{ +	u8 *smpss = data; + +	if (!pci_is_pcie(dev)) +		return 0; + +	/* For PCIE hotplug enabled slots not connected directly to a +	 * PCI-E root port, there can be problems when hotplugging +	 * devices.  This is due to the possibility of hotplugging a +	 * device into the fabric with a smaller MPS that the devices +	 * currently running have configured.  Modifying the MPS on the +	 * running devices could cause a fatal bus error due to an +	 * incoming frame being larger than the newly configured MPS. +	 * To work around this, the MPS for the entire fabric must be +	 * set to the minimum size.  Any devices hotplugged into this +	 * fabric will have the minimum MPS set.  If the PCI hotplug +	 * slot is directly connected to the root port and there are not +	 * other devices on the fabric (which seems to be the most +	 * common case), then this is not an issue and MPS discovery +	 * will occur as normal. +	 */ +	if (dev->is_hotplug_bridge && (!list_is_singular(&dev->bus->devices) || +	     (dev->bus->self && +	      dev->bus->self->pcie_type != PCI_EXP_TYPE_ROOT_PORT))) +		*smpss = 0; + +	if (*smpss > dev->pcie_mpss) +		*smpss = dev->pcie_mpss; + +	return 0; +} + +static void pcie_write_mps(struct pci_dev *dev, int mps) +{ +	int rc, dev_mpss; + +	dev_mpss = 128 << dev->pcie_mpss; + +	if (pcie_bus_config == PCIE_BUS_PERFORMANCE) { +		if (dev->bus->self) { +			dev_dbg(&dev->bus->dev, "Bus MPSS %d\n", +				128 << dev->bus->self->pcie_mpss); + +			/* For "MPS Force Max", the assumption is made that +			 * downstream communication will never be larger than +			 * the MRRS.  So, the MPS only needs to be configured +			 * for the upstream communication.  This being the case, +			 * walk from the top down and set the MPS of the child +			 * to that of the parent bus. +			 */ +			mps = 128 << dev->bus->self->pcie_mpss; +			if (mps > dev_mpss) +				dev_warn(&dev->dev, "MPS configured higher than" +					 " maximum supported by the device.  If" +					 " a bus issue occurs, try running with" +					 " pci=pcie_bus_safe.\n"); +		} + +		dev->pcie_mpss = ffs(mps) - 8; +	} + +	rc = pcie_set_mps(dev, mps); +	if (rc) +		dev_err(&dev->dev, "Failed attempting to set the MPS\n"); +} + +static void pcie_write_mrrs(struct pci_dev *dev, int mps) +{ +	int rc, mrrs, dev_mpss; + +	/* In the "safe" case, do not configure the MRRS.  There appear to be +	 * issues with setting MRRS to 0 on a number of devices. +	 */ + +	if (pcie_bus_config != PCIE_BUS_PERFORMANCE) +		return; + +	dev_mpss = 128 << dev->pcie_mpss; + +	/* For Max performance, the MRRS must be set to the largest supported +	 * value.  However, it cannot be configured larger than the MPS the +	 * device or the bus can support.  This assumes that the largest MRRS +	 * available on the device cannot be smaller than the device MPSS. +	 */ +	mrrs = min(mps, dev_mpss); + +	/* MRRS is a R/W register.  Invalid values can be written, but a +	 * subsequent read will verify if the value is acceptable or not. +	 * If the MRRS value provided is not acceptable (e.g., too large), +	 * shrink the value until it is acceptable to the HW. + 	 */ +	while (mrrs != pcie_get_readrq(dev) && mrrs >= 128) { +		dev_warn(&dev->dev, "Attempting to modify the PCI-E MRRS value" +			 " to %d.  If any issues are encountered, please try " +			 "running with pci=pcie_bus_safe\n", mrrs); +		rc = pcie_set_readrq(dev, mrrs); +		if (rc) +			dev_err(&dev->dev, +				"Failed attempting to set the MRRS\n"); + +		mrrs /= 2; +	} +} + +static int pcie_bus_configure_set(struct pci_dev *dev, void *data) +{ +	int mps = 128 << *(u8 *)data; + +	if (!pci_is_pcie(dev)) +		return 0; + +	dev_dbg(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n", +		 pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev)); + +	pcie_write_mps(dev, mps); +	pcie_write_mrrs(dev, mps); + +	dev_dbg(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n", +		 pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev)); + +	return 0; +} + +/* pcie_bus_configure_mps requires that pci_walk_bus work in a top-down, + * parents then children fashion.  If this changes, then this code will not + * work as designed. + */ +void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss) +{ +	u8 smpss = mpss; + +	if (!pci_is_pcie(bus->self)) +		return; + +	if (pcie_bus_config == PCIE_BUS_SAFE) { +		pcie_find_smpss(bus->self, &smpss); +		pci_walk_bus(bus, pcie_find_smpss, &smpss); +	} + +	pcie_bus_configure_set(bus->self, &smpss); +	pci_walk_bus(bus, pcie_bus_configure_set, &smpss); +} +EXPORT_SYMBOL_GPL(pcie_bus_configure_settings); +  unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)  {  	unsigned int devfn, pass, max = bus->secondary; diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 9995842e45b..784da9d3602 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -34,6 +34,7 @@ struct resource_list_x {  	resource_size_t start;  	resource_size_t end;  	resource_size_t add_size; +	resource_size_t min_align;  	unsigned long flags;  }; @@ -65,7 +66,7 @@ void pci_realloc(void)   */  static void add_to_list(struct resource_list_x *head,  		 struct pci_dev *dev, struct resource *res, -		 resource_size_t add_size) +		 resource_size_t add_size, resource_size_t min_align)  {  	struct resource_list_x *list = head;  	struct resource_list_x *ln = list->next; @@ -84,13 +85,16 @@ static void add_to_list(struct resource_list_x *head,  	tmp->end = res->end;  	tmp->flags = res->flags;  	tmp->add_size = add_size; +	tmp->min_align = min_align;  	list->next = tmp;  }  static void add_to_failed_list(struct resource_list_x *head,  				struct pci_dev *dev, struct resource *res)  { -	add_to_list(head, dev, res, 0); +	add_to_list(head, dev, res, +			0 /* dont care */, +			0 /* dont care */);  }  static void __dev_sort_resources(struct pci_dev *dev, @@ -121,18 +125,18 @@ static inline void reset_resource(struct resource *res)  }  /** - * adjust_resources_sorted() - satisfy any additional resource requests + * reassign_resources_sorted() - satisfy any additional resource requests   * - * @add_head : head of the list tracking requests requiring additional + * @realloc_head : head of the list tracking requests requiring additional   *             resources   * @head     : head of the list tracking requests with allocated   *             resources   * - * Walk through each element of the add_head and try to procure + * Walk through each element of the realloc_head and try to procure   * additional resources for the element, provided the element   * is in the head list.   */ -static void adjust_resources_sorted(struct resource_list_x *add_head, +static void reassign_resources_sorted(struct resource_list_x *realloc_head,  		struct resource_list *head)  {  	struct resource *res; @@ -141,8 +145,8 @@ static void adjust_resources_sorted(struct resource_list_x *add_head,  	resource_size_t add_size;  	int idx; -	prev = add_head; -	for (list = add_head->next; list;) { +	prev = realloc_head; +	for (list = realloc_head->next; list;) {  		res = list->res;  		/* skip resource that has been reset */  		if (!res->flags) @@ -159,13 +163,17 @@ static void adjust_resources_sorted(struct resource_list_x *add_head,  		idx = res - &list->dev->resource[0];  		add_size=list->add_size; -		if (!resource_size(res) && add_size) { -			 res->end = res->start + add_size - 1; -			 if(pci_assign_resource(list->dev, idx)) +		if (!resource_size(res)) { +			res->start = list->start; +			res->end = res->start + add_size - 1; +			if(pci_assign_resource(list->dev, idx))  				reset_resource(res); -		} else if (add_size) { -			adjust_resource(res, res->start, -				resource_size(res) + add_size); +		} else { +			resource_size_t align = list->min_align; +			res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); +			if (pci_reassign_resource(list->dev, idx, add_size, align)) +				dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n", +							res);  		}  out:  		tmp = list; @@ -210,16 +218,16 @@ static void assign_requested_resources_sorted(struct resource_list *head,  }  static void __assign_resources_sorted(struct resource_list *head, -				 struct resource_list_x *add_head, +				 struct resource_list_x *realloc_head,  				 struct resource_list_x *fail_head)  {  	/* Satisfy the must-have resource requests */  	assign_requested_resources_sorted(head, fail_head); -	/* Try to satisfy any additional nice-to-have resource +	/* Try to satisfy any additional optional resource  		requests */ -	if (add_head) -		adjust_resources_sorted(add_head, head); +	if (realloc_head) +		reassign_resources_sorted(realloc_head, head);  	free_list(resource_list, head);  } @@ -235,7 +243,7 @@ static void pdev_assign_resources_sorted(struct pci_dev *dev,  }  static void pbus_assign_resources_sorted(const struct pci_bus *bus, -					 struct resource_list_x *add_head, +					 struct resource_list_x *realloc_head,  					 struct resource_list_x *fail_head)  {  	struct pci_dev *dev; @@ -245,7 +253,7 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus,  	list_for_each_entry(dev, &bus->devices, bus_list)  		__dev_sort_resources(dev, &head); -	__assign_resources_sorted(&head, add_head, fail_head); +	__assign_resources_sorted(&head, realloc_head, fail_head);  }  void pci_setup_cardbus(struct pci_bus *bus) @@ -336,7 +344,6 @@ static void pci_setup_bridge_io(struct pci_bus *bus)  		/* Clear upper 16 bits of I/O base/limit. */  		io_upper16 = 0;  		l = 0x00f0; -		dev_info(&bridge->dev, "  bridge window [io  disabled]\n");  	}  	/* Temporarily disable the I/O range before updating PCI_IO_BASE. */  	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff); @@ -362,7 +369,6 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus)  		dev_info(&bridge->dev, "  bridge window %pR\n", res);  	} else {  		l = 0x0000fff0; -		dev_info(&bridge->dev, "  bridge window [mem disabled]\n");  	}  	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);  } @@ -393,7 +399,6 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)  		dev_info(&bridge->dev, "  bridge window %pR\n", res);  	} else {  		l = 0x0000fff0; -		dev_info(&bridge->dev, "  bridge window [mem pref disabled]\n");  	}  	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); @@ -543,13 +548,27 @@ static resource_size_t calculate_memsize(resource_size_t size,  	return size;  } +static resource_size_t get_res_add_size(struct resource_list_x *realloc_head, +					struct resource *res) +{ +	struct resource_list_x *list; + +	/* check if it is in realloc_head list */ +	for (list = realloc_head->next; list && list->res != res; +			list = list->next); +	if (list) +		return list->add_size; + +	return 0; +} +  /**   * pbus_size_io() - size the io window of a given bus   *   * @bus : the bus   * @min_size : the minimum io window that must to be allocated   * @add_size : additional optional io window - * @add_head : track the additional io window on this list + * @realloc_head : track the additional io window on this list   *   * Sizing the IO windows of the PCI-PCI bridge is trivial,   * since these windows have 4K granularity and the IO ranges @@ -557,11 +576,12 @@ static resource_size_t calculate_memsize(resource_size_t size,   * We must be careful with the ISA aliasing though.   */  static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size, -		resource_size_t add_size, struct resource_list_x *add_head) +		resource_size_t add_size, struct resource_list_x *realloc_head)  {  	struct pci_dev *dev;  	struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);  	unsigned long size = 0, size0 = 0, size1 = 0; +	resource_size_t children_add_size = 0;  	if (!b_res)   		return; @@ -582,11 +602,16 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,  				size += r_size;  			else  				size1 += r_size; + +			if (realloc_head) +				children_add_size += get_res_add_size(realloc_head, r);  		}  	}  	size0 = calculate_iosize(size, min_size, size1,  			resource_size(b_res), 4096); -	size1 = (!add_head || (add_head && !add_size)) ? size0 : +	if (children_add_size > add_size) +		add_size = children_add_size; +	size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :  		calculate_iosize(size, min_size+add_size, size1,  			resource_size(b_res), 4096);  	if (!size0 && !size1) { @@ -601,8 +626,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,  	b_res->start = 4096;  	b_res->end = b_res->start + size0 - 1;  	b_res->flags |= IORESOURCE_STARTALIGN; -	if (size1 > size0 && add_head) -		add_to_list(add_head, bus->self, b_res, size1-size0); +	if (size1 > size0 && realloc_head) +		add_to_list(realloc_head, bus->self, b_res, size1-size0, 4096);  }  /** @@ -611,7 +636,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,   * @bus : the bus   * @min_size : the minimum memory window that must to be allocated   * @add_size : additional optional memory window - * @add_head : track the additional memory window on this list + * @realloc_head : track the additional memory window on this list   *   * Calculate the size of the bus and minimal alignment which   * guarantees that all child resources fit in this size. @@ -619,7 +644,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,  static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,  			 unsigned long type, resource_size_t min_size,  			resource_size_t add_size, -			struct resource_list_x *add_head) +			struct resource_list_x *realloc_head)  {  	struct pci_dev *dev;  	resource_size_t min_align, align, size, size0, size1; @@ -627,6 +652,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,  	int order, max_order;  	struct resource *b_res = find_free_bus_resource(bus, type);  	unsigned int mem64_mask = 0; +	resource_size_t children_add_size = 0;  	if (!b_res)  		return 0; @@ -648,6 +674,16 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,  			if (r->parent || (r->flags & mask) != type)  				continue;  			r_size = resource_size(r); +#ifdef CONFIG_PCI_IOV +			/* put SRIOV requested res to the optional list */ +			if (realloc_head && i >= PCI_IOV_RESOURCES && +					i <= PCI_IOV_RESOURCE_END) { +				r->end = r->start - 1; +				add_to_list(realloc_head, dev, r, r_size, 0/* dont' care */); +				children_add_size += r_size; +				continue; +			} +#endif  			/* For bridges size != alignment */  			align = pci_resource_alignment(dev, r);  			order = __ffs(align) - 20; @@ -668,6 +704,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,  			if (order > max_order)  				max_order = order;  			mem64_mask &= r->flags & IORESOURCE_MEM_64; + +			if (realloc_head) +				children_add_size += get_res_add_size(realloc_head, r);  		}  	}  	align = 0; @@ -684,7 +723,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,  		align += aligns[order];  	}  	size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); -	size1 = (!add_head || (add_head && !add_size)) ? size0 : +	if (children_add_size > add_size) +		add_size = children_add_size; +	size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :  		calculate_memsize(size, min_size+add_size, 0,  				resource_size(b_res), min_align);  	if (!size0 && !size1) { @@ -698,12 +739,22 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,  	b_res->start = min_align;  	b_res->end = size0 + min_align - 1;  	b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask; -	if (size1 > size0 && add_head) -		add_to_list(add_head, bus->self, b_res, size1-size0); +	if (size1 > size0 && realloc_head) +		add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align);  	return 1;  } -static void pci_bus_size_cardbus(struct pci_bus *bus) +unsigned long pci_cardbus_resource_alignment(struct resource *res) +{ +	if (res->flags & IORESOURCE_IO) +		return pci_cardbus_io_size; +	if (res->flags & IORESOURCE_MEM) +		return pci_cardbus_mem_size; +	return 0; +} + +static void pci_bus_size_cardbus(struct pci_bus *bus, +			struct resource_list_x *realloc_head)  {  	struct pci_dev *bridge = bus->self;  	struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES]; @@ -714,12 +765,14 @@ static void pci_bus_size_cardbus(struct pci_bus *bus)  	 * a fixed amount of bus space for CardBus bridges.  	 */  	b_res[0].start = 0; -	b_res[0].end = pci_cardbus_io_size - 1;  	b_res[0].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN; +	if (realloc_head) +		add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size, 0 /* dont care */);  	b_res[1].start = 0; -	b_res[1].end = pci_cardbus_io_size - 1;  	b_res[1].flags |= IORESOURCE_IO | IORESOURCE_SIZEALIGN; +	if (realloc_head) +		add_to_list(realloc_head, bridge, b_res+1, pci_cardbus_io_size, 0 /* dont care */);  	/*  	 * Check whether prefetchable memory is supported @@ -739,21 +792,31 @@ static void pci_bus_size_cardbus(struct pci_bus *bus)  	 */  	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {  		b_res[2].start = 0; -		b_res[2].end = pci_cardbus_mem_size - 1;  		b_res[2].flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_SIZEALIGN; +		if (realloc_head) +			add_to_list(realloc_head, bridge, b_res+2, pci_cardbus_mem_size, 0 /* dont care */);  		b_res[3].start = 0; -		b_res[3].end = pci_cardbus_mem_size - 1;  		b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN; +		if (realloc_head) +			add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size, 0 /* dont care */);  	} else {  		b_res[3].start = 0; -		b_res[3].end = pci_cardbus_mem_size * 2 - 1;  		b_res[3].flags |= IORESOURCE_MEM | IORESOURCE_SIZEALIGN; +		if (realloc_head) +			add_to_list(realloc_head, bridge, b_res+3, pci_cardbus_mem_size * 2, 0 /* dont care */);  	} + +	/* set the size of the resource to zero, so that the resource does not +	 * get assigned during required-resource allocation cycle but gets assigned +	 * during the optional-resource allocation cycle. + 	 */ +	b_res[0].start = b_res[1].start = b_res[2].start = b_res[3].start = 1; +	b_res[0].end = b_res[1].end = b_res[2].end = b_res[3].end = 0;  }  void __ref __pci_bus_size_bridges(struct pci_bus *bus, -			struct resource_list_x *add_head) +			struct resource_list_x *realloc_head)  {  	struct pci_dev *dev;  	unsigned long mask, prefmask; @@ -766,12 +829,12 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,  		switch (dev->class >> 8) {  		case PCI_CLASS_BRIDGE_CARDBUS: -			pci_bus_size_cardbus(b); +			pci_bus_size_cardbus(b, realloc_head);  			break;  		case PCI_CLASS_BRIDGE_PCI:  		default: -			__pci_bus_size_bridges(b, add_head); +			__pci_bus_size_bridges(b, realloc_head);  			break;  		}  	} @@ -795,7 +858,7 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,  		 * Follow thru  		 */  	default: -		pbus_size_io(bus, 0, additional_io_size, add_head); +		pbus_size_io(bus, 0, additional_io_size, realloc_head);  		/* If the bridge supports prefetchable range, size it  		   separately. If it doesn't, or its prefetchable window  		   has already been allocated by arch code, try @@ -803,11 +866,11 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,  		   resources. */  		mask = IORESOURCE_MEM;  		prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; -		if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, add_head)) +		if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, realloc_head))  			mask = prefmask; /* Success, size non-prefetch only. */  		else  			additional_mem_size += additional_mem_size; -		pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, add_head); +		pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, realloc_head);  		break;  	}  } @@ -819,20 +882,20 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)  EXPORT_SYMBOL(pci_bus_size_bridges);  static void __ref __pci_bus_assign_resources(const struct pci_bus *bus, -					 struct resource_list_x *add_head, +					 struct resource_list_x *realloc_head,  					 struct resource_list_x *fail_head)  {  	struct pci_bus *b;  	struct pci_dev *dev; -	pbus_assign_resources_sorted(bus, add_head, fail_head); +	pbus_assign_resources_sorted(bus, realloc_head, fail_head);  	list_for_each_entry(dev, &bus->devices, bus_list) {  		b = dev->subordinate;  		if (!b)  			continue; -		__pci_bus_assign_resources(b, add_head, fail_head); +		__pci_bus_assign_resources(b, realloc_head, fail_head);  		switch (dev->class >> 8) {  		case PCI_CLASS_BRIDGE_PCI: @@ -1042,7 +1105,7 @@ void __init  pci_assign_unassigned_resources(void)  {  	struct pci_bus *bus; -	struct resource_list_x add_list; /* list of resources that +	struct resource_list_x realloc_list; /* list of resources that  					want additional resources */  	int tried_times = 0;  	enum release_type rel_type = leaf_only; @@ -1055,7 +1118,7 @@ pci_assign_unassigned_resources(void)  	head.next = NULL; -	add_list.next = NULL; +	realloc_list.next = NULL;  	pci_try_num = max_depth + 1;  	printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n", @@ -1065,12 +1128,12 @@ again:  	/* Depth first, calculate sizes and alignments of all  	   subordinate buses. */  	list_for_each_entry(bus, &pci_root_buses, node) -		__pci_bus_size_bridges(bus, &add_list); +		__pci_bus_size_bridges(bus, &realloc_list);  	/* Depth last, allocate resources and update the hardware. */  	list_for_each_entry(bus, &pci_root_buses, node) -		__pci_bus_assign_resources(bus, &add_list, &head); -	BUG_ON(add_list.next); +		__pci_bus_assign_resources(bus, &realloc_list, &head); +	BUG_ON(realloc_list.next);  	tried_times++;  	/* any device complain? */ diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c index eec9738f349..eb219a1d16f 100644 --- a/drivers/pci/setup-irq.c +++ b/drivers/pci/setup-irq.c @@ -21,7 +21,7 @@  static void __init  pdev_fixup_irq(struct pci_dev *dev,  	       u8 (*swizzle)(struct pci_dev *, u8 *), -	       int (*map_irq)(struct pci_dev *, u8, u8)) +	       int (*map_irq)(const struct pci_dev *, u8, u8))  {  	u8 pin, slot;  	int irq = 0; @@ -56,7 +56,7 @@ pdev_fixup_irq(struct pci_dev *dev,  void __init  pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *), -	       int (*map_irq)(struct pci_dev *, u8, u8)) +	       int (*map_irq)(const struct pci_dev *, u8, u8))  {  	struct pci_dev *dev = NULL;  	for_each_pci_dev(dev) diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index bc0e6eea0ff..51a9095c7da 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -74,8 +74,7 @@ void pci_update_resource(struct pci_dev *dev, int resno)  			resno, new, check);  	} -	if ((new & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) == -	    (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64)) { +	if (res->flags & IORESOURCE_MEM_64) {  		new = region.start >> 16 >> 16;  		pci_write_config_dword(dev, reg + 4, new);  		pci_read_config_dword(dev, reg + 4, &check); @@ -129,16 +128,16 @@ void pci_disable_bridge_window(struct pci_dev *dev)  }  #endif	/* CONFIG_PCI_QUIRKS */ + +  static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, -				 int resno) +		int resno, resource_size_t size, resource_size_t align)  {  	struct resource *res = dev->resource + resno; -	resource_size_t size, min, align; +	resource_size_t min;  	int ret; -	size = resource_size(res);  	min = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM; -	align = pci_resource_alignment(dev, res);  	/* First, try exact prefetching match.. */  	ret = pci_bus_alloc_resource(bus, res, size, align, min, @@ -155,56 +154,101 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,  		ret = pci_bus_alloc_resource(bus, res, size, align, min, 0,  					     pcibios_align_resource, dev);  	} +	return ret; +} -	if (ret < 0 && dev->fw_addr[resno]) { -		struct resource *root, *conflict; -		resource_size_t start, end; +static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,  +		int resno, resource_size_t size) +{ +	struct resource *root, *conflict; +	resource_size_t start, end; +	int ret = 0; -		/* -		 * If we failed to assign anything, let's try the address -		 * where firmware left it.  That at least has a chance of -		 * working, which is better than just leaving it disabled. -		 */ +	if (res->flags & IORESOURCE_IO) +		root = &ioport_resource; +	else +		root = &iomem_resource; + +	start = res->start; +	end = res->end; +	res->start = dev->fw_addr[resno]; +	res->end = res->start + size - 1; +	dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n", +		 resno, res); +	conflict = request_resource_conflict(root, res); +	if (conflict) { +		dev_info(&dev->dev, +			 "BAR %d: %pR conflicts with %s %pR\n", resno, +			 res, conflict->name, conflict); +		res->start = start; +		res->end = end; +		ret = 1; +	} +	return ret; +} -		if (res->flags & IORESOURCE_IO) -			root = &ioport_resource; +static int _pci_assign_resource(struct pci_dev *dev, int resno, int size, resource_size_t min_align) +{ +	struct resource *res = dev->resource + resno; +	struct pci_bus *bus; +	int ret; +	char *type; + +	bus = dev->bus; +	while ((ret = __pci_assign_resource(bus, dev, resno, size, min_align))) { +		if (!bus->parent || !bus->self->transparent) +			break; +		bus = bus->parent; +	} + +	if (ret) { +		if (res->flags & IORESOURCE_MEM) +			if (res->flags & IORESOURCE_PREFETCH) +				type = "mem pref"; +			else +				type = "mem"; +		else if (res->flags & IORESOURCE_IO) +			type = "io";  		else -			root = &iomem_resource; +			type = "unknown"; +		dev_info(&dev->dev, +			 "BAR %d: can't assign %s (size %#llx)\n", +			 resno, type, (unsigned long long) resource_size(res)); +	} + +	return ret; +} -		start = res->start; -		end = res->end; -		res->start = dev->fw_addr[resno]; -		res->end = res->start + size - 1; -		dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n", -			 resno, res); -		conflict = request_resource_conflict(root, res); -		if (conflict) { -			dev_info(&dev->dev, -				 "BAR %d: %pR conflicts with %s %pR\n", resno, -				 res, conflict->name, conflict); -			res->start = start; -			res->end = end; -		} else -			ret = 0; +int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsize, +			resource_size_t min_align) +{ +	struct resource *res = dev->resource + resno; +	resource_size_t new_size; +	int ret; + +	if (!res->parent) { +		dev_info(&dev->dev, "BAR %d: can't reassign an unassigned resouce %pR " +			 "\n", resno, res); +		return -EINVAL;  	} +	new_size = resource_size(res) + addsize + min_align; +	ret = _pci_assign_resource(dev, resno, new_size, min_align);  	if (!ret) {  		res->flags &= ~IORESOURCE_STARTALIGN;  		dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);  		if (resno < PCI_BRIDGE_RESOURCES)  			pci_update_resource(dev, resno);  	} -  	return ret;  }  int pci_assign_resource(struct pci_dev *dev, int resno)  {  	struct resource *res = dev->resource + resno; -	resource_size_t align; +	resource_size_t align, size;  	struct pci_bus *bus;  	int ret; -	char *type;  	align = pci_resource_alignment(dev, res);  	if (!align) { @@ -214,34 +258,27 @@ int pci_assign_resource(struct pci_dev *dev, int resno)  	}  	bus = dev->bus; -	while ((ret = __pci_assign_resource(bus, dev, resno))) { -		if (bus->parent && bus->self->transparent) -			bus = bus->parent; -		else -			bus = NULL; -		if (bus) -			continue; -		break; -	} +	size = resource_size(res); +	ret = _pci_assign_resource(dev, resno, size, align); -	if (ret) { -		if (res->flags & IORESOURCE_MEM) -			if (res->flags & IORESOURCE_PREFETCH) -				type = "mem pref"; -			else -				type = "mem"; -		else if (res->flags & IORESOURCE_IO) -			type = "io"; -		else -			type = "unknown"; -		dev_info(&dev->dev, -			 "BAR %d: can't assign %s (size %#llx)\n", -			 resno, type, (unsigned long long) resource_size(res)); -	} +	/* +	 * If we failed to assign anything, let's try the address +	 * where firmware left it.  That at least has a chance of +	 * working, which is better than just leaving it disabled. +	 */ +	if (ret < 0 && dev->fw_addr[resno]) +		ret = pci_revert_fw_address(res, dev, resno, size); +	if (!ret) { +		res->flags &= ~IORESOURCE_STARTALIGN; +		dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res); +		if (resno < PCI_BRIDGE_RESOURCES) +			pci_update_resource(dev, resno); +	}  	return ret;  } +  /* Sort resources by alignment */  void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)  { diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 492b7d807fe..6fa215a3861 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -16,7 +16,7 @@  #include <xen/interface/io/pciif.h>  #include <asm/xen/pci.h>  #include <linux/interrupt.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include <linux/workqueue.h>  #include <linux/bitops.h>  #include <linux/time.h>  |