]>
Commit | Line | Data |
---|---|---|
080ce045 AF |
1 | Added smsc95xx.macaddr module parameter to allow the user to |
2 | change the MAC address on boot if there was no MAC on the EEPROM. | |
3 | ||
4 | The parameter take the MAC address in 01:23:45:67:89:ab format and | |
5 | needs to be locally assigned. The MAC get assigned to the first | |
6 | smsc95xx device with no MAC on EEPROM (which resulted in a random | |
7 | MAC before). If there is more than one device without MAC on | |
8 | EEPROM and the user needs set the MAC to a specific device, it | |
9 | can be done by attaching the netdev name (e.g. eth0) to the | |
10 | smsc95xx.macaddr parameter seperated by a ';' as e.g. in | |
11 | '01:23:45:67:89:ab;eth0' | |
12 | ||
13 | This allows e.g. u-boot to pass on PandaBoard or BeagleBoard | |
14 | the by u-boot generated static MAC address to the kernel device | |
15 | to ensure the MAC stays the same during the whole boot process. | |
16 | ||
17 | Signed-off-by: Danny Kukawka <danny.kukawka@...> | |
18 | --- | |
19 | drivers/net/usb/smsc95xx.c | 85 ++++++++++++++++++++++++++++++++++++++++++-- | |
20 | 1 files changed, 82 insertions(+), 3 deletions(-) | |
21 | ||
22 | diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c | |
23 | index d45520e..3198c7d 100644 | |
24 | --- a/drivers/net/usb/smsc95xx.c | |
25 | +++ b/drivers/net/usb/smsc95xx.c | |
26 | @@ -52,6 +52,8 @@ struct smsc95xx_priv { | |
27 | u32 hash_hi; | |
28 | u32 hash_lo; | |
29 | spinlock_t mac_cr_lock; | |
30 | + bool mac_set_from_param; | |
31 | + bool mac_is_random; | |
32 | }; | |
33 | ||
34 | struct usb_context { | |
35 | @@ -63,6 +65,11 @@ static bool turbo_mode = true; | |
36 | module_param(turbo_mode, bool, 0644); | |
37 | MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); | |
38 | ||
39 | +static char *macaddr = ":"; | |
40 | +static bool set_macaddr = false; | |
41 | +module_param(macaddr, charp, 0); | |
42 | +MODULE_PARM_DESC(macaddr, " macaddr=macaddr;[tgt-netdevname] (Set MAC only if there is a device without MAC on EEPROM)"); | |
43 | + | |
44 | static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data) | |
45 | { | |
46 | u32 *buf = kmalloc(4, GFP_KERNEL); | |
47 | @@ -601,8 +608,71 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) | |
48 | return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); | |
49 | } | |
50 | ||
51 | +/* set mac address from the macaddr module parameter */ | |
52 | +static int smsc95xx_init_mac_address_from_param(struct usbnet *dev) | |
53 | +{ | |
54 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
55 | + int i, parsed, ret; | |
56 | + u8 mtbl[ETH_ALEN]; | |
57 | + char *input = NULL; | |
58 | + char *config_param = NULL; | |
59 | + char *netdev_name = NULL; | |
60 | + | |
61 | + parsed = 0; | |
62 | + ret = 0; | |
63 | + | |
64 | + input = kstrdup(macaddr, GFP_KERNEL); | |
65 | + | |
66 | + if (!input) | |
67 | + return -ENOMEM; | |
68 | + | |
69 | + if (strlen(input) >= 17) { | |
70 | + while ((config_param = strsep(&input, ";"))) { | |
71 | + if (parsed == 0) { | |
72 | + if (!mac_pton(config_param, mtbl)) { | |
73 | + ret = 1; | |
74 | + goto parse_err; | |
75 | + } | |
76 | + } else { | |
77 | + netdev_name = config_param; | |
78 | + } | |
79 | + parsed ++; | |
80 | + } | |
81 | + | |
82 | + if (parsed && is_valid_ether_addr(mtbl)) { | |
83 | + if (netdev_name && strlen(netdev_name)) { | |
84 | + if (strcmp(netdev_name, dev->net->name) != 0) { | |
85 | + netif_dbg(dev, ifup, dev->net, "requested devname (%s) didn't match (%s)\n", netdev_name, dev->net->name); | |
86 | + ret = 1; | |
87 | + goto out; | |
88 | + } | |
89 | + } | |
90 | + | |
91 | + for (i = 0; i < ETH_ALEN; i++) { | |
92 | + dev->net->dev_addr[i] = mtbl[i]; | |
93 | + } | |
94 | + | |
95 | + netif_dbg(dev, ifup, dev->net, "set valid MAC address from smsc95xx.macaddr\n"); | |
96 | + set_macaddr = true; | |
97 | + pdata->mac_set_from_param = true; | |
98 | + pdata->mac_is_random = false; | |
99 | + goto out; | |
100 | + } | |
101 | + } | |
102 | + | |
103 | +parse_err: | |
104 | + netif_dbg(dev, ifup, dev->net, "failed to parse (valid) MAC from smsc95xx.macaddr\n"); | |
105 | + set_macaddr = true; | |
106 | +out: | |
107 | + if (input) | |
108 | + kfree(input); | |
109 | + return ret; | |
110 | +} | |
111 | + | |
112 | static void smsc95xx_init_mac_address(struct usbnet *dev) | |
113 | { | |
114 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
115 | + | |
116 | /* try reading mac address from EEPROM */ | |
117 | if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, | |
118 | dev->net->dev_addr) == 0) { | |
119 | @@ -615,16 +685,25 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) | |
120 | ||
121 | /* no eeprom, or eeprom values are invalid. generate random MAC */ | |
122 | random_ether_addr(dev->net->dev_addr); | |
123 | + pdata->mac_is_random = true; | |
124 | netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr\n"); | |
125 | } | |
126 | ||
127 | static int smsc95xx_set_mac_address(struct usbnet *dev) | |
128 | { | |
129 | - u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | | |
130 | - dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24; | |
131 | - u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8; | |
132 | + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); | |
133 | + u32 addr_lo, addr_hi; | |
134 | int ret; | |
135 | ||
136 | + if (pdata->mac_is_random && !pdata->mac_set_from_param && !set_macaddr) { | |
137 | + netif_dbg(dev, ifup, dev->net, "random MAC address, not yet set from smsc95xx.macaddr, try to set it ...\n"); | |
138 | + smsc95xx_init_mac_address_from_param(dev); | |
139 | + } | |
140 | + | |
141 | + addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | | |
142 | + dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24; | |
143 | + addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8; | |
144 | + | |
145 | ret = smsc95xx_write_reg(dev, ADDRL, addr_lo); | |
146 | if (ret < 0) { | |
147 | netdev_warn(dev->net, "Failed to write ADDRL: %d\n", ret); | |
148 | -- | |
149 |