===================================================================
@@ -709,7 +709,7 @@ static int ssb_pci_sprom_get(struct ssb_
if (fallback) {
memcpy(sprom, fallback, sizeof(*sprom));
err = 0;
- goto out_free;
+ goto out;
}
ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
" SPROM CRC (corrupt SPROM)\n");
@@ -763,8 +763,8 @@ static int ssb_pci_sprom_get(struct ssb_
}
err = sprom_extract(bus, sprom, buf, bus->sprom_size);
-out_free:
- kfree(buf);
+out:
+ bus->sprom_data = buf;
return err;
}
@@ -1013,6 +1013,7 @@ void ssb_pci_exit(struct ssb_bus *bus)
if (bus->bustype != SSB_BUSTYPE_PCI)
return;
+ kfree(bus->sprom_data);
pdev = bus->host_pci;
device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
}
===================================================================
@@ -72,24 +72,29 @@ ssize_t ssb_attr_sprom_show(struct ssb_b
ssize_t count = 0;
size_t sprom_size_words = bus->sprom_size;
- sprom = kcalloc(sprom_size_words, sizeof(u16), GFP_KERNEL);
- if (!sprom)
- goto out;
-
- /* Use interruptible locking, as the SPROM write might
- * be holding the lock for several seconds. So allow userspace
- * to cancel operation. */
- err = -ERESTARTSYS;
- if (mutex_lock_interruptible(&bus->sprom_mutex))
- goto out_kfree;
- err = sprom_read(bus, sprom);
- mutex_unlock(&bus->sprom_mutex);
-
+ if (bus->sprom_data) {
+ sprom = bus->sprom_data;
+ err = 0;
+ } else {
+ sprom = kcalloc(sprom_size_words, sizeof(u16), GFP_KERNEL);
+ if (!sprom)
+ goto out;
+
+ /* Use interruptible locking, as the SPROM write might
+ * be holding the lock for several seconds. So allow userspace
+ * to cancel operation. */
+ err = -ERESTARTSYS;
+ if (mutex_lock_interruptible(&bus->sprom_mutex))
+ goto out_kfree;
+ err = sprom_read(bus, sprom);
+ mutex_unlock(&bus->sprom_mutex);
+ }
if (!err)
count = sprom2hex(sprom, buf, PAGE_SIZE, sprom_size_words);
out_kfree:
- kfree(sprom);
+ if (!bus->sprom_data)
+ kfree(sprom);
out:
return err ? err : count;
}
@@ -105,6 +110,8 @@ ssize_t ssb_attr_sprom_store(struct ssb_
size_t sprom_size_words = bus->sprom_size;
struct ssb_freeze_context freeze;
+ if (bus->sprom_offset < SSB_SPROM_BASE1)
+ return -EINVAL;
sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
if (!sprom)
goto out;
===================================================================
@@ -311,6 +311,7 @@ struct ssb_bus {
u16 chip_rev;
u16 sprom_offset;
u16 sprom_size; /* number of words in sprom */
+ u16 *sprom_data; /* saved sprom raw data */
u8 chip_package;
/* List of devices (cores) on the backplane. */