Re: [RFC][PATCH] Add PCI<->PCI bridge driver [4/9]

2005-07-15 Thread Adam Belay
On Fri, 2005-07-15 at 09:58 +0100, Russell King wrote:
> On Thu, Jul 14, 2005 at 04:55:19AM -0400, Adam Belay wrote:
> > This patch adds a basic PCI<->PCI bridge driver that utilizes the new
> > PCI bus class API.
> 
> Thanks.  I think this breaks Cardbus.
> 
> The whole point of the way PCI is _presently_ organised is that it allows
> busses to be configured and setup _before_ the devices are made available
> to drivers.  This breaks that completely:

Hi Russell,

I'm aware of this issue.  These changes are major and will need more
than one pass to be correct.  I'll be redoing most of the bus
configuration code in the next patch set.  I have a strategy for proper
device and bus configuration.  These are my current thoughts:

1.) When bound to its device PCI bridge drivers will add their current
devices to the bus device list, but will not register them with the
driver model.

2.) The bus class driver will initiate a procedure similar to
pci_bus_add_devices(), but only for host (root) bridges and hot-plugged
devices.

pci_register_bus_devices(struct pci_bus *bus)
{
- register all bios configured bridges
- call pci_register_bus_devices() for each previously registered bridge
- register remaining uninitialized bridges and call
pci_register_bus_devices() for each bridge as it's registered.
}

pci_register_devices(struct pci_bus *bus)
{
- register all remaining PCI devices, including those of child pci buses
}

* pci_register_bus_devices() will be called first followed by
pci_register_devices().

3.) Bridge windows will not be configured until a child device is
enabled.  In other words, resource configuration is lazy much like we
handle PCI IRQ routing.  We will, however, verify the validity of BIOS
assignments.  If the assignments are incorrect, the bridge will be
disabled and then reconfigured when needed.

Thanks,
Adam


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC][PATCH] Add PCI<->PCI bridge driver [4/9]

2005-07-15 Thread Russell King
On Thu, Jul 14, 2005 at 04:55:19AM -0400, Adam Belay wrote:
> This patch adds a basic PCI<->PCI bridge driver that utilizes the new
> PCI bus class API.

Thanks.  I think this breaks Cardbus.

The whole point of the way PCI is _presently_ organised is that it allows
busses to be configured and setup _before_ the devices are made available
to drivers.  This breaks that completely:

> +/**
> + * ppb_detect_children - detects and registers child devices
> + * @bus: pci bus
> + */
> +static void ppb_detect_children(struct pci_bus *bus)
> +{
> + unsigned int devfn;
> +
> + /* Go find them, Rover! */
> + for (devfn = 0; devfn < 0x100; devfn += 8)
> + pci_scan_slot(bus, devfn);
> +
> + pcibios_fixup_bus(bus);
> + pci_bus_add_devices(bus);
> +}

since we scan the bus, and immediately make all devices available.

This is broken, plain and simple.

-- 
Russell King
 Linux kernel2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC][PATCH] Add PCI-PCI bridge driver [4/9]

2005-07-15 Thread Russell King
On Thu, Jul 14, 2005 at 04:55:19AM -0400, Adam Belay wrote:
 This patch adds a basic PCI-PCI bridge driver that utilizes the new
 PCI bus class API.

Thanks.  I think this breaks Cardbus.

The whole point of the way PCI is _presently_ organised is that it allows
busses to be configured and setup _before_ the devices are made available
to drivers.  This breaks that completely:

 +/**
 + * ppb_detect_children - detects and registers child devices
 + * @bus: pci bus
 + */
 +static void ppb_detect_children(struct pci_bus *bus)
 +{
 + unsigned int devfn;
 +
 + /* Go find them, Rover! */
 + for (devfn = 0; devfn  0x100; devfn += 8)
 + pci_scan_slot(bus, devfn);
 +
 + pcibios_fixup_bus(bus);
 + pci_bus_add_devices(bus);
 +}

since we scan the bus, and immediately make all devices available.

This is broken, plain and simple.

-- 
Russell King
 Linux kernel2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core
-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [RFC][PATCH] Add PCI-PCI bridge driver [4/9]

