Commit e79c1ba8 authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville

ssb: Add SPROM fallback support

This adds SSB functionality to register a fallback SPROM image from the
architecture setup code.

Weird architectures exist that have half-assed SSB devices without SPROM attached to
their PCI busses. The architecture can register a fallback SPROM image that is
used if no SPROM is found on the SSB device.
Signed-off-by: default avatarMichael Buesch <mb@bu3sch.de>
Cc: Florian Fainelli <florian@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e31ae050
...@@ -564,6 +564,7 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out, ...@@ -564,6 +564,7 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
static int ssb_pci_sprom_get(struct ssb_bus *bus, static int ssb_pci_sprom_get(struct ssb_bus *bus,
struct ssb_sprom *sprom) struct ssb_sprom *sprom)
{ {
const struct ssb_sprom *fallback;
int err = -ENOMEM; int err = -ENOMEM;
u16 *buf; u16 *buf;
...@@ -583,12 +584,23 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus, ...@@ -583,12 +584,23 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
sprom_do_read(bus, buf); sprom_do_read(bus, buf);
err = sprom_check_crc(buf, bus->sprom_size); err = sprom_check_crc(buf, bus->sprom_size);
if (err) if (err) {
/* All CRC attempts failed.
* Maybe there is no SPROM on the device?
* If we have a fallback, use that. */
fallback = ssb_get_fallback_sprom();
if (fallback) {
memcpy(sprom, fallback, sizeof(*sprom));
err = 0;
goto out_free;
}
ssb_printk(KERN_WARNING PFX "WARNING: Invalid" ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
" SPROM CRC (corrupt SPROM)\n"); " SPROM CRC (corrupt SPROM)\n");
}
} }
err = sprom_extract(bus, sprom, buf, bus->sprom_size); err = sprom_extract(bus, sprom, buf, bus->sprom_size);
out_free:
kfree(buf); kfree(buf);
out: out:
return err; return err;
......
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
#include "ssb_private.h" #include "ssb_private.h"
static const struct ssb_sprom *fallback_sprom;
static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
size_t sprom_size_words) size_t sprom_size_words)
{ {
...@@ -131,3 +134,36 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, ...@@ -131,3 +134,36 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
return res; return res;
return err ? err : count; return err ? err : count;
} }
/**
* ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found.
*
* @sprom: The SPROM data structure to register.
*
* With this function the architecture implementation may register a fallback
* SPROM data structure. The fallback is only used for PCI based SSB devices,
* where no valid SPROM can be found in the shadow registers.
*
* This function is useful for weird architectures that have a half-assed SSB device
* hardwired to their PCI bus.
*
* Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
* don't use this fallback.
* Architectures must provide the SPROM for native SSB devices anyway,
* so the fallback also isn't used for native devices.
*
* This function is available for architecture code, only. So it is not exported.
*/
int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom)
{
if (fallback_sprom)
return -EEXIST;
fallback_sprom = sprom;
return 0;
}
const struct ssb_sprom *ssb_get_fallback_sprom(void)
{
return fallback_sprom;
}
...@@ -131,6 +131,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, ...@@ -131,6 +131,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
const char *buf, size_t count, const char *buf, size_t count,
int (*sprom_check_crc)(const u16 *sprom, size_t size), int (*sprom_check_crc)(const u16 *sprom, size_t size),
int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom)); int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom));
extern const struct ssb_sprom *ssb_get_fallback_sprom(void);
/* core.c */ /* core.c */
......
...@@ -339,6 +339,10 @@ extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus, ...@@ -339,6 +339,10 @@ extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
extern void ssb_bus_unregister(struct ssb_bus *bus); extern void ssb_bus_unregister(struct ssb_bus *bus);
/* Set a fallback SPROM.
* See kdoc at the function definition for complete documentation. */
extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
/* Suspend a SSB bus. /* Suspend a SSB bus.
* Call this from the parent bus suspend routine. */ * Call this from the parent bus suspend routine. */
extern int ssb_bus_suspend(struct ssb_bus *bus); extern int ssb_bus_suspend(struct ssb_bus *bus);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment