Merge branch 'linus' into release

Conflicts:
	arch/x86/kernel/acpi/sleep.c

Signed-off-by: Len Brown <[email protected]>
This commit is contained in:
Len Brown 2011-03-23 02:34:54 -04:00
commit 02e2407858
6711 changed files with 449251 additions and 224171 deletions

View file

@ -87,3 +87,5 @@ config PCI_IOAPIC
depends on ACPI
depends on HOTPLUG
default y
select NLS if (DMI || ACPI)

View file

@ -42,6 +42,7 @@ obj-$(CONFIG_PCI_IOV) += iov.o
obj-$(CONFIG_X86) += setup-bus.o
obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
obj-$(CONFIG_UNICORE32) += setup-bus.o setup-irq.o
obj-$(CONFIG_PARISC) += setup-bus.o
obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o
obj-$(CONFIG_PPC) += setup-bus.o
@ -53,8 +54,9 @@ obj-$(CONFIG_TILE) += setup-bus.o setup-irq.o
#
# ACPI Related PCI FW Functions
# ACPI _DSM provided firmware instance and string name
#
obj-$(CONFIG_ACPI) += pci-acpi.o
obj-$(CONFIG_ACPI) += pci-acpi.o pci-label.o
# SMBIOS provided firmware instance and labels
obj-$(CONFIG_DMI) += pci-label.o

View file

@ -212,6 +212,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
pdev = pci_get_slot(pbus, PCI_DEVFN(device, function));
if (pdev) {
pdev->current_state = PCI_D0;
slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
pci_dev_put(pdev);
}

View file