2005-07-15 Thread Adam Belay
On Fri, 2005-07-15 at 09:58 +0100, Russell King wrote:
 On Thu, Jul 14, 2005 at 04:55:19AM -0400, Adam Belay wrote:
  This patch adds a basic PCI-PCI bridge driver that utilizes the new
  PCI bus class API.
 
 Thanks.  I think this breaks Cardbus.
 
 The whole point of the way PCI is _presently_ organised is that it allows
 busses to be configured and setup _before_ the devices are made available
 to drivers.  This breaks that completely:

Hi Russell,

I'm aware of this issue.  These changes are major and will need more
than one pass to be correct.  I'll be redoing most of the bus
configuration code in the next patch set.  I have a strategy for proper
device and bus configuration.  These are my current thoughts:

1.) When bound to its device PCI bridge drivers will add their current
devices to the bus device list, but will not register them with the
driver model.

2.) The bus class driver will initiate a procedure similar to
pci_bus_add_devices(), but only for host (root) bridges and hot-plugged
devices.

pci_register_bus_devices(struct pci_bus *bus)
{
- register all bios configured bridges
- call pci_register_bus_devices() for each previously registered bridge
- register remaining uninitialized bridges and call
pci_register_bus_devices() for each bridge as it's registered.
}

pci_register_devices(struct pci_bus *bus)
{
- register all remaining PCI devices, including those of child pci buses
}

* pci_register_bus_devices() will be called first followed by
pci_register_devices().

3.) Bridge windows will not be configured until a child device is
enabled.  In other words, resource configuration is lazy much like we
handle PCI IRQ routing.  We will, however, verify the validity of BIOS
assignments.  If the assignments are incorrect, the bridge will be
disabled and then reconfigured when needed.

Thanks,
Adam


-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[RFC][PATCH] Add PCI<->PCI bridge driver [4/9]

2005-07-14 Thread Adam Belay
This patch adds a basic PCI<->PCI bridge driver that utilizes the new
PCI bus class API.

Signed-off-by: Adam Belay <[EMAIL PROTECTED]>

--- a/drivers/pci/bus/pci-bridge.c  1969-12-31 19:00:00.0 -0500
+++ b/drivers/pci/bus/pci-bridge.c  2005-07-08 02:18:43.0 -0400
@@ -0,0 +1,165 @@
+/*
+ * pci-bridge.c - a generic PCI bus driver for PCI<->PCI bridges
+ *
+ */
+
+#include 
+#include 
+#include 
+
+static struct pci_device_id ppb_id_tbl[] = {
+   { PCI_DEVICE_CLASS(PCI_CLASS_BRIDGE_PCI << 8, 0x00) },
+   { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, ppb_id_tbl);
+
+/**
+ * ppb_create_bus - allocates a bus and fills in basic information
+ * @dev: the pci bridge device
+ */
+static struct pci_bus * ppb_create_bus(struct pci_dev *dev)
+{
+   int i;
+   struct pci_bus *bus = pci_alloc_bus();
+
+   if (!bus)
+   return NULL;
+
+   bus->parent = dev->bus;
+   bus->bridge = >dev;
+   bus->ops = bus->parent->ops;
+   bus->sysdata = bus->parent->sysdata;
+   bus->bridge = get_device(>dev);
+
+   /* Set up default resource pointers and names.. */
+   for (i = 0; i < 4; i++) {
+   bus->resource[i] = >resource[PCI_BRIDGE_RESOURCES+i];
+   bus->resource[i]->name = bus->name;
+   }
+
+   return bus;
+}
+
+/**
+ * ppb_detect_bus - creates a bus and reads configuration space data
+ * @dev: the pci bridge device
+ *
+ * This function will do some verification to ensure we should drive this
+ * bridge.
+ */
+static struct pci_bus * ppb_detect_bus(struct pci_dev *dev)
+{
+   struct pci_bus *bus;
+   u32 buses;
+   u16 bctl;
+   unsigned int busnr;
+
+   pci_read_config_dword(dev, PCI_PRIMARY_BUS, );
+   busnr = (buses >> 8) & 0xFF;
+
+   /*
+* FIXME: This driver currently doesn't support bridges that haven't
+* been configured by the BIOS.
+*/
+   if (!(buses & 0x00)) {
+   printk(KERN_INFO "PCI: Unable to drive bus %04x:%02x\n",
+   pci_domain_nr(dev->bus), busnr);
+   return NULL;
+   }
+
+   /*
+* If we already got to this bus through a different bridge,
+* ignore it.  This can happen with the i450NX chipset.
+*/
+   if (pci_find_bus(pci_domain_nr(dev->bus), busnr)) {
+   printk(KERN_INFO "PCI: Bus %04x:%02x already known\n",
+   pci_domain_nr(dev->bus), busnr);
+   return NULL;
+   }
+
+   bus = ppb_create_bus(dev);
+   if (!bus)
+   return NULL;
+
+   /* Disable MasterAbortMode during probing to avoid reporting
+* of bus errors (in some architectures)
+*/ 
+   pci_read_config_word(dev, PCI_BRIDGE_CONTROL, );
+   pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
+ bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT);
+
+   bus->number = bus->secondary = busnr;
+   bus->primary = buses & 0xFF;
+   bus->subordinate = (buses >> 16) & 0xFF;
+   bus->bridge_ctl = bctl;
+
+   return bus;
+}
+
+/**
+ * ppb_detect_children - detects and registers child devices
+ * @bus: pci bus
+ */
+static void ppb_detect_children(struct pci_bus *bus)
+{
+   unsigned int devfn;
+
+   /* Go find them, Rover! */
+   for (devfn = 0; devfn < 0x100; devfn += 8)
+   pci_scan_slot(bus, devfn);
+
+   pcibios_fixup_bus(bus);
+   pci_bus_add_devices(bus);
+}
+
+static int ppb_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+   int err;
+   struct pci_bus *bus;
+
+   if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
+   return -ENODEV;
+
+   bus = ppb_detect_bus(dev);
+   if (!bus)
+   return -ENODEV;
+
+   err = pci_add_bus(bus);
+   if (err)
+   goto out;
+
+   dev->subordinate = bus;
+   ppb_detect_children(bus);
+   return 0;
+
+out:
+   kfree(bus);
+   return err;
+}
+
+static void ppb_remove(struct pci_dev *dev)
+{
+   pci_remove_behind_bridge(dev);
+   pci_remove_bus(dev->subordinate);
+}
+
+static struct pci_driver ppb_driver = {
+   .name   = "pci-bridge",
+   .id_table   = ppb_id_tbl,
+   .probe  = ppb_probe,
+   .remove = ppb_remove,
+};
+
+static int __init ppb_init(void)
+{
+   return pci_register_driver(_driver);
+}
+
+static void __exit ppb_exit(void)
+{
+   pci_unregister_driver(_driver);
+}
+
+module_init(ppb_init);
+module_exit(ppb_exit);
--- a/drivers/pci/bus/Makefile  2005-07-07 22:22:49.0 -0400
+++ b/drivers/pci/bus/Makefile  2005-07-08 02:16:39.0 -0400
@@ -2,4 +2,4 @@
 # Makefile for the PCI device detection
 #
 
-obj-y :=  bus.o config.o device.o probe.o
+obj-y :=  bus.o config.o device.o probe.o pci-bridge.o


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info 

[RFC][PATCH] Add PCI-PCI bridge driver [4/9]

2005-07-14 Thread Adam Belay
This patch adds a basic PCI-PCI bridge driver that utilizes the new
PCI bus class API.

Signed-off-by: Adam Belay [EMAIL PROTECTED]

--- a/drivers/pci/bus/pci-bridge.c  1969-12-31 19:00:00.0 -0500
+++ b/drivers/pci/bus/pci-bridge.c  2005-07-08 02:18:43.0 -0400
@@ -0,0 +1,165 @@
+/*
+ * pci-bridge.c - a generic PCI bus driver for PCI-PCI bridges
+ *
+ */
+
+#include linux/pci.h
+#include linux/init.h
+#include linux/module.h
+
+static struct pci_device_id ppb_id_tbl[] = {
+   { PCI_DEVICE_CLASS(PCI_CLASS_BRIDGE_PCI  8, 0x00) },
+   { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, ppb_id_tbl);
+
+/**
+ * ppb_create_bus - allocates a bus and fills in basic information
+ * @dev: the pci bridge device
+ */
+static struct pci_bus * ppb_create_bus(struct pci_dev *dev)
+{
+   int i;
+   struct pci_bus *bus = pci_alloc_bus();
+
+   if (!bus)
+   return NULL;
+
+   bus-parent = dev-bus;
+   bus-bridge = dev-dev;
+   bus-ops = bus-parent-ops;
+   bus-sysdata = bus-parent-sysdata;
+   bus-bridge = get_device(dev-dev);
+
+   /* Set up default resource pointers and names.. */
+   for (i = 0; i  4; i++) {
+   bus-resource[i] = dev-resource[PCI_BRIDGE_RESOURCES+i];
+   bus-resource[i]-name = bus-name;
+   }
+
+   return bus;
+}
+
+/**
+ * ppb_detect_bus - creates a bus and reads configuration space data
+ * @dev: the pci bridge device
+ *
+ * This function will do some verification to ensure we should drive this
+ * bridge.
+ */
+static struct pci_bus * ppb_detect_bus(struct pci_dev *dev)
+{
+   struct pci_bus *bus;
+   u32 buses;
+   u16 bctl;
+   unsigned int busnr;
+
+   pci_read_config_dword(dev, PCI_PRIMARY_BUS, buses);
+   busnr = (buses  8)  0xFF;
+
+   /*
+* FIXME: This driver currently doesn't support bridges that haven't
+* been configured by the BIOS.
+*/
+   if (!(buses  0x00)) {
+   printk(KERN_INFO PCI: Unable to drive bus %04x:%02x\n,
+   pci_domain_nr(dev-bus), busnr);
+   return NULL;
+   }
+
+   /*
+* If we already got to this bus through a different bridge,
+* ignore it.  This can happen with the i450NX chipset.
+*/
+   if (pci_find_bus(pci_domain_nr(dev-bus), busnr)) {
+   printk(KERN_INFO PCI: Bus %04x:%02x already known\n,
+   pci_domain_nr(dev-bus), busnr);
+   return NULL;
+   }
+
+   bus = ppb_create_bus(dev);
+   if (!bus)
+   return NULL;
+
+   /* Disable MasterAbortMode during probing to avoid reporting
+* of bus errors (in some architectures)
+*/ 
+   pci_read_config_word(dev, PCI_BRIDGE_CONTROL, bctl);
+   pci_write_config_word(dev, PCI_BRIDGE_CONTROL,
+ bctl  ~PCI_BRIDGE_CTL_MASTER_ABORT);
+
+   bus-number = bus-secondary = busnr;
+   bus-primary = buses  0xFF;
+   bus-subordinate = (buses  16)  0xFF;
+   bus-bridge_ctl = bctl;
+
+   return bus;
+}
+
+/**
+ * ppb_detect_children - detects and registers child devices
+ * @bus: pci bus
+ */
+static void ppb_detect_children(struct pci_bus *bus)
+{
+   unsigned int devfn;
+
+   /* Go find them, Rover! */
+   for (devfn = 0; devfn  0x100; devfn += 8)
+   pci_scan_slot(bus, devfn);
+
+   pcibios_fixup_bus(bus);
+   pci_bus_add_devices(bus);
+}
+
+static int ppb_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+   int err;
+   struct pci_bus *bus;
+
+   if (dev-hdr_type != PCI_HEADER_TYPE_BRIDGE)
+   return -ENODEV;
+
+   bus = ppb_detect_bus(dev);
+   if (!bus)
+   return -ENODEV;
+
+   err = pci_add_bus(bus);
+   if (err)
+   goto out;
+
+   dev-subordinate = bus;
+   ppb_detect_children(bus);
+   return 0;
+
+out:
+   kfree(bus);
+   return err;
+}
+
+static void ppb_remove(struct pci_dev *dev)
+{
+   pci_remove_behind_bridge(dev);
+   pci_remove_bus(dev-subordinate);
+}
+
+static struct pci_driver ppb_driver = {
+   .name   = pci-bridge,
+   .id_table   = ppb_id_tbl,
+   .probe  = ppb_probe,
+   .remove = ppb_remove,
+};
+
+static int __init ppb_init(void)
+{
+   return pci_register_driver(ppb_driver);
+}
+
+static void __exit ppb_exit(void)
+{
+   pci_unregister_driver(ppb_driver);
+}
+
+module_init(ppb_init);
+module_exit(ppb_exit);
--- a/drivers/pci/bus/Makefile  2005-07-07 22:22:49.0 -0400
+++ b/drivers/pci/bus/Makefile  2005-07-08 02:16:39.0 -0400
@@ -2,4 +2,4 @@
 # Makefile for the PCI device detection
 #
 
-obj-y :=  bus.o config.o device.o probe.o
+obj-y :=  bus.o config.o device.o probe.o pci-bridge.o


-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More