| 1 | --- a/arch/mips/bcm63xx/boards/board_bcm963xx.c |
| 2 | +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c |
| 3 | @@ -643,6 +643,17 @@ static struct ssb_sprom bcm63xx_sprom = |
| 4 | .boardflags_lo = 0x2848, |
| 5 | .boardflags_hi = 0x0000, |
| 6 | }; |
| 7 | + |
| 8 | +int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out) |
| 9 | +{ |
| 10 | + if (bus->bustype == SSB_BUSTYPE_PCI) { |
| 11 | + memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom)); |
| 12 | + return 0; |
| 13 | + } else { |
| 14 | + printk(KERN_ERR PFX "unable to fill SPROM for given bustype.\n"); |
| 15 | + return -EINVAL; |
| 16 | + } |
| 17 | +} |
| 18 | #endif |
| 19 | |
| 20 | /* |
| 21 | @@ -793,8 +804,9 @@ void __init board_prom_init(void) |
| 22 | if (!board_get_mac_address(bcm63xx_sprom.il0mac)) { |
| 23 | memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN); |
| 24 | memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN); |
| 25 | - if (ssb_arch_set_fallback_sprom(&bcm63xx_sprom) < 0) |
| 26 | - printk(KERN_ERR "failed to register fallback SPROM\n"); |
| 27 | + if (ssb_arch_register_fallback_sprom( |
| 28 | + &bcm63xx_get_fallback_sprom) < 0) |
| 29 | + printk(KERN_ERR PFX "failed to register fallback SPROM\n"); |
| 30 | } |
| 31 | #endif |
| 32 | } |
| 33 | --- a/drivers/ssb/pci.c |
| 34 | +++ b/drivers/ssb/pci.c |
| 35 | @@ -662,7 +662,6 @@ static int sprom_extract(struct ssb_bus |
| 36 | static int ssb_pci_sprom_get(struct ssb_bus *bus, |
| 37 | struct ssb_sprom *sprom) |
| 38 | { |
| 39 | - const struct ssb_sprom *fallback; |
| 40 | int err; |
| 41 | u16 *buf; |
| 42 | |
| 43 | @@ -707,10 +706,17 @@ static int ssb_pci_sprom_get(struct ssb_ |
| 44 | if (err) { |
| 45 | /* All CRC attempts failed. |
| 46 | * Maybe there is no SPROM on the device? |
| 47 | - * If we have a fallback, use that. */ |
| 48 | - fallback = ssb_get_fallback_sprom(); |
| 49 | - if (fallback) { |
| 50 | - memcpy(sprom, fallback, sizeof(*sprom)); |
| 51 | + * Now we ask the arch code if there is some sprom |
| 52 | + * avaliable for this device in some other storage */ |
| 53 | + err = ssb_fill_sprom_with_fallback(bus, sprom); |
| 54 | + if (err) { |
| 55 | + ssb_printk(KERN_WARNING PFX "WARNING: Using" |
| 56 | + " fallback SPROM failed (err %d)\n", |
| 57 | + err); |
| 58 | + } else { |
| 59 | + ssb_dprintk(KERN_DEBUG PFX "Using SPROM" |
| 60 | + " revision %d provided by" |
| 61 | + " platform.\n", sprom->revision); |
| 62 | err = 0; |
| 63 | goto out_free; |
| 64 | } |
| 65 | --- a/drivers/ssb/sprom.c |
| 66 | +++ b/drivers/ssb/sprom.c |
| 67 | @@ -17,7 +17,7 @@ |
| 68 | #include <linux/slab.h> |
| 69 | |
| 70 | |
| 71 | -static const struct ssb_sprom *fallback_sprom; |
| 72 | +static int(*get_fallback_sprom)(struct ssb_bus *dev, struct ssb_sprom *out); |
| 73 | |
| 74 | |
| 75 | static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, |
| 76 | @@ -145,13 +145,14 @@ out: |
| 77 | } |
| 78 | |
| 79 | /** |
| 80 | - * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found. |
| 81 | + * ssb_arch_register_fallback_sprom - Registers a method providing a fallback |
| 82 | + * SPROM if no SPROM is found. |
| 83 | * |
| 84 | - * @sprom: The SPROM data structure to register. |
| 85 | + * @sprom_callback: The callbcak function. |
| 86 | * |
| 87 | - * With this function the architecture implementation may register a fallback |
| 88 | - * SPROM data structure. The fallback is only used for PCI based SSB devices, |
| 89 | - * where no valid SPROM can be found in the shadow registers. |
| 90 | + * With this function the architecture implementation may register a callback |
| 91 | + * handler which wills the SPROM data structure. The fallback is only used for |
| 92 | + * PCI based SSB devices, where no valid SPROM can be found in the shadow registers. |
| 93 | * |
| 94 | * This function is useful for weird architectures that have a half-assed SSB device |
| 95 | * hardwired to their PCI bus. |
| 96 | @@ -163,18 +164,21 @@ out: |
| 97 | * |
| 98 | * This function is available for architecture code, only. So it is not exported. |
| 99 | */ |
| 100 | -int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom) |
| 101 | +int ssb_arch_register_fallback_sprom(int (*sprom_callback)(struct ssb_bus *bus, struct ssb_sprom *out)) |
| 102 | { |
| 103 | - if (fallback_sprom) |
| 104 | + if (get_fallback_sprom) |
| 105 | return -EEXIST; |
| 106 | - fallback_sprom = sprom; |
| 107 | + get_fallback_sprom = sprom_callback; |
| 108 | |
| 109 | return 0; |
| 110 | } |
| 111 | |
| 112 | -const struct ssb_sprom *ssb_get_fallback_sprom(void) |
| 113 | +int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out) |
| 114 | { |
| 115 | - return fallback_sprom; |
| 116 | + if (!get_fallback_sprom) |
| 117 | + return -ENOENT; |
| 118 | + |
| 119 | + return get_fallback_sprom(bus, out); |
| 120 | } |
| 121 | |
| 122 | /* http://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */ |
| 123 | --- a/drivers/ssb/ssb_private.h |
| 124 | +++ b/drivers/ssb/ssb_private.h |
| 125 | @@ -171,7 +171,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_ |
| 126 | const char *buf, size_t count, |
| 127 | int (*sprom_check_crc)(const u16 *sprom, size_t size), |
| 128 | int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom)); |
| 129 | -extern const struct ssb_sprom *ssb_get_fallback_sprom(void); |
| 130 | +extern int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out); |
| 131 | |
| 132 | |
| 133 | /* core.c */ |
| 134 | --- a/include/linux/ssb/ssb.h |
| 135 | +++ b/include/linux/ssb/ssb.h |
| 136 | @@ -404,7 +404,9 @@ extern bool ssb_is_sprom_available(struc |
| 137 | |
| 138 | /* Set a fallback SPROM. |
| 139 | * See kdoc at the function definition for complete documentation. */ |
| 140 | -extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom); |
| 141 | +extern int ssb_arch_register_fallback_sprom( |
| 142 | + int (*sprom_callback)(struct ssb_bus *bus, |
| 143 | + struct ssb_sprom *out)); |
| 144 | |
| 145 | /* Suspend a SSB bus. |
| 146 | * Call this from the parent bus suspend routine. */ |
| 147 | |