nvram.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
  7. * Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
  8. * Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com>
  9. */
  10. #define pr_fmt(fmt) "bcm63xx_nvram: " fmt
  11. #include <linux/init.h>
  12. #include <linux/crc32.h>
  13. #include <linux/export.h>
  14. #include <linux/kernel.h>
  15. #include <linux/if_ether.h>
  16. #include <bcm63xx_nvram.h>
  17. /*
  18. * nvram structure
  19. */
  20. struct bcm963xx_nvram {
  21. u32 version;
  22. u8 reserved1[256];
  23. u8 name[16];
  24. u32 main_tp_number;
  25. u32 psi_size;
  26. u32 mac_addr_count;
  27. u8 mac_addr_base[ETH_ALEN];
  28. u8 reserved2[2];
  29. u32 checksum_old;
  30. u8 reserved3[720];
  31. u32 checksum_high;
  32. };
  33. #define BCM63XX_DEFAULT_PSI_SIZE 64
  34. static struct bcm963xx_nvram nvram;
  35. static int mac_addr_used;
  36. void __init bcm63xx_nvram_init(void *addr)
  37. {
  38. unsigned int check_len;
  39. u32 crc, expected_crc;
  40. u8 hcs_mac_addr[ETH_ALEN] = { 0x00, 0x10, 0x18, 0xff, 0xff, 0xff };
  41. /* extract nvram data */
  42. memcpy(&nvram, addr, sizeof(nvram));
  43. /* check checksum before using data */
  44. if (nvram.version <= 4) {
  45. check_len = offsetof(struct bcm963xx_nvram, reserved3);
  46. expected_crc = nvram.checksum_old;
  47. nvram.checksum_old = 0;
  48. } else {
  49. check_len = sizeof(nvram);
  50. expected_crc = nvram.checksum_high;
  51. nvram.checksum_high = 0;
  52. }
  53. crc = crc32_le(~0, (u8 *)&nvram, check_len);
  54. if (crc != expected_crc)
  55. pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
  56. expected_crc, crc);
  57. /* Cable modems have a different NVRAM which is embedded in the eCos
  58. * firmware and not easily extractible, give at least a MAC address
  59. * pool.
  60. */
  61. if (BCMCPU_IS_3368()) {
  62. memcpy(nvram.mac_addr_base, hcs_mac_addr, ETH_ALEN);
  63. nvram.mac_addr_count = 2;
  64. }
  65. }
  66. u8 *bcm63xx_nvram_get_name(void)
  67. {
  68. return nvram.name;
  69. }
  70. EXPORT_SYMBOL(bcm63xx_nvram_get_name);
  71. int bcm63xx_nvram_get_mac_address(u8 *mac)
  72. {
  73. u8 *oui;
  74. int count;
  75. if (mac_addr_used >= nvram.mac_addr_count) {
  76. pr_err("not enough mac addresses\n");
  77. return -ENODEV;
  78. }
  79. memcpy(mac, nvram.mac_addr_base, ETH_ALEN);
  80. oui = mac + ETH_ALEN/2 - 1;
  81. count = mac_addr_used;
  82. while (count--) {
  83. u8 *p = mac + ETH_ALEN - 1;
  84. do {
  85. (*p)++;
  86. if (*p != 0)
  87. break;
  88. p--;
  89. } while (p != oui);
  90. if (p == oui) {
  91. pr_err("unable to fetch mac address\n");
  92. return -ENODEV;
  93. }
  94. }
  95. mac_addr_used++;
  96. return 0;
  97. }
  98. EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);
  99. int bcm63xx_nvram_get_psi_size(void)
  100. {
  101. if (nvram.psi_size > 0)
  102. return nvram.psi_size;
  103. return BCM63XX_DEFAULT_PSI_SIZE;
  104. }
  105. EXPORT_SYMBOL(bcm63xx_nvram_get_psi_size);