LongTrail PCI resource assignment

Michael Schmitz schmitz at opal.biophys.uni-duesseldorf.de
Tue Apr 4 04:42:39 EST 2000


> > - OF reports two base addresses for the Mach64, one of which is the I/O
> > region (according to the PCI BAR values) at 0xc00. OF reports its address
>                                               ^^^^^
> Where does that address come from? I'm missing something here..

Straight from the BAR for region 1, with the resource type bits masked
off. BTW lspci also reports this.

> > as 0x80881000 or some such. Does this mean the I/O registers are
> > accessible at 0x80881000, or did OF probing get some bogus values there?
>
> When talking PCI IO space on PowerMacs, always keep in mind that the
> host bridge adds an offset to PCI IO space, i.e. IO port 0xc00 on the
> bus will have processor physical address 0xf2000c00 or something like
> that. The offset might be reprogrammable, but I'd suggest _not_
> changing it, as it is also the base address for config space accesses on
> that bus...

0xfe000000 is what pmac_pci.c uses for my machine (processor physical as
well as virtual). I'm not trying to change that, I just didn't understand
the address reported by OF for that region. I still don't understand it.

> > - I can successfully remap the MMIO range of the chip to some area outside
> > the VRAM range. XFree86 no longer barfs on the mem resource conflict
> > (though it still reports the I/O resource conflict with the DVD decoder),
> > reports the new mapping of the MMIO range, and starts up nicely. lspci -vv,
> > however, still reports the old range. Where's that one stored
> > (assuming /proc/pci somewhere), and wouldn't it make more sense to have
> > the PCI bus rescanned on reading /proc/pci entries?
>
> If you remap the MMIO range, you need to do two things:
>
> 1. change the BAR setting, so that the device will respond to the new
> address

That's been done :-)

> 2. change the values stored in struct pci_dev, so that the kernel at
> large (that includes other drivers, and the interface used by lspci)
> knows about it.

That's what I missed. I changed the value in the OF tree but forgot the
PCI side.

> > - I picked a range to remap MMIO to more or less at random. How can I find
> > out what ranges are believed to be unassigned from OF data?
>
> There's no other way than to look up all assigned regions. However,
> don't rely (only) on what OF tells you in the devide tree, as some
> assigments may have been changed by PCI fixup code, and OF may have
> forgotten some assigments.

As seen for the MMIO region :-) No thanks, I'l just use the address that
appears to be unused (right beyond the framebuffer). If someone wants to
generalize this hack, be careful. On a side note: I've not changed
ati_regbase after remapping the MMIO region, it still points to the old
location at the end of the LE aperture, and does apparently still work due
to the video RAM aperture remaining unchanged.

Patch appended (use at your own risk, works for me but I don't fully
understand why, etc.).

	Michael
-------------- next part --------------
--- drivers/video/atyfb.c.org	Mon Apr  3 20:20:24 2000
+++ drivers/video/atyfb.c	Mon Apr  3 20:26:11 2000
@@ -3176,7 +3176,7 @@
     u8 bus, devfn;
     u16 cmd;
     struct fb_info_aty *info;
-    int i;
+    int i, i_frame, i_regs, naddr;
 
     if (device_is_compatible(dp, "ATY,264LTPro")) {
 	/* XXX kludge for now */
@@ -3204,6 +3204,13 @@
 	    return;
     }
 
+    printk("atyfb: of_init got %d OF adresses for ATY:\n", dp->n_addrs);
+    for (i = 0; i < dp->n_addrs; i++)
+	printk(" %08x-%08x", dp->addrs[i].address,
+	       dp->addrs[i].address+dp->addrs[i].size-1);
+    if (dp->n_addrs)
+	printk("\n");
+
     info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
     if (!info) {
 	printk("atyfb_of_init: can't alloc fb_info_aty\n");
@@ -3215,6 +3222,8 @@
     info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
 						   0x1000);
 
