pbm->mem_offset);
if (pbm->mem64_space.flags)
pci_add_resource_offset(&resources, &pbm->mem64_space,
- pbm->mem_offset);
+ pbm->mem64_offset);
pbm->busn.start = pbm->pci_first_busno;
pbm->busn.end = pbm->pci_last_busno;
pbm->busn.flags = IORESOURCE_BUS;
return 0;
}
+static resource_size_t get_mem_offset(struct pci_pbm_info *pbm,
+ resource_size_t bus_addr)
+{
+ resource_size_t start;
+
+ if (pbm->mem_space.flags) {
+ start = bus_addr + pbm->mem_offset;
+
+ if (start >= pbm->mem_space.start &&
+ start <= pbm->mem_space.end)
+ return pbm->mem_offset;
+ }
+
+ if (pbm->mem64_space.flags) {
+ start = bus_addr + pbm->mem64_offset;
+
+ if (start >= pbm->mem64_space.start &&
+ start <= pbm->mem64_space.end)
+ return pbm->mem64_offset;
+ }
+
+ return 0;
+}
+
/* Platform support for /proc/bus/pci/X/Y mmap()s. */
/* If the user uses a host-bridge as the PCI device, he may use
{
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
unsigned long space_size, user_offset, user_size;
+ resource_size_t mem_offset = 0;
+
+ /* Make sure the request is in range. */
+ user_offset = vma->vm_pgoff << PAGE_SHIFT;
+ user_size = vma->vm_end - vma->vm_start;
if (mmap_state == pci_mmap_io) {
space_size = resource_size(&pbm->io_space);
} else {
+ mem_offset = get_mem_offset(pbm, user_offset);
space_size = resource_size(&pbm->mem_space);
+ if (mem_offset != pbm->mem_offset && pbm->mem64_space.flags)
+ space_size = resource_size(&pbm->mem64_space);
}
- /* Make sure the request is in range. */
- user_offset = vma->vm_pgoff << PAGE_SHIFT;
- user_size = vma->vm_end - vma->vm_start;
-
if (user_offset >= space_size ||
(user_offset + user_size) > space_size)
return -EINVAL;
vma->vm_pgoff = (pbm->io_offset +
user_offset) >> PAGE_SHIFT;
} else {
- vma->vm_pgoff = (pbm->mem_offset +
+ vma->vm_pgoff = (mem_offset +
user_offset) >> PAGE_SHIFT;
}
const struct resource *rp, resource_size_t *start,
resource_size_t *end)
{
- struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- unsigned long offset;
+ struct pci_bus_region region;
- if (rp->flags & IORESOURCE_IO)
- offset = pbm->io_offset;
- else
- offset = pbm->mem_offset;
+ pcibios_resource_to_bus(pdev->bus, ®ion, (struct resource *)rp);
- *start = rp->start - offset;
- *end = rp->end - offset;
+ *start = region.start;
+ *end = region.end;
}
void pcibios_set_master(struct pci_dev *dev)
}
}
-static void pci_register_region(struct pci_pbm_info *pbm, const char *name,
+static int pci_register_region_one(struct pci_pbm_info *pbm, const char *name,
+ struct resource *mem_res,
+ resource_size_t mem_offset,
resource_size_t rstart, resource_size_t size)
{
struct resource *res, *conflict;
- struct resource *mem_res = &pbm->mem_space;
- resource_size_t offset = pbm->mem_offset;
resource_size_t mem_rstart, mem_rend;
resource_size_t rend = rstart + size - 1UL;
if (!mem_res->flags)
- return;
+ return -1;
- mem_rstart = mem_res->start - offset;
- mem_rend = mem_res->end - offset;
+ mem_rstart = mem_res->start - mem_offset;
+ mem_rend = mem_res->end - mem_offset;
/* contain checking */
if (!(mem_rstart <= rstart && mem_rend >= rend))
- return;
+ return -1;
res = kzalloc(sizeof(*res), GFP_KERNEL);
if (!res)
- return;
+ return 0;
res->name = name;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
- res->start = rstart + offset;
- res->end = rend + offset;
+ res->start = rstart + mem_offset;
+ res->end = rend + mem_offset;
conflict = request_resource_conflict(mem_res, res);
if (conflict) {
printk(KERN_DEBUG "PCI: %s can't claim %s %pR: address conflict with %s %pR\n",
pbm->name, res->name, res, conflict->name, conflict);
kfree(res);
}
+
+ return 0;
+}
+
+static void pci_register_region(struct pci_pbm_info *pbm, const char *name,
+ resource_size_t rstart, resource_size_t size)
+{
+ int ret;
+
+ ret = pci_register_region_one(pbm, name, &pbm->mem_space,
+ pbm->mem_offset, rstart, size);
+
+ if (!ret)
+ return;
+
+ pci_register_region_one(pbm, name, &pbm->mem64_space,
+ pbm->mem64_offset, rstart, size);
}
void pci_register_legacy_regions(struct pci_pbm_info *pbm)
void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
{
const struct linux_prom_pci_ranges *pbm_ranges;
- resource_size_t mem64_offset = 0;
int i, saw_mem, saw_io;
int num_pbm_ranges;
pbm->mem64_space.start = a;
pbm->mem64_space.end = a + size - 1UL;
pbm->mem64_space.flags = IORESOURCE_MEM;
- mem64_offset = a - region_a;
+ pbm->mem64_offset = a - region_a;
saw_mem = 1;
break;
if (pbm->mem_space.flags)
printk("%s: PCI MEM %pR offset %llx\n",
pbm->name, &pbm->mem_space, pbm->mem_offset);
- if (pbm->mem64_space.flags) {
- if (pbm->mem_space.flags) {
- if (mem64_offset != pbm->mem_offset)
- panic("mem offset %llx != mem64 offset %llx\n",
- pbm->mem_offset, mem64_offset);
- } else
- pbm->mem_offset = mem64_offset;
+ if (pbm->mem64_space.flags && pbm->mem_space.flags) {
+ if (pbm->mem64_space.start <= pbm->mem_space.end)
+ pbm->mem64_space.start = pbm->mem_space.end + 1;
+ if (pbm->mem64_space.start > pbm->mem64_space.end)
+ pbm->mem64_space.flags = 0;
+ }
+ if (pbm->mem64_space.flags)
printk("%s: PCI MEM64 %pR offset %llx\n",
- pbm->name, &pbm->mem64_space, pbm->mem_offset);
- }
+ pbm->name, &pbm->mem64_space, pbm->mem64_offset);
pbm->io_space.name = pbm->mem_space.name = pbm->name;
pbm->mem64_space.name = pbm->name;