[kernel] revert 15922 - add back 2.6.29 kernel support
[openwrt.git] / target / linux / generic-2.6 / patches-2.6.29 / 975-ssb-fallback-sprom.patch
1 --- a/drivers/ssb/pci.c
2 +++ b/drivers/ssb/pci.c
3 @@ -514,6 +514,7 @@ unsupported:
4  static int ssb_pci_sprom_get(struct ssb_bus *bus,
5                              struct ssb_sprom *sprom)
6  {
7 +       const struct ssb_sprom *fallback;
8         int err = -ENOMEM;
9         u16 *buf;
10  
11 @@ -533,12 +534,23 @@ static int ssb_pci_sprom_get(struct ssb_
12                 bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
13                 sprom_do_read(bus, buf);
14                 err = sprom_check_crc(buf, bus->sprom_size);
15 -               if (err)
16 +               if (err) {
17 +                       /* All CRC attempts failed.
18 +                        * Maybe there is no SPROM on the device?
19 +                        * If we have a fallback, use that. */
20 +                       fallback = ssb_get_fallback_sprom();
21 +                       if (fallback) {
22 +                               memcpy(sprom, fallback, sizeof(*sprom));
23 +                               err = 0;
24 +                               goto out_free;
25 +                       }
26                         ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
27                                    " SPROM CRC (corrupt SPROM)\n");
28 +               }
29         }
30         err = sprom_extract(bus, sprom, buf, bus->sprom_size);
31  
32 +out_free:
33         kfree(buf);
34  out:
35         return err;
36 --- a/drivers/ssb/sprom.c
37 +++ b/drivers/ssb/sprom.c
38 @@ -14,6 +14,9 @@
39  #include "ssb_private.h"
40  
41  
42 +static const struct ssb_sprom *fallback_sprom;
43 +
44 +
45  static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
46                      size_t sprom_size_words)
47  {
48 @@ -131,3 +134,36 @@ out:
49                 return res;
50         return err ? err : count;
51  }
52 +
53 +/**
54 + * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found.
55 + *
56 + * @sprom: The SPROM data structure to register.
57 + *
58 + * With this function the architecture implementation may register a fallback
59 + * SPROM data structure. The fallback is only used for PCI based SSB devices,
60 + * where no valid SPROM can be found in the shadow registers.
61 + *
62 + * This function is useful for weird architectures that have a half-assed SSB device
63 + * hardwired to their PCI bus.
64 + *
65 + * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
66 + * don't use this fallback.
67 + * Architectures must provide the SPROM for native SSB devices anyway,
68 + * so the fallback also isn't used for native devices.
69 + *
70 + * This function is available for architecture code, only. So it is not exported.
71 + */
72 +int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom)
73 +{
74 +       if (fallback_sprom)
75 +               return -EEXIST;
76 +       fallback_sprom = sprom;
77 +
78 +       return 0;
79 +}
80 +
81 +const struct ssb_sprom *ssb_get_fallback_sprom(void)
82 +{
83 +       return fallback_sprom;
84 +}
85 --- a/drivers/ssb/ssb_private.h
86 +++ b/drivers/ssb/ssb_private.h
87 @@ -131,6 +131,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_
88                              const char *buf, size_t count,
89                              int (*sprom_check_crc)(const u16 *sprom, size_t size),
90                              int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom));
91 +extern const struct ssb_sprom *ssb_get_fallback_sprom(void);
92  
93  
94  /* core.c */
95 --- a/include/linux/ssb/ssb.h
96 +++ b/include/linux/ssb/ssb.h
97 @@ -339,6 +339,10 @@ extern int ssb_bus_pcmciabus_register(st
98  
99  extern void ssb_bus_unregister(struct ssb_bus *bus);
100  
101 +/* Set a fallback SPROM.
102 + * See kdoc at the function definition for complete documentation. */
103 +extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
104 +
105  /* Suspend a SSB bus.
106   * Call this from the parent bus suspend routine. */
107  extern int ssb_bus_suspend(struct ssb_bus *bus);