瀏覽代碼

[POWERPC] Fix powerpc 32-bit resource fixup for 64-bit resources

The 32-bit powerpc resource fixup code uses unsigned longs to do the
offsetting of resources which overflows on platforms such as 4xx where
resources can be 64 bits.

This fixes it by using resource_size_t instead.

However, the IO stuff does rely on some 32 bits arithmetic, so we hack
by cropping the result of the fixups for IO resources with a 32 bits
mask.

This isn't the prettiest but should work for now until we change the
32 bits PCI code to do IO mappings like 64 bits does, within a reserved
are of the kernel address space.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Benjamin Herrenschmidt 17 年之前
父節點
當前提交
05d3957e11
共有 1 個文件被更改,包括 26 次插入20 次删除
  1. 26 20
      arch/powerpc/kernel/pci_32.c

+ 26 - 20
arch/powerpc/kernel/pci_32.c

@@ -104,7 +104,7 @@ pcibios_fixup_resources(struct pci_dev *dev)
 {
 {
 	struct pci_controller* hose = (struct pci_controller *)dev->sysdata;
 	struct pci_controller* hose = (struct pci_controller *)dev->sysdata;
 	int i;
 	int i;
-	unsigned long offset;
+	resource_size_t offset, mask;
 
 
 	if (!hose) {
 	if (!hose) {
 		printk(KERN_ERR "No hose for PCI dev %s!\n", pci_name(dev));
 		printk(KERN_ERR "No hose for PCI dev %s!\n", pci_name(dev));
@@ -123,15 +123,17 @@ pcibios_fixup_resources(struct pci_dev *dev)
 			continue;
 			continue;
 		}
 		}
 		offset = 0;
 		offset = 0;
+		mask = (resource_size_t)-1;
 		if (res->flags & IORESOURCE_MEM) {
 		if (res->flags & IORESOURCE_MEM) {
 			offset = hose->pci_mem_offset;
 			offset = hose->pci_mem_offset;
 		} else if (res->flags & IORESOURCE_IO) {
 		} else if (res->flags & IORESOURCE_IO) {
 			offset = (unsigned long) hose->io_base_virt
 			offset = (unsigned long) hose->io_base_virt
 				- isa_io_base;
 				- isa_io_base;
+			mask = 0xffffffffu;
 		}
 		}
 		if (offset != 0) {
 		if (offset != 0) {
-			res->start += offset;
-			res->end += offset;
+			res->start = (res->start + offset) & mask;
+			res->end = (res->end + offset) & mask;
 			DBG("Fixup res %d (%lx) of dev %s: %llx -> %llx\n",
 			DBG("Fixup res %d (%lx) of dev %s: %llx -> %llx\n",
 			    i, res->flags, pci_name(dev),
 			    i, res->flags, pci_name(dev),
 			    (u64)res->start - offset, (u64)res->start);
 			    (u64)res->start - offset, (u64)res->start);
@@ -147,30 +149,32 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID,		PCI_ANY_ID,			pcibios_fixup_resources);
 void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
 void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
 			struct resource *res)
 			struct resource *res)
 {
 {
-	unsigned long offset = 0;
+	resource_size_t offset = 0, mask = (resource_size_t)-1;
 	struct pci_controller *hose = dev->sysdata;
 	struct pci_controller *hose = dev->sysdata;
 
 
-	if (hose && res->flags & IORESOURCE_IO)
+	if (hose && res->flags & IORESOURCE_IO) {
 		offset = (unsigned long)hose->io_base_virt - isa_io_base;
 		offset = (unsigned long)hose->io_base_virt - isa_io_base;
-	else if (hose && res->flags & IORESOURCE_MEM)
+		mask = 0xffffffffu;
+	} else if (hose && res->flags & IORESOURCE_MEM)
 		offset = hose->pci_mem_offset;
 		offset = hose->pci_mem_offset;
-	region->start = res->start - offset;
-	region->end = res->end - offset;
+	region->start = (res->start - offset) & mask;
+	region->end = (res->end - offset) & mask;
 }
 }
 EXPORT_SYMBOL(pcibios_resource_to_bus);
 EXPORT_SYMBOL(pcibios_resource_to_bus);
 
 
 void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
 void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
 			     struct pci_bus_region *region)
 			     struct pci_bus_region *region)
 {
 {
-	unsigned long offset = 0;
+	resource_size_t offset = 0, mask = (resource_size_t)-1;
 	struct pci_controller *hose = dev->sysdata;
 	struct pci_controller *hose = dev->sysdata;
 
 
-	if (hose && res->flags & IORESOURCE_IO)
+	if (hose && res->flags & IORESOURCE_IO) {
 		offset = (unsigned long)hose->io_base_virt - isa_io_base;
 		offset = (unsigned long)hose->io_base_virt - isa_io_base;
-	else if (hose && res->flags & IORESOURCE_MEM)
+		mask = 0xffffffffu;
+	} else if (hose && res->flags & IORESOURCE_MEM)
 		offset = hose->pci_mem_offset;
 		offset = hose->pci_mem_offset;
-	res->start = region->start + offset;
-	res->end = region->end + offset;
+	res->start = (region->start + offset) & mask;
+	res->end = (region->end + offset) & mask;
 }
 }
 EXPORT_SYMBOL(pcibios_bus_to_resource);
 EXPORT_SYMBOL(pcibios_bus_to_resource);
 
 
