sprom.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. #include "ssb_private.h"
  14. static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
  15. size_t sprom_size_words)
  16. {
  17. int i, pos = 0;
  18. for (i = 0; i < sprom_size_words; i++)
  19. pos += snprintf(buf + pos, buf_len - pos - 1,
  20. "%04X", swab16(sprom[i]) & 0xFFFF);
  21. pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
  22. return pos + 1;
  23. }
  24. static int hex2sprom(u16 *sprom, const char *dump, size_t len,
  25. size_t sprom_size_words)
  26. {
  27. char tmp[5] = { 0 };
  28. int cnt = 0;
  29. unsigned long parsed;
  30. if (len < sprom_size_words * 2)
  31. return -EINVAL;
  32. while (cnt < sprom_size_words) {
  33. memcpy(tmp, dump, 4);
  34. dump += 4;
  35. parsed = simple_strtoul(tmp, NULL, 16);
  36. sprom[cnt++] = swab16((u16)parsed);
  37. }
  38. return 0;
  39. }
  40. /* Common sprom device-attribute show-handler */
  41. ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf,
  42. int (*sprom_read)(struct ssb_bus *bus, u16 *sprom))
  43. {
  44. u16 *sprom;
  45. int err = -ENOMEM;
  46. ssize_t count = 0;
  47. size_t sprom_size_words = bus->sprom_size;
  48. sprom = kcalloc(sprom_size_words, sizeof(u16), GFP_KERNEL);
  49. if (!sprom)
  50. goto out;
  51. /* Use interruptible locking, as the SPROM write might
  52. * be holding the lock for several seconds. So allow userspace
  53. * to cancel operation. */
  54. err = -ERESTARTSYS;
  55. if (mutex_lock_interruptible(&bus->sprom_mutex))
  56. goto out_kfree;
  57. err = sprom_read(bus, sprom);
  58. mutex_unlock(&bus->sprom_mutex);
  59. if (!err)
  60. count = sprom2hex(sprom, buf, PAGE_SIZE, sprom_size_words);
  61. out_kfree:
  62. kfree(sprom);
  63. out:
  64. return err ? err : count;
  65. }
  66. /* Common sprom device-attribute store-handler */
  67. ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
  68. const char *buf, size_t count,
  69. int (*sprom_check_crc)(const u16 *sprom, size_t size),
  70. int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom))
  71. {
  72. u16 *sprom;
  73. int res = 0, err = -ENOMEM;
  74. size_t sprom_size_words = bus->sprom_size;
  75. sprom = kcalloc(bus->sprom_size, sizeof(u16), GFP_KERNEL);
  76. if (!sprom)
  77. goto out;
  78. err = hex2sprom(sprom, buf, count, sprom_size_words);
  79. if (err) {
  80. err = -EINVAL;
  81. goto out_kfree;
  82. }
  83. err = sprom_check_crc(sprom, sprom_size_words);
  84. if (err) {
  85. err = -EINVAL;
  86. goto out_kfree;
  87. }
  88. /* Use interruptible locking, as the SPROM write might
  89. * be holding the lock for several seconds. So allow userspace
  90. * to cancel operation. */
  91. err = -ERESTARTSYS;
  92. if (mutex_lock_interruptible(&bus->sprom_mutex))
  93. goto out_kfree;
  94. err = ssb_devices_freeze(bus);
  95. if (err == -EOPNOTSUPP) {
  96. ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
  97. "No suspend support. Is CONFIG_PM enabled?\n");
  98. goto out_unlock;
  99. }
  100. if (err) {
  101. ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
  102. goto out_unlock;
  103. }
  104. res = sprom_write(bus, sprom);
  105. err = ssb_devices_thaw(bus);
  106. if (err)
  107. ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
  108. out_unlock:
  109. mutex_unlock(&bus->sprom_mutex);
  110. out_kfree:
  111. kfree(sprom);
  112. out:
  113. if (res)
  114. return res;
  115. return err ? err : count;
  116. }