@ -431,7 +431,7 @@ static void pci_device_shutdown(struct device *dev)
pci_msix_shutdown(pci_dev);
}
#ifdef CONFIG_PM_OPS
#ifdef CONFIG_PM
/* Auxiliary functions used for system resume and run-time resume. */
@ -1059,7 +1059,7 @@ static int pci_pm_runtime_idle(struct device *dev)
#endif /* !CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_OPS
#ifdef CONFIG_PM
const struct dev_pm_ops pci_dev_pm_ops = {
.prepare = pci_pm_prepare,

View file

@ -5,6 +5,13 @@
* by Narendra K <Narendra_K@dell.com>,
* Jordan Hargrave <Jordan_Hargrave@dell.com>
*
* PCI Firmware Specification Revision 3.1 section 4.6.7 (DSM for Naming a
* PCI or PCI Express Device Under Operating Systems) defines an instance
* number and string name. This code retrieves them and exports them to sysfs.
* If the system firmware does not provide the ACPI _DSM (Device Specific
* Method), then the SMBIOS type 41 instance number and string is exported to
* sysfs.
*
* SMBIOS defines type 41 for onboard pci devices. This code retrieves
* the instance number and string from the type 41 record and exports
* it to sysfs.
@ -19,8 +26,29 @@
#include <linux/pci_ids.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/nls.h>
#include <linux/acpi.h>
#include <linux/pci-acpi.h>
#include <acpi/acpi_bus.h>
#include "pci.h"
#define DEVICE_LABEL_DSM 0x07
#ifndef CONFIG_DMI
static inline int
pci_create_smbiosname_file(struct pci_dev *pdev)
{
return -1;
}
static inline void
pci_remove_smbiosname_file(struct pci_dev *pdev)
{
}
#else
enum smbios_attr_enum {
SMBIOS_ATTR_NONE = 0,
SMBIOS_ATTR_LABEL_SHOW,
@ -120,9 +148,7 @@ static struct attribute_group smbios_attr_group = {
static int
pci_create_smbiosname_file(struct pci_dev *pdev)
{
if (!sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group))
return 0;
return -ENODEV;
return sysfs_create_group(&pdev->dev.kobj, &smbios_attr_group);
}
static void
@ -131,13 +157,227 @@ pci_remove_smbiosname_file(struct pci_dev *pdev)
sysfs_remove_group(&pdev->dev.kobj, &smbios_attr_group);
}
#endif
#ifndef CONFIG_ACPI
static inline int
pci_create_acpi_index_label_files(struct pci_dev *pdev)
{
return -1;
}
static inline int
pci_remove_acpi_index_label_files(struct pci_dev *pdev)
{
return -1;
}
static inline bool
device_has_dsm(struct device *dev)
{
return false;
}
#else
static const char device_label_dsm_uuid[] = {
0xD0, 0x37, 0xC9, 0xE5, 0x53, 0x35, 0x7A, 0x4D,
0x91, 0x17, 0xEA, 0x4D, 0x19, 0xC3, 0x43, 0x4D
};
enum acpi_attr_enum {
ACPI_ATTR_NONE = 0,
ACPI_ATTR_LABEL_SHOW,
ACPI_ATTR_INDEX_SHOW,
};
static void dsm_label_utf16s_to_utf8s(union acpi_object *obj, char *buf)
{
int len;
len = utf16s_to_utf8s((const wchar_t *)obj->
package.elements[1].string.pointer,
obj->package.elements[1].string.length,
UTF16_LITTLE_ENDIAN,
buf, PAGE_SIZE);
buf[len] = '\n';
}
static int
dsm_get_label(acpi_handle handle, int func,
struct acpi_buffer *output,
char *buf, enum acpi_attr_enum attribute)
{
struct acpi_object_list input;
union acpi_object params[4];
union acpi_object *obj;
int len = 0;
int err;
input.count = 4;
input.pointer = params;
params[0].type = ACPI_TYPE_BUFFER;
params[0].buffer.length = sizeof(device_label_dsm_uuid);
params[0].buffer.pointer = (char *)device_label_dsm_uuid;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = 0x02;
params[2].type = ACPI_TYPE_INTEGER;
params[2].integer.value = func;
params[3].type = ACPI_TYPE_PACKAGE;
params[3].package.count = 0;
params[3].package.elements = NULL;
err = acpi_evaluate_object(handle, "_DSM", &input, output);
if (err)
return -1;
obj = (union acpi_object *)output->pointer;
switch (obj->type) {
case ACPI_TYPE_PACKAGE:
if (obj->package.count != 2)
break;
len = obj->package.elements[0].integer.value;
if (buf) {
if (attribute == ACPI_ATTR_INDEX_SHOW)
scnprintf(buf, PAGE_SIZE, "%llu\n",
obj->package.elements[0].integer.value);
else if (attribute == ACPI_ATTR_LABEL_SHOW)
dsm_label_utf16s_to_utf8s(obj, buf);
kfree(output->pointer);
return strlen(buf);
}
kfree(output->pointer);
return len;
break;
default:
kfree(output->pointer);
}
return -1;
}
static bool
device_has_dsm(struct device *dev)
{
acpi_handle handle;
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
handle = DEVICE_ACPI_HANDLE(dev);
if (!handle)
return FALSE;
if (dsm_get_label(handle, DEVICE_LABEL_DSM, &output, NULL,
ACPI_ATTR_NONE) > 0)
return TRUE;
return FALSE;
}
static mode_t
acpi_index_string_exist(struct kobject *kobj, struct attribute *attr, int n)
{
struct device *dev;
dev = container_of(kobj, struct device, kobj);
if (device_has_dsm(dev))
return S_IRUGO;
return 0;
}
static ssize_t
acpilabel_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_handle handle;
int length;
handle = DEVICE_ACPI_HANDLE(dev);
if (!handle)
return -1;
length = dsm_get_label(handle, DEVICE_LABEL_DSM,
&output, buf, ACPI_ATTR_LABEL_SHOW);
if (length < 1)
return -1;
return length;
}
static ssize_t
acpiindex_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_handle handle;
int length;
handle = DEVICE_ACPI_HANDLE(dev);
if (!handle)
return -1;
length = dsm_get_label(handle, DEVICE_LABEL_DSM,
&output, buf, ACPI_ATTR_INDEX_SHOW);
if (length < 0)
return -1;
return length;
}
static struct device_attribute acpi_attr_label = {
.attr = {.name = "label", .mode = 0444},
.show = acpilabel_show,
};
static struct device_attribute acpi_attr_index = {
.attr = {.name = "acpi_index", .mode = 0444},
.show = acpiindex_show,
};
static struct attribute *acpi_attributes[] = {
&acpi_attr_label.attr,
&acpi_attr_index.attr,
NULL,
};
static struct attribute_group acpi_attr_group = {
.attrs = acpi_attributes,
.is_visible = acpi_index_string_exist,
};
static int
pci_create_acpi_index_label_files(struct pci_dev *pdev)
{
return sysfs_create_group(&pdev->dev.kobj, &acpi_attr_group);
}
static int
pci_remove_acpi_index_label_files(struct pci_dev *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &acpi_attr_group);
return 0;
}
#endif
void pci_create_firmware_label_files(struct pci_dev *pdev)
{
if (!pci_create_smbiosname_file(pdev))
;
if (device_has_dsm(&pdev->dev))
pci_create_acpi_index_label_files(pdev);
else
pci_create_smbiosname_file(pdev);
}
void pci_remove_firmware_label_files(struct pci_dev *pdev)
{
pci_remove_smbiosname_file(pdev);
if (device_has_dsm(&pdev->dev))
pci_remove_acpi_index_label_files(pdev);
else
pci_remove_smbiosname_file(pdev);
}

