drivers/net/r8168: Get mac address from VPD

If RT8168_GET_MAC_FROM_VPD selected, use r8168
driver with some slight mods to check the VPD
for a mac address.  Otherwise, check for mac
address in cbfs.  Use default mac address if
cannot find one.

BUG=b:62090148, b:35775024
BRANCH=None
TEST=Boot to kernel.  Insert mac address into VPD
       vpd -s ethernet_mac=<address>
     reboot the system.
     Ensure we have ip address and corresponding mac
     address with ifconfig.
     Ensure ethernet controller shows up with lspci.

Change-Id: I7ff29de2c4c3635dc786686cc071c68d51b0f975
Signed-off-by: Shelley Chen <shchen@chromium.org>
Reviewed-on: https://review.coreboot.org/20008
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
This commit is contained in:
Shelley Chen 2017-06-12 18:29:24 -07:00 committed by Martin Roth
parent 5aa64b97db
commit 0528b6132e
2 changed files with 108 additions and 20 deletions

View File

@ -6,10 +6,15 @@ config REALTEK_8168_RESET
config REALTEK_8168_MACADDRESS config REALTEK_8168_MACADDRESS
string "Realtek rt8168 mac address" string "Realtek rt8168 mac address"
depends on REALTEK_8168_RESET depends on REALTEK_8168_RESET && !RT8168_GET_MAC_FROM_VPD
default "00:e0:4c:00:c0:b0" default "00:e0:4c:00:c0:b0"
help help
This is a string to set the mac address on a Realtek rt8168 card. This is a string to set the mac address on a Realtek rt8168 card.
It must be in the form of "xx:xx:xx:xx:xx:xx", where x is a It must be in the form of "xx:xx:xx:xx:xx:xx", where x is a
hexadecimal number for it to be valid. Failing to do so will hexadecimal number for it to be valid. Failing to do so will
result in the default macaddress being used. result in the default macaddress being used.
config RT8168_GET_MAC_FROM_VPD
bool
default n
select REALTEK_8168_RESET

View File

