Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6

* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (109 commits)
  PCI: fix coding style issue in pci_save_state()
  PCI: add pci_request_acs
  PCI: fix BUG_ON triggered by logical PCIe root port removal
  PCI: remove ifdefed pci_cleanup_aer_correct_error_status
  PCI: unconditionally clear AER uncorr status register during cleanup
  x86/PCI: claim SR-IOV BARs in pcibios_allocate_resource
  PCI: portdrv: remove redundant definitions
  PCI: portdrv: remove unnecessary struct pcie_port_data
  PCI: portdrv: minor cleanup for pcie_port_device_register
  PCI: portdrv: add missing irq cleanup
  PCI: portdrv: enable device before irq initialization
  PCI: portdrv: cleanup service irqs initialization
  PCI: portdrv: check capabilities first
  PCI: portdrv: move PME capability check
  PCI: portdrv: remove redundant pcie type calculation
  PCI: portdrv: cleanup pcie_device registration
  PCI: portdrv: remove redundant pcie_port_device_probe
  PCI: Always set prefetchable base/limit upper32 registers
  PCI: read-modify-write the pcie device control register when initiating pcie flr
  PCI: show dma_mask bits in /sys
  ...

Fixed up conflicts in:
	arch/x86/kernel/amd_iommu_init.c
	drivers/pci/dmar.c
	drivers/pci/hotplug/acpiphp_glue.c
This commit is contained in:
Linus Torvalds 2009-12-11 12:18:16 -08:00
commit 11bd04f6f3
83 changed files with 1794 additions and 1571 deletions

View file

@ -37,35 +37,9 @@
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
#include <xen/interface/version.h> /* to compile feature.c */ #include <xen/interface/version.h> /* to compile feature.c */
#include <xen/features.h> /* to comiple xen-netfront.c */ #include <xen/features.h> /* to comiple xen-netfront.c */
#include <xen/xen.h>
#include <asm/xen/hypercall.h> #include <asm/xen/hypercall.h>
/* xen_domain_type is set before executing any C code by early_xen_setup */
enum xen_domain_type {
XEN_NATIVE, /* running on bare hardware */
XEN_PV_DOMAIN, /* running in a PV domain */
XEN_HVM_DOMAIN, /* running in a Xen hvm domain*/
};
#ifdef CONFIG_XEN
extern enum xen_domain_type xen_domain_type;
#else
#define xen_domain_type XEN_NATIVE
#endif
#define xen_domain() (xen_domain_type != XEN_NATIVE)
#define xen_pv_domain() (xen_domain() && \
xen_domain_type == XEN_PV_DOMAIN)
#define xen_hvm_domain() (xen_domain() && \
xen_domain_type == XEN_HVM_DOMAIN)
#ifdef CONFIG_XEN_DOM0
#define xen_initial_domain() (xen_pv_domain() && \
(xen_start_info->flags & SIF_INITDOMAIN))
#else
#define xen_initial_domain() (0)
#endif
#ifdef CONFIG_XEN #ifdef CONFIG_XEN
extern struct shared_info *HYPERVISOR_shared_info; extern struct shared_info *HYPERVISOR_shared_info;
extern struct start_info *xen_start_info; extern struct start_info *xen_start_info;

View file

@ -131,6 +131,7 @@ alloc_pci_controller (int seg)
} }
struct pci_root_info { struct pci_root_info {
struct acpi_device *bridge;
struct pci_controller *controller; struct pci_controller *controller;
char *name; char *name;
}; };
@ -297,9 +298,20 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data)
window->offset = offset; window->offset = offset;
if (insert_resource(root, &window->resource)) { if (insert_resource(root, &window->resource)) {
printk(KERN_ERR "alloc 0x%llx-0x%llx from %s for %s failed\n", dev_err(&info->bridge->dev,
window->resource.start, window->resource.end, "can't allocate host bridge window %pR\n",
root->name, info->name); &window->resource);
} else {
if (offset)
dev_info(&info->bridge->dev, "host bridge window %pR "
"(PCI address [%#llx-%#llx])\n",
&window->resource,
window->resource.start - offset,
window->resource.end - offset);
else
dev_info(&info->bridge->dev,
"host bridge window %pR\n",
&window->resource);
} }
return AE_OK; return AE_OK;
@ -319,8 +331,9 @@ pcibios_setup_root_windows(struct pci_bus *bus, struct pci_controller *ctrl)
(res->end - res->start < 16)) (res->end - res->start < 16))
continue; continue;
if (j >= PCI_BUS_NUM_RESOURCES) { if (j >= PCI_BUS_NUM_RESOURCES) {
printk("Ignoring range [%#llx-%#llx] (%lx)\n", dev_warn(&bus->dev,
res->start, res->end, res->flags); "ignoring host bridge window %pR (no space)\n",
res);
continue; continue;
} }
bus->resource[j++] = res; bus->resource[j++] = res;
@ -364,6 +377,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
goto out3; goto out3;
sprintf(name, "PCI Bus %04x:%02x", domain, bus); sprintf(name, "PCI Bus %04x:%02x", domain, bus);
info.bridge = device;
info.controller = controller; info.controller = controller;
info.name = name; info.name = name;
acpi_walk_resources(device->handle, METHOD_NAME__CRS, acpi_walk_resources(device->handle, METHOD_NAME__CRS,
@ -720,9 +734,6 @@ int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size)
return ret; return ret;
} }
/* It's defined in drivers/pci/pci.c */
extern u8 pci_cache_line_size;
/** /**
* set_pci_cacheline_size - determine cacheline size for PCI devices * set_pci_cacheline_size - determine cacheline size for PCI devices
* *
@ -731,7 +742,7 @@ extern u8 pci_cache_line_size;
* *
* Code mostly taken from arch/ia64/kernel/palinfo.c:cache_info(). * Code mostly taken from arch/ia64/kernel/palinfo.c:cache_info().
*/ */
static void __init set_pci_cacheline_size(void) static void __init set_pci_dfl_cacheline_size(void)
{ {
unsigned long levels, unique_caches; unsigned long levels, unique_caches;
long status; long status;
@ -751,7 +762,7 @@ static void __init set_pci_cacheline_size(void)
"(status=%ld)\n", __func__, status); "(status=%ld)\n", __func__, status);
return; return;
} }
pci_cache_line_size = (1 << cci.pcci_line_size) / 4; pci_dfl_cache_line_size = (1 << cci.pcci_line_size) / 4;
} }
u64 ia64_dma_get_required_mask(struct device *dev) u64 ia64_dma_get_required_mask(struct device *dev)
@ -782,7 +793,7 @@ EXPORT_SYMBOL_GPL(dma_get_required_mask);
static int __init pcibios_init(void) static int __init pcibios_init(void)
{ {
set_pci_cacheline_size(); set_pci_dfl_cacheline_size();
return 0; return 0;
} }

View file

@ -16,8 +16,6 @@
#define PCI_IRQ_NONE 0xffffffff #define PCI_IRQ_NONE 0xffffffff
#define PCI_CACHE_LINE_BYTES 64
static inline void pcibios_set_master(struct pci_dev *dev) static inline void pcibios_set_master(struct pci_dev *dev)
{ {
/* No special bus mastering setup handling */ /* No special bus mastering setup handling */

View file

@ -1081,3 +1081,10 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar,
*start = rp->start - offset; *start = rp->start - offset;
*end = rp->end - offset; *end = rp->end - offset;
} }
static int __init pcibios_init(void)
{
pci_dfl_cache_line_size = 64 >> 2;
return 0;
}
subsys_initcall(pcibios_init);

View file

@ -118,11 +118,27 @@ extern int __init pcibios_init(void);
/* pci-mmconfig.c */ /* pci-mmconfig.c */
/* "PCI MMCONFIG %04x [bus %02x-%02x]" */
#define PCI_MMCFG_RESOURCE_NAME_LEN (22 + 4 + 2 + 2)
struct pci_mmcfg_region {
struct list_head list;
struct resource res;
u64 address;
char __iomem *virt;
u16 segment;
u8 start_bus;
u8 end_bus;
char name[PCI_MMCFG_RESOURCE_NAME_LEN];
};
extern int __init pci_mmcfg_arch_init(void); extern int __init pci_mmcfg_arch_init(void);
extern void __init pci_mmcfg_arch_free(void); extern void __init pci_mmcfg_arch_free(void);
extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
extern struct acpi_mcfg_allocation *pci_mmcfg_config; extern struct list_head pci_mmcfg_list;
extern int pci_mmcfg_config_num;
#define PCI_MMCFG_BUS_OFFSET(bus) ((bus) << 20)
/* /*
* AMD Fam10h CPUs are buggy, and cannot access MMIO config space * AMD Fam10h CPUs are buggy, and cannot access MMIO config space

View file

@ -37,31 +37,4 @@
extern struct shared_info *HYPERVISOR_shared_info; extern struct shared_info *HYPERVISOR_shared_info;
extern struct start_info *xen_start_info; extern struct start_info *xen_start_info;
enum xen_domain_type {
XEN_NATIVE, /* running on bare hardware */
XEN_PV_DOMAIN, /* running in a PV domain */
XEN_HVM_DOMAIN, /* running in a Xen hvm domain */
};
#ifdef CONFIG_XEN
extern enum xen_domain_type xen_domain_type;
#else
#define xen_domain_type XEN_NATIVE
#endif
#define xen_domain() (xen_domain_type != XEN_NATIVE)
#define xen_pv_domain() (xen_domain() && \
xen_domain_type == XEN_PV_DOMAIN)
#define xen_hvm_domain() (xen_domain() && \
xen_domain_type == XEN_HVM_DOMAIN)
#ifdef CONFIG_XEN_DOM0
#include <xen/interface/xen.h>
#define xen_initial_domain() (xen_pv_domain() && \
xen_start_info->flags & SIF_INITDOMAIN)
#else /* !CONFIG_XEN_DOM0 */
#define xen_initial_domain() (0)
#endif /* CONFIG_XEN_DOM0 */
#endif /* _ASM_X86_XEN_HYPERVISOR_H */ #endif /* _ASM_X86_XEN_HYPERVISOR_H */

View file

@ -1336,6 +1336,9 @@ void __init amd_iommu_detect(void)
iommu_detected = 1; iommu_detected = 1;
amd_iommu_detected = 1; amd_iommu_detected = 1;
x86_init.iommu.iommu_init = amd_iommu_init; x86_init.iommu.iommu_init = amd_iommu_init;
/* Make sure ACS will be enabled */
pci_request_acs();
} }
} }

View file

@ -15,3 +15,8 @@ obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
obj-y += common.o early.o obj-y += common.o early.o
obj-y += amd_bus.o obj-y += amd_bus.o
obj-$(CONFIG_X86_64) += bus_numa.o intel_bus.o
ifeq ($(CONFIG_PCI_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif

View file

@ -7,6 +7,7 @@
#include <asm/pci_x86.h> #include <asm/pci_x86.h>
struct pci_root_info { struct pci_root_info {
struct acpi_device *bridge;
char *name; char *name;
unsigned int res_num; unsigned int res_num;
struct resource *res; struct resource *res;
@ -58,6 +59,30 @@ bus_has_transparent_bridge(struct pci_bus *bus)
return false; return false;
} }
static void
align_resource(struct acpi_device *bridge, struct resource *res)
{
int align = (res->flags & IORESOURCE_MEM) ? 16 : 4;
/*
* Host bridge windows are not BARs, but the decoders on the PCI side
* that claim this address space have starting alignment and length
* constraints, so fix any obvious BIOS goofs.
*/
if (!IS_ALIGNED(res->start, align)) {
dev_printk(KERN_DEBUG, &bridge->dev,
"host bridge window %pR invalid; "
"aligning start to %d-byte boundary\n", res, align);
res->start &= ~(align - 1);
}
if (!IS_ALIGNED(res->end + 1, align)) {
dev_printk(KERN_DEBUG, &bridge->dev,
"host bridge window %pR invalid; "
"aligning end to %d-byte boundary\n", res, align);
res->end = ALIGN(res->end, align) - 1;
}
}
static acpi_status static acpi_status
setup_resource(struct acpi_resource *acpi_res, void *data) setup_resource(struct acpi_resource *acpi_res, void *data)
{ {
@ -91,11 +116,12 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
start = addr.minimum + addr.translation_offset; start = addr.minimum + addr.translation_offset;
end = start + addr.address_length - 1; end = start + addr.address_length - 1;
if (info->res_num >= max_root_bus_resources) { if (info->res_num >= max_root_bus_resources) {
printk(KERN_WARNING "PCI: Failed to allocate 0x%lx-0x%lx " if (pci_probe & PCI_USE__CRS)
"from %s for %s due to _CRS returning more than " printk(KERN_WARNING "PCI: Failed to allocate "
"%d resource descriptors\n", (unsigned long) start, "0x%lx-0x%lx from %s for %s due to _CRS "
(unsigned long) end, root->name, info->name, "returning more than %d resource descriptors\n",
max_root_bus_resources); (unsigned long) start, (unsigned long) end,
root->name, info->name, max_root_bus_resources);
return AE_OK; return AE_OK;
} }
@ -105,14 +131,28 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
res->start = start; res->start = start;
res->end = end; res->end = end;
res->child = NULL; res->child = NULL;
align_resource(info->bridge, res);
if (!(pci_probe & PCI_USE__CRS)) {
dev_printk(KERN_DEBUG, &info->bridge->dev,
"host bridge window %pR (ignored)\n", res);
return AE_OK;
}
if (insert_resource(root, res)) { if (insert_resource(root, res)) {
printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx " dev_err(&info->bridge->dev,
"from %s for %s\n", (unsigned long) res->start, "can't allocate host bridge window %pR\n", res);
(unsigned long) res->end, root->name, info->name);
} else { } else {
info->bus->resource[info->res_num] = res; info->bus->resource[info->res_num] = res;
info->res_num++; info->res_num++;
if (addr.translation_offset)
dev_info(&info->bridge->dev, "host bridge window %pR "
"(PCI address [%#llx-%#llx])\n",
res, res->start - addr.translation_offset,
res->end - addr.translation_offset);
else
dev_info(&info->bridge->dev,
"host bridge window %pR\n", res);
} }
return AE_OK; return AE_OK;
} }
@ -124,6 +164,12 @@ get_current_resources(struct acpi_device *device, int busnum,
struct pci_root_info info; struct pci_root_info info;
size_t size; size_t size;
if (!(pci_probe & PCI_USE__CRS))
dev_info(&device->dev,
"ignoring host bridge windows from ACPI; "
"boot with \"pci=use_crs\" to use them\n");
info.bridge = device;
info.bus = bus; info.bus = bus;
info.res_num = 0; info.res_num = 0;
acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
@ -163,8 +209,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
#endif #endif
if (domain && !pci_domains_supported) { if (domain && !pci_domains_supported) {
printk(KERN_WARNING "PCI: Multiple domains not supported " printk(KERN_WARNING "pci_bus %04x:%02x: "
"(dom %d, bus %d)\n", domain, busnum); "ignored (multiple domains not supported)\n",
domain, busnum);
return NULL; return NULL;
} }
@ -188,7 +235,8 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
*/ */
sd = kzalloc(sizeof(*sd), GFP_KERNEL); sd = kzalloc(sizeof(*sd), GFP_KERNEL);
if (!sd) { if (!sd) {
printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); printk(KERN_WARNING "pci_bus %04x:%02x: "
"ignored (out of memory)\n", domain, busnum);
return NULL; return NULL;
} }
@ -209,9 +257,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
} else { } else {
bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd); bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd);
if (bus) { if (bus) {
if (pci_probe & PCI_USE__CRS) get_current_resources(device, busnum, domain, bus);
get_current_resources(device, busnum, domain,
bus);
bus->subordinate = pci_scan_child_bus(bus); bus->subordinate = pci_scan_child_bus(bus);
} }
} }

View file

@ -6,10 +6,10 @@
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
#include <asm/pci-direct.h> #include <asm/pci-direct.h>
#include <asm/mpspec.h>
#include <linux/cpumask.h>
#endif #endif
#include "bus_numa.h"
/* /*
* This discovers the pcibus <-> node mapping on AMD K8. * This discovers the pcibus <-> node mapping on AMD K8.
* also get peer root bus resource for io,mmio * also get peer root bus resource for io,mmio
@ -17,67 +17,6 @@
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
/*
* sub bus (transparent) will use entres from 3 to store extra from root,
* so need to make sure have enought slot there, increase PCI_BUS_NUM_RESOURCES?
*/
#define RES_NUM 16
struct pci_root_info {
char name[12];
unsigned int res_num;
struct resource res[RES_NUM];
int bus_min;
int bus_max;
int node;
int link;
};
/* 4 at this time, it may become to 32 */
#define PCI_ROOT_NR 4
static int pci_root_num;
static struct pci_root_info pci_root_info[PCI_ROOT_NR];
void x86_pci_root_bus_res_quirks(struct pci_bus *b)
{
int i;
int j;
struct pci_root_info *info;
/* don't go for it if _CRS is used already */
if (b->resource[0] != &ioport_resource ||
b->resource[1] != &iomem_resource)
return;
/* if only one root bus, don't need to anything */
if (pci_root_num < 2)
return;
for (i = 0; i < pci_root_num; i++) {
if (pci_root_info[i].bus_min == b->number)
break;
}
if (i == pci_root_num)
return;
printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n",
b->number);
info = &pci_root_info[i];
for (j = 0; j < info->res_num; j++) {
struct resource *res;
struct resource *root;
res = &info->res[j];
b->resource[j] = res;
if (res->flags & IORESOURCE_IO)
root = &ioport_resource;
else
root = &iomem_resource;
insert_resource(root, res);
}
}
#define RANGE_NUM 16 #define RANGE_NUM 16
struct res_range { struct res_range {
@ -130,52 +69,6 @@ static void __init update_range(struct res_range *range, size_t start,
} }
} }
static void __init update_res(struct pci_root_info *info, size_t start,
size_t end, unsigned long flags, int merge)
{
int i;
struct resource *res;
if (!merge)
goto addit;
/* try to merge it with old one */
for (i = 0; i < info->res_num; i++) {
size_t final_start, final_end;
size_t common_start, common_end;
res = &info->res[i];
if (res->flags != flags)
continue;
common_start = max((size_t)res->start, start);
common_end = min((size_t)res->end, end);
if (common_start > common_end + 1)
continue;
final_start = min((size_t)res->start, start);
final_end = max((size_t)res->end, end);
res->start = final_start;
res->end = final_end;
return;
}
addit:
/* need to add that */
if (info->res_num >= RES_NUM)
return;
res = &info->res[info->res_num];
res->name = info->name;
res->flags = flags;
res->start = start;
res->end = end;
res->child = NULL;
info->res_num++;
}
struct pci_hostbridge_probe { struct pci_hostbridge_probe {
u32 bus; u32 bus;
u32 slot; u32 slot;
@ -230,7 +123,6 @@ static int __init early_fill_mp_bus_info(void)
int j; int j;
unsigned bus; unsigned bus;
unsigned slot; unsigned slot;
int found;
int node; int node;
int link; int link;
int def_node; int def_node;
@ -247,7 +139,7 @@ static int __init early_fill_mp_bus_info(void)
if (!early_pci_allowed()) if (!early_pci_allowed())
return -1; return -1;
found = 0; found_all_numa_early = 0;
for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
u32 id; u32 id;
u16 device; u16 device;
@ -261,12 +153,12 @@ static int __init early_fill_mp_bus_info(void)
device = (id>>16) & 0xffff; device = (id>>16) & 0xffff;
if (pci_probes[i].vendor == vendor && if (pci_probes[i].vendor == vendor &&
pci_probes[i].device == device) { pci_probes[i].device == device) {
found = 1; found_all_numa_early = 1;
break; break;
} }
} }
if (!found) if (!found_all_numa_early)
return 0; return 0;
pci_root_num = 0; pci_root_num = 0;

101
arch/x86/pci/bus_numa.c Normal file
View file

@ -0,0 +1,101 @@
#include <linux/init.h>
#include <linux/pci.h>
#include "bus_numa.h"
int pci_root_num;
struct pci_root_info pci_root_info[PCI_ROOT_NR];
int found_all_numa_early;
void x86_pci_root_bus_res_quirks(struct pci_bus *b)
{
int i;
int j;
struct pci_root_info *info;
/* don't go for it if _CRS is used already */
if (b->resource[0] != &ioport_resource ||
b->resource[1] != &iomem_resource)
return;
if (!pci_root_num)
return;
/* for amd, if only one root bus, don't need to do anything */
if (pci_root_num < 2 && found_all_numa_early)
return;
for (i = 0; i < pci_root_num; i++) {
if (pci_root_info[i].bus_min == b->number)
break;
}
if (i == pci_root_num)
return;
printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n",
b->number);
info = &pci_root_info[i];
for (j = 0; j < info->res_num; j++) {
struct resource *res;
struct resource *root;
res = &info->res[j];
b->resource[j] = res;
if (res->flags & IORESOURCE_IO)
root = &ioport_resource;
else
root = &iomem_resource;
insert_resource(root, res);
}
}
void __init update_res(struct pci_root_info *info, size_t start,
size_t end, unsigned long flags, int merge)
{
int i;
struct resource *res;
if (start > end)
return;
if (!merge)
goto addit;
/* try to merge it with old one */
for (i = 0; i < info->res_num; i++) {
size_t final_start, final_end;
size_t common_start, common_end;
res = &info->res[i];
if (res->flags != flags)
continue;
common_start = max((size_t)res->start, start);
common_end = min((size_t)res->end, end);
if (common_start > common_end + 1)
continue;
final_start = min((size_t)res->start, start);
final_end = max((size_t)res->end, end);
res->start = final_start;
res->end = final_end;
return;
}
addit:
/* need to add that */
if (info->res_num >= RES_NUM)
return;
res = &info->res[info->res_num];
res->name = info->name;
res->flags = flags;
res->start = start;
res->end = end;
res->child = NULL;
info->res_num++;
}

27
arch/x86/pci/bus_numa.h Normal file
View file

@ -0,0 +1,27 @@
#ifdef CONFIG_X86_64
/*
* sub bus (transparent) will use entres from 3 to store extra from
* root, so need to make sure we have enough slot there, Should we
* increase PCI_BUS_NUM_RESOURCES?
*/
#define RES_NUM 16
struct pci_root_info {
char name[12];
unsigned int res_num;
struct resource res[RES_NUM];
int bus_min;
int bus_max;
int node;
int link;
};
/* 4 at this time, it may become to 32 */
#define PCI_ROOT_NR 4
extern int pci_root_num;
extern struct pci_root_info pci_root_info[PCI_ROOT_NR];
extern int found_all_numa_early;
extern void update_res(struct pci_root_info *info, size_t start,
size_t end, unsigned long flags, int merge);
#endif

View file

@ -410,8 +410,6 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
return bus; return bus;
} }
extern u8 pci_cache_line_size;
int __init pcibios_init(void) int __init pcibios_init(void)
{ {
struct cpuinfo_x86 *c = &boot_cpu_data; struct cpuinfo_x86 *c = &boot_cpu_data;
@ -422,15 +420,19 @@ int __init pcibios_init(void)
} }
/* /*
* Assume PCI cacheline size of 32 bytes for all x86s except K7/K8 * Set PCI cacheline size to that of the CPU if the CPU has reported it.
* and P4. It's also good for 386/486s (which actually have 16) * (For older CPUs that don't support cpuid, we se it to 32 bytes
* It's also good for 386/486s (which actually have 16)
* as quite a few PCI devices do not support smaller values. * as quite a few PCI devices do not support smaller values.
*/ */
pci_cache_line_size = 32 >> 2; if (c->x86_clflush_size > 0) {
if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD) pci_dfl_cache_line_size = c->x86_clflush_size >> 2;
pci_cache_line_size = 64 >> 2; /* K7 & K8 */ printk(KERN_DEBUG "PCI: pci_cache_line_size set to %d bytes\n",
else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL) pci_dfl_cache_line_size << 2);
pci_cache_line_size = 128 >> 2; /* P4 */ } else {
pci_dfl_cache_line_size = 32 >> 2;
printk(KERN_DEBUG "PCI: Unknown cacheline size. Setting to 32 bytes\n");
}
pcibios_resource_survey(); pcibios_resource_survey();

View file

@ -12,8 +12,6 @@ u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset)
u32 v; u32 v;
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
v = inl(0xcfc); v = inl(0xcfc);
if (v != 0xffffffff)
pr_debug("%x reading 4 from %x: %x\n", slot, offset, v);
return v; return v;
} }
@ -22,7 +20,6 @@ u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset)
u8 v; u8 v;
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
v = inb(0xcfc + (offset&3)); v = inb(0xcfc + (offset&3));
pr_debug("%x reading 1 from %x: %x\n", slot, offset, v);
return v; return v;
} }
@ -31,28 +28,24 @@ u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset)
u16 v; u16 v;
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
v = inw(0xcfc + (offset&2)); v = inw(0xcfc + (offset&2));
pr_debug("%x reading 2 from %x: %x\n", slot, offset, v);
return v; return v;
} }
void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset,
u32 val) u32 val)
{ {
pr_debug("%x writing to %x: %x\n", slot, offset, val);
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
outl(val, 0xcfc); outl(val, 0xcfc);
} }
void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val) void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val)
{ {
pr_debug("%x writing to %x: %x\n", slot, offset, val);
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
outb(val, 0xcfc + (offset&3)); outb(val, 0xcfc + (offset&3));
} }
void write_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset, u16 val) void write_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset, u16 val)
{ {
pr_debug("%x writing to %x: %x\n", slot, offset, val);
outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8);
outw(val, 0xcfc + (offset&2)); outw(val, 0xcfc + (offset&2));
} }

View file

