nvram.c 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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. int __init bcm63xx_nvram_init(void *addr)
  36. {
  37. unsigned int check_len;
  38. u32 crc, expected_crc;
  39. /* extract nvram data */
  40. memcpy(&nvram, addr, sizeof(nvram));
  41. /* check checksum before using data */
  42. if (nvram.version <= 4) {
  43. check_len = offsetof(struct bcm963xx_nvram, reserved3);
  44. expected_crc = nvram.checksum_old;
  45. nvram.checksum_old = 0;
  46. } else {
  47. check_len = sizeof(nvram);
  48. expected_crc = nvram.checksum_high;
  49. nvram.checksum_high = 0;
  50. }
  51. crc = crc32_le(~0, (u8 *)&nvram, check_len);
  52. if (crc != expected_crc)
  53. return -EINVAL;
  54. return 0;
  55. }
  56. u8 *bcm63xx_nvram_get_name(void)
  57. {
  58. return nvram.name;
  59. }
  60. EXPORT_SYMBOL(bcm63xx_nvram_get_name);
  61. int bcm63xx_nvram_get_mac_address(u8 *mac)
  62. {
  63. u8 *oui;
  64. int count;
  65. if (mac_addr_used >= nvram.mac_addr_count) {
  66. pr_err("not enough mac addresses\n");
  67. return -ENODEV;
  68. }
  69. memcpy(mac, nvram.mac_addr_base, ETH_ALEN);
  70. oui = mac + ETH_ALEN/2 - 1;
  71. count = mac_addr_used;
  72. while (count--) {
  73. u8 *p = mac + ETH_ALEN - 1;
  74. do {
  75. (*p)++;
  76. if (*p != 0)
  77. break;
  78. p--;
  79. } while (p != oui);
  80. if (p == oui) {
  81. pr_err("unable to fetch mac address\n");
  82. return -ENODEV;
  83. }
  84. }
  85. mac_addr_used++;
  86. return 0;
  87. }
  88. EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);