@ -24,12 +24,13 @@
#include <cbfs.h> #include <cbfs.h>
#include <string.h> #include <string.h>
#include <arch/io.h> #include <arch/io.h>
#include <console/console.h>
#include <device/device.h> #include <device/device.h>
#include <device/pci.h> #include <device/pci.h>
#include <device/pci_ops.h> #include <device/pci_ops.h>
#include <device/pci_def.h> #include <device/pci_def.h>
#include <delay.h> #include <delay.h>
#include <console/console.h> #include <fmap.h>
#define NIC_TIMEOUT 1000 #define NIC_TIMEOUT 1000
@ -40,6 +41,32 @@
#define CFG_9346_LOCK 0x00 #define CFG_9346_LOCK 0x00
#define CFG_9346_UNLOCK 0xc0 #define CFG_9346_UNLOCK 0xc0
/**
* search: Find first instance of string in a given region
* @param p string to find
* @param a start address of region to search
* @param lengthp length of string to search for
* @param lengtha length of region to search in
* @return offset offset from start address a where string was found.
* If string not found, return lengtha.
*/
static size_t search(const char *p, const u8 *a, size_t lengthp,
size_t lengtha)
{
size_t i, j;
if (lengtha < lengthp)
return lengtha;
/* Searching */
for (j = 0; j <= lengtha - lengthp; j++) {
for (i = 0; i < lengthp && p[i] == a[i + j]; i++)
;
if (i >= lengthp)
return j;
}
return lengtha;
}
static u8 get_hex_digit(const u8 c) static u8 get_hex_digit(const u8 c)
{ {
u8 ret = 0; u8 ret = 0;
@ -51,21 +78,78 @@ static u8 get_hex_digit(const u8 c)
ret = c - 'a' + 0x0a; ret = c - 'a' + 0x0a;
} }
if (ret > 0x0f) { if (ret > 0x0f) {
printk(BIOS_DEBUG, "Error: Invalid hex digit found: " printk(BIOS_ERR, "Error: Invalid hex digit found: "
"%c - 0x%02x\n", (char)c, c); "%c - 0x%02x\n", (char)c, c);
ret = 0; ret = 0;
} }
return ret; return ret;
} }
#define MACLEN 17
static enum cb_err fetch_mac_string_vpd(u8 *macstrbuf)
{
struct region_device rdev;
void *search_address;
size_t search_length;
size_t offset;
char key[] = "ethernet_mac";
if (fmap_locate_area_as_rdev("RO_VPD", &rdev)) {
printk(BIOS_ERR, "Error: Couldn't find RO_VPD region.");
return CB_ERR;
}
search_address = rdev_mmap_full(&rdev);
if (search_address == NULL) {
printk(BIOS_ERR, "LAN: VPD not found.\n");
return CB_ERR;
}
search_length = region_device_sz(&rdev);
offset = search(key, search_address, strlen(key),
search_length);
if (offset == search_length) {
printk(BIOS_ERR,
"Error: Could not locate '%s' in VPD\n", key);
return CB_ERR;
}
printk(BIOS_DEBUG, "Located '%s' in VPD\n", key);
offset += sizeof(key); /* move to next character */
if (offset + MACLEN > search_length) {
printk(BIOS_ERR, "Search result too small!\n");
return CB_ERR;
}
memcpy(macstrbuf, search_address + offset, MACLEN);
return CB_SUCCESS;
}
static enum cb_err fetch_mac_string_cbfs(u8 *macstrbuf)
{
struct cbfsf fh;
uint32_t matchraw = CBFS_TYPE_RAW;
if (!cbfs_boot_locate(&fh, "rt8168-macaddress", &matchraw)) {
/* check the cbfs for the mac address */
if (rdev_readat(&fh.data, macstrbuf, 0, MACLEN) != MACLEN) {
printk(BIOS_ERR, "r8168: Error reading MAC from CBFS\n");
return CB_ERR;
}
return CB_SUCCESS;
}
return CB_ERR;
}
static void get_mac_address(u8 *macaddr, const u8 *strbuf) static void get_mac_address(u8 *macaddr, const u8 *strbuf)
{ {
size_t offset = 0; size_t offset = 0;
int i; int i;
if ( (strbuf[2] != ':') || (strbuf[5] != ':') || if ((strbuf[2] != ':') || (strbuf[5] != ':') ||
(strbuf[8] != ':') || (strbuf[11] != ':') || (strbuf[8] != ':') || (strbuf[11] != ':') ||
(strbuf[14] != ':') ) { (strbuf[14] != ':')) {
printk(BIOS_ERR, "r8168: ignore invalid MAC address in cbfs\n"); printk(BIOS_ERR, "r8168: ignore invalid MAC address in cbfs\n");
return; return;
} }
@ -78,25 +162,24 @@ static void get_mac_address(u8 *macaddr, const u8 *strbuf)
} }
} }
#define MACLEN 17
static void program_mac_address(struct device *dev, u16 io_base) static void program_mac_address(struct device *dev, u16 io_base)
{ {
struct cbfsf fh;
uint32_t matchraw = CBFS_TYPE_RAW;
u8 macstrbuf[MACLEN] = { 0 }; u8 macstrbuf[MACLEN] = { 0 };
int i = 0; int i = 0;
/* Default MAC Address of 00:E0:4C:00:C0:B0 */
u8 mac[6] = { 0x00, 0xe0, 0x4c, 0x00, 0xc0, 0xb0 }; u8 mac[6] = { 0x00, 0xe0, 0x4c, 0x00, 0xc0, 0xb0 };
if (!cbfs_boot_locate(&fh, "rt8168-macaddress", &matchraw)) { /* check the VPD for the mac address */
if (rdev_readat(&fh.data, macstrbuf, 0, MACLEN) == MACLEN) if (IS_ENABLED(CONFIG_RT8168_GET_MAC_FROM_VPD)) {
get_mac_address(mac, macstrbuf); if (fetch_mac_string_vpd(macstrbuf) != CB_SUCCESS)
else printk(BIOS_ERR, "r8168: mac address not found in VPD,"
printk(BIOS_ERR, "r8168: Error reading MAC from CBFS\n"); " using default 00:e0:4c:00:c0:b0\n");
} else { } else {
printk(BIOS_ERR, "r8168: 'rt8168-macaddress' not found in CBFS," if (fetch_mac_string_cbfs(macstrbuf) != CB_SUCCESS)
" using default 00:e0:4c:00:c0:b0\n"); printk(BIOS_ERR, "r8168: Error reading MAC from CBFS,"
" using default 00:e0:4c:00:c0:b0\n");
} }
get_mac_address(mac, macstrbuf);
/* Reset NIC */ /* Reset NIC */
printk(BIOS_DEBUG, "r8168: Resetting NIC..."); printk(BIOS_DEBUG, "r8168: Resetting NIC...");
@ -106,7 +189,7 @@ static void program_mac_address(struct device *dev, u16 io_base)
while (i < NIC_TIMEOUT && (inb(io_base + CMD_REG) & CMD_REG_RESET)) { while (i < NIC_TIMEOUT && (inb(io_base + CMD_REG) & CMD_REG_RESET)) {
udelay(1000); udelay(1000);
if (++i >= NIC_TIMEOUT) if (++i >= NIC_TIMEOUT)
printk(BIOS_DEBUG, "timeout waiting for nic to reset\n"); printk(BIOS_ERR, "timeout waiting for nic to reset\n");
} }
if (i < NIC_TIMEOUT) if (i < NIC_TIMEOUT)
printk(BIOS_DEBUG, "done\n"); printk(BIOS_DEBUG, "done\n");
@ -143,7 +226,7 @@ static void r8168_init(struct device *dev)
if (io_base) if (io_base)
program_mac_address(dev, io_base); program_mac_address(dev, io_base);
else else
printk(BIOS_DEBUG, "r8168: Error cant find MMIO resource\n"); printk(BIOS_ERR, "r8168: Error cant find MMIO resource\n");
} }
static struct device_operations r8168_ops = { static struct device_operations r8168_ops = {