@ -129,7 +129,9 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
continue; continue;
if (!r->start || if (!r->start ||
pci_claim_resource(dev, idx) < 0) { pci_claim_resource(dev, idx) < 0) {
dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx); dev_info(&dev->dev,
"can't reserve window %pR\n",
r);
/* /*
* Something is wrong with the region. * Something is wrong with the region.
* Invalidate the resource to prevent * Invalidate the resource to prevent
@ -144,16 +146,29 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
} }
} }
struct pci_check_idx_range {
int start;
int end;
};
static void __init pcibios_allocate_resources(int pass) static void __init pcibios_allocate_resources(int pass)
{ {
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
int idx, disabled; int idx, disabled, i;
u16 command; u16 command;
struct resource *r; struct resource *r;
struct pci_check_idx_range idx_range[] = {
{ PCI_STD_RESOURCES, PCI_STD_RESOURCE_END },
#ifdef CONFIG_PCI_IOV
{ PCI_IOV_RESOURCES, PCI_IOV_RESOURCE_END },
#endif
};
for_each_pci_dev(dev) { for_each_pci_dev(dev) {
pci_read_config_word(dev, PCI_COMMAND, &command); pci_read_config_word(dev, PCI_COMMAND, &command);
for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { for (i = 0; i < ARRAY_SIZE(idx_range); i++)
for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) {
r = &dev->resource[idx]; r = &dev->resource[idx];
if (r->parent) /* Already allocated */ if (r->parent) /* Already allocated */
continue; continue;
@ -164,12 +179,12 @@ static void __init pcibios_allocate_resources(int pass)
else else
disabled = !(command & PCI_COMMAND_MEMORY); disabled = !(command & PCI_COMMAND_MEMORY);
if (pass == disabled) { if (pass == disabled) {
dev_dbg(&dev->dev, "resource %#08llx-%#08llx (f=%lx, d=%d, p=%d)\n", dev_dbg(&dev->dev,
(unsigned long long) r->start, "BAR %d: reserving %pr (d=%d, p=%d)\n",
(unsigned long long) r->end, idx, r, disabled, pass);
r->flags, disabled, pass);
if (pci_claim_resource(dev, idx) < 0) { if (pci_claim_resource(dev, idx) < 0) {
dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx); dev_info(&dev->dev,
"can't reserve %pR\n", r);
/* We'll assign a new address later */ /* We'll assign a new address later */
r->end -= r->start; r->end -= r->start;
r->start = 0; r->start = 0;
@ -182,7 +197,7 @@ static void __init pcibios_allocate_resources(int pass)
/* Turn the ROM off, leave the resource region, /* Turn the ROM off, leave the resource region,
* but keep it unregistered. */ * but keep it unregistered. */
u32 reg; u32 reg;
dev_dbg(&dev->dev, "disabling ROM\n"); dev_dbg(&dev->dev, "disabling ROM %pR\n", r);
r->flags &= ~IORESOURCE_ROM_ENABLE; r->flags &= ~IORESOURCE_ROM_ENABLE;
pci_read_config_dword(dev, pci_read_config_dword(dev,
dev->rom_base_reg, &reg); dev->rom_base_reg, &reg);
@ -282,6 +297,15 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return -EINVAL; return -EINVAL;
prot = pgprot_val(vma->vm_page_prot); prot = pgprot_val(vma->vm_page_prot);
/*
* Return error if pat is not enabled and write_combine is requested.
* Caller can followup with UC MINUS request and add a WC mtrr if there
* is a free mtrr slot.
*/
if (!pat_enabled && write_combine)
return -EINVAL;
if (pat_enabled && write_combine) if (pat_enabled && write_combine)
prot |= _PAGE_CACHE_WC; prot |= _PAGE_CACHE_WC;
else if (pat_enabled || boot_cpu_data.x86 > 3) else if (pat_enabled || boot_cpu_data.x86 > 3)

90
arch/x86/pci/intel_bus.c Normal file
View file

@ -0,0 +1,90 @@
/*
* to read io range from IOH pci conf, need to do it after mmconfig is there
*/
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <asm/pci_x86.h>
#include "bus_numa.h"
static inline void print_ioh_resources(struct pci_root_info *info)
{
int res_num;
int busnum;
int i;
printk(KERN_DEBUG "IOH bus: [%02x, %02x]\n",
info->bus_min, info->bus_max);
res_num = info->res_num;
busnum = info->bus_min;
for (i = 0; i < res_num; i++) {
struct resource *res;
res = &info->res[i];
printk(KERN_DEBUG "IOH bus: %02x index %x %s: [%llx, %llx]\n",
busnum, i,
(res->flags & IORESOURCE_IO) ? "io port" :
"mmio",
res->start, res->end);
}
}
#define IOH_LIO 0x108
#define IOH_LMMIOL 0x10c
#define IOH_LMMIOH 0x110
#define IOH_LMMIOH_BASEU 0x114
#define IOH_LMMIOH_LIMITU 0x118
#define IOH_LCFGBUS 0x11c
static void __devinit pci_root_bus_res(struct pci_dev *dev)
{
u16 word;
u32 dword;
struct pci_root_info *info;
u16 io_base, io_end;
u32 mmiol_base, mmiol_end;
u64 mmioh_base, mmioh_end;
int bus_base, bus_end;
if (pci_root_num >= PCI_ROOT_NR) {
printk(KERN_DEBUG "intel_bus.c: PCI_ROOT_NR is too small\n");
return;
}
info = &pci_root_info[pci_root_num];
pci_root_num++;
pci_read_config_word(dev, IOH_LCFGBUS, &word);
bus_base = (word & 0xff);
bus_end = (word & 0xff00) >> 8;
sprintf(info->name, "PCI Bus #%02x", bus_base);
info->bus_min = bus_base;
info->bus_max = bus_end;
pci_read_config_word(dev, IOH_LIO, &word);
io_base = (word & 0xf0) << (12 - 4);
io_end = (word & 0xf000) | 0xfff;
update_res(info, io_base, io_end, IORESOURCE_IO, 0);
pci_read_config_dword(dev, IOH_LMMIOL, &dword);
mmiol_base = (dword & 0xff00) << (24 - 8);
mmiol_end = (dword & 0xff000000) | 0xffffff;
update_res(info, mmiol_base, mmiol_end, IORESOURCE_MEM, 0);
pci_read_config_dword(dev, IOH_LMMIOH, &dword);
mmioh_base = ((u64)(dword & 0xfc00)) << (26 - 10);
mmioh_end = ((u64)(dword & 0xfc000000) | 0x3ffffff);
pci_read_config_dword(dev, IOH_LMMIOH_BASEU, &dword);
mmioh_base |= ((u64)(dword & 0x7ffff)) << 32;
pci_read_config_dword(dev, IOH_LMMIOH_LIMITU, &dword);
mmioh_end |= ((u64)(dword & 0x7ffff)) << 32;
update_res(info, mmioh_base, mmioh_end, IORESOURCE_MEM, 0);
print_ioh_resources(info);
}
/* intel IOH */
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x342e, pci_root_bus_res);

View file

@ -15,48 +15,98 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/sfi_acpi.h> #include <linux/sfi_acpi.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/sort.h> #include <linux/dmi.h>
#include <asm/e820.h> #include <asm/e820.h>
#include <asm/pci_x86.h> #include <asm/pci_x86.h>
#include <asm/acpi.h> #include <asm/acpi.h>
#define PREFIX "PCI: " #define PREFIX "PCI: "
/* aperture is up to 256MB but BIOS may reserve less */
#define MMCONFIG_APER_MIN (2 * 1024*1024)
#define MMCONFIG_APER_MAX (256 * 1024*1024)
/* Indicate if the mmcfg resources have been placed into the resource table. */ /* Indicate if the mmcfg resources have been placed into the resource table. */
static int __initdata pci_mmcfg_resources_inserted; static int __initdata pci_mmcfg_resources_inserted;
static __init int extend_mmcfg(int num) LIST_HEAD(pci_mmcfg_list);
{
struct acpi_mcfg_allocation *new;
int new_num = pci_mmcfg_config_num + num;
new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL); static __init void pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
{
if (cfg->res.parent)
release_resource(&cfg->res);
list_del(&cfg->list);
kfree(cfg);
}
static __init void free_all_mmcfg(void)
{
struct pci_mmcfg_region *cfg, *tmp;
pci_mmcfg_arch_free();
list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list)
pci_mmconfig_remove(cfg);
}
static __init void list_add_sorted(struct pci_mmcfg_region *new)
{
struct pci_mmcfg_region *cfg;
/* keep list sorted by segment and starting bus number */
list_for_each_entry(cfg, &pci_mmcfg_list, list) {
if (cfg->segment > new->segment ||
(cfg->segment == new->segment &&
cfg->start_bus >= new->start_bus)) {
list_add_tail(&new->list, &cfg->list);
return;
}
}
list_add_tail(&new->list, &pci_mmcfg_list);
}
static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
int end, u64 addr)
{
struct pci_mmcfg_region *new;
int num_buses;
struct resource *res;
if (addr == 0)
return NULL;
new = kzalloc(sizeof(*new), GFP_KERNEL);
if (!new) if (!new)
return -1; return NULL;
if (pci_mmcfg_config) { new->address = addr;
memcpy(new, pci_mmcfg_config, new->segment = segment;
sizeof(pci_mmcfg_config[0]) * new_num); new->start_bus = start;
kfree(pci_mmcfg_config); new->end_bus = end;
}
pci_mmcfg_config = new;
return 0; list_add_sorted(new);
num_buses = end - start + 1;
res = &new->res;
res->start = addr + PCI_MMCFG_BUS_OFFSET(start);
res->end = addr + PCI_MMCFG_BUS_OFFSET(num_buses) - 1;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
"PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
res->name = new->name;
printk(KERN_INFO PREFIX "MMCONFIG for domain %04x [bus %02x-%02x] at "
"%pR (base %#lx)\n", segment, start, end, &new->res,
(unsigned long) addr);
return new;
} }
static __init void fill_one_mmcfg(u64 addr, int segment, int start, int end) struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
{ {
int i = pci_mmcfg_config_num; struct pci_mmcfg_region *cfg;
pci_mmcfg_config_num++; list_for_each_entry(cfg, &pci_mmcfg_list, list)
pci_mmcfg_config[i].address = addr; if (cfg->segment == segment &&
pci_mmcfg_config[i].pci_segment = segment; cfg->start_bus <= bus && bus <= cfg->end_bus)
pci_mmcfg_config[i].start_bus_number = start; return cfg;
pci_mmcfg_config[i].end_bus_number = end;
return NULL;
} }
static const char __init *pci_mmcfg_e7520(void) static const char __init *pci_mmcfg_e7520(void)
@ -68,11 +118,9 @@ static const char __init *pci_mmcfg_e7520(void)
if (win == 0x0000 || win == 0xf000) if (win == 0x0000 || win == 0xf000)
return NULL; return NULL;
if (extend_mmcfg(1) == -1) if (pci_mmconfig_add(0, 0, 255, win << 16) == NULL)
return NULL; return NULL;
fill_one_mmcfg(win << 16, 0, 0, 255);
return "Intel Corporation E7520 Memory Controller Hub"; return "Intel Corporation E7520 Memory Controller Hub";
} }
@ -114,11 +162,9 @@ static const char __init *pci_mmcfg_intel_945(void)
if ((pciexbar & mask) >= 0xf0000000U) if ((pciexbar & mask) >= 0xf0000000U)
return NULL; return NULL;
if (extend_mmcfg(1) == -1) if (pci_mmconfig_add(0, 0, (len >> 20) - 1, pciexbar & mask) == NULL)
return NULL; return NULL;
fill_one_mmcfg(pciexbar & mask, 0, 0, (len >> 20) - 1);
return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
} }
@ -127,7 +173,7 @@ static const char __init *pci_mmcfg_amd_fam10h(void)
u32 low, high, address; u32 low, high, address;
u64 base, msr; u64 base, msr;
int i; int i;
unsigned segnbits = 0, busnbits; unsigned segnbits = 0, busnbits, end_bus;
if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF)) if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
return NULL; return NULL;
@ -161,11 +207,13 @@ static const char __init *pci_mmcfg_amd_fam10h(void)
busnbits = 8; busnbits = 8;
} }
if (extend_mmcfg(1 << segnbits) == -1) end_bus = (1 << busnbits) - 1;
return NULL;
for (i = 0; i < (1 << segnbits); i++) for (i = 0; i < (1 << segnbits); i++)
fill_one_mmcfg(base + (1<<28) * i, i, 0, (1 << busnbits) - 1); if (pci_mmconfig_add(i, 0, end_bus,
base + (1<<28) * i) == NULL) {
free_all_mmcfg();
return NULL;
}
return "AMD Family 10h NB"; return "AMD Family 10h NB";
} }
@ -190,7 +238,7 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void)
/* /*
* do check if amd fam10h already took over * do check if amd fam10h already took over
*/ */
if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked) if (!acpi_disabled || !list_empty(&pci_mmcfg_list) || mcp55_checked)
return NULL; return NULL;
mcp55_checked = true; mcp55_checked = true;
@ -213,16 +261,14 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void)
if (!(extcfg & extcfg_enable_mask)) if (!(extcfg & extcfg_enable_mask))
continue; continue;
if (extend_mmcfg(1) == -1)
continue;
size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift; size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift;
base = extcfg & extcfg_base_mask[size_index]; base = extcfg & extcfg_base_mask[size_index];
/* base could > 4G */ /* base could > 4G */
base <<= extcfg_base_lshift; base <<= extcfg_base_lshift;
start = (extcfg & extcfg_start_mask) >> extcfg_start_shift; start = (extcfg & extcfg_start_mask) >> extcfg_start_shift;
end = start + extcfg_sizebus[size_index] - 1; end = start + extcfg_sizebus[size_index] - 1;
fill_one_mmcfg(base, 0, start, end); if (pci_mmconfig_add(0, start, end, base) == NULL)
continue;
mcp55_mmconf_found++; mcp55_mmconf_found++;
} }
@ -253,45 +299,27 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
0x0369, pci_mmcfg_nvidia_mcp55 }, 0x0369, pci_mmcfg_nvidia_mcp55 },
}; };
static int __init cmp_mmcfg(const void *x1, const void *x2)
{
const typeof(pci_mmcfg_config[0]) *m1 = x1;
const typeof(pci_mmcfg_config[0]) *m2 = x2;
int start1, start2;
start1 = m1->start_bus_number;
start2 = m2->start_bus_number;
return start1 - start2;
}
static void __init pci_mmcfg_check_end_bus_number(void) static void __init pci_mmcfg_check_end_bus_number(void)
{ {
int i; struct pci_mmcfg_region *cfg, *cfgx;
typeof(pci_mmcfg_config[0]) *cfg, *cfgx;
/* sort them at first */
sort(pci_mmcfg_config, pci_mmcfg_config_num,
sizeof(pci_mmcfg_config[0]), cmp_mmcfg, NULL);
/* last one*/ /* last one*/
if (pci_mmcfg_config_num > 0) { cfg = list_entry(pci_mmcfg_list.prev, typeof(*cfg), list);
i = pci_mmcfg_config_num - 1; if (cfg)
cfg = &pci_mmcfg_config[i]; if (cfg->end_bus < cfg->start_bus)
if (cfg->end_bus_number < cfg->start_bus_number) cfg->end_bus = 255;
cfg->end_bus_number = 255;
} if (list_is_singular(&pci_mmcfg_list))
return;
/* don't overlap please */ /* don't overlap please */
for (i = 0; i < pci_mmcfg_config_num - 1; i++) { list_for_each_entry(cfg, &pci_mmcfg_list, list) {
cfg = &pci_mmcfg_config[i]; if (cfg->end_bus < cfg->start_bus)
cfgx = &pci_mmcfg_config[i+1]; cfg->end_bus = 255;
if (cfg->end_bus_number < cfg->start_bus_number) cfgx = list_entry(cfg->list.next, typeof(*cfg), list);
cfg->end_bus_number = 255; if (cfg != cfgx && cfg->end_bus >= cfgx->start_bus)
cfg->end_bus = cfgx->start_bus - 1;
if (cfg->end_bus_number >= cfgx->start_bus_number)
cfg->end_bus_number = cfgx->start_bus_number - 1;
} }
} }
@ -306,8 +334,7 @@ static int __init pci_mmcfg_check_hostbridge(void)
if (!raw_pci_ops) if (!raw_pci_ops)
return 0; return 0;
pci_mmcfg_config_num = 0; free_all_mmcfg();
pci_mmcfg_config = NULL;
for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) { for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
bus = pci_mmcfg_probes[i].bus; bus = pci_mmcfg_probes[i].bus;
@ -322,45 +349,22 @@ static int __init pci_mmcfg_check_hostbridge(void)
name = pci_mmcfg_probes[i].probe(); name = pci_mmcfg_probes[i].probe();
if (name) if (name)
printk(KERN_INFO "PCI: Found %s with MMCONFIG support.\n", printk(KERN_INFO PREFIX "%s with MMCONFIG support\n",
name); name);
} }
/* some end_bus_number is crazy, fix it */ /* some end_bus_number is crazy, fix it */
pci_mmcfg_check_end_bus_number(); pci_mmcfg_check_end_bus_number();
return pci_mmcfg_config_num != 0; return !list_empty(&pci_mmcfg_list);
} }
static void __init pci_mmcfg_insert_resources(void) static void __init pci_mmcfg_insert_resources(void)
{ {
#define PCI_MMCFG_RESOURCE_NAME_LEN 24 struct pci_mmcfg_region *cfg;
int i;
struct resource *res;
char *names;
unsigned num_buses;
res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res), list_for_each_entry(cfg, &pci_mmcfg_list, list)
pci_mmcfg_config_num, GFP_KERNEL); insert_resource(&iomem_resource, &cfg->res);
if (!res) {
printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n");
return;
}
names = (void *)&res[pci_mmcfg_config_num];
for (i = 0; i < pci_mmcfg_config_num; i++, res++) {
struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
res->name = names;
snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN,
"PCI MMCONFIG %u [%02x-%02x]", cfg->pci_segment,
cfg->start_bus_number, cfg->end_bus_number);
res->start = cfg->address + (cfg->start_bus_number << 20);
res->end = res->start + (num_buses << 20) - 1;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
insert_resource(&iomem_resource, res);
names += PCI_MMCFG_RESOURCE_NAME_LEN;
}
/* Mark that the resources have been inserted. */ /* Mark that the resources have been inserted. */
pci_mmcfg_resources_inserted = 1; pci_mmcfg_resources_inserted = 1;
@ -437,11 +441,12 @@ static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used)
typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type); typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type);
static int __init is_mmconf_reserved(check_reserved_t is_reserved, static int __init is_mmconf_reserved(check_reserved_t is_reserved,
u64 addr, u64 size, int i, struct pci_mmcfg_region *cfg, int with_e820)
typeof(pci_mmcfg_config[0]) *cfg, int with_e820)
{ {
u64 addr = cfg->res.start;
u64 size = resource_size(&cfg->res);
u64 old_size = size; u64 old_size = size;
int valid = 0; int valid = 0, num_buses;
while (!is_reserved(addr, addr + size, E820_RESERVED)) { while (!is_reserved(addr, addr + size, E820_RESERVED)) {
size >>= 1; size >>= 1;
@ -450,19 +455,25 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved,
} }
if (size >= (16UL<<20) || size == old_size) { if (size >= (16UL<<20) || size == old_size) {
printk(KERN_NOTICE printk(KERN_INFO PREFIX "MMCONFIG at %pR reserved in %s\n",
"PCI: MCFG area at %Lx reserved in %s\n", &cfg->res,
addr, with_e820?"E820":"ACPI motherboard resources"); with_e820 ? "E820" : "ACPI motherboard resources");
valid = 1; valid = 1;
if (old_size != size) { if (old_size != size) {
/* update end_bus_number */ /* update end_bus */
cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1); cfg->end_bus = cfg->start_bus + ((size>>20) - 1);
printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx " num_buses = cfg->end_bus - cfg->start_bus + 1;
"segment %hu buses %u - %u\n", cfg->res.end = cfg->res.start +
i, (unsigned long)cfg->address, cfg->pci_segment, PCI_MMCFG_BUS_OFFSET(num_buses) - 1;
(unsigned int)cfg->start_bus_number, snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN,
(unsigned int)cfg->end_bus_number); "PCI MMCONFIG %04x [bus %02x-%02x]",
cfg->segment, cfg->start_bus, cfg->end_bus);
printk(KERN_INFO PREFIX
"MMCONFIG for %04x [bus%02x-%02x] "
"at %pR (base %#lx) (size reduced!)\n",
cfg->segment, cfg->start_bus, cfg->end_bus,
&cfg->res, (unsigned long) cfg->address);
} }
} }
@ -471,45 +482,26 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved,
static void __init pci_mmcfg_reject_broken(int early) static void __init pci_mmcfg_reject_broken(int early)
{ {
typeof(pci_mmcfg_config[0]) *cfg; struct pci_mmcfg_region *cfg;
int i;
if ((pci_mmcfg_config_num == 0) || list_for_each_entry(cfg, &pci_mmcfg_list, list) {
(pci_mmcfg_config == NULL) ||
(pci_mmcfg_config[0].address == 0))
return;
for (i = 0; i < pci_mmcfg_config_num; i++) {
int valid = 0; int valid = 0;
u64 addr, size;
cfg = &pci_mmcfg_config[i];
addr = cfg->start_bus_number;
addr <<= 20;
addr += cfg->address;
size = cfg->end_bus_number + 1 - cfg->start_bus_number;
size <<= 20;
printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
"segment %hu buses %u - %u\n",
i, (unsigned long)cfg->address, cfg->pci_segment,
(unsigned int)cfg->start_bus_number,
(unsigned int)cfg->end_bus_number);
if (!early && !acpi_disabled) if (!early && !acpi_disabled)
valid = is_mmconf_reserved(is_acpi_reserved, addr, size, i, cfg, 0); valid = is_mmconf_reserved(is_acpi_reserved, cfg, 0);
if (valid) if (valid)
continue; continue;
if (!early) if (!early)
printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" printk(KERN_ERR FW_BUG PREFIX
" reserved in ACPI motherboard resources\n", "MMCONFIG at %pR not reserved in "
cfg->address); "ACPI motherboard resources\n", &cfg->res);
/* Don't try to do this check unless configuration /* Don't try to do this check unless configuration
type 1 is available. how about type 2 ?*/ type 1 is available. how about type 2 ?*/
if (raw_pci_ops) if (raw_pci_ops)
valid = is_mmconf_reserved(e820_all_mapped, addr, size, i, cfg, 1); valid = is_mmconf_reserved(e820_all_mapped, cfg, 1);
if (!valid) if (!valid)
goto reject; goto reject;
@ -518,34 +510,41 @@ static void __init pci_mmcfg_reject_broken(int early)
return; return;
reject: reject:
printk(KERN_INFO "PCI: Not using MMCONFIG.\n"); printk(KERN_INFO PREFIX "not using MMCONFIG\n");
pci_mmcfg_arch_free(); free_all_mmcfg();
kfree(pci_mmcfg_config);
pci_mmcfg_config = NULL;
pci_mmcfg_config_num = 0;
} }
static int __initdata known_bridge; static int __initdata known_bridge;
static int acpi_mcfg_64bit_base_addr __initdata = FALSE; static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
struct acpi_mcfg_allocation *cfg)
/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
struct acpi_mcfg_allocation *pci_mmcfg_config;
int pci_mmcfg_config_num;
static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg)
{ {
if (!strcmp(mcfg->header.oem_id, "SGI")) int year;
acpi_mcfg_64bit_base_addr = TRUE;
if (cfg->address < 0xFFFFFFFF)
return 0; return 0;
if (!strcmp(mcfg->header.oem_id, "SGI"))
return 0;
if (mcfg->header.revision >= 1) {
if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
year >= 2010)
return 0;
}
printk(KERN_ERR PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
"is above 4GB, ignored\n", cfg->pci_segment,
cfg->start_bus_number, cfg->end_bus_number, cfg->address);
return -EINVAL;
} }
static int __init pci_parse_mcfg(struct acpi_table_header *header) static int __init pci_parse_mcfg(struct acpi_table_header *header)
{ {
struct acpi_table_mcfg *mcfg; struct acpi_table_mcfg *mcfg;
struct acpi_mcfg_allocation *cfg_table, *cfg;
unsigned long i; unsigned long i;
int config_size; int entries;
if (!header) if (!header)
return -EINVAL; return -EINVAL;
@ -553,37 +552,32 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header)
mcfg = (struct acpi_table_mcfg *)header; mcfg = (struct acpi_table_mcfg *)header;
/* how many config structures do we have */ /* how many config structures do we have */
pci_mmcfg_config_num = 0; free_all_mmcfg();
entries = 0;
i = header->length - sizeof(struct acpi_table_mcfg); i = header->length - sizeof(struct acpi_table_mcfg);
while (i >= sizeof(struct acpi_mcfg_allocation)) { while (i >= sizeof(struct acpi_mcfg_allocation)) {
++pci_mmcfg_config_num; entries++;
i -= sizeof(struct acpi_mcfg_allocation); i -= sizeof(struct acpi_mcfg_allocation);
}; };
if (pci_mmcfg_config_num == 0) { if (entries == 0) {
printk(KERN_ERR PREFIX "MMCONFIG has no entries\n"); printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
return -ENODEV; return -ENODEV;
} }
config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config); cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL); for (i = 0; i < entries; i++) {
if (!pci_mmcfg_config) { cfg = &cfg_table[i];
printk(KERN_WARNING PREFIX if (acpi_mcfg_check_entry(mcfg, cfg)) {
"No memory for MCFG config tables\n"); free_all_mmcfg();
return -ENOMEM; return -ENODEV;
} }
memcpy(pci_mmcfg_config, &mcfg[1], config_size); if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
cfg->end_bus_number, cfg->address) == NULL) {
acpi_mcfg_oem_check(mcfg); printk(KERN_WARNING PREFIX
"no memory for MCFG entries\n");
for (i = 0; i < pci_mmcfg_config_num; ++i) { free_all_mmcfg();
if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) && return -ENOMEM;
!acpi_mcfg_64bit_base_addr) {
printk(KERN_ERR PREFIX
"MMCONFIG not in low 4GB of memory\n");
kfree(pci_mmcfg_config);
pci_mmcfg_config_num = 0;
return -ENODEV;
} }
} }
@ -614,9 +608,7 @@ static void __init __pci_mmcfg_init(int early)
pci_mmcfg_reject_broken(early); pci_mmcfg_reject_broken(early);
if ((pci_mmcfg_config_num == 0) || if (list_empty(&pci_mmcfg_list))
(pci_mmcfg_config == NULL) ||
(pci_mmcfg_config[0].address == 0))
return; return;
if (pci_mmcfg_arch_init()) if (pci_mmcfg_arch_init())
@ -648,9 +640,7 @@ static int __init pci_mmcfg_late_insert_resources(void)
*/ */
if ((pci_mmcfg_resources_inserted == 1) || if ((pci_mmcfg_resources_inserted == 1) ||
(pci_probe & PCI_PROBE_MMCONF) == 0 || (pci_probe & PCI_PROBE_MMCONF) == 0 ||
(pci_mmcfg_config_num == 0) || list_empty(&pci_mmcfg_list))
(pci_mmcfg_config == NULL) ||
(pci_mmcfg_config[0].address == 0))
return 1; return 1;
/* /*

View file

@ -27,18 +27,10 @@ static int mmcfg_last_accessed_cpu;
*/ */
static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
{ {
struct acpi_mcfg_allocation *cfg; struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
int cfg_num;
for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { if (cfg)
cfg = &pci_mmcfg_config[cfg_num];
if (cfg->pci_segment == seg &&
(cfg->start_bus_number <= bus) &&
(cfg->end_bus_number >= bus))
return cfg->address; return cfg->address;
}
/* Fall back to type 0 */
return 0; return 0;
} }
@ -47,7 +39,7 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
*/ */
static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn) static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
{ {
u32 dev_base = base | (bus << 20) | (devfn << 12); u32 dev_base = base | PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12);
int cpu = smp_processor_id(); int cpu = smp_processor_id();
if (dev_base != mmcfg_last_accessed_device || if (dev_base != mmcfg_last_accessed_device ||
cpu != mmcfg_last_accessed_cpu) { cpu != mmcfg_last_accessed_cpu) {

View file

@ -12,38 +12,15 @@
#include <asm/e820.h> #include <asm/e820.h>
#include <asm/pci_x86.h> #include <asm/pci_x86.h>
/* Static virtual mapping of the MMCONFIG aperture */ #define PREFIX "PCI: "
struct mmcfg_virt {
struct acpi_mcfg_allocation *cfg;
char __iomem *virt;
};
static struct mmcfg_virt *pci_mmcfg_virt;
static char __iomem *get_virt(unsigned int seg, unsigned bus)
{
struct acpi_mcfg_allocation *cfg;
int cfg_num;
for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) {
cfg = pci_mmcfg_virt[cfg_num].cfg;
if (cfg->pci_segment == seg &&
(cfg->start_bus_number <= bus) &&
(cfg->end_bus_number >= bus))
return pci_mmcfg_virt[cfg_num].virt;
}
/* Fall back to type 0 */
return NULL;
}
static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
{ {
char __iomem *addr; struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
addr = get_virt(seg, bus); if (cfg && cfg->virt)
if (!addr) return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12));
return NULL; return NULL;
return addr + ((bus << 20) | (devfn << 12));
} }
static int pci_mmcfg_read(unsigned int seg, unsigned int bus, static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
@ -109,42 +86,30 @@ static struct pci_raw_ops pci_mmcfg = {
.write = pci_mmcfg_write, .write = pci_mmcfg_write,
}; };
static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg) static void __iomem * __init mcfg_ioremap(struct pci_mmcfg_region *cfg)
{ {
void __iomem *addr; void __iomem *addr;
u64 start, size; u64 start, size;
int num_buses;
start = cfg->start_bus_number; start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
start <<= 20; num_buses = cfg->end_bus - cfg->start_bus + 1;
start += cfg->address; size = PCI_MMCFG_BUS_OFFSET(num_buses);
size = cfg->end_bus_number + 1 - cfg->start_bus_number;
size <<= 20;
addr = ioremap_nocache(start, size); addr = ioremap_nocache(start, size);
if (addr) { if (addr)
printk(KERN_INFO "PCI: Using MMCONFIG at %Lx - %Lx\n", addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
start, start + size - 1);
addr -= cfg->start_bus_number << 20;
}
return addr; return addr;
} }
int __init pci_mmcfg_arch_init(void) int __init pci_mmcfg_arch_init(void)
{ {
int i; struct pci_mmcfg_region *cfg;
pci_mmcfg_virt = kzalloc(sizeof(*pci_mmcfg_virt) *
pci_mmcfg_config_num, GFP_KERNEL);
if (pci_mmcfg_virt == NULL) {
printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
return 0;
}
for (i = 0; i < pci_mmcfg_config_num; ++i) { list_for_each_entry(cfg, &pci_mmcfg_list, list) {
pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i]; cfg->virt = mcfg_ioremap(cfg);
pci_mmcfg_virt[i].virt = mcfg_ioremap(&pci_mmcfg_config[i]); if (!cfg->virt) {
if (!pci_mmcfg_virt[i].virt) { printk(KERN_ERR PREFIX "can't map MMCONFIG at %pR\n",
printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " &cfg->res);
"segment %d\n",
pci_mmcfg_config[i].pci_segment);
pci_mmcfg_arch_free(); pci_mmcfg_arch_free();
return 0; return 0;
} }
@ -155,19 +120,12 @@ int __init pci_mmcfg_arch_init(void)
void __init pci_mmcfg_arch_free(void) void __init pci_mmcfg_arch_free(void)
{ {
int i; struct pci_mmcfg_region *cfg;
if (pci_mmcfg_virt == NULL) list_for_each_entry(cfg, &pci_mmcfg_list, list) {
return; if (cfg->virt) {
iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
for (i = 0; i < pci_mmcfg_config_num; ++i) { cfg->virt = NULL;
if (pci_mmcfg_virt[i].virt) {
iounmap(pci_mmcfg_virt[i].virt + (pci_mmcfg_virt[i].cfg->start_bus_number << 20));
pci_mmcfg_virt[i].virt = NULL;
pci_mmcfg_virt[i].cfg = NULL;
} }
} }
kfree(pci_mmcfg_virt);
pci_mmcfg_virt = NULL;
} }

View file

@ -27,7 +27,9 @@
#include <linux/page-flags.h> #include <linux/page-flags.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/pci.h>
#include <xen/xen.h>
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
#include <xen/interface/version.h> #include <xen/interface/version.h>
#include <xen/interface/physdev.h> #include <xen/interface/physdev.h>
@ -1175,8 +1177,12 @@ asmlinkage void __init xen_start_kernel(void)
add_preferred_console("xenboot", 0, NULL); add_preferred_console("xenboot", 0, NULL);
add_preferred_console("tty", 0, NULL); add_preferred_console("tty", 0, NULL);
add_preferred_console("hvc", 0, NULL); add_preferred_console("hvc", 0, NULL);
} else {
/* Make sure ACS will be enabled */
pci_request_acs();
} }
xen_raw_console_write("about to get started...\n"); xen_raw_console_write("about to get started...\n");
xen_setup_runstate_info(0); xen_setup_runstate_info(0);

View file

@ -19,6 +19,7 @@ obj-y += acpi.o \
# All the builtin files are in the "acpi." module_param namespace. # All the builtin files are in the "acpi." module_param namespace.
acpi-y += osl.o utils.o reboot.o acpi-y += osl.o utils.o reboot.o
acpi-y += hest.o
# sleep related files # sleep related files
acpi-y += wakeup.o acpi-y += wakeup.o

135
drivers/acpi/hest.c Normal file
View file

@ -0,0 +1,135 @@
#include <linux/acpi.h>
#include <linux/pci.h>
#define PREFIX "ACPI: "
static inline unsigned long parse_acpi_hest_ia_machine_check(struct acpi_hest_ia_machine_check *p)
{
return sizeof(*p) +
(sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks);
}
static inline unsigned long parse_acpi_hest_ia_corrected(struct acpi_hest_ia_corrected *p)
{
return sizeof(*p) +
(sizeof(struct acpi_hest_ia_error_bank) * p->num_hardware_banks);
}
static inline unsigned long parse_acpi_hest_ia_nmi(struct acpi_hest_ia_nmi *p)
{
return sizeof(*p);
}
static inline unsigned long parse_acpi_hest_generic(struct acpi_hest_generic *p)
{
return sizeof(*p);
}
static inline unsigned int hest_match_pci(struct acpi_hest_aer_common *p, struct pci_dev *pci)
{
return (0 == pci_domain_nr(pci->bus) &&
p->bus == pci->bus->number &&
p->device == PCI_SLOT(pci->devfn) &&
p->function == PCI_FUNC(pci->devfn));
}
static unsigned long parse_acpi_hest_aer(void *hdr, int type, struct pci_dev *pci, int *firmware_first)
{
struct acpi_hest_aer_common *p = hdr + sizeof(struct acpi_hest_header);
unsigned long rc=0;
u8 pcie_type = 0;
u8 bridge = 0;
switch (type) {
case ACPI_HEST_TYPE_AER_ROOT_PORT:
rc = sizeof(struct acpi_hest_aer_root);
pcie_type = PCI_EXP_TYPE_ROOT_PORT;
break;
case ACPI_HEST_TYPE_AER_ENDPOINT:
rc = sizeof(struct acpi_hest_aer);
pcie_type = PCI_EXP_TYPE_ENDPOINT;
break;
case ACPI_HEST_TYPE_AER_BRIDGE:
rc = sizeof(struct acpi_hest_aer_bridge);
if ((pci->class >> 16) == PCI_BASE_CLASS_BRIDGE)
bridge = 1;
break;
}
if (p->flags & ACPI_HEST_GLOBAL) {
if ((pci->is_pcie && (pci->pcie_type == pcie_type)) || bridge)
*firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
}
else
if (hest_match_pci(p, pci))
*firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST);
return rc;
}
static int acpi_hest_firmware_first(struct acpi_table_header *stdheader, struct pci_dev *pci)
{
struct acpi_table_hest *hest = (struct acpi_table_hest *)stdheader;
void *p = (void *)hest + sizeof(*hest); /* defined by the ACPI 4.0 spec */
struct acpi_hest_header *hdr = p;
int i;
int firmware_first = 0;
static unsigned char printed_unused = 0;
static unsigned char printed_reserved = 0;
for (i=0, hdr=p; p < (((void *)hest) + hest->header.length) && i < hest->error_source_count; i++) {
switch (hdr->type) {
case ACPI_HEST_TYPE_IA32_CHECK:
p += parse_acpi_hest_ia_machine_check(p);
break;
case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK:
p += parse_acpi_hest_ia_corrected(p);
break;
case ACPI_HEST_TYPE_IA32_NMI:
p += parse_acpi_hest_ia_nmi(p);
break;
/* These three should never appear */
case ACPI_HEST_TYPE_NOT_USED3:
case ACPI_HEST_TYPE_NOT_USED4:
case ACPI_HEST_TYPE_NOT_USED5:
if (!printed_unused) {
printk(KERN_DEBUG PREFIX
"HEST Error Source list contains an obsolete type (%d).\n", hdr->type);
printed_unused = 1;
}
break;
case ACPI_HEST_TYPE_AER_ROOT_PORT:
case ACPI_HEST_TYPE_AER_ENDPOINT:
case ACPI_HEST_TYPE_AER_BRIDGE:
p += parse_acpi_hest_aer(p, hdr->type, pci, &firmware_first);
break;
case ACPI_HEST_TYPE_GENERIC_ERROR:
p += parse_acpi_hest_generic(p);
break;
/* These should never appear either */
case ACPI_HEST_TYPE_RESERVED:
default:
if (!printed_reserved) {
printk(KERN_DEBUG PREFIX
"HEST Error Source list contains a reserved type (%d).\n", hdr->type);
printed_reserved = 1;
}
break;
}
}
return firmware_first;
}
int acpi_hest_firmware_first_pci(struct pci_dev *pci)
{
acpi_status status = AE_NOT_FOUND;
struct acpi_table_header *hest = NULL;
status = acpi_get_table(ACPI_SIG_HEST, 1, &hest);
if (ACPI_SUCCESS(status)) {
if (acpi_hest_firmware_first(hest, pci)) {
return 1;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(acpi_hest_firmware_first_pci);

View file

@ -42,6 +42,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <xen/xen.h>
#include <xen/xenbus.h> #include <xen/xenbus.h>
#include <xen/grant_table.h> #include <xen/grant_table.h>
#include <xen/events.h> #include <xen/events.h>

View file

@ -25,6 +25,8 @@
#include <linux/types.h> #include <linux/types.h>
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
#include <xen/xen.h>
#include <xen/page.h> #include <xen/page.h>
#include <xen/events.h> #include <xen/events.h>
#include <xen/interface/io/console.h> #include <xen/interface/io/console.h>

View file

@ -21,7 +21,10 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/input.h> #include <linux/input.h>
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
#include <xen/xen.h>
#include <xen/events.h> #include <xen/events.h>
#include <xen/page.h> #include <xen/page.h>
#include <xen/interface/io/fbif.h> #include <xen/interface/io/fbif.h>

View file

@ -42,6 +42,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <net/ip.h> #include <net/ip.h>
#include <xen/xen.h>
#include <xen/xenbus.h> #include <xen/xenbus.h>
#include <xen/events.h> #include <xen/events.h>
#include <xen/page.h> #include <xen/page.h>

View file

@ -27,10 +27,10 @@ config PCI_LEGACY
default y default y
help help
Say Y here if you want to include support for the deprecated Say Y here if you want to include support for the deprecated
pci_find_slot() and pci_find_device() APIs. Most drivers have pci_find_device() API. Most drivers have been converted over
been converted over to using the proper hotplug APIs, so this to using the proper hotplug APIs, so this option serves to
option serves to include/exclude only a few drivers that are include/exclude only a few drivers that are still using this
still using this API. API.
config PCI_DEBUG config PCI_DEBUG
bool "PCI Debugging" bool "PCI Debugging"
@ -69,3 +69,10 @@ config PCI_IOV
physical resources. physical resources.
If unsure, say N. If unsure, say N.
config PCI_IOAPIC
bool
depends on PCI
depends on ACPI
depends on HOTPLUG
default y

View file

@ -14,6 +14,8 @@ CFLAGS_legacy.o += -Wno-deprecated-declarations
# Build PCI Express stuff if needed # Build PCI Express stuff if needed
obj-$(CONFIG_PCIEPORTBUS) += pcie/ obj-$(CONFIG_PCIEPORTBUS) += pcie/
obj-$(CONFIG_PCI_IOAPIC) += ioapic.o
obj-$(CONFIG_HOTPLUG) += hotplug.o obj-$(CONFIG_HOTPLUG) += hotplug.o
# Build the PCI Hotplug drivers if we were asked to # Build the PCI Hotplug drivers if we were asked to

View file

@ -320,7 +320,7 @@ found:
for (bus = dev->bus; bus; bus = bus->parent) { for (bus = dev->bus; bus; bus = bus->parent) {
struct pci_dev *bridge = bus->self; struct pci_dev *bridge = bus->self;
if (!bridge || !bridge->is_pcie || if (!bridge || !pci_is_pcie(bridge) ||
bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) bridge->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE)
return 0; return 0;
@ -645,8 +645,11 @@ void __init detect_intel_iommu(void)
"x2apic and Intr-remapping.\n"); "x2apic and Intr-remapping.\n");
#endif #endif
#ifdef CONFIG_DMAR #ifdef CONFIG_DMAR
if (ret && !no_iommu && !iommu_detected && !dmar_disabled) if (ret && !no_iommu && !iommu_detected && !dmar_disabled) {
iommu_detected = 1; iommu_detected = 1;
/* Make sure ACS will be enabled */
pci_request_acs();
}
#endif #endif
#ifdef CONFIG_X86 #ifdef CONFIG_X86
if (ret) if (ret)

View file

@ -6,18 +6,22 @@ obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o
obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o
obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o
# pciehp should be linked before acpiphp in order to allow the native driver # native drivers should be linked before acpiphp in order to allow the
# to attempt to bind first. We can then fall back to generic support. # native driver to attempt to bind first. We can then fall back to
# generic support.
obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o
obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o
obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o
obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o
obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o
obj-$(CONFIG_HOTPLUG_PCI_SHPC) += shpchp.o obj-$(CONFIG_HOTPLUG_PCI_SHPC) += shpchp.o
obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o
obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o
obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o
obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o
# acpiphp_ibm extends acpiphp, so should be linked afterwards.
obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o
# Link this last so it doesn't claim devices that have a real hotplug driver # Link this last so it doesn't claim devices that have a real hotplug driver
obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.o

View file

@ -362,6 +362,8 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
status = acpi_pci_osc_control_set(handle, flags); status = acpi_pci_osc_control_set(handle, flags);
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
goto got_one; goto got_one;
if (status == AE_SUPPORT)
goto no_control;
kfree(string.pointer); kfree(string.pointer);
string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL }; string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL };
} }
@ -394,10 +396,9 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
break; break;
} }
no_control:
dbg("Cannot get control of hotplug hardware for pci %s\n", dbg("Cannot get control of hotplug hardware for pci %s\n",
pci_name(pdev)); pci_name(pdev));
kfree(string.pointer); kfree(string.pointer);
return -ENODEV; return -ENODEV;
got_one: got_one:

