summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2015-06-10 13:35:04 +0200
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2015-06-10 13:35:04 +0200
commit090a9fba60fb60d58ef9fc29d7b0c93f08ce2c9e (patch)
tree39ac5d0c7bd67e0b0df0ae803c36cd675fd2a7b2 /drivers
parent0aa8350c3e98bcfebd55ab7d07e70baafcb55811 (diff)
colibri_t20/t30: net: usb: asix: ethernet mac address handling
Revise Ethernet MAC address assignment: should now handle up to two instances of custom user MACs (2nd one with a 0x100000 offset). This way customer does not have to worry about NVM on a secondary Ethernet on the carrier board and still gets a valid official MAC address from us (e.g. analogous to how we did it on our Protea carrier board). Please note that instead of defaulting to the default ASIX MAC address if no valid one is encountered this driver now generates a random one pre-fixed with the ASIX OUI.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/usb/asix.c72
1 files changed, 71 insertions, 1 deletions
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index e317a1e53bb2..9600516bb97c 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -49,6 +49,9 @@ KERN_INFO "ASIX USB Ethernet Adapter:v" DRV_VERSION
" " __TIME__ " " __DATE__ "\n"
" http://www.asix.com.tw\n";
+static char g_mac_addr[ETH_ALEN];
+static int g_usr_mac = 0;
+
/* configuration of maximum bulk in size */
static int bsize = AX88772B_MAX_BULKIN_16K;
module_param(bsize, int, 0);
@@ -69,6 +72,39 @@ static void ax8817x_mdio_write_le(struct net_device *netdev, int phy_id,
static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc);
static int ax88772b_set_csums(struct usbnet *dev);
+/* Retrieve user set MAC address */
+static int __init setup_asix_mac(char *macstr)
+{
+ int i, j;
+ unsigned char result, value;
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ result = 0;
+
+ if (i != 5 && *(macstr + 2) != ':')
+ return -1;
+
+ for (j = 0; j < 2; j++) {
+ if (isxdigit(*macstr)
+ && (value =
+ isdigit(*macstr) ? *macstr -
+ '0' : toupper(*macstr) - 'A' + 10) < 16) {
+ result = result * 16 + value;
+ macstr++;
+ } else
+ return -1;
+ }
+
+ macstr++;
+ g_mac_addr[i] = result;
+ }
+
+ g_usr_mac = 1;
+
+ return 0;
+}
+__setup("asix_mac=", setup_asix_mac);
+
/* ASIX AX8817X based USB 2.0 Ethernet Devices */
static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
@@ -1171,12 +1207,32 @@ static int ax8817x_check_ether_addr(struct usbnet *dev)
static int ax8817x_get_mac(struct usbnet *dev, u8* buf)
{
int ret, i;
-
+ u8 default_asix_mac[ETH_ALEN] = { 0x00, 0x0e, 0xc6, 0x87, 0x72, 0x01 };
ret = access_eeprom_mac(dev, buf, 0x04, 0);
if (ret < 0)
goto out;
+ /*
+ * Check for default ASIX MAC (e.g. 00:0e:c6:87:72:01) in case of no
+ * EEPROM being present
+ */
+ if (!memcmp(dev->net->dev_addr, default_asix_mac, ETH_ALEN)) {
+ if (g_usr_mac && (g_usr_mac < 3)) {
+ /* Get user set MAC address */
+ if (g_usr_mac == 2) {
+ /* 0x100000 offset for 2nd Ethernet MAC */
+ g_mac_addr[3] += 0x10;
+ if (g_mac_addr[3] < 0x10)
+ devwarn(dev, "MAC address byte 3 "
+ "(0x%02x) wrap around",
+ g_mac_addr[3]);
+ }
+ memcpy(dev->net->dev_addr, g_mac_addr, ETH_ALEN);
+ g_usr_mac++;
+ } else devwarn(dev, "using default ASIX MAC");
+ }
+
if (ax8817x_check_ether_addr(dev)) {
ret = access_eeprom_mac(dev, dev->net->dev_addr, 0x04, 1);
if (ret < 0) {
@@ -2255,6 +2311,20 @@ static void ax88772b_unbind(struct usbnet *dev, struct usb_interface *intf)
struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv;
if (ax772b_data) {
+ /* Check for user set MAC address */
+ if (!memcmp(dev->net->dev_addr, g_mac_addr, ETH_ALEN)) {
+ /* Release user set MAC address */
+ g_usr_mac--;
+
+ if (g_usr_mac == 2) {
+ /* 0x100000 offset for 2nd Ethernet MAC */
+ g_mac_addr[3] -= 0x10;
+ if (g_mac_addr[3] > 0xf0)
+ devwarn(dev, "MAC address byte 3 "
+ "(0x%02x) wrap around",
+ g_mac_addr[3]);
+ }
+ }
flush_workqueue(ax772b_data->ax_work);
destroy_workqueue(ax772b_data->ax_work);