> 00:11.0 Display controller: ATI Technologies Inc 3D Rage LT Pro (rev dc)
>         Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr-
> Stepping+ SERR- FastB2B-
>         Status: Cap+ 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort-
> <TAbort- <MAbort- >SERR- <PERR-
>         Latency: 32 (2000ns min), cache line size 08
>         Interrupt: pin A routed to IRQ 24
>         Region 0: Memory at 82000000 (32-bit, non-prefetchable)
>         Region 1: I/O ports at 0400 [disabled]
>         Region 2: Memory at 82fff000 (32-bit, non-prefetchable)

That's what I expected...

Please try to apply the attached patch to the 2.2.18 ppc kernel source and
recompile.

        Michael
--- drivers/video/atyfb.c.orig  Thu Oct 19 19:49:53 2000
+++ drivers/video/atyfb.c       Fri Oct 20 12:10:37 2000
@@ -3242,14 +3242,72 @@
     return 1;
 }
 
+/*
+ * Check PCI resource overlap between any PCI device (but mydev) and this 
region.
+ * This function does not discriminate between IO and memory space so memory 
regions 
+ * will be considered to overlap IO regions though they might be decoded 
separate on
+ * machines with separate memory and IO access. This being for PPC I don't 
care - MSch.
+ */
+__initfunc(int atyfb_check_overlap(struct pci_dev *mydev, unsigned long 
mybase, unsigned int mysize))
+{
+
+    int i,j;
+    struct pci_dev *pdev;
+
+    for (pdev = pci_devices; pdev; pdev = pdev->next) {
+
+       if (pdev == mydev)
+           continue;
+
+        for (i = 0, j = 2; i < 6 && pdev->base_address[i]; i++) {
+           int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
+           unsigned long base;
+           u32 size, pbase;
+
+           base = pdev->base_address[i];
+
+           if (!base)
+               continue;
+
+           io = (base & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+
+           pci_read_config_dword(pdev, breg, &pbase);
+           pci_write_config_dword(pdev, breg, 0xffffffff);
+           pci_read_config_dword(pdev, breg, &size);
+           pci_write_config_dword(pdev, breg, pbase);
+
+           if (io) {
+               size &= PCI_BASE_ADDRESS_IO_MASK;
+               base &= PCI_BASE_ADDRESS_IO_MASK;
+           } else {
+               size &= PCI_BASE_ADDRESS_MEM_MASK;
+               base &= PCI_BASE_ADDRESS_MEM_MASK;
+           }
+           size = ~(size) + 1;
+
+           if ( (base < mybase+mysize-1 && base+size-1 >= mybase)
+                || (mybase < base+size-1 && mybase+mysize-1 >= base) ) {
+               printk("\nPCI resource conflict: %lx-%lx overlaps %lx-%lx !\n",
+                   base, base+size-1, mybase, mybase+mysize-1);
+               return 1;       /* conflicting region overlaps */
+           }
+
+        }
+    }
+
+    return 0;                  /* no conflicting region found */
+
+}
+
+
 #ifdef CONFIG_FB_OF
 __initfunc(void atyfb_of_init(struct device_node *dp))
 {
-    unsigned long addr;
+    unsigned long addr, io_base=NULL;
     u8 bus, devfn;
     u16 cmd;
     struct fb_info_aty *info;
-    int i;
+    int i, i_frame, i_regs, i_io, naddr;
 
     if (device_is_compatible(dp, "ATY,264LTPro")) {
        /* XXX kludge for now */
@@ -3284,6 +3342,12 @@
     }
     memset(info, 0, sizeof(struct fb_info_aty));
 
+    /* 
+     * Use register set in the little endian aperture regardless of what was 
set 
+     * up in OF or the PCI registers for MMIO. We could use the registers in 
the 
+     * big endian aperture as well (at least on some LTPro), or set up a 
separate 
+     * PCI mapping. Seems to work either way (again, on my Lombard) - MSch.
+     */
     info->ati_regbase_phys = 0x7ff000+addr;
     info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
                                                   0x1000);
@@ -3297,8 +3361,49 @@
     info->ati_regbase_phys += 0xc00;
     info->ati_regbase += 0xc00;
 
-    /* enable memory-space accesses using config-space command register */
+    /* search PCI config space for VRAM, IO and MMIO regions */
     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;
+               pbase &= ~1;            
+               i_io = i;
+           }
+
+           size = ~(size) + 1;
+           
+           if (size == 0) 
+               break;
+
+           if (!base) {
+               dp->addrs[i].address = pbase;
+               dp->addrs[i].size = size;
+           }
+           if (pbase == addr) {
+               i_frame = i;
+           } else if (size == 0x1000) {
+               i_regs = i;
+               io_base = pbase;
+            }
+       }
+
+       naddr = i;
+
+        /* enable memory-space accesses using config-space command register */
        pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
        if (cmd != 0xffff) {
            cmd |= PCI_COMMAND_MEMORY;
@@ -3319,6 +3424,105 @@
            printk("atyfb_init: ioremap() returned NULL\n");
            kfree(info);
            return;
+    }
+
+    /* 
+     * Fix MMIO mapping if MMIO and VRAM PCI mappings set up by MacOS overlap 
- MSch.
+     * 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;
+               pbase &= ~1;
+           }
+           size = ~(size) + 1;
+           
+           printk("atyfb: region %d ofbase 0x%lx breg %d io %d pbase 0x%lx 
size 0x%lx overlaps VRAM ",
+               i_regs, base, breg, io, pbase, size);
+
+           /* 
+            * Best guess: try address used by OF/yaboot, check for overlap 
with existing devices!
+            */
+           new = 0x80881000;
+
+           if (atyfb_check_overlap(pdev, new, size)) {
+               /* 
+                * Something overlaps our new mapping. Move MMIO before frame 
buffer and past I/O for now. 
+                * Need to walk PCI resources to find guaranteed free spot 
(currently we bail out when our
+                * next best guess is taken as well). 
+                */
+               if 
(dp->addrs[i_io].address+dp->addrs[i_io].size+dp->addrs[i_regs].size < 
dp->addrs[i_frame].address) {
+                   new = (dp->addrs[i_io].address&0xff000000) | 
(dp->addrs[i_regs].address&0x00ffffff);
+               } else {
+                   new = (dp->addrs[i_frame].address+dp->addrs[i_frame].size);
+               }
+               if (atyfb_check_overlap(pdev, new, size)) {
+                   printk("\natyfb: can't resolve overlap, bailing out!\n");
+                   /* gotos are evil */
+                   new = base;
+               }
+           }
+
+           new |= 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;
+               pbase &= ~1;
+           }
+           size = ~(size) + 1;
+           
+           printk(" - reassigned to pbase 0x%lx size 0x%lx ! \n", pbase, size);
+
+           /* update OF device tree */
+           dp->addrs[i_regs].address = pbase;
+
+           /*
+            * Note: we only fixed up PCI config and brought the OF device tree 
+            * in line with the new PCI config. regbase still is mapped to the 
original
+            * location in the LE aperture which overlaps with the full (LE and 
BE) 
+            * VRAM. If someone at xfree ever starts to check if regbase falls 
within
+            * the PCI region of VRAM, slap them silly - MSch.
+            */
     }
 
     if (!aty_init(info, dp->full_name)) {

Reply via email to