Re: [PATCH 02/11] PCI: Try to allocate mem64 above 4G at first

Yinghai Lu
2012-06-01T23:30:54Z

[-- Attachment #1: Type: text/plain, Size: 366 bytes --]

On Tue, May 29, 2012 at 1:50 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>
> The bus-side address space should not be more than 32 bits no matter
> what.  As Bjorn indicates, you seem to be mixing up bus and cpu
> addresses all over the place.

please check update patches that is using converted pci bus address
for boundary checking.

Thanks

Yinghai Lu

[-- Attachment #2: pcibus_addr_converting_bus.patch --]
[-- Type: application/octet-stream, Size: 4469 bytes --]

Subject: [PATCH] PCI: pcibus address to resource converting take bus directly

For allocating resource under bus path, we do have dev pass along, and we
could just use bus instead.

Also add helper: pcibios_bus_addr_to_res to convert address only.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>

---
drivers/pci/host-bridge.c | 48 +++++++++++++++++++++++++++++++++-------------
include/linux/pci.h | 5 ++++
2 files changed, 40 insertions(+), 13 deletions(-)

Index: linux-2.6/drivers/pci/host-bridge.c
===================================================================
--- linux-2.6.orig/drivers/pci/host-bridge.c
+++ linux-2.6/drivers/pci/host-bridge.c
@@ -9,22 +9,19 @@

#include "pci.h"

-static struct pci_bus *find_pci_root_bus(struct pci_dev *dev)
+static struct pci_bus *find_pci_root_bus(struct pci_bus *bus)
{
- struct pci_bus *bus;
-
- bus = dev->bus;
while (bus->parent)
bus = bus->parent;

return bus;
}

-static struct pci_host_bridge *find_pci_host_bridge(struct pci_dev *dev)
+static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
{
- struct pci_bus *bus = find_pci_root_bus(dev);
+ struct pci_bus *root_bus = find_pci_root_bus(bus);

- return to_pci_host_bridge(bus->bridge);
+ return to_pci_host_bridge(root_bus->bridge);
}

void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
@@ -40,10 +37,11 @@ static bool resource_contains(struct res
return res1->start <= res2->start && res1->end >= res2->end;
}

-void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
- struct resource *res)
+void __pcibios_resource_to_bus(struct pci_bus *bus,
+ struct pci_bus_region *region,
+ struct resource *res)
{
- struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
+ struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
struct pci_host_bridge_window *window;
resource_size_t offset = 0;

@@ -60,6 +58,11 @@ void pcibios_resource_to_bus(struct pci_
region->start = res->start - offset;
region->end = res->end - offset;
}
+void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
+ struct resource *res)
+{
+ __pcibios_resource_to_bus(dev->bus, region, res);
+}
EXPORT_SYMBOL(pcibios_resource_to_bus);

static bool region_contains(struct pci_bus_region *region1,
@@ -68,10 +71,10 @@ static bool region_contains(struct pci_b
return region1->start <= region2->start && region1->end >= region2->end;
}

-void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
- struct pci_bus_region *region)
+static void __pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
+ struct pci_bus_region *region)
{
- struct pci_host_bridge *bridge = find_pci_host_bridge(dev);
+ struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
struct pci_host_bridge_window *window;
resource_size_t offset = 0;

@@ -93,4 +96,23 @@ void pcibios_bus_to_resource(struct pci_
res->start = region->start + offset;
res->end = region->end + offset;
}
+void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
+ struct pci_bus_region *region)
+{
+ __pcibios_bus_to_resource(dev->bus, res, region);
+}
EXPORT_SYMBOL(pcibios_bus_to_resource);
+
+resource_size_t pcibios_bus_addr_to_res(struct pci_bus *bus, int flags,
+ resource_size_t addr)
+{
+ struct pci_bus_region region;
+ struct resource r;
+
+ r.flags = flags;
+ region.start = addr;
+ region.end = addr;
+ __pcibios_bus_to_resource(bus, &r, &region);
+
+ return r.end;
+}
Index: linux-2.6/include/linux/pci.h
===================================================================
--- linux-2.6.orig/include/linux/pci.h
+++ linux-2.6/include/linux/pci.h
@@ -653,10 +653,15 @@ void pcibios_update_irq(struct pci_dev *

/* Generic PCI functions used internally */

+void __pcibios_resource_to_bus(struct pci_bus *bus,
+ struct pci_bus_region *region,
+ struct resource *res);
void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res);
void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
struct pci_bus_region *region);
+resource_size_t pcibios_bus_addr_to_res(struct pci_bus *bus, int flags,
+ resource_size_t addr);
void pcibios_scan_specific_bus(int busn);
extern struct pci_bus *pci_find_bus(int domain, int busnr);
void pci_bus_add_devices(const struct pci_bus *bus);

