aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
authorChristian Riesch <christian.riesch@omicron.at>2012-07-18 20:23:06 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-19 13:48:07 -0400
commitceb02c91dd76012e902799e0132ad3ad3e659394 (patch)
tree4a200ab9b830cc15eebb88a2201d197c30ccf800 /drivers/net/usb
parent84c9f8c41df9f62a34eb680009b59cc817a76d6e (diff)
asix: Rework reading from EEPROM
The current code for reading the EEPROM via ethtool in the asix driver has a few issues. It cannot handle odd length values (accesses must be aligned at 16 bit boundaries) and interprets the offset provided by ethtool as 16 bit word offset instead as byte offset. The new code for asix_get_eeprom() introduced by this patch is modeled after the code in drivers/net/ethernet/atheros/atl1e/atl1e_ethtool.c and provides read access to the entire EEPROM with arbitrary offsets and lengths. Signed-off-by: Christian Riesch <christian.riesch@omicron.at> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/asix.h5
-rw-r--r--drivers/net/usb/asix_common.c39
-rw-r--r--drivers/net/usb/asix_devices.c9
-rw-r--r--drivers/net/usb/ax88172a.c3
4 files changed, 24 insertions, 32 deletions
diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h
index 77d9e4c1e235..fbff17748a1d 100644
--- a/drivers/net/usb/asix.h
+++ b/drivers/net/usb/asix.h
@@ -156,8 +156,7 @@
156#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ 156#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */
157 157
158#define AX_EEPROM_MAGIC 0xdeadbeef 158#define AX_EEPROM_MAGIC 0xdeadbeef
159#define AX88172_EEPROM_LEN 0x40 159#define AX_EEPROM_LEN 0x200
160#define AX88772_EEPROM_LEN 0xff
161 160
162/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ 161/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
163struct asix_data { 162struct asix_data {
@@ -165,7 +164,7 @@ struct asix_data {
165 u8 mac_addr[ETH_ALEN]; 164 u8 mac_addr[ETH_ALEN];
166 u8 phymode; 165 u8 phymode;
167 u8 ledmode; 166 u8 ledmode;
168 u8 eeprom_len; 167 u8 res;
169}; 168};
170 169
171int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, 170int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c
index 336f75567091..0b5b2d328a56 100644
--- a/drivers/net/usb/asix_common.c
+++ b/drivers/net/usb/asix_common.c
@@ -478,46 +478,51 @@ int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
478 478
479int asix_get_eeprom_len(struct net_device *net) 479int asix_get_eeprom_len(struct net_device *net)
480{ 480{
481 struct usbnet *dev = netdev_priv(net); 481 return AX_EEPROM_LEN;
482 struct asix_data *data = (struct asix_data *)&dev->data;
483
484 return data->eeprom_len;
485} 482}
486 483
487int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, 484int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
488 u8 *data) 485 u8 *data)
489{ 486{
490 struct usbnet *dev = netdev_priv(net); 487 struct usbnet *dev = netdev_priv(net);
491 __le16 *ebuf = (__le16 *)data; 488 u16 *eeprom_buff;
489 int first_word, last_word;
492 int i; 490 int i;
493 491
494 /* Crude hack to ensure that we don't overwrite memory 492 if (eeprom->len == 0)
495 * if an odd length is supplied
496 */
497 if (eeprom->len % 2)
498 return -EINVAL; 493 return -EINVAL;
499 494
500 eeprom->magic = AX_EEPROM_MAGIC; 495 eeprom->magic = AX_EEPROM_MAGIC;
501 496
497 first_word = eeprom->offset >> 1;
498 last_word = (eeprom->offset + eeprom->len - 1) >> 1;
499
500 eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
501 GFP_KERNEL);
502 if (!eeprom_buff)
503 return -ENOMEM;
504
502 /* ax8817x returns 2 bytes from eeprom on read */ 505 /* ax8817x returns 2 bytes from eeprom on read */
503 for (i=0; i < eeprom->len / 2; i++) { 506 for (i = first_word; i <= last_word; i++) {
504 if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, 507 if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2,
505 eeprom->offset + i, 0, 2, &ebuf[i]) < 0) 508 &(eeprom_buff[i - first_word])) < 0) {
506 return -EINVAL; 509 kfree(eeprom_buff);
510 return -EIO;
511 }
507 } 512 }
513
514 memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
515 kfree(eeprom_buff);
508 return 0; 516 return 0;
509} 517}
510 518
511void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) 519void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
512{ 520{
513 struct usbnet *dev = netdev_priv(net);
514 struct asix_data *data = (struct asix_data *)&dev->data;
515
516 /* Inherit standard device info */ 521 /* Inherit standard device info */
517 usbnet_get_drvinfo(net, info); 522 usbnet_get_drvinfo(net, info);
518 strncpy (info->driver, DRIVER_NAME, sizeof info->driver); 523 strncpy (info->driver, DRIVER_NAME, sizeof info->driver);
519 strncpy (info->version, DRIVER_VERSION, sizeof info->version); 524 strncpy (info->version, DRIVER_VERSION, sizeof info->version);
520 info->eedump_len = data->eeprom_len; 525 info->eedump_len = AX_EEPROM_LEN;
521} 526}
522 527
523int asix_set_mac_address(struct net_device *net, void *p) 528int asix_set_mac_address(struct net_device *net, void *p)
diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c
index ed9403b0c437..658c08fe2c03 100644
--- a/drivers/net/usb/asix_devices.c
+++ b/drivers/net/usb/asix_devices.c
@@ -201,9 +201,6 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
201 u8 buf[ETH_ALEN]; 201 u8 buf[ETH_ALEN];
202 int i; 202 int i;
203 unsigned long gpio_bits = dev->driver_info->data; 203 unsigned long gpio_bits = dev->driver_info->data;
204 struct asix_data *data = (struct asix_data *)&dev->data;
205
206 data->eeprom_len = AX88172_EEPROM_LEN;
207 204
208 usbnet_get_endpoints(dev,intf); 205 usbnet_get_endpoints(dev,intf);
209 206
@@ -409,12 +406,9 @@ static const struct net_device_ops ax88772_netdev_ops = {
409static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) 406static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
410{ 407{
411 int ret, embd_phy; 408 int ret, embd_phy;
412 struct asix_data *data = (struct asix_data *)&dev->data;
413 u8 buf[ETH_ALEN]; 409 u8 buf[ETH_ALEN];
414 u32 phyid; 410 u32 phyid;
415 411
416 data->eeprom_len = AX88772_EEPROM_LEN;
417
418 usbnet_get_endpoints(dev,intf); 412 usbnet_get_endpoints(dev,intf);
419 413
420 /* Get the MAC address */ 414 /* Get the MAC address */
@@ -767,9 +761,6 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
767{ 761{
768 int ret; 762 int ret;
769 u8 buf[ETH_ALEN]; 763 u8 buf[ETH_ALEN];
770 struct asix_data *data = (struct asix_data *)&dev->data;
771
772 data->eeprom_len = AX88772_EEPROM_LEN;
773 764
774 usbnet_get_endpoints(dev,intf); 765 usbnet_get_endpoints(dev,intf);
775 766
diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c
index 3d0f8fa05386..97dce0f567d2 100644
--- a/drivers/net/usb/ax88172a.c
+++ b/drivers/net/usb/ax88172a.c
@@ -228,12 +228,9 @@ err:
228static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) 228static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf)
229{ 229{
230 int ret; 230 int ret;
231 struct asix_data *data = (struct asix_data *)&dev->data;
232 u8 buf[ETH_ALEN]; 231 u8 buf[ETH_ALEN];
233 struct ax88172a_private *priv; 232 struct ax88172a_private *priv;
234 233
235 data->eeprom_len = AX88772_EEPROM_LEN;
236
237 usbnet_get_endpoints(dev, intf); 234 usbnet_get_endpoints(dev, intf);
238 235
239 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 236 priv = kzalloc(sizeof(*priv), GFP_KERNEL);