Messages in this thread Patch in this message |  | | Date | Thu, 12 Oct 2000 09:57:36 -0700 (PDT) | From | Linus Torvalds <> | Subject | Re: Updated 2.4 TODO List - more on PCI resources...] |
| |
On Thu, 12 Oct 2000, Dag Bakke wrote: > > Linus, > I realized there was one more test to do before deeming the hardware sane. > > PCMCIA (16-bit) in my laptop is tested and works fine with three different > types of cards. > Another Xircom card behaved just the same (non-functional) in my latop. > My Xircom card was tested in another laptop and found working. > > Today I took my card *and* disk and tested it in an identical laptop. > It works. > > So it appears that the *cardbus* logic is broken on my machine. Plain, old > hardware defect. And I have been wasting your time. Sorry about that.
No problem. This was good to have it out of the way. And I don't think you actually wasted my time: this may still be a Linux bug. See more below.
> In any case, debug output follows for both the non-working and the working > case. Feel free to pin-point the hw-bug or flat out ignore it.....
Yup, bug pin-pointed, and clear: these are the resources for the failing case:
> device PCI device 115d:0003 resource 1 size 04000800 > device PCI device 115d:0003 resource 2 size 04000800 > device PCI device 115d:0003 resource 6 size 04004000 > device PCI device 115d:0003 resource 6 size 04004000 > device PCI device 115d:0103 resource 1 size 04000800 > device PCI device 115d:0103 resource 2 size 04000800 > device PCI device 115d:0103 resource 6 size 04004000 > device PCI device 115d:0103 resource 6 size 04004000
While I'll bet you $20 that the working case (which doesn't print out the same printk because it doesn't fail) has the exact same resources, except the "size" field doesn't have that pesky high bit set, so the sizes are all 0x0800 of 0x4000 instead of being 64MB+.
Now, that said, I do think that this is a linux bug. Sure, your hardware is strange too, and hardware obviously _does_ make a difference, but there is no way a non-power-of-two size field can ever be valid, and Linux is buggy for allowing the hardware to confuse it this way.
What seems to be happening is that somehow your cardbus bridge (or docking station bridge) is set up so that it doesn't let through that high bit that defines the size of the PCI bridge map, and the way Linux calculates the size is basically the simplistic
write all 1's to the base register read the base register sz = ~(base & mask) & maxmask;
and while that works most of the time in normal situations, it's really not correct. What we _should_ do is more akin to this patch. Can you test this on your broken system, and see if the system magically comes to life?
NOTE! I do worry about the masking off of a bit in the bridge. There may be a real hardware bug there - but the fact that the mask seems to move depending on how big a bridge window there is (judging by your past mails about how behaviour did actually change when changing the cardbus window size) implies to me that it's not something as simple as a stuck bit.
If it is a stuck bit somehow, then you're screwed, and the patch below won't help you at all. But if it's the bridge snooping (and modifying) the decode window sizes, then the patch below should make a difference.
Thanks,
Linus
---- --- v2.4.0-test9/linux/drivers/pci/pci.c Sun Oct 8 10:50:20 2000 +++ linux/drivers/pci/pci.c Thu Oct 12 09:52:07 2000 @@ -474,6 +474,16 @@ return IORESOURCE_MEM; } +/* + * Find the extent of a PCI decode.. + */ +static u32 pci_size(u32 base, u32 mask) +{ + u32 size = mask & base; /* Find the significant bits */ + size = size & ~(size-1); /* Get the lowest of them to find the decode size */ + return size-1; /* extent = size - 1 */ +} + static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) { unsigned int pos, reg, next; @@ -501,10 +511,10 @@ l = 0; if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { res->start = l & PCI_BASE_ADDRESS_MEM_MASK; - sz = ~(sz & PCI_BASE_ADDRESS_MEM_MASK); + sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK); } else { res->start = l & PCI_BASE_ADDRESS_IO_MASK; - sz = ~(sz & PCI_BASE_ADDRESS_IO_MASK) & 0xffff; + sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff); } res->end = res->start + (unsigned long) sz; res->flags |= (l & 0xf) | pci_calc_resource_flags(l); @@ -543,7 +553,7 @@ res->flags = (l & PCI_ROM_ADDRESS_ENABLE) | IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE; res->start = l & PCI_ROM_ADDRESS_MASK; - sz = ~(sz & PCI_ROM_ADDRESS_MASK); + sz = pci_size(sz, PCI_ROM_ADDRESS_MASK); res->end = res->start + (unsigned long) sz; } res->name = dev->name; - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org Please read the FAQ at http://www.tux.org/lkml/
|  |