Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 31479
b: refs/heads/master
c: b435261
h: refs/heads/master
i:
  31477: ac2ce38
  31475: f9ca238
  31471: cea8540
v: v3
  • Loading branch information
Bernhard Kaindl authored and Dominik Brodowski committed Jun 30, 2006
1 parent ab41f27 commit 67727b7
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: d250a4810402ec68f64802b66340a0e70c61cbd3
refs/heads/master: b435261b1e09bb2bb6acc4abbc7f6e3d885f9e62
73 changes: 73 additions & 0 deletions trunk/drivers/pcmcia/yenta_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,77 @@ static void yenta_config_init(struct yenta_socket *socket)
config_writew(socket, CB_BRIDGE_CONTROL, bridge);
}

/**
* yenta_fixup_parent_subordinate - Fix subordinate bus# of the parent bridge
* @cardbus_bridge: The PCI bus which the CardBus bridge bridges to
*
* Checks if devices on the bus which the CardBus bridge bridges to would be
* invisible during PCI scans because of a misconfigured subordinate number
* of the parent brige - some BIOSes seem to be too lazy to set it right.
* Does the fixup carefully by checking how far it can go without conflicts.
* See http://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information.
*/
static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
{
struct list_head *tmp;
unsigned char upper_limit;
/*
* We only check and fix the parent bridge: All systems which need
* this fixup that have been reviewed are laptops and the only bridge
* which needed fixing was the parent bridge of the CardBus bridge:
*/
struct pci_bus *bridge_to_fix = cardbus_bridge->parent;

/* Check bus numbers are already set up correctly: */
if (bridge_to_fix->subordinate >= cardbus_bridge->subordinate)
return; /* The subordinate number is ok, nothing to do */

if (!bridge_to_fix->parent)
return; /* Root bridges are ok */

/* stay within the limits of the bus range of the parent: */
upper_limit = bridge_to_fix->parent->subordinate;

/* check the bus ranges of all silbling bridges to prevent overlap */
list_for_each(tmp, &bridge_to_fix->parent->children) {
struct pci_bus * silbling = pci_bus_b(tmp);
/*
* If the silbling has a higher secondary bus number
* and it's secondary is equal or smaller than our
* current upper limit, set the new upper limit to
* the bus number below the silbling's range:
*/
if (silbling->secondary > bridge_to_fix->subordinate
&& silbling->secondary <= upper_limit)
upper_limit = silbling->secondary - 1;
}

/* Show that the wanted subordinate number is not possible: */
if (cardbus_bridge->subordinate > upper_limit)
printk(KERN_WARNING "Yenta: Upper limit for fixing this "
"bridge's parent bridge: #%02x\n", upper_limit);

/* If we have room to increase the bridge's subordinate number, */
if (bridge_to_fix->subordinate < upper_limit) {

/* use the highest number of the hidden bus, within limits */
unsigned char subordinate_to_assign =
min(cardbus_bridge->subordinate, upper_limit);

printk(KERN_INFO "Yenta: Raising subordinate bus# of parent "
"bus (#%02x) from #%02x to #%02x\n",
bridge_to_fix->number,
bridge_to_fix->subordinate, subordinate_to_assign);

/* Save the new subordinate in the bus struct of the bridge */
bridge_to_fix->subordinate = subordinate_to_assign;

/* and update the PCI config space with the new subordinate */
pci_write_config_byte(bridge_to_fix->self,
PCI_SUBORDINATE_BUS, bridge_to_fix->subordinate);
}
}

/*
* Initialize a cardbus controller. Make sure we have a usable
* interrupt, and that we can map the cardbus area. Fill in the
Expand Down Expand Up @@ -1120,6 +1191,8 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
yenta_get_socket_capabilities(socket, isa_interrupts);
printk(KERN_INFO "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));

yenta_fixup_parent_bridge(dev->subordinate);

/* Register it with the pcmcia layer.. */
ret = pcmcia_register_socket(&socket->socket);
if (ret == 0) {
Expand Down

0 comments on commit 67727b7

Please sign in to comment.