Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Michael Buesch <mb@bu3sch.de>
Cc: Florian Fainelli <florian@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Michael Buesch and committed by
John W. Linville
e79c1ba8 e31ae050

+54 -1
+13 -1
drivers/ssb/pci.c
··· 564 564 static int ssb_pci_sprom_get(struct ssb_bus *bus, 565 565 struct ssb_sprom *sprom) 566 566 { 567 + const struct ssb_sprom *fallback; 567 568 int err = -ENOMEM; 568 569 u16 *buf; 569 570 ··· 584 583 bus->sprom_size = SSB_SPROMSIZE_WORDS_R4; 585 584 sprom_do_read(bus, buf); 586 585 err = sprom_check_crc(buf, bus->sprom_size); 587 - if (err) 586 + if (err) { 587 + /* All CRC attempts failed. 588 + * Maybe there is no SPROM on the device? 589 + * If we have a fallback, use that. */ 590 + fallback = ssb_get_fallback_sprom(); 591 + if (fallback) { 592 + memcpy(sprom, fallback, sizeof(*sprom)); 593 + err = 0; 594 + goto out_free; 595 + } 588 596 ssb_printk(KERN_WARNING PFX "WARNING: Invalid" 589 597 " SPROM CRC (corrupt SPROM)\n"); 598 + } 590 599 } 591 600 err = sprom_extract(bus, sprom, buf, bus->sprom_size); 592 601 602 + out_free: 593 603 kfree(buf); 594 604 out: 595 605 return err;
+36
drivers/ssb/sprom.c
··· 14 14 #include "ssb_private.h" 15 15 16 16 17 + static const struct ssb_sprom *fallback_sprom; 18 + 19 + 17 20 static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, 18 21 size_t sprom_size_words) 19 22 { ··· 133 130 if (res) 134 131 return res; 135 132 return err ? err : count; 133 + } 134 + 135 + /** 136 + * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found. 137 + * 138 + * @sprom: The SPROM data structure to register. 139 + * 140 + * With this function the architecture implementation may register a fallback 141 + * SPROM data structure. The fallback is only used for PCI based SSB devices, 142 + * where no valid SPROM can be found in the shadow registers. 143 + * 144 + * This function is useful for weird architectures that have a half-assed SSB device 145 + * hardwired to their PCI bus. 146 + * 147 + * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently 148 + * don't use this fallback. 149 + * Architectures must provide the SPROM for native SSB devices anyway, 150 + * so the fallback also isn't used for native devices. 151 + * 152 + * This function is available for architecture code, only. So it is not exported. 153 + */ 154 + int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom) 155 + { 156 + if (fallback_sprom) 157 + return -EEXIST; 158 + fallback_sprom = sprom; 159 + 160 + return 0; 161 + } 162 + 163 + const struct ssb_sprom *ssb_get_fallback_sprom(void) 164 + { 165 + return fallback_sprom; 136 166 }
+1
drivers/ssb/ssb_private.h
··· 131 131 const char *buf, size_t count, 132 132 int (*sprom_check_crc)(const u16 *sprom, size_t size), 133 133 int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom)); 134 + extern const struct ssb_sprom *ssb_get_fallback_sprom(void); 134 135 135 136 136 137 /* core.c */
+4
include/linux/ssb/ssb.h
··· 339 339 340 340 extern void ssb_bus_unregister(struct ssb_bus *bus); 341 341 342 + /* Set a fallback SPROM. 343 + * See kdoc at the function definition for complete documentation. */ 344 + extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom); 345 + 342 346 /* Suspend a SSB bus. 343 347 * Call this from the parent bus suspend routine. */ 344 348 extern int ssb_bus_suspend(struct ssb_bus *bus);