aboutsummaryrefslogtreecommitdiff
path: root/src/devices
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices')
-rw-r--r--src/devices/Config.lb6
-rw-r--r--src/devices/agp_device.c54
-rw-r--r--src/devices/device.c164
-rw-r--r--src/devices/device_util.c68
-rw-r--r--src/devices/hypertransport.c388
-rw-r--r--src/devices/pci_device.c566
-rw-r--r--src/devices/pciexp_device.c60
-rw-r--r--src/devices/pcix_device.c140
-rw-r--r--src/devices/pnp_device.c6
-rw-r--r--src/devices/root_device.c72
10 files changed, 1093 insertions, 431 deletions
diff --git a/src/devices/Config.lb b/src/devices/Config.lb
index 8de8d4af32..6ba7472cc7 100644
--- a/src/devices/Config.lb
+++ b/src/devices/Config.lb
@@ -3,8 +3,12 @@ object device.o
object root_device.o
object device_util.o
object pci_device.o
-object pnp_device.o
object hypertransport.o
+object pcix_device.o
+object pciexp_device.o
+object agp_device.o
+object cardbus_device.o
+object pnp_device.o
object pci_ops.o
object smbus_ops.o
diff --git a/src/devices/agp_device.c b/src/devices/agp_device.c
new file mode 100644
index 0000000000..27ae36eefd
--- /dev/null
+++ b/src/devices/agp_device.c
@@ -0,0 +1,54 @@
+/* (c) 2005 Linux Networx GPL see COPYING for details */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/agp.h>
+
+static void agp_tune_dev(device_t dev)
+{
+ unsigned cap;
+ cap = pci_find_capability(dev, PCI_CAP_ID_AGP);
+ if (!cap) {
+ return;
+ }
+ /* The OS is responsible for AGP tuning so do nothing here */
+}
+
+unsigned int agp_scan_bus(struct bus *bus,
+ unsigned min_devfn, unsigned max_devfn, unsigned int max)
+{
+ device_t child;
+ max = pci_scan_bus(bus, min_devfn, max_devfn, max);
+ for(child = bus->children; child; child = child->sibling) {
+ if ( (child->path.u.pci.devfn < min_devfn) ||
+ (child->path.u.pci.devfn > max_devfn))
+ {
+ continue;
+ }
+ agp_tune_dev(child);
+ }
+ return max;
+}
+
+unsigned int agp_scan_bridge(device_t dev, unsigned int max)
+{
+ return do_pci_scan_bridge(dev, max, agp_scan_bus);
+}
+
+/** Default device operations for AGP bridges */
+static struct pci_operations agp_bus_ops_pci = {
+ .set_subsystem = 0,
+};
+
+struct device_operations default_agp_ops_bus = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = 0,
+ .scan_bus = agp_scan_bridge,
+ .enable = 0,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = &agp_bus_ops_pci,
+};
diff --git a/src/devices/device.c b/src/devices/device.c
index d2c435fb72..303a669d9f 100644
--- a/src/devices/device.c
+++ b/src/devices/device.c
@@ -58,7 +58,7 @@ device_t alloc_dev(struct bus *parent, struct device_path *path)
spin_lock(&dev_lock);
/* Find the last child of our parent */
- for (child = parent->children; child && child->sibling; ) {
+ for(child = parent->children; child && child->sibling; ) {
child = child->sibling;
}
@@ -70,7 +70,7 @@ device_t alloc_dev(struct bus *parent, struct device_path *path)
memcpy(&dev->path, path, sizeof(*path));
/* Initialize the back pointers in the link fields */
- for (link = 0; link < MAX_LINKS; link++) {
+ for(link = 0; link < MAX_LINKS; link++) {
dev->link[link].dev = dev;
dev->link[link].link = link;
}
@@ -119,10 +119,10 @@ static void read_resources(struct bus *bus)
struct device *curdev;
printk_spew("%s read_resources bus %d link: %d\n",
- dev_path(bus->dev), bus->secondary, bus->link);
+ dev_path(bus->dev), bus->secondary, bus->link);
/* Walk through all of the devices and find which resources they need. */
- for (curdev = bus->children; curdev; curdev = curdev->sibling) {
+ for(curdev = bus->children; curdev; curdev = curdev->sibling) {
unsigned links;
int i;
if (curdev->have_resources) {
@@ -140,7 +140,7 @@ static void read_resources(struct bus *bus)
curdev->have_resources = 1;
/* Read in subtractive resources behind the current device */
links = 0;
- for (i = 0; i < curdev->resources; i++) {
+ for(i = 0; i < curdev->resources; i++) {
struct resource *resource;
unsigned link;
resource = &curdev->resource[i];
@@ -149,18 +149,17 @@ static void read_resources(struct bus *bus)
link = IOINDEX_SUBTRACTIVE_LINK(resource->index);
if (link > MAX_LINKS) {
printk_err("%s subtractive index on link: %d\n",
- dev_path(curdev), link);
+ dev_path(curdev), link);
continue;
}
if (!(links & (1 << link))) {
links |= (1 << link);
- read_resources(&curdev->link[resource->index]);
-
+ read_resources(&curdev->link[link]);
}
}
}
printk_spew("%s read_resources bus %d link: %d done\n",
- dev_path(bus->dev), bus->secondary, bus->link);
+ dev_path(bus->dev), bus->secondary, bus->link);
}
struct pick_largest_state {
@@ -181,6 +180,7 @@ static void pick_largest_resource(void *gp,
state->seen_last = 1;
return;
}
+ if (resource->flags & IORESOURCE_FIXED ) return; //skip it
if (last && (
(last->align < resource->align) ||
((last->align == resource->align) &&
@@ -191,9 +191,10 @@ static void pick_largest_resource(void *gp,
return;
}
if (!state->result ||
- (state->result->align < resource->align) ||
- ((state->result->align == resource->align) &&
- (state->result->size < resource->size))) {
+ (state->result->align < resource->align) ||
+ ((state->result->align == resource->align) &&
+ (state->result->size < resource->size)))
+ {
state->result_dev = dev;
state->result = resource;
}
@@ -258,10 +259,10 @@ void compute_allocate_resource(
base = bridge->base;
printk_spew("%s compute_allocate_%s: base: %08Lx size: %08Lx align: %d gran: %d\n",
- dev_path(bus->dev),
- (bridge->flags & IORESOURCE_IO)? "io":
- (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
- base, bridge->size, bridge->align, bridge->gran);
+ dev_path(bus->dev),
+ (bridge->flags & IORESOURCE_IO)? "io":
+ (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
+ base, bridge->size, bridge->align, bridge->gran);
/* We want different minimum alignments for different kinds of
* resources. These minimums are not device type specific
@@ -283,7 +284,7 @@ void compute_allocate_resource(
/* Walk through all the devices on the current bus and
* compute the addresses.
*/
- while ((dev = largest_resource(bus, &resource, type_mask, type))) {
+ while((dev = largest_resource(bus, &resource, type_mask, type))) {
resource_t size;
/* Do NOT I repeat do not ignore resources which have zero size.
* If they need to be ignored dev->read_resources should not even
@@ -301,9 +302,11 @@ void compute_allocate_resource(
if (align < min_align) {
align = min_align;
}
+
if (resource->flags & IORESOURCE_FIXED) {
continue;
}
+
/* Propogate the resource limit to the bridge register */
if (bridge->limit > resource->limit) {
bridge->limit = resource->limit;
@@ -338,13 +341,14 @@ void compute_allocate_resource(
resource->flags &= ~IORESOURCE_STORED;
base += size;
- printk_spew("%s %02x * [0x%08Lx - 0x%08Lx] %s\n",
- dev_path(dev),
- resource->index,
- resource->base,
- resource->base + resource->size - 1,
- (resource->flags & IORESOURCE_IO)? "io":
- (resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem");
+ printk_spew(
+ "%s %02x * [0x%08Lx - 0x%08Lx] %s\n",
+ dev_path(dev),
+ resource->index,
+ resource->base,
+ resource->base + resource->size - 1,
+ (resource->flags & IORESOURCE_IO)? "io":
+ (resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem");
}
}
/* A pci bridge resource does not need to be a power
@@ -356,15 +360,16 @@ void compute_allocate_resource(
bridge->size = round(base, bridge->gran) - bridge->base;
printk_spew("%s compute_allocate_%s: base: %08Lx size: %08Lx align: %d gran: %d done\n",
- dev_path(bus->dev),
- (bridge->flags & IORESOURCE_IO)? "io":
- (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
- base, bridge->size, bridge->align, bridge->gran);
+ dev_path(bus->dev),
+ (bridge->flags & IORESOURCE_IO)? "io":
+ (bridge->flags & IORESOURCE_PREFETCH)? "prefmem" : "mem",
+ base, bridge->size, bridge->align, bridge->gran);
}
#if CONFIG_CONSOLE_VGA == 1
+
device_t vga_pri = 0;
static void allocate_vga_resource(void)
{
@@ -377,10 +382,11 @@ static void allocate_vga_resource(void)
bus = 0;
vga = 0;
vga_onboard = 0;
- for (dev = all_devices; dev; dev = dev->next) {
+ for(dev = all_devices; dev; dev = dev->next) {
if (!dev->enabled) continue;
if (((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
- ((dev->class >> 8) != PCI_CLASS_DISPLAY_OTHER)) {
+ ((dev->class >> 8) != PCI_CLASS_DISPLAY_OTHER))
+ {
if (!vga) {
if (dev->on_mainboard) {
vga_onboard = dev;
@@ -398,14 +404,15 @@ static void allocate_vga_resource(void)
}
if (vga) {
- // vga is first add on card or the only onboard vga
+ /* vga is first add on card or the only onboard vga */
printk_debug("Allocating VGA resource %s\n", dev_path(vga));
+ /* All legacy VGA cards have MEM & I/O space registers */
vga->command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
vga_pri = vga;
bus = vga->bus;
}
/* Now walk up the bridges setting the VGA enable */
- while (bus) {
+ while(bus) {
printk_debug("Setting PCI_BRIDGE_CTL_VGA for bridge %s\n",
dev_path(bus->dev));
bus->bridge_ctrl |= PCI_BRIDGE_CTL_VGA;
@@ -435,7 +442,7 @@ void assign_resources(struct bus *bus)
printk_spew("%s assign_resources, bus %d link: %d\n",
dev_path(bus->dev), bus->secondary, bus->link);
- for (curdev = bus->children; curdev; curdev = curdev->sibling) {
+ for(curdev = bus->children; curdev; curdev = curdev->sibling) {
if (!curdev->enabled || !curdev->resources) {
continue;
}
@@ -480,6 +487,70 @@ void enable_resources(struct device *dev)
dev->ops->enable_resources(dev);
}
+/**
+ * @brief Reset all of the devices a bus
+ *
+ * Reset all of the devices on a bus and clear the bus's reset_needed flag.
+ *
+ * @param bus pointer to the bus structure
+ *
+ * @return 1 if the bus was successfully reset, 0 otherwise.
+ *
+ */
+int reset_bus(struct bus *bus)
+{
+ device_t dev;
+ if (bus && bus->dev && bus->dev->ops && bus->dev->ops->reset_bus)
+ {
+ bus->dev->ops->reset_bus(bus);
+ bus->reset_needed = 0;
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * @brief Scan for devices on a bus.
+ *
+ * If there are bridges on the bus, recursively scan the buses behind the bridges.
+ * If the setting up and tuning of the bus causes a reset to be required,
+ * reset the bus and scan it again.
+ *
+ * @param bus pointer to the bus device
+ * @param max current bus number
+ *
+ * @return The maximum bus number found, after scanning all subordinate busses
+ */
+unsigned int scan_bus(device_t bus, unsigned int max)
+{
+ unsigned int new_max;
+ int do_scan_bus;
+ if ( !bus ||
+ !bus->enabled ||
+ !bus->ops ||
+ !bus->ops->scan_bus)
+ {
+ return max;
+ }
+ do_scan_bus = 1;
+ while(do_scan_bus) {
+ int link;
+ new_max = bus->ops->scan_bus(bus, max);
+ do_scan_bus = 0;
+ for(link = 0; link < bus->links; link++) {
+ if (bus->link[link].reset_needed) {
+ if (reset_bus(&bus->link[link])) {
+ do_scan_bus = 1;
+ } else {
+ bus->bus->reset_needed = 1;
+ }
+ }
+ }
+ }
+ return new_max;
+}
+
+
/**
* @brief Determine the existence of devices and extend the device tree.
*
@@ -515,7 +586,7 @@ void dev_enumerate(void)
printk_err("dev_root missing scan_bus operation");
return;
}
- subordinate = root->ops->scan_bus(root, 0);
+ subordinate = scan_bus(root, 0);
printk_info("done\n");
}
@@ -613,18 +684,19 @@ void dev_initialize(void)
struct device *dev;
printk_info("Initializing devices...\n");
-
- for (dev = all_devices; dev; dev = dev->next) {
- if (dev->enabled && !dev->initialized &&
- dev->ops && dev->ops->init)
- {
- if(dev->path.type == DEVICE_PATH_I2C)
- printk_debug("smbus: %s[%d]->", dev_path(dev->bus->dev), dev->bus->link );
- printk_debug("%s init\n", dev_path(dev));
- dev->initialized = 1;
- dev->ops->init(dev);
- }
- }
+ for(dev = all_devices; dev; dev = dev->next) {
+ if (dev->enabled && !dev->initialized &&
+ dev->ops && dev->ops->init)
+ {
+ if (dev->path.type == DEVICE_PATH_I2C) {
+ printk_debug("smbus: %s[%d]->",
+ dev_path(dev->bus->dev), dev->bus->link);
+ }
+ printk_debug("%s init\n", dev_path(dev));
+ dev->initialized = 1;
+ dev->ops->init(dev);
+ }
+ }
printk_info("Devices initialized\n");
}
diff --git a/src/devices/device_util.c b/src/devices/device_util.c
index a19a878b47..fa2adaef4f 100644
--- a/src/devices/device_util.c
+++ b/src/devices/device_util.c
@@ -16,7 +16,7 @@
device_t find_dev_path(struct bus *parent, struct device_path *path)
{
device_t child;
- for (child = parent->children; child; child = child->sibling) {
+ for(child = parent->children; child; child = child->sibling) {
if (path_eq(path, &child->path)) {
break;
}
@@ -178,6 +178,14 @@ const char *dev_path(device_t dev)
return buffer;
}
+const char *bus_path(struct bus *bus)
+{
+ static char buffer[BUS_PATH_MAX];
+ sprintf(buffer, "%s,%d",
+ dev_path(bus->dev), bus->link);
+ return buffer;
+}
+
int path_eq(struct device_path *path1, struct device_path *path2)
{
int equal = 0;
@@ -390,12 +398,30 @@ resource_t resource_max(struct resource *resource)
}
/**
+ * @brief return the resource type of a resource
+ * @param resource the resource type to decode.
+ */
+const char *resource_type(struct resource *resource)
+{
+ static char buffer[RESOURCE_TYPE_MAX];
+ sprintf(buffer, "%s%s%s%s",
+ ((resource->flags & IORESOURCE_READONLY)? "ro": ""),
+ ((resource->flags & IORESOURCE_PREFETCH)? "pref":""),
+ ((resource->flags == 0)? "unused":
+ (resource->flags & IORESOURCE_IO)? "io":
+ (resource->flags & IORESOURCE_DRQ)? "drq":
+ (resource->flags & IORESOURCE_IRQ)? "irq":
+ (resource->flags & IORESOURCE_MEM)? "mem":"??????"),
+ ((resource->flags & IORESOURCE_PCI64)?"64":""));
+ return buffer;
+}
+
+/**
* @brief print the resource that was just stored.
* @param dev the device the stored resorce lives on
* @param resource the resource that was just stored.
*/
-void report_resource_stored(device_t dev, struct resource *resource,
- const char *comment)
+void report_resource_stored(device_t dev, struct resource *resource, const char *comment)
{
if (resource->flags & IORESOURCE_STORED) {
unsigned char buf[10];
@@ -407,18 +433,12 @@ void report_resource_stored(device_t dev, struct resource *resource,
sprintf(buf, "bus %d ", dev->link[0].secondary);
}
printk_debug(
- "%s %02x <- [0x%010Lx - 0x%010Lx] %s%s%s%s\n",
+ "%s %02x <- [0x%010Lx - 0x%010Lx] %s%s%s\n",
dev_path(dev),
resource->index,
base, end,
buf,
- (resource->flags & IORESOURCE_PREFETCH) ? "pref" : "",
- (resource->flags & IORESOURCE_IO)? "io":
- (resource->flags & IORESOURCE_DRQ)? "drq":
- (resource->flags & IORESOURCE_IRQ)? "irq":
- (resource->flags & IORESOURCE_READONLY)? "rom":
- (resource->flags & IORESOURCE_MEM)? "mem":
- "????",
+ resource_type(resource),
comment);
}
}
@@ -473,3 +493,29 @@ void search_global_resources(
}
}
}
+
+void dev_set_enabled(device_t dev, int enable)
+{
+ if (dev->enabled == enable) {
+ return;
+ }
+ dev->enabled = enable;
+ if (dev->ops && dev->ops->enable) {
+ dev->ops->enable(dev);
+ }
+ else if (dev->chip_ops && dev->chip_ops->enable_dev) {
+ dev->chip_ops->enable_dev(dev);
+ }
+}
+
+void disable_children(struct bus *bus)
+{
+ device_t child;
+ for(child = bus->children; child; child = child->sibling) {
+ int link;
+ for(link = 0; link < child->links; link++) {
+ disable_children(&child->link[link]);
+ }
+ dev_set_enabled(child, 0);
+ }
+}
diff --git a/src/devices/hypertransport.c b/src/devices/hypertransport.c
index 80c621ed79..a30c8f6a8d 100644
--- a/src/devices/hypertransport.c
+++ b/src/devices/hypertransport.c
@@ -9,7 +9,7 @@
#include <part/fallback_boot.h>
#define OPT_HT_LINK 0
-
+
#if OPT_HT_LINK == 1
#include "../northbridge/amd/amdk8/cpu_rev.c"
#endif
@@ -19,17 +19,37 @@ static device_t ht_scan_get_devs(device_t *old_devices)
device_t first, last;
first = *old_devices;
last = first;
+ /* Extract the chain of devices to (first through last)
+ * for the next hypertransport device.
+ */
while(last && last->sibling &&
(last->sibling->path.type == DEVICE_PATH_PCI) &&
- (last->sibling->path.u.pci.devfn > last->path.u.pci.devfn)) {
+ (last->sibling->path.u.pci.devfn > last->path.u.pci.devfn))
+ {
last = last->sibling;
}
if (first) {
+ device_t child;
+ /* Unlink the chain from the list of old devices */
*old_devices = last->sibling;
last->sibling = 0;
+
+ /* Now add the device to the list of devices on the bus.
+ */
+ /* Find the last child of our parent */
+ for(child = first->bus->children; child && child->sibling; ) {
+ child = child->sibling;
+ }
+ /* Place the chain on the list of children of their parent. */
+ if (child) {
+ child->sibling = first;
+ } else {
+ first->bus->children = first;
+ }
}
return first;
}
+
#if OPT_HT_LINK == 1
static unsigned ht_read_freq_cap(device_t dev, unsigned pos)
{
@@ -43,30 +63,37 @@ static unsigned ht_read_freq_cap(device_t dev, unsigned pos)
if ((dev->vendor == PCI_VENDOR_ID_AMD) &&
(dev->device == PCI_DEVICE_ID_AMD_8131_PCIX)) {
freq_cap &= ~(1 << HT_FREQ_800Mhz);
- } else
+ }
/* AMD 8151 Errata 23 */
if ((dev->vendor == PCI_VENDOR_ID_AMD) &&
(dev->device == PCI_DEVICE_ID_AMD_8151_SYSCTRL)) {
freq_cap &= ~(1 << HT_FREQ_800Mhz);
- } else
+ }
/* AMD K8 Unsupported 1Ghz? */
if ((dev->vendor == PCI_VENDOR_ID_AMD) && (dev->device == 0x1100)) {
+#if K8_HT_FREQ_1G_SUPPORT == 1
if (is_cpu_pre_e0())
+#endif
+ {
freq_cap &= ~(1 << HT_FREQ_1000Mhz);
+ }
+
}
return freq_cap;
}
+#endif
-struct prev_link {
+struct ht_link {
struct device *dev;
unsigned pos;
- unsigned char config_off, freq_off, freq_cap_off;
+ unsigned char ctrl_off, config_off, freq_off, freq_cap_off;
};
-static int ht_setup_link(struct prev_link *prev, device_t dev, unsigned pos)
+static int ht_setup_link(struct ht_link *prev, device_t dev, unsigned pos)
{
static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 };
static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 };
+ struct ht_link cur[1];
unsigned present_width_cap, upstream_width_cap;
unsigned present_freq_cap, upstream_freq_cap;
unsigned ln_present_width_in, ln_upstream_width_in;
@@ -78,13 +105,30 @@ static int ht_setup_link(struct prev_link *prev, device_t dev, unsigned pos)
/* Set the hypertransport link width and frequency */
reset_needed = 0;
- linkb_to_host = (pci_read_config16(dev, pos + PCI_CAP_FLAGS) >> 10) & 1;
-
+ /* See which side of the device our previous write to
+ * set the unitid came from.
+ */
+ cur->dev = dev;
+ cur->pos = pos;
+ linkb_to_host = (pci_read_config16(cur->dev, cur->pos + PCI_CAP_FLAGS) >> 10) & 1;
+ if (!linkb_to_host) {
+ cur->ctrl_off = PCI_HT_CAP_SLAVE_CTRL0;
+ cur->config_off = PCI_HT_CAP_SLAVE_WIDTH0;
+ cur->freq_off = PCI_HT_CAP_SLAVE_FREQ0;
+ cur->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP0;
+ }
+ else {
+ cur->ctrl_off = PCI_HT_CAP_SLAVE_CTRL1;
+ cur->config_off = PCI_HT_CAP_SLAVE_WIDTH1;
+ cur->freq_off = PCI_HT_CAP_SLAVE_FREQ1;
+ cur->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP1;
+ }
+#if OPT_HT_LINK == 1
/* Read the capabilities */
- present_freq_cap = ht_read_freq_cap(dev, pos + (linkb_to_host ? PCI_HT_CAP_SLAVE_FREQ_CAP1: PCI_HT_CAP_SLAVE_FREQ_CAP0));
+ present_freq_cap = ht_read_freq_cap(cur->dev, cur->pos + cur->freq_cap_off);
upstream_freq_cap = ht_read_freq_cap(prev->dev, prev->pos + prev->freq_cap_off);
- present_width_cap = pci_read_config8(dev, pos + (linkb_to_host ? PCI_HT_CAP_SLAVE_WIDTH1: PCI_HT_CAP_SLAVE_WIDTH0));
- upstream_width_cap = pci_read_config8(prev->dev, prev->pos + prev->config_off);
+ present_width_cap = pci_read_config8(cur->dev, cur->pos + cur->config_off);
+ upstream_width_cap = pci_read_config8(prev->dev, prev->pos + prev->config_off);
/* Calculate the highest useable frequency */
freq = log2(present_freq_cap & upstream_freq_cap);
@@ -107,87 +151,130 @@ static int ht_setup_link(struct prev_link *prev, device_t dev, unsigned pos)
present_width |= pow2_to_link_width[ln_upstream_width_out];
/* Set the current device */
- old_freq = pci_read_config8(dev, pos + (linkb_to_host ? PCI_HT_CAP_SLAVE_FREQ1:PCI_HT_CAP_SLAVE_FREQ0));
+ old_freq = pci_read_config8(cur->dev, cur->pos + cur->freq_off);
+ old_freq &= 0x0f;
if (freq != old_freq) {
- pci_write_config8(dev, pos + (linkb_to_host ? PCI_HT_CAP_SLAVE_FREQ1:PCI_HT_CAP_SLAVE_FREQ0), freq);
+ unsigned new_freq;
+ pci_write_config8(cur->dev, cur->pos + cur->freq_off, freq);
reset_needed = 1;
printk_spew("HyperT FreqP old %x new %x\n",old_freq,freq);
+ new_freq = pci_read_config8(cur->dev, cur->pos + cur->freq_off);
+ new_freq &= 0x0f;
+ if (new_freq != freq) {
+ printk_err("%s Hypertransport frequency would not set wanted: %x got: %x\n",
+ dev_path(dev), freq, new_freq);
+ }
}
- old_width = pci_read_config8(dev, pos + (linkb_to_host ? PCI_HT_CAP_SLAVE_WIDTH1: PCI_HT_CAP_SLAVE_WIDTH0) + 1);
+ old_width = pci_read_config8(cur->dev, cur->pos + cur->config_off + 1);
if (present_width != old_width) {
- pci_write_config8(dev, pos + (linkb_to_host ? PCI_HT_CAP_SLAVE_WIDTH1: PCI_HT_CAP_SLAVE_WIDTH0) + 1, present_width);
+ unsigned new_width;
+ pci_write_config8(cur->dev, cur->pos + cur->config_off + 1,
+ present_width);
reset_needed = 1;
printk_spew("HyperT widthP old %x new %x\n",old_width, present_width);
+ new_width = pci_read_config8(cur->dev, cur->pos + cur->config_off + 1);
+ if (new_width != present_width) {
+ printk_err("%s Hypertransport width would not set wanted: %x got: %x\n",
+ dev_path(dev), present_width, new_width);
+ }
}
/* Set the upstream device */
old_freq = pci_read_config8(prev->dev, prev->pos + prev->freq_off);
old_freq &= 0x0f;
if (freq != old_freq) {
+ unsigned new_freq;
pci_write_config8(prev->dev, prev->pos + prev->freq_off, freq);
reset_needed = 1;
printk_spew("HyperT freqU old %x new %x\n", old_freq, freq);
+ new_freq = pci_read_config8(prev->dev, prev->pos + prev->freq_off);
+ new_freq &= 0x0f;
+ if (new_freq != freq) {
+ printk_err("%s Hypertransport frequency would not set wanted: %x got: %x\n",
+ dev_path(prev->dev), freq, new_freq);
+ }
}
old_width = pci_read_config8(prev->dev, prev->pos + prev->config_off + 1);
if (upstream_width != old_width) {
+ unsigned new_width;
pci_write_config8(prev->dev, prev->pos + prev->config_off + 1, upstream_width);
reset_needed = 1;
printk_spew("HyperT widthU old %x new %x\n", old_width, upstream_width);
+ new_width = pci_read_config8(prev->dev, prev->pos + prev->config_off + 1);
+ if (new_width != upstream_width) {
+ printk_err("%s Hypertransport width would not set wanted: %x got: %x\n",
+ dev_path(prev->dev), upstream_width, new_width);
+ }
}
+#endif
- /* Remember the current link as the previous link */
- prev->dev = dev;
- prev->pos = pos;
- if(linkb_to_host) {
- prev->config_off = PCI_HT_CAP_SLAVE_WIDTH0;
- prev->freq_off = PCI_HT_CAP_SLAVE_FREQ0;
- prev->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP0;
- }
- else {
- prev->config_off = PCI_HT_CAP_SLAVE_WIDTH1;
- prev->freq_off = PCI_HT_CAP_SLAVE_FREQ1;
- prev->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP1;
- }
+ /* Remember the current link as the previous link,
+ * But look at the other offsets.
+ */
+ prev->dev = cur->dev;
+ prev->pos = cur->pos;
+ if (cur->ctrl_off == PCI_HT_CAP_SLAVE_CTRL0) {
+ prev->ctrl_off = PCI_HT_CAP_SLAVE_CTRL1;
+ prev->config_off = PCI_HT_CAP_SLAVE_WIDTH1;
+ prev->freq_off = PCI_HT_CAP_SLAVE_FREQ1;
+ prev->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP1;
+ } else {
+ prev->ctrl_off = PCI_HT_CAP_SLAVE_CTRL0;
+ prev->config_off = PCI_HT_CAP_SLAVE_WIDTH0;
+ prev->freq_off = PCI_HT_CAP_SLAVE_FREQ0;
+ prev->freq_cap_off = PCI_HT_CAP_SLAVE_FREQ_CAP0;
+ }
return reset_needed;
}
-#endif
static unsigned ht_lookup_slave_capability(struct device *dev)
{
unsigned pos;
pos = 0;
- switch(dev->hdr_type & 0x7f) {
- case PCI_HEADER_TYPE_NORMAL:
- case PCI_HEADER_TYPE_BRIDGE:
- pos = PCI_CAPABILITY_LIST;
- break;
- }
- if (pos > PCI_CAP_LIST_NEXT) {
- pos = pci_read_config8(dev, pos);
- }
- while(pos != 0) { /* loop through the linked list */
- uint8_t cap;
- cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID);
- printk_spew("Capability: 0x%02x @ 0x%02x\n", cap, pos);
- if (cap == PCI_CAP_ID_HT) {
+ do {
+ pos = pci_find_next_capability(dev, PCI_CAP_ID_HT, pos);
+ if (pos) {
unsigned flags;
flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
- printk_spew("flags: 0x%04x\n", (unsigned)flags);
+ printk_spew("flags: 0x%04x\n", flags);
if ((flags >> 13) == 0) {
- /* Entry is a Slave secondary, success...*/
+ /* Entry is a Slave secondary, success... */
break;
}
}
- pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT);
- }
+ } while(pos);
return pos;
}
static void ht_collapse_early_enumeration(struct bus *bus)
{
unsigned int devfn;
+ struct ht_link prev;
+ unsigned ctrl;
+
+ /* Initialize the hypertransport enumeration state */
+ prev.dev = bus->dev;
+ prev.pos = bus->cap;
+ prev.ctrl_off = PCI_HT_CAP_HOST_CTRL;
+ prev.config_off = PCI_HT_CAP_HOST_WIDTH;
+ prev.freq_off = PCI_HT_CAP_HOST_FREQ;
+ prev.freq_cap_off = PCI_HT_CAP_HOST_FREQ_CAP;
+
+ /* Wait until the link initialization is complete */
+ do {
+ ctrl = pci_read_config16(prev.dev, prev.pos + prev.ctrl_off);
+ /* Is this the end of the hypertransport chain */
+ if (ctrl & (1 << 6)) {
+ return;
+ }
+ /* Has the link failed? */
+ if (ctrl & (1 << 4)) {
+ return;
+ }
+ } while((ctrl & (1 << 5)) == 0);
+
/* Spin through the devices and collapse any early
* hypertransport enumeration.
@@ -200,21 +287,10 @@ static void ht_collapse_early_enumeration(struct bus *bus)
dummy.path.type = DEVICE_PATH_PCI;
dummy.path.u.pci.devfn = devfn;
id = pci_read_config32(&dummy, PCI_VENDOR_ID);
- if (id == 0xffffffff || id == 0x00000000 ||
- id == 0x0000ffff || id == 0xffff0000) {
+ if ( (id == 0xffffffff) || (id == 0x00000000) ||
+ (id == 0x0000ffff) || (id == 0xffff0000)) {
continue;
}
-
-#if 0
-#if CK804_DEVN_BASE==0
- //CK804 workaround:
- // CK804 UnitID changes not use
- if(id == 0x005e10de) {
- break;
- }
-#endif
-#endif
-
dummy.vendor = id & 0xffff;
dummy.device = (id >> 16) & 0xffff;
dummy.hdr_type = pci_read_config8(&dummy, PCI_HEADER_TYPE);
@@ -232,15 +308,13 @@ static void ht_collapse_early_enumeration(struct bus *bus)
}
}
-unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max)
+unsigned int hypertransport_scan_chain(struct bus *bus,
+ unsigned min_devfn, unsigned max_devfn, unsigned int max)
{
- unsigned next_unitid, last_unitid, previous_unitid;
- device_t old_devices, dev, func, *chain_last;
+ unsigned next_unitid, last_unitid;
+ device_t old_devices, dev, func;
unsigned min_unitid = 1;
-#if OPT_HT_LINK == 1
- int reset_needed;
- struct prev_link prev;
-#endif
+ struct ht_link prev;
/* Restore the hypertransport chain to it's unitialized state */
ht_collapse_early_enumeration(bus);
@@ -248,71 +322,48 @@ unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max)
/* See which static device nodes I have */
old_devices = bus->children;
bus->children = 0;
- chain_last = &bus->children;
/* Initialize the hypertransport enumeration state */
-#if OPT_HT_LINK == 1
- reset_needed = 0;
prev.dev = bus->dev;
prev.pos = bus->cap;
+ prev.ctrl_off = PCI_HT_CAP_HOST_CTRL;
prev.config_off = PCI_HT_CAP_HOST_WIDTH;
prev.freq_off = PCI_HT_CAP_HOST_FREQ;
prev.freq_cap_off = PCI_HT_CAP_HOST_FREQ_CAP;
-#endif
/* If present assign unitid to a hypertransport chain */
last_unitid = min_unitid -1;
next_unitid = min_unitid;
do {
- uint32_t id, class;
- uint8_t hdr_type;
- unsigned pos;
+ uint8_t pos;
uint16_t flags;
unsigned count, static_count;
+ unsigned ctrl;
- previous_unitid = last_unitid;
last_unitid = next_unitid;
- /* Get setup the device_structure */
+ /* Wait until the link initialization is complete */
+ do {
+ ctrl = pci_read_config16(prev.dev, prev.pos + prev.ctrl_off);
+ /* Is this the end of the hypertransport chain?
+ * Has the link failed?
+ * If so further scanning is pointless.
+ */
+ if (ctrl & ((1 << 6) | (1 << 4))) {
+ goto end_of_chain;
+ }
+ } while((ctrl & (1 << 5)) == 0);
+
+
+ /* Get and setup the device_structure */
dev = ht_scan_get_devs(&old_devices);
- if (!dev) {
- struct device dummy;
- dummy.bus = bus;
- dummy.path.type = DEVICE_PATH_PCI;
- dummy.path.u.pci.devfn = 0;
- id = pci_read_config32(&dummy, PCI_VENDOR_ID);
- /* If the chain is fully enumerated quit */
- if (id == 0xffffffff || id == 0x00000000 ||
- id == 0x0000ffff || id == 0xffff0000) {
- break;
- }
- dev = alloc_dev(bus, &dummy.path);
- }
- else {
- /* Add this device to the pci bus chain */
- *chain_last = dev;
- /* Run the magice enable sequence for the device */
- if (dev->chip_ops && dev->chip_ops->enable_dev) {
- dev->chip_ops->enable_dev(dev);
- }
- /* Now read the vendor and device id */
- id = pci_read_config32(dev, PCI_VENDOR_ID);
-
- /* If the chain is fully enumerated quit */
- if (id == 0xffffffff || id == 0x00000000 ||
- id == 0x0000ffff || id == 0xffff0000) {
- if (dev->enabled) {
- printk_info("Disabling static device: %s\n",
- dev_path(dev));
- dev->enabled = 0;
- }
- break;
- }
- }
- /* Update the device chain tail */
- for(func = dev; func; func = func->sibling) {
- chain_last = &func->sibling;
+ /* See if a device is present and setup the
+ * device structure.
+ */
+ dev = pci_probe_dev(dev, bus, 0);
+ if (!dev || !dev->enabled) {
+ break;
}
/* Find the hypertransport link capability */
@@ -323,20 +374,29 @@ unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max)
break;
}
-
/* Update the Unitid of the current device */
flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
+
+ /* If the devices has a unitid set and is at devfn 0 we are done.
+ * This can happen with shadow hypertransport devices,
+ * or if we have reached the bottom of a
+ * hypertransport device chain.
+ */
+ if (flags & 0x1f) {
+ break;
+ }
+
flags &= ~0x1f; /* mask out base Unit ID */
#if CK804_DEVN_BASE==0
- if(id == 0x005e10de) {
- next_unitid = 0;
- }
- else {
+ if((dev->vendor == 0x10de) && (dev->device == 0x005e)) {
+ next_unitid = 0;
+ }
+ else {
#endif
- flags |= next_unitid & 0x1f;
- pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
+ flags |= next_unitid & 0x1f;
+ pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
#if CK804_DEVN_BASE==0
- }
+ }
#endif
/* Update the Unitd id in the device structure */
@@ -347,17 +407,6 @@ unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max)
- (dev->path.u.pci.devfn >> 3) + 1;
}
- /* Read the rest of the pci configuration information */
- hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
- class = pci_read_config32(dev, PCI_CLASS_REVISION);
-
- /* Store the interesting information in the device structure */
- dev->vendor = id & 0xffff;
- dev->device = (id >> 16) & 0xffff;
- dev->hdr_type = hdr_type;
- /* class code, the upper 3 bytes of PCI_CLASS_REVISION */
- dev->class = class >> 8;
-
/* Compute the number of unitids consumed */
count = (flags >> 5) & 0x1f; /* get unit count */
printk_spew("%s count: %04x static_count: %04x\n",
@@ -369,36 +418,83 @@ unsigned int hypertransport_scan_chain(struct bus *bus, unsigned int max)
/* Update the Unitid of the next device */
next_unitid += count;
-#if OPT_HT_LINK == 1
/* Setup the hypetransport link */
- reset_needed |= ht_setup_link(&prev, dev, pos);
-#endif
+ bus->reset_needed |= ht_setup_link(&prev, dev, pos);
printk_debug("%s [%04x/%04x] %s next_unitid: %04x\n",
dev_path(dev),
dev->vendor, dev->device,
(dev->enabled? "enabled": "disabled"), next_unitid);
+
#if CK804_DEVN_BASE==0
- if(id == 0x005e10de) {
- break; // CK804 can not change unitid, so it only can be alone in the link
- }
+ if ((dev->vendor == 0x10de) && (dev->device == 0x005e)) {
+ break; // CK804 can not change unitid, so it only can be alone in the link
+ }
#endif
- } while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
-
+ } while((last_unitid != next_unitid) && (next_unitid <= (max_devfn >> 3)));
+ end_of_chain:
#if OPT_HT_LINK == 1
-#if HAVE_HARD_RESET == 1
- if(reset_needed) {
+ if(bus->reset_needed) {
printk_info("HyperT reset needed\n");
- hard_reset();
}
else {
printk_debug("HyperT reset not needed\n");
}
#endif
-#endif
if (next_unitid > 0x1f) {
next_unitid = 0x1f;
}
- return pci_scan_bus(bus, 0x00, (next_unitid << 3)|7, max);
+
+ /* Die if any leftover Static devices are are found.
+ * There's probably a problem in the Config.lb.
+ */
+ if(old_devices) {
+ device_t left;
+ for(left = old_devices; left; left = left->sibling) {
+ printk_debug("%s\n", dev_path(left));
+ }
+ die("Left over static devices. Check your Config.lb\n");
+ }
+
+ /* Now that nothing is overlapping it is safe to scan the
+ * children.
+ */
+ max = pci_scan_bus(bus, 0x00, (next_unitid << 3)|7, max);
+ return max;
+}
+
+/**
+ * @brief Scan a PCI bridge and the buses behind the bridge.
+ *
+ * Determine the existence of buses behind the bridge. Set up the bridge
+ * according to the result of the scan.
+ *
+ * This function is the default scan_bus() method for PCI bridge devices.
+ *
+ * @param dev pointer to the bridge device
+ * @param max the highest bus number assgined up to now
+ *
+ * @return The maximum bus number found, after scanning all subordinate busses
+ */
+unsigned int ht_scan_bridge(struct device *dev, unsigned int max)
+{
+ return do_pci_scan_bridge(dev, max, hypertransport_scan_chain);
}
+
+
+/** Default device operations for hypertransport bridges */
+static struct pci_operations ht_bus_ops_pci = {
+ .set_subsystem = 0,
+};
+
+struct device_operations default_ht_ops_bus = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = 0,
+ .scan_bus = ht_scan_bridge,
+ .enable = 0,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = &ht_bus_ops_pci,
+};
diff --git a/src/devices/pci_device.c b/src/devices/pci_device.c
index 3f9a1cadae..f3f53f0688 100644
--- a/src/devices/pci_device.c
+++ b/src/devices/pci_device.c
@@ -21,8 +21,23 @@
#include <part/hard_reset.h>
#include <part/fallback_boot.h>
#include <delay.h>
+#if CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT == 1
+#include <device/hypertransport.h>
+#endif
+#if CONFIG_PCIX_PLUGIN_SUPPORT == 1
+#include <device/pcix.h>
+#endif
+#if CONFIG_PCIEXP_PLUGIN_SUPPORT == 1
+#include <device/pciexp.h>
+#endif
+#if CONFGI_AGP_PLUGIN_SUPPORT == 1
+#include <device/agp.h>
+#endif
+#if CONFIG_CARDBUS_PLUGIN_SUPPORT == 1
+#include <device/cardbus.h>
+#endif
-static uint8_t pci_moving_config8(struct device *dev, unsigned reg)
+uint8_t pci_moving_config8(struct device *dev, unsigned reg)
{
uint8_t value, ones, zeroes;
value = pci_read_config8(dev, reg);
@@ -38,7 +53,7 @@ static uint8_t pci_moving_config8(struct device *dev, unsigned reg)
return ones ^ zeroes;
}
-static uint16_t pci_moving_config16(struct device *dev, unsigned reg)
+uint16_t pci_moving_config16(struct device *dev, unsigned reg)
{
uint16_t value, ones, zeroes;
value = pci_read_config16(dev, reg);
@@ -54,7 +69,7 @@ static uint16_t pci_moving_config16(struct device *dev, unsigned reg)
return ones ^ zeroes;
}
-static uint32_t pci_moving_config32(struct device *dev, unsigned reg)
+uint32_t pci_moving_config32(struct device *dev, unsigned reg)
{
uint32_t value, ones, zeroes;
value = pci_read_config32(dev, reg);
@@ -70,29 +85,53 @@ static uint32_t pci_moving_config32(struct device *dev, unsigned reg)
return ones ^ zeroes;
}
-unsigned pci_find_capability(device_t dev, unsigned cap)
+unsigned pci_find_next_capability(device_t dev, unsigned cap, unsigned last)
{
unsigned pos;
+ unsigned status;
+ unsigned reps = 48;
pos = 0;
+ status = pci_read_config16(dev, PCI_STATUS);
+ if (!(status & PCI_STATUS_CAP_LIST)) {
+ return 0;
+ }
switch(dev->hdr_type & 0x7f) {
case PCI_HEADER_TYPE_NORMAL:
case PCI_HEADER_TYPE_BRIDGE:
pos = PCI_CAPABILITY_LIST;
break;
+ case PCI_HEADER_TYPE_CARDBUS:
+ pos = PCI_CB_CAPABILITY_LIST;
+ break;
+ default:
+ return 0;
}
- if (pos > PCI_CAP_LIST_NEXT) {
- pos = pci_read_config8(dev, pos);
- }
- while (pos != 0) { /* loop through the linked list */
+ pos = pci_read_config8(dev, pos);
+ while(reps-- && (pos >= 0x40)) { /* loop through the linked list */
int this_cap;
+ pos &= ~3;
this_cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID);
- if (this_cap == cap) {
+ printk_spew("Capability: 0x%02x @ 0x%02x\n", cap, pos);
+ if (this_cap == 0xff) {
+ break;
+ }
+ if (!last && (this_cap == cap)) {
return pos;
}
+ if (last == pos) {
+ last = 0;
+ }
+ pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT);
}
return 0;
}
+unsigned pci_find_capability(device_t dev, unsigned cap)
+{
+ return pci_find_next_capability(dev, cap, 0);
+
+}
+
/** Given a device and register, read the size of the BAR for that register.
* @param dev Pointer to the device structure
* @param resource Pointer to the resource structure
@@ -118,7 +157,7 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index)
/* If it is a 64bit resource look at the high half as well */
if (((attr & PCI_BASE_ADDRESS_SPACE_IO) == 0) &&
- ((attr & PCI_BASE_ADDRESS_MEM_LIMIT_MASK) == PCI_BASE_ADDRESS_MEM_LIMIT_64))
+ ((attr & PCI_BASE_ADDRESS_MEM_LIMIT_MASK) == PCI_BASE_ADDRESS_MEM_LIMIT_64))
{
/* Find the high bits that move */
moving |= ((resource_t)pci_moving_config32(dev, index + 4)) << 32;
@@ -134,7 +173,7 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index)
if (moving) {
resource->size = 1;
resource->align = resource->gran = 0;
- while (!(moving & resource->size)) {
+ while(!(moving & resource->size)) {
resource->size <<= 1;
resource->align += 1;
resource->gran += 1;
@@ -154,17 +193,20 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index)
*/
if (moving == 0) {
if (value != 0) {
- printk_debug("%s register %02x(%08x), read-only ignoring it\n",
- dev_path(dev), index, value);
+ printk_debug(
+ "%s register %02x(%08x), read-only ignoring it\n",
+ dev_path(dev), index, value);
}
resource->flags = 0;
- } else if (attr & PCI_BASE_ADDRESS_SPACE_IO) {
+ }
+ else if (attr & PCI_BASE_ADDRESS_SPACE_IO) {
/* An I/O mapped base address */
attr &= PCI_BASE_ADDRESS_IO_ATTR_MASK;
resource->flags |= IORESOURCE_IO;
/* I don't want to deal with 32bit I/O resources */
resource->limit = 0xffff;
- } else {
+ }
+ else {
/* A Memory mapped base address */
attr &= PCI_BASE_ADDRESS_MEM_ATTR_MASK;
resource->flags |= IORESOURCE_MEM;
@@ -175,14 +217,17 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index)
if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_32) {
/* 32bit limit */
resource->limit = 0xffffffffUL;
- } else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_1M) {
+ }
+ else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_1M) {
/* 1MB limit */
resource->limit = 0x000fffffUL;
- } else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_64) {
+ }
+ else if (attr == PCI_BASE_ADDRESS_MEM_LIMIT_64) {
/* 64bit limit */
resource->limit = 0xffffffffffffffffULL;
resource->flags |= IORESOURCE_PCI64;
- } else {
+ }
+ else {
/* Invalid value */
resource->flags = 0;
}
@@ -194,18 +239,15 @@ struct resource *pci_get_resource(struct device *dev, unsigned long index)
#if 0
if (resource->flags) {
printk_debug("%s %02x ->",
- dev_path(dev), resource->index);
+ dev_path(dev), resource->index);
printk_debug(" value: 0x%08Lx zeroes: 0x%08Lx ones: 0x%08Lx attr: %08lx\n",
- value, zeroes, ones, attr);
+ value, zeroes, ones, attr);
printk_debug(
- "%s %02x -> size: 0x%08Lx max: 0x%08Lx %s%s\n ",
+ "%s %02x -> size: 0x%08Lx max: 0x%08Lx %s\n ",
dev_path(dev),
resource->index,
resource->size, resource->limit,
- (resource->flags == 0) ? "unused":
- (resource->flags & IORESOURCE_IO)? "io":
- (resource->flags & IORESOURCE_PREFETCH)? "prefmem": "mem",
- (resource->flags & IORESOURCE_PCI64)?"64":"");
+ resource_type(resource));
}
#endif
@@ -272,32 +314,32 @@ static void pci_get_rom_resource(struct device *dev, unsigned long index)
resource->flags |= IORESOURCE_MEM | IORESOURCE_READONLY |
IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
}
+
+ compact_resources(dev);
}
/** Read the base address registers for a given device.
* @param dev Pointer to the dev structure
* @param howmany How many registers to read (6 for device, 2 for bridge)
*/
-static void pci_read_bases(struct device *dev, unsigned int howmany, unsigned long rom)
+static void pci_read_bases(struct device *dev, unsigned int howmany)
{
unsigned long index;
- for (index = PCI_BASE_ADDRESS_0; (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) {
+ for(index = PCI_BASE_ADDRESS_0; (index < PCI_BASE_ADDRESS_0 + (howmany << 2)); ) {
struct resource *resource;
resource = pci_get_resource(dev, index);
index += (resource->flags & IORESOURCE_PCI64)?8:4;
}
- if (rom)
- pci_get_rom_resource(dev, rom);
compact_resources(dev);
}
static void pci_set_resource(struct device *dev, struct resource *resource);
-static void pci_record_bridge_resource( struct device *dev, resource_t moving,
- unsigned index, unsigned long mask,
- unsigned long type)
+static void pci_record_bridge_resource(
+ struct device *dev, resource_t moving,
+ unsigned index, unsigned long mask, unsigned long type)
{
/* Initiliaze the constraints on the current bus */
struct resource *resource;
@@ -346,8 +388,10 @@ static void pci_bridge_read_bases(struct device *dev)
moving = moving_base & moving_limit;
/* Initialize the io space constraints on the current bus */
- pci_record_bridge_resource(dev, moving, PCI_IO_BASE,
- IORESOURCE_IO, IORESOURCE_IO);
+ pci_record_bridge_resource(
+ dev, moving, PCI_IO_BASE,
+ IORESOURCE_IO, IORESOURCE_IO);
+
/* See if the bridge prefmem resources are implemented */
moving_base = ((resource_t)pci_moving_config16(dev, PCI_PREF_MEMORY_BASE)) << 16;
@@ -358,9 +402,11 @@ static void pci_bridge_read_bases(struct device *dev)
moving = moving_base & moving_limit;
/* Initiliaze the prefetchable memory constraints on the current bus */
- pci_record_bridge_resource(dev, moving, PCI_PREF_MEMORY_BASE,
- IORESOURCE_MEM | IORESOURCE_PREFETCH,
- IORESOURCE_MEM | IORESOURCE_PREFETCH);
+ pci_record_bridge_resource(
+ dev, moving, PCI_PREF_MEMORY_BASE,
+ IORESOURCE_MEM | IORESOURCE_PREFETCH,
+ IORESOURCE_MEM | IORESOURCE_PREFETCH);
+
/* See if the bridge mem resources are implemented */
moving_base = ((uint32_t)pci_moving_config16(dev, PCI_MEMORY_BASE)) << 16;
@@ -369,26 +415,25 @@ static void pci_bridge_read_bases(struct device *dev)
moving = moving_base & moving_limit;
/* Initialize the memory resources on the current bus */
- pci_record_bridge_resource(dev, moving, PCI_MEMORY_BASE,
- IORESOURCE_MEM | IORESOURCE_PREFETCH,
- IORESOURCE_MEM);
+ pci_record_bridge_resource(
+ dev, moving, PCI_MEMORY_BASE,
+ IORESOURCE_MEM | IORESOURCE_PREFETCH,
+ IORESOURCE_MEM);
compact_resources(dev);
}
void pci_dev_read_resources(struct device *dev)
{
- uint32_t addr;
-
- pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
+ pci_read_bases(dev, 6);
+ pci_get_rom_resource(dev, PCI_ROM_ADDRESS);
}
void pci_bus_read_resources(struct device *dev)
{
- uint32_t addr;
-
pci_bridge_read_bases(dev);
- pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
+ pci_read_bases(dev, 2);
+ pci_get_rom_resource(dev, PCI_ROM_ADDRESS1);
}
static void pci_set_resource(struct device *dev, struct resource *resource)
@@ -397,8 +442,10 @@ static void pci_set_resource(struct device *dev, struct resource *resource)
/* Make certain the resource has actually been set */
if (!(resource->flags & IORESOURCE_ASSIGNED)) {
- printk_err("ERROR: %s %02x not allocated\n",
- dev_path(dev), resource->index);
+ printk_err("ERROR: %s %02x %s size: 0x%010Lx not assigned\n",
+ dev_path(dev), resource->index,
+ resource_type(resource),
+ resource->size);
return;
}
@@ -497,10 +544,10 @@ void pci_dev_set_resources(struct device *dev)
last = &dev->resource[dev->resources];
- for (resource = &dev->resource[0]; resource < last; resource++) {
+ for(resource = &dev->resource[0]; resource < last; resource++) {
pci_set_resource(dev, resource);
}
- for (link = 0; link < dev->links; link++) {
+ for(link = 0; link < dev->links; link++) {
struct bus *bus;
bus = &dev->link[link];
if (bus->children) {
@@ -551,14 +598,10 @@ void pci_dev_enable_resources(struct device *dev)
void pci_bus_enable_resources(struct device *dev)
{
uint16_t ctrl;
-
-#if CONFIG_CONSOLE_VGA == 1
/* enable IO in command register if there is VGA card
* connected with (even it does not claim IO resource) */
if (dev->link[0].bridge_ctrl & PCI_BRIDGE_CTL_VGA)
dev->command |= PCI_COMMAND_IO;
-#endif
-
ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL);
ctrl |= dev->link[0].bridge_ctrl;
ctrl |= (PCI_BRIDGE_CTL_PARITY + PCI_BRIDGE_CTL_SERR); /* error check */
@@ -570,15 +613,27 @@ void pci_bus_enable_resources(struct device *dev)
enable_childrens_resources(dev);
}
+void pci_bus_reset(struct bus *bus)
+{
+ unsigned ctl;
+ ctl = pci_read_config16(bus->dev, PCI_BRIDGE_CONTROL);
+ ctl |= PCI_BRIDGE_CTL_BUS_RESET;
+ pci_write_config16(bus->dev, PCI_BRIDGE_CONTROL, ctl);
+ mdelay(10);
+ ctl &= ~PCI_BRIDGE_CTL_BUS_RESET;
+ pci_write_config16(bus->dev, PCI_BRIDGE_CONTROL, ctl);
+ delay(1);
+}
+
void pci_dev_set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
((device & 0xffff) << 16) | (vendor & 0xffff));
}
-#if CONFIG_PCI_ROM_RUN == 1
void pci_dev_init(struct device *dev)
{
+#if CONFIG_PCI_ROM_RUN == 1
struct rom_header *rom, *ram;
rom = pci_rom_probe(dev);
@@ -589,8 +644,8 @@ void pci_dev_init(struct device *dev)
return;
run_bios(dev, ram);
-}
#endif
+}
/** Default device operation for PCI devices */
static struct pci_operations pci_dev_ops_pci = {
@@ -601,11 +656,7 @@ struct device_operations default_pci_ops_dev = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
-#if CONFIG_PCI_ROM_RUN == 1
.init = pci_dev_init,
-#else
- .init = 0,
-#endif
.scan_bus = 0,
.enable = 0,
.ops_pci = &pci_dev_ops_pci,
@@ -623,10 +674,79 @@ struct device_operations default_pci_ops_bus = {
.init = 0,
.scan_bus = pci_scan_bridge,
.enable = 0,
+ .reset_bus = pci_bus_reset,
.ops_pci = &pci_bus_ops_pci,
};
/**
+ * @brief Detect the type of downstream bridge
+ *
+ * This function is a heuristic to detect which type
+ * of bus is downstream of a pci to pci bridge. This
+ * functions by looking for various capability blocks
+ * to figure out the type of downstream bridge. PCI-X
+ * PCI-E, and Hypertransport all seem to have appropriate
+ * capabilities.
+ *
+ * When only a PCI-Express capability is found the type
+ * is examined to see which type of bridge we have.
+ *
+ * @param dev
+ *
+ * @return appropriate bridge operations
+ */
+static struct device_operations *get_pci_bridge_ops(device_t dev)
+{
+ unsigned pos;
+
+#if CONFIG_PCIX_PLUGIN_SUPPORT == 1
+ pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+ if (pos) {
+ printk_debug("%s subbordinate bus PCI-X\n", dev_path(dev));
+ return &default_pcix_ops_bus;
+ }
+#endif
+#if CONFIG_AGP_PLUGIN_SUPPORT == 1
+ /* How do I detect an PCI to AGP bridge? */
+#endif
+#if CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT == 1
+ pos = 0;
+ while((pos = pci_find_next_capability(dev, PCI_CAP_ID_HT, pos))) {
+ unsigned flags;
+ flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
+ if ((flags >> 13) == 1) {
+ /* Host or Secondary Interface */
+ printk_debug("%s subbordinate bus Hypertransport\n",
+ dev_path(dev));
+ return &default_ht_ops_bus;
+ }
+ }
+#endif
+#if CONFIG_PCIEXP_PLUGIN_SUPPORT == 1
+ pos = pci_find_capability(dev, PCI_CAP_ID_PCIE);
+ if (pos) {
+ unsigned flags;
+ flags = pci_read_config16(dev, pos + PCI_EXP_FLAGS);
+ switch((flags & PCI_EXP_FLAGS_TYPE) >> 4) {
+ case PCI_EXP_TYPE_ROOT_PORT:
+ case PCI_EXP_TYPE_UPSTREAM:
+ case PCI_EXP_TYPE_DOWNSTREAM:
+ printk_debug("%s subbordinate bus PCI Express\n",
+ dev_path(dev));
+ return &default_pciexp_ops_bus;
+ case PCI_EXP_TYPE_PCI_BRIDGE:
+ printk_debug("%s subbordinate PCI\n",
+ dev_path(dev));
+ return &default_pci_ops_bus;
+ default:
+ break;
+ }
+ }
+#endif
+ return &default_pci_ops_bus;
+}
+
+/**
* @brief Set up PCI device operation
*
*
@@ -644,12 +764,12 @@ static void set_pci_ops(struct device *dev)
/* Look through the list of setup drivers and find one for
* this pci device
*/
- for (driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) {
+ for(driver = &pci_drivers[0]; driver != &epci_drivers[0]; driver++) {
if ((driver->vendor == dev->vendor) &&
- (driver->device == dev->device))
+ (driver->device == dev->device))
{
dev->ops = driver->ops;
- printk_debug("%s [%04x/%04x] %sops\n",
+ printk_spew("%s [%04x/%04x] %sops\n",
dev_path(dev),
driver->vendor, driver->device,
(driver->ops->scan_bus?"bus ":""));
@@ -667,8 +787,13 @@ static void set_pci_ops(struct device *dev)
case PCI_HEADER_TYPE_BRIDGE:
if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
goto bad;
- dev->ops = &default_pci_ops_bus;
+ dev->ops = get_pci_bridge_ops(dev);
break;
+#if CONFIG_CARDBUS_PLUGIN_SUPPORT == 1
+ case PCI_HEADER_TYPE_CARDBUS:
+ dev->ops = &default_cardbus_ops_bus;
+ break;
+#endif
default:
bad:
if (dev->enabled) {
@@ -682,6 +807,8 @@ static void set_pci_ops(struct device *dev)
return;
}
+
+
/**
* @brief See if we have already allocated a device structure for a given devfn.
*
@@ -702,7 +829,7 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn)
for(; *list; list = &(*list)->sibling) {
if ((*list)->path.type != DEVICE_PATH_PCI) {
printk_err("child %s not a pci device\n",
- dev_path(*list));
+ dev_path(*list));
continue;
}
if ((*list)->path.u.pci.devfn == devfn) {
@@ -713,15 +840,15 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn)
break;
}
}
- /* Just like alloc_dev add the device to the list of device on the bus.
- * When the list of devices was formed we removed all of the parents
- * children, and now we are interleaving static and dynamic devices in
+ /* Just like alloc_dev add the device to the list of device on the bus.
+ * When the list of devices was formed we removed all of the parents
+ * children, and now we are interleaving static and dynamic devices in
* order on the bus.
*/
if (dev) {
device_t child;
/* Find the last child of our parent */
- for (child = dev->bus->children; child && child->sibling; ) {
+ for(child = dev->bus->children; child && child->sibling; ) {
child = child->sibling;
}
/* Place the device on the list of children of it's parent. */
@@ -738,9 +865,128 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn)
/**
* @brief Scan a PCI bus.
*
+ * Determine the existence of a given PCI device.
+ *
+ * @param bus pointer to the bus structure
+ * @param devfn to look at
+ *
+ * @return The device structure for hte device (if found)
+ * or the NULL if no device is found.
+ */
+device_t pci_probe_dev(device_t dev, struct bus *bus, unsigned devfn)
+{
+ uint32_t id, class;
+ uint8_t hdr_type;
+
+ /* Detect if a device is present */
+ if (!dev) {
+ struct device dummy;
+ dummy.bus = bus;
+ dummy.path.type = DEVICE_PATH_PCI;
+ dummy.path.u.pci.devfn = devfn;
+ id = pci_read_config32(&dummy, PCI_VENDOR_ID);
+ /* Have we found somthing?
+ * Some broken boards return 0 if a slot is empty.
+ */
+ if ( (id == 0xffffffff) || (id == 0x00000000) ||
+ (id == 0x0000ffff) || (id == 0xffff0000))
+ {
+ printk_spew("PCI: devfn 0x%x, bad id 0x%x\n", devfn, id);
+ return NULL;
+ }
+ dev = alloc_dev(bus, &dummy.path);
+ }
+ else {
+ /* Enable/disable the device. Once we have
+ * found the device specific operations this
+ * operations we will disable the device with
+ * those as well.
+ *
+ * This is geared toward devices that have subfunctions
+ * that do not show up by default.
+ *
+ * If a device is a stuff option on the motherboard
+ * it may be absent and enable_dev must cope.
+ *
+ */
+ /* Run the magice enable sequence for the device */
+ if (dev->chip_ops && dev->chip_ops->enable_dev) {
+ dev->chip_ops->enable_dev(dev);
+ }
+ /* Now read the vendor and device id */
+ id = pci_read_config32(dev, PCI_VENDOR_ID);
+
+
+ /* If the device does not have a pci id disable it.
+ * Possibly this is because we have already disabled
+ * the device. But this also handles optional devices
+ * that may not always show up.
+ */
+ /* If the chain is fully enumerated quit */
+ if ( (id == 0xffffffff) || (id == 0x00000000) ||
+ (id == 0x0000ffff) || (id == 0xffff0000))
+ {
+ if (dev->enabled) {
+ printk_info("Disabling static device: %s\n",
+ dev_path(dev));
+ dev->enabled = 0;
+ }
+ return dev;
+ }
+ }
+ /* Read the rest of the pci configuration information */
+ hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+ class = pci_read_config32(dev, PCI_CLASS_REVISION);
+
+ /* Store the interesting information in the device structure */
+ dev->vendor = id & 0xffff;
+ dev->device = (id >> 16) & 0xffff;
+ dev->hdr_type = hdr_type;
+ /* class code, the upper 3 bytes of PCI_CLASS_REVISION */
+ dev->class = class >> 8;
+
+
+ /* Architectural/System devices always need to
+ * be bus masters.
+ */
+ if ((dev->class >> 16) == PCI_BASE_CLASS_SYSTEM) {
+ dev->command |= PCI_COMMAND_MASTER;
+ }
+ /* Look at the vendor and device id, or at least the
+ * header type and class and figure out which set of
+ * configuration methods to use. Unless we already
+ * have some pci ops.
+ */
+ set_pci_ops(dev);
+
+ /* Now run the magic enable/disable sequence for the device */
+ if (dev->ops && dev->ops->enable) {
+ dev->ops->enable(dev);
+ }
+
+
+ /* Display the device and error if we don't have some pci operations
+ * for it.
+ */
+ printk_debug("%s [%04x/%04x] %s%s\n",
+ dev_path(dev),
+ dev->vendor, dev->device,
+ dev->enabled?"enabled": "disabled",
+ dev->ops?"" : " No operations"
+ );
+
+ return dev;
+}
+
+/**
+ * @brief Scan a PCI bus.
+ *
* Determine the existence of devices and bridges on a PCI bus. If there are
* bridges on the bus, recursively scan the buses behind the bridges.
*
+ * This function is the default scan_bus() method for the root device
+ * 'dev_root'.
+ *
* @param bus pointer to the bus structure
* @param min_devfn minimum devfn to look at in the scan usually 0x00
* @param max_devfn maximum devfn to look at in the scan usually 0xff
@@ -748,11 +994,11 @@ static struct device *pci_scan_get_dev(struct device **list, unsigned int devfn)
*
* @return The maximum bus number found, after scanning all subordinate busses
*/
-unsigned int pci_scan_bus(struct bus *bus, unsigned min_devfn, unsigned max_devfn,
- unsigned int max)
+unsigned int pci_scan_bus(struct bus *bus,
+ unsigned min_devfn, unsigned max_devfn,
+ unsigned int max)
{
unsigned int devfn;
- device_t dev;
device_t old_devices;
device_t child;
@@ -762,141 +1008,49 @@ unsigned int pci_scan_bus(struct bus *bus, unsigned min_devfn, unsigned max_devf
bus->children = 0;
post_code(0x24);
-
/* probe all devices/functions on this bus with some optimization for
* non-existence and single funcion devices
*/
for (devfn = min_devfn; devfn <= max_devfn; devfn++) {
- uint32_t id, class;
- uint8_t hdr_type;
+ device_t dev;
/* First thing setup the device structure */
dev = pci_scan_get_dev(&old_devices, devfn);
-
- /* Detect if a device is present */
- if (!dev) {
- struct device dummy;
- dummy.bus = bus;
- dummy.path.type = DEVICE_PATH_PCI;
- dummy.path.u.pci.devfn = devfn;
- id = pci_read_config32(&dummy, PCI_VENDOR_ID);
- /* some broken boards return 0 if a slot is empty: */
- if ((id == 0xffffffff) || (id == 0x00000000) ||
- (id == 0x0000ffff) || (id == 0xffff0000))
- {
- printk_spew("PCI: devfn 0x%x, bad id 0x%x\n", devfn, id);
- if (PCI_FUNC(devfn) == 0x00) {
- /* if this is a function 0 device and
- * it is not present,
- * skip to next device
- */
- devfn += 0x07;
- }
- /* This function in a multi function device is
- * not present, skip to the next function.
- */
- continue;
- }
- dev = alloc_dev(bus, &dummy.path);
- }
- else {
- /* Enable/disable the device. Once we have
- * found the device specific operations this
- * operations we will disable the device with
- * those as well.
- *
- * This is geared toward devices that have subfunctions
- * that do not show up by default.
- *
- * If a device is a stuff option on the motherboard
- * it may be absent and enable_dev must cope.
- *
- */
- if (dev->chip_ops && dev->chip_ops->enable_dev)
- {
- dev->chip_ops->enable_dev(dev);
- }
- /* Now read the vendor and device id */
- id = pci_read_config32(dev, PCI_VENDOR_ID);
-
- /* If the device does not have a pci id disable it.
- * Possibly this is because we have already disabled
- * the device. But this also handles optional devices
- * that may not always show up.
- */
- if (id == 0xffffffff || id == 0x00000000 ||
- id == 0x0000ffff || id == 0xffff0000)
- {
- if (dev->enabled) {
- printk_info("Disabling static device: %s\n",
- dev_path(dev));
- dev->enabled = 0;
- }
- continue;
- }
- }
- /* Read the rest of the pci configuration information */
- hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
- class = pci_read_config32(dev, PCI_CLASS_REVISION);
-
- /* Store the interesting information in the device structure */
- dev->vendor = id & 0xffff;
- dev->device = (id >> 16) & 0xffff;
- dev->hdr_type = hdr_type;
- /* class code, the upper 3 bytes of PCI_CLASS_REVISION */
- dev->class = class >> 8;
-
- /* Architectural/System devices always need to
- * be bus masters.
- */
- if ((dev->class >> 16) == PCI_BASE_CLASS_SYSTEM) {
- dev->command |= PCI_COMMAND_MASTER;
- }
- /* Look at the vendor and device id, or at least the
- * header type and class and figure out which set of
- * configuration methods to use. Unless we already
- * have some pci ops.
+ /* See if a device is present and setup the device
+ * structure.
*/
- set_pci_ops(dev);
- /* Error if we don't have some pci operations for it */
- if (!dev->ops) {
- printk_err("%s No device operations\n",
- dev_path(dev));
- continue;
- }
+ dev = pci_probe_dev(dev, bus, devfn);
- /* Now run the magic enable/disable sequence for the device */
- if (dev->ops && dev->ops->enable) {
- dev->ops->enable(dev);
- }
-
- printk_debug("%s [%04x/%04x] %s\n",
- dev_path(dev),
- dev->vendor, dev->device,
- dev->enabled?"enabled": "disabled");
-
- if (PCI_FUNC(devfn) == 0x00 && (hdr_type & 0x80) != 0x80) {
- /* if this is not a multi function device,
- * don't waste time probing another function.
- * Skip to next device.
- */
+ /* if this is not a multi function device,
+ * or the device is not present don't waste
+ * time probing another function.
+ * Skip to next device.
+ */
+ if ((PCI_FUNC(devfn) == 0x00) &&
+ (!dev || (dev->enabled && ((dev->hdr_type & 0x80) != 0x80))))
+ {
devfn += 0x07;
}
}
post_code(0x25);
+ /* Die if any leftover Static devices are are found.
+ * There's probably a problem in the Config.lb.
+ */
+ if(old_devices) {
+ device_t left;
+ for(left = old_devices; left; left = left->sibling) {
+ printk_debug("%s\n", dev_path(left));
+ }
+ die("Left over static devices. Check your Config.lb\n");
+ }
+
/* For all children that implement scan_bus (i.e. bridges)
* scan the bus behind that child.
*/
- for (child = bus->children; child; child = child->sibling) {
- if (!child->enabled ||
- !child->ops ||
- !child->ops->scan_bus)
- {
- continue;
- }
- max = child->ops->scan_bus(child, max);
+ for(child = bus->children; child; child = child->sibling) {
+ max = scan_bus(child, max);
}
/*
@@ -911,6 +1065,7 @@ unsigned int pci_scan_bus(struct bus *bus, unsigned min_devfn, unsigned max_devf
return max;
}
+
/**
* @brief Scan a PCI bridge and the buses behind the bridge.
*
@@ -924,7 +1079,9 @@ unsigned int pci_scan_bus(struct bus *bus, unsigned min_devfn, unsigned max_devf
*
* @return The maximum bus number found, after scanning all subordinate busses
*/
-unsigned int pci_scan_bridge(struct device *dev, unsigned int max)
+unsigned int do_pci_scan_bridge(struct device *dev, unsigned int max,
+ unsigned int (*do_scan_bus)(struct bus *bus,
+ unsigned min_devfn, unsigned max_devfn, unsigned int max))
{
struct bus *bus;
uint32_t buses;
@@ -960,14 +1117,14 @@ unsigned int pci_scan_bridge(struct device *dev, unsigned int max)
*/
buses &= 0xff000000;
buses |= (((unsigned int) (dev->bus->secondary) << 0) |
- ((unsigned int) (bus->secondary) << 8) |
- ((unsigned int) (bus->subordinate) << 16));
+ ((unsigned int) (bus->secondary) << 8) |
+ ((unsigned int) (bus->subordinate) << 16));
pci_write_config32(dev, PCI_PRIMARY_BUS, buses);
/* Now we can scan all subordinate buses
* i.e. the bus behind the bridge.
*/
- max = pci_scan_bus(bus, 0x00, 0xff, max);
+ max = do_scan_bus(bus, 0x00, 0xff, max);
/* We know the number of buses behind this bridge. Set the subordinate
* bus number to its real value.
@@ -977,11 +1134,29 @@ unsigned int pci_scan_bridge(struct device *dev, unsigned int max)
((unsigned int) (bus->subordinate) << 16);
pci_write_config32(dev, PCI_PRIMARY_BUS, buses);
pci_write_config16(dev, PCI_COMMAND, cr);
-
+
printk_spew("%s returns max %d\n", __func__, max);
return max;
}
+/**
+ * @brief Scan a PCI bridge and the buses behind the bridge.
+ *
+ * Determine the existence of buses behind the bridge. Set up the bridge
+ * according to the result of the scan.
+ *
+ * This function is the default scan_bus() method for PCI bridge devices.
+ *
+ * @param dev pointer to the bridge device
+ * @param max the highest bus number assgined up to now
+ *
+ * @return The maximum bus number found, after scanning all subordinate busses
+ */
+unsigned int pci_scan_bridge(struct device *dev, unsigned int max)
+{
+ return do_pci_scan_bridge(dev, max, pci_scan_bus);
+}
+
/*
Tell the EISA int controller this int must be level triggered
THIS IS A KLUDGE -- sorry, this needs to get cleaned up.
@@ -1026,7 +1201,8 @@ static void pci_level_irq(unsigned char intNum)
-kevinh@ispiri.com
*/
-void pci_assign_irqs(unsigned bus, unsigned slot, const unsigned char pIntAtoD[4])
+void pci_assign_irqs(unsigned bus, unsigned slot,
+ const unsigned char pIntAtoD[4])
{
unsigned functNum;
device_t pdev;
diff --git a/src/devices/pciexp_device.c b/src/devices/pciexp_device.c
new file mode 100644
index 0000000000..5422a8eb18
--- /dev/null
+++ b/src/devices/pciexp_device.c
@@ -0,0 +1,60 @@
+/* (c) 2005 Linux Networx GPL see COPYING for details */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pciexp.h>
+
+
+static void pciexp_tune_dev(device_t dev)
+{
+ unsigned cap;
+
+ cap = pci_find_capability(dev, PCI_CAP_ID_PCIE);
+ if (!cap) {
+ /* error... */
+ return;
+ }
+ printk_debug("PCIEXP: tunning %s\n", dev_path(dev));
+#warning "IMPLEMENT PCI EXPRESS TUNING"
+}
+
+unsigned int pciexp_scan_bus(struct bus *bus,
+ unsigned min_devfn, unsigned max_devfn,
+ unsigned int max)
+{
+ device_t child;
+ max = pci_scan_bus(bus, min_devfn, max_devfn, max);
+ for(child = bus->children; child; child = child->sibling) {
+ if ( (child->path.u.pci.devfn < min_devfn) ||
+ (child->path.u.pci.devfn > max_devfn))
+ {
+ continue;
+ }
+ pciexp_tune_dev(child);
+ }
+ return max;
+}
+
+
+unsigned int pciexp_scan_bridge(device_t dev, unsigned int max)
+{
+ return do_pci_scan_bridge(dev, max, pciexp_scan_bus);
+}
+
+/** Default device operations for PCI Express bridges */
+static struct pci_operations pciexp_bus_ops_pci = {
+ .set_subsystem = 0,
+};
+
+struct device_operations default_pciexp_ops_bus = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = 0,
+ .scan_bus = pciexp_scan_bridge,
+ .enable = 0,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = &pciexp_bus_ops_pci,
+};
diff --git a/src/devices/pcix_device.c b/src/devices/pcix_device.c
new file mode 100644
index 0000000000..8915e56a1b
--- /dev/null
+++ b/src/devices/pcix_device.c
@@ -0,0 +1,140 @@
+/* (c) 2005 Linux Networx GPL see COPYING for details */
+
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pcix.h>
+
+
+static void pcix_tune_dev(device_t dev)
+{
+ unsigned cap;
+ unsigned status, orig_cmd, cmd;
+ unsigned max_read, max_tran;
+
+ if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL) {
+ return;
+ }
+ cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+ if (!cap) {
+ return;
+ }
+ printk_debug("%s PCI-X tuning\n", dev_path(dev));
+ status = pci_read_config32(dev, cap + PCI_X_STATUS);
+ orig_cmd = cmd = pci_read_config16(dev,cap + PCI_X_CMD);
+
+ max_read = (status & PCI_X_STATUS_MAX_READ) >> 21;
+ max_tran = (status & PCI_X_STATUS_MAX_SPLIT) >> 23;
+ if (max_read != ((cmd & PCI_X_CMD_MAX_READ) >> 2)) {
+ cmd &= ~PCI_X_CMD_MAX_READ;
+ cmd |= max_read << 2;
+ }
+ if (max_tran != ((cmd & PCI_X_CMD_MAX_SPLIT) >> 4)) {
+ cmd &= ~PCI_X_CMD_MAX_SPLIT;
+ cmd |= max_tran << 4;
+ }
+ /* Don't attempt to handle PCI-X errors */
+ cmd &= ~PCI_X_CMD_DPERR_E;
+ /* Enable Relaxed Ordering */
+ cmd |= PCI_X_CMD_ERO;
+ if (orig_cmd != cmd) {
+ pci_write_config16(dev, cap + PCI_X_CMD, cmd);
+ }
+}
+
+unsigned int pcix_scan_bus(struct bus *bus,
+ unsigned min_devfn, unsigned max_devfn, unsigned int max)
+{
+ device_t child;
+ max = pci_scan_bus(bus, min_devfn, max_devfn, max);
+ for(child = bus->children; child; child = child->sibling) {
+ if ( (child->path.u.pci.devfn < min_devfn) ||
+ (child->path.u.pci.devfn > max_devfn))
+ {
+ continue;
+ }
+ pcix_tune_dev(child);
+ }
+ return max;
+}
+
+const char *pcix_speed(unsigned sstatus)
+{
+ static const char conventional[] = "Conventional PCI";
+ static const char pcix_66mhz[] = "66MHz PCI-X";
+ static const char pcix_100mhz[] = "100MHz PCI-X";
+ static const char pcix_133mhz[] = "133MHz PCI-X";
+ static const char pcix_266mhz[] = "266MHz PCI-X";
+ static const char pcix_533mhz[] = "533MHZ PCI-X";
+ static const char unknown[] = "Unknown";
+
+ const char *result;
+ result = unknown;
+ switch(PCI_X_SSTATUS_MFREQ(sstatus)) {
+ case PCI_X_SSTATUS_CONVENTIONAL_PCI:
+ result = conventional;
+ break;
+ case PCI_X_SSTATUS_MODE1_66MHZ:
+ result = pcix_66mhz;
+ break;
+ case PCI_X_SSTATUS_MODE1_100MHZ:
+ result = pcix_100mhz;
+ break;
+
+ case PCI_X_SSTATUS_MODE1_133MHZ:
+ result = pcix_133mhz;
+ break;
+
+ case PCI_X_SSTATUS_MODE2_266MHZ_REF_66MHZ:
+ case PCI_X_SSTATUS_MODE2_266MHZ_REF_100MHZ:
+ case PCI_X_SSTATUS_MODE2_266MHZ_REF_133MHZ:
+ result = pcix_266mhz;
+ break;
+
+ case PCI_X_SSTATUS_MODE2_533MHZ_REF_66MHZ:
+ case PCI_X_SSTATUS_MODE2_533MHZ_REF_100MHZ:
+ case PCI_X_SSTATUS_MODE2_533MHZ_REF_133MHZ:
+ result = pcix_533mhz;
+ break;
+ }
+ return result;
+}
+
+unsigned int pcix_scan_bridge(device_t dev, unsigned int max)
+{
+ unsigned pos;
+ unsigned sstatus;
+
+ /* Find the PCI-X capability */
+ pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+ sstatus = pci_read_config16(dev, pos + PCI_X_SEC_STATUS);
+
+ if (PCI_X_SSTATUS_MFREQ(sstatus) == PCI_X_SSTATUS_CONVENTIONAL_PCI) {
+ max = do_pci_scan_bridge(dev, max, pci_scan_bus);
+ } else {
+ max = do_pci_scan_bridge(dev, max, pcix_scan_bus);
+ }
+
+ /* Print the PCI-X bus speed */
+ printk_debug("PCI: %02x: %s\n", dev->link[0].secondary, pcix_speed(sstatus));
+
+ return max;
+}
+
+
+/** Default device operations for PCI-X bridges */
+static struct pci_operations pcix_bus_ops_pci = {
+ .set_subsystem = 0,
+};
+
+struct device_operations default_pcix_ops_bus = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = 0,
+ .scan_bus = pcix_scan_bridge,
+ .enable = 0,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = &pcix_bus_ops_pci,
+};
diff --git a/src/devices/pnp_device.c b/src/devices/pnp_device.c
index cde571f561..13f12ee4e4 100644
--- a/src/devices/pnp_device.c
+++ b/src/devices/pnp_device.c
@@ -68,8 +68,10 @@ void pnp_read_resources(device_t dev)
static void pnp_set_resource(device_t dev, struct resource *resource)
{
if (!(resource->flags & IORESOURCE_ASSIGNED)) {
- printk_err("ERROR: %s %02x not allocated\n",
- dev_path(dev), resource->index);
+ printk_err("ERROR: %s %02x %s size: 0x%010Lx not assigned\n",
+ dev_path(dev), resource->index,
+ resource_type(resource),
+ resource->size);
return;
}
diff --git a/src/devices/root_device.c b/src/devices/root_device.c
index 2bb4f0afe8..3e559ea7c0 100644
--- a/src/devices/root_device.c
+++ b/src/devices/root_device.c
@@ -1,6 +1,7 @@
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
+#include <part/hard_reset.h>
/**
* Read the resources for the root device,
@@ -35,8 +36,9 @@ void root_dev_read_resources(device_t root)
}
/**
- * @brief Write the resources for the root device
+ * @brief Write the resources for every device
*
+ * Write the resources for the root device,
* and every device under it which are all of the devices.
* @param root Pointer to the device structure for the system root device
*/
@@ -45,10 +47,10 @@ void root_dev_set_resources(device_t root)
struct bus *bus;
bus = &root->link[0];
- compute_allocate_resource(bus, &root->resource[0],
- IORESOURCE_IO, IORESOURCE_IO);
- compute_allocate_resource(bus, &root->resource[1],
- IORESOURCE_MEM, IORESOURCE_MEM);
+ compute_allocate_resource(bus,
+ &root->resource[0], IORESOURCE_IO, IORESOURCE_IO);
+ compute_allocate_resource(bus,
+ &root->resource[1], IORESOURCE_MEM, IORESOURCE_MEM);
assign_resources(bus);
}
@@ -57,9 +59,9 @@ void root_dev_set_resources(device_t root)
*
* The enumeration of certain buses is purely static. The existence of
* devices on those buses can be completely determined at compile time
- * and is specified in the config file. Typical exapmles are the 'PNP'
- * devices on a legacy ISA/LPC bus. There is no need of probing of any
- * kind, the only thing we have to do is to walk through the bus and
+ * and is specified in the config file. Typical examples are the 'PNP'
+ * devices on a legacy ISA/LPC bus. There is no need of probing of any kind,
+ * the only thing we have to do is to walk through the bus and
* enable or disable devices as indicated in the config file.
*
* On the other hand, some devices are virtual and their existence is
@@ -70,47 +72,50 @@ void root_dev_set_resources(device_t root)
* This function is the default scan_bus() method for the root device and
* LPC bridges.
*
- * @param root Pointer to the root device which the static buses are attached
+ * @param bus Pointer to the device structure which the static buses are attached
* @param max Maximum bus number currently used before scanning.
- * @return Largest bus number used after scanning.
+ * @return Largest bus number used.
*/
static int smbus_max = 0;
-unsigned int scan_static_bus(device_t root, unsigned int max)
+unsigned int scan_static_bus(device_t bus, unsigned int max)
{
device_t child;
unsigned link;
- printk_spew("%s for %s\n", __func__, dev_path(root));
+ printk_spew("%s for %s\n", __func__, dev_path(bus));
- for (link = 0; link < root->links; link++) {
- /* for smbus bus enumerate */
- child = root->link[link].children;
- if(child && child->path.type == DEVICE_PATH_I2C) {
- root->link[link].secondary = ++smbus_max;
- }
- for (child = root->link[link].children; child; child = child->sibling) {
+ for(link = 0; link < bus->links; link++) {
+ /* for smbus bus enumerate */
+ child = bus->link[link].children;
+ if(child && child->path.type == DEVICE_PATH_I2C) {
+ bus->link[link].secondary = ++smbus_max;
+ }
+ for(child = bus->link[link].children; child; child = child->sibling) {
if (child->chip_ops && child->chip_ops->enable_dev) {
child->chip_ops->enable_dev(child);
}
if (child->ops && child->ops->enable) {
child->ops->enable(child);
}
- if (child->path.type == DEVICE_PATH_I2C)
- printk_debug("smbus: %s[%d]->", dev_path(child->bus->dev), child->bus->link );
- printk_debug("%s %s\n", dev_path(child),
- child->enabled?"enabled": "disabled");
+ if (child->path.type == DEVICE_PATH_I2C) {
+ printk_debug("smbus: %s[%d]->",
+ dev_path(child->bus->dev), child->bus->link );
+ }
+ printk_debug("%s %s\n",
+ dev_path(child),
+ child->enabled?"enabled": "disabled");
}
}
- for (link = 0; link < root->links; link++) {
- for (child = root->link[link].children; child; child = child->sibling) {
+ for(link = 0; link < bus->links; link++) {
+ for(child = bus->link[link].children; child; child = child->sibling) {
if (!child->ops || !child->ops->scan_bus)
continue;
printk_spew("%s scanning...\n", dev_path(child));
- max = child->ops->scan_bus(child, max);
+ max = scan_bus(child, max);
}
}
- printk_spew("%s for %s done\n", __func__, dev_path(root));
+ printk_spew("%s for %s done\n", __func__, dev_path(bus));
return max;
}
@@ -120,7 +125,7 @@ unsigned int scan_static_bus(device_t root, unsigned int max)
*
* @param dev the device whos children's resources are to be enabled
*
- * This function is call by the global enable_resources() indirectly via the
+ * This function is called by the global enable_resource() indirectly via the
* device_operation::enable_resources() method of devices.
*
* Indirect mutual recursion:
@@ -131,9 +136,9 @@ unsigned int scan_static_bus(device_t root, unsigned int max)
void enable_childrens_resources(device_t dev)
{
unsigned link;
- for (link = 0; link < dev->links; link++) {
+ for(link = 0; link < dev->links; link++) {
device_t child;
- for (child = dev->link[link].children; child; child = child->sibling) {
+ for(child = dev->link[link].children; child; child = child->sibling) {
enable_resources(child);
}
}
@@ -161,6 +166,12 @@ void root_dev_init(device_t root)
{
}
+void root_dev_reset(struct bus *bus)
+{
+ printk_info("Reseting board...\n");
+ hard_reset();
+}
+
/**
* @brief Default device operation for root device
*
@@ -174,6 +185,7 @@ struct device_operations default_dev_ops_root = {
.enable_resources = root_dev_enable_resources,
.init = root_dev_init,
.scan_bus = root_dev_scan_bus,
+ .reset_bus = root_dev_reset,
};
/**