View file

@ -146,12 +146,6 @@ struct acpiphp_attention_info
struct module *owner; struct module *owner;
}; };
struct acpiphp_ioapic {
struct pci_dev *dev;
u32 gsi_base;
struct list_head list;
};
/* PCI bus bridge HID */ /* PCI bus bridge HID */
#define ACPI_PCI_HOST_HID "PNP0A03" #define ACPI_PCI_HOST_HID "PNP0A03"

View file

@ -52,8 +52,6 @@
#include "acpiphp.h" #include "acpiphp.h"
static LIST_HEAD(bridge_list); static LIST_HEAD(bridge_list);
static LIST_HEAD(ioapic_list);
static DEFINE_SPINLOCK(ioapic_list_lock);
#define MY_NAME "acpiphp_glue" #define MY_NAME "acpiphp_glue"
@ -311,17 +309,13 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
/* find acpiphp_func from acpiphp_bridge */ /* find acpiphp_func from acpiphp_bridge */
static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle) static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
{ {
struct list_head *node, *l;
struct acpiphp_bridge *bridge; struct acpiphp_bridge *bridge;
struct acpiphp_slot *slot; struct acpiphp_slot *slot;
struct acpiphp_func *func; struct acpiphp_func *func;
list_for_each(node, &bridge_list) { list_for_each_entry(bridge, &bridge_list, list) {
bridge = list_entry(node, struct acpiphp_bridge, list);
for (slot = bridge->slots; slot; slot = slot->next) { for (slot = bridge->slots; slot; slot = slot->next) {
list_for_each(l, &slot->funcs) { list_for_each_entry(func, &slot->funcs, sibling) {
func = list_entry(l, struct acpiphp_func,
sibling);
if (func->handle == handle) if (func->handle == handle)
return func; return func;
} }
@ -495,21 +489,19 @@ static int add_bridge(acpi_handle handle)
static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle) static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
{ {
struct list_head *head; struct acpiphp_bridge *bridge;
list_for_each(head, &bridge_list) {
struct acpiphp_bridge *bridge = list_entry(head, list_for_each_entry(bridge, &bridge_list, list)
struct acpiphp_bridge, list);
if (bridge->handle == handle) if (bridge->handle == handle)
return bridge; return bridge;
}
return NULL; return NULL;
} }
static void cleanup_bridge(struct acpiphp_bridge *bridge) static void cleanup_bridge(struct acpiphp_bridge *bridge)
{ {
struct list_head *list, *tmp; struct acpiphp_slot *slot, *next;
struct acpiphp_slot *slot; struct acpiphp_func *func, *tmp;
acpi_status status; acpi_status status;
acpi_handle handle = bridge->handle; acpi_handle handle = bridge->handle;
@ -530,10 +522,8 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
slot = bridge->slots; slot = bridge->slots;
while (slot) { while (slot) {
struct acpiphp_slot *next = slot->next; next = slot->next;
list_for_each_safe (list, tmp, &slot->funcs) { list_for_each_entry_safe(func, tmp, &slot->funcs, sibling) {
struct acpiphp_func *func;
func = list_entry(list, struct acpiphp_func, sibling);
if (is_dock_device(func->handle)) { if (is_dock_device(func->handle)) {
unregister_hotplug_dock_device(func->handle); unregister_hotplug_dock_device(func->handle);
unregister_dock_notifier(&func->nb); unregister_dock_notifier(&func->nb);
@ -545,7 +535,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
err("failed to remove notify handler\n"); err("failed to remove notify handler\n");
} }
list_del(list); list_del(&func->sibling);
kfree(func); kfree(func);
} }
acpiphp_unregister_hotplug_slot(slot); acpiphp_unregister_hotplug_slot(slot);
@ -606,204 +596,17 @@ static void remove_bridge(acpi_handle handle)
handle_hotplug_event_bridge); handle_hotplug_event_bridge);
} }
static struct pci_dev * get_apic_pci_info(acpi_handle handle)
{
struct pci_dev *dev;
dev = acpi_get_pci_dev(handle);
if (!dev)
return NULL;
if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) &&
(dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC))
{
pci_dev_put(dev);
return NULL;
}
return dev;
}
static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
{
acpi_status status;
int result = -1;
unsigned long long gsb;
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *obj;
void *table;
status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
if (ACPI_SUCCESS(status)) {
*gsi_base = (u32)gsb;
return 0;
}
status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer);
if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer)
return -1;
obj = buffer.pointer;
if (obj->type != ACPI_TYPE_BUFFER)
goto out;
table = obj->buffer.pointer;
switch (((struct acpi_subtable_header *)table)->type) {
case ACPI_MADT_TYPE_IO_SAPIC:
*gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base;
result = 0;
break;
case ACPI_MADT_TYPE_IO_APIC:
*gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base;
result = 0;
break;
default:
break;
}
out:
kfree(buffer.pointer);
return result;
}
static acpi_status
ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
unsigned long long sta;
acpi_handle tmp;
struct pci_dev *pdev;
u32 gsi_base;
u64 phys_addr;
struct acpiphp_ioapic *ioapic;
/* Evaluate _STA if present */
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL)
return AE_CTRL_DEPTH;
/* Scan only PCI bus scope */
status = acpi_get_handle(handle, "_HID", &tmp);
if (ACPI_SUCCESS(status))
return AE_CTRL_DEPTH;
if (get_gsi_base(handle, &gsi_base))
return AE_OK;
ioapic = kmalloc(sizeof(*ioapic), GFP_KERNEL);
if (!ioapic)
return AE_NO_MEMORY;
pdev = get_apic_pci_info(handle);
if (!pdev)
goto exit_kfree;
if (pci_enable_device(pdev))
goto exit_pci_dev_put;
pci_set_master(pdev);
if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)"))
goto exit_pci_disable_device;
phys_addr = pci_resource_start(pdev, 0);
if (acpi_register_ioapic(handle, phys_addr, gsi_base))
goto exit_pci_release_region;
ioapic->gsi_base = gsi_base;
ioapic->dev = pdev;
spin_lock(&ioapic_list_lock);
list_add_tail(&ioapic->list, &ioapic_list);
spin_unlock(&ioapic_list_lock);
return AE_OK;
exit_pci_release_region:
pci_release_region(pdev, 0);
exit_pci_disable_device:
pci_disable_device(pdev);
exit_pci_dev_put:
pci_dev_put(pdev);
exit_kfree:
kfree(ioapic);
return AE_OK;
}
static acpi_status
ioapic_remove(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
unsigned long long sta;
acpi_handle tmp;
u32 gsi_base;
struct acpiphp_ioapic *pos, *n, *ioapic = NULL;
/* Evaluate _STA if present */
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL)
return AE_CTRL_DEPTH;
/* Scan only PCI bus scope */
status = acpi_get_handle(handle, "_HID", &tmp);
if (ACPI_SUCCESS(status))
return AE_CTRL_DEPTH;
if (get_gsi_base(handle, &gsi_base))
return AE_OK;
acpi_unregister_ioapic(handle, gsi_base);
spin_lock(&ioapic_list_lock);
list_for_each_entry_safe(pos, n, &ioapic_list, list) {
if (pos->gsi_base != gsi_base)
continue;
ioapic = pos;
list_del(&ioapic->list);
break;
}
spin_unlock(&ioapic_list_lock);
if (!ioapic)
return AE_OK;
pci_release_region(ioapic->dev, 0);
pci_disable_device(ioapic->dev);
pci_dev_put(ioapic->dev);
kfree(ioapic);
return AE_OK;
}
static int acpiphp_configure_ioapics(acpi_handle handle)
{
ioapic_add(handle, 0, NULL, NULL);
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
ACPI_UINT32_MAX, ioapic_add, NULL, NULL, NULL);
return 0;
}
static int acpiphp_unconfigure_ioapics(acpi_handle handle)
{
ioapic_remove(handle, 0, NULL, NULL);
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
ACPI_UINT32_MAX, ioapic_remove, NULL, NULL, NULL);
return 0;
}
static int power_on_slot(struct acpiphp_slot *slot) static int power_on_slot(struct acpiphp_slot *slot)
{ {
acpi_status status; acpi_status status;
struct acpiphp_func *func; struct acpiphp_func *func;
struct list_head *l;
int retval = 0; int retval = 0;
/* if already enabled, just skip */ /* if already enabled, just skip */
if (slot->flags & SLOT_POWEREDON) if (slot->flags & SLOT_POWEREDON)
goto err_exit; goto err_exit;
list_for_each (l, &slot->funcs) { list_for_each_entry(func, &slot->funcs, sibling) {
func = list_entry(l, struct acpiphp_func, sibling);
if (func->flags & FUNC_HAS_PS0) { if (func->flags & FUNC_HAS_PS0) {
dbg("%s: executing _PS0\n", __func__); dbg("%s: executing _PS0\n", __func__);
status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
@ -829,7 +632,6 @@ static int power_off_slot(struct acpiphp_slot *slot)
{ {
acpi_status status; acpi_status status;
struct acpiphp_func *func; struct acpiphp_func *func;
struct list_head *l;
int retval = 0; int retval = 0;
@ -837,9 +639,7 @@ static int power_off_slot(struct acpiphp_slot *slot)
if ((slot->flags & SLOT_POWEREDON) == 0) if ((slot->flags & SLOT_POWEREDON) == 0)
goto err_exit; goto err_exit;
list_for_each (l, &slot->funcs) { list_for_each_entry(func, &slot->funcs, sibling) {
func = list_entry(l, struct acpiphp_func, sibling);
if (func->flags & FUNC_HAS_PS3) { if (func->flags & FUNC_HAS_PS3) {
status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
@ -966,7 +766,6 @@ static int __ref enable_device(struct acpiphp_slot *slot)
{ {
struct pci_dev *dev; struct pci_dev *dev;
struct pci_bus *bus = slot->bridge->pci_bus; struct pci_bus *bus = slot->bridge->pci_bus;
struct list_head *l;
struct acpiphp_func *func; struct acpiphp_func *func;
int retval = 0; int retval = 0;
int num, max, pass; int num, max, pass;
@ -1006,21 +805,16 @@ static int __ref enable_device(struct acpiphp_slot *slot)
} }
} }
list_for_each (l, &slot->funcs) { list_for_each_entry(func, &slot->funcs, sibling)
func = list_entry(l, struct acpiphp_func, sibling);
acpiphp_bus_add(func); acpiphp_bus_add(func);
}
pci_bus_assign_resources(bus); pci_bus_assign_resources(bus);
acpiphp_sanitize_bus(bus); acpiphp_sanitize_bus(bus);
acpiphp_set_hpp_values(bus); acpiphp_set_hpp_values(bus);
list_for_each_entry(func, &slot->funcs, sibling)
acpiphp_configure_ioapics(func->handle);
pci_enable_bridges(bus); pci_enable_bridges(bus);
pci_bus_add_devices(bus); pci_bus_add_devices(bus);
list_for_each (l, &slot->funcs) { list_for_each_entry(func, &slot->funcs, sibling) {
func = list_entry(l, struct acpiphp_func, sibling);
dev = pci_get_slot(bus, PCI_DEVFN(slot->device, dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
func->function)); func->function));
if (!dev) if (!dev)
@ -1091,7 +885,6 @@ static int disable_device(struct acpiphp_slot *slot)
} }
list_for_each_entry(func, &slot->funcs, sibling) { list_for_each_entry(func, &slot->funcs, sibling) {
acpiphp_unconfigure_ioapics(func->handle);
acpiphp_bus_trim(func->handle); acpiphp_bus_trim(func->handle);
} }
@ -1119,12 +912,9 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
acpi_status status; acpi_status status;
unsigned long long sta = 0; unsigned long long sta = 0;
u32 dvid; u32 dvid;
struct list_head *l;
struct acpiphp_func *func; struct acpiphp_func *func;
list_for_each (l, &slot->funcs) { list_for_each_entry(func, &slot->funcs, sibling) {
func = list_entry(l, struct acpiphp_func, sibling);
if (func->flags & FUNC_HAS_STA) { if (func->flags & FUNC_HAS_STA) {
status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta);
if (ACPI_SUCCESS(status) && sta) if (ACPI_SUCCESS(status) && sta)
@ -1152,13 +942,10 @@ int acpiphp_eject_slot(struct acpiphp_slot *slot)
{ {
acpi_status status; acpi_status status;
struct acpiphp_func *func; struct acpiphp_func *func;
struct list_head *l;
struct acpi_object_list arg_list; struct acpi_object_list arg_list;
union acpi_object arg; union acpi_object arg;
list_for_each (l, &slot->funcs) { list_for_each_entry(func, &slot->funcs, sibling) {
func = list_entry(l, struct acpiphp_func, sibling);
/* We don't want to call _EJ0 on non-existing functions. */ /* We don't want to call _EJ0 on non-existing functions. */
if ((func->flags & FUNC_HAS_EJ0)) { if ((func->flags & FUNC_HAS_EJ0)) {
/* _EJ0 method take one argument */ /* _EJ0 method take one argument */
@ -1275,7 +1062,6 @@ static int acpiphp_configure_bridge (acpi_handle handle)
acpiphp_sanitize_bus(bus); acpiphp_sanitize_bus(bus);
acpiphp_set_hpp_values(bus); acpiphp_set_hpp_values(bus);
pci_enable_bridges(bus); pci_enable_bridges(bus);
acpiphp_configure_ioapics(handle);
return 0; return 0;
} }

View file

@ -890,7 +890,7 @@ static int poll_hpc(void *data)
msleep(POLL_INTERVAL_SEC * 1000); msleep(POLL_INTERVAL_SEC * 1000);
if (kthread_should_stop()) if (kthread_should_stop())
break; goto out_sleep;
down (&semOperations); down (&semOperations);
@ -904,6 +904,7 @@ static int poll_hpc(void *data)
/* give up the hardware semaphore */ /* give up the hardware semaphore */
up (&semOperations); up (&semOperations);
/* sleep for a short time just for good measure */ /* sleep for a short time just for good measure */
out_sleep:
msleep(100); msleep(100);
} }
up (&sem_exit); up (&sem_exit);

View file

@ -68,26 +68,26 @@ static DEFINE_MUTEX(pci_hp_mutex);
static char *pci_bus_speed_strings[] = { static char *pci_bus_speed_strings[] = {
"33 MHz PCI", /* 0x00 */ "33 MHz PCI", /* 0x00 */
"66 MHz PCI", /* 0x01 */ "66 MHz PCI", /* 0x01 */
"66 MHz PCIX", /* 0x02 */ "66 MHz PCI-X", /* 0x02 */
"100 MHz PCIX", /* 0x03 */ "100 MHz PCI-X", /* 0x03 */
"133 MHz PCIX", /* 0x04 */ "133 MHz PCI-X", /* 0x04 */
NULL, /* 0x05 */ NULL, /* 0x05 */
NULL, /* 0x06 */ NULL, /* 0x06 */
NULL, /* 0x07 */ NULL, /* 0x07 */
NULL, /* 0x08 */ NULL, /* 0x08 */
"66 MHz PCIX 266", /* 0x09 */ "66 MHz PCI-X 266", /* 0x09 */
"100 MHz PCIX 266", /* 0x0a */ "100 MHz PCI-X 266", /* 0x0a */
"133 MHz PCIX 266", /* 0x0b */ "133 MHz PCI-X 266", /* 0x0b */
NULL, /* 0x0c */ NULL, /* 0x0c */
NULL, /* 0x0d */ NULL, /* 0x0d */
NULL, /* 0x0e */ NULL, /* 0x0e */
NULL, /* 0x0f */ NULL, /* 0x0f */
NULL, /* 0x10 */ NULL, /* 0x10 */
"66 MHz PCIX 533", /* 0x11 */ "66 MHz PCI-X 533", /* 0x11 */
"100 MHz PCIX 533", /* 0x12 */ "100 MHz PCI-X 533", /* 0x12 */
"133 MHz PCIX 533", /* 0x13 */ "133 MHz PCI-X 533", /* 0x13 */
"2.5 GT/s PCI-E", /* 0x14 */ "2.5 GT/s PCIe", /* 0x14 */
"5.0 GT/s PCI-E", /* 0x15 */ "5.0 GT/s PCIe", /* 0x15 */
}; };
#ifdef CONFIG_HOTPLUG_PCI_CPCI #ifdef CONFIG_HOTPLUG_PCI_CPCI

View file

@ -91,7 +91,6 @@ struct controller {
struct slot *slot; struct slot *slot;
wait_queue_head_t queue; /* sleep & wake process */ wait_queue_head_t queue; /* sleep & wake process */
u32 slot_cap; u32 slot_cap;
u8 cap_base;
struct timer_list poll_timer; struct timer_list poll_timer;
unsigned int cmd_busy:1; unsigned int cmd_busy:1;
unsigned int no_cmd_complete:1; unsigned int no_cmd_complete:1;

View file

@ -87,7 +87,8 @@ static int __init dummy_probe(struct pcie_device *dev)
/* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */ /* Note: pciehp_detect_mode != PCIEHP_DETECT_ACPI here */
if (pciehp_get_hp_hw_control_from_firmware(pdev)) if (pciehp_get_hp_hw_control_from_firmware(pdev))
return -ENODEV; return -ENODEV;
if (!(pos = pci_find_capability(pdev, PCI_CAP_ID_EXP))) pos = pci_pcie_cap(pdev);
if (!pos)
return -ENODEV; return -ENODEV;
pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap); pci_read_config_dword(pdev, pos + PCI_EXP_SLTCAP, &slot_cap);
slot = kzalloc(sizeof(*slot), GFP_KERNEL); slot = kzalloc(sizeof(*slot), GFP_KERNEL);

View file

@ -72,18 +72,6 @@ static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
.set_attention_status = set_attention_status,
.enable_slot = enable_slot,
.disable_slot = disable_slot,
.get_power_status = get_power_status,
.get_attention_status = get_attention_status,
.get_latch_status = get_latch_status,
.get_adapter_status = get_adapter_status,
.get_max_bus_speed = get_max_bus_speed,
.get_cur_bus_speed = get_cur_bus_speed,
};
/** /**
* release_slot - free up the memory used by a slot * release_slot - free up the memory used by a slot
* @hotplug_slot: slot to free * @hotplug_slot: slot to free
@ -95,6 +83,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, hotplug_slot_name(hotplug_slot)); __func__, hotplug_slot_name(hotplug_slot));
kfree(hotplug_slot->ops);
kfree(hotplug_slot->info); kfree(hotplug_slot->info);
kfree(hotplug_slot); kfree(hotplug_slot);
} }
@ -104,6 +93,7 @@ static int init_slot(struct controller *ctrl)
struct slot *slot = ctrl->slot; struct slot *slot = ctrl->slot;
struct hotplug_slot *hotplug = NULL; struct hotplug_slot *hotplug = NULL;
struct hotplug_slot_info *info = NULL; struct hotplug_slot_info *info = NULL;
struct hotplug_slot_ops *ops = NULL;
char name[SLOT_NAME_SIZE]; char name[SLOT_NAME_SIZE];
int retval = -ENOMEM; int retval = -ENOMEM;
@ -115,11 +105,28 @@ static int init_slot(struct controller *ctrl)
if (!info) if (!info)
goto out; goto out;
/* Setup hotplug slot ops */
ops = kzalloc(sizeof(*ops), GFP_KERNEL);
if (!ops)
goto out;
ops->enable_slot = enable_slot;
ops->disable_slot = disable_slot;
ops->get_power_status = get_power_status;
ops->get_adapter_status = get_adapter_status;
ops->get_max_bus_speed = get_max_bus_speed;
ops->get_cur_bus_speed = get_cur_bus_speed;
if (MRL_SENS(ctrl))
ops->get_latch_status = get_latch_status;
if (ATTN_LED(ctrl)) {
ops->get_attention_status = get_attention_status;
ops->set_attention_status = set_attention_status;
}
/* register this slot with the hotplug pci core */ /* register this slot with the hotplug pci core */
hotplug->info = info; hotplug->info = info;
hotplug->private = slot; hotplug->private = slot;
hotplug->release = &release_slot; hotplug->release = &release_slot;
hotplug->ops = &pciehp_hotplug_slot_ops; hotplug->ops = ops;
slot->hotplug_slot = hotplug; slot->hotplug_slot = hotplug;
snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl)); snprintf(name, SLOT_NAME_SIZE, "%u", PSN(ctrl));
@ -128,17 +135,12 @@ static int init_slot(struct controller *ctrl)
ctrl->pcie->port->subordinate->number, PSN(ctrl)); ctrl->pcie->port->subordinate->number, PSN(ctrl));
retval = pci_hp_register(hotplug, retval = pci_hp_register(hotplug,
ctrl->pcie->port->subordinate, 0, name); ctrl->pcie->port->subordinate, 0, name);
if (retval) { if (retval)
ctrl_err(ctrl, ctrl_err(ctrl,
"pci_hp_register failed with error %d\n", retval); "pci_hp_register failed with error %d\n", retval);
goto out;
}
get_power_status(hotplug, &info->power_status);
get_attention_status(hotplug, &info->attention_status);
get_latch_status(hotplug, &info->latch_status);
get_adapter_status(hotplug, &info->adapter_status);
out: out:
if (retval) { if (retval) {
kfree(ops);
kfree(info); kfree(info);
kfree(hotplug); kfree(hotplug);
} }
@ -160,12 +162,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
hotplug_slot->info->attention_status = status; return pciehp_set_attention_status(slot, status);
if (ATTN_LED(slot->ctrl))
pciehp_set_attention_status(slot, status);
return 0;
} }
@ -193,92 +190,62 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
{ {
struct slot *slot = hotplug_slot->private; struct slot *slot = hotplug_slot->private;
int retval;
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
retval = pciehp_get_power_status(slot, value); return pciehp_get_power_status(slot, value);
if (retval < 0)
*value = hotplug_slot->info->power_status;
return 0;
} }
static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 *value)
{ {
struct slot *slot = hotplug_slot->private; struct slot *slot = hotplug_slot->private;
int retval;
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
retval = pciehp_get_attention_status(slot, value); return pciehp_get_attention_status(slot, value);
if (retval < 0)
*value = hotplug_slot->info->attention_status;
return 0;
} }
static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 *value)
{ {
struct slot *slot = hotplug_slot->private; struct slot *slot = hotplug_slot->private;
int retval;
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
retval = pciehp_get_latch_status(slot, value); return pciehp_get_latch_status(slot, value);
if (retval < 0)
*value = hotplug_slot->info->latch_status;
return 0;
} }
static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
{ {
struct slot *slot = hotplug_slot->private; struct slot *slot = hotplug_slot->private;
int retval;
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
retval = pciehp_get_adapter_status(slot, value); return pciehp_get_adapter_status(slot, value);
if (retval < 0)
*value = hotplug_slot->info->adapter_status;
return 0;
} }
static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, static int get_max_bus_speed(struct hotplug_slot *hotplug_slot,
enum pci_bus_speed *value) enum pci_bus_speed *value)
{ {
struct slot *slot = hotplug_slot->private; struct slot *slot = hotplug_slot->private;
int retval;
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
retval = pciehp_get_max_link_speed(slot, value); return pciehp_get_max_link_speed(slot, value);
if (retval < 0)
*value = PCI_SPEED_UNKNOWN;
return 0;
} }
static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
{ {
struct slot *slot = hotplug_slot->private; struct slot *slot = hotplug_slot->private;
int retval;
ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n", ctrl_dbg(slot->ctrl, "%s: physical_slot = %s\n",
__func__, slot_name(slot)); __func__, slot_name(slot));
retval = pciehp_get_cur_link_speed(slot, value); return pciehp_get_cur_link_speed(slot, value);
if (retval < 0)
*value = PCI_SPEED_UNKNOWN;
return 0;
} }
static int pciehp_probe(struct pcie_device *dev) static int pciehp_probe(struct pcie_device *dev)
@ -286,14 +253,13 @@ static int pciehp_probe(struct pcie_device *dev)
int rc; int rc;
struct controller *ctrl; struct controller *ctrl;
struct slot *slot; struct slot *slot;
u8 value; u8 occupied, poweron;
struct pci_dev *pdev = dev->port;
if (pciehp_force) if (pciehp_force)
dev_info(&dev->device, dev_info(&dev->device,
"Bypassing BIOS check for pciehp use on %s\n", "Bypassing BIOS check for pciehp use on %s\n",
pci_name(pdev)); pci_name(dev->port));
else if (pciehp_get_hp_hw_control_from_firmware(pdev)) else if (pciehp_get_hp_hw_control_from_firmware(dev->port))
goto err_out_none; goto err_out_none;
ctrl = pcie_init(dev); ctrl = pcie_init(dev);
@ -318,23 +284,18 @@ static int pciehp_probe(struct pcie_device *dev)
rc = pcie_init_notification(ctrl); rc = pcie_init_notification(ctrl);
if (rc) { if (rc) {
ctrl_err(ctrl, "Notification initialization failed\n"); ctrl_err(ctrl, "Notification initialization failed\n");
goto err_out_release_ctlr; goto err_out_free_ctrl_slot;
} }
/* Check if slot is occupied */ /* Check if slot is occupied */
slot = ctrl->slot; slot = ctrl->slot;
pciehp_get_adapter_status(slot, &value); pciehp_get_adapter_status(slot, &occupied);
if (value) { pciehp_get_power_status(slot, &poweron);
if (pciehp_force) if (occupied && pciehp_force)
pciehp_enable_slot(slot); pciehp_enable_slot(slot);
} else { /* If empty slot's power status is on, turn power off */
/* Power off slot if not occupied */ if (!occupied && poweron && POWER_CTRL(ctrl))
if (POWER_CTRL(ctrl)) { pciehp_power_off_slot(slot);
rc = pciehp_power_off_slot(slot);
if (rc)
goto err_out_free_ctrl_slot;
}
}
return 0; return 0;

View file

@ -142,23 +142,9 @@ u8 pciehp_handle_power_fault(struct slot *p_slot)
/* power fault */ /* power fault */
ctrl_dbg(ctrl, "Power fault interrupt received\n"); ctrl_dbg(ctrl, "Power fault interrupt received\n");
ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot));
if (!pciehp_query_power_fault(p_slot)) {
/*
* power fault Cleared
*/
ctrl_info(ctrl, "Power fault cleared on Slot(%s)\n",
slot_name(p_slot));
event_type = INT_POWER_FAULT_CLEAR;
} else {
/*
* power fault
*/
ctrl_info(ctrl, "Power fault on Slot(%s)\n", slot_name(p_slot));
event_type = INT_POWER_FAULT; event_type = INT_POWER_FAULT;
ctrl_info(ctrl, "Power fault bit %x set\n", 0); ctrl_info(ctrl, "Power fault bit %x set\n", 0);
}
queue_interrupt_event(p_slot, event_type); queue_interrupt_event(p_slot, event_type);
return 1; return 1;
@ -224,13 +210,12 @@ static int board_added(struct slot *p_slot)
retval = pciehp_check_link_status(ctrl); retval = pciehp_check_link_status(ctrl);
if (retval) { if (retval) {
ctrl_err(ctrl, "Failed to check link status\n"); ctrl_err(ctrl, "Failed to check link status\n");
set_slot_off(ctrl, p_slot); goto err_exit;
return retval;
} }
/* Check for a power fault */ /* Check for a power fault */
if (pciehp_query_power_fault(p_slot)) { if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) {
ctrl_dbg(ctrl, "Power fault detected\n"); ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot));
retval = -EIO; retval = -EIO;
goto err_exit; goto err_exit;
} }
@ -363,25 +348,6 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
mutex_unlock(&p_slot->lock); mutex_unlock(&p_slot->lock);
} }
static int update_slot_info(struct slot *slot)
{
struct hotplug_slot_info *info;
int result;
info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
pciehp_get_power_status(slot, &info->power_status);
pciehp_get_attention_status(slot, &info->attention_status);
pciehp_get_latch_status(slot, &info->latch_status);
pciehp_get_adapter_status(slot, &info->adapter_status);
result = pci_hp_change_slot_info(slot->hotplug_slot, info);
kfree (info);
return result;
}
/* /*
* Note: This function must be called with slot->lock held * Note: This function must be called with slot->lock held
*/ */
@ -442,7 +408,6 @@ static void handle_button_press_event(struct slot *p_slot)
* to hot-add or hot-remove is undergoing * to hot-add or hot-remove is undergoing
*/ */
ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot)); ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot));
update_slot_info(p_slot);
break; break;
default: default:
ctrl_warn(ctrl, "Not a valid state\n"); ctrl_warn(ctrl, "Not a valid state\n");
@ -500,11 +465,9 @@ static void interrupt_event_handler(struct work_struct *work)
if (!HP_SUPR_RM(ctrl)) if (!HP_SUPR_RM(ctrl))
break; break;
ctrl_dbg(ctrl, "Surprise Removal\n"); ctrl_dbg(ctrl, "Surprise Removal\n");
update_slot_info(p_slot);
handle_surprise_event(p_slot); handle_surprise_event(p_slot);
break; break;
default: default:
update_slot_info(p_slot);
break; break;
} }
mutex_unlock(&p_slot->lock); mutex_unlock(&p_slot->lock);
@ -547,9 +510,6 @@ int pciehp_enable_slot(struct slot *p_slot)
if (rc) { if (rc) {
pciehp_get_latch_status(p_slot, &getstatus); pciehp_get_latch_status(p_slot, &getstatus);
} }
update_slot_info(p_slot);
return rc; return rc;
} }
@ -590,10 +550,7 @@ int pciehp_disable_slot(struct slot *p_slot)
} }
} }
ret = remove_board(p_slot); return remove_board(p_slot);
update_slot_info(p_slot);
return ret;
} }
int pciehp_sysfs_enable_slot(struct slot *p_slot) int pciehp_sysfs_enable_slot(struct slot *p_slot)

View file

@ -45,25 +45,25 @@ static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);
static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value) static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value)
{ {
struct pci_dev *dev = ctrl->pcie->port; struct pci_dev *dev = ctrl->pcie->port;
return pci_read_config_word(dev, ctrl->cap_base + reg, value); return pci_read_config_word(dev, pci_pcie_cap(dev) + reg, value);
} }
static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value) static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value)
{ {
struct pci_dev *dev = ctrl->pcie->port; struct pci_dev *dev = ctrl->pcie->port;
return pci_read_config_dword(dev, ctrl->cap_base + reg, value); return pci_read_config_dword(dev, pci_pcie_cap(dev) + reg, value);
} }
static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value) static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value)
{ {
struct pci_dev *dev = ctrl->pcie->port; struct pci_dev *dev = ctrl->pcie->port;
return pci_write_config_word(dev, ctrl->cap_base + reg, value); return pci_write_config_word(dev, pci_pcie_cap(dev) + reg, value);
} }
static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value) static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
{ {
struct pci_dev *dev = ctrl->pcie->port; struct pci_dev *dev = ctrl->pcie->port;
return pci_write_config_dword(dev, ctrl->cap_base + reg, value); return pci_write_config_dword(dev, pci_pcie_cap(dev) + reg, value);
} }
/* Power Control Command */ /* Power Control Command */
@ -318,8 +318,8 @@ int pciehp_get_attention_status(struct slot *slot, u8 *status)
return retval; return retval;
} }
ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", __func__,
__func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl);
atten_led_state = (slot_ctrl & PCI_EXP_SLTCTL_AIC) >> 6; atten_led_state = (slot_ctrl & PCI_EXP_SLTCTL_AIC) >> 6;
@ -356,8 +356,8 @@ int pciehp_get_power_status(struct slot *slot, u8 *status)
ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__); ctrl_err(ctrl, "%s: Cannot read SLOTCTRL register\n", __func__);
return retval; return retval;
} }
ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", __func__,
__func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_ctrl); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl);
pwr_state = (slot_ctrl & PCI_EXP_SLTCTL_PCC) >> 10; pwr_state = (slot_ctrl & PCI_EXP_SLTCTL_PCC) >> 10;
@ -427,7 +427,6 @@ int pciehp_set_attention_status(struct slot *slot, u8 value)
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
u16 slot_cmd; u16 slot_cmd;
u16 cmd_mask; u16 cmd_mask;
int rc;
cmd_mask = PCI_EXP_SLTCTL_AIC; cmd_mask = PCI_EXP_SLTCTL_AIC;
switch (value) { switch (value) {
@ -441,13 +440,11 @@ int pciehp_set_attention_status(struct slot *slot, u8 value)
slot_cmd = 0x0080; slot_cmd = 0x0080;
break; break;
default: default:
return -1; return -EINVAL;
} }
rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
__func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); return pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
return rc;
} }
void pciehp_green_led_on(struct slot *slot) void pciehp_green_led_on(struct slot *slot)
@ -459,8 +456,8 @@ void pciehp_green_led_on(struct slot *slot)
slot_cmd = 0x0100; slot_cmd = 0x0100;
cmd_mask = PCI_EXP_SLTCTL_PIC; cmd_mask = PCI_EXP_SLTCTL_PIC;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask); pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
__func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
} }
void pciehp_green_led_off(struct slot *slot) void pciehp_green_led_off(struct slot *slot)
@ -472,8 +469,8 @@ void pciehp_green_led_off(struct slot *slot)
slot_cmd = 0x0300; slot_cmd = 0x0300;
cmd_mask = PCI_EXP_SLTCTL_PIC; cmd_mask = PCI_EXP_SLTCTL_PIC;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask); pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
__func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
} }
void pciehp_green_led_blink(struct slot *slot) void pciehp_green_led_blink(struct slot *slot)
@ -485,8 +482,8 @@ void pciehp_green_led_blink(struct slot *slot)
slot_cmd = 0x0200; slot_cmd = 0x0200;
cmd_mask = PCI_EXP_SLTCTL_PIC; cmd_mask = PCI_EXP_SLTCTL_PIC;
pcie_write_cmd(ctrl, slot_cmd, cmd_mask); pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
__func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
} }
int pciehp_power_on_slot(struct slot * slot) int pciehp_power_on_slot(struct slot * slot)
@ -514,98 +511,39 @@ int pciehp_power_on_slot(struct slot * slot)
return retval; return retval;
} }
} }
ctrl->power_fault_detected = 0;
slot_cmd = POWER_ON; slot_cmd = POWER_ON;
cmd_mask = PCI_EXP_SLTCTL_PCC; cmd_mask = PCI_EXP_SLTCTL_PCC;
if (!pciehp_poll_mode) {
/* Enable power fault detection turned off at power off time */
slot_cmd |= PCI_EXP_SLTCTL_PFDE;
cmd_mask |= PCI_EXP_SLTCTL_PFDE;
}
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
if (retval) { if (retval) {
ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd); ctrl_err(ctrl, "Write %x command failed!\n", slot_cmd);
return retval; return retval;
} }
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
__func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd); pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
ctrl->power_fault_detected = 0;
return retval; return retval;
} }
static inline int pcie_mask_bad_dllp(struct controller *ctrl)
{
struct pci_dev *dev = ctrl->pcie->port;
int pos;
u32 reg;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos)
return 0;
pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg);
if (reg & PCI_ERR_COR_BAD_DLLP)
return 0;
reg |= PCI_ERR_COR_BAD_DLLP;
pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
return 1;
}
static inline void pcie_unmask_bad_dllp(struct controller *ctrl)
{
struct pci_dev *dev = ctrl->pcie->port;
u32 reg;
int pos;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos)
return;
pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg);
if (!(reg & PCI_ERR_COR_BAD_DLLP))
return;
reg &= ~PCI_ERR_COR_BAD_DLLP;
pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg);
}
int pciehp_power_off_slot(struct slot * slot) int pciehp_power_off_slot(struct slot * slot)
{ {
struct controller *ctrl = slot->ctrl; struct controller *ctrl = slot->ctrl;
u16 slot_cmd; u16 slot_cmd;
u16 cmd_mask; u16 cmd_mask;
int retval = 0; int retval;
int changed;
/*
* Set Bad DLLP Mask bit in Correctable Error Mask
* Register. This is the workaround against Bad DLLP error
* that sometimes happens during turning power off the slot
* which conforms to PCI Express 1.0a spec.
*/
changed = pcie_mask_bad_dllp(ctrl);
slot_cmd = POWER_OFF; slot_cmd = POWER_OFF;
cmd_mask = PCI_EXP_SLTCTL_PCC; cmd_mask = PCI_EXP_SLTCTL_PCC;
if (!pciehp_poll_mode) {
/* Disable power fault detection */
slot_cmd &= ~PCI_EXP_SLTCTL_PFDE;
cmd_mask |= PCI_EXP_SLTCTL_PFDE;
}
retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
if (retval) { if (retval) {
ctrl_err(ctrl, "Write command failed!\n"); ctrl_err(ctrl, "Write command failed!\n");
retval = -1;
goto out;
}
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n",
__func__, ctrl->cap_base + PCI_EXP_SLTCTL, slot_cmd);
out:
if (changed)
pcie_unmask_bad_dllp(ctrl);
return retval; return retval;
} }
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd);
return 0;
}
static irqreturn_t pcie_isr(int irq, void *dev_id) static irqreturn_t pcie_isr(int irq, void *dev_id)
{ {
@ -840,11 +778,19 @@ int pcie_enable_notification(struct controller *ctrl)
{ {
u16 cmd, mask; u16 cmd, mask;
/*
* TBD: Power fault detected software notification support.
*
* Power fault detected software notification is not enabled
* now, because it caused power fault detected interrupt storm
* on some machines. On those machines, power fault detected
* bit in the slot status register was set again immediately
* when it is cleared in the interrupt service routine, and
* next power fault detected interrupt was notified again.
*/
cmd = PCI_EXP_SLTCTL_PDCE; cmd = PCI_EXP_SLTCTL_PDCE;
if (ATTN_BUTTN(ctrl)) if (ATTN_BUTTN(ctrl))
cmd |= PCI_EXP_SLTCTL_ABPE; cmd |= PCI_EXP_SLTCTL_ABPE;
if (POWER_CTRL(ctrl))
cmd |= PCI_EXP_SLTCTL_PFDE;
if (MRL_SENS(ctrl)) if (MRL_SENS(ctrl))
cmd |= PCI_EXP_SLTCTL_MRLSCE; cmd |= PCI_EXP_SLTCTL_MRLSCE;
if (!pciehp_poll_mode) if (!pciehp_poll_mode)
@ -866,7 +812,8 @@ static void pcie_disable_notification(struct controller *ctrl)
u16 mask; u16 mask;
mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE | mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE | PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE); PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
PCI_EXP_SLTCTL_DLLSCE);
if (pcie_write_cmd(ctrl, 0, mask)) if (pcie_write_cmd(ctrl, 0, mask))
ctrl_warn(ctrl, "Cannot disable software notification\n"); ctrl_warn(ctrl, "Cannot disable software notification\n");
} }
@ -934,7 +881,8 @@ static inline void dbg_ctrl(struct controller *ctrl)
pdev->subsystem_device); pdev->subsystem_device);
ctrl_info(ctrl, " Subsystem Vendor ID : 0x%04x\n", ctrl_info(ctrl, " Subsystem Vendor ID : 0x%04x\n",
pdev->subsystem_vendor); pdev->subsystem_vendor);
ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n", ctrl->cap_base); ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n",
pci_pcie_cap(pdev));
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
if (!pci_resource_len(pdev, i)) if (!pci_resource_len(pdev, i))
continue; continue;
@ -978,8 +926,7 @@ struct controller *pcie_init(struct pcie_device *dev)
goto abort; goto abort;
} }
ctrl->pcie = dev; ctrl->pcie = dev;
ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); if (!pci_pcie_cap(pdev)) {
if (!ctrl->cap_base) {
ctrl_err(ctrl, "Cannot find PCI Express capability\n"); ctrl_err(ctrl, "Cannot find PCI Express capability\n");
goto abort_ctrl; goto abort_ctrl;
} }

View file

@ -43,7 +43,7 @@ static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp)
* Perhaps we *should* use default settings for PCIe, but * Perhaps we *should* use default settings for PCIe, but
* pciehp didn't, so we won't either. * pciehp didn't, so we won't either.
*/ */
if (dev->is_pcie) if (pci_is_pcie(dev))
return; return;
dev_info(&dev->dev, "using default PCI settings\n"); dev_info(&dev->dev, "using default PCI settings\n");
hpp = &pci_default_type0; hpp = &pci_default_type0;
@ -102,7 +102,7 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
return; return;
/* Find PCI Express capability */ /* Find PCI Express capability */
pos = pci_find_capability(dev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(dev);
if (!pos) if (!pos)
return; return;

View file

@ -1611,7 +1611,7 @@ domain_context_mapping(struct dmar_domain *domain, struct pci_dev *pdev,
return ret; return ret;
parent = parent->bus->self; parent = parent->bus->self;
} }
if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */ if (pci_is_pcie(tmp)) /* this is a PCIE-to-PCI bridge */
return domain_context_mapping_one(domain, return domain_context_mapping_one(domain,
pci_domain_nr(tmp->subordinate), pci_domain_nr(tmp->subordinate),
tmp->subordinate->number, 0, tmp->subordinate->number, 0,
@ -1651,7 +1651,7 @@ static int domain_context_mapped(struct pci_dev *pdev)
return ret; return ret;
parent = parent->bus->self; parent = parent->bus->self;
} }
if (tmp->is_pcie) if (pci_is_pcie(tmp))
return device_context_mapped(iommu, tmp->subordinate->number, return device_context_mapped(iommu, tmp->subordinate->number,
0); 0);
else else
@ -1821,7 +1821,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
dev_tmp = pci_find_upstream_pcie_bridge(pdev); dev_tmp = pci_find_upstream_pcie_bridge(pdev);
if (dev_tmp) { if (dev_tmp) {
if (dev_tmp->is_pcie) { if (pci_is_pcie(dev_tmp)) {
bus = dev_tmp->subordinate->number; bus = dev_tmp->subordinate->number;
devfn = 0; devfn = 0;
} else { } else {
@ -2182,7 +2182,7 @@ static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
* the 1:1 domain, just in _case_ one of their siblings turns out * the 1:1 domain, just in _case_ one of their siblings turns out
* not to be able to map all of memory. * not to be able to map all of memory.
*/ */
if (!pdev->is_pcie) { if (!pci_is_pcie(pdev)) {
if (!pci_is_root_bus(pdev->bus)) if (!pci_is_root_bus(pdev->bus))
return 0; return 0;
if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) if (pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI)
@ -3319,7 +3319,7 @@ static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
parent->devfn); parent->devfn);
parent = parent->bus->self; parent = parent->bus->self;
} }
if (tmp->is_pcie) /* this is a PCIE-to-PCI bridge */ if (pci_is_pcie(tmp)) /* this is a PCIE-to-PCI bridge */
iommu_detach_dev(iommu, iommu_detach_dev(iommu,
tmp->subordinate->number, 0); tmp->subordinate->number, 0);
else /* this is a legacy PCI bridge */ else /* this is a legacy PCI bridge */

View file

@ -520,7 +520,7 @@ int set_msi_sid(struct irte *irte, struct pci_dev *dev)
return -1; return -1;
/* PCIe device or Root Complex integrated PCI device */ /* PCIe device or Root Complex integrated PCI device */
if (dev->is_pcie || !dev->bus->parent) { if (pci_is_pcie(dev) || !dev->bus->parent) {
set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16,
(dev->bus->number << 8) | dev->devfn); (dev->bus->number << 8) | dev->devfn);
return 0; return 0;
@ -528,7 +528,7 @@ int set_msi_sid(struct irte *irte, struct pci_dev *dev)
bridge = pci_find_upstream_pcie_bridge(dev); bridge = pci_find_upstream_pcie_bridge(dev);
if (bridge) { if (bridge) {
if (bridge->is_pcie) /* this is a PCIE-to-PCI/PCIX bridge */ if (pci_is_pcie(bridge))/* this is a PCIE-to-PCI/PCIX bridge */
set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16, set_irte_sid(irte, SVT_VERIFY_BUS, SQ_ALL_16,
(bridge->bus->number << 8) | dev->bus->number); (bridge->bus->number << 8) | dev->bus->number);
else /* this is a legacy PCI bridge */ else /* this is a legacy PCI bridge */

127
drivers/pci/ioapic.c Normal file
View file

@ -0,0 +1,127 @@
/*
* IOAPIC/IOxAPIC/IOSAPIC driver
*
* Copyright (C) 2009 Fujitsu Limited.
* (c) Copyright 2009 Hewlett-Packard Development Company, L.P.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* This driver manages PCI I/O APICs added by hotplug after boot. We try to
* claim all I/O APIC PCI devices, but those present at boot were registered
* when we parsed the ACPI MADT, so we'll fail when we try to re-register
* them.
*/
#include <linux/pci.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
struct ioapic {
acpi_handle handle;
u32 gsi_base;
};
static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent)
{
acpi_handle handle;
acpi_status status;
unsigned long long gsb;
struct ioapic *ioapic;
u64 addr;
int ret;
char *type;
handle = DEVICE_ACPI_HANDLE(&dev->dev);
if (!handle)
return -EINVAL;
status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
if (ACPI_FAILURE(status))
return -EINVAL;
/*
* The previous code in acpiphp evaluated _MAT if _GSB failed, but
* ACPI spec 4.0 sec 6.2.2 requires _GSB for hot-pluggable I/O APICs.
*/
ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
if (!ioapic)
return -ENOMEM;
ioapic->handle = handle;
ioapic->gsi_base = (u32) gsb;
if (dev->class == PCI_CLASS_SYSTEM_PIC_IOAPIC)
type = "IOAPIC";
else
type = "IOxAPIC";
ret = pci_enable_device(dev);
if (ret < 0)
goto exit_free;
pci_set_master(dev);
if (pci_request_region(dev, 0, type))
goto exit_disable;
addr = pci_resource_start(dev, 0);
if (acpi_register_ioapic(ioapic->handle, addr, ioapic->gsi_base))
goto exit_release;
pci_set_drvdata(dev, ioapic);
dev_info(&dev->dev, "%s at %#llx, GSI %u\n", type, addr,
ioapic->gsi_base);
return 0;
exit_release:
pci_release_region(dev, 0);
exit_disable:
pci_disable_device(dev);
exit_free:
kfree(ioapic);
return -ENODEV;
}
static void ioapic_remove(struct pci_dev *dev)
{
struct ioapic *ioapic = pci_get_drvdata(dev);
acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base);
pci_release_region(dev, 0);
pci_disable_device(dev);
kfree(ioapic);
}
static struct pci_device_id ioapic_devices[] = {
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_SYSTEM_PIC_IOAPIC << 8, 0xffff00, },
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_SYSTEM_PIC_IOXAPIC << 8, 0xffff00, },
{ }
};
static struct pci_driver ioapic_driver = {
.name = "ioapic",
.id_table = ioapic_devices,
.probe = ioapic_probe,
.remove = __devexit_p(ioapic_remove),
};
static int __init ioapic_init(void)
{
return pci_register_driver(&ioapic_driver);
}
static void __exit ioapic_exit(void)
{
pci_unregister_driver(&ioapic_driver);
}
module_init(ioapic_init);
module_exit(ioapic_exit);

View file

@ -555,7 +555,7 @@ int pci_iov_init(struct pci_dev *dev)
{ {
int pos; int pos;
if (!dev->is_pcie) if (!pci_is_pcie(dev))
return -ENODEV; return -ENODEV;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV);

View file

@ -116,7 +116,7 @@ static void acpi_pci_propagate_wakeup_enable(struct pci_bus *bus, bool enable)
int ret; int ret;
ret = acpi_pm_device_sleep_wake(&bridge->dev, enable); ret = acpi_pm_device_sleep_wake(&bridge->dev, enable);
if (!ret || bridge->is_pcie) if (!ret || pci_is_pcie(bridge))
return; return;
bus = bus->parent; bus = bus->parent;
} }
@ -131,7 +131,7 @@ static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable)
if (acpi_pci_can_wakeup(dev)) if (acpi_pci_can_wakeup(dev))
return acpi_pm_device_sleep_wake(&dev->dev, enable); return acpi_pm_device_sleep_wake(&dev->dev, enable);
if (!dev->is_pcie) if (!pci_is_pcie(dev))
acpi_pci_propagate_wakeup_enable(dev->bus, enable); acpi_pci_propagate_wakeup_enable(dev->bus, enable);
return 0; return 0;

View file

@ -74,7 +74,11 @@ static ssize_t local_cpus_show(struct device *dev,
const struct cpumask *mask; const struct cpumask *mask;
int len; int len;
#ifdef CONFIG_NUMA
mask = cpumask_of_node(dev_to_node(dev));
#else
mask = cpumask_of_pcibus(to_pci_dev(dev)->bus); mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
#endif
len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask); len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask);
buf[len++] = '\n'; buf[len++] = '\n';
buf[len] = '\0'; buf[len] = '\0';
@ -88,7 +92,11 @@ static ssize_t local_cpulist_show(struct device *dev,
const struct cpumask *mask; const struct cpumask *mask;
int len; int len;
#ifdef CONFIG_NUMA
mask = cpumask_of_node(dev_to_node(dev));
#else
mask = cpumask_of_pcibus(to_pci_dev(dev)->bus); mask = cpumask_of_pcibus(to_pci_dev(dev)->bus);
#endif
len = cpulist_scnprintf(buf, PAGE_SIZE-2, mask); len = cpulist_scnprintf(buf, PAGE_SIZE-2, mask);
buf[len++] = '\n'; buf[len++] = '\n';
buf[len] = '\0'; buf[len] = '\0';
@ -175,6 +183,21 @@ numa_node_show(struct device *dev, struct device_attribute *attr, char *buf)
} }
#endif #endif
static ssize_t
dma_mask_bits_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
return sprintf (buf, "%d\n", fls64(pdev->dma_mask));
}
static ssize_t
consistent_dma_mask_bits_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf (buf, "%d\n", fls64(dev->coherent_dma_mask));
}
static ssize_t static ssize_t
msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf) msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf)
{ {
@ -306,6 +329,8 @@ struct device_attribute pci_dev_attrs[] = {
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
__ATTR_RO(numa_node), __ATTR_RO(numa_node),
#endif #endif
__ATTR_RO(dma_mask_bits),
__ATTR_RO(consistent_dma_mask_bits),
__ATTR(enable, 0600, is_enabled_show, is_enabled_store), __ATTR(enable, 0600, is_enabled_show, is_enabled_store),
__ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
broken_parity_status_show,broken_parity_status_store), broken_parity_status_show,broken_parity_status_store),

View file

@ -47,6 +47,15 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE; unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE;
unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE; unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
/*
* 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
* the dfl or actual value as it sees fit. Don't forget this is
* measured in 32-bit words, not bytes.
*/
u8 pci_dfl_cache_line_size __devinitdata = L1_CACHE_BYTES >> 2;
u8 pci_cache_line_size;
/** /**
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
* @bus: pointer to PCI bus structure to search * @bus: pointer to PCI bus structure to search
@ -373,8 +382,12 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
continue; /* Wrong type */ continue; /* Wrong type */
if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
return r; /* Exact match */ return r; /* Exact match */
if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH)) /* We can't insert a non-prefetch resource inside a prefetchable parent .. */
best = r; /* Approximating prefetchable by non-prefetchable */ if (r->flags & IORESOURCE_PREFETCH)
continue;
/* .. but we can put a prefetchable resource inside a non-prefetchable one */
if (!best)
best = r;
} }
return best; return best;
} }
@ -728,8 +741,8 @@ static int pci_save_pcie_state(struct pci_dev *dev)
u16 *cap; u16 *cap;
u16 flags; u16 flags;
pos = pci_find_capability(dev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(dev);
if (pos <= 0) if (!pos)
return 0; return 0;
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
@ -1202,7 +1215,7 @@ void pci_pme_active(struct pci_dev *dev, bool enable)
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr); pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
dev_printk(KERN_INFO, &dev->dev, "PME# %s\n", dev_printk(KERN_DEBUG, &dev->dev, "PME# %s\n",
enable ? "enabled" : "disabled"); enable ? "enabled" : "disabled");
} }
@ -1413,7 +1426,8 @@ void pci_pm_init(struct pci_dev *dev)
pmc &= PCI_PM_CAP_PME_MASK; pmc &= PCI_PM_CAP_PME_MASK;
if (pmc) { if (pmc) {
dev_info(&dev->dev, "PME# supported from%s%s%s%s%s\n", dev_printk(KERN_DEBUG, &dev->dev,
"PME# supported from%s%s%s%s%s\n",
(pmc & PCI_PM_CAP_PME_D0) ? " D0" : "", (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
(pmc & PCI_PM_CAP_PME_D1) ? " D1" : "", (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
(pmc & PCI_PM_CAP_PME_D2) ? " D2" : "", (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
@ -1510,7 +1524,7 @@ void pci_enable_ari(struct pci_dev *dev)
u16 ctrl; u16 ctrl;
struct pci_dev *bridge; struct pci_dev *bridge;
if (!dev->is_pcie || dev->devfn) if (!pci_is_pcie(dev) || dev->devfn)
return; return;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
@ -1518,10 +1532,10 @@ void pci_enable_ari(struct pci_dev *dev)
return; return;
bridge = dev->bus->self; bridge = dev->bus->self;
if (!bridge || !bridge->is_pcie) if (!bridge || !pci_is_pcie(bridge))
return; return;
pos = pci_find_capability(bridge, PCI_CAP_ID_EXP); pos = pci_pcie_cap(bridge);
if (!pos) if (!pos)
return; return;
@ -1536,6 +1550,54 @@ void pci_enable_ari(struct pci_dev *dev)
bridge->ari_enabled = 1; bridge->ari_enabled = 1;
} }
static int pci_acs_enable;
/**
* pci_request_acs - ask for ACS to be enabled if supported
*/
void pci_request_acs(void)
{
pci_acs_enable = 1;
}
/**
* pci_enable_acs - enable ACS if hardware support it
* @dev: the PCI device
*/
void pci_enable_acs(struct pci_dev *dev)
{
int pos;
u16 cap;
u16 ctrl;
if (!pci_acs_enable)
return;
if (!pci_is_pcie(dev))
return;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ACS);
if (!pos)
return;
pci_read_config_word(dev, pos + PCI_ACS_CAP, &cap);
pci_read_config_word(dev, pos + PCI_ACS_CTRL, &ctrl);
/* Source Validation */
ctrl |= (cap & PCI_ACS_SV);
/* P2P Request Redirect */
ctrl |= (cap & PCI_ACS_RR);
/* P2P Completion Redirect */
ctrl |= (cap & PCI_ACS_CR);
/* Upstream Forwarding */
ctrl |= (cap & PCI_ACS_UF);
pci_write_config_word(dev, pos + PCI_ACS_CTRL, ctrl);
}
/** /**
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
* @dev: the PCI device * @dev: the PCI device
@ -1669,9 +1731,7 @@ static int __pci_request_region(struct pci_dev *pdev, int bar, const char *res_n
return 0; return 0;
err_out: err_out:
dev_warn(&pdev->dev, "BAR %d: can't reserve %s region %pR\n", dev_warn(&pdev->dev, "BAR %d: can't reserve %pR\n", bar,
bar,
pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
&pdev->resource[bar]); &pdev->resource[bar]);
return -EBUSY; return -EBUSY;
} }
@ -1866,31 +1926,6 @@ void pci_clear_master(struct pci_dev *dev)
__pci_set_master(dev, false); __pci_set_master(dev, false);
} }
#ifdef PCI_DISABLE_MWI
int pci_set_mwi(struct pci_dev *dev)
{
return 0;
}
int pci_try_set_mwi(struct pci_dev *dev)
{
return 0;
}
void pci_clear_mwi(struct pci_dev *dev)
{
}
#else
#ifndef PCI_CACHE_LINE_BYTES
#define PCI_CACHE_LINE_BYTES L1_CACHE_BYTES
#endif
/* This can be overridden by arch code. */
/* Don't forget this is measured in 32-bit words, not bytes */
u8 pci_cache_line_size = PCI_CACHE_LINE_BYTES / 4;
/** /**
* pci_set_cacheline_size - ensure the CACHE_LINE_SIZE register is programmed * pci_set_cacheline_size - ensure the CACHE_LINE_SIZE register is programmed
* @dev: the PCI device for which MWI is to be enabled * @dev: the PCI device for which MWI is to be enabled
@ -1901,13 +1936,12 @@ u8 pci_cache_line_size = PCI_CACHE_LINE_BYTES / 4;
* *
* RETURNS: An appropriate -ERRNO error value on error, or zero for success. * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
*/ */
static int int pci_set_cacheline_size(struct pci_dev *dev)
pci_set_cacheline_size(struct pci_dev *dev)
{ {
u8 cacheline_size; u8 cacheline_size;
if (!pci_cache_line_size) if (!pci_cache_line_size)
return -EINVAL; /* The system doesn't support MWI. */ return -EINVAL;
/* Validate current setting: the PCI_CACHE_LINE_SIZE must be /* Validate current setting: the PCI_CACHE_LINE_SIZE must be
equal to or multiple of the right value. */ equal to or multiple of the right value. */
@ -1928,6 +1962,24 @@ pci_set_cacheline_size(struct pci_dev *dev)
return -EINVAL; return -EINVAL;
} }
EXPORT_SYMBOL_GPL(pci_set_cacheline_size);
#ifdef PCI_DISABLE_MWI
int pci_set_mwi(struct pci_dev *dev)
{
return 0;
}
int pci_try_set_mwi(struct pci_dev *dev)
{
return 0;
}
void pci_clear_mwi(struct pci_dev *dev)
{
}
#else
/** /**
* pci_set_mwi - enables memory-write-invalidate PCI transaction * pci_set_mwi - enables memory-write-invalidate PCI transaction
@ -2062,6 +2114,7 @@ pci_set_dma_mask(struct pci_dev *dev, u64 mask)
return -EIO; return -EIO;
dev->dma_mask = mask; dev->dma_mask = mask;
dev_dbg(&dev->dev, "using %dbit DMA mask\n", fls64(mask));
return 0; return 0;
} }
@ -2073,6 +2126,7 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
return -EIO; return -EIO;
dev->dev.coherent_dma_mask = mask; dev->dev.coherent_dma_mask = mask;
dev_dbg(&dev->dev, "using %dbit consistent DMA mask\n", fls64(mask));
return 0; return 0;
} }
@ -2099,9 +2153,9 @@ static int pcie_flr(struct pci_dev *dev, int probe)
int i; int i;
int pos; int pos;
u32 cap; u32 cap;
u16 status; u16 status, control;
pos = pci_find_capability(dev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(dev);
if (!pos) if (!pos)
return -ENOTTY; return -ENOTTY;
@ -2126,8 +2180,10 @@ static int pcie_flr(struct pci_dev *dev, int probe)
"proceeding with reset anyway\n"); "proceeding with reset anyway\n");
clear: clear:
pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &control);
PCI_EXP_DEVCTL_BCR_FLR); control |= PCI_EXP_DEVCTL_BCR_FLR;
pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, control);
msleep(100); msleep(100);
return 0; return 0;
@ -2450,7 +2506,7 @@ int pcie_get_readrq(struct pci_dev *dev)
int ret, cap; int ret, cap;
u16 ctl; u16 ctl;
cap = pci_find_capability(dev, PCI_CAP_ID_EXP); cap = pci_pcie_cap(dev);
if (!cap) if (!cap)
return -EINVAL; return -EINVAL;
@ -2480,7 +2536,7 @@ int pcie_set_readrq(struct pci_dev *dev, int rq)
v = (ffs(rq) - 8) << 12; v = (ffs(rq) - 8) << 12;
cap = pci_find_capability(dev, PCI_CAP_ID_EXP); cap = pci_pcie_cap(dev);
if (!cap) if (!cap)
goto out; goto out;
@ -2540,7 +2596,7 @@ int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
return reg; return reg;
} }
dev_err(&dev->dev, "BAR: invalid resource #%d\n", resno); dev_err(&dev->dev, "BAR %d: invalid resource\n", resno);
return 0; return 0;
} }
@ -2590,7 +2646,7 @@ int pci_set_vga_state(struct pci_dev *dev, bool decode,
#define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE #define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE
static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0}; static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0};
spinlock_t resource_alignment_lock = SPIN_LOCK_UNLOCKED; static DEFINE_SPINLOCK(resource_alignment_lock);
/** /**
* pci_specified_resource_alignment - get resource alignment specified by user. * pci_specified_resource_alignment - get resource alignment specified by user.

View file

@ -311,4 +311,6 @@ static inline int pci_resource_alignment(struct pci_dev *dev,
return resource_alignment(res); return resource_alignment(res);
} }
extern void pci_enable_acs(struct pci_dev *dev);
#endif /* DRIVERS_PCI_H */ #endif /* DRIVERS_PCI_H */

View file

@ -23,6 +23,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/stddef.h>
#include "aerdrv.h" #include "aerdrv.h"
struct aer_error_inj { struct aer_error_inj {
@ -35,10 +36,12 @@ struct aer_error_inj {
u32 header_log1; u32 header_log1;
u32 header_log2; u32 header_log2;
u32 header_log3; u32 header_log3;
u16 domain;
}; };
struct aer_error { struct aer_error {
struct list_head list; struct list_head list;
u16 domain;
unsigned int bus; unsigned int bus;
unsigned int devfn; unsigned int devfn;
int pos_cap_err; int pos_cap_err;
@ -66,22 +69,27 @@ static LIST_HEAD(pci_bus_ops_list);
/* Protect einjected and pci_bus_ops_list */ /* Protect einjected and pci_bus_ops_list */
static DEFINE_SPINLOCK(inject_lock); static DEFINE_SPINLOCK(inject_lock);
static void aer_error_init(struct aer_error *err, unsigned int bus, static void aer_error_init(struct aer_error *err, u16 domain,
unsigned int devfn, int pos_cap_err) unsigned int bus, unsigned int devfn,
int pos_cap_err)
{ {
INIT_LIST_HEAD(&err->list); INIT_LIST_HEAD(&err->list);
err->domain = domain;
err->bus = bus; err->bus = bus;
err->devfn = devfn; err->devfn = devfn;
err->pos_cap_err = pos_cap_err; err->pos_cap_err = pos_cap_err;
} }
/* inject_lock must be held before calling */ /* inject_lock must be held before calling */
static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn) static struct aer_error *__find_aer_error(u16 domain, unsigned int bus,
unsigned int devfn)
{ {
struct aer_error *err; struct aer_error *err;
list_for_each_entry(err, &einjected, list) { list_for_each_entry(err, &einjected, list) {
if (bus == err->bus && devfn == err->devfn) if (domain == err->domain &&
bus == err->bus &&
devfn == err->devfn)
return err; return err;
} }
return NULL; return NULL;
@ -90,7 +98,10 @@ static struct aer_error *__find_aer_error(unsigned int bus, unsigned int devfn)
/* inject_lock must be held before calling */ /* inject_lock must be held before calling */
static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev) static struct aer_error *__find_aer_error_by_dev(struct pci_dev *dev)
{ {
return __find_aer_error(dev->bus->number, dev->devfn); int domain = pci_domain_nr(dev->bus);
if (domain < 0)
return NULL;
return __find_aer_error((u16)domain, dev->bus->number, dev->devfn);
} }
/* inject_lock must be held before calling */ /* inject_lock must be held before calling */
@ -172,11 +183,15 @@ static int pci_read_aer(struct pci_bus *bus, unsigned int devfn, int where,
struct aer_error *err; struct aer_error *err;
unsigned long flags; unsigned long flags;
struct pci_ops *ops; struct pci_ops *ops;
int domain;
spin_lock_irqsave(&inject_lock, flags); spin_lock_irqsave(&inject_lock, flags);
if (size != sizeof(u32)) if (size != sizeof(u32))
goto out; goto out;
err = __find_aer_error(bus->number, devfn); domain = pci_domain_nr(bus);
if (domain < 0)
goto out;
err = __find_aer_error((u16)domain, bus->number, devfn);
if (!err) if (!err)
goto out; goto out;
@ -200,11 +215,15 @@ int pci_write_aer(struct pci_bus *bus, unsigned int devfn, int where, int size,
unsigned long flags; unsigned long flags;
int rw1cs; int rw1cs;
struct pci_ops *ops; struct pci_ops *ops;
int domain;
spin_lock_irqsave(&inject_lock, flags); spin_lock_irqsave(&inject_lock, flags);
if (size != sizeof(u32)) if (size != sizeof(u32))
goto out; goto out;
err = __find_aer_error(bus->number, devfn); domain = pci_domain_nr(bus);
if (domain < 0)
goto out;
err = __find_aer_error((u16)domain, bus->number, devfn);
if (!err) if (!err)
goto out; goto out;
@ -262,7 +281,7 @@ out:
static struct pci_dev *pcie_find_root_port(struct pci_dev *dev) static struct pci_dev *pcie_find_root_port(struct pci_dev *dev)
{ {
while (1) { while (1) {
if (!dev->is_pcie) if (!pci_is_pcie(dev))
break; break;
if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
return dev; return dev;
@ -305,25 +324,25 @@ static int aer_inject(struct aer_error_inj *einj)
u32 sever; u32 sever;
int ret = 0; int ret = 0;
dev = pci_get_bus_and_slot(einj->bus, devfn); dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn);
if (!dev) if (!dev)
return -EINVAL; return -ENODEV;
rpdev = pcie_find_root_port(dev); rpdev = pcie_find_root_port(dev);
if (!rpdev) { if (!rpdev) {
ret = -EINVAL; ret = -ENOTTY;
goto out_put; goto out_put;
} }
pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); pos_cap_err = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos_cap_err) { if (!pos_cap_err) {
ret = -EIO; ret = -ENOTTY;
goto out_put; goto out_put;
} }
pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever); pci_read_config_dword(dev, pos_cap_err + PCI_ERR_UNCOR_SEVER, &sever);
rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR); rp_pos_cap_err = pci_find_ext_capability(rpdev, PCI_EXT_CAP_ID_ERR);
if (!rp_pos_cap_err) { if (!rp_pos_cap_err) {
ret = -EIO; ret = -ENOTTY;
goto out_put; goto out_put;
} }
@ -344,7 +363,8 @@ static int aer_inject(struct aer_error_inj *einj)
if (!err) { if (!err) {
err = err_alloc; err = err_alloc;
err_alloc = NULL; err_alloc = NULL;
aer_error_init(err, einj->bus, devfn, pos_cap_err); aer_error_init(err, einj->domain, einj->bus, devfn,
pos_cap_err);
list_add(&err->list, &einjected); list_add(&err->list, &einjected);
} }
err->uncor_status |= einj->uncor_status; err->uncor_status |= einj->uncor_status;
@ -358,7 +378,8 @@ static int aer_inject(struct aer_error_inj *einj)
if (!rperr) { if (!rperr) {
rperr = rperr_alloc; rperr = rperr_alloc;
rperr_alloc = NULL; rperr_alloc = NULL;
aer_error_init(rperr, rpdev->bus->number, rpdev->devfn, aer_error_init(rperr, pci_domain_nr(rpdev->bus),
rpdev->bus->number, rpdev->devfn,
rp_pos_cap_err); rp_pos_cap_err);
list_add(&rperr->list, &einjected); list_add(&rperr->list, &einjected);
} }
@ -411,10 +432,11 @@ static ssize_t aer_inject_write(struct file *filp, const char __user *ubuf,
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (usize < offsetof(struct aer_error_inj, domain) ||
if (usize != sizeof(struct aer_error_inj)) usize > sizeof(einj))
return -EINVAL; return -EINVAL;
memset(&einj, 0, sizeof(einj));
if (copy_from_user(&einj, ubuf, usize)) if (copy_from_user(&einj, ubuf, usize))
return -EFAULT; return -EFAULT;
@ -452,7 +474,7 @@ static void __exit aer_inject_exit(void)
} }
spin_lock_irqsave(&inject_lock, flags); spin_lock_irqsave(&inject_lock, flags);
list_for_each_entry_safe(err, err_next, &pci_bus_ops_list, list) { list_for_each_entry_safe(err, err_next, &einjected, list) {
list_del(&err->list); list_del(&err->list);
kfree(err); kfree(err);
} }

View file

@ -53,7 +53,7 @@ static struct pci_error_handlers aer_error_handlers = {
static struct pcie_port_service_driver aerdriver = { static struct pcie_port_service_driver aerdriver = {
.name = "aer", .name = "aer",
.port_type = PCIE_RC_PORT, .port_type = PCI_EXP_TYPE_ROOT_PORT,
.service = PCIE_PORT_SERVICE_AER, .service = PCIE_PORT_SERVICE_AER,
.probe = aer_probe, .probe = aer_probe,
@ -295,7 +295,7 @@ static void aer_error_resume(struct pci_dev *dev)
u16 reg16; u16 reg16;
/* Clean up Root device status */ /* Clean up Root device status */
pos = pci_find_capability(dev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(dev);
pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16); pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16);
pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16); pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);

View file

@ -35,11 +35,14 @@ int pci_enable_pcie_error_reporting(struct pci_dev *dev)
u16 reg16 = 0; u16 reg16 = 0;
int pos; int pos;
if (dev->aer_firmware_first)
return -EIO;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos) if (!pos)
return -EIO; return -EIO;
pos = pci_find_capability(dev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(dev);
if (!pos) if (!pos)
return -EIO; return -EIO;
@ -60,7 +63,10 @@ int pci_disable_pcie_error_reporting(struct pci_dev *dev)
u16 reg16 = 0; u16 reg16 = 0;
int pos; int pos;
pos = pci_find_capability(dev, PCI_CAP_ID_EXP); if (dev->aer_firmware_first)
return -EIO;
pos = pci_pcie_cap(dev);
if (!pos) if (!pos)
return -EIO; return -EIO;
@ -76,28 +82,6 @@ int pci_disable_pcie_error_reporting(struct pci_dev *dev)
EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting); EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
{
int pos;
u32 status, mask;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
if (!pos)
return -EIO;
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
if (dev->error_state == pci_channel_io_normal)
status &= ~mask; /* Clear corresponding nonfatal bits */
else
status &= mask; /* Clear corresponding fatal bits */
pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
return 0;
}
EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
#if 0
int pci_cleanup_aer_correct_error_status(struct pci_dev *dev)
{ {
int pos; int pos;
u32 status; u32 status;
@ -106,20 +90,21 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev)
if (!pos) if (!pos)
return -EIO; return -EIO;
pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status); pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, status); if (status)
pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
return 0; return 0;
} }
#endif /* 0 */ EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
static int set_device_error_reporting(struct pci_dev *dev, void *data) static int set_device_error_reporting(struct pci_dev *dev, void *data)
{ {
bool enable = *((bool *)data); bool enable = *((bool *)data);
if (dev->pcie_type == PCIE_RC_PORT || if ((dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) ||
dev->pcie_type == PCIE_SW_UPSTREAM_PORT || (dev->pcie_type == PCI_EXP_TYPE_UPSTREAM) ||
dev->pcie_type == PCIE_SW_DOWNSTREAM_PORT) { (dev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)) {
if (enable) if (enable)
pci_enable_pcie_error_reporting(dev); pci_enable_pcie_error_reporting(dev);
else else
@ -218,7 +203,7 @@ static int find_device_iter(struct pci_dev *dev, void *data)
*/ */
if (atomic_read(&dev->enable_cnt) == 0) if (atomic_read(&dev->enable_cnt) == 0)
return 0; return 0;
pos = pci_find_capability(dev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(dev);
if (!pos) if (!pos)
return 0; return 0;
/* Check if AER is enabled */ /* Check if AER is enabled */
@ -431,10 +416,9 @@ static int find_aer_service_iter(struct device *device, void *data)
result = (struct find_aer_service_data *) data; result = (struct find_aer_service_data *) data;
if (device->bus == &pcie_port_bus_type) { if (device->bus == &pcie_port_bus_type) {
struct pcie_port_data *port_data; struct pcie_device *pcie = to_pcie_device(device);
port_data = pci_get_drvdata(to_pcie_device(device)->port); if (pcie->port->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
if (port_data->port_type == PCIE_SW_DOWNSTREAM_PORT)
result->is_downstream = 1; result->is_downstream = 1;
driver = device->driver; driver = device->driver;
@ -612,7 +596,7 @@ void aer_enable_rootport(struct aer_rpc *rpc)
u16 reg16; u16 reg16;
u32 reg32; u32 reg32;
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(pdev);
/* Clear PCIE Capability's Device Status */ /* Clear PCIE Capability's Device Status */
pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16); pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16);
pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16); pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16);
@ -874,8 +858,22 @@ void aer_delete_rootport(struct aer_rpc *rpc)
*/ */
int aer_init(struct pcie_device *dev) int aer_init(struct pcie_device *dev)
{ {
if (aer_osc_setup(dev) && !forceload) if (dev->port->aer_firmware_first) {
return -ENXIO; dev_printk(KERN_DEBUG, &dev->device,
"PCIe errors handled by platform firmware.\n");
goto out;
}
if (aer_osc_setup(dev))
goto out;
return 0; return 0;
out:
if (forceload) {
dev_printk(KERN_DEBUG, &dev->device,
"aerdrv forceload requested.\n");
dev->port->aer_firmware_first = 0;
return 0;
}
return -ENXIO;
} }

View file

@ -51,7 +51,7 @@ static int enable_ecrc_checking(struct pci_dev *dev)
int pos; int pos;
u32 reg32; u32 reg32;
if (!dev->is_pcie) if (!pci_is_pcie(dev))
return -ENODEV; return -ENODEV;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
@ -79,7 +79,7 @@ static int disable_ecrc_checking(struct pci_dev *dev)
int pos; int pos;
u32 reg32; u32 reg32;
if (!dev->is_pcie) if (!pci_is_pcie(dev))
return -ENODEV; return -ENODEV;
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR); pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);

View file

@ -122,7 +122,7 @@ static void pcie_set_clkpm_nocheck(struct pcie_link_state *link, int enable)
struct pci_bus *linkbus = link->pdev->subordinate; struct pci_bus *linkbus = link->pdev->subordinate;
list_for_each_entry(child, &linkbus->devices, bus_list) { list_for_each_entry(child, &linkbus->devices, bus_list) {
pos = pci_find_capability(child, PCI_CAP_ID_EXP); pos = pci_pcie_cap(child);
if (!pos) if (!pos)
return; return;
pci_read_config_word(child, pos + PCI_EXP_LNKCTL, &reg16); pci_read_config_word(child, pos + PCI_EXP_LNKCTL, &reg16);
@ -156,7 +156,7 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
/* All functions should have the same cap and state, take the worst */ /* All functions should have the same cap and state, take the worst */
list_for_each_entry(child, &linkbus->devices, bus_list) { list_for_each_entry(child, &linkbus->devices, bus_list) {
pos = pci_find_capability(child, PCI_CAP_ID_EXP); pos = pci_pcie_cap(child);
if (!pos) if (!pos)
return; return;
pci_read_config_dword(child, pos + PCI_EXP_LNKCAP, &reg32); pci_read_config_dword(child, pos + PCI_EXP_LNKCAP, &reg32);
@ -191,23 +191,23 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
* Configuration, so just check one function * Configuration, so just check one function
*/ */
child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); child = list_entry(linkbus->devices.next, struct pci_dev, bus_list);
BUG_ON(!child->is_pcie); BUG_ON(!pci_is_pcie(child));
/* Check downstream component if bit Slot Clock Configuration is 1 */ /* Check downstream component if bit Slot Clock Configuration is 1 */
cpos = pci_find_capability(child, PCI_CAP_ID_EXP); cpos = pci_pcie_cap(child);
pci_read_config_word(child, cpos + PCI_EXP_LNKSTA, &reg16); pci_read_config_word(child, cpos + PCI_EXP_LNKSTA, &reg16);
if (!(reg16 & PCI_EXP_LNKSTA_SLC)) if (!(reg16 & PCI_EXP_LNKSTA_SLC))
same_clock = 0; same_clock = 0;
/* Check upstream component if bit Slot Clock Configuration is 1 */ /* Check upstream component if bit Slot Clock Configuration is 1 */
ppos = pci_find_capability(parent, PCI_CAP_ID_EXP); ppos = pci_pcie_cap(parent);
pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, &reg16); pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, &reg16);
if (!(reg16 & PCI_EXP_LNKSTA_SLC)) if (!(reg16 & PCI_EXP_LNKSTA_SLC))
same_clock = 0; same_clock = 0;
/* Configure downstream component, all functions */ /* Configure downstream component, all functions */
list_for_each_entry(child, &linkbus->devices, bus_list) { list_for_each_entry(child, &linkbus->devices, bus_list) {
cpos = pci_find_capability(child, PCI_CAP_ID_EXP); cpos = pci_pcie_cap(child);
pci_read_config_word(child, cpos + PCI_EXP_LNKCTL, &reg16); pci_read_config_word(child, cpos + PCI_EXP_LNKCTL, &reg16);
child_reg[PCI_FUNC(child->devfn)] = reg16; child_reg[PCI_FUNC(child->devfn)] = reg16;
if (same_clock) if (same_clock)
@ -247,7 +247,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
dev_printk(KERN_ERR, &parent->dev, dev_printk(KERN_ERR, &parent->dev,
"ASPM: Could not configure common clock\n"); "ASPM: Could not configure common clock\n");
list_for_each_entry(child, &linkbus->devices, bus_list) { list_for_each_entry(child, &linkbus->devices, bus_list) {
cpos = pci_find_capability(child, PCI_CAP_ID_EXP); cpos = pci_pcie_cap(child);
pci_write_config_word(child, cpos + PCI_EXP_LNKCTL, pci_write_config_word(child, cpos + PCI_EXP_LNKCTL,
child_reg[PCI_FUNC(child->devfn)]); child_reg[PCI_FUNC(child->devfn)]);
} }
@ -300,7 +300,7 @@ static void pcie_get_aspm_reg(struct pci_dev *pdev,
u16 reg16; u16 reg16;
u32 reg32; u32 reg32;
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(pdev);
pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, &reg32); pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, &reg32);
info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; info->support = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10;
info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; info->latency_encoding_l0s = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12;
@ -420,7 +420,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
child->pcie_type != PCI_EXP_TYPE_LEG_END) child->pcie_type != PCI_EXP_TYPE_LEG_END)
continue; continue;
pos = pci_find_capability(child, PCI_CAP_ID_EXP); pos = pci_pcie_cap(child);
pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, &reg32); pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, &reg32);
/* Calculate endpoint L0s acceptable latency */ /* Calculate endpoint L0s acceptable latency */
encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; encoding = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6;
@ -436,7 +436,7 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val) static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val)
{ {
u16 reg16; u16 reg16;
int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); int pos = pci_pcie_cap(pdev);
pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16); pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, &reg16);
reg16 &= ~0x3; reg16 &= ~0x3;
@ -503,7 +503,7 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev)
* very strange. Disable ASPM for the whole slot * very strange. Disable ASPM for the whole slot
*/ */
list_for_each_entry(child, &pdev->subordinate->devices, bus_list) { list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {
pos = pci_find_capability(child, PCI_CAP_ID_EXP); pos = pci_pcie_cap(child);
if (!pos) if (!pos)
return -EINVAL; return -EINVAL;
/* /*
@ -563,7 +563,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
struct pcie_link_state *link; struct pcie_link_state *link;
int blacklist = !!pcie_aspm_sanity_check(pdev); int blacklist = !!pcie_aspm_sanity_check(pdev);
if (aspm_disabled || !pdev->is_pcie || pdev->link_state) if (aspm_disabled || !pci_is_pcie(pdev) || pdev->link_state)
return; return;
if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)
@ -629,7 +629,8 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev)
struct pci_dev *parent = pdev->bus->self; struct pci_dev *parent = pdev->bus->self;
struct pcie_link_state *link, *root, *parent_link; struct pcie_link_state *link, *root, *parent_link;
if (aspm_disabled || !pdev->is_pcie || !parent || !parent->link_state) if (aspm_disabled || !pci_is_pcie(pdev) ||
!parent || !parent->link_state)
return; return;
if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
(parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
@ -670,7 +671,7 @@ void pcie_aspm_pm_state_change(struct pci_dev *pdev)
{ {
struct pcie_link_state *link = pdev->link_state; struct pcie_link_state *link = pdev->link_state;
if (aspm_disabled || !pdev->is_pcie || !link) if (aspm_disabled || !pci_is_pcie(pdev) || !link)
return; return;
if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && if ((pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
(pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) (pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM))
@ -696,7 +697,7 @@ void pci_disable_link_state(struct pci_dev *pdev, int state)
struct pci_dev *parent = pdev->bus->self; struct pci_dev *parent = pdev->bus->self;
struct pcie_link_state *link; struct pcie_link_state *link;
if (aspm_disabled || !pdev->is_pcie) if (aspm_disabled || !pci_is_pcie(pdev))
return; return;
if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
@ -841,7 +842,8 @@ void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev)
{ {
struct pcie_link_state *link_state = pdev->link_state; struct pcie_link_state *link_state = pdev->link_state;
if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && if (!pci_is_pcie(pdev) ||
(pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state)
return; return;
@ -857,7 +859,8 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev)
{ {
struct pcie_link_state *link_state = pdev->link_state; struct pcie_link_state *link_state = pdev->link_state;
if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && if (!pci_is_pcie(pdev) ||
(pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT &&
pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state) pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) || !link_state)
return; return;

View file

@ -11,31 +11,16 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#if !defined(PCI_CAP_ID_PME)
#define PCI_CAP_ID_PME 1
#endif
#if !defined(PCI_CAP_ID_EXP)
#define PCI_CAP_ID_EXP 0x10
#endif
#define PORT_TYPE_MASK 0xf
#define PORT_TO_SLOT_MASK 0x100
#define SLOT_HP_CAPABLE_MASK 0x40
#define PCIE_CAPABILITIES_REG 0x2
#define PCIE_SLOT_CAPABILITIES_REG 0x14
#define PCIE_PORT_DEVICE_MAXSERVICES 4 #define PCIE_PORT_DEVICE_MAXSERVICES 4
#define PCIE_PORT_MSI_VECTOR_MASK 0x1f
/* /*
* According to the PCI Express Base Specification 2.0, the indices of the MSI-X * According to the PCI Express Base Specification 2.0, the indices of
* table entires used by port services must not exceed 31 * the MSI-X table entires used by port services must not exceed 31
*/ */
#define PCIE_PORT_MAX_MSIX_ENTRIES 32 #define PCIE_PORT_MAX_MSIX_ENTRIES 32
#define get_descriptor_id(type, service) (((type - 4) << 4) | service) #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
extern struct bus_type pcie_port_bus_type; extern struct bus_type pcie_port_bus_type;
extern int pcie_port_device_probe(struct pci_dev *dev);
extern int pcie_port_device_register(struct pci_dev *dev); extern int pcie_port_device_register(struct pci_dev *dev);
#ifdef CONFIG_PM #ifdef CONFIG_PM
extern int pcie_port_device_suspend(struct device *dev); extern int pcie_port_device_suspend(struct device *dev);

View file

@ -26,7 +26,6 @@ EXPORT_SYMBOL_GPL(pcie_port_bus_type);
static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
{ {
struct pcie_device *pciedev; struct pcie_device *pciedev;
struct pcie_port_data *port_data;
struct pcie_port_service_driver *driver; struct pcie_port_service_driver *driver;
if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type) if (drv->bus != &pcie_port_bus_type || dev->bus != &pcie_port_bus_type)
@ -38,10 +37,8 @@ static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
if (driver->service != pciedev->service) if (driver->service != pciedev->service)
return 0; return 0;
port_data = pci_get_drvdata(pciedev->port); if ((driver->port_type != PCIE_ANY_PORT) &&
(driver->port_type != pciedev->port->pcie_type))
if (driver->port_type != PCIE_ANY_PORT
&& driver->port_type != port_data->port_type)
return 0; return 0;
return 1; return 1;

View file

@ -108,9 +108,9 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
* the value in this field indicates which MSI-X Table entry is * the value in this field indicates which MSI-X Table entry is
* used to generate the interrupt message." * used to generate the interrupt message."
*/ */
pos = pci_find_capability(dev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(dev);
pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg16); pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
entry = (reg16 >> 9) & PCIE_PORT_MSI_VECTOR_MASK; entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9;
if (entry >= nr_entries) if (entry >= nr_entries)
goto Error; goto Error;
@ -177,37 +177,40 @@ static int pcie_port_enable_msix(struct pci_dev *dev, int *vectors, int mask)
} }
/** /**
* assign_interrupt_mode - choose interrupt mode for PCI Express port services * init_service_irqs - initialize irqs for PCI Express port services
* (INTx, MSI-X, MSI) and set up vectors
* @dev: PCI Express port to handle * @dev: PCI Express port to handle
* @vectors: Array of interrupt vectors to populate * @irqs: Array of irqs to populate
* @mask: Bitmask of port capabilities returned by get_port_device_capability() * @mask: Bitmask of port capabilities returned by get_port_device_capability()
* *
* Return value: Interrupt mode associated with the port * Return value: Interrupt mode associated with the port
*/ */
static int assign_interrupt_mode(struct pci_dev *dev, int *vectors, int mask) static int init_service_irqs(struct pci_dev *dev, int *irqs, int mask)
{ {
int irq, interrupt_mode = PCIE_PORT_NO_IRQ; int i, irq;
int i;
/* Try to use MSI-X if supported */ /* Try to use MSI-X if supported */
if (!pcie_port_enable_msix(dev, vectors, mask)) if (!pcie_port_enable_msix(dev, irqs, mask))
return PCIE_PORT_MSIX_MODE; return 0;
/* We're not going to use MSI-X, so try MSI and fall back to INTx */ /* We're not going to use MSI-X, so try MSI and fall back to INTx */
if (!pci_enable_msi(dev)) irq = -1;
interrupt_mode = PCIE_PORT_MSI_MODE; if (!pci_enable_msi(dev) || dev->pin)
irq = dev->irq;
if (interrupt_mode == PCIE_PORT_NO_IRQ && dev->pin)
interrupt_mode = PCIE_PORT_INTx_MODE;
irq = interrupt_mode != PCIE_PORT_NO_IRQ ? dev->irq : -1;
for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++)
vectors[i] = irq; irqs[i] = irq;
irqs[PCIE_PORT_SERVICE_VC_SHIFT] = -1;
vectors[PCIE_PORT_SERVICE_VC_SHIFT] = -1; if (irq < 0)
return -ENODEV;
return 0;
}
return interrupt_mode; static void cleanup_service_irqs(struct pci_dev *dev)
{
if (dev->msix_enabled)
pci_disable_msix(dev);
else if (dev->msi_enabled)
pci_disable_msi(dev);
} }
/** /**
@ -226,13 +229,12 @@ static int get_port_device_capability(struct pci_dev *dev)
u16 reg16; u16 reg16;
u32 reg32; u32 reg32;
pos = pci_find_capability(dev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(dev);
pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg16); pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
/* Hot-Plug Capable */ /* Hot-Plug Capable */
if (reg16 & PORT_TO_SLOT_MASK) { if (reg16 & PCI_EXP_FLAGS_SLOT) {
pci_read_config_dword(dev, pci_read_config_dword(dev, pos + PCI_EXP_SLTCAP, &reg32);
pos + PCIE_SLOT_CAPABILITIES_REG, &reg32); if (reg32 & PCI_EXP_SLTCAP_HPC)
if (reg32 & SLOT_HP_CAPABLE_MASK)
services |= PCIE_PORT_SERVICE_HP; services |= PCIE_PORT_SERVICE_HP;
} }
/* AER capable */ /* AER capable */
@ -241,80 +243,47 @@ static int get_port_device_capability(struct pci_dev *dev)
/* VC support */ /* VC support */
if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC)) if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_VC))
services |= PCIE_PORT_SERVICE_VC; services |= PCIE_PORT_SERVICE_VC;
/* Root ports are capable of generating PME too */
if (dev->pcie_type == PCI_EXP_TYPE_ROOT_PORT)
services |= PCIE_PORT_SERVICE_PME;
return services; return services;
} }
/** /**
* pcie_device_init - initialize PCI Express port service device * pcie_device_init - allocate and initialize PCI Express port service device
* @dev: Port service device to initialize * @pdev: PCI Express port to associate the service device with
* @parent: PCI Express port to associate the service device with * @service: Type of service to associate with the service device
* @port_type: Type of the port
* @service_type: Type of service to associate with the service device
* @irq: Interrupt vector to associate with the service device * @irq: Interrupt vector to associate with the service device
*/ */
static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev, static int pcie_device_init(struct pci_dev *pdev, int service, int irq)
int service_type, int irq)
{ {
struct pcie_port_data *port_data = pci_get_drvdata(parent); int retval;
struct pcie_device *pcie;
struct device *device; struct device *device;
int port_type = port_data->port_type;
dev->port = parent; pcie = kzalloc(sizeof(*pcie), GFP_KERNEL);
dev->irq = irq; if (!pcie)
dev->service = service_type; return -ENOMEM;
pcie->port = pdev;
pcie->irq = irq;
pcie->service = service;
/* Initialize generic device interface */ /* Initialize generic device interface */
device = &dev->device; device = &pcie->device;
memset(device, 0, sizeof(struct device));
device->bus = &pcie_port_bus_type; device->bus = &pcie_port_bus_type;
device->driver = NULL;
dev_set_drvdata(device, NULL);
device->release = release_pcie_device; /* callback to free pcie dev */ device->release = release_pcie_device; /* callback to free pcie dev */
dev_set_name(device, "%s:pcie%02x", dev_set_name(device, "%s:pcie%02x",
pci_name(parent), get_descriptor_id(port_type, service_type)); pci_name(pdev),
device->parent = &parent->dev; get_descriptor_id(pdev->pcie_type, service));
} device->parent = &pdev->dev;
/** retval = device_register(device);
* alloc_pcie_device - allocate PCI Express port service device structure if (retval)
* @parent: PCI Express port to associate the service device with kfree(pcie);
* @port_type: Type of the port else
* @service_type: Type of service to associate with the service device get_device(device);
* @irq: Interrupt vector to associate with the service device return retval;
*/
static struct pcie_device* alloc_pcie_device(struct pci_dev *parent,
int service_type, int irq)
{
struct pcie_device *device;
device = kzalloc(sizeof(struct pcie_device), GFP_KERNEL);
if (!device)
return NULL;
pcie_device_init(parent, device, service_type, irq);
return device;
}
/**
* pcie_port_device_probe - check if device is a PCI Express port
* @dev: Device to check
*/
int pcie_port_device_probe(struct pci_dev *dev)
{
int pos, type;
u16 reg;
if (!(pos = pci_find_capability(dev, PCI_CAP_ID_EXP)))
return -ENODEV;
pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg);
type = (reg >> 4) & PORT_TYPE_MASK;
if ( type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT ||
type == PCIE_SW_DOWNSTREAM_PORT )
return 0;
return -ENODEV;
} }
/** /**
@ -326,77 +295,49 @@ int pcie_port_device_probe(struct pci_dev *dev)
*/ */
int pcie_port_device_register(struct pci_dev *dev) int pcie_port_device_register(struct pci_dev *dev)
{ {
struct pcie_port_data *port_data; int status, capabilities, i, nr_service;
int status, capabilities, irq_mode, i, nr_serv; int irqs[PCIE_PORT_DEVICE_MAXSERVICES];
int vectors[PCIE_PORT_DEVICE_MAXSERVICES];
u16 reg16;
port_data = kzalloc(sizeof(*port_data), GFP_KERNEL);
if (!port_data)
return -ENOMEM;
pci_set_drvdata(dev, port_data);
/* Get port type */
pci_read_config_word(dev,
pci_find_capability(dev, PCI_CAP_ID_EXP) +
PCIE_CAPABILITIES_REG, &reg16);
port_data->port_type = (reg16 >> 4) & PORT_TYPE_MASK;
/* Get and check PCI Express port services */
capabilities = get_port_device_capability(dev); capabilities = get_port_device_capability(dev);
/* Root ports are capable of generating PME too */ if (!capabilities)
if (port_data->port_type == PCIE_RC_PORT) return -ENODEV;
capabilities |= PCIE_PORT_SERVICE_PME;
irq_mode = assign_interrupt_mode(dev, vectors, capabilities);
if (irq_mode == PCIE_PORT_NO_IRQ) {
/*
* Don't use service devices that require interrupts if there is
* no way to generate them.
*/
if (!(capabilities & PCIE_PORT_SERVICE_VC)) {
status = -ENODEV;
goto Error;
}
capabilities = PCIE_PORT_SERVICE_VC;
}
port_data->port_irq_mode = irq_mode;
/* Enable PCI Express port device */
status = pci_enable_device(dev); status = pci_enable_device(dev);
if (status) if (status)
goto Error; return status;
pci_set_master(dev); pci_set_master(dev);
/*
* Initialize service irqs. Don't use service devices that
* require interrupts if there is no way to generate them.
*/
status = init_service_irqs(dev, irqs, capabilities);
if (status) {
capabilities &= PCIE_PORT_SERVICE_VC;
if (!capabilities)
goto error_disable;
}
/* Allocate child services if any */ /* Allocate child services if any */
for (i = 0, nr_serv = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) { status = -ENODEV;
struct pcie_device *child; nr_service = 0;
for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
int service = 1 << i; int service = 1 << i;
if (!(capabilities & service)) if (!(capabilities & service))
continue; continue;
if (!pcie_device_init(dev, service, irqs[i]))
child = alloc_pcie_device(dev, service, vectors[i]); nr_service++;
if (!child)
continue;
status = device_register(&child->device);
if (status) {
kfree(child);
continue;
}
get_device(&child->device);
nr_serv++;
}
if (!nr_serv) {
pci_disable_device(dev);
status = -ENODEV;
goto Error;
} }
if (!nr_service)
goto error_cleanup_irqs;
return 0; return 0;
Error: error_cleanup_irqs:
kfree(port_data); cleanup_service_irqs(dev);
error_disable:
pci_disable_device(dev);
return status; return status;
} }
@ -464,21 +405,9 @@ static int remove_iter(struct device *dev, void *data)
*/ */
void pcie_port_device_remove(struct pci_dev *dev) void pcie_port_device_remove(struct pci_dev *dev)
{ {
struct pcie_port_data *port_data = pci_get_drvdata(dev);
device_for_each_child(&dev->dev, NULL, remove_iter); device_for_each_child(&dev->dev, NULL, remove_iter);
cleanup_service_irqs(dev);
pci_disable_device(dev); pci_disable_device(dev);
switch (port_data->port_irq_mode) {
case PCIE_PORT_MSIX_MODE:
pci_disable_msix(dev);
break;
case PCIE_PORT_MSI_MODE:
pci_disable_msi(dev);
break;
}
kfree(port_data);
} }
/** /**

View file

@ -72,9 +72,11 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
{ {
int status; int status;
status = pcie_port_device_probe(dev); if (!pci_is_pcie(dev) ||
if (status) ((dev->pcie_type != PCI_EXP_TYPE_ROOT_PORT) &&
return status; (dev->pcie_type != PCI_EXP_TYPE_UPSTREAM) &&
(dev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)))
return -ENODEV;
if (!dev->irq && dev->pin) { if (!dev->irq && dev->pin) {
dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; " dev_warn(&dev->dev, "device [%04x:%04x] has invalid IRQ; "

View file

@ -10,6 +10,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/pci-aspm.h> #include <linux/pci-aspm.h>
#include <acpi/acpi_hest.h>
#include "pci.h" #include "pci.h"
#define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */
@ -163,12 +164,12 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
{ {
u32 l, sz, mask; u32 l, sz, mask;
mask = type ? ~PCI_ROM_ADDRESS_ENABLE : ~0; mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
res->name = pci_name(dev); res->name = pci_name(dev);
pci_read_config_dword(dev, pos, &l); pci_read_config_dword(dev, pos, &l);
pci_write_config_dword(dev, pos, mask); pci_write_config_dword(dev, pos, l | mask);
pci_read_config_dword(dev, pos, &sz); pci_read_config_dword(dev, pos, &sz);
pci_write_config_dword(dev, pos, l); pci_write_config_dword(dev, pos, l);
@ -223,9 +224,13 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
goto fail; goto fail;
if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) { if ((sizeof(resource_size_t) < 8) && (sz64 > 0x100000000ULL)) {
dev_err(&dev->dev, "can't handle 64-bit BAR\n"); dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n",
pos);
goto fail; goto fail;
} else if ((sizeof(resource_size_t) < 8) && l) { }
res->flags |= IORESOURCE_MEM_64;
if ((sizeof(resource_size_t) < 8) && l) {
/* Address above 32-bit boundary; disable the BAR */ /* Address above 32-bit boundary; disable the BAR */
pci_write_config_dword(dev, pos, 0); pci_write_config_dword(dev, pos, 0);
pci_write_config_dword(dev, pos + 4, 0); pci_write_config_dword(dev, pos + 4, 0);
@ -234,14 +239,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
} else { } else {
res->start = l64; res->start = l64;
res->end = l64 + sz64; res->end = l64 + sz64;
dev_printk(KERN_DEBUG, &dev->dev, dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n",
"reg %x %s: %pR\n", pos, pos, res);
(res->flags & IORESOURCE_PREFETCH) ?
"64bit mmio pref" : "64bit mmio",
res);
} }
res->flags |= IORESOURCE_MEM_64;
} else { } else {
sz = pci_size(l, sz, mask); sz = pci_size(l, sz, mask);
@ -251,11 +251,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
res->start = l; res->start = l;
res->end = l + sz; res->end = l + sz;
dev_printk(KERN_DEBUG, &dev->dev, "reg %x %s: %pR\n", pos, dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res);
(res->flags & IORESOURCE_IO) ? "io port" :
((res->flags & IORESOURCE_PREFETCH) ?
"32bit mmio pref" : "32bit mmio"),
res);
} }
out: out:
@ -297,8 +293,11 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */ if (pci_is_root_bus(child)) /* It's a host bus, nothing to read */
return; return;
dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n",
child->secondary, child->subordinate,
dev->transparent ? " (subtractive decode)": "");
if (dev->transparent) { if (dev->transparent) {
dev_info(&dev->dev, "transparent bridge\n");
for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++) for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
child->resource[i] = child->parent->resource[i - 3]; child->resource[i] = child->parent->resource[i - 3];
} }
@ -323,7 +322,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->start = base; res->start = base;
if (!res->end) if (!res->end)
res->end = limit + 0xfff; res->end = limit + 0xfff;
dev_printk(KERN_DEBUG, &dev->dev, "bridge io port: %pR\n", res); dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
} }
res = child->resource[1]; res = child->resource[1];
@ -335,8 +334,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
res->start = base; res->start = base;
res->end = limit + 0xfffff; res->end = limit + 0xfffff;
dev_printk(KERN_DEBUG, &dev->dev, "bridge 32bit mmio: %pR\n", dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
res);
} }
res = child->resource[2]; res = child->resource[2];
@ -375,9 +373,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
res->flags |= IORESOURCE_MEM_64; res->flags |= IORESOURCE_MEM_64;
res->start = base; res->start = base;
res->end = limit + 0xfffff; res->end = limit + 0xfffff;
dev_printk(KERN_DEBUG, &dev->dev, "bridge %sbit mmio pref: %pR\n", dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res);
(res->flags & PCI_PREF_RANGE_TYPE_64) ? "64" : "32",
res);
} }
} }
@ -651,13 +647,14 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
(child->number > bus->subordinate) || (child->number > bus->subordinate) ||
(child->number < bus->number) || (child->number < bus->number) ||
(child->subordinate < bus->number)) { (child->subordinate < bus->number)) {
pr_debug("PCI: Bus #%02x (-#%02x) is %s " dev_info(&child->dev, "[bus %02x-%02x] %s "
"hidden behind%s bridge #%02x (-#%02x)\n", "hidden behind%s bridge %s [bus %02x-%02x]\n",
child->number, child->subordinate, child->number, child->subordinate,
(bus->number > child->subordinate && (bus->number > child->subordinate &&
bus->subordinate < child->number) ? bus->subordinate < child->number) ?
"wholly" : "partially", "wholly" : "partially",
bus->self->transparent ? " transparent" : "", bus->self->transparent ? " transparent" : "",
dev_name(&bus->dev),
bus->number, bus->subordinate); bus->number, bus->subordinate);
} }
bus = bus->parent; bus = bus->parent;
@ -693,6 +690,7 @@ static void set_pcie_port_type(struct pci_dev *pdev)
if (!pos) if (!pos)
return; return;
pdev->is_pcie = 1; pdev->is_pcie = 1;
pdev->pcie_cap = pos;
pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16); pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4; pdev->pcie_type = (reg16 & PCI_EXP_FLAGS_TYPE) >> 4;
} }
@ -703,7 +701,7 @@ static void set_pcie_hotplug_bridge(struct pci_dev *pdev)
u16 reg16; u16 reg16;
u32 reg32; u32 reg32;
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(pdev);
if (!pos) if (!pos)
return; return;
pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16); pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, &reg16);
@ -714,6 +712,12 @@ static void set_pcie_hotplug_bridge(struct pci_dev *pdev)
pdev->is_hotplug_bridge = 1; pdev->is_hotplug_bridge = 1;
} }
static void set_pci_aer_firmware_first(struct pci_dev *pdev)
{
if (acpi_hest_firmware_first_pci(pdev))
pdev->aer_firmware_first = 1;
}
#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED) #define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
/** /**
@ -731,6 +735,7 @@ int pci_setup_device(struct pci_dev *dev)
u32 class; u32 class;
u8 hdr_type; u8 hdr_type;
struct pci_slot *slot; struct pci_slot *slot;
int pos = 0;
if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type)) if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type))
return -EIO; return -EIO;
@ -742,6 +747,7 @@ int pci_setup_device(struct pci_dev *dev)
dev->multifunction = !!(hdr_type & 0x80); dev->multifunction = !!(hdr_type & 0x80);
dev->error_state = pci_channel_io_normal; dev->error_state = pci_channel_io_normal;
set_pcie_port_type(dev); set_pcie_port_type(dev);
set_pci_aer_firmware_first(dev);
list_for_each_entry(slot, &dev->bus->slots, list) list_for_each_entry(slot, &dev->bus->slots, list)
if (PCI_SLOT(dev->devfn) == slot->number) if (PCI_SLOT(dev->devfn) == slot->number)
@ -822,6 +828,11 @@ int pci_setup_device(struct pci_dev *dev)
dev->transparent = ((dev->class & 0xff) == 1); dev->transparent = ((dev->class & 0xff) == 1);
pci_read_bases(dev, 2, PCI_ROM_ADDRESS1); pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
set_pcie_hotplug_bridge(dev); set_pcie_hotplug_bridge(dev);
pos = pci_find_capability(dev, PCI_CAP_ID_SSVID);
if (pos) {
pci_read_config_word(dev, pos + PCI_SSVID_VENDOR_ID, &dev->subsystem_vendor);
pci_read_config_word(dev, pos + PCI_SSVID_DEVICE_ID, &dev->subsystem_device);
}
break; break;
case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */ case PCI_HEADER_TYPE_CARDBUS: /* CardBus bridge header */
@ -907,7 +918,7 @@ int pci_cfg_space_size(struct pci_dev *dev)
if (class == PCI_CLASS_BRIDGE_HOST) if (class == PCI_CLASS_BRIDGE_HOST)
return pci_cfg_space_size_ext(dev); return pci_cfg_space_size_ext(dev);
pos = pci_find_capability(dev, PCI_CAP_ID_EXP); pos = pci_pcie_cap(dev);
if (!pos) { if (!pos) {
pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
if (!pos) if (!pos)
@ -1014,6 +1025,9 @@ static void pci_init_capabilities(struct pci_dev *dev)
/* Single Root I/O Virtualization */ /* Single Root I/O Virtualization */
pci_iov_init(dev); pci_iov_init(dev);
/* Enable ACS P2P upstream forwarding */
pci_enable_acs(dev);
} }
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
@ -1110,7 +1124,7 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
unsigned int devfn, pass, max = bus->secondary; unsigned int devfn, pass, max = bus->secondary;
struct pci_dev *dev; struct pci_dev *dev;
pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(bus), bus->number); dev_dbg(&bus->dev, "scanning bus\n");
/* Go find them, Rover! */ /* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8) for (devfn = 0; devfn < 0x100; devfn += 8)
@ -1124,8 +1138,7 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
* all PCI-to-PCI bridges on this bus. * all PCI-to-PCI bridges on this bus.
*/ */
if (!bus->is_added) { if (!bus->is_added) {
pr_debug("PCI: Fixups for bus %04x:%02x\n", dev_dbg(&bus->dev, "fixups for bus\n");
pci_domain_nr(bus), bus->number);
pcibios_fixup_bus(bus); pcibios_fixup_bus(bus);
if (pci_is_root_bus(bus)) if (pci_is_root_bus(bus))
bus->is_added = 1; bus->is_added = 1;
@ -1145,8 +1158,7 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
* *
* Return how far we've got finding sub-buses. * Return how far we've got finding sub-buses.
*/ */
pr_debug("PCI: Bus scan for %04x:%02x returning with max=%02x\n", dev_dbg(&bus->dev, "bus scan returning with max=%02x\n", max);
pci_domain_nr(bus), bus->number, max);
return max; return max;
} }
@ -1154,7 +1166,7 @@ struct pci_bus * pci_create_bus(struct device *parent,
int bus, struct pci_ops *ops, void *sysdata) int bus, struct pci_ops *ops, void *sysdata)
{ {
int error; int error;
struct pci_bus *b; struct pci_bus *b, *b2;
struct device *dev; struct device *dev;
b = pci_alloc_bus(); b = pci_alloc_bus();
@ -1170,9 +1182,10 @@ struct pci_bus * pci_create_bus(struct device *parent,
b->sysdata = sysdata; b->sysdata = sysdata;
b->ops = ops; b->ops = ops;
if (pci_find_bus(pci_domain_nr(b), bus)) { b2 = pci_find_bus(pci_domain_nr(b), bus);
if (b2) {
/* If we already got to this bus through a different bridge, ignore it */ /* If we already got to this bus through a different bridge, ignore it */
pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus); dev_dbg(&b2->dev, "bus already known\n");
goto err_out; goto err_out;
} }

View file

@ -357,7 +357,7 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region,
pcibios_bus_to_resource(dev, res, &bus_region); pcibios_bus_to_resource(dev, res, &bus_region);
pci_claim_resource(dev, nr); pci_claim_resource(dev, nr);
dev_info(&dev->dev, "quirk: region %04x-%04x claimed by %s\n", region, region + size - 1, name); dev_info(&dev->dev, "quirk: %pR claimed by %s\n", res, name);
} }
} }
@ -1680,6 +1680,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_
*/ */
#define AMD_813X_MISC 0x40 #define AMD_813X_MISC 0x40
#define AMD_813X_NOIOAMODE (1<<0) #define AMD_813X_NOIOAMODE (1<<0)
#define AMD_813X_REV_B1 0x12
#define AMD_813X_REV_B2 0x13 #define AMD_813X_REV_B2 0x13
static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev) static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev)
@ -1688,7 +1689,8 @@ static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev)
if (noioapicquirk) if (noioapicquirk)
return; return;
if (dev->revision == AMD_813X_REV_B2) if ((dev->revision == AMD_813X_REV_B1) ||
(dev->revision == AMD_813X_REV_B2))
return; return;
pci_read_config_dword(dev, AMD_813X_MISC, &pci_config_dword); pci_read_config_dword(dev, AMD_813X_MISC, &pci_config_dword);
@ -1699,6 +1701,8 @@ static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev)
dev->vendor, dev->device); dev->vendor, dev->device);
} }
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_amd_813x_boot_interrupt); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_amd_813x_boot_interrupt);
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_amd_813x_boot_interrupt);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, quirk_disable_amd_813x_boot_interrupt);
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, quirk_disable_amd_813x_boot_interrupt); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, quirk_disable_amd_813x_boot_interrupt);
#define AMD_8111_PCI_IRQ_ROUTING 0x56 #define AMD_8111_PCI_IRQ_ROUTING 0x56
@ -2595,9 +2599,37 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
static int __init pci_apply_final_quirks(void) static int __init pci_apply_final_quirks(void)
{ {
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
u8 cls = 0;
u8 tmp;
if (pci_cache_line_size)
printk(KERN_DEBUG "PCI: CLS %u bytes\n",
pci_cache_line_size << 2);
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_fixup_device(pci_fixup_final, dev); pci_fixup_device(pci_fixup_final, dev);
/*
* If arch hasn't set it explicitly yet, use the CLS
* value shared by all PCI devices. If there's a
* mismatch, fall back to the default value.
*/
if (!pci_cache_line_size) {
pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &tmp);
if (!cls)
cls = tmp;
if (!tmp || cls == tmp)
continue;
printk(KERN_DEBUG "PCI: CLS mismatch (%u != %u), "
"using %u bytes\n", cls << 2, tmp << 2,
pci_dfl_cache_line_size << 2);
pci_cache_line_size = pci_dfl_cache_line_size;
}
}
if (!pci_cache_line_size) {
printk(KERN_DEBUG "PCI: CLS %u bytes, default %u\n",
cls << 2, pci_dfl_cache_line_size << 2);
pci_cache_line_size = cls;
} }
return 0; return 0;

View file

@ -26,14 +26,14 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
{ {
struct pci_dev *tmp = NULL; struct pci_dev *tmp = NULL;
if (pdev->is_pcie) if (pci_is_pcie(pdev))
return NULL; return NULL;
while (1) { while (1) {
if (pci_is_root_bus(pdev->bus)) if (pci_is_root_bus(pdev->bus))
break; break;
pdev = pdev->bus->self; pdev = pdev->bus->self;
/* a p2p bridge */ /* a p2p bridge */
if (!pdev->is_pcie) { if (!pci_is_pcie(pdev)) {
tmp = pdev; tmp = pdev;
continue; continue;
} }
@ -149,32 +149,33 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
} }
/** /**
* pci_get_bus_and_slot - locate PCI device from a given PCI bus & slot * pci_get_domain_bus_and_slot - locate PCI device for a given PCI domain (segment), bus, and slot
* @bus: number of PCI bus on which desired PCI device resides * @domain: PCI domain/segment on which the PCI device resides.
* @devfn: encodes number of PCI slot in which the desired PCI * @bus: PCI bus on which desired PCI device resides
* device resides and the logical device number within that slot * @devfn: encodes number of PCI slot in which the desired PCI device
* in case of multi-function devices. * resides and the logical device number within that slot in case of
* multi-function devices.
* *
* Note: the bus/slot search is limited to PCI domain (segment) 0. * Given a PCI domain, bus, and slot/function number, the desired PCI
* * device is located in the list of PCI devices. If the device is
* Given a PCI bus and slot/function number, the desired PCI device * found, its reference count is increased and this function returns a
* is located in system global list of PCI devices. If the device * pointer to its data structure. The caller must decrement the
* is found, a pointer to its data structure is returned. If no * reference count by calling pci_dev_put(). If no device is found,
* device is found, %NULL is returned. The returned device has its * %NULL is returned.
* reference count bumped by one.
*/ */
struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn) unsigned int devfn)
{ {
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
if (pci_domain_nr(dev->bus) == 0 && if (pci_domain_nr(dev->bus) == domain &&
(dev->bus->number == bus && dev->devfn == devfn)) (dev->bus->number == bus && dev->devfn == devfn))
return dev; return dev;
} }
return NULL; return NULL;
} }
EXPORT_SYMBOL(pci_get_domain_bus_and_slot);
static int match_pci_dev_by_id(struct device *dev, void *data) static int match_pci_dev_by_id(struct device *dev, void *data)
{ {
@ -354,5 +355,4 @@ EXPORT_SYMBOL(pci_find_next_bus);
EXPORT_SYMBOL(pci_get_device); EXPORT_SYMBOL(pci_get_device);
EXPORT_SYMBOL(pci_get_subsys); EXPORT_SYMBOL(pci_get_subsys);
EXPORT_SYMBOL(pci_get_slot); EXPORT_SYMBOL(pci_get_slot);
EXPORT_SYMBOL(pci_get_bus_and_slot);
EXPORT_SYMBOL(pci_get_class); EXPORT_SYMBOL(pci_get_class);

View file

@ -71,53 +71,50 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus)
void pci_setup_cardbus(struct pci_bus *bus) void pci_setup_cardbus(struct pci_bus *bus)
{ {
struct pci_dev *bridge = bus->self; struct pci_dev *bridge = bus->self;
struct resource *res;
struct pci_bus_region region; struct pci_bus_region region;
dev_info(&bridge->dev, "CardBus bridge, secondary bus %04x:%02x\n", dev_info(&bridge->dev, "CardBus bridge to [bus %02x-%02x]\n",
pci_domain_nr(bus), bus->number); bus->secondary, bus->subordinate);
pcibios_resource_to_bus(bridge, &region, bus->resource[0]); res = bus->resource[0];
if (bus->resource[0]->flags & IORESOURCE_IO) { pcibios_resource_to_bus(bridge, &region, res);
if (res->flags & IORESOURCE_IO) {
/* /*
* The IO resource is allocated a range twice as large as it * The IO resource is allocated a range twice as large as it
* would normally need. This allows us to set both IO regs. * would normally need. This allows us to set both IO regs.
*/ */
dev_info(&bridge->dev, " IO window: %#08lx-%#08lx\n", dev_info(&bridge->dev, " bridge window %pR\n", res);
(unsigned long)region.start,
(unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_0, pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
region.start); region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0, pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
region.end); region.end);
} }
pcibios_resource_to_bus(bridge, &region, bus->resource[1]); res = bus->resource[1];
if (bus->resource[1]->flags & IORESOURCE_IO) { pcibios_resource_to_bus(bridge, &region, res);
dev_info(&bridge->dev, " IO window: %#08lx-%#08lx\n", if (res->flags & IORESOURCE_IO) {
(unsigned long)region.start, dev_info(&bridge->dev, " bridge window %pR\n", res);
(unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
region.start); region.start);
pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1, pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
region.end); region.end);
} }
pcibios_resource_to_bus(bridge, &region, bus->resource[2]); res = bus->resource[2];
if (bus->resource[2]->flags & IORESOURCE_MEM) { pcibios_resource_to_bus(bridge, &region, res);
dev_info(&bridge->dev, " PREFETCH window: %#08lx-%#08lx\n", if (res->flags & IORESOURCE_MEM) {
(unsigned long)region.start, dev_info(&bridge->dev, " bridge window %pR\n", res);
(unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
region.start); region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0, pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
region.end); region.end);
} }
pcibios_resource_to_bus(bridge, &region, bus->resource[3]); res = bus->resource[3];
if (bus->resource[3]->flags & IORESOURCE_MEM) { pcibios_resource_to_bus(bridge, &region, res);
dev_info(&bridge->dev, " MEM window: %#08lx-%#08lx\n", if (res->flags & IORESOURCE_MEM) {
(unsigned long)region.start, dev_info(&bridge->dev, " bridge window %pR\n", res);
(unsigned long)region.end);
pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
region.start); region.start);
pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1, pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
@ -140,34 +137,33 @@ EXPORT_SYMBOL(pci_setup_cardbus);
static void pci_setup_bridge(struct pci_bus *bus) static void pci_setup_bridge(struct pci_bus *bus)
{ {
struct pci_dev *bridge = bus->self; struct pci_dev *bridge = bus->self;
struct resource *res;
struct pci_bus_region region; struct pci_bus_region region;
u32 l, bu, lu, io_upper16; u32 l, bu, lu, io_upper16;
int pref_mem64;
if (pci_is_enabled(bridge)) if (pci_is_enabled(bridge))
return; return;
dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n", dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n",
pci_domain_nr(bus), bus->number); bus->secondary, bus->subordinate);
/* Set up the top and bottom of the PCI I/O segment for this bus. */ /* Set up the top and bottom of the PCI I/O segment for this bus. */
pcibios_resource_to_bus(bridge, &region, bus->resource[0]); res = bus->resource[0];
if (bus->resource[0]->flags & IORESOURCE_IO) { pcibios_resource_to_bus(bridge, &region, res);
if (res->flags & IORESOURCE_IO) {
pci_read_config_dword(bridge, PCI_IO_BASE, &l); pci_read_config_dword(bridge, PCI_IO_BASE, &l);
l &= 0xffff0000; l &= 0xffff0000;
l |= (region.start >> 8) & 0x00f0; l |= (region.start >> 8) & 0x00f0;
l |= region.end & 0xf000; l |= region.end & 0xf000;
/* Set up upper 16 bits of I/O base/limit. */ /* Set up upper 16 bits of I/O base/limit. */
io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
dev_info(&bridge->dev, " IO window: %#04lx-%#04lx\n", dev_info(&bridge->dev, " bridge window %pR\n", res);
(unsigned long)region.start,
(unsigned long)region.end);
} }
else { else {
/* Clear upper 16 bits of I/O base/limit. */ /* Clear upper 16 bits of I/O base/limit. */
io_upper16 = 0; io_upper16 = 0;
l = 0x00f0; l = 0x00f0;
dev_info(&bridge->dev, " IO window: disabled\n"); dev_info(&bridge->dev, " bridge window [io disabled]\n");
} }
/* Temporarily disable the I/O range before updating PCI_IO_BASE. */ /* Temporarily disable the I/O range before updating PCI_IO_BASE. */
pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff); pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
@ -178,17 +174,16 @@ static void pci_setup_bridge(struct pci_bus *bus)
/* Set up the top and bottom of the PCI Memory segment /* Set up the top and bottom of the PCI Memory segment
for this bus. */ for this bus. */
pcibios_resource_to_bus(bridge, &region, bus->resource[1]); res = bus->resource[1];
if (bus->resource[1]->flags & IORESOURCE_MEM) { pcibios_resource_to_bus(bridge, &region, res);
if (res->flags & IORESOURCE_MEM) {
l = (region.start >> 16) & 0xfff0; l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000; l |= region.end & 0xfff00000;
dev_info(&bridge->dev, " MEM window: %#08lx-%#08lx\n", dev_info(&bridge->dev, " bridge window %pR\n", res);
(unsigned long)region.start,
(unsigned long)region.end);
} }
else { else {
l = 0x0000fff0; l = 0x0000fff0;
dev_info(&bridge->dev, " MEM window: disabled\n"); dev_info(&bridge->dev, " bridge window [mem disabled]\n");
} }
pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
@ -198,34 +193,27 @@ static void pci_setup_bridge(struct pci_bus *bus)
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
/* Set up PREF base/limit. */ /* Set up PREF base/limit. */
pref_mem64 = 0;
bu = lu = 0; bu = lu = 0;
pcibios_resource_to_bus(bridge, &region, bus->resource[2]); res = bus->resource[2];
if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { pcibios_resource_to_bus(bridge, &region, res);
int width = 8; if (res->flags & IORESOURCE_PREFETCH) {
l = (region.start >> 16) & 0xfff0; l = (region.start >> 16) & 0xfff0;
l |= region.end & 0xfff00000; l |= region.end & 0xfff00000;
if (bus->resource[2]->flags & IORESOURCE_MEM_64) { if (res->flags & IORESOURCE_MEM_64) {
pref_mem64 = 1;
bu = upper_32_bits(region.start); bu = upper_32_bits(region.start);
lu = upper_32_bits(region.end); lu = upper_32_bits(region.end);
width = 16;
} }
dev_info(&bridge->dev, " PREFETCH window: %#0*llx-%#0*llx\n", dev_info(&bridge->dev, " bridge window %pR\n", res);
width, (unsigned long long)region.start,
width, (unsigned long long)region.end);
} }
else { else {
l = 0x0000fff0; l = 0x0000fff0;
dev_info(&bridge->dev, " PREFETCH window: disabled\n"); dev_info(&bridge->dev, " bridge window [mem pref disabled]\n");
} }
pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
if (pref_mem64) {
/* Set the upper 32 bits of PREF base & limit. */ /* Set the upper 32 bits of PREF base & limit. */
pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
}
pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
} }
@ -345,6 +333,10 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size)
#endif #endif
size = ALIGN(size + size1, 4096); size = ALIGN(size + size1, 4096);
if (!size) { if (!size) {
if (b_res->start || b_res->end)
dev_info(&bus->self->dev, "disabling bridge window "
"%pR to [bus %02x-%02x] (unused)\n", b_res,
bus->secondary, bus->subordinate);
b_res->flags = 0; b_res->flags = 0;
return; return;
} }
@ -390,8 +382,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
align = pci_resource_alignment(dev, r); align = pci_resource_alignment(dev, r);
order = __ffs(align) - 20; order = __ffs(align) - 20;
if (order > 11) { if (order > 11) {
dev_warn(&dev->dev, "BAR %d bad alignment %llx: " dev_warn(&dev->dev, "disabling BAR %d: %pR "
"%pR\n", i, (unsigned long long)align, r); "(bad alignment %#llx)\n", i, r,
(unsigned long long) align);
r->flags = 0; r->flags = 0;
continue; continue;
} }
@ -425,6 +418,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
} }
size = ALIGN(size, min_align); size = ALIGN(size, min_align);
if (!size) { if (!size) {
if (b_res->start || b_res->end)
dev_info(&bus->self->dev, "disabling bridge window "
"%pR to [bus %02x-%02x] (unused)\n", b_res,
bus->secondary, bus->subordinate);
b_res->flags = 0; b_res->flags = 0;
return 1; return 1;
} }
@ -582,10 +579,7 @@ static void pci_bus_dump_res(struct pci_bus *bus)
if (!res || !res->end) if (!res || !res->end)
continue; continue;
dev_printk(KERN_DEBUG, &bus->dev, "resource %d %s %pR\n", i, dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pR\n", i, res);
(res->flags & IORESOURCE_IO) ? "io: " :
((res->flags & IORESOURCE_PREFETCH)? "pref mem":"mem:"),
res);
} }
} }

View file

