1 /* 2 * Sonics Silicon Backplane 3 * Common SPROM support routines 4 * 5 * Copyright (C) 2005-2008 Michael Buesch <mb@bu3sch.de> 6 * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de> 7 * Copyright (C) 2005 Stefano Brivio <st3@riseup.net> 8 * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org> 9 * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> 10 * 11 * Licensed under the GNU/GPL. See COPYING for details. 12 */ 13 14 #include "ssb_private.h" 15 16 #include <linux/ctype.h> 17 18 19 static const struct ssb_sprom *fallback_sprom; 20 21 22 static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len, 23 size_t sprom_size_words) 24 { 25 int i, pos = 0; 26 27 for (i = 0; i < sprom_size_words; i++) 28 pos += snprintf(buf + pos, buf_len - pos - 1, 29 "%04X", swab16(sprom[i]) & 0xFFFF); 30 pos += snprintf(buf + pos, buf_len - pos - 1, "\n"); 31 32 return pos + 1; 33 } 34 35 static int hex2sprom(u16 *sprom, const char *dump, size_t len, 36 size_t sprom_size_words) 37 { 38 char c, tmp[5] = { 0 }; 39 int err, cnt = 0; 40 unsigned long parsed; 41 42 /* Strip whitespace at the end. */ 43 while (len) { 44 c = dump[len - 1]; 45 if (!isspace(c) && c != '\0') 46 break; 47 len--; 48 } 49 /* Length must match exactly. */ 50 if (len != sprom_size_words * 4) 51 return -EINVAL; 52 53 while (cnt < sprom_size_words) { 54 memcpy(tmp, dump, 4); 55 dump += 4; 56 err = strict_strtoul(tmp, 16, &parsed); 57 if (err) 58 return err; 59 sprom[cnt++] = swab16((u16)parsed); 60 } 61 62 return 0; 63 } 64 65 /* Common sprom device-attribute show-handler */ 66 ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf, 67 int (*sprom_read)(struct ssb_bus *bus, u16 *sprom)) 68 { 69 u16 *sprom; 70 int err = -ENOMEM; 71 ssize_t count = 0; 72 size_t sprom_size_words = bus->sprom_size; 73 74 sprom = kcalloc(sprom_size_words, sizeof(u16), GFP_KERNEL); 75 if (!sprom) 76 goto out; 77 78 /* Use interruptible locking, as the SPROM write might 79 * be holding the lock for several seconds. So allow userspace 80 * to cancel operation. */ 81 err = -ERESTARTSYS; 82 if (mutex_lock_interruptible(&bus->sprom_mutex)) 83 goto out_kfree; 84 err = sprom_read(bus, sprom); 85 mutex_unlock(&bus->sprom_mutex); 86 87 if (!err) 88 count = sprom2hex(sprom, buf, PAGE_SIZE, sprom_size_words); 89 90 out_kfree: 91 kfree(sprom); 92 out: 93 return err ? err : count; 94 } 95 96 /* Common sprom device-attribute store-handler */ 97 ssize_t ssb_attr_sprom_store(struct ssb_bus *bus, 98 const char *buf, size_t count, 99 int (*sprom_check_crc)(const u16 *sprom, size_t size), 100 int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom)) 101 { 102 u16 *sprom; 103 int res = 0, err = -ENOMEM; 104 size_t sprom_size_words = bus->sprom_size; 105 struct ssb_freeze_context freeze; 106 107 sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL); 108 if (!sprom) 109 goto out; 110 err = hex2sprom(sprom, buf, count, sprom_size_words); 111 if (err) { 112 err = -EINVAL; 113 goto out_kfree; 114 } 115 err = sprom_check_crc(sprom, sprom_size_words); 116 if (err) { 117 err = -EINVAL; 118 goto out_kfree; 119 } 120 121 /* Use interruptible locking, as the SPROM write might 122 * be holding the lock for several seconds. So allow userspace 123 * to cancel operation. */ 124 err = -ERESTARTSYS; 125 if (mutex_lock_interruptible(&bus->sprom_mutex)) 126 goto out_kfree; 127 err = ssb_devices_freeze(bus, &freeze); 128 if (err) { 129 ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n"); 130 goto out_unlock; 131 } 132 res = sprom_write(bus, sprom); 133 err = ssb_devices_thaw(&freeze); 134 if (err) 135 ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n"); 136 out_unlock: 137 mutex_unlock(&bus->sprom_mutex); 138 out_kfree: 139 kfree(sprom); 140 out: 141 if (res) 142 return res; 143 return err ? err : count; 144 } 145 146 /** 147 * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found. 148 * 149 * @sprom: The SPROM data structure to register. 150 * 151 * With this function the architecture implementation may register a fallback 152 * SPROM data structure. The fallback is only used for PCI based SSB devices, 153 * where no valid SPROM can be found in the shadow registers. 154 * 155 * This function is useful for weird architectures that have a half-assed SSB device 156 * hardwired to their PCI bus. 157 * 158 * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently 159 * don't use this fallback. 160 * Architectures must provide the SPROM for native SSB devices anyway, 161 * so the fallback also isn't used for native devices. 162 * 163 * This function is available for architecture code, only. So it is not exported. 164 */ 165 int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom) 166 { 167 if (fallback_sprom) 168 return -EEXIST; 169 fallback_sprom = sprom; 170 171 return 0; 172 } 173 174 const struct ssb_sprom *ssb_get_fallback_sprom(void) 175 { 176 return fallback_sprom; 177 } 178