Blame view

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