diff options
-rw-r--r-- | target/linux/atheros/files/arch/mips/atheros/board.c | 94 |
1 files changed, 77 insertions, 17 deletions
diff --git a/target/linux/atheros/files/arch/mips/atheros/board.c b/target/linux/atheros/files/arch/mips/atheros/board.c index ba427883a7..4fa0e78bdb 100644 --- a/target/linux/atheros/files/arch/mips/atheros/board.c +++ b/target/linux/atheros/files/arch/mips/atheros/board.c @@ -22,16 +22,54 @@ #include <linux/kernel.h> #include <linux/serial.h> #include <linux/serial_core.h> +#include <linux/random.h> #include <asm/bootinfo.h> #include <asm/irq_cpu.h> #include <asm/io.h> #include <ar531x.h> -char *board_config, *radio_config; +char *board_config = NULL; +char *radio_config = NULL; +int broken_boarddata = 0; extern int early_serial_setup(struct uart_port *port); -static u8 *find_board_config(char *flash_limit) +static inline bool +check_radio_magic(unsigned char *addr) +{ + addr += 0x7a; /* offset for flash magic */ + if ((addr[0] == 0x5a) && (addr[1] == 0xa5)) { + return 1; + } + return 0; +} + +static inline bool +check_board_data(unsigned char *flash_limit, unsigned char *addr, bool broken) +{ + /* config magic found */ + if ( *(int *)addr == 0x35333132) + return 1; + + if (!broken) + return 0; + + if (check_radio_magic(addr + 0xf8)) + radio_config = addr + 0xf8; + if ((addr < flash_limit + 0x10000) && + check_radio_magic(addr + 0x10000)) + radio_config = addr + 0x10000; + + if (radio_config) { + /* broken board data detected, use radio data to find the offset, + * user will fix this */ + broken_boarddata = 1; + return 1; + } + return 0; +} + +static u8 *find_board_config(char *flash_limit, bool broken) { char *addr; int found = 0; @@ -40,17 +78,14 @@ static u8 *find_board_config(char *flash_limit) addr >= (char *) (flash_limit - 0x30000); addr -= 0x1000) { - if ( *(int *)addr == 0x35333131) { - /* config magic found */ + if (check_board_data(flash_limit, addr, broken)) { found = 1; break; } } - if (!found) { - printk("WARNING: No board configuration data found!\n"); + if (!found) addr = NULL; - } return addr; } @@ -58,7 +93,7 @@ static u8 *find_board_config(char *flash_limit) static u8 *find_radio_config(char *flash_limit, char *board_config) { int dataFound; - u32 radio_config; + char *radio_config; /* * Now find the start of Radio Configuration data, using heuristics: @@ -66,10 +101,11 @@ static u8 *find_radio_config(char *flash_limit, char *board_config) * at a time until we find non-0xffffffff. */ dataFound = 0; - for (radio_config = (u32) board_config + 0x1000; - (radio_config < (u32) flash_limit); + for (radio_config = board_config + 0x1000; + (radio_config < flash_limit); radio_config += 0x1000) { - if (*(int *)radio_config != 0xffffffff) { + if ((*(u32 *)radio_config != 0xffffffff) && + check_radio_magic(radio_config)) { dataFound = 1; break; } @@ -77,10 +113,11 @@ static u8 *find_radio_config(char *flash_limit, char *board_config) #ifdef CONFIG_ATHEROS_AR5315 if (!dataFound) { /* AR2316 relocates radio config to new location */ - for (radio_config = (u32) board_config + 0xf8; - (radio_config < (u32) flash_limit - 0x1000 + 0xf8); + for (radio_config = board_config + 0xf8; + (radio_config < flash_limit - 0x1000 + 0xf8); radio_config += 0x1000) { - if (*(int *)radio_config != 0xffffffff) { + if ((*(u32 *)radio_config != 0xffffffff) && + check_radio_magic(radio_config)) { dataFound = 1; break; } @@ -98,6 +135,7 @@ static u8 *find_radio_config(char *flash_limit, char *board_config) int __init ar531x_find_config(char *flash_limit) { + struct ar531x_boarddata *bd; unsigned int rcfg_size; char *bcfg, *rcfg; @@ -105,23 +143,45 @@ int __init ar531x_find_config(char *flash_limit) * spiflash driver, accessing the mapped memory directly is no * longer safe */ - bcfg = find_board_config(flash_limit); + bcfg = find_board_config(flash_limit, false); if (!bcfg) + bcfg = find_board_config(flash_limit, true); + if (!bcfg) { + printk("WARNING: No board configuration data found!\n"); return -ENODEV; + } board_config = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL); memcpy(board_config, bcfg, 0x100); + if (broken_boarddata) { + printk("WARNING: broken board data detected\n"); + bd = (struct ar531x_boarddata *)board_config; + if (!memcmp(bd->enet0Mac, "\x00\x00\x00\x00\x00\x00", 6)) { + printk("Fixing up empty mac addresses\n"); + bd->enet0Mac[1] = 0x13; + bd->enet0Mac[2] = 0x37; + get_random_bytes(bd->enet0Mac + 3, 3); + bd->wlan0Mac[1] = 0x13; + bd->wlan0Mac[2] = 0x37; + get_random_bytes(bd->wlan0Mac + 3, 3); + } + } + /* Radio config starts 0x100 bytes after board config, regardless * of what the physical layout on the flash chip looks like */ - rcfg = find_radio_config(flash_limit, bcfg); + if (radio_config) + rcfg = radio_config; + else + rcfg = find_radio_config(flash_limit, bcfg); + if (!rcfg) return -ENODEV; radio_config = board_config + 0x100 + ((rcfg - bcfg) & 0xfff); printk("Radio config found at offset 0x%x(0x%x)\n", rcfg - bcfg, radio_config - board_config); - rcfg_size = BOARD_CONFIG_BUFSZ - ((0x100 + rcfg - bcfg) & (BOARD_CONFIG_BUFSZ - 1)); + rcfg_size = BOARD_CONFIG_BUFSZ - (radio_config - board_config); memcpy(radio_config, rcfg, rcfg_size); return 0; |