[-- Attachment #3: allocate_high_at_first_v6.patch --]
[-- Type: application/octet-stream, Size: 4274 bytes --]

Subject: [PATCH] PCI: Try to allocate mem64 above 4G at first

and will fall back to below 4g if it can not find any above 4g.

x86 32bit without X86_PAE support will have bottom set to 0, becuase
resource_size_t is 32bit.

Also for 32bit with resource_size_t 64bit kernel on machine with pae support
we are safe because iomem_resource is limited to 32bit according to
x86_phys_bits.

-v2: update bottom assigning to make it clear for non-pae support machine.
-v3: Bjorn's change:
use MAX_REOURCE instead of -1
use start/end instead of bottom/max
for all arch instead of just x86_64
-v4: updated after PCI_MAX_RESOURCE_32 change.
-v5: restore io handling to use PCI_MAX_RESOURCE_32 as limit.
-v6: checking pcibios_resource_to_bus return for every bus res, to decide it
if we need to try high at first.
It support all arches instead of just x86_64.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>

---
arch/x86/include/asm/pci.h | 1 -
drivers/pci/bus.c | 42 ++++++++++++++++++++++++++++++++++--------
drivers/pci/pci.h | 2 ++
include/linux/pci.h | 4 ----
4 files changed, 36 insertions(+), 13 deletions(-)

Index: linux-2.6/arch/x86/include/asm/pci.h
===================================================================
--- linux-2.6.orig/arch/x86/include/asm/pci.h
+++ linux-2.6/arch/x86/include/asm/pci.h
@@ -149,7 +149,6 @@ void default_restore_msi_irqs(struct pci

/* generic pci stuff */
#include <asm-generic/pci.h>
-#define PCIBIOS_MAX_MEM_32 0xffffffff

#ifdef CONFIG_NUMA
/* Returns the node based on pci bus */
Index: linux-2.6/drivers/pci/bus.c
===================================================================
--- linux-2.6.orig/drivers/pci/bus.c
+++ linux-2.6/drivers/pci/bus.c
@@ -121,15 +121,13 @@ pci_bus_alloc_resource(struct pci_bus *b
{
int i, ret = -ENOMEM;
struct resource *r;
- resource_size_t max = -1;

type_mask |= IORESOURCE_IO | IORESOURCE_MEM;

- /* don't allocate too high if the pref mem doesn't support 64bit*/
- if (!(res->flags & IORESOURCE_MEM_64))
- max = PCIBIOS_MAX_MEM_32;
-
pci_bus_for_each_resource(bus, r, i) {
+ resource_size_t start, end, middle;
+ struct pci_bus_region region;
+
if (!r)
continue;

@@ -143,14 +141,42 @@ pci_bus_alloc_resource(struct pci_bus *b
!(res->flags & IORESOURCE_PREFETCH))
continue;

+ /*
+ * don't allocate too high if the pref mem doesn't
+ * support 64bit, also if this is a 64-bit mem
+ * resource, try above 4GB first
+ */
+ __pcibios_resource_to_bus(bus, &region, r);
+ start = 0;
+ end = MAX_RESOURCE;
+ if (region.start <= PCI_MAX_ADDR_32 &&
+ region.end > PCI_MAX_ADDR_32) {
+ middle = pcibios_bus_addr_to_res(bus, res->flags,
+ PCI_MAX_ADDR_32);
+ if (res->flags & IORESOURCE_MEM_64)
+ start = middle + 1;
+ else
+ end = middle;
+ } else if (region.start > PCI_MAX_ADDR_32 &&
+ !(res->flags & IORESOURCE_MEM_64))
+ continue;
+
+again:
/* Ok, try it out.. */
ret = allocate_resource(r, res, size,
- r->start ? : min,
- max, align,
+ max(start, r->start ? : min),
+ end, align,
alignf, alignf_data);
if (ret == 0)
- break;
+ return 0;
+
+ if (start != 0) {
+ start = 0;
+ goto again;
+ }
}
+
+
return ret;
}

Index: linux-2.6/drivers/pci/pci.h
===================================================================
--- linux-2.6.orig/drivers/pci/pci.h
+++ linux-2.6/drivers/pci/pci.h
@@ -208,6 +208,8 @@ enum pci_bar_type {
pci_bar_mem64, /* A 64-bit memory BAR */
};

+#define PCI_MAX_ADDR_32 ((resource_size_t)0xffffffff)
+
bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl,
int crs_timeout);
extern int pci_setup_device(struct pci_dev *dev);
Index: linux-2.6/include/linux/pci.h
===================================================================
--- linux-2.6.orig/include/linux/pci.h
+++ linux-2.6/include/linux/pci.h
@@ -1345,10 +1345,6 @@ static inline int pci_domain_nr(struct p

#include <asm/pci.h>

-#ifndef PCIBIOS_MAX_MEM_32
-#define PCIBIOS_MAX_MEM_32 (-1)
-#endif
-
/* these helpers provide future and backwards compatibility
* for accessing popular PCI BAR info */
#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)