@@ -334,9 +338,9 @@ static int __init
 pci_relocate_bridge_resource(struct pci_bus *bus, int i)
 pci_relocate_bridge_resource(struct pci_bus *bus, int i)
 {
 {
 	struct resource *res, *pr, *conflict;
 	struct resource *res, *pr, *conflict;
-	unsigned long try, size;
-	int j;
+	resource_size_t try, size;
 	struct pci_bus *parent = bus->parent;
 	struct pci_bus *parent = bus->parent;
+	int j;
 
 
 	if (parent == NULL) {
 	if (parent == NULL) {
 		/* shouldn't ever happen */
 		/* shouldn't ever happen */
@@ -438,7 +442,7 @@ update_bridge_resource(struct pci_dev *dev, struct resource *res)
 	u8 io_base_lo, io_limit_lo;
 	u8 io_base_lo, io_limit_lo;
 	u16 mem_base, mem_limit;
 	u16 mem_base, mem_limit;
 	u16 cmd;
 	u16 cmd;
-	unsigned long start, end, off;
+	resource_size_t start, end, off;
 	struct pci_controller *hose = dev->sysdata;
 	struct pci_controller *hose = dev->sysdata;
 
 
 	if (!hose) {
 	if (!hose) {
@@ -1157,8 +1161,8 @@ void pcibios_fixup_bus(struct pci_bus *bus)
 			res->end = IO_SPACE_LIMIT;
 			res->end = IO_SPACE_LIMIT;
 			res->flags = IORESOURCE_IO;
 			res->flags = IORESOURCE_IO;
 		}
 		}
-		res->start += io_offset;
-		res->end += io_offset;
+		res->start = (res->start + io_offset) & 0xffffffffu;
+		res->end = (res->end + io_offset) & 0xffffffffu;
 
 
 		for (i = 0; i < 3; ++i) {
 		for (i = 0; i < 3; ++i) {
 			res = &hose->mem_resources[i];
 			res = &hose->mem_resources[i];
@@ -1183,8 +1187,10 @@ void pcibios_fixup_bus(struct pci_bus *bus)
 			if (!res->flags || bus->self->transparent)
 			if (!res->flags || bus->self->transparent)
 				continue;
 				continue;
 			if (io_offset && (res->flags & IORESOURCE_IO)) {
 			if (io_offset && (res->flags & IORESOURCE_IO)) {
-				res->start += io_offset;
-				res->end += io_offset;
+				res->start = (res->start + io_offset) &
+					0xffffffffu;
+				res->end = (res->end + io_offset) &
+					0xffffffffu;
 			} else if (hose->pci_mem_offset
 			} else if (hose->pci_mem_offset
 				   && (res->flags & IORESOURCE_MEM)) {
 				   && (res->flags & IORESOURCE_MEM)) {
 				res->start += hose->pci_mem_offset;
 				res->start += hose->pci_mem_offset;