View file

@ -1088,7 +1088,7 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev)
attr->write = write_vpd_attr;
retval = sysfs_create_bin_file(&dev->dev.kobj, attr);
if (retval) {
kfree(dev->vpd->attr);
kfree(attr);
return retval;
}
dev->vpd->attr = attr;

View file

@ -11,7 +11,7 @@
extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
#ifndef CONFIG_DMI
#if !defined(CONFIG_DMI) && !defined(CONFIG_ACPI)
static inline void pci_create_firmware_label_files(struct pci_dev *pdev)
{ return; }
static inline void pci_remove_firmware_label_files(struct pci_dev *pdev)

View file

@ -27,6 +27,10 @@
#include <linux/stddef.h>
#include "aerdrv.h"
/* Override the existing corrected and uncorrected error masks */
static int aer_mask_override;
module_param(aer_mask_override, bool, 0);
struct aer_error_inj {
u8 bus;
u8 dev;
@ -322,7 +326,7 @@ static int aer_inject(struct aer_error_inj *einj)
unsigned long flags;
unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn);
int pos_cap_err, rp_pos_cap_err;
u32 sever, cor_mask, uncor_mask;
u32 sever, cor_mask, uncor_mask, cor_mask_orig, uncor_mask_orig;
int ret = 0;
dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn);
@ -361,6 +365,18 @@ static int aer_inject(struct aer_error_inj *einj)
goto out_put;
}
if (aer_mask_override) {
cor_mask_orig = cor_mask;
cor_mask &= !(einj->cor_status);
pci_write_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK,
cor_mask);
uncor_mask_orig = uncor_mask;
uncor_mask &= !(einj->uncor_status);
pci_write_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK,
uncor_mask);
}
spin_lock_irqsave(&inject_lock, flags);
err = __find_aer_error_by_dev(dev);
@ -378,14 +394,16 @@ static int aer_inject(struct aer_error_inj *einj)
err->header_log2 = einj->header_log2;
err->header_log3 = einj->header_log3;
if (einj->cor_status && !(einj->cor_status & ~cor_mask)) {
if (!aer_mask_override && einj->cor_status &&
!(einj->cor_status & ~cor_mask)) {
ret = -EINVAL;
printk(KERN_WARNING "The correctable error(s) is masked "
"by device\n");
spin_unlock_irqrestore(&inject_lock, flags);
goto out_put;
}
if (einj->uncor_status && !(einj->uncor_status & ~uncor_mask)) {
if (!aer_mask_override && einj->uncor_status &&
!(einj->uncor_status & ~uncor_mask)) {
ret = -EINVAL;
printk(KERN_WARNING "The uncorrectable error(s) is masked "
"by device\n");
@ -425,6 +443,13 @@ static int aer_inject(struct aer_error_inj *einj)
}
spin_unlock_irqrestore(&inject_lock, flags);
if (aer_mask_override) {
pci_write_config_dword(dev, pos_cap_err + PCI_ERR_COR_MASK,
cor_mask_orig);
pci_write_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_MASK,
uncor_mask_orig);
}
ret = pci_bus_set_aer_ops(dev->bus);
if (ret)
goto out_put;

View file

@ -764,6 +764,8 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
if (pci_find_bus(pci_domain_nr(bus), max+1))
goto out;
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)
@ -777,7 +779,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
buses &= ~0xff000000;
buses |= CARDBUS_LATENCY_TIMER << 24;
}
/*
* We need to blast all three values with a single write.
*/

View file

@ -533,6 +533,17 @@ static void __devinit quirk_piix4_acpi(struct pci_dev *dev)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, quirk_piix4_acpi);
#define ICH_PMBASE 0x40
#define ICH_ACPI_CNTL 0x44
#define ICH4_ACPI_EN 0x10
#define ICH6_ACPI_EN 0x80
#define ICH4_GPIOBASE 0x58
#define ICH4_GPIO_CNTL 0x5c
#define ICH4_GPIO_EN 0x10
#define ICH6_GPIOBASE 0x48
#define ICH6_GPIO_CNTL 0x4c
#define ICH6_GPIO_EN 0x10
/*
* ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at
* 0x40 (128 bytes of ACPI, GPIO & TCO registers)
@ -541,12 +552,33 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, qui
static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev)
{
u32 region;
u8 enable;
pci_read_config_dword(dev, 0x40, &region);
quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, "ICH4 ACPI/GPIO/TCO");
/*
* The check for PCIBIOS_MIN_IO is to ensure we won't create a conflict
* with low legacy (and fixed) ports. We don't know the decoding
* priority and can't tell whether the legacy device or the one created
* here is really at that address. This happens on boards with broken
* BIOSes.
*/
pci_read_config_dword(dev, 0x58, &region);
quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH4 GPIO");
pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
if (enable & ICH4_ACPI_EN) {
pci_read_config_dword(dev, ICH_PMBASE, &region);
region &= PCI_BASE_ADDRESS_IO_MASK;
if (region >= PCIBIOS_MIN_IO)
quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES,
"ICH4 ACPI/GPIO/TCO");
}
pci_read_config_byte(dev, ICH4_GPIO_CNTL, &enable);
if (enable & ICH4_GPIO_EN) {
pci_read_config_dword(dev, ICH4_GPIOBASE, &region);
region &= PCI_BASE_ADDRESS_IO_MASK;
if (region >= PCIBIOS_MIN_IO)
quirk_io_region(dev, region, 64,
PCI_BRIDGE_RESOURCES + 1, "ICH4 GPIO");
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi);
@ -562,12 +594,25 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, qui
static void __devinit ich6_lpc_acpi_gpio(struct pci_dev *dev)
{
u32 region;
u8 enable;
pci_read_config_dword(dev, 0x40, &region);
quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES, "ICH6 ACPI/GPIO/TCO");
pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
if (enable & ICH6_ACPI_EN) {
pci_read_config_dword(dev, ICH_PMBASE, &region);
region &= PCI_BASE_ADDRESS_IO_MASK;
if (region >= PCIBIOS_MIN_IO)
quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES,
"ICH6 ACPI/GPIO/TCO");
}
pci_read_config_dword(dev, 0x48, &region);
quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH6 GPIO");
pci_read_config_byte(dev, ICH6_GPIO_CNTL, &enable);
if (enable & ICH4_GPIO_EN) {
pci_read_config_dword(dev, ICH6_GPIOBASE, &region);
region &= PCI_BASE_ADDRESS_IO_MASK;
if (region >= PCIBIOS_MIN_IO)
quirk_io_region(dev, region, 64,
PCI_BRIDGE_RESOURCES + 1, "ICH6 GPIO");
}
}
static void __devinit ich6_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name, int dynsize)
@ -2618,58 +2663,6 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x4375,
#endif /* CONFIG_PCI_MSI */
#ifdef CONFIG_PCI_IOV
/*
* For Intel 82576 SR-IOV NIC, if BIOS doesn't allocate resources for the
* SR-IOV BARs, zero the Flash BAR and program the SR-IOV BARs to use the
* old Flash Memory Space.
*/
static void __devinit quirk_i82576_sriov(struct pci_dev *dev)
{
int pos, flags;
u32 bar, start, size;
if (PAGE_SIZE > 0x10000)
return;
flags = pci_resource_flags(dev, 0);
if ((flags & PCI_BASE_ADDRESS_SPACE) !=
PCI_BASE_ADDRESS_SPACE_MEMORY ||
(flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) !=
PCI_BASE_ADDRESS_MEM_TYPE_32)
return;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);
if (!pos)
return;
pci_read_config_dword(dev, pos + PCI_SRIOV_BAR, &bar);
if (bar & PCI_BASE_ADDRESS_MEM_MASK)
return;
start = pci_resource_start(dev, 1);
size = pci_resource_len(dev, 1);
if (!start || size != 0x400000 || start & (size - 1))
return;
pci_resource_flags(dev, 1) = 0;
pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0);
pci_write_config_dword(dev, pos + PCI_SRIOV_BAR, start);
pci_write_config_dword(dev, pos + PCI_SRIOV_BAR + 12, start + size / 2);
dev_info(&dev->dev, "use Flash Memory Space for SR-IOV BARs\n");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10c9, quirk_i82576_sriov);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e6, quirk_i82576_sriov);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e7, quirk_i82576_sriov);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x10e8, quirk_i82576_sriov);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x150a, quirk_i82576_sriov);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x150d, quirk_i82576_sriov);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1518, quirk_i82576_sriov);
#endif /* CONFIG_PCI_IOV */
/* Allow manual resource allocation for PCI hotplug bridges
* via pci=hpmemsize=nnM and pci=hpiosize=nnM parameters. For
* some PCI-PCI hotplug bridges, like PLX 6254 (former HINT HB6),

View file

@ -33,11 +33,32 @@ struct resource_list_x {
struct pci_dev *dev;
resource_size_t start;
resource_size_t end;
resource_size_t add_size;
unsigned long flags;
};
static void add_to_failed_list(struct resource_list_x *head,
struct pci_dev *dev, struct resource *res)
#define free_list(type, head) do { \
struct type *list, *tmp; \
for (list = (head)->next; list;) { \
tmp = list; \
list = list->next; \
kfree(tmp); \
} \
(head)->next = NULL; \
} while (0)
/**
* add_to_list() - add a new resource tracker to the list
* @head: Head of the list
* @dev: device corresponding to which the resource
* belongs
* @res: The resource to be tracked
* @add_size: additional size to be optionally added
* to the resource
*/
static void add_to_list(struct resource_list_x *head,
struct pci_dev *dev, struct resource *res,
resource_size_t add_size)
{
struct resource_list_x *list = head;
struct resource_list_x *ln = list->next;
@ -45,7 +66,7 @@ static void add_to_failed_list(struct resource_list_x *head,
tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp) {
pr_warning("add_to_failed_list: kmalloc() failed!\n");
pr_warning("add_to_list: kmalloc() failed!\n");
return;
}
@ -55,20 +76,14 @@ static void add_to_failed_list(struct resource_list_x *head,
tmp->start = res->start;
tmp->end = res->end;
tmp->flags = res->flags;
tmp->add_size = add_size;
list->next = tmp;
}
static void free_failed_list(struct resource_list_x *head)
static void add_to_failed_list(struct resource_list_x *head,
struct pci_dev *dev, struct resource *res)
{
struct resource_list_x *list, *tmp;
for (list = head->next; list;) {
tmp = list;
list = list->next;
kfree(tmp);
}
head->next = NULL;
add_to_list(head, dev, res, 0);
}
static void __dev_sort_resources(struct pci_dev *dev,
@ -91,18 +106,88 @@ static void __dev_sort_resources(struct pci_dev *dev,
pdev_sort_resources(dev, head);
}
static void __assign_resources_sorted(struct resource_list *head,
static inline void reset_resource(struct resource *res)
{
res->start = 0;
res->end = 0;
res->flags = 0;
}
/**
* adjust_resources_sorted() - satisfy any additional resource requests
*
* @add_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
* additional resources for the element, provided the element
* is in the head list.
*/
static void adjust_resources_sorted(struct resource_list_x *add_head,
struct resource_list *head)
{
struct resource *res;
struct resource_list_x *list, *tmp, *prev;
struct resource_list *hlist;
resource_size_t add_size;
int idx;
prev = add_head;
for (list = add_head->next; list;) {
res = list->res;
/* skip resource that has been reset */
if (!res->flags)
goto out;
/* skip this resource if not found in head list */
for (hlist = head->next; hlist && hlist->res != res;
hlist = hlist->next);
if (!hlist) { /* just skip */
prev = list;
list = list->next;
continue;
}
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))
reset_resource(res);
} else if (add_size) {
adjust_resource(res, res->start,
resource_size(res) + add_size);
}
out:
tmp = list;
prev->next = list = list->next;
kfree(tmp);
}
}
/**
* assign_requested_resources_sorted() - satisfy resource requests
*
* @head : head of the list tracking requests for resources
* @failed_list : head of the list tracking requests that could
* not be allocated
*
* Satisfy resource requests of each element in the list. Add
* requests that could not satisfied to the failed_list.
*/
static void assign_requested_resources_sorted(struct resource_list *head,
struct resource_list_x *fail_head)
{
struct resource *res;
struct resource_list *list, *tmp;
struct resource_list *list;
int idx;
for (list = head->next; list;) {
for (list = head->next; list; list = list->next) {
res = list->res;
idx = res - &list->dev->resource[0];
if (pci_assign_resource(list->dev, idx)) {
if (resource_size(res) && pci_assign_resource(list->dev, idx)) {
if (fail_head && !pci_is_root_bus(list->dev->bus)) {
/*
* if the failed res is for ROM BAR, and it will
@ -112,16 +197,25 @@ static void __assign_resources_sorted(struct resource_list *head,
(!(res->flags & IORESOURCE_ROM_ENABLE))))
add_to_failed_list(fail_head, list->dev, res);
}
res->start = 0;
res->end = 0;
res->flags = 0;
reset_resource(res);
}
tmp = list;
list = list->next;
kfree(tmp);
}
}
static void __assign_resources_sorted(struct resource_list *head,
struct resource_list_x *add_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
requests */
if (add_head)
adjust_resources_sorted(add_head, head);
free_list(resource_list, head);
}
static void pdev_assign_resources_sorted(struct pci_dev *dev,
struct resource_list_x *fail_head)
{
@ -129,11 +223,12 @@ static void pdev_assign_resources_sorted(struct pci_dev *dev,
head.next = NULL;
__dev_sort_resources(dev, &head);
__assign_resources_sorted(&head, fail_head);
__assign_resources_sorted(&head, NULL, fail_head);
}
static void pbus_assign_resources_sorted(const struct pci_bus *bus,
struct resource_list_x *add_head,
struct resource_list_x *fail_head)
{
struct pci_dev *dev;
@ -143,7 +238,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, fail_head);
__assign_resources_sorted(&head, add_head, fail_head);
}
void pci_setup_cardbus(struct pci_bus *bus)
@ -404,15 +499,62 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon
return NULL;
}
/* Sizing the IO windows of the PCI-PCI bridge is trivial,
since these windows have 4K granularity and the IO ranges
of non-bridge PCI devices are limited to 256 bytes.
We must be careful with the ISA aliasing though. */
static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size)
static resource_size_t calculate_iosize(resource_size_t size,
resource_size_t min_size,
resource_size_t size1,
resource_size_t old_size,
resource_size_t align)
{
if (size < min_size)
size = min_size;
if (old_size == 1 )
old_size = 0;
/* To be fixed in 2.5: we should have sort of HAVE_ISA
flag in the struct pci_bus. */
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
size = (size & 0xff) + ((size & ~0xffUL) << 2);
#endif
size = ALIGN(size + size1, align);
if (size < old_size)
size = old_size;
return size;
}
static resource_size_t calculate_memsize(resource_size_t size,
resource_size_t min_size,
resource_size_t size1,
resource_size_t old_size,
resource_size_t align)
{
if (size < min_size)
size = min_size;
if (old_size == 1 )
old_size = 0;
if (size < old_size)
size = old_size;
size = ALIGN(size + size1, align);
return size;
}
/**
* 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
*
* Sizing the IO windows of the PCI-PCI bridge is trivial,
* since these windows have 4K granularity and the IO ranges
* of non-bridge PCI devices are limited to 256 bytes.
* 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)
{
struct pci_dev *dev;
struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
unsigned long size = 0, size1 = 0, old_size;
unsigned long size = 0, size0 = 0, size1 = 0;
if (!b_res)
return;
@ -435,20 +577,12 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size)
size1 += r_size;
}
}
if (size < min_size)
size = min_size;
old_size = resource_size(b_res);
if (old_size == 1)
old_size = 0;
/* To be fixed in 2.5: we should have sort of HAVE_ISA
flag in the struct pci_bus. */
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
size = (size & 0xff) + ((size & ~0xffUL) << 2);
#endif
size = ALIGN(size + size1, 4096);
if (size < old_size)
size = old_size;
if (!size) {
size0 = calculate_iosize(size, min_size, size1,
resource_size(b_res), 4096);
size1 = !add_size? size0:
calculate_iosize(size, min_size+add_size, size1,
resource_size(b_res), 4096);
if (!size0 && !size1) {
if (b_res->start || b_res->end)
dev_info(&bus->self->dev, "disabling bridge window "
"%pR to [bus %02x-%02x] (unused)\n", b_res,
@ -458,17 +592,30 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size)
}
/* Alignment of the IO window is always 4K */
b_res->start = 4096;
b_res->end = b_res->start + size - 1;
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);
}
/* Calculate the size of the bus and minimal alignment which
guarantees that all child resources fit in this size. */
/**
* pbus_size_mem() - size the memory window of a given bus
*
* @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
*
* Calculate the size of the bus and minimal alignment which
* guarantees that all child resources fit in this size.
*/
static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
unsigned long type, resource_size_t min_size)
unsigned long type, resource_size_t min_size,
resource_size_t add_size,
struct resource_list_x *add_head)
{
struct pci_dev *dev;
resource_size_t min_align, align, size, old_size;
resource_size_t min_align, align, size, size0, size1;
resource_size_t aligns[12]; /* Alignments from 1Mb to 2Gb */
int order, max_order;
struct resource *b_res = find_free_bus_resource(bus, type);
@ -516,14 +663,6 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
mem64_mask &= r->flags & IORESOURCE_MEM_64;
}
}
if (size < min_size)
size = min_size;
old_size = resource_size(b_res);
if (old_size == 1)
old_size = 0;
if (size < old_size)
size = old_size;
align = 0;
min_align = 0;
for (order = 0; order <= max_order; order++) {
@ -537,8 +676,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
min_align = align1 >> 1;
align += aligns[order];
}
size = ALIGN(size, min_align);
if (!size) {
size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), align);
size1 = !add_size ? size :
calculate_memsize(size, min_size+add_size, 0,
resource_size(b_res), align);
if (!size0 && !size1) {
if (b_res->start || b_res->end)
dev_info(&bus->self->dev, "disabling bridge window "
"%pR to [bus %02x-%02x] (unused)\n", b_res,
@ -547,9 +689,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
return 1;
}
b_res->start = min_align;
b_res->end = size + min_align - 1;
b_res->flags |= IORESOURCE_STARTALIGN;
b_res->flags |= mem64_mask;
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);
return 1;
}
@ -602,11 +745,12 @@ static void pci_bus_size_cardbus(struct pci_bus *bus)
}
}
void __ref pci_bus_size_bridges(struct pci_bus *bus)
void __ref __pci_bus_size_bridges(struct pci_bus *bus,
struct resource_list_x *add_head)
{
struct pci_dev *dev;
unsigned long mask, prefmask;
resource_size_t min_mem_size = 0, min_io_size = 0;
resource_size_t additional_mem_size = 0, additional_io_size = 0;
list_for_each_entry(dev, &bus->devices, bus_list) {
struct pci_bus *b = dev->subordinate;
@ -620,7 +764,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
case PCI_CLASS_BRIDGE_PCI:
default:
pci_bus_size_bridges(b);
__pci_bus_size_bridges(b, add_head);
break;
}
}
@ -637,11 +781,14 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
case PCI_CLASS_BRIDGE_PCI:
pci_bridge_check_ranges(bus);
if (bus->self->is_hotplug_bridge) {
min_io_size = pci_hotplug_io_size;
min_mem_size = pci_hotplug_mem_size;
additional_io_size = pci_hotplug_io_size;
additional_mem_size = pci_hotplug_mem_size;
}
/*
* Follow thru
*/
default:
pbus_size_io(bus, min_io_size);
pbus_size_io(bus, 0, additional_io_size, add_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
@ -649,30 +796,36 @@ 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, min_mem_size))
if (pbus_size_mem(bus, prefmask, prefmask, 0, additional_mem_size, add_head))
mask = prefmask; /* Success, size non-prefetch only. */
else
min_mem_size += min_mem_size;
pbus_size_mem(bus, mask, IORESOURCE_MEM, min_mem_size);
additional_mem_size += additional_mem_size;
pbus_size_mem(bus, mask, IORESOURCE_MEM, 0, additional_mem_size, add_head);
break;
}
}
void __ref pci_bus_size_bridges(struct pci_bus *bus)
{
__pci_bus_size_bridges(bus, NULL);
}
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 *fail_head)
{
struct pci_bus *b;
struct pci_dev *dev;
pbus_assign_resources_sorted(bus, fail_head);
pbus_assign_resources_sorted(bus, add_head, fail_head);
list_for_each_entry(dev, &bus->devices, bus_list) {
b = dev->subordinate;
if (!b)
continue;
__pci_bus_assign_resources(b, fail_head);
__pci_bus_assign_resources(b, add_head, fail_head);
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
@ -694,7 +847,7 @@ static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
void __ref pci_bus_assign_resources(const struct pci_bus *bus)
{
__pci_bus_assign_resources(bus, NULL);
__pci_bus_assign_resources(bus, NULL, NULL);
}
EXPORT_SYMBOL(pci_bus_assign_resources);
@ -709,7 +862,7 @@ static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
if (!b)
return;
__pci_bus_assign_resources(b, fail_head);
__pci_bus_assign_resources(b, NULL, fail_head);
switch (bridge->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
@ -842,17 +995,21 @@ void __init
pci_assign_unassigned_resources(void)
{
struct pci_bus *bus;
struct resource_list_x add_list; /* list of resources that
want additional resources */
add_list.next = NULL;
/* Depth first, calculate sizes and alignments of all
subordinate buses. */
list_for_each_entry(bus, &pci_root_buses, node) {
pci_bus_size_bridges(bus);
__pci_bus_size_bridges(bus, &add_list);
}
/* Depth last, allocate resources and update the hardware. */
list_for_each_entry(bus, &pci_root_buses, node) {
pci_bus_assign_resources(bus);
__pci_bus_assign_resources(bus, &add_list, NULL);
pci_enable_bridges(bus);
}
BUG_ON(add_list.next);
/* dump the resource on buses */
list_for_each_entry(bus, &pci_root_buses, node) {
@ -882,7 +1039,7 @@ again:
if (tried_times >= 2) {
/* still fail, don't need to try more */
free_failed_list(&head);
free_list(resource_list_x, &head);
goto enable_all;
}
@ -913,7 +1070,7 @@ again:
list = list->next;
}
free_failed_list(&head);
free_list(resource_list_x, &head);
goto again;

View file

@ -243,7 +243,7 @@ struct pci_ops pcifront_bus_ops = {
#ifdef CONFIG_PCI_MSI
static int pci_frontend_enable_msix(struct pci_dev *dev,
int **vector, int nvec)
int vector[], int nvec)
{
int err;
int i;
@ -277,18 +277,24 @@ static int pci_frontend_enable_msix(struct pci_dev *dev,
if (likely(!err)) {
if (likely(!op.value)) {
/* we get the result */
for (i = 0; i < nvec; i++)
*(*vector+i) = op.msix_entries[i].vector;
return 0;
for (i = 0; i < nvec; i++) {
if (op.msix_entries[i].vector <= 0) {
dev_warn(&dev->dev, "MSI-X entry %d is invalid: %d!\n",
i, op.msix_entries[i].vector);
err = -EINVAL;
vector[i] = -1;
continue;
}
vector[i] = op.msix_entries[i].vector;
}
} else {
printk(KERN_DEBUG "enable msix get value %x\n",
op.value);
return op.value;
}
} else {
dev_err(&dev->dev, "enable msix get err %x\n", err);
return err;
}
return err;
}
static void pci_frontend_disable_msix(struct pci_dev *dev)
@ -310,7 +316,7 @@ static void pci_frontend_disable_msix(struct pci_dev *dev)
dev_err(&dev->dev, "pci_disable_msix get err %x\n", err);
}
static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector)
static int pci_frontend_enable_msi(struct pci_dev *dev, int vector[])
{
int err;
struct xen_pci_op op = {
@ -324,7 +330,13 @@ static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector)
err = do_pci_op(pdev, &op);
if (likely(!err)) {
*(*vector) = op.value;
vector[0] = op.value;
if (op.value <= 0) {
dev_warn(&dev->dev, "MSI entry is invalid: %d!\n",
op.value);
err = -EINVAL;
vector[0] = -1;
}
} else {
dev_err(&dev->dev, "pci frontend enable msi failed for dev "
"%x:%x\n", op.bus, op.devfn);
@ -733,8 +745,7 @@ static void free_pdev(struct pcifront_device *pdev)
pcifront_free_roots(pdev);
/*For PCIE_AER error handling job*/
flush_scheduled_work();
cancel_work_sync(&pdev->op_work);
if (pdev->irq >= 0)
unbind_from_irqhandler(pdev->irq, pdev);