Skip to content

Commit

Permalink
Merge branch 'topic/jiang-mmconfig-v10' into next
Browse files Browse the repository at this point in the history
* topic/jiang-mmconfig-v10:
  ACPI: mark acpi_sfi_table_parse() as __init
  x86/PCI: use pr_level() to replace printk(KERN_LEVEL)
  x86/PCI: refine __pci_mmcfg_init() for better code readability
  x86/PCI: get rid of redundant log messages
  x86/PCI: simplify pci_mmcfg_late_insert_resources()
  x86/PCI: update MMCONFIG information when hot-plugging PCI host bridges
  PCI/ACPI: provide MMCONFIG address for PCI host bridges
  x86/PCI: add pci_mmconfig_insert()/delete() for PCI root bridge hotplug
  x86/PCI: prepare pci_mmcfg_check_reserved() to be called at runtime
  x86/PCI: introduce pci_mmcfg_arch_map()/pci_mmcfg_arch_unmap()
  x86/PCI: use RCU list to protect mmconfig list
  x86/PCI: split out pci_mmconfig_alloc() for code reuse
  x86/PCI: split out pci_mmcfg_check_reserved() for code reuse
  • Loading branch information
Bjorn Helgaas committed Jun 22, 2012
2 parents 0f6662a + 3970385 commit e5028b5
Show file tree
Hide file tree
Showing 11 changed files with 430 additions and 154 deletions.
7 changes: 7 additions & 0 deletions arch/x86/include/asm/pci_x86.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ struct pci_raw_ops {
extern const struct pci_raw_ops *raw_pci_ops;
extern const struct pci_raw_ops *raw_pci_ext_ops;

extern const struct pci_raw_ops pci_mmcfg;
extern const struct pci_raw_ops pci_direct_conf1;
extern bool port_cf9_safe;

Expand Down Expand Up @@ -135,6 +136,12 @@ struct pci_mmcfg_region {

extern int __init pci_mmcfg_arch_init(void);
extern void __init pci_mmcfg_arch_free(void);
extern int __devinit pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg);
extern void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg);
extern int __devinit pci_mmconfig_insert(struct device *dev,
u16 seg, u8 start,
u8 end, phys_addr_t addr);
extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);

extern struct list_head pci_mmcfg_list;
Expand Down
100 changes: 90 additions & 10 deletions arch/x86/pci/acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ struct pci_root_info {
unsigned int res_num;
struct resource *res;
struct pci_sysdata sd;
#ifdef CONFIG_PCI_MMCONFIG
bool mcfg_added;
u16 segment;
u8 start_bus;
u8 end_bus;
#endif
};

static bool pci_use_crs = true;
Expand Down Expand Up @@ -119,6 +125,81 @@ void __init pci_acpi_crs_quirks(void)
pci_use_crs ? "nocrs" : "use_crs");
}

#ifdef CONFIG_PCI_MMCONFIG
static int __devinit check_segment(u16 seg, struct device *dev, char *estr)
{
if (seg) {
dev_err(dev,
"%s can't access PCI configuration "
"space under this host bridge.\n",
estr);
return -EIO;
}

/*
* Failure in adding MMCFG information is not fatal,
* just can't access extended configuration space of
* devices under this host bridge.
*/
dev_warn(dev,
"%s can't access extended PCI configuration "
"space under this bridge.\n",
estr);

return 0;
}

static int __devinit setup_mcfg_map(struct pci_root_info *info,
u16 seg, u8 start, u8 end,
phys_addr_t addr)
{
int result;
struct device *dev = &info->bridge->dev;

info->start_bus = start;
info->end_bus = end;
info->mcfg_added = false;

/* return success if MMCFG is not in use */
if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg)
return 0;

if (!(pci_probe & PCI_PROBE_MMCONF))
return check_segment(seg, dev, "MMCONFIG is disabled,");

result = pci_mmconfig_insert(dev, seg, start, end, addr);
if (result == 0) {
/* enable MMCFG if it hasn't been enabled yet */
if (raw_pci_ext_ops == NULL)
raw_pci_ext_ops = &pci_mmcfg;
info->mcfg_added = true;
} else if (result != -EEXIST)
return check_segment(seg, dev,
"fail to add MMCONFIG information,");

return 0;
}

static void teardown_mcfg_map(struct pci_root_info *info)
{
if (info->mcfg_added) {
pci_mmconfig_delete(info->segment, info->start_bus,
info->end_bus);
info->mcfg_added = false;
}
}
#else
static int __devinit setup_mcfg_map(struct pci_root_info *info,
u16 seg, u8 start, u8 end,
phys_addr_t addr)
{
return 0;
}
static void teardown_mcfg_map(struct pci_root_info *info)
{
}
#endif

static acpi_status
resource_to_addr(struct acpi_resource *resource,
struct acpi_resource_address64 *addr)
Expand Down Expand Up @@ -233,13 +314,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
}

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;
}
Expand Down Expand Up @@ -331,8 +405,11 @@ static void __release_pci_root_info(struct pci_root_info *info)

free_pci_root_info_res(info);

teardown_mcfg_map(info);

kfree(info);
}

static void release_pci_root_info(struct pci_host_bridge *bridge)
{
struct pci_root_info *info = bridge->release_data;
Expand Down Expand Up @@ -372,7 +449,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
int domain = root->segment;
int busnum = root->secondary.start;
LIST_HEAD(resources);
struct pci_bus *bus;
struct pci_bus *bus = NULL;
struct pci_sysdata *sd;
int node;
#ifdef CONFIG_ACPI_NUMA
Expand Down Expand Up @@ -438,8 +515,11 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)
x86_pci_root_bus_resources(busnum, &resources);
}

bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd,
&resources);
if (!setup_mcfg_map(info, domain, (u8)root->secondary.start,
(u8)root->secondary.end, root->mcfg_addr))
bus = pci_create_root_bus(NULL, busnum, &pci_root_ops,
sd, &resources);

if (bus) {
pci_scan_child_bus(bus);
pci_set_host_bridge_release(
Expand Down
Loading

0 comments on commit e5028b5

Please sign in to comment.