Always make sure buspower is applied, when accessing the PCI MMIO space.
Otherwise this can result in crashes.
Signed-off-by: Michael Buesch <[EMAIL PROTECTED]>
Index: ssb-merge-new/drivers/ssb/main.c
===================================================================
--- ssb-merge-new.orig/drivers/ssb/main.c 2007-08-13 17:33:23.000000000
+0200
+++ ssb-merge-new/drivers/ssb/main.c 2007-08-13 17:33:34.000000000 +0200
@@ -131,6 +131,9 @@ static void ssb_bus_suspend(struct ssb_b
#ifdef CONFIG_SSB_DRIVER_PCICORE
bus->pcicore.setup_done = 0;
#endif
+#ifdef CONFIG_SSB_DEBUG
+ bus->powered_up = 0;
+#endif
}
static int ssb_device_suspend(struct device *dev, pm_message_t state)
@@ -486,9 +489,14 @@ static int ssb_attach_queued_buses(void)
* is too early in boot for embedded systems
* (no udelay() available). So do it here in attach stage.
*/
+ err = ssb_bus_powerup(bus, 0);
+ if (err)
+ goto error;
ssb_pcicore_init(&bus->pcicore);
+ ssb_bus_may_powerdown(bus);
err = ssb_devices_register(bus);
+error:
if (err) {
drop_them_all = 1;
list_del(&bus->list);
@@ -586,11 +594,17 @@ static int ssb_bus_register(struct ssb_b
goto err_pci_exit;
/* Initialize basic system devices (if available) */
+ err = ssb_bus_powerup(bus, 0);
+ if (err)
+ goto err_pcmcia_exit;
ssb_chipcommon_init(&bus->chipco);
ssb_mipscore_init(&bus->mipscore);
err = ssb_fetch_invariants(bus, get_invariants);
- if (err)
+ if (err) {
+ ssb_bus_may_powerdown(bus);
goto err_pcmcia_exit;
+ }
+ ssb_bus_may_powerdown(bus);
/* Queue it for attach.
* See the comment at the ssb_is_early_boot definition. */
@@ -1012,24 +1026,27 @@ EXPORT_SYMBOL(ssb_dma_set_mask);
int ssb_bus_may_powerdown(struct ssb_bus *bus)
{
struct ssb_chipcommon *cc;
- int err;
+ int err = 0;
/* On buses where more than one core may be working
* at a time, we must not powerdown stuff if there are
* still cores that may want to run. */
if (bus->bustype == SSB_BUSTYPE_SSB)
- return 0;
+ goto out;
cc = &bus->chipco;
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW);
err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
if (err)
goto error;
-
- return 0;
+out:
+#ifdef CONFIG_SSB_DEBUG
+ bus->powered_up = 0;
+#endif
+ return err;
error:
ssb_printk(KERN_ERR PFX "Bus powerdown failed\n");
- return err;
+ goto out;
}
EXPORT_SYMBOL(ssb_bus_may_powerdown);
@@ -1046,6 +1063,9 @@ int ssb_bus_powerup(struct ssb_bus *bus,
mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
ssb_chipco_set_clockmode(cc, mode);
+#ifdef CONFIG_SSB_DEBUG
+ bus->powered_up = 1;
+#endif
return 0;
error:
ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
Index: ssb-merge-new/drivers/ssb/pci.c
===================================================================
--- ssb-merge-new.orig/drivers/ssb/pci.c 2007-08-11 20:25:54.000000000
+0200
+++ ssb-merge-new/drivers/ssb/pci.c 2007-08-13 17:33:34.000000000 +0200
@@ -499,10 +499,34 @@ out:
return err;
}
+#ifdef CONFIG_SSB_DEBUG
+static int ssb_pci_assert_buspower(struct ssb_bus *bus)
+{
+ if (likely(bus->powered_up))
+ return 0;
+
+ printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
+ "while accessing PCI MMIO space\n");
+ if (bus->power_warn_count <= 10) {
+ bus->power_warn_count++;
+ dump_stack();
+ }
+
+ return -ENODEV;
+}
+#else /* DEBUG */
+static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
+{
+ return 0;
+}
+#endif /* DEBUG */
+
static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
{
struct ssb_bus *bus = dev->bus;
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return 0xFFFF;
if (unlikely(bus->mapped_device != dev)) {
if (unlikely(ssb_pci_switch_core(bus, dev)))
return 0xFFFF;
@@ -514,6 +538,8 @@ static u32 ssb_pci_read32(struct ssb_dev
{
struct ssb_bus *bus = dev->bus;
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return 0xFFFFFFFF;
if (unlikely(bus->mapped_device != dev)) {
if (unlikely(ssb_pci_switch_core(bus, dev)))
return 0xFFFFFFFF;
@@ -525,6 +551,8 @@ static void ssb_pci_write16(struct ssb_d
{
struct ssb_bus *bus = dev->bus;
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return;
if (unlikely(bus->mapped_device != dev)) {
if (unlikely(ssb_pci_switch_core(bus, dev)))
return;
@@ -536,6 +564,8 @@ static void ssb_pci_write32(struct ssb_d
{
struct ssb_bus *bus = dev->bus;
+ if (unlikely(ssb_pci_assert_buspower(bus)))
+ return;
if (unlikely(bus->mapped_device != dev)) {
if (unlikely(ssb_pci_switch_core(bus, dev)))
return;
Index: ssb-merge-new/include/linux/ssb/ssb.h
===================================================================
--- ssb-merge-new.orig/include/linux/ssb/ssb.h 2007-08-11 20:26:09.000000000
+0200
+++ ssb-merge-new/include/linux/ssb/ssb.h 2007-08-13 17:33:34.000000000
+0200
@@ -319,8 +319,13 @@ struct ssb_bus {
/* Contents of the SPROM. */
struct ssb_sprom sprom;
- /* Internal. */
+ /* Internal-only stuff follows. Do not touch. */
struct list_head list;
+#ifdef CONFIG_SSB_DEBUG
+ /* Is the bus already powered up? */
+ bool powered_up;
+ int power_warn_count;
+#endif /* DEBUG */
};
/* The initialization-invariants. */
--
_______________________________________________
Bcm43xx-dev mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/bcm43xx-dev