diff options
author | Christian Riesch <christian.riesch@omicron.at> | 2012-07-18 20:23:06 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-19 13:48:07 -0400 |
commit | ceb02c91dd76012e902799e0132ad3ad3e659394 (patch) | |
tree | 4a200ab9b830cc15eebb88a2201d197c30ccf800 /drivers/net/usb | |
parent | 84c9f8c41df9f62a34eb680009b59cc817a76d6e (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.h | 5 | ||||
-rw-r--r-- | drivers/net/usb/asix_common.c | 39 | ||||
-rw-r--r-- | drivers/net/usb/asix_devices.c | 9 | ||||
-rw-r--r-- | drivers/net/usb/ax88172a.c | 3 |
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 */ |
163 | struct asix_data { | 162 | struct 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 | ||
171 | int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, | 170 | int 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 | ||
479 | int asix_get_eeprom_len(struct net_device *net) | 479 | int 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 | ||
487 | int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, | 484 | int 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 | ||
511 | void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) | 519 | void 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 | ||
523 | int asix_set_mac_address(struct net_device *net, void *p) | 528 | int 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 = { | |||
409 | static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) | 406 | static 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: | |||
228 | static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) | 228 | static 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); |