Commit 27aee7c4 authored by David T. Hollis's avatar David T. Hollis Committed by Greg Kroah-Hartman

[PATCH] USB: AX8817x mii/ethtool fixes among others

This patch:
Adds the Intellinet device IDs
Adds msg_level support (to be utilized in the future)
Fixes ethtool/mii support so link checking actually works
Changed timeout on usb_fill_int_urb to support High Speed (mru@users.sf.net)
Added devdbg/err/info defines borrowed from usbnet
Changed strlcpy to strncpy

Key issue not currently resolved (as brought up by mru@users.sf.net) is
that the receive performance is terrible on OHCI.  I ran a set of tests
with ttcp and transmit performance achieved 6146.16 KB/sec  but receive
only yielded 466.26 KB/sec which really sucks (sorry for the technical
jargon).  In porting the driver to 2.5 I had to pull the transmit
queueing that Tivo had originally used for the driver to even function.
My initial attempts at pulling the receive queueing met with many
Ooopses thus I backed off.  Looks like I will need to dig in again on
that one.
parent 829673a9
/* /*
* ASIX AX8817x USB 2.0 10/100/HomePNA Ethernet controller driver * ASIX AX8817x USB 2.0 10/100/HomePNA Ethernet controller driver
* *
* $Id: ax8817x.c,v 1.11 2003/06/15 19:00:02 dhollis Exp $ * $Id: ax8817x.c,v 1.17 2003/07/23 20:46:13 dhollis Exp $
* *
* Copyright (c) 2002-2003 TiVo Inc. * Copyright (c) 2002-2003 TiVo Inc.
* *
...@@ -10,6 +10,12 @@ ...@@ -10,6 +10,12 @@
* *
* History * History
* *
* 2003-07-22 - Dave Hollis <dhollis@davehollis.com> 2.0.1
* * Add Intellinet USB ids
* * Fix mii/ethtool support - link check works!
* * Add msglevel support
* * Shamelessly 'borrowed' devdbg/err/info macros from usbnet
* * Change strlcpy to strncpy
* 2003-06-15 - Dave Hollis <dhollis@davehollis.com> 2.0.0 * 2003-06-15 - Dave Hollis <dhollis@davehollis.com> 2.0.0
* * Remove crc32 inline function, use core kernel instead * * Remove crc32 inline function, use core kernel instead
* * Set sane defaults for rx_buffers * * Set sane defaults for rx_buffers
...@@ -50,7 +56,7 @@ ...@@ -50,7 +56,7 @@
* Known Issues * Known Issues
* *
* Todo * Todo
* Fix mii/ethtool output * Fix receive performance on OHCI
*/ */
#include <linux/slab.h> #include <linux/slab.h>
...@@ -69,7 +75,7 @@ ...@@ -69,7 +75,7 @@
#include <linux/version.h> #include <linux/version.h>
/* Version Information */ /* Version Information */
#define DRIVER_VERSION "v2.0.0" #define DRIVER_VERSION "v2.0.1"
#define DRIVER_AUTHOR "TiVo, Inc." #define DRIVER_AUTHOR "TiVo, Inc."
#define DRIVER_DESC "ASIX AX8817x USB Ethernet driver" #define DRIVER_DESC "ASIX AX8817x USB Ethernet driver"
#define DRIVER_NAME "ax8817x" #define DRIVER_NAME "ax8817x"
...@@ -95,6 +101,7 @@ MODULE_LICENSE("GPL"); ...@@ -95,6 +101,7 @@ MODULE_LICENSE("GPL");
#define AX_RX_MAX ETH_FRAME_LEN #define AX_RX_MAX ETH_FRAME_LEN
#define AX_TIMEOUT_CMD ( HZ / 10 ) #define AX_TIMEOUT_CMD ( HZ / 10 )
#define AX_TIMEOUT_TX ( HZ * 2 ) #define AX_TIMEOUT_TX ( HZ * 2 )
#define AX_MCAST_FILTER_SIZE 8
#define AX_MAX_MCAST 64 #define AX_MAX_MCAST 64
#define AX_DRV_STATE_INITIALIZING 0x00 #define AX_DRV_STATE_INITIALIZING 0x00
...@@ -155,6 +162,7 @@ struct ax8817x_info { ...@@ -155,6 +162,7 @@ struct ax8817x_info {
u8 phy_id; u8 phy_id;
u8 phy_state; u8 phy_state;
u8 drv_state; u8 drv_state;
int msg_level;
}; };
...@@ -167,12 +175,27 @@ const struct usb_device_id ax8817x_id_table[] = { ...@@ -167,12 +175,27 @@ const struct usb_device_id ax8817x_id_table[] = {
{USB_DEVICE(0x0846, 0x1040), driver_info:0x00130103}, {USB_DEVICE(0x0846, 0x1040), driver_info:0x00130103},
/* D-Link DUB-E100 */ /* D-Link DUB-E100 */
{USB_DEVICE(0x2001, 0x1a00), driver_info:0x009f9d9f}, {USB_DEVICE(0x2001, 0x1a00), driver_info:0x009f9d9f},
/* Intellinet USB Ethernet */
{USB_DEVICE(0x0b95, 0x1720), driver_info:0x00130103},
{} {}
}; };
MODULE_DEVICE_TABLE(usb, ax8817x_id_table); MODULE_DEVICE_TABLE(usb, ax8817x_id_table);
#ifdef DEBUG
#define devdbg(ax_info, fmt, arg...) \
printk(KERN_DEBUG "%s: " fmt "\n" , (ax_info)->net->name, ## arg)
#else
#define devdbg(ax_info, fmt, arg...) do {} while(0)
#endif
#define deverr(ax_info, fmt, arg...) \
printk(KERN_ERR "%s: " fmt "\n", (ax_info)->net->name, ## arg)
#define devinfo(ax_info, fmt, arg...) \
do { if ((ax_info)->msg_level >= 1) \
printk(KERN_INFO "%s: " fmt "\n", (ax_info)->net->name, ## arg); \
} while (0)
static void ax_run_ctl_queue(struct ax8817x_info *, struct ax_cmd_req *, static void ax_run_ctl_queue(struct ax8817x_info *, struct ax_cmd_req *,
int); int);
...@@ -880,14 +903,14 @@ static void ax8817x_set_multicast(struct net_device *net) ...@@ -880,14 +903,14 @@ static void ax8817x_set_multicast(struct net_device *net)
u32 crc_bits; u32 crc_bits;
int i; int i;
multi_filter = kmalloc(8, GFP_ATOMIC); multi_filter = kmalloc(AX_MCAST_FILTER_SIZE, GFP_ATOMIC);
if (multi_filter == NULL) { if (multi_filter == NULL) {
/* Oops, couldn't allocate a DMA buffer for setting the multicast /* Oops, couldn't allocate a DMA buffer for setting the multicast
filter. Try all multi mode, although the ax_write_cmd_async filter. Try all multi mode, although the ax_write_cmd_async
will almost certainly fail, too... (but it will printk). */ will almost certainly fail, too... (but it will printk). */
rx_ctl |= 0x02; rx_ctl |= 0x02;
} else { } else {
memset(multi_filter, 0, 8); memset(multi_filter, 0, AX_MCAST_FILTER_SIZE);
/* Build the multicast hash filter. */ /* Build the multicast hash filter. */
for (i = 0; i < net->mc_count; i++) { for (i = 0; i < net->mc_count; i++) {
...@@ -901,7 +924,7 @@ static void ax8817x_set_multicast(struct net_device *net) ...@@ -901,7 +924,7 @@ static void ax8817x_set_multicast(struct net_device *net)
ax_write_cmd_async(ax_info, ax_write_cmd_async(ax_info,
AX_CMD_WRITE_MULTI_FILTER, 0, 0, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
8, multi_filter); AX_MCAST_FILTER_SIZE, multi_filter);
rx_ctl |= 0x10; rx_ctl |= 0x10;
} }
...@@ -915,19 +938,24 @@ static int read_mii_word(struct ax8817x_info *ax_info, __u8 phy, __u8 indx, ...@@ -915,19 +938,24 @@ static int read_mii_word(struct ax8817x_info *ax_info, __u8 phy, __u8 indx,
__u16 * regd) __u16 * regd)
{ {
int ret; int ret;
u8 buf[4];
ax_write_cmd(ax_info, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); devdbg(ax_info,"read_mii_word: phy=%02x, indx=%02x, regd=%04x", phy, indx, *regd);
ret =
ax_read_cmd(ax_info, AX_CMD_READ_MII_REG, phy, indx, 2, regd); ax_write_cmd(ax_info, AX_CMD_SET_SW_MII, 0, 0, 0, &buf);
ax_write_cmd(ax_info, AX_CMD_SET_HW_MII, 0, 0, 0, NULL);
ret = ax_read_cmd(ax_info, AX_CMD_READ_MII_REG, ax_info->phy_id, (__u16)indx, 2, regd);
return 0; devdbg(ax_info,"read_mii_word: AX_CMD_READ_MII_REG ret=%02x, regd=%04x", ret, *regd);
ax_write_cmd(ax_info, AX_CMD_SET_HW_MII, 0, 0, 0, &buf);
return ret;
} }
static int write_mii_word(struct ax8817x_info *ax_info, __u8 phy, static int write_mii_word(struct ax8817x_info *ax_info, __u8 phy,
__u8 indx, __u16 regd) __u8 indx, __u16 regd)
{ {
warn("write_mii_word - not implemented!"); deverr(ax_info, "write_mii_word - not implemented!");
return 0; return 0;
} }
...@@ -936,6 +964,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int loc) ...@@ -936,6 +964,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int loc)
struct ax8817x_info *ax_info = dev->priv; struct ax8817x_info *ax_info = dev->priv;
int res; int res;
devdbg(ax_info, "mdio_read: phy_id=%02x, loc=%02x", phy_id, loc);
read_mii_word(ax_info, phy_id, loc, (u16 *) & res); read_mii_word(ax_info, phy_id, loc, (u16 *) & res);
return res & 0xffff; return res & 0xffff;
} }
...@@ -945,6 +975,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, ...@@ -945,6 +975,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc,
{ {
struct ax8817x_info *ax_info = dev->priv; struct ax8817x_info *ax_info = dev->priv;
devdbg(ax_info, "mdio_write: phy_id=%02x, loc=%02x", phy_id, loc);
write_mii_word(ax_info, phy_id, loc, val); write_mii_word(ax_info, phy_id, loc, val);
} }
...@@ -961,10 +992,10 @@ static int ax8817x_ethtool_ioctl(struct net_device *net, void __user *uaddr) ...@@ -961,10 +992,10 @@ static int ax8817x_ethtool_ioctl(struct net_device *net, void __user *uaddr)
case ETHTOOL_GDRVINFO:{ case ETHTOOL_GDRVINFO:{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strlcpy(info.driver, DRIVER_NAME, strncpy(info.driver, DRIVER_NAME,
ETHTOOL_BUSINFO_LEN); sizeof(info.driver) - 1);
strlcpy(info.version, DRIVER_VERSION, strncpy(info.version, DRIVER_VERSION,
ETHTOOL_BUSINFO_LEN); sizeof(info.version) - 1);
usb_make_path(ax_info->usb, info.bus_info,sizeof info.bus_info); usb_make_path(ax_info->usb, info.bus_info,sizeof info.bus_info);
if (copy_to_user(uaddr, &info, sizeof(info))) if (copy_to_user(uaddr, &info, sizeof(info)))
return -EFAULT; return -EFAULT;
...@@ -993,15 +1024,14 @@ static int ax8817x_ethtool_ioctl(struct net_device *net, void __user *uaddr) ...@@ -993,15 +1024,14 @@ static int ax8817x_ethtool_ioctl(struct net_device *net, void __user *uaddr)
case ETHTOOL_GLINK:{ case ETHTOOL_GLINK:{
struct ethtool_value edata = { ETHTOOL_GLINK }; struct ethtool_value edata = { ETHTOOL_GLINK };
edata.data = edata.data = mii_link_ok(&ax_info->mii);
ax_info->phy_state == AX_PHY_STATE_LINK;
if (copy_to_user(uaddr, &edata, sizeof(edata))) if (copy_to_user(uaddr, &edata, sizeof(edata)))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }
case ETHTOOL_GMSGLVL:{ case ETHTOOL_GMSGLVL:{
struct ethtool_value edata = { ETHTOOL_GMSGLVL }; struct ethtool_value edata = { ETHTOOL_GMSGLVL };
/* edata.data = ax_info->msg_enable; FIXME */ edata.data = ax_info->msg_level;
if (copy_to_user(uaddr, &edata, sizeof(edata))) if (copy_to_user(uaddr, &edata, sizeof(edata)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -1011,62 +1041,24 @@ static int ax8817x_ethtool_ioctl(struct net_device *net, void __user *uaddr) ...@@ -1011,62 +1041,24 @@ static int ax8817x_ethtool_ioctl(struct net_device *net, void __user *uaddr)
if (copy_from_user(&edata, uaddr, sizeof(edata))) if (copy_from_user(&edata, uaddr, sizeof(edata)))
return -EFAULT; return -EFAULT;
/* sp->msg_enable = edata.data; FIXME */ ax_info->msg_level = edata.data;
return 0; return 0;
} }
} }
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static int ax8817x_mii_ioctl(struct net_device *net, struct ifreq *ifr,
int cmd)
{
struct ax8817x_info *ax_info;
struct mii_ioctl_data *data_ptr =
(struct mii_ioctl_data *) &(ifr->ifr_data);
ax_info = net->priv;
switch (cmd) {
case SIOCGMIIPHY:
data_ptr->phy_id = ax_info->phy_id;
break;
case SIOCGMIIREG:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
ax_read_cmd(ax_info, AX_CMD_READ_MII_REG, 0,
data_ptr->reg_num & 0x1f, 2,
&(data_ptr->val_out));
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int ax8817x_ioctl(struct net_device *net, struct ifreq *ifr, static int ax8817x_ioctl(struct net_device *net, struct ifreq *ifr,
int cmd) int cmd)
{ {
struct ax8817x_info *ax_info; struct ax8817x_info *ax_info;
int res;
ax_info = net->priv; ax_info = net->priv;
res = 0;
switch (cmd) {
case SIOCETHTOOL:
res = ax8817x_ethtool_ioctl(net, (void __user *)ifr->ifr_data);
break;
case SIOCGMIIPHY: /* Get address of PHY in use */
case SIOCGMIIREG: /* Read from MII PHY register */
case SIOCSMIIREG: /* Write to MII PHY register */
return ax8817x_mii_ioctl(net, ifr, cmd);
default:
res = -EOPNOTSUPP;
}
return res; if (cmd == SIOCETHTOOL)
return ax8817x_ethtool_ioctl(net, (void __user *) ifr->ifr_data);
return generic_mii_ioctl(&ax_info->mii, (struct mii_ioctl_data *) &ifr->ifr_data, cmd, NULL);
} }
static int ax8817x_net_init(struct net_device *net) static int ax8817x_net_init(struct net_device *net)
...@@ -1219,7 +1211,8 @@ static int ax8817x_bind(struct usb_interface *intf, ...@@ -1219,7 +1211,8 @@ static int ax8817x_bind(struct usb_interface *intf,
ax_info->mii.dev = net; ax_info->mii.dev = net;
ax_info->mii.mdio_read = mdio_read; ax_info->mii.mdio_read = mdio_read;
ax_info->mii.mdio_write = mdio_write; ax_info->mii.mdio_write = mdio_write;
ax_info->mii.phy_id_mask = 0x1f; ax_info->mii.phy_id = ax_info->phy_id;
ax_info->mii.phy_id_mask = 0x3f;
ax_info->mii.reg_num_mask = 0x1f; ax_info->mii.reg_num_mask = 0x1f;
/* Set up the interrupt URB, and start PHY state monitoring */ /* Set up the interrupt URB, and start PHY state monitoring */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment