mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 19:26:25 +00:00
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:
commit
11bd04f6f3
83 changed files with 1794 additions and 1571 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
101
arch/x86/pci/bus_numa.c
Normal 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
27
arch/x86/pci/bus_numa.h
Normal 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
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, ®);
|
dev->rom_base_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
90
arch/x86/pci/intel_bus.c
Normal 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);
|
|
@ -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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
135
drivers/acpi/hest.c
Normal 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);
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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, ®);
|
|
||||||
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, ®);
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
127
drivers/pci/ioapic.c
Normal 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);
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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, ®16);
|
pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, ®16);
|
||||||
pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
|
pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
|
||||||
|
|
||||||
|
|
|
@ -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, ®16);
|
pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, ®16);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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, ®16);
|
pci_read_config_word(child, pos + PCI_EXP_LNKCTL, ®16);
|
||||||
|
@ -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, ®32);
|
pci_read_config_dword(child, pos + PCI_EXP_LNKCAP, ®32);
|
||||||
|
@ -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, ®16);
|
pci_read_config_word(child, cpos + PCI_EXP_LNKSTA, ®16);
|
||||||
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, ®16);
|
pci_read_config_word(parent, ppos + PCI_EXP_LNKSTA, ®16);
|
||||||
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, ®16);
|
pci_read_config_word(child, cpos + PCI_EXP_LNKCTL, ®16);
|
||||||
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, ®32);
|
pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32);
|
||||||
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, ®32);
|
pci_read_config_dword(child, pos + PCI_EXP_DEVCAP, ®32);
|
||||||
/* 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, ®16);
|
pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16);
|
||||||
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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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, ®16);
|
pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16);
|
||||||
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, ®16);
|
pci_read_config_word(dev, pos + PCI_EXP_FLAGS, ®16);
|
||||||
/* 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, ®32);
|
||||||
pos + PCIE_SLOT_CAPABILITIES_REG, ®32);
|
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, ®);
|
|
||||||
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, ®16);
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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; "
|
||||||
|
|
|
@ -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, ®16);
|
pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16);
|
||||||
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, ®16);
|
pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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, ®ion, bus->resource[0]);
|
res = bus->resource[0];
|
||||||
if (bus->resource[0]->flags & IORESOURCE_IO) {
|
pcibios_resource_to_bus(bridge, ®ion, 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, ®ion, bus->resource[1]);
|
res = bus->resource[1];
|
||||||
if (bus->resource[1]->flags & IORESOURCE_IO) {
|
pcibios_resource_to_bus(bridge, ®ion, 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, ®ion, bus->resource[2]);
|
res = bus->resource[2];
|
||||||
if (bus->resource[2]->flags & IORESOURCE_MEM) {
|
pcibios_resource_to_bus(bridge, ®ion, 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, ®ion, bus->resource[3]);
|
res = bus->resource[3];
|
||||||
if (bus->resource[3]->flags & IORESOURCE_MEM) {
|
pcibios_resource_to_bus(bridge, ®ion, 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, ®ion, bus->resource[0]);
|
res = bus->resource[0];
|
||||||
if (bus->resource[0]->flags & IORESOURCE_IO) {
|
pcibios_resource_to_bus(bridge, ®ion, 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, ®ion, bus->resource[1]);
|
res = bus->resource[1];
|
||||||
if (bus->resource[1]->flags & IORESOURCE_MEM) {
|
pcibios_resource_to_bus(bridge, ®ion, 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, ®ion, bus->resource[2]);
|
res = bus->resource[2];
|
||||||
if (bus->resource[2]->flags & IORESOURCE_PREFETCH) {
|
pcibios_resource_to_bus(bridge, ®ion, 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,12 +51,6 @@ void pci_update_resource(struct pci_dev *dev, int resno)
|
||||||
|
|
||||||
pcibios_resource_to_bus(dev, ®ion, res);
|
pcibios_resource_to_bus(dev, ®ion, 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
12
include/acpi/acpi_hest.h
Normal 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
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
32
include/xen/xen.h
Normal 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 */
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue