nvram.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. static struct bcm963xx_nvram nvram;
  34. static int mac_addr_used;
  35. void __init bcm63xx_nvram_init(void *addr)
  36. {
  37. unsigned int check_len;
  38. u32 crc, expected_crc;
  39. u8 hcs_mac_addr[ETH_ALEN] = { 0x00, 0x10, 0x18, 0xff, 0xff, 0xff };
  40. /* extract nvram data */
  41. memcpy(&nvram, addr, sizeof(nvram));
  42. /* check checksum before using data */
  43. if (nvram.version <= 4) {
  44. check_len = offsetof(struct bcm963xx_nvram, reserved3);
  45. expected_crc = nvram.checksum_old;
  46. nvram.checksum_old = 0;
  47. } else {
  48. check_len = sizeof(nvram);
  49. expected_crc = nvram.checksum_high;
  50. nvram.checksum_high = 0;
  51. }
  52. crc = crc32_le(~0, (u8 *)&nvram, check_len);
  53. if (crc != expected_crc)
  54. pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
  55. expected_crc, crc);
  56. /* Cable modems have a different NVRAM which is embedded in the eCos
  57. * firmware and not easily extractible, give at least a MAC address
  58. * pool.
  59. */
  60. if (BCMCPU_IS_3368()) {
  61. memcpy(nvram.mac_addr_base, hcs_mac_addr, ETH_ALEN);
  62. nvram.mac_addr_count = 2;
  63. }
  64. }
  65. u8 *bcm63xx_nvram_get_name(void)
  66. {
  67. return nvram.name;
  68. }
  69. EXPORT_SYMBOL(bcm63xx_nvram_get_name);
  70. int bcm63xx_nvram_get_mac_address(u8 *mac)
  71. {
  72. u8 *oui;
  73. int count;
  74. if (mac_addr_used >= nvram.mac_addr_count) {
  75. pr_err("not enough mac addresses\n");
  76. return -ENODEV;
  77. }
  78. memcpy(mac, nvram.mac_addr_base, ETH_ALEN);
  79. oui = mac + ETH_ALEN/2 - 1;
  80. count = mac_addr_used;
  81. while (count--) {
  82. u8 *p = mac + ETH_ALEN - 1;
  83. do {
  84. (*p)++;
  85. if (*p != 0)
  86. break;
  87. p--;
  88. } while (p != oui);
  89. if (p == oui) {
  90. pr_err("unable to fetch mac address\n");
  91. return -ENODEV;
  92. }
  93. }
  94. mac_addr_used++;
  95. return 0;
  96. }
  97. EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);