+    printk("atyfb: regbase phys 0x%lx virt 0x%lx\n", info->ati_regbase_phys, info->ati_regbase);
+
     if(! info->ati_regbase) {
 	    printk("atyfb_init: ioremap() returned NULL\n");
 	    kfree(info);
@@ -3226,6 +3235,50 @@
 
     /* enable memory-space accesses using config-space command register */
     if (pci_device_loc(dp, &bus, &devfn) == 0) {
+
+	for (i = 0; i < dp->n_addrs + 2; i++) {
+	    int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
+	    unsigned long base;
+	    u32 size, pbase;
+
+	    base = dp->addrs[i].address;
+
+	    pcibios_read_config_dword(bus, devfn, breg, &pbase);
+	    pcibios_write_config_dword(bus, devfn, breg, 0xffffffff);
+	    pcibios_read_config_dword(bus, devfn, breg, &size);
+	    pcibios_write_config_dword(bus, devfn, breg, pbase);
+
+	    io = (pbase & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+
+	    if (io)
+		size &= ~1;
+	    size = ~(size) + 1;
+	    
+	    if (size == 0) 
+	    	break;
+
+	    printk("atyfb: chunk %d ofbase 0x%lx breg %d io %d pbase 0x%lx size 0x%lx \n",
+		i, base, breg, io, pbase, size);
+
+	    if (!base) {
+		printk("atyfb: chunk %d assigning ofbase 0x%lx \n", i, pbase);
+		dp->addrs[i].address = pbase;
+		dp->addrs[i].size = size;
+	    }
+	    if (pbase == addr) {
+		printk("atyfb: chunk %d assigned as VRAM aperture! \n", i);
+		i_frame = i;
+	    }
+	    if (size == 0x1000) {
+		printk("atyfb: chunk %d assigned as MMIO aperture! \n", i);
+		i_regs = i;
+	    }
+
+	}
+
+	naddr = i;
+	printk("atyfb: found %d PCI addresses total. \n", i);
+
 	pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
 	if (cmd != 0xffff) {
 	    cmd |= PCI_COMMAND_MEMORY;
@@ -3242,12 +3295,80 @@
     info->frame_buffer_phys = addr;
     info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
 
+    printk("atyfb: framebuffer phys 0x%lx virt 0x%lx\n", info->frame_buffer_phys, info->frame_buffer);
+
     if(! info->frame_buffer) {
 	    printk("atyfb_init: ioremap() returned NULL\n");
 	    kfree(info);
 	    return;
     }
 
+    /* 
+     * Fix MMIO mapping if MMIO and VRAM overlap 
+     * Note that we can't move the VRAM base address to the BE aperture (this would move the whole
+     * VRAM region, not resize it) so it's easier to remap MMIO someplace else.
+     */
+    if ( (dp->addrs[i_frame].address < dp->addrs[i_regs].address+dp->addrs[i_regs].size 
+	 && dp->addrs[i_frame].address+dp->addrs[i_frame].size >= dp->addrs[i_regs].address)
+    	 || (dp->addrs[i_regs].address < dp->addrs[i_frame].address+dp->addrs[i_frame].size
+    	    && dp->addrs[i_regs].address+dp->addrs[i_regs].size >= dp->addrs[i_frame].address) ) {
+
+	    struct pci_dev *pdev = pci_find_slot(bus, devfn);
+	    int io, breg = PCI_BASE_ADDRESS_0 + (i_regs << 2);
+	    int flags;
+	    unsigned long base;
+	    u32 size, pbase, new;
+
+	    base = dp->addrs[i_regs].address;
+
+	    pcibios_read_config_dword(bus, devfn, breg, &pbase);
+	    pcibios_write_config_dword(bus, devfn, breg, 0xffffffff);
+	    pcibios_read_config_dword(bus, devfn, breg, &size);
+	    pcibios_write_config_dword(bus, devfn, breg, pbase);
+
+	    io = (pbase & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+	    flags = (pbase & PCI_BASE_ADDRESS_MEM_MASK);
+
+	    if (io)
+		size &= ~1;
+	    size = ~(size) + 1;
+	    
+	    printk("atyfb: chunk %d ofbase 0x%lx breg %d io %d pbase 0x%lx size 0x%lx needs reassigning! \n",
+		i_regs, base, breg, io, pbase, size);
+
+	    /* move MMIO past frame buffer for now. Need to walk PCI resources to find safe place */
+	    new = (dp->addrs[i_frame].address+dp->addrs[i_frame].size) | (flags & 0x0f);
+
+	    pcibios_write_config_dword(bus, devfn, breg, new);
+
+	    pcibios_read_config_dword(bus, devfn, breg, &pbase);
+	    pcibios_write_config_dword(bus, devfn, breg, 0xffffffff);
+	    pcibios_read_config_dword(bus, devfn, breg, &size);
+	    pcibios_write_config_dword(bus, devfn, breg, pbase);
+
+	    if (new != pbase) 
+	    	printk("atyfb: failed to remap MMIO region! \n");
+
+	    /* update PCI struct */
+	    if (!pdev) 
+	    	printk("atyfb: no pci_dev registered for device!\n");
+	    else
+	    	pdev->base_address[i_regs] = pbase;
+
+	    io = (pbase & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+	    flags = (pbase & ~PCI_BASE_ADDRESS_MEM_MASK);
+
+	    if (io)
+		size &= ~1;
+	    size = ~(size) + 1;
+	    
+	    printk("atyfb: chunk %d ofbase 0x%lx breg %d io %d reassigned to pbase 0x%lx size 0x%lx ! \n",
+		i_regs, base, breg, io, pbase, size);
+
+	    /* update OF device tree */
+	    dp->addrs[i_regs].address = dp->addrs[i_frame].address+dp->addrs[i_frame].size;
+    }
+
     if (!aty_init(info, dp->full_name)) {
 	kfree(info);
 	return;
@@ -3267,7 +3388,6 @@
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 }
 #endif /* CONFIG_FB_OF */
-
 
 __initfunc(void atyfb_setup(char *options, int *ints))
 {


More information about the Linuxppc-dev mailing list