Skip to content

Commit 3678024

Browse files
Ivan KokshayskyLinus Torvalds
authored andcommitted
[PATCH] pci bus resources, transparent bridges
Added PCI_BUS_NUM_RESOURCES as Ben suggested. Default value is 4 and can be overridden by arch (probably in asm/system.h). pci_read_bridge_bases() and pci_assign_bus_resource() changed accordingly. "for (i = 0 ; i < 4; i++)" in pci_add_new_bus() not changed, as it's used _only_ for pci-pci and cardbus bridges.
1 parent be4bde6 commit 3678024

File tree

5 files changed

+50
-17
lines changed

5 files changed

+50
-17
lines changed

arch/i386/pci/fixup.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,22 @@ static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d)
166166
}
167167
}
168168

169+
/*
170+
* For some reasons Intel decided that certain parts of their
171+
* 815, 845 and some other chipsets must look like PCI-to-PCI bridges
172+
* while they are obviously not. The 82801 family (AA, AB, BAM/CAM,
173+
* BA/CA/DB and E) PCI bridges are actually HUB-to-PCI ones, according
174+
* to Intel terminology. These devices do forward all addresses from
175+
* system to PCI bus no matter what are their window settings, so they are
176+
* "transparent" (or subtractive decoding) from programmers point of view.
177+
*/
178+
static void __init pci_fixup_transparent_bridge(struct pci_dev *dev)
179+
{
180+
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
181+
(dev->device & 0xff00) == 0x2400)
182+
dev->transparent = 1;
183+
}
184+
169185
struct pci_fixup pcibios_fixups[] = {
170186
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx },
171187
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx },
@@ -183,5 +199,6 @@ struct pci_fixup pcibios_fixups[] = {
183199
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, pci_fixup_via_northbridge_bug },
184200
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_via_northbridge_bug },
185201
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810 },
202+
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge },
186203
{ 0 }
187204
};

drivers/pci/probe.c

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
128128
if (!dev) /* It's a host bus, nothing to read */
129129
return;
130130

131+
if (dev->transparent) {
132+
printk("Transparent bridge - %s\n", dev->name);
133+
for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++)
134+
child->resource[i] = child->parent->resource[i];
135+
return;
136+
}
137+
131138
for(i=0; i<3; i++)
132139
child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
133140

@@ -149,13 +156,6 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
149156
res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
150157
res->start = base;
151158
res->end = limit + 0xfff;
152-
} else {
153-
/*
154-
* Ugh. We don't know enough about this bridge. Just assume
155-
* that it's entirely transparent.
156-
*/
157-
printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0);
158-
child->resource[0] = child->parent->resource[0];
159159
}
160160

161161
res = child->resource[1];
@@ -167,10 +167,6 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
167167
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
168168
res->start = base;
169169
res->end = limit + 0xfffff;
170-
} else {
171-
/* See comment above. Same thing */
172-
printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1);
173-
child->resource[1] = child->parent->resource[1];
174170
}
175171

176172
res = child->resource[2];
@@ -197,10 +193,6 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
197193
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
198194
res->start = base;
199195
res->end = limit + 0xfffff;
200-
} else {
201-
/* See comments above */
202-
printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2);
203-
child->resource[2] = child->parent->resource[2];
204196
}
205197
}
206198

@@ -389,6 +381,10 @@ int pci_setup_device(struct pci_dev * dev)
389381
case PCI_HEADER_TYPE_BRIDGE: /* bridge header */
390382
if (class != PCI_CLASS_BRIDGE_PCI)
391383
goto bad;
384+
/* The PCI-to-PCI bridge spec requires that subtractive
385+
decoding (i.e. transparent) bridge must have programming
386+
interface code of 0x01. */
387+
dev->transparent = ((class & 0xff) == 1);
392388
pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
393389
break;
394390

drivers/pci/quirks.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,11 @@ static void __init quirk_dunord ( struct pci_dev * dev )
471471
r -> end = 0xffffff;
472472
}
473473

474+
static void __init quirk_transparent_bridge(struct pci_dev *dev)
475+
{
476+
dev->transparent = 1;
477+
}
478+
474479
/*
475480
* The main table of quirks.
476481
*/
@@ -525,6 +530,13 @@ static struct pci_fixup pci_fixups[] __initdata = {
525530

526531
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic },
527532
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering },
533+
/*
534+
* i82380FB mobile docking controller: its PCI-to-PCI bridge
535+
* is subtractive decoding (transparent), and does indicate this
536+
* in the ProgIf. Unfortunately, the ProgIf value is wrong - 0x80
537+
* instead of 0x01.
538+
*/
539+
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge },
528540

529541
{ 0 }
530542
};

drivers/pci/setup-res.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ static int pci_assign_bus_resource(const struct pci_bus *bus,
7373
int i;
7474

7575
type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
76-
for (i = 0 ; i < 4; i++) {
76+
for (i = 0 ; i < PCI_BUS_NUM_RESOURCES; i++) {
7777
struct resource *r = bus->resource[i];
7878
if (!r)
7979
continue;

include/linux/pci.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,9 @@ struct pci_dev {
386386
int ro; /* ISAPnP: read only */
387387
unsigned short regs; /* ISAPnP: supported registers */
388388

389+
/* These fields are used by common fixups */
390+
unsigned short transparent:1; /* Transparent PCI bridge */
391+
389392
int (*prepare)(struct pci_dev *dev); /* ISAPnP hooks */
390393
int (*activate)(struct pci_dev *dev);
391394
int (*deactivate)(struct pci_dev *dev);
@@ -406,6 +409,10 @@ struct pci_dev {
406409
#define PCI_ROM_RESOURCE 6
407410
#define PCI_BRIDGE_RESOURCES 7
408411
#define PCI_NUM_RESOURCES 11
412+
413+
#ifndef PCI_BUS_NUM_RESOURCES
414+
#define PCI_BUS_NUM_RESOURCES 4
415+
#endif
409416

410417
#define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */
411418

@@ -415,7 +422,8 @@ struct pci_bus {
415422
struct list_head children; /* list of child buses */
416423
struct list_head devices; /* list of devices on this bus */
417424
struct pci_dev *self; /* bridge device as seen by parent */
418-
struct resource *resource[4]; /* address space routed to this bus */
425+
struct resource *resource[PCI_BUS_NUM_RESOURCES];
426+
/* address space routed to this bus */
419427

420428
struct pci_ops *ops; /* configuration access functions */
421429
void *sysdata; /* hook for sys-specific extension */

0 commit comments

Comments
 (0)