Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * BCM947xx nvram variable access
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2005 Broadcom Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/bcm47xx_nvram.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #define NVRAM_MAGIC			0x48534C46	/* 'FLSH' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #define NVRAM_SPACE			0x10000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #define NVRAM_MAX_GPIO_ENTRIES		32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #define NVRAM_MAX_GPIO_VALUE_LEN	30
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #define FLASH_MIN		0x00020000	/* Minimum flash size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) struct nvram_header {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	u32 magic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 	u32 len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	u32 config_ncdl;	/* ncdl values for memc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) static char nvram_buf[NVRAM_SPACE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) static size_t nvram_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) static const u32 nvram_sizes[] = {0x6000, 0x8000, 0xF000, 0x10000};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) static u32 find_nvram_size(void __iomem *end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	struct nvram_header __iomem *header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 		header = (struct nvram_header *)(end - nvram_sizes[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 		if (header->magic == NVRAM_MAGIC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 			return nvram_sizes[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) /* Probe for NVRAM header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) static int nvram_find_and_copy(void __iomem *iobase, u32 lim)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	struct nvram_header __iomem *header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	u32 off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	u32 size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	if (nvram_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 		pr_warn("nvram already initialized\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 		return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	/* TODO: when nvram is on nand flash check for bad blocks first. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	off = FLASH_MIN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	while (off <= lim) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 		/* Windowed flash access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 		size = find_nvram_size(iobase + off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		if (size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 			header = (struct nvram_header *)(iobase + off - size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 			goto found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 		off <<= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	header = (struct nvram_header *)(iobase + 4096);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	if (header->magic == NVRAM_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		size = NVRAM_SPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 		goto found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	header = (struct nvram_header *)(iobase + 1024);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	if (header->magic == NVRAM_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 		size = NVRAM_SPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 		goto found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	pr_err("no nvram found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) found:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	__ioread32_copy(nvram_buf, header, sizeof(*header) / 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	nvram_len = ((struct nvram_header *)(nvram_buf))->len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	if (nvram_len > size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 		nvram_len = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	if (nvram_len >= NVRAM_SPACE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		       nvram_len, NVRAM_SPACE - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 		nvram_len = NVRAM_SPACE - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	/* proceed reading data after header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	__ioread32_copy(nvram_buf + sizeof(*header), header + 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 			DIV_ROUND_UP(nvram_len, 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	nvram_buf[NVRAM_SPACE - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)  * On bcm47xx we need access to the NVRAM very early, so we can't use mtd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)  * subsystem to access flash. We can't even use platform device / driver to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)  * store memory offset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)  * To handle this we provide following symbol. It's supposed to be called as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)  * soon as we get info about flash device, before any NVRAM entry is needed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) int bcm47xx_nvram_init_from_mem(u32 base, u32 lim)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	void __iomem *iobase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	iobase = ioremap(base, lim);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	if (!iobase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	err = nvram_find_and_copy(iobase, lim);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	iounmap(iobase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static int nvram_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #ifdef CONFIG_MTD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	struct mtd_info *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	struct nvram_header header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	size_t bytes_read;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	mtd = get_mtd_device_nm("nvram");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	if (IS_ERR(mtd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	err = mtd_read(mtd, 0, sizeof(header), &bytes_read, (uint8_t *)&header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	if (!err && header.magic == NVRAM_MAGIC &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	    header.len > sizeof(header)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 		nvram_len = header.len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 		if (nvram_len >= NVRAM_SPACE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 			pr_err("nvram on flash (%zu bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 				nvram_len, NVRAM_SPACE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 			nvram_len = NVRAM_SPACE - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 		err = mtd_read(mtd, 0, nvram_len, &nvram_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 			       (u8 *)nvram_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	char *var, *value, *end, *eq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	if (!name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	if (!nvram_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 		err = nvram_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 			return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	/* Look for name=value and return value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	var = &nvram_buf[sizeof(struct nvram_header)];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	end = nvram_buf + sizeof(nvram_buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	while (var < end && *var) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 		eq = strchr(var, '=');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		if (!eq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		value = eq + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		if (eq - var == strlen(name) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		    strncmp(var, name, eq - var) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 			return snprintf(val, val_len, "%s", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 		var = value + strlen(value) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) EXPORT_SYMBOL(bcm47xx_nvram_getenv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) int bcm47xx_nvram_gpio_pin(const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	int i, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	char nvram_var[] = "gpioXX";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	char buf[NVRAM_MAX_GPIO_VALUE_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	/* TODO: Optimize it to don't call getenv so many times */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	for (i = 0; i < NVRAM_MAX_GPIO_ENTRIES; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 		err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 		if (err <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 		if (err <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		if (!strcmp(name, buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 			return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) char *bcm47xx_nvram_get_contents(size_t *nvram_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	char *nvram;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 	if (!nvram_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 		err = nvram_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 		if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 			return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	*nvram_size = nvram_len - sizeof(struct nvram_header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	nvram = vmalloc(*nvram_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	if (!nvram)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	memcpy(nvram, &nvram_buf[sizeof(struct nvram_header)], *nvram_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 	return nvram;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) EXPORT_SYMBOL(bcm47xx_nvram_get_contents);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) MODULE_LICENSE("GPL v2");