Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Christian Riesch and committed by
David S. Miller
ceb02c91 84c9f8c4

+24 -32
+2 -3
drivers/net/usb/asix.h
··· 156 156 #define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ 157 157 158 158 #define AX_EEPROM_MAGIC 0xdeadbeef 159 - #define AX88172_EEPROM_LEN 0x40 160 - #define AX88772_EEPROM_LEN 0xff 159 + #define AX_EEPROM_LEN 0x200 161 160 162 161 /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ 163 162 struct asix_data { ··· 164 165 u8 mac_addr[ETH_ALEN]; 165 166 u8 phymode; 166 167 u8 ledmode; 167 - u8 eeprom_len; 168 + u8 res; 168 169 }; 169 170 170 171 int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+22 -17
drivers/net/usb/asix_common.c
··· 478 478 479 479 int asix_get_eeprom_len(struct net_device *net) 480 480 { 481 - struct usbnet *dev = netdev_priv(net); 482 - struct asix_data *data = (struct asix_data *)&dev->data; 483 - 484 - return data->eeprom_len; 481 + return AX_EEPROM_LEN; 485 482 } 486 483 487 484 int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, 488 485 u8 *data) 489 486 { 490 487 struct usbnet *dev = netdev_priv(net); 491 - __le16 *ebuf = (__le16 *)data; 488 + u16 *eeprom_buff; 489 + int first_word, last_word; 492 490 int i; 493 491 494 - /* Crude hack to ensure that we don't overwrite memory 495 - * if an odd length is supplied 496 - */ 497 - if (eeprom->len % 2) 492 + if (eeprom->len == 0) 498 493 return -EINVAL; 499 494 500 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 505 /* ax8817x returns 2 bytes from eeprom on read */ 503 - for (i=0; i < eeprom->len / 2; i++) { 504 - if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, 505 - eeprom->offset + i, 0, 2, &ebuf[i]) < 0) 506 - return -EINVAL; 506 + for (i = first_word; i <= last_word; i++) { 507 + if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2, 508 + &(eeprom_buff[i - first_word])) < 0) { 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 516 return 0; 509 517 } 510 518 511 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 521 /* Inherit standard device info */ 517 522 usbnet_get_drvinfo(net, info); 518 523 strncpy (info->driver, DRIVER_NAME, sizeof info->driver); 519 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 528 int asix_set_mac_address(struct net_device *net, void *p)
-9
drivers/net/usb/asix_devices.c
··· 201 201 u8 buf[ETH_ALEN]; 202 202 int i; 203 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 205 usbnet_get_endpoints(dev,intf); 209 206 ··· 406 409 static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) 407 410 { 408 411 int ret, embd_phy; 409 - struct asix_data *data = (struct asix_data *)&dev->data; 410 412 u8 buf[ETH_ALEN]; 411 413 u32 phyid; 412 - 413 - data->eeprom_len = AX88772_EEPROM_LEN; 414 414 415 415 usbnet_get_endpoints(dev,intf); 416 416 ··· 761 767 { 762 768 int ret; 763 769 u8 buf[ETH_ALEN]; 764 - struct asix_data *data = (struct asix_data *)&dev->data; 765 - 766 - data->eeprom_len = AX88772_EEPROM_LEN; 767 770 768 771 usbnet_get_endpoints(dev,intf); 769 772
-3
drivers/net/usb/ax88172a.c
··· 228 228 static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) 229 229 { 230 230 int ret; 231 - struct asix_data *data = (struct asix_data *)&dev->data; 232 231 u8 buf[ETH_ALEN]; 233 232 struct ax88172a_private *priv; 234 - 235 - data->eeprom_len = AX88772_EEPROM_LEN; 236 233 237 234 usbnet_get_endpoints(dev, intf); 238 235