@ -51,12 +51,6 @@ void pci_update_resource(struct pci_dev *dev, int resno)
pcibios_resource_to_bus(dev, &region, res); pcibios_resource_to_bus(dev, &region, res);
dev_dbg(&dev->dev, "BAR %d: got res %pR bus [%#llx-%#llx] "
"flags %#lx\n", resno, res,
(unsigned long long)region.start,
(unsigned long long)region.end,
(unsigned long)res->flags);
new = region.start | (res->flags & PCI_REGION_FLAG_MASK); new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
if (res->flags & IORESOURCE_IO) if (res->flags & IORESOURCE_IO)
mask = (u32)PCI_BASE_ADDRESS_IO_MASK; mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
@ -91,9 +85,9 @@ void pci_update_resource(struct pci_dev *dev, int resno)
} }
} }
res->flags &= ~IORESOURCE_UNSET; res->flags &= ~IORESOURCE_UNSET;
dev_dbg(&dev->dev, "BAR %d: moved to bus [%#llx-%#llx] flags %#lx\n", dev_info(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx]\n",
resno, (unsigned long long)region.start, resno, res, (unsigned long long)region.start,
(unsigned long long)region.end, res->flags); (unsigned long long)region.end);
} }
int pci_claim_resource(struct pci_dev *dev, int resource) int pci_claim_resource(struct pci_dev *dev, int resource)
@ -103,20 +97,17 @@ int pci_claim_resource(struct pci_dev *dev, int resource)
int err; int err;
root = pci_find_parent_resource(dev, res); root = pci_find_parent_resource(dev, res);
if (!root) {
err = -EINVAL; dev_err(&dev->dev, "no compatible bridge window for %pR\n",
if (root != NULL) res);
err = request_resource(root, res); return -EINVAL;
if (err) {
const char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
dev_err(&dev->dev, "BAR %d: %s of %s %pR\n",
resource,
root ? "address space collision on" :
"no parent found for",
dtype, res);
} }
err = request_resource(root, res);
if (err)
dev_err(&dev->dev,
"address space collision: %pR already in use\n", res);
return err; return err;
} }
EXPORT_SYMBOL(pci_claim_resource); EXPORT_SYMBOL(pci_claim_resource);
@ -124,7 +115,7 @@ EXPORT_SYMBOL(pci_claim_resource);
#ifdef CONFIG_PCI_QUIRKS #ifdef CONFIG_PCI_QUIRKS
void pci_disable_bridge_window(struct pci_dev *dev) void pci_disable_bridge_window(struct pci_dev *dev)
{ {
dev_dbg(&dev->dev, "Disabling bridge window.\n"); dev_info(&dev->dev, "disabling bridge mem windows\n");
/* MMIO Base/Limit */ /* MMIO Base/Limit */
pci_write_config_dword(dev, PCI_MEMORY_BASE, 0x0000fff0); pci_write_config_dword(dev, PCI_MEMORY_BASE, 0x0000fff0);
@ -165,6 +156,7 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
if (!ret) { if (!ret) {
res->flags &= ~IORESOURCE_STARTALIGN; res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
if (resno < PCI_BRIDGE_RESOURCES) if (resno < PCI_BRIDGE_RESOURCES)
pci_update_resource(dev, resno); pci_update_resource(dev, resno);
} }
@ -178,12 +170,12 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
resource_size_t align; resource_size_t align;
struct pci_bus *bus; struct pci_bus *bus;
int ret; int ret;
char *type;
align = pci_resource_alignment(dev, res); align = pci_resource_alignment(dev, res);
if (!align) { if (!align) {
dev_info(&dev->dev, "BAR %d: can't allocate resource (bogus " dev_info(&dev->dev, "BAR %d: can't assign %pR "
"alignment) %pR flags %#lx\n", "(bogus alignment)\n", resno, res);
resno, res, res->flags);
return -EINVAL; return -EINVAL;
} }
@ -198,9 +190,20 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
break; break;
} }
if (ret) if (ret) {
dev_info(&dev->dev, "BAR %d: can't allocate %s resource %pR\n", if (res->flags & IORESOURCE_MEM)
resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res); 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));
}
return ret; return ret;
} }
@ -225,9 +228,8 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
r_align = pci_resource_alignment(dev, r); r_align = pci_resource_alignment(dev, r);
if (!r_align) { if (!r_align) {
dev_warn(&dev->dev, "BAR %d: bogus alignment " dev_warn(&dev->dev, "BAR %d: %pR has bogus alignment\n",
"%pR flags %#lx\n", i, r);
i, r, r->flags);
continue; continue;
} }
for (list = head; ; list = list->next) { for (list = head; ; list = list->next) {
@ -274,8 +276,8 @@ int pci_enable_resources(struct pci_dev *dev, int mask)
continue; continue;
if (!r->parent) { if (!r->parent) {
dev_err(&dev->dev, "device not available because of " dev_err(&dev->dev, "device not available "
"BAR %d %pR collisions\n", i, r); "(can't reserve %pR)\n", r);
return -EINVAL; return -EINVAL;
} }

View file

@ -184,26 +184,33 @@ fail:
=====================================================================*/ =====================================================================*/
/* static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq)
* Since there is only one interrupt available to CardBus
* devices, all devices downstream of this device must
* be using this IRQ.
*/
static void cardbus_assign_irqs(struct pci_bus *bus, int irq)
{ {
struct pci_dev *dev; struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) { list_for_each_entry(dev, &bus->devices, bus_list) {
u8 irq_pin; u8 irq_pin;
/*
* Since there is only one interrupt available to
* CardBus devices, all devices downstream of this
* device must be using this IRQ.
*/
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
if (irq_pin) { if (irq_pin) {
dev->irq = irq; dev->irq = irq;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
} }
/*
* Some controllers transfer very slowly with 0 CLS.
* Configure it. This may fail as CLS configuration
* is mandatory only for MWI.
*/
pci_set_cacheline_size(dev);
if (dev->subordinate) if (dev->subordinate)
cardbus_assign_irqs(dev->subordinate, irq); cardbus_config_irq_and_cls(dev->subordinate, irq);
} }
} }
@ -228,7 +235,7 @@ int __ref cb_alloc(struct pcmcia_socket * s)
*/ */
pci_bus_size_bridges(bus); pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus); pci_bus_assign_resources(bus);
cardbus_assign_irqs(bus, s->pci_irq); cardbus_config_irq_and_cls(bus, s->pci_irq);
/* socket specific tune function */ /* socket specific tune function */
if (s->tune_bridge) if (s->tune_bridge)

View file

@ -285,15 +285,10 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
* the PCI region, and that might prevent a PCI * the PCI region, and that might prevent a PCI
* driver from requesting its resources. * driver from requesting its resources.
*/ */
dev_warn(&dev->dev, "%s resource " dev_warn(&dev->dev,
"(0x%llx-0x%llx) overlaps %s BAR %d " "disabling %pR because it overlaps "
"(0x%llx-0x%llx), disabling\n", "%s BAR %d %pR\n", res,
pnp_resource_type_name(res), pci_name(pdev), i, &pdev->resource[i]);
(unsigned long long) pnp_start,
(unsigned long long) pnp_end,
pci_name(pdev), i,
(unsigned long long) pci_start,
(unsigned long long) pci_end);
res->flags |= IORESOURCE_DISABLED; res->flags |= IORESOURCE_DISABLED;
} }
} }

View file

@ -517,7 +517,7 @@ struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
res->start = irq; res->start = irq;
res->end = irq; res->end = irq;
pnp_dbg(&dev->dev, " add irq %d flags %#x\n", irq, flags); pnp_dbg(&dev->dev, " add %pr\n", res);
return pnp_res; return pnp_res;
} }
@ -538,7 +538,7 @@ struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
res->start = dma; res->start = dma;
res->end = dma; res->end = dma;
pnp_dbg(&dev->dev, " add dma %d flags %#x\n", dma, flags); pnp_dbg(&dev->dev, " add %pr\n", res);
return pnp_res; return pnp_res;
} }
@ -562,8 +562,7 @@ struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
res->start = start; res->start = start;
res->end = end; res->end = end;
pnp_dbg(&dev->dev, " add io %#llx-%#llx flags %#x\n", pnp_dbg(&dev->dev, " add %pr\n", res);
(unsigned long long) start, (unsigned long long) end, flags);
return pnp_res; return pnp_res;
} }
@ -587,8 +586,7 @@ struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
res->start = start; res->start = start;
res->end = end; res->end = end;
pnp_dbg(&dev->dev, " add mem %#llx-%#llx flags %#x\n", pnp_dbg(&dev->dev, " add %pr\n", res);
(unsigned long long) start, (unsigned long long) end, flags);
return pnp_res; return pnp_res;
} }

View file

@ -75,47 +75,14 @@ char *pnp_resource_type_name(struct resource *res)
void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc) void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc)
{ {
char buf[128];
int len;
struct pnp_resource *pnp_res; struct pnp_resource *pnp_res;
struct resource *res;
if (list_empty(&dev->resources)) { if (list_empty(&dev->resources))
pnp_dbg(&dev->dev, "%s: no current resources\n", desc); pnp_dbg(&dev->dev, "%s: no current resources\n", desc);
return; else {
}
pnp_dbg(&dev->dev, "%s: current resources:\n", desc); pnp_dbg(&dev->dev, "%s: current resources:\n", desc);
list_for_each_entry(pnp_res, &dev->resources, list) { list_for_each_entry(pnp_res, &dev->resources, list)
res = &pnp_res->res; pnp_dbg(&dev->dev, "%pr\n", &pnp_res->res);
len = 0;
len += scnprintf(buf + len, sizeof(buf) - len, " %-3s ",
pnp_resource_type_name(res));
if (res->flags & IORESOURCE_DISABLED) {
pnp_dbg(&dev->dev, "%sdisabled\n", buf);
continue;
}
switch (pnp_resource_type(res)) {
case IORESOURCE_IO:
case IORESOURCE_MEM:
len += scnprintf(buf + len, sizeof(buf) - len,
"%#llx-%#llx flags %#lx",
(unsigned long long) res->start,
(unsigned long long) res->end,
res->flags);
break;
case IORESOURCE_IRQ:
case IORESOURCE_DMA:
len += scnprintf(buf + len, sizeof(buf) - len,
"%lld flags %#lx",
(unsigned long long) res->start,
res->flags);
break;
}
pnp_dbg(&dev->dev, "%s\n", buf);
} }
} }

View file

@ -22,11 +22,11 @@ static const struct pnp_device_id pnp_dev_table[] = {
{"", 0} {"", 0}
}; };
static void reserve_range(struct pnp_dev *dev, resource_size_t start, static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
resource_size_t end, int port)
{ {
char *regionid; char *regionid;
const char *pnpid = dev_name(&dev->dev); const char *pnpid = dev_name(&dev->dev);
resource_size_t start = r->start, end = r->end;
struct resource *res; struct resource *res;
regionid = kmalloc(16, GFP_KERNEL); regionid = kmalloc(16, GFP_KERNEL);
@ -48,9 +48,7 @@ static void reserve_range(struct pnp_dev *dev, resource_size_t start,
* example do reserve stuff they know about too, so we may well * example do reserve stuff they know about too, so we may well
* have double reservations. * have double reservations.
*/ */
dev_info(&dev->dev, "%s range 0x%llx-0x%llx %s reserved\n", dev_info(&dev->dev, "%pR %s reserved\n", r,
port ? "ioport" : "iomem",
(unsigned long long) start, (unsigned long long) end,
res ? "has been" : "could not be"); res ? "has been" : "could not be");
} }
@ -77,14 +75,14 @@ static void reserve_resources_of_dev(struct pnp_dev *dev)
if (res->end < res->start) if (res->end < res->start)
continue; /* invalid */ continue; /* invalid */
reserve_range(dev, res->start, res->end, 1); reserve_range(dev, res, 1);
} }
for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) { for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
if (res->flags & IORESOURCE_DISABLED) if (res->flags & IORESOURCE_DISABLED)
continue; continue;
reserve_range(dev, res->start, res->end, 0); reserve_range(dev, res, 0);
} }
} }

View file

@ -25,7 +25,10 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
#include <xen/xen.h>
#include <xen/events.h> #include <xen/events.h>
#include <xen/page.h> #include <xen/page.h>
#include <xen/interface/io/fbif.h> #include <xen/interface/io/fbif.h>

View file

@ -52,6 +52,8 @@
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h> #include <asm/xen/hypercall.h>
#include <xen/xen.h>
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
#include <xen/interface/memory.h> #include <xen/interface/memory.h>
#include <xen/xenbus.h> #include <xen/xenbus.h>

View file

@ -1,5 +1,6 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <xen/xen.h>
#include <xen/xenbus.h> #include <xen/xenbus.h>
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>

View file

@ -48,6 +48,8 @@
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <xen/xen.h>
#include <xen/events.h> #include <xen/events.h>
#include <xen/evtchn.h> #include <xen/evtchn.h>
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>

View file

@ -37,6 +37,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <xen/xen.h>
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
#include <xen/page.h> #include <xen/page.h>
#include <xen/grant_table.h> #include <xen/grant_table.h>

View file

@ -14,6 +14,7 @@
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h> #include <asm/xen/hypercall.h>
#include <xen/xen.h>
#include <xen/xenbus.h> #include <xen/xenbus.h>
#include <xen/interface/xen.h> #include <xen/interface/xen.h>
#include <xen/interface/version.h> #include <xen/interface/version.h>

View file

@ -49,6 +49,8 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>
#include <xen/xen.h>
#include <xen/xenbus.h> #include <xen/xenbus.h>
#include <xen/events.h> #include <xen/events.h>
#include <xen/page.h> #include <xen/page.h>

View file

@ -13,6 +13,8 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <xen/xen.h>
#include "xenfs.h" #include "xenfs.h"
#include <asm/xen/hypervisor.h> #include <asm/xen/hypervisor.h>

12
include/acpi/acpi_hest.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef __ACPI_HEST_H
#define __ACPI_HEST_H
#include <linux/pci.h>
#ifdef CONFIG_ACPI
extern int acpi_hest_firmware_first_pci(struct pci_dev *pci);
#else
static inline int acpi_hest_firmware_first_pci(struct pci_dev *pci) { return 0; }
#endif
#endif

View file

@ -218,6 +218,7 @@ struct pci_dev {
unsigned int class; /* 3 bytes: (base,sub,prog-if) */ unsigned int class; /* 3 bytes: (base,sub,prog-if) */
u8 revision; /* PCI revision, low byte of class word */ u8 revision; /* PCI revision, low byte of class word */
u8 hdr_type; /* PCI header type (`multi' flag masked out) */ u8 hdr_type; /* PCI header type (`multi' flag masked out) */
u8 pcie_cap; /* PCI-E capability offset */
u8 pcie_type; /* PCI-E device/port type */ u8 pcie_type; /* PCI-E device/port type */
u8 rom_base_reg; /* which config register controls the ROM */ u8 rom_base_reg; /* which config register controls the ROM */
u8 pin; /* which interrupt pin this device uses */ u8 pin; /* which interrupt pin this device uses */
@ -280,6 +281,7 @@ struct pci_dev {
unsigned int is_virtfn:1; unsigned int is_virtfn:1;
unsigned int reset_fn:1; unsigned int reset_fn:1;
unsigned int is_hotplug_bridge:1; unsigned int is_hotplug_bridge:1;
unsigned int aer_firmware_first:1;
pci_dev_flags_t dev_flags; pci_dev_flags_t dev_flags;
atomic_t enable_cnt; /* pci_enable_device has been called */ atomic_t enable_cnt; /* pci_enable_device has been called */
@ -635,7 +637,13 @@ struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device,
unsigned int ss_vendor, unsigned int ss_device, unsigned int ss_vendor, unsigned int ss_device,
struct pci_dev *from); struct pci_dev *from);
struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn); struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn);
struct pci_dev *pci_get_bus_and_slot(unsigned int bus, unsigned int devfn); struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus,
unsigned int devfn);
static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus,
unsigned int devfn)
{
return pci_get_domain_bus_and_slot(0, bus, devfn);
}
struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from); struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from);
int pci_dev_present(const struct pci_device_id *ids); int pci_dev_present(const struct pci_device_id *ids);
@ -701,6 +709,7 @@ void pci_disable_device(struct pci_dev *dev);
void pci_set_master(struct pci_dev *dev); void pci_set_master(struct pci_dev *dev);
void pci_clear_master(struct pci_dev *dev); void pci_clear_master(struct pci_dev *dev);
int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state); int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
int pci_set_cacheline_size(struct pci_dev *dev);
#define HAVE_PCI_SET_MWI #define HAVE_PCI_SET_MWI
int __must_check pci_set_mwi(struct pci_dev *dev); int __must_check pci_set_mwi(struct pci_dev *dev);
int pci_try_set_mwi(struct pci_dev *dev); int pci_try_set_mwi(struct pci_dev *dev);
@ -1246,6 +1255,8 @@ extern int pci_pci_problems;
extern unsigned long pci_cardbus_io_size; extern unsigned long pci_cardbus_io_size;
extern unsigned long pci_cardbus_mem_size; extern unsigned long pci_cardbus_mem_size;
extern u8 pci_dfl_cache_line_size;
extern u8 pci_cache_line_size;
extern unsigned long pci_hotplug_io_size; extern unsigned long pci_hotplug_io_size;
extern unsigned long pci_hotplug_mem_size; extern unsigned long pci_hotplug_mem_size;
@ -1290,5 +1301,34 @@ extern void pci_hp_create_module_link(struct pci_slot *pci_slot);
extern void pci_hp_remove_module_link(struct pci_slot *pci_slot); extern void pci_hp_remove_module_link(struct pci_slot *pci_slot);
#endif #endif
/**
* pci_pcie_cap - get the saved PCIe capability offset
* @dev: PCI device
*
* PCIe capability offset is calculated at PCI device initialization
* time and saved in the data structure. This function returns saved
* PCIe capability offset. Using this instead of pci_find_capability()
* reduces unnecessary search in the PCI configuration space. If you
* need to calculate PCIe capability offset from raw device for some
* reasons, please use pci_find_capability() instead.
*/
static inline int pci_pcie_cap(struct pci_dev *dev)
{
return dev->pcie_cap;
}
/**
* pci_is_pcie - check if the PCI device is PCI Express capable
* @dev: PCI device
*
* Retrun true if the PCI device is PCI Express capable, false otherwise.
*/
static inline bool pci_is_pcie(struct pci_dev *dev)
{
return !!pci_pcie_cap(dev);
}
void pci_request_acs(void);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* LINUX_PCI_H */ #endif /* LINUX_PCI_H */

View file

@ -365,6 +365,11 @@
#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ #define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */
#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ #define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */
/* PCI Bridge Subsystem ID registers */
#define PCI_SSVID_VENDOR_ID 4 /* PCI-Bridge subsystem vendor id register */
#define PCI_SSVID_DEVICE_ID 6 /* PCI-Bridge subsystem device id register */
/* PCI Express capability registers */ /* PCI Express capability registers */
#define PCI_EXP_FLAGS 2 /* Capabilities register */ #define PCI_EXP_FLAGS 2 /* Capabilities register */
@ -502,6 +507,7 @@
#define PCI_EXT_CAP_ID_VC 2 #define PCI_EXT_CAP_ID_VC 2
#define PCI_EXT_CAP_ID_DSN 3 #define PCI_EXT_CAP_ID_DSN 3
#define PCI_EXT_CAP_ID_PWR 4 #define PCI_EXT_CAP_ID_PWR 4
#define PCI_EXT_CAP_ID_ACS 13
#define PCI_EXT_CAP_ID_ARI 14 #define PCI_EXT_CAP_ID_ARI 14
#define PCI_EXT_CAP_ID_ATS 15 #define PCI_EXT_CAP_ID_ATS 15
#define PCI_EXT_CAP_ID_SRIOV 16 #define PCI_EXT_CAP_ID_SRIOV 16
@ -662,4 +668,16 @@
#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ #define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */
#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ #define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */
/* Access Control Service */
#define PCI_ACS_CAP 0x04 /* ACS Capability Register */
#define PCI_ACS_SV 0x01 /* Source Validation */
#define PCI_ACS_TB 0x02 /* Translation Blocking */
#define PCI_ACS_RR 0x04 /* P2P Request Redirect */
#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */
#define PCI_ACS_UF 0x10 /* Upstream Forwarding */
#define PCI_ACS_EC 0x20 /* P2P Egress Control */
#define PCI_ACS_DT 0x40 /* Direct Translated P2P */
#define PCI_ACS_CTRL 0x06 /* ACS Control Register */
#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */
#endif /* LINUX_PCI_REGS_H */ #endif /* LINUX_PCI_REGS_H */

View file

@ -10,10 +10,7 @@
#define _PCIEPORT_IF_H_ #define _PCIEPORT_IF_H_
/* Port Type */ /* Port Type */
#define PCIE_RC_PORT 4 /* Root port of RC */ #define PCIE_ANY_PORT (~0)
#define PCIE_SW_UPSTREAM_PORT 5 /* Upstream port of Switch */
#define PCIE_SW_DOWNSTREAM_PORT 6 /* Downstream port of Switch */
#define PCIE_ANY_PORT 7
/* Service Type */ /* Service Type */
#define PCIE_PORT_SERVICE_PME_SHIFT 0 /* Power Management Event */ #define PCIE_PORT_SERVICE_PME_SHIFT 0 /* Power Management Event */
@ -25,17 +22,6 @@
#define PCIE_PORT_SERVICE_VC_SHIFT 3 /* Virtual Channel */ #define PCIE_PORT_SERVICE_VC_SHIFT 3 /* Virtual Channel */
#define PCIE_PORT_SERVICE_VC (1 << PCIE_PORT_SERVICE_VC_SHIFT) #define PCIE_PORT_SERVICE_VC (1 << PCIE_PORT_SERVICE_VC_SHIFT)
/* Root/Upstream/Downstream Port's Interrupt Mode */
#define PCIE_PORT_NO_IRQ (-1)
#define PCIE_PORT_INTx_MODE 0
#define PCIE_PORT_MSI_MODE 1
#define PCIE_PORT_MSIX_MODE 2
struct pcie_port_data {
int port_type; /* Type of the port */
int port_irq_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */
};
struct pcie_device { struct pcie_device {
int irq; /* Service IRQ/MSI/MSI-X Vector */ int irq; /* Service IRQ/MSI/MSI-X Vector */
struct pci_dev *port; /* Root/Upstream/Downstream Port */ struct pci_dev *port; /* Root/Upstream/Downstream Port */

32
include/xen/xen.h Normal file
View file

@ -0,0 +1,32 @@
#ifndef _XEN_XEN_H
#define _XEN_XEN_H
enum xen_domain_type {
XEN_NATIVE, /* running on bare hardware */
XEN_PV_DOMAIN, /* running in a PV domain */
XEN_HVM_DOMAIN, /* running in a Xen hvm domain */
};
#ifdef CONFIG_XEN
extern enum xen_domain_type xen_domain_type;
#else
#define xen_domain_type XEN_NATIVE
#endif
#define xen_domain() (xen_domain_type != XEN_NATIVE)
#define xen_pv_domain() (xen_domain() && \
xen_domain_type == XEN_PV_DOMAIN)
#define xen_hvm_domain() (xen_domain() && \
xen_domain_type == XEN_HVM_DOMAIN)
#ifdef CONFIG_XEN_DOM0
#include <xen/interface/xen.h>
#include <asm/xen/hypervisor.h>
#define xen_initial_domain() (xen_pv_domain() && \
xen_start_info->flags & SIF_INITDOMAIN)
#else /* !CONFIG_XEN_DOM0 */
#define xen_initial_domain() (0)
#endif /* CONFIG_XEN_DOM0 */
#endif /* _XEN_XEN_H */

View file

@ -308,35 +308,37 @@ static int find_resource(struct resource *root, struct resource *new,
void *alignf_data) void *alignf_data)
{ {
struct resource *this = root->child; struct resource *this = root->child;
resource_size_t start, end;
new->start = root->start; start = root->start;
/* /*
* Skip past an allocated resource that starts at 0, since the assignment * Skip past an allocated resource that starts at 0, since the assignment
* of this->start - 1 to new->end below would cause an underflow. * of this->start - 1 to new->end below would cause an underflow.
*/ */
if (this && this->start == 0) { if (this && this->start == 0) {
new->start = this->end + 1; start = this->end + 1;
this = this->sibling; this = this->sibling;
} }
for(;;) { for(;;) {
if (this) if (this)
new->end = this->start - 1; end = this->start - 1;
else else
new->end = root->end; end = root->end;
if (new->start < min) if (start < min)
new->start = min; start = min;
if (new->end > max) if (end > max)
new->end = max; end = max;
new->start = ALIGN(new->start, align); start = ALIGN(start, align);
if (alignf) if (alignf)
alignf(alignf_data, new, size, align); alignf(alignf_data, new, size, align);
if (new->start < new->end && new->end - new->start >= size - 1) { if (start < end && end - start >= size - 1) {
new->end = new->start + size - 1; new->start = start;
new->end = start + size - 1;
return 0; return 0;
} }
if (!this) if (!this)
break; break;
new->start = this->end + 1; start = this->end + 1;
this = this->sibling; this = this->sibling;
} }
return -EBUSY; return -EBUSY;

View file

@ -595,37 +595,89 @@ static char *symbol_string(char *buf, char *end, void *ptr,
} }
static char *resource_string(char *buf, char *end, struct resource *res, static char *resource_string(char *buf, char *end, struct resource *res,
struct printf_spec spec) struct printf_spec spec, const char *fmt)
{ {
#ifndef IO_RSRC_PRINTK_SIZE #ifndef IO_RSRC_PRINTK_SIZE
#define IO_RSRC_PRINTK_SIZE 4 #define IO_RSRC_PRINTK_SIZE 6
#endif #endif
#ifndef MEM_RSRC_PRINTK_SIZE #ifndef MEM_RSRC_PRINTK_SIZE
#define MEM_RSRC_PRINTK_SIZE 8 #define MEM_RSRC_PRINTK_SIZE 10
#endif #endif
struct printf_spec num_spec = { struct printf_spec hex_spec = {
.base = 16, .base = 16,
.precision = -1, .precision = -1,
.flags = SPECIAL | SMALL | ZEROPAD, .flags = SPECIAL | SMALL | ZEROPAD,
}; };
/* room for the actual numbers, the two "0x", -, [, ] and the final zero */ struct printf_spec dec_spec = {
char sym[4*sizeof(resource_size_t) + 8]; .base = 10,
char *p = sym, *pend = sym + sizeof(sym); .precision = -1,
int size = -1; .flags = 0,
};
struct printf_spec str_spec = {
.field_width = -1,
.precision = 10,
.flags = LEFT,
};
struct printf_spec flag_spec = {
.base = 16,
.precision = -1,
.flags = SPECIAL | SMALL,
};
if (res->flags & IORESOURCE_IO) /* 32-bit res (sizeof==4): 10 chars in dec, 10 in hex ("0x" + 8)
* 64-bit res (sizeof==8): 20 chars in dec, 18 in hex ("0x" + 16) */
#define RSRC_BUF_SIZE ((2 * sizeof(resource_size_t)) + 4)
#define FLAG_BUF_SIZE (2 * sizeof(res->flags))
#define DECODED_BUF_SIZE sizeof("[mem - 64bit pref disabled]")
#define RAW_BUF_SIZE sizeof("[mem - flags 0x]")
char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE,
2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)];
char *p = sym, *pend = sym + sizeof(sym);
int size = -1, addr = 0;
int decode = (fmt[0] == 'R') ? 1 : 0;
if (res->flags & IORESOURCE_IO) {
size = IO_RSRC_PRINTK_SIZE; size = IO_RSRC_PRINTK_SIZE;
else if (res->flags & IORESOURCE_MEM) addr = 1;
} else if (res->flags & IORESOURCE_MEM) {
size = MEM_RSRC_PRINTK_SIZE; size = MEM_RSRC_PRINTK_SIZE;
addr = 1;
}
*p++ = '['; *p++ = '[';
num_spec.field_width = size; if (res->flags & IORESOURCE_IO)
p = number(p, pend, res->start, num_spec); p = string(p, pend, "io ", str_spec);
else if (res->flags & IORESOURCE_MEM)
p = string(p, pend, "mem ", str_spec);
else if (res->flags & IORESOURCE_IRQ)
p = string(p, pend, "irq ", str_spec);
else if (res->flags & IORESOURCE_DMA)
p = string(p, pend, "dma ", str_spec);
else {
p = string(p, pend, "??? ", str_spec);
decode = 0;
}
hex_spec.field_width = size;
p = number(p, pend, res->start, addr ? hex_spec : dec_spec);
if (res->start != res->end) {
*p++ = '-'; *p++ = '-';
p = number(p, pend, res->end, num_spec); p = number(p, pend, res->end, addr ? hex_spec : dec_spec);
}
if (decode) {
if (res->flags & IORESOURCE_MEM_64)
p = string(p, pend, " 64bit", str_spec);
if (res->flags & IORESOURCE_PREFETCH)
p = string(p, pend, " pref", str_spec);
if (res->flags & IORESOURCE_DISABLED)
p = string(p, pend, " disabled", str_spec);
} else {
p = string(p, pend, " flags ", str_spec);
p = number(p, pend, res->flags, flag_spec);
}
*p++ = ']'; *p++ = ']';
*p = 0; *p = '\0';
return string(buf, end, sym, spec); return string(buf, end, sym, spec);
} }
@ -801,8 +853,8 @@ static char *ip4_addr_string(char *buf, char *end, const u8 *addr,
* - 'f' For simple symbolic function names without offset * - 'f' For simple symbolic function names without offset
* - 'S' For symbolic direct pointers with offset * - 'S' For symbolic direct pointers with offset
* - 's' For symbolic direct pointers without offset * - 's' For symbolic direct pointers without offset
* - 'R' For a struct resource pointer, it prints the range of * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
* addresses (not the name nor the flags) * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
* - 'M' For a 6-byte MAC address, it prints the address in the * - 'M' For a 6-byte MAC address, it prints the address in the
* usual colon-separated hex notation * usual colon-separated hex notation
* - 'm' For a 6-byte MAC address, it prints the hex address without colons * - 'm' For a 6-byte MAC address, it prints the hex address without colons
@ -833,7 +885,8 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
case 'S': case 'S':
return symbol_string(buf, end, ptr, spec, *fmt); return symbol_string(buf, end, ptr, spec, *fmt);
case 'R': case 'R':
return resource_string(buf, end, ptr, spec); case 'r':
return resource_string(buf, end, ptr, spec, fmt);
case 'M': /* Colon separated: 00:01:02:03:04:05 */ case 'M': /* Colon separated: 00:01:02:03:04:05 */
case 'm': /* Contiguous: 000102030405 */ case 'm': /* Contiguous: 000102030405 */
return mac_address_string(buf, end, ptr, spec, fmt); return mac_address_string(buf, end, ptr, spec, fmt);