From b1a98b695b4efe10067d0e1cb5b66146a4e517bf Mon Sep 17 00:00:00 2001 From: Tiejun Chen Date: Thu, 2 Jun 2011 11:02:50 +0800 Subject: PCI: enumerate the PCI device only removed out PCI hieratchy of OS when re-scanning PCI When hot-plugging a root bridge, we always prevent assigning a bus number that already exists. This makes sure we don't step over an existing bus. But sometimes we only remove PCI device in PCI hieratchy of OS, i,e. echo 1 > /sys/bus/pci/devices/.../remove but actually don't hotplug this device out the platform, so in this case we still should re-scan this bus to enumerate this device when re-scanning PCI again. Signed-off-by: Tiejun Chen Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index bafb3c3d4a89..f03ed96533d5 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -724,12 +724,14 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, pci_write_config_word(dev, PCI_STATUS, 0xffff); /* Prevent assigning a bus number that already exists. - * This can happen when a bridge is hot-plugged */ - if (pci_find_bus(pci_domain_nr(bus), max+1)) - goto out; - child = pci_add_new_bus(bus, dev, ++max); - if (!child) - goto out; + * This can happen when a bridge is hot-plugged, so in + * this case we only re-scan this bus. */ + child = pci_find_bus(pci_domain_nr(bus), max+1); + if (!child) { + child = pci_add_new_bus(bus, dev, ++max); + if (!child) + goto out; + } buses = (buses & 0xff000000) | ((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) -- cgit v1.2.1 From 8d6a6a47636648754dc371b01228520a2adaf430 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 14 Jun 2011 13:04:29 -0600 Subject: PCI: treat mem BAR type "11" (reserved) as 32-bit, not 64-bit, BAR This fixes a minor regression where broken PCI devices that use the reserved "11" memory BAR type worked before e354597cce but not after. The low four bits of a memory BAR are "PTT0" where P=1 for prefetchable BARs, and TT is as follows: 00 32-bit BAR, anywhere in lower 4GB 01 anywhere below 1MB (reserved as of PCI 2.2) 10 64-bit BAR 11 reserved Prior to e354597cce, we treated "0100" as a 64-bit BAR and all others, including prefetchable 64-bit BARs ("1100") as 32-bit BARs. The e354597cce fix, which appeared in 2.6.28, treats "x1x0" as 64-bit BARs, so the reserved "x110" types are treated as 64-bit instead of 32-bit. This patch returns to treating the reserved "11" type as a 32-bit BAR and adds a warning if we see it. It also logs a note if we see a 1M BAR. This is not a warning, because such hardware conforms to pre-PCI 2.2 spec, but I think it's worth noting because Linux ignores the 1M restriction if it ever has to assign the BAR. CC: Peter Chubb Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=35952 Reported-by: Jan Zwiegers Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f03ed96533d5..3e7a00a3fc81 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -100,8 +100,11 @@ static u64 pci_size(u64 base, u64 maxbase, u64 mask) return size; } -static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar) +static inline enum pci_bar_type decode_bar(struct pci_dev *dev, + struct resource *res, u32 bar) { + u32 mem_type; + if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK; return pci_bar_io; @@ -109,8 +112,21 @@ static inline enum pci_bar_type decode_bar(struct resource *res, u32 bar) res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK; - if (res->flags & PCI_BASE_ADDRESS_MEM_TYPE_64) + mem_type = bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK; + switch (mem_type) { + case PCI_BASE_ADDRESS_MEM_TYPE_32: + break; + case PCI_BASE_ADDRESS_MEM_TYPE_1M: + dev_info(&dev->dev, "1M mem BAR treated as 32-bit BAR\n"); + break; + case PCI_BASE_ADDRESS_MEM_TYPE_64: return pci_bar_mem64; + default: + dev_warn(&dev->dev, + "mem unknown type %x treated as 32-bit BAR\n", + mem_type); + break; + } return pci_bar_mem32; } @@ -164,7 +180,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, l = 0; if (type == pci_bar_unknown) { - type = decode_bar(res, l); + type = decode_bar(dev, res, l); res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; if (type == pci_bar_io) { l &= PCI_BASE_ADDRESS_IO_MASK; -- cgit v1.2.1 From 28c6821a0f8e686d4f1a6107d970705d37475d87 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 14 Jun 2011 13:04:35 -0600 Subject: PCI: fold pci_calc_resource_flags() into decode_bar() decode_bar() and pci_calc_resource_flags() both looked at the PCI BAR type information, and it's simpler to just do it all in one place. decode_bar() sets IORESOURCE_IO, IORESOURCE_MEM, and IORESOURCE_MEM_64 as appropriate, so res->flags contains all the information pci_bar_type does, so we don't need to test the pci_bar_type return value. decode_bar() used to return pci_bar_type, which we no longer need. We can simplify it a bit by returning the struct resource flags rather than updating them internally. In pci_update_resource(), there's no need to decode the BAR type bits again; we can just test for IORESOURCE_MEM_64 directly. Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 45 +++++++++++++++++---------------------------- 1 file changed, 17 insertions(+), 28 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 3e7a00a3fc81..ef17cf99830e 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -67,21 +67,6 @@ static int __init pcibus_class_init(void) } postcore_initcall(pcibus_class_init); -/* - * Translate the low bits of the PCI base - * to the resource type - */ -static inline unsigned int pci_calc_resource_flags(unsigned int flags) -{ - if (flags & PCI_BASE_ADDRESS_SPACE_IO) - return IORESOURCE_IO; - - if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) - return IORESOURCE_MEM | IORESOURCE_PREFETCH; - - return IORESOURCE_MEM; -} - static u64 pci_size(u64 base, u64 maxbase, u64 mask) { u64 size = mask & maxbase; /* Find the significant bits */ @@ -100,17 +85,21 @@ static u64 pci_size(u64 base, u64 maxbase, u64 mask) return size; } -static inline enum pci_bar_type decode_bar(struct pci_dev *dev, - struct resource *res, u32 bar) +static inline unsigned long decode_bar(struct pci_dev *dev, u32 bar) { u32 mem_type; + unsigned long flags; if ((bar & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { - res->flags = bar & ~PCI_BASE_ADDRESS_IO_MASK; - return pci_bar_io; + flags = bar & ~PCI_BASE_ADDRESS_IO_MASK; + flags |= IORESOURCE_IO; + return flags; } - res->flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK; + flags = bar & ~PCI_BASE_ADDRESS_MEM_MASK; + flags |= IORESOURCE_MEM; + if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH) + flags |= IORESOURCE_PREFETCH; mem_type = bar & PCI_BASE_ADDRESS_MEM_TYPE_MASK; switch (mem_type) { @@ -120,14 +109,15 @@ static inline enum pci_bar_type decode_bar(struct pci_dev *dev, dev_info(&dev->dev, "1M mem BAR treated as 32-bit BAR\n"); break; case PCI_BASE_ADDRESS_MEM_TYPE_64: - return pci_bar_mem64; + flags |= IORESOURCE_MEM_64; + break; default: dev_warn(&dev->dev, "mem unknown type %x treated as 32-bit BAR\n", mem_type); break; } - return pci_bar_mem32; + return flags; } /** @@ -180,9 +170,9 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, l = 0; if (type == pci_bar_unknown) { - type = decode_bar(dev, res, l); - res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN; - if (type == pci_bar_io) { + res->flags = decode_bar(dev, l); + res->flags |= IORESOURCE_SIZEALIGN; + if (res->flags & IORESOURCE_IO) { l &= PCI_BASE_ADDRESS_IO_MASK; mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT; } else { @@ -195,7 +185,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, mask = (u32)PCI_ROM_ADDRESS_MASK; } - if (type == pci_bar_mem64) { + if (res->flags & IORESOURCE_MEM_64) { u64 l64 = l; u64 sz64 = sz; u64 mask64 = mask | (u64)~0 << 32; @@ -219,7 +209,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, goto fail; } - res->flags |= IORESOURCE_MEM_64; if ((sizeof(resource_size_t) < 8) && l) { /* Address above 32-bit boundary; disable the BAR */ pci_write_config_dword(dev, pos, 0); @@ -245,7 +234,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, } out: - return (type == pci_bar_mem64) ? 1 : 0; + return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; fail: res->flags = 0; goto out; -- cgit v1.2.1 From 7b87c9df5602efd6c7edeb291bbd104d49a6babf Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 14 Jun 2011 13:04:40 -0600 Subject: PCI: remove printks about disabled bridge windows I don't think there's enough value in the fact of a bridge window being disabled to justify cluttering the dmesg log with it. Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- drivers/pci/probe.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers/pci/probe.c') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ef17cf99830e..fd6066dfde5c 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -288,10 +288,6 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child) if (!res->end) res->end = limit + 0xfff; dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); - } else { - dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [io %#06lx-%#06lx] (disabled)\n", - base, limit); } } @@ -312,10 +308,6 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child) res->start = base; res->end = limit + 0xfffff; dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); - } else { - dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [mem %#010lx-%#010lx] (disabled)\n", - base, limit + 0xfffff); } } @@ -363,10 +355,6 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child) res->start = base; res->end = limit + 0xfffff; dev_printk(KERN_DEBUG, &dev->dev, " bridge window %pR\n", res); - } else { - dev_printk(KERN_DEBUG, &dev->dev, - " bridge window [mem %#010lx-%#010lx pref] (disabled)\n", - base, limit + 0xfffff); } } -- cgit v1.2.1