linux/arch/mips/bcm63xx/nvram.c
<<
>>
Prefs
   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
  11#define pr_fmt(fmt) "bcm63xx_nvram: " fmt
  12
  13#include <linux/init.h>
  14#include <linux/crc32.h>
  15#include <linux/export.h>
  16#include <linux/kernel.h>
  17#include <linux/if_ether.h>
  18
  19#include <bcm63xx_nvram.h>
  20
  21/*
  22 * nvram structure
  23 */
  24struct bcm963xx_nvram {
  25        u32     version;
  26        u8      reserved1[256];
  27        u8      name[16];
  28        u32     main_tp_number;
  29        u32     psi_size;
  30        u32     mac_addr_count;
  31        u8      mac_addr_base[ETH_ALEN];
  32        u8      reserved2[2];
  33        u32     checksum_old;
  34        u8      reserved3[720];
  35        u32     checksum_high;
  36};
  37
  38static struct bcm963xx_nvram nvram;
  39static int mac_addr_used;
  40
  41void __init bcm63xx_nvram_init(void *addr)
  42{
  43        unsigned int check_len;
  44        u32 crc, expected_crc;
  45
  46        /* extract nvram data */
  47        memcpy(&nvram, addr, sizeof(nvram));
  48
  49        /* check checksum before using data */
  50        if (nvram.version <= 4) {
  51                check_len = offsetof(struct bcm963xx_nvram, reserved3);
  52                expected_crc = nvram.checksum_old;
  53                nvram.checksum_old = 0;
  54        } else {
  55                check_len = sizeof(nvram);
  56                expected_crc = nvram.checksum_high;
  57                nvram.checksum_high = 0;
  58        }
  59
  60        crc = crc32_le(~0, (u8 *)&nvram, check_len);
  61
  62        if (crc != expected_crc)
  63                pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
  64                        expected_crc, crc);
  65}
  66
  67u8 *bcm63xx_nvram_get_name(void)
  68{
  69        return nvram.name;
  70}
  71EXPORT_SYMBOL(bcm63xx_nvram_get_name);
  72
  73int bcm63xx_nvram_get_mac_address(u8 *mac)
  74{
  75        u8 *oui;
  76        int count;
  77
  78        if (mac_addr_used >= nvram.mac_addr_count) {
  79                pr_err("not enough mac addresses\n");
  80                return -ENODEV;
  81        }
  82
  83        memcpy(mac, nvram.mac_addr_base, ETH_ALEN);
  84        oui = mac + ETH_ALEN/2 - 1;
  85        count = mac_addr_used;
  86
  87        while (count--) {
  88                u8 *p = mac + ETH_ALEN - 1;
  89
  90                do {
  91                        (*p)++;
  92                        if (*p != 0)
  93                                break;
  94                        p--;
  95                } while (p != oui);
  96
  97                if (p == oui) {
  98                        pr_err("unable to fetch mac address\n");
  99                        return -ENODEV;
 100                }
 101        }
 102
 103        mac_addr_used++;
 104        return 0;
 105}
 106EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);
 107