add ax88772C AX88772C_eeprom_tools
16 files added
2 files modified
.. | .. |
---|
2076 | 2076 | CONFIG_USB_RTL8152=y |
---|
2077 | 2077 | # CONFIG_USB_LAN78XX is not set |
---|
2078 | 2078 | CONFIG_USB_USBNET=y |
---|
2079 | | -CONFIG_USB_NET_AX8817X=y |
---|
2080 | | -CONFIG_USB_NET_AX88179_178A=y |
---|
| 2079 | +# CONFIG_USB_NET_AX8817X is not set |
---|
| 2080 | +# CONFIG_USB_NET_AX88179_178A is not set |
---|
2081 | 2081 | CONFIG_USB_NET_CDCETHER=y |
---|
2082 | 2082 | # CONFIG_USB_NET_CDC_EEM is not set |
---|
2083 | | -CONFIG_USB_NET_CDC_NCM=y |
---|
| 2083 | +# CONFIG_USB_NET_CDC_NCM is not set |
---|
2084 | 2084 | # CONFIG_USB_NET_HUAWEI_CDC_NCM is not set |
---|
2085 | 2085 | # CONFIG_USB_NET_CDC_MBIM is not set |
---|
2086 | 2086 | # CONFIG_USB_NET_DM9601 is not set |
---|
.. | .. |
---|
2089 | 2089 | # CONFIG_USB_NET_SMSC75XX is not set |
---|
2090 | 2090 | # CONFIG_USB_NET_SMSC95XX is not set |
---|
2091 | 2091 | # CONFIG_USB_NET_GL620A is not set |
---|
2092 | | -CONFIG_USB_NET_NET1080=y |
---|
| 2092 | +# CONFIG_USB_NET_NET1080 is not set |
---|
2093 | 2093 | # CONFIG_USB_NET_PLUSB is not set |
---|
2094 | 2094 | # CONFIG_USB_NET_MCS7830 is not set |
---|
2095 | 2095 | # CONFIG_USB_NET_RNDIS_HOST is not set |
---|
.. | .. |
---|
| 1 | +/* |
---|
| 2 | + * ASIX AX8817X based USB 2.0 Ethernet Devices |
---|
| 3 | + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> |
---|
| 4 | + * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> |
---|
| 5 | + * Copyright (c) 2002-2003 TiVo Inc. |
---|
| 6 | + * |
---|
| 7 | + * This program is free software; you can redistribute it and/or modify |
---|
| 8 | + * it under the terms of the GNU General Public License as published by |
---|
| 9 | + * the Free Software Foundation; either version 2 of the License, or |
---|
| 10 | + * (at your option) any later version. |
---|
| 11 | + * |
---|
| 12 | + * This program is distributed in the hope that it will be useful, |
---|
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 15 | + * GNU General Public License for more details. |
---|
| 16 | + * |
---|
| 17 | + * You should have received a copy of the GNU General Public License |
---|
| 18 | + * along with this program; if not, write to the Free Software |
---|
| 19 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 20 | + */ |
---|
| 21 | + |
---|
| 22 | +/* debug messages, extra info */ |
---|
| 23 | +/* #define DEBUG */ |
---|
| 24 | + |
---|
| 25 | +#include <linux/version.h> |
---|
| 26 | +/* #include <linux/config.h> */ |
---|
| 27 | +#ifdef CONFIG_USB_DEBUG |
---|
| 28 | +# define DEBUG |
---|
| 29 | +#endif |
---|
| 30 | +#include <linux/module.h> |
---|
| 31 | +#include <linux/kmod.h> |
---|
| 32 | +#include <linux/sched.h> |
---|
| 33 | +#include <linux/init.h> |
---|
| 34 | +#include <linux/netdevice.h> |
---|
| 35 | +#include <linux/etherdevice.h> |
---|
| 36 | +#include <linux/ethtool.h> |
---|
| 37 | +#include <linux/workqueue.h> |
---|
| 38 | +#include <linux/mii.h> |
---|
| 39 | +#include <linux/usb.h> |
---|
| 40 | +#include <linux/crc32.h> |
---|
| 41 | + |
---|
| 42 | +#include "axusbnet.c" |
---|
| 43 | +#include "asix.h" |
---|
| 44 | +#include "command.h" |
---|
| 45 | + |
---|
| 46 | +#define DRV_VERSION "4.24.100" |
---|
| 47 | + |
---|
| 48 | +static char version[] = |
---|
| 49 | +KERN_INFO "ASIX USB Ethernet Adapter:v" DRV_VERSION |
---|
| 50 | + " http://www.asix.com.tw\n"; |
---|
| 51 | + |
---|
| 52 | +/* configuration of maximum bulk in size */ |
---|
| 53 | +static int bsize = AX88772B_MAX_BULKIN_16K; |
---|
| 54 | +module_param(bsize, int, 0); |
---|
| 55 | +MODULE_PARM_DESC(bsize, "Maximum transfer size per bulk"); |
---|
| 56 | + |
---|
| 57 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 58 | +static void ax88772b_link_reset(void *data); |
---|
| 59 | +static void ax88772a_link_reset(void *data); |
---|
| 60 | +static void ax88772_link_reset(void *data); |
---|
| 61 | +#else |
---|
| 62 | +static void ax88772b_link_reset(struct work_struct *work); |
---|
| 63 | +static void ax88772a_link_reset(struct work_struct *work); |
---|
| 64 | +static void ax88772_link_reset(struct work_struct *work); |
---|
| 65 | +#endif |
---|
| 66 | +static int ax88772a_phy_powerup(struct usbnet *dev); |
---|
| 67 | +static void ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, |
---|
| 68 | + int loc, int val); |
---|
| 69 | +static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc); |
---|
| 70 | +static int ax88772b_set_csums(struct usbnet *dev); |
---|
| 71 | +static int ax88772b_external_phyinit(struct usbnet *dev); |
---|
| 72 | + |
---|
| 73 | +/* ASIX AX8817X based USB 2.0 Ethernet Devices */ |
---|
| 74 | + |
---|
| 75 | +static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
---|
| 76 | + u16 size, void *data) |
---|
| 77 | +{ |
---|
| 78 | + return usb_control_msg( |
---|
| 79 | + dev->udev, |
---|
| 80 | + usb_rcvctrlpipe(dev->udev, 0), |
---|
| 81 | + cmd, |
---|
| 82 | + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
---|
| 83 | + value, |
---|
| 84 | + index, |
---|
| 85 | + data, |
---|
| 86 | + size, |
---|
| 87 | + USB_CTRL_GET_TIMEOUT); |
---|
| 88 | +} |
---|
| 89 | + |
---|
| 90 | +static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
---|
| 91 | + u16 size, void *data) |
---|
| 92 | +{ |
---|
| 93 | + return usb_control_msg( |
---|
| 94 | + dev->udev, |
---|
| 95 | + usb_sndctrlpipe(dev->udev, 0), |
---|
| 96 | + cmd, |
---|
| 97 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
---|
| 98 | + value, |
---|
| 99 | + index, |
---|
| 100 | + data, |
---|
| 101 | + size, |
---|
| 102 | + USB_CTRL_SET_TIMEOUT); |
---|
| 103 | +} |
---|
| 104 | + |
---|
| 105 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 106 | +static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) |
---|
| 107 | +#else |
---|
| 108 | +static void ax8817x_async_cmd_callback(struct urb *urb) |
---|
| 109 | +#endif |
---|
| 110 | +{ |
---|
| 111 | + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; |
---|
| 112 | + |
---|
| 113 | + if (urb->status < 0) |
---|
| 114 | + printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d", |
---|
| 115 | + urb->status); |
---|
| 116 | + |
---|
| 117 | + kfree(req); |
---|
| 118 | + usb_free_urb(urb); |
---|
| 119 | +} |
---|
| 120 | + |
---|
| 121 | +static int ax8817x_set_mac_addr(struct net_device *net, void *p) |
---|
| 122 | +{ |
---|
| 123 | + struct usbnet *dev = netdev_priv(net); |
---|
| 124 | + struct sockaddr *addr = p; |
---|
| 125 | + int ret; |
---|
| 126 | + |
---|
| 127 | + memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); |
---|
| 128 | + |
---|
| 129 | + /* Set the MAC address */ |
---|
| 130 | + ret = ax8817x_write_cmd(dev, AX88772_CMD_WRITE_NODE_ID, |
---|
| 131 | + 0, 0, ETH_ALEN, net->dev_addr); |
---|
| 132 | + if (ret < 0) |
---|
| 133 | + return ret; |
---|
| 134 | + |
---|
| 135 | + return 0; |
---|
| 136 | +} |
---|
| 137 | + |
---|
| 138 | +static void ax88178_status(struct usbnet *dev, struct urb *urb) |
---|
| 139 | +{ |
---|
| 140 | + struct ax88172_int_data *event; |
---|
| 141 | + struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv; |
---|
| 142 | + int link; |
---|
| 143 | + |
---|
| 144 | + if (urb->actual_length < 8) |
---|
| 145 | + return; |
---|
| 146 | + |
---|
| 147 | + if (ax178dataptr->EepromData == PHY_MODE_MAC_TO_MAC_GMII) |
---|
| 148 | + return; |
---|
| 149 | + |
---|
| 150 | + event = urb->transfer_buffer; |
---|
| 151 | + link = event->link & 0x01; |
---|
| 152 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 153 | + if (link) { |
---|
| 154 | + netif_carrier_on(dev->net); |
---|
| 155 | + axusbnet_defer_kevent(dev, EVENT_LINK_RESET); |
---|
| 156 | + } else |
---|
| 157 | + netif_carrier_off(dev->net); |
---|
| 158 | + devwarn(dev, "ax88178 - Link status is: %d", link); |
---|
| 159 | + } |
---|
| 160 | +} |
---|
| 161 | + |
---|
| 162 | +static void ax8817x_status(struct usbnet *dev, struct urb *urb) |
---|
| 163 | +{ |
---|
| 164 | + struct ax88172_int_data *event; |
---|
| 165 | + int link; |
---|
| 166 | + |
---|
| 167 | + if (urb->actual_length < 8) |
---|
| 168 | + return; |
---|
| 169 | + |
---|
| 170 | + event = urb->transfer_buffer; |
---|
| 171 | + link = event->link & 0x01; |
---|
| 172 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 173 | + if (link) { |
---|
| 174 | + netif_carrier_on(dev->net); |
---|
| 175 | + axusbnet_defer_kevent(dev, EVENT_LINK_RESET); |
---|
| 176 | + } else |
---|
| 177 | + netif_carrier_off(dev->net); |
---|
| 178 | + devwarn(dev, "ax8817x - Link status is: %d", link); |
---|
| 179 | + } |
---|
| 180 | +} |
---|
| 181 | + |
---|
| 182 | +static void ax88772_status(struct usbnet *dev, struct urb *urb) |
---|
| 183 | +{ |
---|
| 184 | + struct ax88172_int_data *event; |
---|
| 185 | + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; |
---|
| 186 | + int link; |
---|
| 187 | + |
---|
| 188 | + if (urb->actual_length < 8) |
---|
| 189 | + return; |
---|
| 190 | + |
---|
| 191 | + event = urb->transfer_buffer; |
---|
| 192 | + link = event->link & 0x01; |
---|
| 193 | + |
---|
| 194 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 195 | + if (link) { |
---|
| 196 | + netif_carrier_on(dev->net); |
---|
| 197 | + ax772_data->Event = AX_SET_RX_CFG; |
---|
| 198 | + } else { |
---|
| 199 | + netif_carrier_off(dev->net); |
---|
| 200 | + if (ax772_data->Event == AX_NOP) { |
---|
| 201 | + ax772_data->Event = PHY_POWER_DOWN; |
---|
| 202 | + ax772_data->TickToExpire = 25; |
---|
| 203 | + } |
---|
| 204 | + } |
---|
| 205 | + |
---|
| 206 | + devwarn(dev, "ax88772 - Link status is: %d", link); |
---|
| 207 | + } |
---|
| 208 | + |
---|
| 209 | + if (ax772_data->Event) |
---|
| 210 | + queue_work(ax772_data->ax_work, &ax772_data->check_link); |
---|
| 211 | +} |
---|
| 212 | + |
---|
| 213 | +static void ax88772a_status(struct usbnet *dev, struct urb *urb) |
---|
| 214 | +{ |
---|
| 215 | + struct ax88172_int_data *event; |
---|
| 216 | + struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv; |
---|
| 217 | + int link; |
---|
| 218 | + int powsave = (ax772a_data->EepromData >> 14); |
---|
| 219 | + |
---|
| 220 | + if (urb->actual_length < 8) |
---|
| 221 | + return; |
---|
| 222 | + |
---|
| 223 | + event = urb->transfer_buffer; |
---|
| 224 | + link = event->link & 0x01; |
---|
| 225 | + |
---|
| 226 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 227 | + |
---|
| 228 | + if (link) { |
---|
| 229 | + netif_carrier_on(dev->net); |
---|
| 230 | + ax772a_data->Event = AX_SET_RX_CFG; |
---|
| 231 | + } else if ((powsave == 0x3) || (powsave == 0x1)) { |
---|
| 232 | + netif_carrier_off(dev->net); |
---|
| 233 | + if (ax772a_data->Event == AX_NOP) { |
---|
| 234 | + ax772a_data->Event = CHK_CABLE_EXIST; |
---|
| 235 | + ax772a_data->TickToExpire = 14; |
---|
| 236 | + } |
---|
| 237 | + } else { |
---|
| 238 | + netif_carrier_off(dev->net); |
---|
| 239 | + ax772a_data->Event = AX_NOP; |
---|
| 240 | + } |
---|
| 241 | + |
---|
| 242 | + devwarn(dev, "ax88772a - Link status is: %d", link); |
---|
| 243 | + } |
---|
| 244 | + |
---|
| 245 | + if (ax772a_data->Event) |
---|
| 246 | + queue_work(ax772a_data->ax_work, &ax772a_data->check_link); |
---|
| 247 | +} |
---|
| 248 | + |
---|
| 249 | +static int ax88772b_stop(struct usbnet *dev) |
---|
| 250 | +{ |
---|
| 251 | + u16 *medium; |
---|
| 252 | + |
---|
| 253 | + medium = kmalloc(2, GFP_ATOMIC); |
---|
| 254 | + if (medium) { |
---|
| 255 | + ax8817x_read_cmd(dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, medium); |
---|
| 256 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 257 | + (*medium & ~AX88772_MEDIUM_RX_ENABLE), |
---|
| 258 | + 0, 0, NULL); |
---|
| 259 | + |
---|
| 260 | + kfree(medium); |
---|
| 261 | + return 0; |
---|
| 262 | + } |
---|
| 263 | + return -EINVAL; |
---|
| 264 | +} |
---|
| 265 | + |
---|
| 266 | +static int ax88772b_reset(struct usbnet *dev) |
---|
| 267 | +{ |
---|
| 268 | + int ret; |
---|
| 269 | + |
---|
| 270 | + /* Set the MAC address */ |
---|
| 271 | + ret = ax8817x_write_cmd(dev, AX88772_CMD_WRITE_NODE_ID, |
---|
| 272 | + 0, 0, ETH_ALEN, dev->net->dev_addr); |
---|
| 273 | + if (ret < 0) |
---|
| 274 | + deverr(dev, "set MAC address failed: %d", ret); |
---|
| 275 | + |
---|
| 276 | + /* stop MAC operation */ |
---|
| 277 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, AX_RX_CTL_STOP, |
---|
| 278 | + 0, 0, NULL); |
---|
| 279 | + if (ret < 0) |
---|
| 280 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 281 | + |
---|
| 282 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 283 | + AX88772_MEDIUM_DEFAULT, 0, 0, |
---|
| 284 | + NULL); |
---|
| 285 | + if (ret < 0) |
---|
| 286 | + deverr(dev, "Write medium mode register: %d", ret); |
---|
| 287 | + |
---|
| 288 | + return ret; |
---|
| 289 | +} |
---|
| 290 | + |
---|
| 291 | +static void ax88772b_status(struct usbnet *dev, struct urb *urb) |
---|
| 292 | +{ |
---|
| 293 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 294 | + struct ax88172_int_data *event; |
---|
| 295 | + int link; |
---|
| 296 | + |
---|
| 297 | + if (urb->actual_length < 8) |
---|
| 298 | + return; |
---|
| 299 | + |
---|
| 300 | + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) |
---|
| 301 | + return; |
---|
| 302 | + |
---|
| 303 | + event = urb->transfer_buffer; |
---|
| 304 | + if (ax772b_data->PhySelect == 0 && |
---|
| 305 | + ax772b_data->OperationMode == OPERATION_MAC_MODE) |
---|
| 306 | + link = (event->link & AX_INT_SPLS_LINK) >> 1; |
---|
| 307 | + else |
---|
| 308 | + link = event->link & AX_INT_PPLS_LINK; |
---|
| 309 | + |
---|
| 310 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 311 | + if (link) { |
---|
| 312 | + netif_carrier_on(dev->net); |
---|
| 313 | + ax772b_data->Event = AX_SET_RX_CFG; |
---|
| 314 | + } else { |
---|
| 315 | + netif_carrier_off(dev->net); |
---|
| 316 | + ax772b_data->time_to_chk = jiffies; |
---|
| 317 | + } |
---|
| 318 | + devwarn(dev, "ax88772b - Link status is: %d", link); |
---|
| 319 | + } |
---|
| 320 | + |
---|
| 321 | + if (!link) { |
---|
| 322 | + |
---|
| 323 | + int no_cable = (event->link & AX_INT_CABOFF_UNPLUG) ? 1 : 0; |
---|
| 324 | + |
---|
| 325 | + if (no_cable) { |
---|
| 326 | + if ((ax772b_data->psc & |
---|
| 327 | + (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) && |
---|
| 328 | + !ax772b_data->pw_enabled) { |
---|
| 329 | + /* |
---|
| 330 | + * AX88772B already entered power saving state |
---|
| 331 | + */ |
---|
| 332 | + ax772b_data->pw_enabled = 1; |
---|
| 333 | + } |
---|
| 334 | + if (ax772b_data->psc & AX_SWRESET_AUTODETACH) |
---|
| 335 | + ax772b_data->Event = AX_CHK_AUTODETACH; |
---|
| 336 | + |
---|
| 337 | + } else { |
---|
| 338 | + /* AX88772B resumed from power saving state */ |
---|
| 339 | + if (ax772b_data->pw_enabled || |
---|
| 340 | + (jiffies > (ax772b_data->time_to_chk + |
---|
| 341 | + AX88772B_WATCHDOG))) { |
---|
| 342 | + if (ax772b_data->pw_enabled) |
---|
| 343 | + ax772b_data->pw_enabled = 0; |
---|
| 344 | + ax772b_data->Event = PHY_POWER_UP; |
---|
| 345 | + ax772b_data->time_to_chk = jiffies; |
---|
| 346 | + } |
---|
| 347 | + } |
---|
| 348 | + } |
---|
| 349 | + |
---|
| 350 | + if (ax772b_data->Event) |
---|
| 351 | + queue_work(ax772b_data->ax_work, &ax772b_data->check_link); |
---|
| 352 | +} |
---|
| 353 | + |
---|
| 354 | +static void ax88772c_status(struct usbnet *dev, struct urb *urb) |
---|
| 355 | +{ |
---|
| 356 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 357 | + struct ax88172_int_data *event; |
---|
| 358 | + int link; |
---|
| 359 | + |
---|
| 360 | + if (urb->actual_length < 8) |
---|
| 361 | + return; |
---|
| 362 | + |
---|
| 363 | + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) |
---|
| 364 | + return; |
---|
| 365 | + |
---|
| 366 | + event = urb->transfer_buffer; |
---|
| 367 | + if (ax772b_data->PhySelect == 0 && |
---|
| 368 | + ax772b_data->OperationMode == OPERATION_MAC_MODE) |
---|
| 369 | + link = (event->link & AX_INT_SPLS_LINK) >> 1; |
---|
| 370 | + else |
---|
| 371 | + link = event->link & AX_INT_PPLS_LINK; |
---|
| 372 | + |
---|
| 373 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 374 | + if (link) { |
---|
| 375 | + netif_carrier_on(dev->net); |
---|
| 376 | + ax772b_data->Event = AX_SET_RX_CFG; |
---|
| 377 | + } else { |
---|
| 378 | + netif_carrier_off(dev->net); |
---|
| 379 | + ax772b_data->time_to_chk = jiffies; |
---|
| 380 | + } |
---|
| 381 | + devwarn(dev, "ax88772c - Link status is: %d", link); |
---|
| 382 | + } |
---|
| 383 | + |
---|
| 384 | + if (!link) { |
---|
| 385 | + |
---|
| 386 | + int no_cable = (event->link & AX_INT_CABOFF_UNPLUG) ? 1 : 0; |
---|
| 387 | + |
---|
| 388 | + if (no_cable) { |
---|
| 389 | + if ((ax772b_data->psc & |
---|
| 390 | + (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) && |
---|
| 391 | + !ax772b_data->pw_enabled) { |
---|
| 392 | + /* |
---|
| 393 | + * AX88772B already entered power saving state |
---|
| 394 | + */ |
---|
| 395 | + ax772b_data->pw_enabled = 1; |
---|
| 396 | + } |
---|
| 397 | + if (ax772b_data->psc & AX_SWRESET_AUTODETACH) |
---|
| 398 | + ax772b_data->Event = AX_CHK_AUTODETACH; |
---|
| 399 | + } else { |
---|
| 400 | + /* AX88772B resumed from power saving state */ |
---|
| 401 | + if (ax772b_data->pw_enabled || |
---|
| 402 | + (jiffies > (ax772b_data->time_to_chk + |
---|
| 403 | + AX88772B_WATCHDOG))) { |
---|
| 404 | + if (ax772b_data->pw_enabled) |
---|
| 405 | + ax772b_data->pw_enabled = 0; |
---|
| 406 | + ax772b_data->Event = PHY_POWER_UP; |
---|
| 407 | + ax772b_data->time_to_chk = jiffies; |
---|
| 408 | + } |
---|
| 409 | + } |
---|
| 410 | + } |
---|
| 411 | + |
---|
| 412 | + if (ax772b_data->Event) |
---|
| 413 | + queue_work(ax772b_data->ax_work, &ax772b_data->check_link); |
---|
| 414 | +} |
---|
| 415 | + |
---|
| 416 | +void |
---|
| 417 | +ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
---|
| 418 | + u16 size, void *data) |
---|
| 419 | +{ |
---|
| 420 | + struct usb_ctrlrequest *req; |
---|
| 421 | + int status; |
---|
| 422 | + struct urb *urb; |
---|
| 423 | + |
---|
| 424 | + urb = usb_alloc_urb(0, GFP_ATOMIC); |
---|
| 425 | + if (urb == NULL) { |
---|
| 426 | + deverr(dev, "Error allocating URB in write_cmd_async!"); |
---|
| 427 | + return; |
---|
| 428 | + } |
---|
| 429 | + |
---|
| 430 | + req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); |
---|
| 431 | + if (req == NULL) { |
---|
| 432 | + deverr(dev, "Failed to allocate memory for control request"); |
---|
| 433 | + usb_free_urb(urb); |
---|
| 434 | + return; |
---|
| 435 | + } |
---|
| 436 | + |
---|
| 437 | + req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; |
---|
| 438 | + req->bRequest = cmd; |
---|
| 439 | + req->wValue = cpu_to_le16(value); |
---|
| 440 | + req->wIndex = cpu_to_le16(index); |
---|
| 441 | + req->wLength = cpu_to_le16(size); |
---|
| 442 | + |
---|
| 443 | + usb_fill_control_urb(urb, dev->udev, |
---|
| 444 | + usb_sndctrlpipe(dev->udev, 0), |
---|
| 445 | + (void *)req, data, size, |
---|
| 446 | + ax8817x_async_cmd_callback, req); |
---|
| 447 | + |
---|
| 448 | + status = usb_submit_urb(urb, GFP_ATOMIC); |
---|
| 449 | + if (status < 0) { |
---|
| 450 | + deverr(dev, "Error submitting the control message: status=%d", |
---|
| 451 | + status); |
---|
| 452 | + kfree(req); |
---|
| 453 | + usb_free_urb(urb); |
---|
| 454 | + } |
---|
| 455 | +} |
---|
| 456 | + |
---|
| 457 | +static void ax8817x_set_multicast(struct net_device *net) |
---|
| 458 | +{ |
---|
| 459 | + struct usbnet *dev = netdev_priv(net); |
---|
| 460 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 461 | + u8 rx_ctl = AX_RX_CTL_START | AX_RX_CTL_AB; |
---|
| 462 | + int mc_count; |
---|
| 463 | + |
---|
| 464 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 465 | + mc_count = net->mc_count; |
---|
| 466 | +#else |
---|
| 467 | + mc_count = netdev_mc_count(net); |
---|
| 468 | +#endif |
---|
| 469 | + |
---|
| 470 | + if (net->flags & IFF_PROMISC) { |
---|
| 471 | + rx_ctl |= AX_RX_CTL_PRO; |
---|
| 472 | + } else if (net->flags & IFF_ALLMULTI |
---|
| 473 | + || mc_count > AX_MAX_MCAST) { |
---|
| 474 | + rx_ctl |= AX_RX_CTL_AMALL; |
---|
| 475 | + } else if (mc_count == 0) { |
---|
| 476 | + /* just broadcast and directed */ |
---|
| 477 | + } else { |
---|
| 478 | + /* We use the 20 byte dev->data |
---|
| 479 | + * for our 8 byte filter buffer |
---|
| 480 | + * to avoid allocating memory that |
---|
| 481 | + * is tricky to free later */ |
---|
| 482 | + u32 crc_bits; |
---|
| 483 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 484 | + struct dev_mc_list *mc_list = net->mc_list; |
---|
| 485 | + int i; |
---|
| 486 | + |
---|
| 487 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 488 | + |
---|
| 489 | + /* Build the multicast hash filter. */ |
---|
| 490 | + for (i = 0; i < net->mc_count; i++) { |
---|
| 491 | + crc_bits = |
---|
| 492 | + ether_crc(ETH_ALEN, |
---|
| 493 | + mc_list->dmi_addr) >> 26; |
---|
| 494 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 495 | + 1 << (crc_bits & 7); |
---|
| 496 | + mc_list = mc_list->next; |
---|
| 497 | + } |
---|
| 498 | +#else |
---|
| 499 | + struct netdev_hw_addr *ha = NULL; |
---|
| 500 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 501 | + netdev_for_each_mc_addr(ha, net) { |
---|
| 502 | + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; |
---|
| 503 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 504 | + 1 << (crc_bits & 7); |
---|
| 505 | + } |
---|
| 506 | +#endif |
---|
| 507 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, |
---|
| 508 | + AX_MCAST_FILTER_SIZE, data->multi_filter); |
---|
| 509 | + |
---|
| 510 | + rx_ctl |= AX_RX_CTL_AM; |
---|
| 511 | + } |
---|
| 512 | + |
---|
| 513 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); |
---|
| 514 | +} |
---|
| 515 | + |
---|
| 516 | +static void ax88178_set_multicast(struct net_device *net) |
---|
| 517 | +{ |
---|
| 518 | + struct usbnet *dev = netdev_priv(net); |
---|
| 519 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 520 | + u16 rx_ctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_CTL_MFB); |
---|
| 521 | + int mc_count; |
---|
| 522 | + |
---|
| 523 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 524 | + mc_count = net->mc_count; |
---|
| 525 | +#else |
---|
| 526 | + mc_count = netdev_mc_count(net); |
---|
| 527 | +#endif |
---|
| 528 | + |
---|
| 529 | + if (net->flags & IFF_PROMISC) { |
---|
| 530 | + rx_ctl |= AX_RX_CTL_PRO; |
---|
| 531 | + } else if (net->flags & IFF_ALLMULTI |
---|
| 532 | + || mc_count > AX_MAX_MCAST) { |
---|
| 533 | + rx_ctl |= AX_RX_CTL_AMALL; |
---|
| 534 | + } else if (mc_count == 0) { |
---|
| 535 | + /* just broadcast and directed */ |
---|
| 536 | + } else { |
---|
| 537 | + /* We use the 20 byte dev->data |
---|
| 538 | + * for our 8 byte filter buffer |
---|
| 539 | + * to avoid allocating memory that |
---|
| 540 | + * is tricky to free later */ |
---|
| 541 | + u32 crc_bits; |
---|
| 542 | + |
---|
| 543 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 544 | + struct dev_mc_list *mc_list = net->mc_list; |
---|
| 545 | + int i; |
---|
| 546 | + |
---|
| 547 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 548 | + |
---|
| 549 | + /* Build the multicast hash filter. */ |
---|
| 550 | + for (i = 0; i < net->mc_count; i++) { |
---|
| 551 | + crc_bits = |
---|
| 552 | + ether_crc(ETH_ALEN, |
---|
| 553 | + mc_list->dmi_addr) >> 26; |
---|
| 554 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 555 | + 1 << (crc_bits & 7); |
---|
| 556 | + mc_list = mc_list->next; |
---|
| 557 | + } |
---|
| 558 | +#else |
---|
| 559 | + struct netdev_hw_addr *ha = NULL; |
---|
| 560 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 561 | + netdev_for_each_mc_addr(ha, net) { |
---|
| 562 | + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; |
---|
| 563 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 564 | + 1 << (crc_bits & 7); |
---|
| 565 | + } |
---|
| 566 | +#endif |
---|
| 567 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, |
---|
| 568 | + AX_MCAST_FILTER_SIZE, data->multi_filter); |
---|
| 569 | + |
---|
| 570 | + rx_ctl |= AX_RX_CTL_AM; |
---|
| 571 | + } |
---|
| 572 | + |
---|
| 573 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); |
---|
| 574 | +} |
---|
| 575 | + |
---|
| 576 | +static void ax88772b_set_multicast(struct net_device *net) |
---|
| 577 | +{ |
---|
| 578 | + struct usbnet *dev = netdev_priv(net); |
---|
| 579 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 580 | + u16 rx_ctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_HEADER_DEFAULT); |
---|
| 581 | + int mc_count; |
---|
| 582 | + |
---|
| 583 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 584 | + mc_count = net->mc_count; |
---|
| 585 | +#else |
---|
| 586 | + mc_count = netdev_mc_count(net); |
---|
| 587 | +#endif |
---|
| 588 | + |
---|
| 589 | + if (net->flags & IFF_PROMISC) { |
---|
| 590 | + rx_ctl |= AX_RX_CTL_PRO; |
---|
| 591 | + } else if (net->flags & IFF_ALLMULTI |
---|
| 592 | + || mc_count > AX_MAX_MCAST) { |
---|
| 593 | + rx_ctl |= AX_RX_CTL_AMALL; |
---|
| 594 | + } else if (mc_count == 0) { |
---|
| 595 | + /* just broadcast and directed */ |
---|
| 596 | + } else { |
---|
| 597 | + /* We use the 20 byte dev->data |
---|
| 598 | + * for our 8 byte filter buffer |
---|
| 599 | + * to avoid allocating memory that |
---|
| 600 | + * is tricky to free later */ |
---|
| 601 | + u32 crc_bits; |
---|
| 602 | + |
---|
| 603 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 604 | + struct dev_mc_list *mc_list = net->mc_list; |
---|
| 605 | + int i; |
---|
| 606 | + |
---|
| 607 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 608 | + |
---|
| 609 | + /* Build the multicast hash filter. */ |
---|
| 610 | + for (i = 0; i < net->mc_count; i++) { |
---|
| 611 | + crc_bits = |
---|
| 612 | + ether_crc(ETH_ALEN, |
---|
| 613 | + mc_list->dmi_addr) >> 26; |
---|
| 614 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 615 | + 1 << (crc_bits & 7); |
---|
| 616 | + mc_list = mc_list->next; |
---|
| 617 | + } |
---|
| 618 | +#else |
---|
| 619 | + struct netdev_hw_addr *ha = NULL; |
---|
| 620 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 621 | + netdev_for_each_mc_addr(ha, net) { |
---|
| 622 | + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; |
---|
| 623 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 624 | + 1 << (crc_bits & 7); |
---|
| 625 | + } |
---|
| 626 | +#endif |
---|
| 627 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, |
---|
| 628 | + AX_MCAST_FILTER_SIZE, data->multi_filter); |
---|
| 629 | + |
---|
| 630 | + rx_ctl |= AX_RX_CTL_AM; |
---|
| 631 | + } |
---|
| 632 | + |
---|
| 633 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); |
---|
| 634 | +} |
---|
| 635 | + |
---|
| 636 | +static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc) |
---|
| 637 | +{ |
---|
| 638 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 639 | + u16 *res, ret; |
---|
| 640 | + u8* smsr; |
---|
| 641 | + int i = 0; |
---|
| 642 | + |
---|
| 643 | + res = kmalloc(2, GFP_ATOMIC); |
---|
| 644 | + if (!res) |
---|
| 645 | + return 0; |
---|
| 646 | + |
---|
| 647 | + do { |
---|
| 648 | + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 649 | + |
---|
| 650 | + msleep(1); |
---|
| 651 | + |
---|
| 652 | + smsr = (u8*) res; |
---|
| 653 | + ax8817x_read_cmd(dev, AX_CMD_READ_STATMNGSTS_REG, 0, 0, 1, smsr); |
---|
| 654 | + } while (!(*smsr & AX_HOST_EN) && (i++ < 30)); |
---|
| 655 | + |
---|
| 656 | + ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, res); |
---|
| 657 | + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); |
---|
| 658 | + |
---|
| 659 | + ret = *res & 0xffff; |
---|
| 660 | + kfree(res); |
---|
| 661 | + |
---|
| 662 | + return ret; |
---|
| 663 | +} |
---|
| 664 | + |
---|
| 665 | +static int |
---|
| 666 | +ax8817x_swmii_mdio_read(struct net_device *netdev, int phy_id, int loc) |
---|
| 667 | +{ |
---|
| 668 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 669 | + u16 *res; |
---|
| 670 | + u16 ret; |
---|
| 671 | + |
---|
| 672 | + res = kmalloc(2, GFP_ATOMIC); |
---|
| 673 | + if (!res) |
---|
| 674 | + return 0; |
---|
| 675 | + |
---|
| 676 | + ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, |
---|
| 677 | + (__u16)loc, 2, res); |
---|
| 678 | + |
---|
| 679 | + ret = *res & 0xffff; |
---|
| 680 | + kfree(res); |
---|
| 681 | + |
---|
| 682 | + return ret; |
---|
| 683 | +} |
---|
| 684 | + |
---|
| 685 | +/* same as above, but converts resulting value to cpu byte order */ |
---|
| 686 | +static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc) |
---|
| 687 | +{ |
---|
| 688 | + return le16_to_cpu(ax8817x_mdio_read(netdev, phy_id, loc)); |
---|
| 689 | +} |
---|
| 690 | + |
---|
| 691 | +static int |
---|
| 692 | +ax8817x_swmii_mdio_read_le(struct net_device *netdev, int phy_id, int loc) |
---|
| 693 | +{ |
---|
| 694 | + return le16_to_cpu(ax8817x_swmii_mdio_read(netdev, phy_id, loc)); |
---|
| 695 | +} |
---|
| 696 | + |
---|
| 697 | +static void |
---|
| 698 | +ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) |
---|
| 699 | +{ |
---|
| 700 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 701 | + u16 *res; |
---|
| 702 | + u8* smsr; |
---|
| 703 | + int i = 0; |
---|
| 704 | + |
---|
| 705 | + res = kmalloc(2, GFP_ATOMIC); |
---|
| 706 | + if (!res) |
---|
| 707 | + return; |
---|
| 708 | + smsr = (u8 *) res; |
---|
| 709 | + |
---|
| 710 | + do { |
---|
| 711 | + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 712 | + |
---|
| 713 | + msleep(1); |
---|
| 714 | + |
---|
| 715 | + ax8817x_read_cmd(dev, AX_CMD_READ_STATMNGSTS_REG, 0, 0, 1, smsr); |
---|
| 716 | + } while (!(*smsr & AX_HOST_EN) && (i++ < 30)); |
---|
| 717 | + |
---|
| 718 | + *res = val; |
---|
| 719 | + |
---|
| 720 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, |
---|
| 721 | + (__u16)loc, 2, res); |
---|
| 722 | + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); |
---|
| 723 | + |
---|
| 724 | + kfree(res); |
---|
| 725 | +} |
---|
| 726 | + |
---|
| 727 | +static void ax8817x_swmii_mdio_write(struct net_device *netdev, int phy_id, |
---|
| 728 | + int loc, int val) |
---|
| 729 | +{ |
---|
| 730 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 731 | + u16 *res; |
---|
| 732 | + |
---|
| 733 | + res = kmalloc(2, GFP_ATOMIC); |
---|
| 734 | + if (!res) |
---|
| 735 | + return; |
---|
| 736 | + *res = val; |
---|
| 737 | + |
---|
| 738 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, |
---|
| 739 | + (__u16)loc, 2, res); |
---|
| 740 | + |
---|
| 741 | + kfree(res); |
---|
| 742 | +} |
---|
| 743 | + |
---|
| 744 | +static void |
---|
| 745 | +ax88772b_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) |
---|
| 746 | +{ |
---|
| 747 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 748 | + u16 *res; |
---|
| 749 | + |
---|
| 750 | + res = kmalloc(2, GFP_ATOMIC); |
---|
| 751 | + if (!res) |
---|
| 752 | + return; |
---|
| 753 | + *res = val; |
---|
| 754 | + |
---|
| 755 | + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 756 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, |
---|
| 757 | + (__u16)loc, 2, res); |
---|
| 758 | + |
---|
| 759 | + if (loc == MII_ADVERTISE) { |
---|
| 760 | + *res = cpu_to_le16(BMCR_ANENABLE | BMCR_ANRESTART); |
---|
| 761 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, |
---|
| 762 | + (__u16)MII_BMCR, 2, res); |
---|
| 763 | + } |
---|
| 764 | + |
---|
| 765 | + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); |
---|
| 766 | + |
---|
| 767 | + kfree(res); |
---|
| 768 | +} |
---|
| 769 | + |
---|
| 770 | +/* same as above, but converts new value to le16 byte order before writing */ |
---|
| 771 | +static void |
---|
| 772 | +ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val) |
---|
| 773 | +{ |
---|
| 774 | + ax8817x_mdio_write(netdev, phy_id, loc, cpu_to_le16(val)); |
---|
| 775 | +} |
---|
| 776 | + |
---|
| 777 | +static void ax8817x_swmii_mdio_write_le(struct net_device *netdev, |
---|
| 778 | + int phy_id, int loc, int val) |
---|
| 779 | +{ |
---|
| 780 | + ax8817x_swmii_mdio_write(netdev, phy_id, loc, cpu_to_le16(val)); |
---|
| 781 | +} |
---|
| 782 | + |
---|
| 783 | +static void |
---|
| 784 | +ax88772b_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val) |
---|
| 785 | +{ |
---|
| 786 | + ax88772b_mdio_write(netdev, phy_id, loc, cpu_to_le16(val)); |
---|
| 787 | +} |
---|
| 788 | + |
---|
| 789 | +static int ax88772_suspend(struct usb_interface *intf, |
---|
| 790 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) |
---|
| 791 | + pm_message_t message) |
---|
| 792 | +#else |
---|
| 793 | + u32 message) |
---|
| 794 | +#endif |
---|
| 795 | +{ |
---|
| 796 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 797 | + u16 *medium; |
---|
| 798 | + |
---|
| 799 | + medium = kmalloc(2, GFP_ATOMIC); |
---|
| 800 | + if (!medium) |
---|
| 801 | + return axusbnet_suspend(intf, message); |
---|
| 802 | + |
---|
| 803 | + ax8817x_read_cmd(dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, medium); |
---|
| 804 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 805 | + (*medium & ~AX88772_MEDIUM_RX_ENABLE), 0, 0, NULL); |
---|
| 806 | + |
---|
| 807 | + kfree(medium); |
---|
| 808 | + return axusbnet_suspend(intf, message); |
---|
| 809 | +} |
---|
| 810 | + |
---|
| 811 | +static int ax88772b_suspend(struct usb_interface *intf, |
---|
| 812 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) |
---|
| 813 | + pm_message_t message) |
---|
| 814 | +#else |
---|
| 815 | + u32 message) |
---|
| 816 | +#endif |
---|
| 817 | +{ |
---|
| 818 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 819 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 820 | + u16 *tmp16; |
---|
| 821 | + u8 *opt; |
---|
| 822 | + |
---|
| 823 | + tmp16 = kmalloc(2, GFP_ATOMIC); |
---|
| 824 | + if (!tmp16) |
---|
| 825 | + return axusbnet_suspend(intf, message); |
---|
| 826 | + opt = (u8 *)tmp16; |
---|
| 827 | +#if 0 |
---|
| 828 | + /* Read Wake-up Frame Array Register (Mask Wakeup Timer) */ |
---|
| 829 | + ax8817x_read_cmd(dev, AX_CMD_READ_WKFARY, 0x11, 0, 4, &tmp32); |
---|
| 830 | + tmp32 &= 0xFFF0FFFF; |
---|
| 831 | + /* 8 second */ |
---|
| 832 | + tmp32 |= 0x00020000; |
---|
| 833 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_WKFARY, 0x11, 0, 4, &tmp32); |
---|
| 834 | +#endif |
---|
| 835 | + /* Preserve BMCR for restoring */ |
---|
| 836 | + ax772b_data->presvd_phy_bmcr = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_BMCR); |
---|
| 837 | + |
---|
| 838 | + /* Preserve Advertisement control reg for restoring */ |
---|
| 839 | + ax772b_data->presvd_phy_advertise = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 840 | + |
---|
| 841 | + ax8817x_read_cmd(dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, tmp16); |
---|
| 842 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 843 | + (*tmp16 & ~AX88772_MEDIUM_RX_ENABLE), |
---|
| 844 | + 0, 0, NULL); |
---|
| 845 | + |
---|
| 846 | + ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, opt); |
---|
| 847 | + if (!(*opt & AX_MONITOR_LINK) && !(*opt & AX_MONITOR_MAGIC)) { |
---|
| 848 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 849 | + AX_SWRESET_IPRL | AX_SWRESET_IPPD, |
---|
| 850 | + 0, 0, NULL); |
---|
| 851 | + |
---|
| 852 | + } else { |
---|
| 853 | + |
---|
| 854 | + if (ax772b_data->psc & AX_SWRESET_WOLLP) { |
---|
| 855 | + *tmp16 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 856 | + MII_BMCR); |
---|
| 857 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 858 | + MII_BMCR, *tmp16 | BMCR_ANENABLE); |
---|
| 859 | + |
---|
| 860 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 861 | + AX_SWRESET_IPRL | ax772b_data->psc, |
---|
| 862 | + 0, 0, NULL); |
---|
| 863 | + } |
---|
| 864 | + |
---|
| 865 | + if (ax772b_data->psc & |
---|
| 866 | + (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) { |
---|
| 867 | + *opt |= AX_MONITOR_LINK; |
---|
| 868 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, *opt, |
---|
| 869 | + 0, 0, NULL); |
---|
| 870 | + } |
---|
| 871 | + } |
---|
| 872 | + |
---|
| 873 | + kfree(tmp16); |
---|
| 874 | + return axusbnet_suspend(intf, message); |
---|
| 875 | +} |
---|
| 876 | + |
---|
| 877 | +static int ax88772_resume(struct usb_interface *intf) |
---|
| 878 | +{ |
---|
| 879 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 880 | + |
---|
| 881 | + netif_carrier_off(dev->net); |
---|
| 882 | + |
---|
| 883 | + return axusbnet_resume(intf); |
---|
| 884 | +} |
---|
| 885 | + |
---|
| 886 | +static int ax88772b_resume(struct usb_interface *intf) |
---|
| 887 | +{ |
---|
| 888 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 889 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 890 | + |
---|
| 891 | + if (ax772b_data->psc & AX_SWRESET_WOLLP) { |
---|
| 892 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 893 | + AX_SWRESET_IPRL | (ax772b_data->psc & 0x7FFF), |
---|
| 894 | + 0, 0, NULL); |
---|
| 895 | + } |
---|
| 896 | + |
---|
| 897 | + if (ax772b_data->psc & (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) |
---|
| 898 | + ax88772a_phy_powerup(dev); |
---|
| 899 | + |
---|
| 900 | + netif_carrier_off(dev->net); |
---|
| 901 | + |
---|
| 902 | + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) |
---|
| 903 | + netif_carrier_on(dev->net); |
---|
| 904 | + |
---|
| 905 | + return axusbnet_resume(intf); |
---|
| 906 | +} |
---|
| 907 | + |
---|
| 908 | +static int ax88172_link_reset(struct usbnet *dev) |
---|
| 909 | +{ |
---|
| 910 | + u16 lpa; |
---|
| 911 | + u16 adv; |
---|
| 912 | + u16 res; |
---|
| 913 | + u8 mode; |
---|
| 914 | + |
---|
| 915 | + mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN; |
---|
| 916 | + lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); |
---|
| 917 | + adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 918 | + res = mii_nway_result(lpa|adv); |
---|
| 919 | + if (res & LPA_DUPLEX) |
---|
| 920 | + mode |= AX_MEDIUM_FULL_DUPLEX; |
---|
| 921 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); |
---|
| 922 | + |
---|
| 923 | + return 0; |
---|
| 924 | +} |
---|
| 925 | + |
---|
| 926 | +static void |
---|
| 927 | +ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) |
---|
| 928 | +{ |
---|
| 929 | + struct usbnet *dev = netdev_priv(net); |
---|
| 930 | + u8 *opt; |
---|
| 931 | + |
---|
| 932 | + wolinfo->supported = 0; |
---|
| 933 | + wolinfo->wolopts = 0; |
---|
| 934 | + |
---|
| 935 | + opt = kmalloc(1, GFP_KERNEL); |
---|
| 936 | + if (!opt) |
---|
| 937 | + return; |
---|
| 938 | + |
---|
| 939 | + if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, opt) < 0) { |
---|
| 940 | + kfree(opt); |
---|
| 941 | + return; |
---|
| 942 | + } |
---|
| 943 | + |
---|
| 944 | + wolinfo->supported = WAKE_PHY | WAKE_MAGIC; |
---|
| 945 | + |
---|
| 946 | + if (*opt & AX_MONITOR_LINK) |
---|
| 947 | + wolinfo->wolopts |= WAKE_PHY; |
---|
| 948 | + if (*opt & AX_MONITOR_MAGIC) |
---|
| 949 | + wolinfo->wolopts |= WAKE_MAGIC; |
---|
| 950 | + |
---|
| 951 | + kfree(opt); |
---|
| 952 | +} |
---|
| 953 | + |
---|
| 954 | +static int |
---|
| 955 | +ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) |
---|
| 956 | +{ |
---|
| 957 | + struct usbnet *dev = netdev_priv(net); |
---|
| 958 | + u8 *opt; |
---|
| 959 | + |
---|
| 960 | + opt = kmalloc(1, GFP_KERNEL); |
---|
| 961 | + if (!opt) |
---|
| 962 | + return -ENOMEM; |
---|
| 963 | + |
---|
| 964 | + *opt = 0; |
---|
| 965 | + if (wolinfo->wolopts & WAKE_PHY) |
---|
| 966 | + *opt |= AX_MONITOR_LINK; |
---|
| 967 | + if (wolinfo->wolopts & WAKE_MAGIC) |
---|
| 968 | + *opt |= AX_MONITOR_MAGIC; |
---|
| 969 | + |
---|
| 970 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, *opt, 0, 0, NULL); |
---|
| 971 | + |
---|
| 972 | + kfree(opt); |
---|
| 973 | + return 0; |
---|
| 974 | +} |
---|
| 975 | + |
---|
| 976 | +static int ax8817x_get_eeprom_len(struct net_device *net) |
---|
| 977 | +{ |
---|
| 978 | + return AX_EEPROM_LEN; |
---|
| 979 | +} |
---|
| 980 | + |
---|
| 981 | +static int ax8817x_get_eeprom(struct net_device *net, |
---|
| 982 | + struct ethtool_eeprom *eeprom, u8 *data) |
---|
| 983 | +{ |
---|
| 984 | + struct usbnet *dev = netdev_priv(net); |
---|
| 985 | + u16 *ebuf = (u16 *)data; |
---|
| 986 | + int i; |
---|
| 987 | + |
---|
| 988 | + /* Crude hack to ensure that we don't overwrite memory |
---|
| 989 | + * if an odd length is supplied |
---|
| 990 | + */ |
---|
| 991 | + if (eeprom->len % 2) |
---|
| 992 | + return -EINVAL; |
---|
| 993 | + |
---|
| 994 | + eeprom->magic = AX_EEPROM_MAGIC; |
---|
| 995 | + |
---|
| 996 | + /* ax8817x returns 2 bytes from eeprom on read */ |
---|
| 997 | + for (i = 0; i < eeprom->len / 2; i++) { |
---|
| 998 | + if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, |
---|
| 999 | + eeprom->offset + i, 0, 2, |
---|
| 1000 | + &ebuf[i]) < 0) |
---|
| 1001 | + return -EINVAL; |
---|
| 1002 | + } |
---|
| 1003 | + return 0; |
---|
| 1004 | +} |
---|
| 1005 | + |
---|
| 1006 | +static void ax8817x_get_drvinfo(struct net_device *net, |
---|
| 1007 | + struct ethtool_drvinfo *info) |
---|
| 1008 | +{ |
---|
| 1009 | + /* Inherit standard device info */ |
---|
| 1010 | + axusbnet_get_drvinfo(net, info); |
---|
| 1011 | + info->eedump_len = 0x3e; |
---|
| 1012 | +} |
---|
| 1013 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) |
---|
| 1014 | +static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd) |
---|
| 1015 | +{ |
---|
| 1016 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1017 | + return mii_ethtool_gset(&dev->mii, cmd); |
---|
| 1018 | +} |
---|
| 1019 | + |
---|
| 1020 | +static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd) |
---|
| 1021 | +{ |
---|
| 1022 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1023 | + return mii_ethtool_sset(&dev->mii, cmd); |
---|
| 1024 | +} |
---|
| 1025 | +#else |
---|
| 1026 | +static int ax8817x_get_link_ksettings(struct net_device *net, |
---|
| 1027 | + struct ethtool_link_ksettings *cmd) |
---|
| 1028 | +{ |
---|
| 1029 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1030 | + |
---|
| 1031 | + if (!dev->mii.mdio_read) |
---|
| 1032 | + return -EOPNOTSUPP; |
---|
| 1033 | + |
---|
| 1034 | + mii_ethtool_get_link_ksettings(&dev->mii, cmd); |
---|
| 1035 | + |
---|
| 1036 | + return 0; |
---|
| 1037 | +} |
---|
| 1038 | + |
---|
| 1039 | +static int ax8817x_set_link_ksettings(struct net_device *net, |
---|
| 1040 | + const struct ethtool_link_ksettings *cmd) |
---|
| 1041 | +{ |
---|
| 1042 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1043 | + |
---|
| 1044 | + if (!dev->mii.mdio_write) |
---|
| 1045 | + return -EOPNOTSUPP; |
---|
| 1046 | + |
---|
| 1047 | + return mii_ethtool_set_link_ksettings(&dev->mii, cmd); |
---|
| 1048 | +} |
---|
| 1049 | +#endif |
---|
| 1050 | +/* We need to override some ethtool_ops so we require our |
---|
| 1051 | + own structure so we don't interfere with other usbnet |
---|
| 1052 | + devices that may be connected at the same time. */ |
---|
| 1053 | +static struct ethtool_ops ax8817x_ethtool_ops = { |
---|
| 1054 | + .get_drvinfo = ax8817x_get_drvinfo, |
---|
| 1055 | + .get_link = ethtool_op_get_link, |
---|
| 1056 | + .get_msglevel = axusbnet_get_msglevel, |
---|
| 1057 | + .set_msglevel = axusbnet_set_msglevel, |
---|
| 1058 | + .get_wol = ax8817x_get_wol, |
---|
| 1059 | + .set_wol = ax8817x_set_wol, |
---|
| 1060 | + .get_eeprom_len = ax8817x_get_eeprom_len, |
---|
| 1061 | + .get_eeprom = ax8817x_get_eeprom, |
---|
| 1062 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) |
---|
| 1063 | + .get_settings = ax8817x_get_settings, |
---|
| 1064 | + .set_settings = ax8817x_set_settings, |
---|
| 1065 | +#else |
---|
| 1066 | + .get_link_ksettings = ax8817x_get_link_ksettings, |
---|
| 1067 | + .set_link_ksettings = ax8817x_set_link_ksettings, |
---|
| 1068 | +#endif |
---|
| 1069 | +}; |
---|
| 1070 | + |
---|
| 1071 | +int ioctl_signature(struct usbnet *dev, AX_IOCTL_COMMAND *info) |
---|
| 1072 | +{ |
---|
| 1073 | + strncpy(info->sig, AX88772B_SIGNATURE, strlen(AX88772B_SIGNATURE)); |
---|
| 1074 | + |
---|
| 1075 | + return 0; |
---|
| 1076 | +} |
---|
| 1077 | + |
---|
| 1078 | +static void debug_func(const char *func_name, unsigned short *buf, unsigned long wLen) |
---|
| 1079 | +{ |
---|
| 1080 | +#if (DEBUG_PARAM & DEB_DRIVER) |
---|
| 1081 | + int i; |
---|
| 1082 | + char str_buf[50]; |
---|
| 1083 | + printk("%s :\n", func_name); |
---|
| 1084 | + printk("---------------------------------------\n"); |
---|
| 1085 | + for (i = 0; i < wLen / 8; i++) { |
---|
| 1086 | + int j = 8 * i; |
---|
| 1087 | + snprintf(str_buf, 50, |
---|
| 1088 | + "%04x %04x %04x %04x %04x %04x " |
---|
| 1089 | + "%04x %04x\n", |
---|
| 1090 | + *(buf + j + 0), *(buf + j + 1), |
---|
| 1091 | + *(buf + j + 2), *(buf + j + 3), |
---|
| 1092 | + *(buf + j + 4), *(buf + j + 5), |
---|
| 1093 | + *(buf + j + 6), *(buf + j + 7)); |
---|
| 1094 | + printk("%s", str_buf); |
---|
| 1095 | + } |
---|
| 1096 | + printk("------------------------------------%3ld\n", wLen); |
---|
| 1097 | +#endif |
---|
| 1098 | +} |
---|
| 1099 | + |
---|
| 1100 | +int ioctl_read_eeprom(struct usbnet *dev, AX_IOCTL_COMMAND *info) |
---|
| 1101 | +{ |
---|
| 1102 | + int i, retval = 0; |
---|
| 1103 | + u16 * buf; |
---|
| 1104 | + |
---|
| 1105 | + if (down_interruptible(&dev->sem)) { |
---|
| 1106 | + return -ERESTARTSYS; |
---|
| 1107 | + } |
---|
| 1108 | + |
---|
| 1109 | + buf = kmalloc((sizeof(u16) * info->size), GFP_KERNEL); |
---|
| 1110 | + if (!buf) { |
---|
| 1111 | + return -ERESTARTSYS; |
---|
| 1112 | + } |
---|
| 1113 | + |
---|
| 1114 | + for (i = 0; i < info->size; i++) { |
---|
| 1115 | + retval = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, i, |
---|
| 1116 | + 0, 2, &buf[i]); |
---|
| 1117 | + |
---|
| 1118 | + if(retval < 0) { |
---|
| 1119 | + kfree(buf); |
---|
| 1120 | + up(&dev->sem); |
---|
| 1121 | + return retval; |
---|
| 1122 | + } |
---|
| 1123 | + buf[i] = be16_to_cpu(buf[i]); |
---|
| 1124 | + } |
---|
| 1125 | + |
---|
| 1126 | + if (copy_to_user(info->buf, buf, (sizeof(unsigned short) * info->size))) { |
---|
| 1127 | + retval = -EFAULT; |
---|
| 1128 | + } |
---|
| 1129 | + kfree(buf); |
---|
| 1130 | + up(&dev->sem); |
---|
| 1131 | + |
---|
| 1132 | + return retval; |
---|
| 1133 | + |
---|
| 1134 | +} |
---|
| 1135 | + |
---|
| 1136 | +int ioctl_write_eeprom(struct usbnet *dev, AX_IOCTL_COMMAND *info) |
---|
| 1137 | +{ |
---|
| 1138 | + int i, retval; |
---|
| 1139 | + u16 * buf; |
---|
| 1140 | + |
---|
| 1141 | + if (down_interruptible(&dev->sem)) |
---|
| 1142 | + return -ERESTARTSYS; |
---|
| 1143 | + |
---|
| 1144 | + buf = kmalloc((sizeof(u16) * info->size), GFP_KERNEL); |
---|
| 1145 | + if (!buf) { |
---|
| 1146 | + return -ERESTARTSYS; |
---|
| 1147 | + } |
---|
| 1148 | + |
---|
| 1149 | + if (copy_from_user(buf, info->buf, (sizeof(u16) * info->size))) { |
---|
| 1150 | + kfree(buf); |
---|
| 1151 | + up(&dev->sem); |
---|
| 1152 | + return -EFAULT; |
---|
| 1153 | + } |
---|
| 1154 | + |
---|
| 1155 | + retval = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM_EN, 0, |
---|
| 1156 | + 0, 0, NULL); |
---|
| 1157 | + if (retval < 0) { |
---|
| 1158 | + kfree(buf); |
---|
| 1159 | + up(&dev->sem); |
---|
| 1160 | + return retval; |
---|
| 1161 | + } |
---|
| 1162 | + |
---|
| 1163 | + mdelay(info->delay); |
---|
| 1164 | + |
---|
| 1165 | + for (i = 0; i < info->size; i++){ |
---|
| 1166 | + retval = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM, i, |
---|
| 1167 | + cpu_to_be16(buf[i]), 0, NULL); |
---|
| 1168 | + |
---|
| 1169 | + if (retval < 0) { |
---|
| 1170 | + DPRINT_D("Failed to command Write EEPROM(retval:%d, offset:%d)\n", retval, i); |
---|
| 1171 | + kfree(buf); |
---|
| 1172 | + up(&dev->sem); |
---|
| 1173 | + return retval; |
---|
| 1174 | + } |
---|
| 1175 | + mdelay(info->delay); |
---|
| 1176 | + } |
---|
| 1177 | + |
---|
| 1178 | + debug_func(__FUNCTION__, buf, i); |
---|
| 1179 | + |
---|
| 1180 | + retval = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM_DIS, 0, |
---|
| 1181 | + 0, 0, NULL); |
---|
| 1182 | + if (retval < 0) { |
---|
| 1183 | + kfree(buf); |
---|
| 1184 | + up(&dev->sem); |
---|
| 1185 | + return retval; |
---|
| 1186 | + } |
---|
| 1187 | + |
---|
| 1188 | + mdelay(info->delay); |
---|
| 1189 | + |
---|
| 1190 | + retval = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, AXGPIOS_RSE, 0, 0, NULL); |
---|
| 1191 | + |
---|
| 1192 | + mdelay(info->delay); |
---|
| 1193 | + |
---|
| 1194 | + kfree(buf); |
---|
| 1195 | + up(&dev->sem); |
---|
| 1196 | + |
---|
| 1197 | + return retval; |
---|
| 1198 | +} |
---|
| 1199 | + |
---|
| 1200 | +typedef int (*IOCTRL_TABLE)(struct usbnet *dev, AX_IOCTL_COMMAND *info); |
---|
| 1201 | + |
---|
| 1202 | +IOCTRL_TABLE ioctl_tbl[] = { |
---|
| 1203 | + ioctl_signature, //AX_SIGNATURE |
---|
| 1204 | + ioctl_read_eeprom, |
---|
| 1205 | + ioctl_write_eeprom, |
---|
| 1206 | +}; |
---|
| 1207 | + |
---|
| 1208 | +static int ax8817x_ioctl(struct net_device *net, struct ifreq *rq, int cmd) |
---|
| 1209 | +{ |
---|
| 1210 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1211 | + |
---|
| 1212 | + AX_IOCTL_COMMAND info; |
---|
| 1213 | + AX_IOCTL_COMMAND *uptr = (AX_IOCTL_COMMAND*) rq->ifr_data; |
---|
| 1214 | + int private_cmd; |
---|
| 1215 | + |
---|
| 1216 | + switch (cmd) { |
---|
| 1217 | + case AX_PRIVATE : |
---|
| 1218 | + if (copy_from_user(&info, uptr, sizeof(AX_IOCTL_COMMAND))) { |
---|
| 1219 | + return -EFAULT; |
---|
| 1220 | + } |
---|
| 1221 | + |
---|
| 1222 | + private_cmd = info.ioctl_cmd; |
---|
| 1223 | + if ((*ioctl_tbl[private_cmd])(dev,&info) < 0) { |
---|
| 1224 | + return -EFAULT; |
---|
| 1225 | + } |
---|
| 1226 | + |
---|
| 1227 | + if (copy_to_user(uptr, &info, sizeof(AX_IOCTL_COMMAND))) { |
---|
| 1228 | + return -EFAULT; |
---|
| 1229 | + } |
---|
| 1230 | + |
---|
| 1231 | + break; |
---|
| 1232 | + |
---|
| 1233 | + default : |
---|
| 1234 | + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); |
---|
| 1235 | + } |
---|
| 1236 | + return 0; |
---|
| 1237 | +} |
---|
| 1238 | + |
---|
| 1239 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29) |
---|
| 1240 | +static const struct net_device_ops ax88x72_netdev_ops = { |
---|
| 1241 | + .ndo_open = axusbnet_open, |
---|
| 1242 | + .ndo_stop = axusbnet_stop, |
---|
| 1243 | + .ndo_start_xmit = axusbnet_start_xmit, |
---|
| 1244 | + .ndo_tx_timeout = axusbnet_tx_timeout, |
---|
| 1245 | + .ndo_change_mtu = axusbnet_change_mtu, |
---|
| 1246 | + .ndo_get_stats = axusbnet_get_stats, |
---|
| 1247 | + .ndo_do_ioctl = ax8817x_ioctl, |
---|
| 1248 | + .ndo_set_mac_address = ax8817x_set_mac_addr, |
---|
| 1249 | + .ndo_validate_addr = eth_validate_addr, |
---|
| 1250 | +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 0) |
---|
| 1251 | + .ndo_set_multicast_list = ax8817x_set_multicast, |
---|
| 1252 | +#else |
---|
| 1253 | + .ndo_set_rx_mode = ax8817x_set_multicast, |
---|
| 1254 | +#endif |
---|
| 1255 | +}; |
---|
| 1256 | +#endif |
---|
| 1257 | + |
---|
| 1258 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29) |
---|
| 1259 | +static const struct net_device_ops ax88178_netdev_ops = { |
---|
| 1260 | + .ndo_open = axusbnet_open, |
---|
| 1261 | + .ndo_stop = axusbnet_stop, |
---|
| 1262 | + .ndo_start_xmit = axusbnet_start_xmit, |
---|
| 1263 | + .ndo_tx_timeout = axusbnet_tx_timeout, |
---|
| 1264 | + .ndo_change_mtu = axusbnet_change_mtu, |
---|
| 1265 | + .ndo_get_stats = axusbnet_get_stats, |
---|
| 1266 | + .ndo_do_ioctl = ax8817x_ioctl, |
---|
| 1267 | + .ndo_set_mac_address = ax8817x_set_mac_addr, |
---|
| 1268 | + .ndo_validate_addr = eth_validate_addr, |
---|
| 1269 | +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 0) |
---|
| 1270 | + .ndo_set_multicast_list = ax88178_set_multicast, |
---|
| 1271 | +#else |
---|
| 1272 | + .ndo_set_rx_mode = ax88178_set_multicast, |
---|
| 1273 | +#endif |
---|
| 1274 | +}; |
---|
| 1275 | +#endif |
---|
| 1276 | + |
---|
| 1277 | +static int access_eeprom_mac(struct usbnet *dev, u8 *buf, u8 offset, bool wflag) |
---|
| 1278 | +{ |
---|
| 1279 | + int ret = 0, i; |
---|
| 1280 | + u16* tmp = (u16*)buf; |
---|
| 1281 | + |
---|
| 1282 | + if (wflag) { |
---|
| 1283 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM_EN, |
---|
| 1284 | + 0, 0, 0, NULL); |
---|
| 1285 | + if (ret < 0) |
---|
| 1286 | + return ret; |
---|
| 1287 | + |
---|
| 1288 | + mdelay(15); |
---|
| 1289 | + } |
---|
| 1290 | + |
---|
| 1291 | + for (i = 0; i < (ETH_ALEN >> 1); i++) { |
---|
| 1292 | + if (wflag) { |
---|
| 1293 | + u16 wd = cpu_to_le16(*(tmp + i)); |
---|
| 1294 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM, offset + i, |
---|
| 1295 | + wd, 0, NULL); |
---|
| 1296 | + if (ret < 0) |
---|
| 1297 | + break; |
---|
| 1298 | + |
---|
| 1299 | + mdelay(15); |
---|
| 1300 | + } |
---|
| 1301 | + else { |
---|
| 1302 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, |
---|
| 1303 | + offset + i, 0, 2, tmp + i); |
---|
| 1304 | + if (ret < 0) |
---|
| 1305 | + break; |
---|
| 1306 | + } |
---|
| 1307 | + } |
---|
| 1308 | + |
---|
| 1309 | + if (!wflag) { |
---|
| 1310 | + if (ret < 0) { |
---|
| 1311 | + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) |
---|
| 1312 | + netdev_dbg(dev->net, "Failed to read MAC address from EEPROM: %d\n", ret); |
---|
| 1313 | + #else |
---|
| 1314 | + devdbg(dev, "Failed to read MAC address from EEPROM: %d\n", ret); |
---|
| 1315 | + #endif |
---|
| 1316 | + return ret; |
---|
| 1317 | + } |
---|
| 1318 | + memcpy(dev->net->dev_addr, buf, ETH_ALEN); |
---|
| 1319 | + } |
---|
| 1320 | + else { |
---|
| 1321 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM_DIS, |
---|
| 1322 | + 0, 0, 0, NULL); |
---|
| 1323 | + if (ret < 0) |
---|
| 1324 | + return ret; |
---|
| 1325 | + |
---|
| 1326 | + /* reload eeprom data */ |
---|
| 1327 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 1328 | + AXGPIOS_RSE, 0, 0, NULL); |
---|
| 1329 | + if (ret < 0) |
---|
| 1330 | + return ret; |
---|
| 1331 | + } |
---|
| 1332 | + |
---|
| 1333 | + return 0; |
---|
| 1334 | +} |
---|
| 1335 | + |
---|
| 1336 | +static int ax8817x_check_ether_addr(struct usbnet *dev) |
---|
| 1337 | +{ |
---|
| 1338 | + unsigned char *tmp = (unsigned char*)dev->net->dev_addr; |
---|
| 1339 | + u8 default_mac[6] = {0, 0x0e, 0xc6, 0x87, 0x72, 0x01}; |
---|
| 1340 | + |
---|
| 1341 | + if (((*((u8*)tmp) == 0) && (*((u8*)tmp + 1) == 0) && (*((u8*)tmp + 2) == 0)) || |
---|
| 1342 | + !is_valid_ether_addr((u8*)tmp) || |
---|
| 1343 | + !memcmp(dev->net->dev_addr, default_mac, ETH_ALEN)) { |
---|
| 1344 | + printk("Found invalid EEPROM MAC address value "); |
---|
| 1345 | + printk("%02X-%02X-%02X-%02X-%02X-%02X\n", *((u8*)tmp + 0), |
---|
| 1346 | + *((u8*)tmp + 1), |
---|
| 1347 | + *((u8*)tmp + 2), |
---|
| 1348 | + *((u8*)tmp + 3), |
---|
| 1349 | + *((u8*)tmp + 4), |
---|
| 1350 | + *((u8*)tmp + 5)); |
---|
| 1351 | + |
---|
| 1352 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) |
---|
| 1353 | + eth_hw_addr_random(dev->net); |
---|
| 1354 | +#else |
---|
| 1355 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) |
---|
| 1356 | + dev->net->addr_assign_type |= NET_ADDR_RANDOM; |
---|
| 1357 | +#endif |
---|
| 1358 | + random_ether_addr(dev->net->dev_addr); |
---|
| 1359 | +#endif |
---|
| 1360 | + *tmp = 0; |
---|
| 1361 | + *(tmp + 1) = 0x0E; |
---|
| 1362 | + *(tmp + 2) = 0xC6; |
---|
| 1363 | + *(tmp + 3) = 0x8F; |
---|
| 1364 | + |
---|
| 1365 | + return -EADDRNOTAVAIL; |
---|
| 1366 | + } |
---|
| 1367 | + return 0; |
---|
| 1368 | +} |
---|
| 1369 | + |
---|
| 1370 | +static int ax8817x_get_mac(struct usbnet *dev, u8* buf) |
---|
| 1371 | +{ |
---|
| 1372 | + int ret, i; |
---|
| 1373 | + |
---|
| 1374 | + |
---|
| 1375 | + ret = access_eeprom_mac(dev, buf, 0x04, 0); |
---|
| 1376 | + if (ret < 0) |
---|
| 1377 | + goto out; |
---|
| 1378 | + |
---|
| 1379 | + if (ax8817x_check_ether_addr(dev)) { |
---|
| 1380 | + ret = access_eeprom_mac(dev, dev->net->dev_addr, 0x04, 1); |
---|
| 1381 | + if (ret < 0) { |
---|
| 1382 | + deverr(dev, "Failed to write MAC to EEPROM: %d", ret); |
---|
| 1383 | + goto out; |
---|
| 1384 | + } |
---|
| 1385 | + |
---|
| 1386 | + msleep(5); |
---|
| 1387 | + |
---|
| 1388 | + ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, |
---|
| 1389 | + 0, 0, ETH_ALEN, buf); |
---|
| 1390 | + if (ret < 0) { |
---|
| 1391 | + deverr(dev, "Failed to read MAC address: %d", ret); |
---|
| 1392 | + goto out; |
---|
| 1393 | + } |
---|
| 1394 | + |
---|
| 1395 | + for (i = 0; i < ETH_ALEN; i++) |
---|
| 1396 | + if (*(dev->net->dev_addr + i) != *((u8*)buf + i)) { |
---|
| 1397 | + devwarn(dev, "Found invalid EEPROM part or non-EEPROM"); |
---|
| 1398 | + break; |
---|
| 1399 | + } |
---|
| 1400 | + } |
---|
| 1401 | + |
---|
| 1402 | + memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN); |
---|
| 1403 | + |
---|
| 1404 | + /* Set the MAC address */ |
---|
| 1405 | + ax8817x_write_cmd (dev, AX88772_CMD_WRITE_NODE_ID, 0, 0, |
---|
| 1406 | + ETH_ALEN, dev->net->dev_addr); |
---|
| 1407 | + |
---|
| 1408 | + if (ret < 0) { |
---|
| 1409 | + deverr(dev, "Failed to write MAC address: %d", ret); |
---|
| 1410 | + goto out; |
---|
| 1411 | + } |
---|
| 1412 | + |
---|
| 1413 | + return 0; |
---|
| 1414 | +out: |
---|
| 1415 | + return ret; |
---|
| 1416 | +} |
---|
| 1417 | + |
---|
| 1418 | +static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 1419 | +{ |
---|
| 1420 | + int ret = 0; |
---|
| 1421 | + void *buf; |
---|
| 1422 | + int i; |
---|
| 1423 | + unsigned long gpio_bits = dev->driver_info->data; |
---|
| 1424 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 1425 | + |
---|
| 1426 | + axusbnet_get_endpoints(dev, intf); |
---|
| 1427 | + |
---|
| 1428 | + buf = kmalloc(ETH_ALEN, GFP_KERNEL); |
---|
| 1429 | + if (!buf) { |
---|
| 1430 | + ret = -ENOMEM; |
---|
| 1431 | + goto out1; |
---|
| 1432 | + } |
---|
| 1433 | + |
---|
| 1434 | + /* Toggle the GPIOs in a manufacturer/model specific way */ |
---|
| 1435 | + for (i = 2; i >= 0; i--) { |
---|
| 1436 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 1437 | + (gpio_bits >> (i * 8)) & 0xff, |
---|
| 1438 | + 0, 0, NULL); |
---|
| 1439 | + if (ret < 0) |
---|
| 1440 | + goto out2; |
---|
| 1441 | + |
---|
| 1442 | + msleep(5); |
---|
| 1443 | + } |
---|
| 1444 | + |
---|
| 1445 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, NULL); |
---|
| 1446 | + if (ret < 0) { |
---|
| 1447 | + deverr(dev, "send AX_CMD_WRITE_RX_CTL failed: %d", ret); |
---|
| 1448 | + goto out2; |
---|
| 1449 | + } |
---|
| 1450 | + |
---|
| 1451 | + /* Get the MAC address */ |
---|
| 1452 | + memset(buf, 0, ETH_ALEN); |
---|
| 1453 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf); |
---|
| 1454 | + if (ret < 0) { |
---|
| 1455 | + deverr(dev, "read AX_CMD_READ_NODE_ID failed: %d", ret); |
---|
| 1456 | + goto out2; |
---|
| 1457 | + } |
---|
| 1458 | + memcpy(dev->net->dev_addr, buf, ETH_ALEN); |
---|
| 1459 | + |
---|
| 1460 | + /* Get the PHY id */ |
---|
| 1461 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); |
---|
| 1462 | + if (ret < 0) { |
---|
| 1463 | + deverr(dev, "error on read AX_CMD_READ_PHY_ID: %02x", ret); |
---|
| 1464 | + goto out2; |
---|
| 1465 | + } else if (ret < 2) { |
---|
| 1466 | + /* this should always return 2 bytes */ |
---|
| 1467 | + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", |
---|
| 1468 | + ret); |
---|
| 1469 | + ret = -EIO; |
---|
| 1470 | + goto out2; |
---|
| 1471 | + } |
---|
| 1472 | + |
---|
| 1473 | + /* Initialize MII structure */ |
---|
| 1474 | + dev->mii.dev = dev->net; |
---|
| 1475 | + dev->mii.mdio_read = ax8817x_mdio_read_le; |
---|
| 1476 | + dev->mii.mdio_write = ax8817x_mdio_write_le; |
---|
| 1477 | + dev->mii.phy_id_mask = 0x3f; |
---|
| 1478 | + dev->mii.reg_num_mask = 0x1f; |
---|
| 1479 | + dev->mii.phy_id = *((u8 *)buf + 1); |
---|
| 1480 | + |
---|
| 1481 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 1482 | + dev->net->do_ioctl = ax8817x_ioctl; |
---|
| 1483 | + dev->net->set_multicast_list = ax8817x_set_multicast; |
---|
| 1484 | + dev->net->set_mac_address = ax8817x_set_mac_addr; |
---|
| 1485 | +#else |
---|
| 1486 | + dev->net->netdev_ops = &ax88x72_netdev_ops; |
---|
| 1487 | +#endif |
---|
| 1488 | + |
---|
| 1489 | + dev->net->ethtool_ops = &ax8817x_ethtool_ops; |
---|
| 1490 | + |
---|
| 1491 | + /* Register suspend and resume functions */ |
---|
| 1492 | + data->suspend = axusbnet_suspend; |
---|
| 1493 | + data->resume = axusbnet_resume; |
---|
| 1494 | + |
---|
| 1495 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); |
---|
| 1496 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 1497 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); |
---|
| 1498 | + mii_nway_restart(&dev->mii); |
---|
| 1499 | + |
---|
| 1500 | + printk(version); |
---|
| 1501 | + |
---|
| 1502 | + return 0; |
---|
| 1503 | +out2: |
---|
| 1504 | + kfree(buf); |
---|
| 1505 | +out1: |
---|
| 1506 | + return ret; |
---|
| 1507 | +} |
---|
| 1508 | + |
---|
| 1509 | +static struct ethtool_ops ax88772_ethtool_ops = { |
---|
| 1510 | + .get_drvinfo = ax8817x_get_drvinfo, |
---|
| 1511 | + .get_link = ethtool_op_get_link, |
---|
| 1512 | + .get_msglevel = axusbnet_get_msglevel, |
---|
| 1513 | + .set_msglevel = axusbnet_set_msglevel, |
---|
| 1514 | + .get_wol = ax8817x_get_wol, |
---|
| 1515 | + .set_wol = ax8817x_set_wol, |
---|
| 1516 | + .get_eeprom_len = ax8817x_get_eeprom_len, |
---|
| 1517 | + .get_eeprom = ax8817x_get_eeprom, |
---|
| 1518 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) |
---|
| 1519 | + .get_settings = ax8817x_get_settings, |
---|
| 1520 | + .set_settings = ax8817x_set_settings, |
---|
| 1521 | +#else |
---|
| 1522 | + .get_link_ksettings = ax8817x_get_link_ksettings, |
---|
| 1523 | + .set_link_ksettings = ax8817x_set_link_ksettings, |
---|
| 1524 | +#endif |
---|
| 1525 | +}; |
---|
| 1526 | + |
---|
| 1527 | +static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 1528 | +{ |
---|
| 1529 | + int ret; |
---|
| 1530 | + void *buf; |
---|
| 1531 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 1532 | + struct ax88772_data *ax772_data = NULL; |
---|
| 1533 | + |
---|
| 1534 | + axusbnet_get_endpoints(dev, intf); |
---|
| 1535 | + |
---|
| 1536 | + buf = kmalloc(6, GFP_KERNEL); |
---|
| 1537 | + if (!buf) { |
---|
| 1538 | + deverr(dev, "Cannot allocate memory for buffer"); |
---|
| 1539 | + ret = -ENOMEM; |
---|
| 1540 | + goto out1; |
---|
| 1541 | + } |
---|
| 1542 | + |
---|
| 1543 | + ax772_data = kmalloc(sizeof(*ax772_data), GFP_KERNEL); |
---|
| 1544 | + if (!ax772_data) { |
---|
| 1545 | + deverr(dev, "Cannot allocate memory for AX88772 data"); |
---|
| 1546 | + kfree(buf); |
---|
| 1547 | + return -ENOMEM; |
---|
| 1548 | + } |
---|
| 1549 | + |
---|
| 1550 | + memset(ax772_data, 0, sizeof(*ax772_data)); |
---|
| 1551 | + dev->priv = ax772_data; |
---|
| 1552 | + |
---|
| 1553 | + ax772_data->ax_work = create_singlethread_workqueue("ax88772"); |
---|
| 1554 | + if (!ax772_data->ax_work) { |
---|
| 1555 | + kfree(ax772_data); |
---|
| 1556 | + kfree(buf); |
---|
| 1557 | + return -ENOMEM; |
---|
| 1558 | + } |
---|
| 1559 | + |
---|
| 1560 | + ax772_data->dev = dev; |
---|
| 1561 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 1562 | + INIT_WORK(&ax772_data->check_link, ax88772_link_reset, dev); |
---|
| 1563 | +#else |
---|
| 1564 | + INIT_WORK(&ax772_data->check_link, ax88772_link_reset); |
---|
| 1565 | +#endif |
---|
| 1566 | + |
---|
| 1567 | + /* reload eeprom data */ |
---|
| 1568 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, 0x00B0, 0, 0, NULL); |
---|
| 1569 | + if (ret < 0) |
---|
| 1570 | + goto out2; |
---|
| 1571 | + |
---|
| 1572 | + msleep(5); |
---|
| 1573 | + |
---|
| 1574 | + /* Initialize MII structure */ |
---|
| 1575 | + dev->mii.dev = dev->net; |
---|
| 1576 | + dev->mii.mdio_read = ax8817x_mdio_read_le; |
---|
| 1577 | + dev->mii.mdio_write = ax8817x_mdio_write_le; |
---|
| 1578 | + dev->mii.phy_id_mask = 0xff; |
---|
| 1579 | + dev->mii.reg_num_mask = 0xff; |
---|
| 1580 | + |
---|
| 1581 | + /* Get the PHY id */ |
---|
| 1582 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); |
---|
| 1583 | + if (ret < 0) { |
---|
| 1584 | + deverr(dev, "Error reading PHY ID: %02x", ret); |
---|
| 1585 | + goto out2; |
---|
| 1586 | + } else if (ret < 2) { |
---|
| 1587 | + /* this should always return 2 bytes */ |
---|
| 1588 | + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", |
---|
| 1589 | + ret); |
---|
| 1590 | + ret = -EIO; |
---|
| 1591 | + goto out2; |
---|
| 1592 | + } |
---|
| 1593 | + dev->mii.phy_id = *((u8 *)buf + 1); |
---|
| 1594 | + |
---|
| 1595 | + if (dev->mii.phy_id == 0x10) { |
---|
| 1596 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, |
---|
| 1597 | + 0x0001, 0, 0, NULL); |
---|
| 1598 | + if (ret < 0) { |
---|
| 1599 | + deverr(dev, "Select PHY #1 failed: %d", ret); |
---|
| 1600 | + goto out2; |
---|
| 1601 | + } |
---|
| 1602 | + |
---|
| 1603 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, |
---|
| 1604 | + 0, 0, NULL); |
---|
| 1605 | + if (ret < 0) { |
---|
| 1606 | + deverr(dev, "Failed to power down PHY: %d", ret); |
---|
| 1607 | + goto out2; |
---|
| 1608 | + } |
---|
| 1609 | + |
---|
| 1610 | + msleep(150); |
---|
| 1611 | + |
---|
| 1612 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, |
---|
| 1613 | + 0, 0, NULL); |
---|
| 1614 | + if (ret < 0) { |
---|
| 1615 | + deverr(dev, "Failed to perform software reset: %d", |
---|
| 1616 | + ret); |
---|
| 1617 | + goto out2; |
---|
| 1618 | + } |
---|
| 1619 | + |
---|
| 1620 | + msleep(150); |
---|
| 1621 | + |
---|
| 1622 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 1623 | + AX_SWRESET_IPRL | AX_SWRESET_PRL, |
---|
| 1624 | + 0, 0, NULL); |
---|
| 1625 | + if (ret < 0) { |
---|
| 1626 | + deverr(dev, |
---|
| 1627 | + "Failed to set PHY reset control: %d", ret); |
---|
| 1628 | + goto out2; |
---|
| 1629 | + } |
---|
| 1630 | + } else { |
---|
| 1631 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, |
---|
| 1632 | + 0x0000, 0, 0, NULL); |
---|
| 1633 | + if (ret < 0) { |
---|
| 1634 | + deverr(dev, "Select PHY #1 failed: %d", ret); |
---|
| 1635 | + goto out2; |
---|
| 1636 | + } |
---|
| 1637 | + |
---|
| 1638 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 1639 | + AX_SWRESET_IPPD | AX_SWRESET_PRL, |
---|
| 1640 | + 0, 0, NULL); |
---|
| 1641 | + if (ret < 0) { |
---|
| 1642 | + deverr(dev, "Failed to power down internal PHY: %d", |
---|
| 1643 | + ret); |
---|
| 1644 | + goto out2; |
---|
| 1645 | + } |
---|
| 1646 | + } |
---|
| 1647 | + |
---|
| 1648 | + msleep(150); |
---|
| 1649 | + |
---|
| 1650 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 1651 | + 0x0000, 0, 0, NULL); |
---|
| 1652 | + if (ret < 0) { |
---|
| 1653 | + deverr(dev, "Failed to reset RX_CTL: %d", ret); |
---|
| 1654 | + goto out2; |
---|
| 1655 | + } |
---|
| 1656 | + |
---|
| 1657 | + /* Get the MAC address */ |
---|
| 1658 | + memset(buf, 0, ETH_ALEN); |
---|
| 1659 | + ret = ax8817x_get_mac(dev, buf); |
---|
| 1660 | + if (ret < 0) { |
---|
| 1661 | + deverr(dev, "Get HW address failed: %d", ret); |
---|
| 1662 | + goto out2; |
---|
| 1663 | + } |
---|
| 1664 | + |
---|
| 1665 | + ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 1666 | + if (ret < 0) { |
---|
| 1667 | + deverr(dev, "Enabling software MII failed: %d", ret); |
---|
| 1668 | + goto out2; |
---|
| 1669 | + } |
---|
| 1670 | + |
---|
| 1671 | + if (dev->mii.phy_id == 0x10) { |
---|
| 1672 | + ret = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 2); |
---|
| 1673 | + if (ret != 0x003b) { |
---|
| 1674 | + deverr(dev, "Read PHY register 2 must be 0x3b00: %d", |
---|
| 1675 | + ret); |
---|
| 1676 | + goto out2; |
---|
| 1677 | + } |
---|
| 1678 | + |
---|
| 1679 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, |
---|
| 1680 | + 0, 0, NULL); |
---|
| 1681 | + if (ret < 0) { |
---|
| 1682 | + deverr(dev, "Set external PHY reset pin level: %d", |
---|
| 1683 | + ret); |
---|
| 1684 | + goto out2; |
---|
| 1685 | + } |
---|
| 1686 | + msleep(150); |
---|
| 1687 | + |
---|
| 1688 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 1689 | + AX_SWRESET_IPRL | AX_SWRESET_PRL, |
---|
| 1690 | + 0, 0, NULL); |
---|
| 1691 | + if (ret < 0) { |
---|
| 1692 | + deverr(dev, |
---|
| 1693 | + "Set Internal/External PHY reset control: %d", |
---|
| 1694 | + ret); |
---|
| 1695 | + goto out2; |
---|
| 1696 | + } |
---|
| 1697 | + msleep(150); |
---|
| 1698 | + } |
---|
| 1699 | + |
---|
| 1700 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 1701 | + dev->net->do_ioctl = ax8817x_ioctl; |
---|
| 1702 | + dev->net->set_multicast_list = ax8817x_set_multicast; |
---|
| 1703 | + dev->net->set_mac_address = ax8817x_set_mac_addr; |
---|
| 1704 | +#else |
---|
| 1705 | + dev->net->netdev_ops = &ax88x72_netdev_ops; |
---|
| 1706 | +#endif |
---|
| 1707 | + |
---|
| 1708 | + dev->net->ethtool_ops = &ax88772_ethtool_ops; |
---|
| 1709 | + |
---|
| 1710 | + /* Register suspend and resume functions */ |
---|
| 1711 | + data->suspend = ax88772_suspend; |
---|
| 1712 | + data->resume = ax88772_resume; |
---|
| 1713 | + |
---|
| 1714 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); |
---|
| 1715 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 1716 | + ADVERTISE_ALL | ADVERTISE_CSMA); |
---|
| 1717 | + |
---|
| 1718 | + mii_nway_restart(&dev->mii); |
---|
| 1719 | + ax772_data->autoneg_start = jiffies; |
---|
| 1720 | + ax772_data->Event = WAIT_AUTONEG_COMPLETE; |
---|
| 1721 | + |
---|
| 1722 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, 0, 0, 0, NULL); |
---|
| 1723 | + if (ret < 0) { |
---|
| 1724 | + deverr(dev, "Write medium mode register: %d", ret); |
---|
| 1725 | + goto out2; |
---|
| 1726 | + } |
---|
| 1727 | + |
---|
| 1728 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, |
---|
| 1729 | + AX88772_IPG0_DEFAULT | |
---|
| 1730 | + (AX88772_IPG1_DEFAULT << 8), |
---|
| 1731 | + AX88772_IPG2_DEFAULT, 0, NULL); |
---|
| 1732 | + if (ret < 0) { |
---|
| 1733 | + deverr(dev, "Write IPG,IPG1,IPG2 failed: %d", ret); |
---|
| 1734 | + goto out2; |
---|
| 1735 | + } |
---|
| 1736 | + |
---|
| 1737 | + ret = ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); |
---|
| 1738 | + if (ret < 0) { |
---|
| 1739 | + deverr(dev, "Failed to set hardware MII: %02x", ret); |
---|
| 1740 | + goto out2; |
---|
| 1741 | + } |
---|
| 1742 | + |
---|
| 1743 | + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ |
---|
| 1744 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, NULL); |
---|
| 1745 | + if (ret < 0) { |
---|
| 1746 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 1747 | + goto out2; |
---|
| 1748 | + } |
---|
| 1749 | + |
---|
| 1750 | + /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ |
---|
| 1751 | + if (dev->driver_info->flags & FLAG_FRAMING_AX) { |
---|
| 1752 | + /* hard_mtu is still the default - the device does not support |
---|
| 1753 | + jumbo eth frames */ |
---|
| 1754 | + dev->rx_urb_size = 2048; |
---|
| 1755 | + } |
---|
| 1756 | + |
---|
| 1757 | + kfree(buf); |
---|
| 1758 | + printk(version); |
---|
| 1759 | + return 0; |
---|
| 1760 | + |
---|
| 1761 | +out2: |
---|
| 1762 | + destroy_workqueue(ax772_data->ax_work); |
---|
| 1763 | + kfree(ax772_data); |
---|
| 1764 | + kfree(buf); |
---|
| 1765 | +out1: |
---|
| 1766 | + return ret; |
---|
| 1767 | +} |
---|
| 1768 | + |
---|
| 1769 | +static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 1770 | +{ |
---|
| 1771 | + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; |
---|
| 1772 | + |
---|
| 1773 | + if (ax772_data) { |
---|
| 1774 | + flush_workqueue(ax772_data->ax_work); |
---|
| 1775 | + destroy_workqueue(ax772_data->ax_work); |
---|
| 1776 | + |
---|
| 1777 | + /* stop MAC operation */ |
---|
| 1778 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, AX_RX_CTL_STOP, |
---|
| 1779 | + 0, 0, NULL); |
---|
| 1780 | + |
---|
| 1781 | + /* Power down PHY */ |
---|
| 1782 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, |
---|
| 1783 | + 0, 0, NULL); |
---|
| 1784 | + |
---|
| 1785 | + kfree(ax772_data); |
---|
| 1786 | + } |
---|
| 1787 | +} |
---|
| 1788 | + |
---|
| 1789 | +static int ax88772a_phy_powerup(struct usbnet *dev) |
---|
| 1790 | +{ |
---|
| 1791 | + int ret; |
---|
| 1792 | + /* set the embedded Ethernet PHY in power-down state */ |
---|
| 1793 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 1794 | + AX_SWRESET_IPPD | AX_SWRESET_IPRL, 0, 0, NULL); |
---|
| 1795 | + if (ret < 0) { |
---|
| 1796 | + deverr(dev, "Failed to power down PHY: %d", ret); |
---|
| 1797 | + return ret; |
---|
| 1798 | + } |
---|
| 1799 | + |
---|
| 1800 | + msleep(10); |
---|
| 1801 | + |
---|
| 1802 | + /* set the embedded Ethernet PHY in power-up state */ |
---|
| 1803 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL, |
---|
| 1804 | + 0, 0, NULL); |
---|
| 1805 | + if (ret < 0) { |
---|
| 1806 | + deverr(dev, "Failed to reset PHY: %d", ret); |
---|
| 1807 | + return ret; |
---|
| 1808 | + } |
---|
| 1809 | + |
---|
| 1810 | + msleep(600); |
---|
| 1811 | + |
---|
| 1812 | + /* set the embedded Ethernet PHY in reset state */ |
---|
| 1813 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, |
---|
| 1814 | + 0, 0, NULL); |
---|
| 1815 | + if (ret < 0) { |
---|
| 1816 | + deverr(dev, "Failed to power up PHY: %d", ret); |
---|
| 1817 | + return ret; |
---|
| 1818 | + } |
---|
| 1819 | + |
---|
| 1820 | + /* set the embedded Ethernet PHY in power-up state */ |
---|
| 1821 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL, |
---|
| 1822 | + 0, 0, NULL); |
---|
| 1823 | + if (ret < 0) { |
---|
| 1824 | + deverr(dev, "Failed to reset PHY: %d", ret); |
---|
| 1825 | + return ret; |
---|
| 1826 | + } |
---|
| 1827 | + |
---|
| 1828 | + return 0; |
---|
| 1829 | +} |
---|
| 1830 | + |
---|
| 1831 | +static int ax88772a_bind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 1832 | +{ |
---|
| 1833 | + int ret = -EIO; |
---|
| 1834 | + void *buf; |
---|
| 1835 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 1836 | + struct ax88772a_data *ax772a_data = NULL; |
---|
| 1837 | + |
---|
| 1838 | + printk(version); |
---|
| 1839 | + |
---|
| 1840 | + axusbnet_get_endpoints(dev, intf); |
---|
| 1841 | + |
---|
| 1842 | + buf = kmalloc(6, GFP_KERNEL); |
---|
| 1843 | + if (!buf) { |
---|
| 1844 | + deverr(dev, "Cannot allocate memory for buffer"); |
---|
| 1845 | + ret = -ENOMEM; |
---|
| 1846 | + goto out1; |
---|
| 1847 | + } |
---|
| 1848 | + |
---|
| 1849 | + ax772a_data = kmalloc(sizeof(*ax772a_data), GFP_KERNEL); |
---|
| 1850 | + if (!ax772a_data) { |
---|
| 1851 | + deverr(dev, "Cannot allocate memory for AX88772A data"); |
---|
| 1852 | + kfree(buf); |
---|
| 1853 | + return -ENOMEM; |
---|
| 1854 | + } |
---|
| 1855 | + memset(ax772a_data, 0, sizeof(*ax772a_data)); |
---|
| 1856 | + dev->priv = ax772a_data; |
---|
| 1857 | + |
---|
| 1858 | + ax772a_data->ax_work = create_singlethread_workqueue("ax88772a"); |
---|
| 1859 | + if (!ax772a_data->ax_work) { |
---|
| 1860 | + kfree(ax772a_data); |
---|
| 1861 | + kfree(buf); |
---|
| 1862 | + return -ENOMEM; |
---|
| 1863 | + } |
---|
| 1864 | + |
---|
| 1865 | + ax772a_data->dev = dev; |
---|
| 1866 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 1867 | + INIT_WORK(&ax772a_data->check_link, ax88772a_link_reset, dev); |
---|
| 1868 | +#else |
---|
| 1869 | + INIT_WORK(&ax772a_data->check_link, ax88772a_link_reset); |
---|
| 1870 | +#endif |
---|
| 1871 | + |
---|
| 1872 | + /* Get the EEPROM data*/ |
---|
| 1873 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, |
---|
| 1874 | + (void *)&ax772a_data->EepromData); |
---|
| 1875 | + if (ret < 0) { |
---|
| 1876 | + deverr(dev, "read SROM address 17h failed: %d", ret); |
---|
| 1877 | + goto out2; |
---|
| 1878 | + } |
---|
| 1879 | + le16_to_cpus(&ax772a_data->EepromData); |
---|
| 1880 | + /* End of get EEPROM data */ |
---|
| 1881 | + |
---|
| 1882 | + /* reload eeprom data */ |
---|
| 1883 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 1884 | + AXGPIOS_RSE, 0, 0, NULL); |
---|
| 1885 | + if (ret < 0) |
---|
| 1886 | + goto out2; |
---|
| 1887 | + |
---|
| 1888 | + msleep(5); |
---|
| 1889 | + |
---|
| 1890 | + /* Initialize MII structure */ |
---|
| 1891 | + dev->mii.dev = dev->net; |
---|
| 1892 | + dev->mii.mdio_read = ax8817x_mdio_read_le; |
---|
| 1893 | + dev->mii.mdio_write = ax8817x_mdio_write_le; |
---|
| 1894 | + dev->mii.phy_id_mask = 0xff; |
---|
| 1895 | + dev->mii.reg_num_mask = 0xff; |
---|
| 1896 | + |
---|
| 1897 | + /* Get the PHY id */ |
---|
| 1898 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); |
---|
| 1899 | + if (ret < 0) { |
---|
| 1900 | + deverr(dev, "Error reading PHY ID: %02x", ret); |
---|
| 1901 | + goto out2; |
---|
| 1902 | + } else if (ret < 2) { |
---|
| 1903 | + /* this should always return 2 bytes */ |
---|
| 1904 | + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", |
---|
| 1905 | + ret); |
---|
| 1906 | + goto out2; |
---|
| 1907 | + } |
---|
| 1908 | + dev->mii.phy_id = *((u8 *)buf + 1); |
---|
| 1909 | + |
---|
| 1910 | + if (dev->mii.phy_id != 0x10) { |
---|
| 1911 | + deverr(dev, "Got wrong PHY ID: %02x", dev->mii.phy_id); |
---|
| 1912 | + goto out2; |
---|
| 1913 | + } |
---|
| 1914 | + |
---|
| 1915 | + /* select the embedded 10/100 Ethernet PHY */ |
---|
| 1916 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, |
---|
| 1917 | + AX_PHYSEL_SSEN | AX_PHYSEL_PSEL | AX_PHYSEL_SSMII, |
---|
| 1918 | + 0, 0, NULL); |
---|
| 1919 | + if (ret < 0) { |
---|
| 1920 | + deverr(dev, "Select PHY #1 failed: %d", ret); |
---|
| 1921 | + goto out2; |
---|
| 1922 | + } |
---|
| 1923 | + |
---|
| 1924 | + ret = ax88772a_phy_powerup(dev); |
---|
| 1925 | + if (ret < 0) |
---|
| 1926 | + goto out2; |
---|
| 1927 | + |
---|
| 1928 | + /* stop MAC operation */ |
---|
| 1929 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, AX_RX_CTL_STOP, |
---|
| 1930 | + 0, 0, NULL); |
---|
| 1931 | + if (ret < 0) { |
---|
| 1932 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 1933 | + goto out2; |
---|
| 1934 | + } |
---|
| 1935 | + |
---|
| 1936 | + /* Get the MAC address */ |
---|
| 1937 | + memset(buf, 0, ETH_ALEN); |
---|
| 1938 | + ret = ax8817x_get_mac(dev, buf); |
---|
| 1939 | + if (ret < 0) { |
---|
| 1940 | + deverr(dev, "Get HW address failed: %d", ret); |
---|
| 1941 | + goto out2; |
---|
| 1942 | + } |
---|
| 1943 | + |
---|
| 1944 | + /* make sure the driver can enable sw mii operation */ |
---|
| 1945 | + ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 1946 | + if (ret < 0) { |
---|
| 1947 | + deverr(dev, "Enabling software MII failed: %d", ret); |
---|
| 1948 | + goto out2; |
---|
| 1949 | + } |
---|
| 1950 | + |
---|
| 1951 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 1952 | + dev->net->do_ioctl = ax8817x_ioctl; |
---|
| 1953 | + dev->net->set_multicast_list = ax8817x_set_multicast; |
---|
| 1954 | + dev->net->set_mac_address = ax8817x_set_mac_addr; |
---|
| 1955 | +#else |
---|
| 1956 | + dev->net->netdev_ops = &ax88x72_netdev_ops; |
---|
| 1957 | +#endif |
---|
| 1958 | + |
---|
| 1959 | + dev->net->ethtool_ops = &ax88772_ethtool_ops; |
---|
| 1960 | + |
---|
| 1961 | + /* Register suspend and resume functions */ |
---|
| 1962 | + data->suspend = ax88772_suspend; |
---|
| 1963 | + data->resume = ax88772_resume; |
---|
| 1964 | + |
---|
| 1965 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); |
---|
| 1966 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 1967 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); |
---|
| 1968 | + |
---|
| 1969 | + mii_nway_restart(&dev->mii); |
---|
| 1970 | + ax772a_data->autoneg_start = jiffies; |
---|
| 1971 | + ax772a_data->Event = WAIT_AUTONEG_COMPLETE; |
---|
| 1972 | + |
---|
| 1973 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 1974 | + 0, 0, 0, NULL); |
---|
| 1975 | + if (ret < 0) { |
---|
| 1976 | + deverr(dev, "Write medium mode register: %d", ret); |
---|
| 1977 | + goto out2; |
---|
| 1978 | + } |
---|
| 1979 | + |
---|
| 1980 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, |
---|
| 1981 | + AX88772A_IPG0_DEFAULT | AX88772A_IPG1_DEFAULT << 8, |
---|
| 1982 | + AX88772A_IPG2_DEFAULT, 0, NULL); |
---|
| 1983 | + if (ret < 0) { |
---|
| 1984 | + deverr(dev, "Write IPG,IPG1,IPG2 failed: %d", ret); |
---|
| 1985 | + goto out2; |
---|
| 1986 | + } |
---|
| 1987 | + |
---|
| 1988 | + memset(buf, 0, 4); |
---|
| 1989 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_IPG012, 0, 0, 3, buf); |
---|
| 1990 | + *((u8 *)buf + 3) = 0x00; |
---|
| 1991 | + if (ret < 0) { |
---|
| 1992 | + deverr(dev, "Failed to read IPG,IPG1,IPG2 failed: %d", ret); |
---|
| 1993 | + goto out2; |
---|
| 1994 | + } else { |
---|
| 1995 | + __u32 tmp32 = *((u32*)buf); |
---|
| 1996 | + le32_to_cpus(&tmp32); |
---|
| 1997 | + if (tmp32 != (AX88772A_IPG2_DEFAULT << 16 | |
---|
| 1998 | + AX88772A_IPG1_DEFAULT << 8 | AX88772A_IPG0_DEFAULT)) { |
---|
| 1999 | + printk("Non-authentic ASIX product\nASIX does not support it\n"); |
---|
| 2000 | + ret = -ENODEV; |
---|
| 2001 | + goto out2; |
---|
| 2002 | + } |
---|
| 2003 | + } |
---|
| 2004 | + |
---|
| 2005 | + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ |
---|
| 2006 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 2007 | + (AX_RX_CTL_START | AX_RX_CTL_AB), |
---|
| 2008 | + 0, 0, NULL); |
---|
| 2009 | + if (ret < 0) { |
---|
| 2010 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 2011 | + goto out2; |
---|
| 2012 | + } |
---|
| 2013 | + |
---|
| 2014 | + /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ |
---|
| 2015 | + if (dev->driver_info->flags & FLAG_FRAMING_AX) { |
---|
| 2016 | + /* hard_mtu is still the default - the device does not support |
---|
| 2017 | + jumbo eth frames */ |
---|
| 2018 | + dev->rx_urb_size = 2048; |
---|
| 2019 | + } |
---|
| 2020 | + |
---|
| 2021 | + kfree(buf); |
---|
| 2022 | + |
---|
| 2023 | + return ret; |
---|
| 2024 | +out2: |
---|
| 2025 | + destroy_workqueue(ax772a_data->ax_work); |
---|
| 2026 | + kfree(ax772a_data); |
---|
| 2027 | + kfree(buf); |
---|
| 2028 | +out1: |
---|
| 2029 | + return ret; |
---|
| 2030 | +} |
---|
| 2031 | + |
---|
| 2032 | +static void ax88772a_unbind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 2033 | +{ |
---|
| 2034 | + struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv; |
---|
| 2035 | + |
---|
| 2036 | + if (ax772a_data) { |
---|
| 2037 | + |
---|
| 2038 | + flush_workqueue(ax772a_data->ax_work); |
---|
| 2039 | + destroy_workqueue(ax772a_data->ax_work); |
---|
| 2040 | + |
---|
| 2041 | + /* stop MAC operation */ |
---|
| 2042 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 2043 | + AX_RX_CTL_STOP, 0, 0, NULL); |
---|
| 2044 | + |
---|
| 2045 | + /* Power down PHY */ |
---|
| 2046 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 2047 | + AX_SWRESET_IPPD, 0, 0, NULL); |
---|
| 2048 | + |
---|
| 2049 | + kfree(ax772a_data); |
---|
| 2050 | + } |
---|
| 2051 | +} |
---|
| 2052 | + |
---|
| 2053 | +static int ax88772b_set_csums(struct usbnet *dev) |
---|
| 2054 | +{ |
---|
| 2055 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 2056 | + u16 checksum; |
---|
| 2057 | + |
---|
| 2058 | + if (ax772b_data->checksum & AX_RX_CHECKSUM) |
---|
| 2059 | + checksum = AX_RXCOE_DEF_CSUM; |
---|
| 2060 | + else |
---|
| 2061 | + checksum = 0; |
---|
| 2062 | + |
---|
| 2063 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_RXCOE_CTL, |
---|
| 2064 | + checksum, 0, 0, NULL); |
---|
| 2065 | + |
---|
| 2066 | + if (ax772b_data->checksum & AX_TX_CHECKSUM) |
---|
| 2067 | + checksum = AX_TXCOE_DEF_CSUM; |
---|
| 2068 | + else |
---|
| 2069 | + checksum = 0; |
---|
| 2070 | + |
---|
| 2071 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_TXCOE_CTL, |
---|
| 2072 | + checksum, 0, 0, NULL); |
---|
| 2073 | + |
---|
| 2074 | + return 0; |
---|
| 2075 | +} |
---|
| 2076 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) |
---|
| 2077 | +static u32 ax88772b_get_tx_csum(struct net_device *netdev) |
---|
| 2078 | +{ |
---|
| 2079 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 2080 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 2081 | + |
---|
| 2082 | + return ax772b_data->checksum & AX_TX_CHECKSUM; |
---|
| 2083 | +} |
---|
| 2084 | + |
---|
| 2085 | +static u32 ax88772b_get_rx_csum(struct net_device *netdev) |
---|
| 2086 | +{ |
---|
| 2087 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 2088 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 2089 | + |
---|
| 2090 | + return ax772b_data->checksum & AX_RX_CHECKSUM; |
---|
| 2091 | +} |
---|
| 2092 | + |
---|
| 2093 | +static int ax88772b_set_rx_csum(struct net_device *netdev, u32 val) |
---|
| 2094 | +{ |
---|
| 2095 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 2096 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 2097 | + |
---|
| 2098 | + if (val) |
---|
| 2099 | + ax772b_data->checksum |= AX_RX_CHECKSUM; |
---|
| 2100 | + else |
---|
| 2101 | + ax772b_data->checksum &= ~AX_RX_CHECKSUM; |
---|
| 2102 | + |
---|
| 2103 | + return ax88772b_set_csums(dev); |
---|
| 2104 | +} |
---|
| 2105 | + |
---|
| 2106 | +static int ax88772b_set_tx_csum(struct net_device *netdev, u32 val) |
---|
| 2107 | +{ |
---|
| 2108 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 2109 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 2110 | + |
---|
| 2111 | + if (val) |
---|
| 2112 | + ax772b_data->checksum |= AX_TX_CHECKSUM; |
---|
| 2113 | + else |
---|
| 2114 | + ax772b_data->checksum &= ~AX_TX_CHECKSUM; |
---|
| 2115 | + |
---|
| 2116 | + ethtool_op_set_tx_csum(netdev, val); |
---|
| 2117 | + |
---|
| 2118 | + return ax88772b_set_csums(dev); |
---|
| 2119 | +} |
---|
| 2120 | +#endif |
---|
| 2121 | +static struct ethtool_ops ax88772b_ethtool_ops = { |
---|
| 2122 | + .get_drvinfo = ax8817x_get_drvinfo, |
---|
| 2123 | + .get_link = ethtool_op_get_link, |
---|
| 2124 | + .get_msglevel = axusbnet_get_msglevel, |
---|
| 2125 | + .set_msglevel = axusbnet_set_msglevel, |
---|
| 2126 | + .get_wol = ax8817x_get_wol, |
---|
| 2127 | + .set_wol = ax8817x_set_wol, |
---|
| 2128 | + .get_eeprom_len = ax8817x_get_eeprom_len, |
---|
| 2129 | + .get_eeprom = ax8817x_get_eeprom, |
---|
| 2130 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) |
---|
| 2131 | + .get_settings = ax8817x_get_settings, |
---|
| 2132 | + .set_settings = ax8817x_set_settings, |
---|
| 2133 | +#else |
---|
| 2134 | + .get_link_ksettings = ax8817x_get_link_ksettings, |
---|
| 2135 | + .set_link_ksettings = ax8817x_set_link_ksettings, |
---|
| 2136 | +#endif |
---|
| 2137 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) |
---|
| 2138 | + .set_tx_csum = ax88772b_set_tx_csum, |
---|
| 2139 | + .get_tx_csum = ax88772b_get_tx_csum, |
---|
| 2140 | + .get_rx_csum = ax88772b_get_rx_csum, |
---|
| 2141 | + .set_rx_csum = ax88772b_set_rx_csum, |
---|
| 2142 | +#endif |
---|
| 2143 | +}; |
---|
| 2144 | + |
---|
| 2145 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29) |
---|
| 2146 | +static const struct net_device_ops ax88772b_netdev_ops = { |
---|
| 2147 | + .ndo_open = axusbnet_open, |
---|
| 2148 | + .ndo_stop = axusbnet_stop, |
---|
| 2149 | + .ndo_start_xmit = axusbnet_start_xmit, |
---|
| 2150 | + .ndo_tx_timeout = axusbnet_tx_timeout, |
---|
| 2151 | + .ndo_change_mtu = axusbnet_change_mtu, |
---|
| 2152 | + .ndo_do_ioctl = ax8817x_ioctl, |
---|
| 2153 | + .ndo_get_stats = axusbnet_get_stats, |
---|
| 2154 | + .ndo_set_mac_address = ax8817x_set_mac_addr, |
---|
| 2155 | + .ndo_validate_addr = eth_validate_addr, |
---|
| 2156 | +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 0) |
---|
| 2157 | + .ndo_set_multicast_list = ax88772b_set_multicast, |
---|
| 2158 | +#else |
---|
| 2159 | + .ndo_set_rx_mode = ax88772b_set_multicast, |
---|
| 2160 | +#endif |
---|
| 2161 | +}; |
---|
| 2162 | +#endif |
---|
| 2163 | + |
---|
| 2164 | +static int ax88772b_bind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 2165 | +{ |
---|
| 2166 | + int ret; |
---|
| 2167 | + void *buf; |
---|
| 2168 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 2169 | + struct ax88772b_data *ax772b_data; |
---|
| 2170 | + u16 *tmp16; |
---|
| 2171 | + u8 *tmp8; |
---|
| 2172 | + u8 tempphyselect; |
---|
| 2173 | + bool internalphy; |
---|
| 2174 | + |
---|
| 2175 | + printk(version); |
---|
| 2176 | + axusbnet_get_endpoints(dev, intf); |
---|
| 2177 | + buf = kmalloc(6, GFP_KERNEL); |
---|
| 2178 | + if (!buf) { |
---|
| 2179 | + deverr(dev, "Cannot allocate memory for buffer"); |
---|
| 2180 | + return -ENOMEM; |
---|
| 2181 | + } |
---|
| 2182 | + tmp16 = (u16 *)buf; |
---|
| 2183 | + ax772b_data = kmalloc(sizeof(*ax772b_data), GFP_KERNEL); |
---|
| 2184 | + if (!ax772b_data) { |
---|
| 2185 | + deverr(dev, "Cannot allocate memory for AX88772B data"); |
---|
| 2186 | + kfree(buf); |
---|
| 2187 | + return -ENOMEM; |
---|
| 2188 | + } |
---|
| 2189 | + memset(ax772b_data, 0, sizeof(*ax772b_data)); |
---|
| 2190 | + dev->priv = ax772b_data; |
---|
| 2191 | + ax772b_data->ax_work = create_singlethread_workqueue("ax88772b"); |
---|
| 2192 | + if (!ax772b_data->ax_work) { |
---|
| 2193 | + kfree(buf); |
---|
| 2194 | + kfree(ax772b_data); |
---|
| 2195 | + return -ENOMEM; |
---|
| 2196 | + } |
---|
| 2197 | + |
---|
| 2198 | + ax772b_data->dev = dev; |
---|
| 2199 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 2200 | + INIT_WORK(&ax772b_data->check_link, ax88772b_link_reset, dev); |
---|
| 2201 | +#else |
---|
| 2202 | + INIT_WORK(&ax772b_data->check_link, ax88772b_link_reset); |
---|
| 2203 | +#endif |
---|
| 2204 | + |
---|
| 2205 | + tmp8 = (u8 *)buf; |
---|
| 2206 | + ret = ax8817x_read_cmd(dev, AX_CMD_SW_PHY_STATUS, |
---|
| 2207 | + 0, 0, 1, tmp8); |
---|
| 2208 | + |
---|
| 2209 | + if (ret < 0) { |
---|
| 2210 | + deverr(dev, |
---|
| 2211 | + "read SW interface selection status register failed: %d\n", |
---|
| 2212 | + ret); |
---|
| 2213 | + goto err_out; |
---|
| 2214 | + } |
---|
| 2215 | + tempphyselect = *tmp8; |
---|
| 2216 | + tempphyselect &= 0x0C; |
---|
| 2217 | + |
---|
| 2218 | + if (tempphyselect == AX_PHYSEL_SSRMII) { |
---|
| 2219 | + internalphy = false; |
---|
| 2220 | + ax772b_data->OperationMode = OPERATION_MAC_MODE; |
---|
| 2221 | + ax772b_data->PhySelect = 0x00; |
---|
| 2222 | + } else if (tempphyselect == AX_PHYSEL_SSRRMII) { |
---|
| 2223 | + internalphy = true; |
---|
| 2224 | + ax772b_data->OperationMode = OPERATION_PHY_MODE; |
---|
| 2225 | + ax772b_data->PhySelect = 0x00; |
---|
| 2226 | + } else if (tempphyselect == AX_PHYSEL_SSMII) { |
---|
| 2227 | + internalphy = true; |
---|
| 2228 | + ax772b_data->OperationMode = OPERATION_MAC_MODE; |
---|
| 2229 | + ax772b_data->PhySelect = 0x01; |
---|
| 2230 | + } else { |
---|
| 2231 | + deverr(dev, "Unknown MII type\n"); |
---|
| 2232 | + goto err_out; |
---|
| 2233 | + } |
---|
| 2234 | + |
---|
| 2235 | + /* reload eeprom data */ |
---|
| 2236 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, AXGPIOS_RSE, |
---|
| 2237 | + 0, 0, NULL); |
---|
| 2238 | + if (ret < 0) { |
---|
| 2239 | + deverr(dev, "Failed to enable GPIO function: %d", ret); |
---|
| 2240 | + goto err_out; |
---|
| 2241 | + } |
---|
| 2242 | + msleep(5); |
---|
| 2243 | + |
---|
| 2244 | + /* Get the EEPROM data*/ |
---|
| 2245 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, 0x18, 0, 2, |
---|
| 2246 | + (void *)tmp16); |
---|
| 2247 | + if (ret < 0) { |
---|
| 2248 | + deverr(dev, "read SROM address 18h failed: %d", ret); |
---|
| 2249 | + goto err_out; |
---|
| 2250 | + } |
---|
| 2251 | + le16_to_cpus(tmp16); |
---|
| 2252 | + ax772b_data->psc = *tmp16 & 0xFF00; |
---|
| 2253 | + /* End of get EEPROM data */ |
---|
| 2254 | + |
---|
| 2255 | + /* Get the MAC address */ |
---|
| 2256 | + memset(buf, 0, ETH_ALEN); |
---|
| 2257 | + ret = ax8817x_get_mac(dev, buf); |
---|
| 2258 | + if (ret < 0) { |
---|
| 2259 | + deverr(dev, "Get HW address failed: %d", ret); |
---|
| 2260 | + goto err_out; |
---|
| 2261 | + } |
---|
| 2262 | + |
---|
| 2263 | + /* Initialize MII structure */ |
---|
| 2264 | + dev->mii.dev = dev->net; |
---|
| 2265 | + dev->mii.mdio_read = ax8817x_mdio_read_le; |
---|
| 2266 | + dev->mii.mdio_write = ax88772b_mdio_write_le; |
---|
| 2267 | + dev->mii.phy_id_mask = 0xff; |
---|
| 2268 | + dev->mii.reg_num_mask = 0xff; |
---|
| 2269 | + |
---|
| 2270 | + /* Get the PHY id */ |
---|
| 2271 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); |
---|
| 2272 | + if (ret < 0) { |
---|
| 2273 | + deverr(dev, "Error reading PHY ID: %02x", ret); |
---|
| 2274 | + goto err_out; |
---|
| 2275 | + } else if (ret < 2) { |
---|
| 2276 | + /* this should always return 2 bytes */ |
---|
| 2277 | + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", |
---|
| 2278 | + ret); |
---|
| 2279 | + ret = -EIO; |
---|
| 2280 | + goto err_out; |
---|
| 2281 | + } |
---|
| 2282 | + |
---|
| 2283 | + if (internalphy) |
---|
| 2284 | + dev->mii.phy_id = *((u8 *)buf + 1); |
---|
| 2285 | + else |
---|
| 2286 | + dev->mii.phy_id = *((u8 *)buf); |
---|
| 2287 | + |
---|
| 2288 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, |
---|
| 2289 | + ax772b_data->PhySelect, 0, 0, NULL); |
---|
| 2290 | + if (ret < 0) { |
---|
| 2291 | + deverr(dev, "Select PHY #1 failed: %d", ret); |
---|
| 2292 | + goto err_out; |
---|
| 2293 | + } |
---|
| 2294 | + |
---|
| 2295 | +#if 0 |
---|
| 2296 | + /* select the embedded 10/100 Ethernet PHY */ |
---|
| 2297 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, |
---|
| 2298 | + AX_PHYSEL_SSEN | AX_PHYSEL_PSEL | AX_PHYSEL_SSMII, |
---|
| 2299 | + 0, 0, NULL); |
---|
| 2300 | + if (ret < 0) { |
---|
| 2301 | + deverr(dev, "Select PHY #1 failed: %d", ret); |
---|
| 2302 | + goto err_out; |
---|
| 2303 | + } |
---|
| 2304 | + |
---|
| 2305 | + if (dev->mii.phy_id != 0x10) { |
---|
| 2306 | + deverr(dev, "Got wrong PHY ID: %02x", dev->mii.phy_id); |
---|
| 2307 | + ret = -EIO; |
---|
| 2308 | + goto err_out; |
---|
| 2309 | + } |
---|
| 2310 | +#endif |
---|
| 2311 | + ret = ax88772a_phy_powerup(dev); |
---|
| 2312 | + if (ret < 0) |
---|
| 2313 | + goto err_out; |
---|
| 2314 | + |
---|
| 2315 | + /* stop MAC operation */ |
---|
| 2316 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 2317 | + AX_RX_CTL_STOP, 0, 0, NULL); |
---|
| 2318 | + if (ret < 0) { |
---|
| 2319 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 2320 | + goto err_out; |
---|
| 2321 | + } |
---|
| 2322 | + |
---|
| 2323 | + /* make sure the driver can enable sw mii operation */ |
---|
| 2324 | + ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 2325 | + if (ret < 0) { |
---|
| 2326 | + deverr(dev, "Enabling software MII failed: %d", ret); |
---|
| 2327 | + goto err_out; |
---|
| 2328 | + } |
---|
| 2329 | + |
---|
| 2330 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 2331 | + dev->net->do_ioctl = ax8817x_ioctl; |
---|
| 2332 | + dev->net->set_multicast_list = ax88772b_set_multicast; |
---|
| 2333 | + dev->net->set_mac_address = ax8817x_set_mac_addr; |
---|
| 2334 | +#else |
---|
| 2335 | + dev->net->netdev_ops = &ax88772b_netdev_ops; |
---|
| 2336 | +#endif |
---|
| 2337 | + |
---|
| 2338 | + dev->net->ethtool_ops = &ax88772b_ethtool_ops; |
---|
| 2339 | + |
---|
| 2340 | + /* Register suspend and resume functions */ |
---|
| 2341 | + data->suspend = ax88772b_suspend; |
---|
| 2342 | + data->resume = ax88772b_resume; |
---|
| 2343 | + |
---|
| 2344 | + if ((ax772b_data->OperationMode == OPERATION_MAC_MODE) && |
---|
| 2345 | + (ax772b_data->PhySelect == 0x00)) { |
---|
| 2346 | + if (ax88772b_external_phyinit(dev) != 0x00) { |
---|
| 2347 | + deverr(dev, "Failed to initial the external phy"); |
---|
| 2348 | + goto err_out; |
---|
| 2349 | + } |
---|
| 2350 | + } |
---|
| 2351 | + |
---|
| 2352 | + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) |
---|
| 2353 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id |
---|
| 2354 | + , MII_BMCR, 0x3900); |
---|
| 2355 | + |
---|
| 2356 | + if (dev->mii.phy_id != 0x10) |
---|
| 2357 | + ax8817x_mdio_write_le(dev->net, 0x10, MII_BMCR, 0x3900); |
---|
| 2358 | + |
---|
| 2359 | + if (dev->mii.phy_id == 0x10 && ax772b_data->OperationMode |
---|
| 2360 | + != OPERATION_PHY_MODE) { |
---|
| 2361 | + |
---|
| 2362 | + *tmp16 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); |
---|
| 2363 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, 0x12, |
---|
| 2364 | + ((*tmp16 & 0xFF9F) | 0x0040)); |
---|
| 2365 | + } |
---|
| 2366 | + |
---|
| 2367 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 2368 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); |
---|
| 2369 | + |
---|
| 2370 | + mii_nway_restart(&dev->mii); |
---|
| 2371 | + |
---|
| 2372 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 2373 | + 0, 0, 0, NULL); |
---|
| 2374 | + if (ret < 0) { |
---|
| 2375 | + deverr(dev, "Failed to write medium mode: %d", ret); |
---|
| 2376 | + goto err_out; |
---|
| 2377 | + } |
---|
| 2378 | + |
---|
| 2379 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, |
---|
| 2380 | + AX88772A_IPG0_DEFAULT | AX88772A_IPG1_DEFAULT << 8, |
---|
| 2381 | + AX88772A_IPG2_DEFAULT, 0, NULL); |
---|
| 2382 | + if (ret < 0) { |
---|
| 2383 | + deverr(dev, "Failed to write interframe gap: %d", ret); |
---|
| 2384 | + goto err_out; |
---|
| 2385 | + } |
---|
| 2386 | + |
---|
| 2387 | + memset(buf, 0, 4); |
---|
| 2388 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_IPG012, 0, 0, 3, buf); |
---|
| 2389 | + *((u8 *)buf + 3) = 0x00; |
---|
| 2390 | + if (ret < 0) { |
---|
| 2391 | + deverr(dev, "Failed to read IPG,IPG1,IPG2 failed: %d", ret); |
---|
| 2392 | + goto err_out; |
---|
| 2393 | + } else { |
---|
| 2394 | + __u32 tmp32 = *((u32*)buf); |
---|
| 2395 | + le32_to_cpus(&tmp32); |
---|
| 2396 | + if (tmp32 != (AX88772A_IPG2_DEFAULT << 16 | |
---|
| 2397 | + AX88772A_IPG1_DEFAULT << 8 | AX88772A_IPG0_DEFAULT)) { |
---|
| 2398 | + printk("Non-authentic ASIX product\nASIX does not support it\n"); |
---|
| 2399 | + ret = -ENODEV; |
---|
| 2400 | + goto err_out; |
---|
| 2401 | + } |
---|
| 2402 | + } |
---|
| 2403 | + |
---|
| 2404 | + dev->net->features |= NETIF_F_IP_CSUM; |
---|
| 2405 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) |
---|
| 2406 | + dev->net->features |= NETIF_F_IPV6_CSUM; |
---|
| 2407 | +#endif |
---|
| 2408 | + |
---|
| 2409 | + ax772b_data->checksum = AX_RX_CHECKSUM | AX_TX_CHECKSUM; |
---|
| 2410 | + ret = ax88772b_set_csums(dev); |
---|
| 2411 | + if (ret < 0) { |
---|
| 2412 | + deverr(dev, "Write RX_COE/TX_COE failed: %d", ret); |
---|
| 2413 | + goto err_out; |
---|
| 2414 | + } |
---|
| 2415 | + |
---|
| 2416 | + dev->rx_size = bsize & 0x07; |
---|
| 2417 | + if (dev->udev->speed == USB_SPEED_HIGH) { |
---|
| 2418 | + |
---|
| 2419 | + ret = ax8817x_write_cmd(dev, 0x2A, |
---|
| 2420 | + AX88772B_BULKIN_SIZE[dev->rx_size].byte_cnt, |
---|
| 2421 | + AX88772B_BULKIN_SIZE[dev->rx_size].threshold, |
---|
| 2422 | + 0, NULL); |
---|
| 2423 | + if (ret < 0) { |
---|
| 2424 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 2425 | + goto err_out; |
---|
| 2426 | + } |
---|
| 2427 | + |
---|
| 2428 | + dev->rx_urb_size = AX88772B_BULKIN_SIZE[dev->rx_size].size; |
---|
| 2429 | + } else { |
---|
| 2430 | + ret = ax8817x_write_cmd(dev, 0x2A, |
---|
| 2431 | + 0x8000, 0x8001, 0, NULL); |
---|
| 2432 | + if (ret < 0) { |
---|
| 2433 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 2434 | + goto err_out; |
---|
| 2435 | + } |
---|
| 2436 | + dev->rx_urb_size = 2048; |
---|
| 2437 | + } |
---|
| 2438 | + |
---|
| 2439 | + /* Configure RX header type */ |
---|
| 2440 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 2441 | + (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_HEADER_DEFAULT), |
---|
| 2442 | + 0, 0, NULL); |
---|
| 2443 | + if (ret < 0) { |
---|
| 2444 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 2445 | + goto err_out; |
---|
| 2446 | + } |
---|
| 2447 | + |
---|
| 2448 | + /* Overwrite power saving configuration from eeprom */ |
---|
| 2449 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | |
---|
| 2450 | + (ax772b_data->psc & 0x7FFF), 0, 0, NULL); |
---|
| 2451 | + |
---|
| 2452 | + if (ret < 0) { |
---|
| 2453 | + deverr(dev, "Failed to configure PHY power saving: %d", ret); |
---|
| 2454 | + goto err_out; |
---|
| 2455 | + } |
---|
| 2456 | + |
---|
| 2457 | + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) |
---|
| 2458 | + netif_carrier_on(dev->net); |
---|
| 2459 | + |
---|
| 2460 | + kfree(buf); |
---|
| 2461 | + |
---|
| 2462 | + return ret; |
---|
| 2463 | +err_out: |
---|
| 2464 | + destroy_workqueue(ax772b_data->ax_work); |
---|
| 2465 | + kfree(buf); |
---|
| 2466 | + kfree(ax772b_data); |
---|
| 2467 | + return ret; |
---|
| 2468 | +} |
---|
| 2469 | + |
---|
| 2470 | +static int ax88772b_external_phyinit(struct usbnet *dev) { |
---|
| 2471 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 2472 | + u16 phyid1, phyid2; |
---|
| 2473 | + |
---|
| 2474 | + phyid1 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x02); |
---|
| 2475 | + phyid2 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x03); |
---|
| 2476 | + ax772b_data->ext_phy_oui = EXTPHY_ID_MASK_OUI(phyid1, phyid2); |
---|
| 2477 | + ax772b_data->ext_phy_model = EXTPHY_ID_MASK_MODEL(phyid2); |
---|
| 2478 | + |
---|
| 2479 | + if (ax772b_data->ext_phy_oui == EXTPHY_BROADCOM_OUI) { |
---|
| 2480 | + if(ax772b_data->ext_phy_model == EXTPHY_BCM89811_MODEL) { |
---|
| 2481 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x0, 0x8000); |
---|
| 2482 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2483 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2484 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2485 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2486 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2487 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2488 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1F, 0x0c00); |
---|
| 2489 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1E, 0x030A); |
---|
| 2490 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1F, 0x3440); |
---|
| 2491 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1E, 0x0166); |
---|
| 2492 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1F, 0x0020); |
---|
| 2493 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x012D); |
---|
| 2494 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x9B52); |
---|
| 2495 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x012E); |
---|
| 2496 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0xA04D); |
---|
| 2497 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0123); |
---|
| 2498 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x00c0); |
---|
| 2499 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0154); |
---|
| 2500 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x81C4); |
---|
| 2501 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0811); |
---|
| 2502 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x0000); |
---|
| 2503 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x01D3); |
---|
| 2504 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x0064); |
---|
| 2505 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x01C1); |
---|
| 2506 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0xA5F7); |
---|
| 2507 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2508 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x0400); |
---|
| 2509 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x001D); |
---|
| 2510 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x3411); |
---|
| 2511 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0820); |
---|
| 2512 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x0401); |
---|
| 2513 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x002F); |
---|
| 2514 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0xF167); |
---|
| 2515 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0045); |
---|
| 2516 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x0500); |
---|
| 2517 | + return 0; |
---|
| 2518 | + } |
---|
| 2519 | + } |
---|
| 2520 | + |
---|
| 2521 | + return 0; |
---|
| 2522 | +} |
---|
| 2523 | + |
---|
| 2524 | +static void ax88772b_unbind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 2525 | +{ |
---|
| 2526 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 2527 | + |
---|
| 2528 | + if (ax772b_data) { |
---|
| 2529 | + |
---|
| 2530 | + flush_workqueue(ax772b_data->ax_work); |
---|
| 2531 | + destroy_workqueue(ax772b_data->ax_work); |
---|
| 2532 | + |
---|
| 2533 | + /* stop MAC operation */ |
---|
| 2534 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 2535 | + AX_RX_CTL_STOP, 0, 0, NULL); |
---|
| 2536 | + |
---|
| 2537 | + /* Power down PHY */ |
---|
| 2538 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 2539 | + AX_SWRESET_IPPD, 0, 0, NULL); |
---|
| 2540 | + |
---|
| 2541 | + kfree(ax772b_data); |
---|
| 2542 | + } |
---|
| 2543 | +} |
---|
| 2544 | + |
---|
| 2545 | +static int |
---|
| 2546 | +ax88178_media_check(struct usbnet *dev, struct ax88178_data *ax178dataptr) |
---|
| 2547 | +{ |
---|
| 2548 | + int fullduplex, i = 0; |
---|
| 2549 | + u16 tempshort = 0; |
---|
| 2550 | + u16 media; |
---|
| 2551 | + u16 advertise, lpa, result, stat1000, _lpa, _stat1000, delay = 5 * HZ; |
---|
| 2552 | + unsigned long jtimeout; |
---|
| 2553 | + |
---|
| 2554 | + jtimeout = jiffies + delay; |
---|
| 2555 | + do { |
---|
| 2556 | + _lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); |
---|
| 2557 | + _stat1000 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 2558 | + MII_STAT1000); |
---|
| 2559 | + |
---|
| 2560 | + lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); |
---|
| 2561 | + stat1000 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 2562 | + MII_STAT1000); |
---|
| 2563 | + |
---|
| 2564 | + if (time_after(jiffies, jtimeout)) |
---|
| 2565 | + break; |
---|
| 2566 | + |
---|
| 2567 | + } while ((_lpa != lpa) || (_stat1000 != stat1000) || i++ < 3); |
---|
| 2568 | + |
---|
| 2569 | + advertise = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 2570 | + MII_ADVERTISE); |
---|
| 2571 | + result = advertise & lpa; |
---|
| 2572 | + |
---|
| 2573 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2574 | + (ax178dataptr->LedMode == 1)) { |
---|
| 2575 | + tempshort = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 2576 | + MARVELL_MANUAL_LED) & 0xfc0f; |
---|
| 2577 | + } |
---|
| 2578 | + |
---|
| 2579 | + fullduplex = 1; |
---|
| 2580 | + if (stat1000 & LPA_1000FULL) { |
---|
| 2581 | + media = MEDIUM_GIGA_MODE | MEDIUM_FULL_DUPLEX_MODE | |
---|
| 2582 | + MEDIUM_ENABLE_125MHZ | MEDIUM_ENABLE_RECEIVE; |
---|
| 2583 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2584 | + (ax178dataptr->LedMode == 1)) |
---|
| 2585 | + tempshort |= 0x3e0; |
---|
| 2586 | + } else if (result & LPA_100FULL) { |
---|
| 2587 | + media = MEDIUM_FULL_DUPLEX_MODE | MEDIUM_ENABLE_RECEIVE | |
---|
| 2588 | + MEDIUM_MII_100M_MODE; |
---|
| 2589 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2590 | + (ax178dataptr->LedMode == 1)) |
---|
| 2591 | + tempshort |= 0x3b0; |
---|
| 2592 | + } else if (result & LPA_100HALF) { |
---|
| 2593 | + fullduplex = 0; |
---|
| 2594 | + media = MEDIUM_ENABLE_RECEIVE | MEDIUM_MII_100M_MODE; |
---|
| 2595 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2596 | + (ax178dataptr->LedMode == 1)) |
---|
| 2597 | + tempshort |= 0x3b0; |
---|
| 2598 | + } else if (result & LPA_10FULL) { |
---|
| 2599 | + media = MEDIUM_FULL_DUPLEX_MODE | MEDIUM_ENABLE_RECEIVE; |
---|
| 2600 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2601 | + (ax178dataptr->LedMode == 1)) |
---|
| 2602 | + tempshort |= 0x2f0; |
---|
| 2603 | + } else { |
---|
| 2604 | + media = MEDIUM_ENABLE_RECEIVE; |
---|
| 2605 | + fullduplex = 0; |
---|
| 2606 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2607 | + (ax178dataptr->LedMode == 1)) |
---|
| 2608 | + tempshort |= 0x02f0; |
---|
| 2609 | + } |
---|
| 2610 | + |
---|
| 2611 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2612 | + (ax178dataptr->LedMode == 1)) { |
---|
| 2613 | + ax8817x_mdio_write_le(dev->net, |
---|
| 2614 | + dev->mii.phy_id, MARVELL_MANUAL_LED, tempshort); |
---|
| 2615 | + } |
---|
| 2616 | + |
---|
| 2617 | + media |= 0x0004; |
---|
| 2618 | + if (ax178dataptr->UseRgmii) |
---|
| 2619 | + media |= 0x0008; |
---|
| 2620 | + if (fullduplex) { |
---|
| 2621 | + media |= 0x0020; /* ebable tx flow control as default; */ |
---|
| 2622 | + media |= 0x0010; /* ebable rx flow control as default; */ |
---|
| 2623 | + } |
---|
| 2624 | + |
---|
| 2625 | + return media; |
---|
| 2626 | +} |
---|
| 2627 | + |
---|
| 2628 | +static void Vitess_8601_Init(struct usbnet *dev, int state) |
---|
| 2629 | +{ |
---|
| 2630 | + u16 reg; |
---|
| 2631 | + |
---|
| 2632 | + switch (state) { |
---|
| 2633 | + case 0: /* tx, rx clock skew */ |
---|
| 2634 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, 31, 1); |
---|
| 2635 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, 28, 0); |
---|
| 2636 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, 31, 0); |
---|
| 2637 | + break; |
---|
| 2638 | + |
---|
| 2639 | + case 1: |
---|
| 2640 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2641 | + dev->mii.phy_id, 31, 0x52B5); |
---|
| 2642 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2643 | + dev->mii.phy_id, 18, 0x009E); |
---|
| 2644 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2645 | + dev->mii.phy_id, 17, 0xDD39); |
---|
| 2646 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2647 | + dev->mii.phy_id, 16, 0x87AA); |
---|
| 2648 | + |
---|
| 2649 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2650 | + dev->mii.phy_id, 16, 0xA7B4); |
---|
| 2651 | + |
---|
| 2652 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2653 | + dev->mii.phy_id, 18, |
---|
| 2654 | + ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2655 | + dev->mii.phy_id, 18)); |
---|
| 2656 | + |
---|
| 2657 | + reg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2658 | + dev->mii.phy_id, 17) & ~0x003f) | 0x003c; |
---|
| 2659 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2660 | + dev->mii.phy_id, 17, reg); |
---|
| 2661 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2662 | + dev->mii.phy_id, 16, 0x87B4); |
---|
| 2663 | + |
---|
| 2664 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2665 | + dev->mii.phy_id, 16, 0xa794); |
---|
| 2666 | + |
---|
| 2667 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2668 | + dev->mii.phy_id, 18, |
---|
| 2669 | + ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2670 | + dev->mii.phy_id, 18)); |
---|
| 2671 | + |
---|
| 2672 | + reg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2673 | + dev->mii.phy_id, 17) & ~0x003f) | 0x003e; |
---|
| 2674 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2675 | + dev->mii.phy_id, 17, reg); |
---|
| 2676 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2677 | + dev->mii.phy_id, 16, 0x8794); |
---|
| 2678 | + |
---|
| 2679 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2680 | + dev->mii.phy_id, 18, 0x00f7); |
---|
| 2681 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2682 | + dev->mii.phy_id, 17, 0xbe36); |
---|
| 2683 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2684 | + dev->mii.phy_id, 16, 0x879e); |
---|
| 2685 | + |
---|
| 2686 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2687 | + dev->mii.phy_id, 16, 0xa7a0); |
---|
| 2688 | + |
---|
| 2689 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2690 | + dev->mii.phy_id, 18, |
---|
| 2691 | + ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2692 | + dev->mii.phy_id, 18)); |
---|
| 2693 | + |
---|
| 2694 | + reg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2695 | + dev->mii.phy_id, 17) & ~0x003f) | 0x0034; |
---|
| 2696 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2697 | + dev->mii.phy_id, 17, reg); |
---|
| 2698 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2699 | + dev->mii.phy_id, 16, 0x87a0); |
---|
| 2700 | + |
---|
| 2701 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2702 | + dev->mii.phy_id, 18, 0x003c); |
---|
| 2703 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2704 | + dev->mii.phy_id, 17, 0xf3cf); |
---|
| 2705 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2706 | + dev->mii.phy_id, 16, 0x87a2); |
---|
| 2707 | + |
---|
| 2708 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2709 | + dev->mii.phy_id, 18, 0x003c); |
---|
| 2710 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2711 | + dev->mii.phy_id, 17, 0xf3cf); |
---|
| 2712 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2713 | + dev->mii.phy_id, 16, 0x87a4); |
---|
| 2714 | + |
---|
| 2715 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2716 | + dev->mii.phy_id, 18, 0x003c); |
---|
| 2717 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2718 | + dev->mii.phy_id, 17, 0xd287); |
---|
| 2719 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2720 | + dev->mii.phy_id, 16, 0x87a6); |
---|
| 2721 | + |
---|
| 2722 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2723 | + dev->mii.phy_id, 16, 0xa7a8); |
---|
| 2724 | + |
---|
| 2725 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2726 | + dev->mii.phy_id, 18, |
---|
| 2727 | + ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2728 | + dev->mii.phy_id, 18)); |
---|
| 2729 | + |
---|
| 2730 | + reg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2731 | + dev->mii.phy_id, 17) & ~0x0fff) | 0x0125; |
---|
| 2732 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2733 | + dev->mii.phy_id, 17, reg); |
---|
| 2734 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2735 | + dev->mii.phy_id, 16, 0x87a8); |
---|
| 2736 | + |
---|
| 2737 | + /* Enable Smart Pre-emphasis */ |
---|
| 2738 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2739 | + dev->mii.phy_id, 16, 0xa7fa); |
---|
| 2740 | + |
---|
| 2741 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2742 | + dev->mii.phy_id, 18, |
---|
| 2743 | + ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2744 | + dev->mii.phy_id, 18)); |
---|
| 2745 | + |
---|
| 2746 | + reg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2747 | + dev->mii.phy_id, 17) & ~0x0008) | 0x0008; |
---|
| 2748 | + |
---|
| 2749 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2750 | + dev->mii.phy_id, 17, reg); |
---|
| 2751 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2752 | + dev->mii.phy_id, 16, 0x87fa); |
---|
| 2753 | + |
---|
| 2754 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2755 | + dev->mii.phy_id, 31, 0); |
---|
| 2756 | + |
---|
| 2757 | + break; |
---|
| 2758 | + } |
---|
| 2759 | +} |
---|
| 2760 | + |
---|
| 2761 | +static void |
---|
| 2762 | +marvell_88E1510_magic_init(struct usbnet *dev) |
---|
| 2763 | +{ |
---|
| 2764 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2765 | + dev->mii.phy_id, 22, 0xff); |
---|
| 2766 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2767 | + dev->mii.phy_id, 17, 0x214b); |
---|
| 2768 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2769 | + dev->mii.phy_id, 16, 0x2144); |
---|
| 2770 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2771 | + dev->mii.phy_id, 17, 0x0c28); |
---|
| 2772 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2773 | + dev->mii.phy_id, 16, 0x2146); |
---|
| 2774 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2775 | + dev->mii.phy_id, 17, 0xb233); |
---|
| 2776 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2777 | + dev->mii.phy_id, 16, 0x214d); |
---|
| 2778 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2779 | + dev->mii.phy_id, 17, 0xcc0c); |
---|
| 2780 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2781 | + dev->mii.phy_id, 16, 0x2159); |
---|
| 2782 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2783 | + dev->mii.phy_id, 22, 0x00fb); |
---|
| 2784 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2785 | + dev->mii.phy_id, 7, 0xc00d); |
---|
| 2786 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2787 | + dev->mii.phy_id, 22, 0); |
---|
| 2788 | +} |
---|
| 2789 | + |
---|
| 2790 | +static int |
---|
| 2791 | +ax88178_phy_init(struct usbnet *dev, struct ax88178_data *ax178dataptr) |
---|
| 2792 | +{ |
---|
| 2793 | + int i; |
---|
| 2794 | + u16 phyanar, phyauxctrl, phyctrl, tempshort, phyid1; |
---|
| 2795 | + u16 phyreg = 0; |
---|
| 2796 | + |
---|
| 2797 | + /* Disable MII operation of AX88178 Hardware */ |
---|
| 2798 | + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); |
---|
| 2799 | + |
---|
| 2800 | + |
---|
| 2801 | + /* Read SROM - MiiPhy Address (ID) */ |
---|
| 2802 | + ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, &dev->mii.phy_id); |
---|
| 2803 | + le32_to_cpus(&dev->mii.phy_id); |
---|
| 2804 | + |
---|
| 2805 | + /* Initialize MII structure */ |
---|
| 2806 | + dev->mii.phy_id >>= 8; |
---|
| 2807 | + dev->mii.phy_id &= PHY_ID_MASK; |
---|
| 2808 | + dev->mii.dev = dev->net; |
---|
| 2809 | + dev->mii.mdio_read = ax8817x_mdio_read_le; |
---|
| 2810 | + dev->mii.mdio_write = ax8817x_mdio_write_le; |
---|
| 2811 | + dev->mii.phy_id_mask = 0x3f; |
---|
| 2812 | + dev->mii.reg_num_mask = 0x1f; |
---|
| 2813 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 11) |
---|
| 2814 | + dev->mii.supports_gmii = 1; |
---|
| 2815 | +#endif |
---|
| 2816 | + |
---|
| 2817 | + if (ax178dataptr->PhyMode == PHY_MODE_MAC_TO_MAC_GMII) { |
---|
| 2818 | + ax178dataptr->UseRgmii = 0; |
---|
| 2819 | + ax178dataptr->MediaLink = MEDIUM_GIGA_MODE | |
---|
| 2820 | + MEDIUM_FULL_DUPLEX_MODE | |
---|
| 2821 | + MEDIUM_ENABLE_125MHZ | |
---|
| 2822 | + MEDIUM_ENABLE_RECEIVE | |
---|
| 2823 | + MEDIUM_ENABLE_RX_FLOWCTRL | |
---|
| 2824 | + MEDIUM_ENABLE_TX_FLOWCTRL; |
---|
| 2825 | + goto SKIPPHYSETTING; |
---|
| 2826 | + } |
---|
| 2827 | + |
---|
| 2828 | + /* test read phy register 2 */ |
---|
| 2829 | + if (!ax178dataptr->UseGpio0) { |
---|
| 2830 | + i = 1000; |
---|
| 2831 | + while (i--) { |
---|
| 2832 | + phyid1 = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2833 | + dev->mii.phy_id, GMII_PHY_OUI); |
---|
| 2834 | + if ((phyid1 == 0x000f) || (phyid1 == 0x0141) || |
---|
| 2835 | + (phyid1 == 0x0282) || (phyid1 == 0x004d) || |
---|
| 2836 | + (phyid1 == 0x0243) || (phyid1 == 0x001C) || |
---|
| 2837 | + (phyid1 == 0x0007)) |
---|
| 2838 | + break; |
---|
| 2839 | + msleep(5); |
---|
| 2840 | + } |
---|
| 2841 | + if (i < 0) |
---|
| 2842 | + return -EIO; |
---|
| 2843 | + } |
---|
| 2844 | + |
---|
| 2845 | + ax178dataptr->UseRgmii = 0; |
---|
| 2846 | + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { |
---|
| 2847 | + phyreg = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2848 | + dev->mii.phy_id, 27); |
---|
| 2849 | + if (!(phyreg & 4) && !(ax178dataptr->LedMode & 0x10)) { |
---|
| 2850 | + ax178dataptr->UseRgmii = 1; |
---|
| 2851 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2852 | + dev->mii.phy_id, 20, 0x82); |
---|
| 2853 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2854 | + } else if (ax178dataptr->LedMode & 0x10) { |
---|
| 2855 | + |
---|
| 2856 | + ax178dataptr->UseRgmii = 1; |
---|
| 2857 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2858 | + marvell_88E1510_magic_init(dev); |
---|
| 2859 | + |
---|
| 2860 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2861 | + dev->mii.phy_id, 22, 2); |
---|
| 2862 | + |
---|
| 2863 | + phyreg = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2864 | + dev->mii.phy_id, 21); |
---|
| 2865 | + |
---|
| 2866 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2867 | + dev->mii.phy_id, 21, phyreg | 0x30); |
---|
| 2868 | + |
---|
| 2869 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2870 | + dev->mii.phy_id, 22, 0); |
---|
| 2871 | + } |
---|
| 2872 | + } else if ((ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) || |
---|
| 2873 | + (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0_GMII)) { |
---|
| 2874 | + if (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) { |
---|
| 2875 | + ax178dataptr->UseRgmii = 1; |
---|
| 2876 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2877 | + } |
---|
| 2878 | + } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V1) { |
---|
| 2879 | + /* not Cameo */ |
---|
| 2880 | + if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode) { |
---|
| 2881 | + ax178dataptr->UseRgmii = 1; |
---|
| 2882 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2883 | + } |
---|
| 2884 | + |
---|
| 2885 | + for (i = 0; i < (sizeof(CICADA_FAMILY_HWINIT) / |
---|
| 2886 | + sizeof(CICADA_FAMILY_HWINIT[0])); i++) { |
---|
| 2887 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2888 | + dev->mii.phy_id, |
---|
| 2889 | + CICADA_FAMILY_HWINIT[i].offset, |
---|
| 2890 | + CICADA_FAMILY_HWINIT[i].value); |
---|
| 2891 | + } |
---|
| 2892 | + |
---|
| 2893 | + } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2) { |
---|
| 2894 | + /* not Cameo */ |
---|
| 2895 | + if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode) { |
---|
| 2896 | + ax178dataptr->UseRgmii = 1; |
---|
| 2897 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2898 | + } |
---|
| 2899 | + |
---|
| 2900 | + for (i = 0; i < (sizeof(CICADA_V2_HWINIT) / |
---|
| 2901 | + sizeof(CICADA_V2_HWINIT[0])); i++) { |
---|
| 2902 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2903 | + dev->mii.phy_id, CICADA_V2_HWINIT[i].offset, |
---|
| 2904 | + CICADA_V2_HWINIT[i].value); |
---|
| 2905 | + } |
---|
| 2906 | + } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2_ASIX) { |
---|
| 2907 | + /* not Cameo */ |
---|
| 2908 | + if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode) { |
---|
| 2909 | + ax178dataptr->UseRgmii = 1; |
---|
| 2910 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2911 | + } |
---|
| 2912 | + |
---|
| 2913 | + for (i = 0; i < (sizeof(CICADA_V2_HWINIT) / |
---|
| 2914 | + sizeof(CICADA_V2_HWINIT[0])); i++) { |
---|
| 2915 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2916 | + dev->mii.phy_id, CICADA_V2_HWINIT[i].offset, |
---|
| 2917 | + CICADA_V2_HWINIT[i].value); |
---|
| 2918 | + } |
---|
| 2919 | + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211CL) { |
---|
| 2920 | + ax178dataptr->UseRgmii = 1; |
---|
| 2921 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2922 | + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211BN) { |
---|
| 2923 | + ax178dataptr->UseRgmii = 1; |
---|
| 2924 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2925 | + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8251CL) { |
---|
| 2926 | + ax178dataptr->UseRgmii = 1; |
---|
| 2927 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2928 | + } else if (ax178dataptr->PhyMode == PHY_MODE_VSC8601) { |
---|
| 2929 | + ax178dataptr->UseRgmii = 1; |
---|
| 2930 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2931 | + /* Vitess_8601_Init (dev, 0); */ |
---|
| 2932 | + } |
---|
| 2933 | + |
---|
| 2934 | + if (ax178dataptr->PhyMode != PHY_MODE_ATTANSIC_V0) { |
---|
| 2935 | + /* software reset */ |
---|
| 2936 | + ax8817x_swmii_mdio_write_le( |
---|
| 2937 | + dev->net, dev->mii.phy_id, GMII_PHY_CONTROL, |
---|
| 2938 | + ax8817x_swmii_mdio_read_le( |
---|
| 2939 | + dev->net, dev->mii.phy_id, GMII_PHY_CONTROL) |
---|
| 2940 | + | GMII_CONTROL_RESET); |
---|
| 2941 | + msleep(1); |
---|
| 2942 | + } |
---|
| 2943 | + |
---|
| 2944 | + if ((ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) || |
---|
| 2945 | + (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0_GMII)) { |
---|
| 2946 | + if (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) { |
---|
| 2947 | + i = 1000; |
---|
| 2948 | + while (i--) { |
---|
| 2949 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2950 | + dev->mii.phy_id, 21, 0x1001); |
---|
| 2951 | + |
---|
| 2952 | + phyreg = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2953 | + dev->mii.phy_id, 21); |
---|
| 2954 | + if ((phyreg & 0xf00f) == 0x1001) |
---|
| 2955 | + break; |
---|
| 2956 | + } |
---|
| 2957 | + if (i < 0) |
---|
| 2958 | + return -EIO; |
---|
| 2959 | + } |
---|
| 2960 | + |
---|
| 2961 | + if (ax178dataptr->LedMode == 4) { |
---|
| 2962 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2963 | + dev->mii.phy_id, 28, 0x7417); |
---|
| 2964 | + } else if (ax178dataptr->LedMode == 9) { |
---|
| 2965 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2966 | + dev->mii.phy_id, 28, 0x7a10); |
---|
| 2967 | + } else if (ax178dataptr->LedMode == 10) { |
---|
| 2968 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2969 | + dev->mii.phy_id, 28, 0x7a13); |
---|
| 2970 | + } |
---|
| 2971 | + |
---|
| 2972 | + for (i = 0; i < (sizeof(AGERE_FAMILY_HWINIT) / |
---|
| 2973 | + sizeof(AGERE_FAMILY_HWINIT[0])); i++) { |
---|
| 2974 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2975 | + dev->mii.phy_id, AGERE_FAMILY_HWINIT[i].offset, |
---|
| 2976 | + AGERE_FAMILY_HWINIT[i].value); |
---|
| 2977 | + } |
---|
| 2978 | + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211CL) { |
---|
| 2979 | + |
---|
| 2980 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2981 | + dev->mii.phy_id, 0x1f, 0x0005); |
---|
| 2982 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2983 | + dev->mii.phy_id, 0x0c, 0); |
---|
| 2984 | + |
---|
| 2985 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, 0x01, |
---|
| 2986 | + (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2987 | + dev->mii.phy_id, 0x01) | 0x0080)); |
---|
| 2988 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2989 | + dev->mii.phy_id, 0x1f, 0); |
---|
| 2990 | + |
---|
| 2991 | + if (ax178dataptr->LedMode == 12) { |
---|
| 2992 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2993 | + dev->mii.phy_id, 0x1f, 0x0002); |
---|
| 2994 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2995 | + dev->mii.phy_id, 0x1a, 0x00cb); |
---|
| 2996 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2997 | + dev->mii.phy_id, 0x1f, 0); |
---|
| 2998 | + } |
---|
| 2999 | + } else if (ax178dataptr->PhyMode == PHY_MODE_VSC8601) { |
---|
| 3000 | + Vitess_8601_Init(dev, 1); |
---|
| 3001 | + } |
---|
| 3002 | + |
---|
| 3003 | + /* read phy register 0 */ |
---|
| 3004 | + phyctrl = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 3005 | + dev->mii.phy_id, GMII_PHY_CONTROL); |
---|
| 3006 | + tempshort = phyctrl; |
---|
| 3007 | + phyctrl &= ~(GMII_CONTROL_POWER_DOWN | GMII_CONTROL_ISOLATE); |
---|
| 3008 | + if (phyctrl != tempshort) { |
---|
| 3009 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3010 | + dev->mii.phy_id, GMII_PHY_CONTROL, phyctrl); |
---|
| 3011 | + } |
---|
| 3012 | + |
---|
| 3013 | + /* LED */ |
---|
| 3014 | + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { |
---|
| 3015 | + if (ax178dataptr->LedMode == 1) { |
---|
| 3016 | + |
---|
| 3017 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 3018 | + dev->mii.phy_id, 24) & 0xf8ff) | (1 + 0x100); |
---|
| 3019 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3020 | + dev->mii.phy_id, 24, phyreg); |
---|
| 3021 | + phyreg = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 3022 | + dev->mii.phy_id, 25) & 0xfc0f; |
---|
| 3023 | + } else if (ax178dataptr->LedMode == 2) { |
---|
| 3024 | + |
---|
| 3025 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 3026 | + dev->mii.phy_id, 24) & 0xf886) | |
---|
| 3027 | + (1 + 0x10 + 0x300); |
---|
| 3028 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3029 | + dev->mii.phy_id, 24, phyreg); |
---|
| 3030 | + } else if (ax178dataptr->LedMode == 5) { |
---|
| 3031 | + |
---|
| 3032 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 3033 | + dev->mii.phy_id, 24) & 0xf8be) | |
---|
| 3034 | + (1 + 0x40 + 0x300); |
---|
| 3035 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3036 | + dev->mii.phy_id, 24, phyreg); |
---|
| 3037 | + } else if (ax178dataptr->LedMode == 7) { |
---|
| 3038 | + |
---|
| 3039 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 3040 | + dev->mii.phy_id, 24) & 0xf8ff) | |
---|
| 3041 | + (1 + 0x100); |
---|
| 3042 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3043 | + dev->mii.phy_id, 24, phyreg); |
---|
| 3044 | + |
---|
| 3045 | + } else if (ax178dataptr->LedMode == 8) { |
---|
| 3046 | + |
---|
| 3047 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 3048 | + dev->mii.phy_id, 24) & 0xf8be) | |
---|
| 3049 | + (1 + 0x40 + 0x100); |
---|
| 3050 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3051 | + dev->mii.phy_id, 24, phyreg); |
---|
| 3052 | + |
---|
| 3053 | + } else if (ax178dataptr->LedMode == 11) { |
---|
| 3054 | + |
---|
| 3055 | + phyreg = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 3056 | + dev->mii.phy_id, 24) & 0x4106; |
---|
| 3057 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3058 | + dev->mii.phy_id, 24, phyreg); |
---|
| 3059 | + } else if (ax178dataptr->LedMode == 0x10) { |
---|
| 3060 | + /* MARVEL 88e1510 use default led setting */ |
---|
| 3061 | + } |
---|
| 3062 | + |
---|
| 3063 | + } else if ((ax178dataptr->PhyMode == PHY_MODE_CICADA_V1) || |
---|
| 3064 | + (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2) || |
---|
| 3065 | + (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2_ASIX)) { |
---|
| 3066 | + |
---|
| 3067 | + if (ax178dataptr->LedMode == 3) { |
---|
| 3068 | + |
---|
| 3069 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 3070 | + dev->mii.phy_id, 27) & 0xFCFF) | 0x0100; |
---|
| 3071 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3072 | + dev->mii.phy_id, 27, phyreg); |
---|
| 3073 | + } |
---|
| 3074 | + |
---|
| 3075 | + } |
---|
| 3076 | + |
---|
| 3077 | + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { |
---|
| 3078 | + if (ax178dataptr->LedMode == 1) |
---|
| 3079 | + phyreg |= 0x3f0; |
---|
| 3080 | + } |
---|
| 3081 | + |
---|
| 3082 | + phyanar = 1 | (GMII_ANAR_PAUSE | GMII_ANAR_100TXFD | GMII_ANAR_100TX | |
---|
| 3083 | + GMII_ANAR_10TFD | GMII_ANAR_10T | GMII_ANAR_ASYM_PAUSE); |
---|
| 3084 | + |
---|
| 3085 | + phyauxctrl = GMII_1000_AUX_CTRL_FD_CAPABLE; |
---|
| 3086 | + |
---|
| 3087 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3088 | + dev->mii.phy_id, GMII_PHY_ANAR, phyanar); |
---|
| 3089 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3090 | + dev->mii.phy_id, GMII_PHY_1000BT_CONTROL, phyauxctrl); |
---|
| 3091 | + |
---|
| 3092 | + if (ax178dataptr->PhyMode == PHY_MODE_VSC8601) { |
---|
| 3093 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 3094 | + 31, 0x52B5); |
---|
| 3095 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 3096 | + 16, 0xA7F8); |
---|
| 3097 | + |
---|
| 3098 | + tempshort = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 3099 | + dev->mii.phy_id, 17) & (~0x0018); |
---|
| 3100 | + |
---|
| 3101 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 3102 | + 17, tempshort); |
---|
| 3103 | + |
---|
| 3104 | + tempshort = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 3105 | + dev->mii.phy_id, 18); |
---|
| 3106 | + |
---|
| 3107 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, 18, |
---|
| 3108 | + tempshort); |
---|
| 3109 | + |
---|
| 3110 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 3111 | + 16, 0x87F8); |
---|
| 3112 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 3113 | + 31, 0); |
---|
| 3114 | + } |
---|
| 3115 | + |
---|
| 3116 | + if (ax178dataptr->PhyMode == PHY_MODE_ATTANSIC_V0) { |
---|
| 3117 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3118 | + dev->mii.phy_id, GMII_PHY_CONTROL, 0x9000); |
---|
| 3119 | + |
---|
| 3120 | + } else { |
---|
| 3121 | + phyctrl &= ~GMII_CONTROL_LOOPBACK; |
---|
| 3122 | + phyctrl |= (GMII_CONTROL_ENABLE_AUTO | GMII_CONTROL_START_AUTO); |
---|
| 3123 | + |
---|
| 3124 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3125 | + dev->mii.phy_id, GMII_PHY_CONTROL, phyctrl); |
---|
| 3126 | + } |
---|
| 3127 | + |
---|
| 3128 | + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { |
---|
| 3129 | + if (ax178dataptr->LedMode == 1) |
---|
| 3130 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 3131 | + dev->mii.phy_id, 25, phyreg); |
---|
| 3132 | + } |
---|
| 3133 | + |
---|
| 3134 | +SKIPPHYSETTING: |
---|
| 3135 | + |
---|
| 3136 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 3137 | + ax178dataptr->MediaLink, 0, 0, NULL); |
---|
| 3138 | + |
---|
| 3139 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, |
---|
| 3140 | + AX88772_IPG0_DEFAULT | (AX88772_IPG1_DEFAULT << 8), |
---|
| 3141 | + AX88772_IPG2_DEFAULT, 0, NULL); |
---|
| 3142 | + |
---|
| 3143 | + msleep(1); |
---|
| 3144 | + |
---|
| 3145 | + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); |
---|
| 3146 | + |
---|
| 3147 | + return 0; |
---|
| 3148 | +} |
---|
| 3149 | + |
---|
| 3150 | +static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 3151 | +{ |
---|
| 3152 | + int ret; |
---|
| 3153 | + void *buf; |
---|
| 3154 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 3155 | + struct ax88178_data *ax178dataptr = NULL; |
---|
| 3156 | + |
---|
| 3157 | + axusbnet_get_endpoints(dev, intf); |
---|
| 3158 | + |
---|
| 3159 | + buf = kmalloc(6, GFP_KERNEL); |
---|
| 3160 | + if (!buf) { |
---|
| 3161 | + deverr(dev, "Cannot allocate memory for buffer"); |
---|
| 3162 | + return -ENOMEM; |
---|
| 3163 | + } |
---|
| 3164 | + |
---|
| 3165 | + /* allocate 178 data */ |
---|
| 3166 | + ax178dataptr = kmalloc(sizeof(*ax178dataptr), GFP_KERNEL); |
---|
| 3167 | + if (!ax178dataptr) { |
---|
| 3168 | + deverr(dev, "Cannot allocate memory for AX88178 data"); |
---|
| 3169 | + ret = -ENOMEM; |
---|
| 3170 | + goto error_out; |
---|
| 3171 | + } |
---|
| 3172 | + memset(ax178dataptr, 0, sizeof(struct ax88178_data)); |
---|
| 3173 | + dev->priv = ax178dataptr; |
---|
| 3174 | + /* end of allocate 178 data */ |
---|
| 3175 | + |
---|
| 3176 | + /* Get the EEPROM data*/ |
---|
| 3177 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, |
---|
| 3178 | + (void *)(&ax178dataptr->EepromData)); |
---|
| 3179 | + if (ret < 0) { |
---|
| 3180 | + deverr(dev, "read SROM address 17h failed: %d", ret); |
---|
| 3181 | + goto error_out; |
---|
| 3182 | + } |
---|
| 3183 | + le16_to_cpus(&ax178dataptr->EepromData); |
---|
| 3184 | + /* End of get EEPROM data */ |
---|
| 3185 | + |
---|
| 3186 | + if (ax178dataptr->EepromData == 0xffff) { |
---|
| 3187 | + ax178dataptr->PhyMode = PHY_MODE_MARVELL; |
---|
| 3188 | + ax178dataptr->LedMode = 0; |
---|
| 3189 | + ax178dataptr->UseGpio0 = 1; /* True */ |
---|
| 3190 | + } else { |
---|
| 3191 | + ax178dataptr->PhyMode = (u8)(ax178dataptr->EepromData & |
---|
| 3192 | + EEPROMMASK); |
---|
| 3193 | + ax178dataptr->LedMode = (u8)(ax178dataptr->EepromData >> 8); |
---|
| 3194 | + |
---|
| 3195 | + /* for buffalo new (use gpio2) */ |
---|
| 3196 | + if (ax178dataptr->LedMode == 6) |
---|
| 3197 | + ax178dataptr->LedMode = 1; |
---|
| 3198 | + else if (ax178dataptr->LedMode == 1) |
---|
| 3199 | + ax178dataptr->BuffaloOld = 1; |
---|
| 3200 | + |
---|
| 3201 | + |
---|
| 3202 | + if (ax178dataptr->EepromData & 0x80) |
---|
| 3203 | + ax178dataptr->UseGpio0 = 0; /* MARVEL se and other */ |
---|
| 3204 | + else |
---|
| 3205 | + ax178dataptr->UseGpio0 = 1; /* cameo */ |
---|
| 3206 | + } |
---|
| 3207 | + |
---|
| 3208 | + if (ax178dataptr->UseGpio0) { |
---|
| 3209 | + |
---|
| 3210 | + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { |
---|
| 3211 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3212 | + AXGPIOS_GPO0EN | AXGPIOS_RSE, |
---|
| 3213 | + 0, 0, NULL); |
---|
| 3214 | + if (ret < 0) { |
---|
| 3215 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3216 | + goto error_out; |
---|
| 3217 | + } |
---|
| 3218 | + |
---|
| 3219 | + msleep(25); |
---|
| 3220 | + |
---|
| 3221 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3222 | + (AXGPIOS_GPO2 | AXGPIOS_GPO2EN | |
---|
| 3223 | + AXGPIOS_GPO0EN), 0, 0, NULL); |
---|
| 3224 | + if (ret < 0) { |
---|
| 3225 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3226 | + goto error_out; |
---|
| 3227 | + } |
---|
| 3228 | + |
---|
| 3229 | + msleep(15); |
---|
| 3230 | + |
---|
| 3231 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3232 | + AXGPIOS_GPO2EN | AXGPIOS_GPO0EN, |
---|
| 3233 | + 0, 0, NULL); |
---|
| 3234 | + if (ret < 0) { |
---|
| 3235 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3236 | + goto error_out; |
---|
| 3237 | + } |
---|
| 3238 | + |
---|
| 3239 | + msleep(245); |
---|
| 3240 | + |
---|
| 3241 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3242 | + (AXGPIOS_GPO2 | AXGPIOS_GPO2EN | |
---|
| 3243 | + AXGPIOS_GPO0EN), 0, 0, NULL); |
---|
| 3244 | + if (ret < 0) { |
---|
| 3245 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3246 | + goto error_out; |
---|
| 3247 | + } |
---|
| 3248 | + |
---|
| 3249 | + } else { /* vitesse */ |
---|
| 3250 | + |
---|
| 3251 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3252 | + (AXGPIOS_RSE | AXGPIOS_GPO0EN | |
---|
| 3253 | + AXGPIOS_GPO0), 0, 0, NULL); |
---|
| 3254 | + if (ret < 0) { |
---|
| 3255 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3256 | + goto error_out; |
---|
| 3257 | + } |
---|
| 3258 | + |
---|
| 3259 | + msleep(25); |
---|
| 3260 | + |
---|
| 3261 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3262 | + (AXGPIOS_GPO0EN | AXGPIOS_GPO0 | |
---|
| 3263 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), |
---|
| 3264 | + 0, 0, NULL); |
---|
| 3265 | + if (ret < 0) { |
---|
| 3266 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3267 | + goto error_out; |
---|
| 3268 | + } |
---|
| 3269 | + |
---|
| 3270 | + msleep(25); |
---|
| 3271 | + |
---|
| 3272 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3273 | + (AXGPIOS_GPO0EN | AXGPIOS_GPO0 | |
---|
| 3274 | + AXGPIOS_GPO2EN), 0, 0, NULL); |
---|
| 3275 | + if (ret < 0) { |
---|
| 3276 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3277 | + goto error_out; |
---|
| 3278 | + } |
---|
| 3279 | + |
---|
| 3280 | + msleep(245); |
---|
| 3281 | + |
---|
| 3282 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3283 | + (AXGPIOS_GPO0EN | AXGPIOS_GPO0 | |
---|
| 3284 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), |
---|
| 3285 | + 0, 0, NULL); |
---|
| 3286 | + if (ret < 0) { |
---|
| 3287 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3288 | + goto error_out; |
---|
| 3289 | + } |
---|
| 3290 | + } |
---|
| 3291 | + } else { /* use gpio1 */ |
---|
| 3292 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3293 | + (AXGPIOS_GPO1 | AXGPIOS_GPO1EN | |
---|
| 3294 | + AXGPIOS_RSE), 0, 0, NULL); |
---|
| 3295 | + if (ret < 0) { |
---|
| 3296 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3297 | + goto error_out; |
---|
| 3298 | + } |
---|
| 3299 | + |
---|
| 3300 | + if (ax178dataptr->BuffaloOld) { |
---|
| 3301 | + msleep(350); |
---|
| 3302 | + |
---|
| 3303 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3304 | + AXGPIOS_GPO1EN, 0, 0, NULL); |
---|
| 3305 | + if (ret < 0) { |
---|
| 3306 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3307 | + goto error_out; |
---|
| 3308 | + } |
---|
| 3309 | + |
---|
| 3310 | + msleep(350); |
---|
| 3311 | + |
---|
| 3312 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3313 | + AXGPIOS_GPO1EN | AXGPIOS_GPO1, |
---|
| 3314 | + 0, 0, NULL); |
---|
| 3315 | + if (ret < 0) { |
---|
| 3316 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3317 | + goto error_out; |
---|
| 3318 | + } |
---|
| 3319 | + } else { |
---|
| 3320 | + msleep(25); |
---|
| 3321 | + |
---|
| 3322 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3323 | + (AXGPIOS_GPO1EN | AXGPIOS_GPO1 | |
---|
| 3324 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), |
---|
| 3325 | + 0, 0, NULL); |
---|
| 3326 | + if (ret < 0) { |
---|
| 3327 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3328 | + goto error_out; |
---|
| 3329 | + } |
---|
| 3330 | + |
---|
| 3331 | + msleep(25); |
---|
| 3332 | + |
---|
| 3333 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3334 | + (AXGPIOS_GPO1EN | AXGPIOS_GPO1 | |
---|
| 3335 | + AXGPIOS_GPO2EN), 0, 0, NULL); |
---|
| 3336 | + if (ret < 0) { |
---|
| 3337 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3338 | + goto error_out; |
---|
| 3339 | + } |
---|
| 3340 | + |
---|
| 3341 | + msleep(245); |
---|
| 3342 | + |
---|
| 3343 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3344 | + (AXGPIOS_GPO1EN | AXGPIOS_GPO1 | |
---|
| 3345 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), |
---|
| 3346 | + 0, 0, NULL); |
---|
| 3347 | + if (ret < 0) { |
---|
| 3348 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3349 | + goto error_out; |
---|
| 3350 | + } |
---|
| 3351 | + } |
---|
| 3352 | + } |
---|
| 3353 | + |
---|
| 3354 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); |
---|
| 3355 | + if (ret < 0) { |
---|
| 3356 | + deverr(dev, "Select PHY failed: %d", ret); |
---|
| 3357 | + goto error_out; |
---|
| 3358 | + } |
---|
| 3359 | + |
---|
| 3360 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD | |
---|
| 3361 | + AX_SWRESET_PRL, 0, 0, NULL); |
---|
| 3362 | + if (ret < 0) { |
---|
| 3363 | + deverr(dev, "Issue sw reset failed: %d", ret); |
---|
| 3364 | + goto error_out; |
---|
| 3365 | + } |
---|
| 3366 | + |
---|
| 3367 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0, 0, 0, NULL); |
---|
| 3368 | + if (ret < 0) { |
---|
| 3369 | + deverr(dev, "Issue rx ctrl failed: %d", ret); |
---|
| 3370 | + goto error_out; |
---|
| 3371 | + } |
---|
| 3372 | + |
---|
| 3373 | + /* Get the MAC address */ |
---|
| 3374 | + memset(buf, 0, ETH_ALEN); |
---|
| 3375 | + ax8817x_get_mac(dev, buf); |
---|
| 3376 | + if (ret < 0) |
---|
| 3377 | + goto error_out; |
---|
| 3378 | + /* End of get MAC address */ |
---|
| 3379 | + |
---|
| 3380 | + ret = ax88178_phy_init(dev, ax178dataptr); |
---|
| 3381 | + if (ret < 0) |
---|
| 3382 | + goto error_out; |
---|
| 3383 | + |
---|
| 3384 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 3385 | + dev->net->do_ioctl = ax8817x_ioctl; |
---|
| 3386 | + dev->net->set_multicast_list = ax88178_set_multicast; |
---|
| 3387 | + dev->net->set_mac_address = ax8817x_set_mac_addr; |
---|
| 3388 | +#else |
---|
| 3389 | + dev->net->netdev_ops = &ax88178_netdev_ops; |
---|
| 3390 | +#endif |
---|
| 3391 | + dev->net->ethtool_ops = &ax8817x_ethtool_ops; |
---|
| 3392 | + |
---|
| 3393 | + /* Register suspend and resume functions */ |
---|
| 3394 | + data->suspend = ax88772_suspend; |
---|
| 3395 | + data->resume = ax88772_resume; |
---|
| 3396 | + |
---|
| 3397 | + if (dev->driver_info->flags & FLAG_FRAMING_AX) |
---|
| 3398 | + dev->rx_urb_size = 16384; |
---|
| 3399 | + |
---|
| 3400 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, (AX_RX_CTL_MFB | |
---|
| 3401 | + AX_RX_CTL_START | AX_RX_CTL_AB), 0, 0, NULL); |
---|
| 3402 | + if (ret < 0) { |
---|
| 3403 | + deverr(dev, "write RX ctrl reg failed: %d", ret); |
---|
| 3404 | + goto error_out; |
---|
| 3405 | + } |
---|
| 3406 | + |
---|
| 3407 | + kfree(buf); |
---|
| 3408 | + printk(version); |
---|
| 3409 | + return ret; |
---|
| 3410 | + |
---|
| 3411 | +error_out: |
---|
| 3412 | + kfree(ax178dataptr); |
---|
| 3413 | + kfree(buf); |
---|
| 3414 | + return ret; |
---|
| 3415 | +} |
---|
| 3416 | + |
---|
| 3417 | +static void ax88178_unbind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 3418 | +{ |
---|
| 3419 | + struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv; |
---|
| 3420 | + |
---|
| 3421 | + if (ax178dataptr) { |
---|
| 3422 | + |
---|
| 3423 | + /* stop MAC operation */ |
---|
| 3424 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 3425 | + AX_RX_CTL_STOP, 0, 0, NULL); |
---|
| 3426 | + |
---|
| 3427 | + kfree(ax178dataptr); |
---|
| 3428 | + } |
---|
| 3429 | +} |
---|
| 3430 | + |
---|
| 3431 | +static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
---|
| 3432 | +{ |
---|
| 3433 | + u8 *head; |
---|
| 3434 | + u32 header; |
---|
| 3435 | + char *packet; |
---|
| 3436 | + struct sk_buff *ax_skb = NULL; |
---|
| 3437 | + u16 size; |
---|
| 3438 | + |
---|
| 3439 | + head = (u8 *) skb->data; |
---|
| 3440 | + memcpy(&header, head, sizeof(header)); |
---|
| 3441 | + le32_to_cpus(&header); |
---|
| 3442 | + packet = head + sizeof(header); |
---|
| 3443 | + |
---|
| 3444 | + skb_pull(skb, 4); |
---|
| 3445 | + |
---|
| 3446 | + while (skb->len > 0) { |
---|
| 3447 | + if ((short)(header & 0x00007ff) != |
---|
| 3448 | + ~((short)(((header & 0xffff0000) | 0xf8000000) >> 16))) { |
---|
| 3449 | + deverr(dev, "header length data is error 0x%08x, %d\n", |
---|
| 3450 | + header, skb->len); |
---|
| 3451 | + } |
---|
| 3452 | + /* get the packet length */ |
---|
| 3453 | + size = (u16) (header & 0x00007ff); |
---|
| 3454 | + |
---|
| 3455 | + if ((skb->len) - ((size + 1) & 0xfffe) == 0) { |
---|
| 3456 | + |
---|
| 3457 | + /* Make sure ip header is aligned on 32-bit boundary */ |
---|
| 3458 | + if (!((unsigned long)skb->data & 0x02)) { |
---|
| 3459 | + memmove(skb->data - 2, skb->data, size); |
---|
| 3460 | + skb->data -= 2; |
---|
| 3461 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3462 | + skb->tail = skb->data + size; |
---|
| 3463 | +#else |
---|
| 3464 | + skb_set_tail_pointer(skb, size); |
---|
| 3465 | +#endif |
---|
| 3466 | + } |
---|
| 3467 | + skb->truesize = size + sizeof(struct sk_buff); |
---|
| 3468 | + skb->len = size; |
---|
| 3469 | + |
---|
| 3470 | + return 2; |
---|
| 3471 | + } |
---|
| 3472 | + |
---|
| 3473 | + if (size > ETH_FRAME_LEN) { |
---|
| 3474 | + deverr(dev, "invalid rx length %d", size); |
---|
| 3475 | + return 0; |
---|
| 3476 | + } |
---|
| 3477 | +#ifndef RX_SKB_COPY |
---|
| 3478 | + ax_skb = skb_clone(skb, GFP_ATOMIC); |
---|
| 3479 | +#else |
---|
| 3480 | + ax_skb = alloc_skb(size + NET_IP_ALIGN, GFP_ATOMIC); |
---|
| 3481 | + skb_reserve(ax_skb, NET_IP_ALIGN); |
---|
| 3482 | +#endif |
---|
| 3483 | + if (ax_skb) { |
---|
| 3484 | +#ifndef RX_SKB_COPY |
---|
| 3485 | + /* Make sure ip header is aligned on 32-bit boundary */ |
---|
| 3486 | + if (!((unsigned long)packet & 0x02)) { |
---|
| 3487 | + memmove(packet - 2, packet, size); |
---|
| 3488 | + packet -= 2; |
---|
| 3489 | + } |
---|
| 3490 | + ax_skb->data = packet; |
---|
| 3491 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3492 | + ax_skb->tail = packet + size; |
---|
| 3493 | +#else |
---|
| 3494 | + skb_set_tail_pointer(ax_skb, size); |
---|
| 3495 | +#endif |
---|
| 3496 | + |
---|
| 3497 | +#else |
---|
| 3498 | + skb_put(ax_skb, size); |
---|
| 3499 | + memcpy(ax_skb->data, packet , size); |
---|
| 3500 | +#endif |
---|
| 3501 | + ax_skb->truesize = size + sizeof(struct sk_buff); |
---|
| 3502 | + axusbnet_skb_return(dev, ax_skb); |
---|
| 3503 | + |
---|
| 3504 | + } else { |
---|
| 3505 | + return 0; |
---|
| 3506 | + } |
---|
| 3507 | + |
---|
| 3508 | + skb_pull(skb, (size + 1) & 0xfffe); |
---|
| 3509 | + |
---|
| 3510 | + if (skb->len == 0) |
---|
| 3511 | + break; |
---|
| 3512 | + |
---|
| 3513 | + head = (u8 *) skb->data; |
---|
| 3514 | + memcpy(&header, head, sizeof(header)); |
---|
| 3515 | + le32_to_cpus(&header); |
---|
| 3516 | + packet = head + sizeof(header); |
---|
| 3517 | + skb_pull(skb, 4); |
---|
| 3518 | + } |
---|
| 3519 | + |
---|
| 3520 | + if (skb->len < 0) { |
---|
| 3521 | + deverr(dev, "invalid rx length %d", skb->len); |
---|
| 3522 | + return 0; |
---|
| 3523 | + } |
---|
| 3524 | + return 1; |
---|
| 3525 | +} |
---|
| 3526 | + |
---|
| 3527 | +static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, |
---|
| 3528 | + gfp_t flags) |
---|
| 3529 | +{ |
---|
| 3530 | + int padlen = ((skb->len + 4) % 512) ? 0 : 4; |
---|
| 3531 | + u32 packet_len; |
---|
| 3532 | + u32 padbytes = 0xffff0000; |
---|
| 3533 | + |
---|
| 3534 | +#if (!AX_FORCE_BUFF_ALIGN) |
---|
| 3535 | + int headroom = skb_headroom(skb); |
---|
| 3536 | + int tailroom = skb_tailroom(skb); |
---|
| 3537 | + |
---|
| 3538 | + if ((!skb_cloned(skb)) |
---|
| 3539 | + && ((headroom + tailroom) >= (4 + padlen))) { |
---|
| 3540 | + if ((headroom < 4) || (tailroom < padlen)) { |
---|
| 3541 | + skb->data = memmove(skb->head + 4, skb->data, skb->len); |
---|
| 3542 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3543 | + skb->tail = skb->data + skb->len; |
---|
| 3544 | +#else |
---|
| 3545 | + skb_set_tail_pointer(skb, skb->len); |
---|
| 3546 | +#endif |
---|
| 3547 | + } |
---|
| 3548 | + } else |
---|
| 3549 | +#endif |
---|
| 3550 | + { |
---|
| 3551 | + struct sk_buff *skb2; |
---|
| 3552 | + skb2 = skb_copy_expand(skb, 4, padlen, flags); |
---|
| 3553 | + dev_kfree_skb_any(skb); |
---|
| 3554 | + skb = skb2; |
---|
| 3555 | + if (!skb) |
---|
| 3556 | + return NULL; |
---|
| 3557 | + } |
---|
| 3558 | + |
---|
| 3559 | + skb_push(skb, 4); |
---|
| 3560 | + packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); |
---|
| 3561 | + cpu_to_le32s(&packet_len); |
---|
| 3562 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3563 | + memcpy(skb->data, &packet_len, sizeof(packet_len)); |
---|
| 3564 | +#else |
---|
| 3565 | + skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); |
---|
| 3566 | +#endif |
---|
| 3567 | + |
---|
| 3568 | + if ((skb->len % 512) == 0) { |
---|
| 3569 | + cpu_to_le32s(&padbytes); |
---|
| 3570 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3571 | + memcpy(skb->tail, &padbytes, sizeof(padbytes)); |
---|
| 3572 | +#else |
---|
| 3573 | + memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); |
---|
| 3574 | +#endif |
---|
| 3575 | + skb_put(skb, sizeof(padbytes)); |
---|
| 3576 | + } |
---|
| 3577 | + return skb; |
---|
| 3578 | +} |
---|
| 3579 | + |
---|
| 3580 | +static void |
---|
| 3581 | +ax88772b_rx_checksum(struct sk_buff *skb, struct ax88772b_rx_header *rx_hdr) |
---|
| 3582 | +{ |
---|
| 3583 | + skb->ip_summed = CHECKSUM_NONE; |
---|
| 3584 | + |
---|
| 3585 | + /* checksum error bit is set */ |
---|
| 3586 | + if (rx_hdr->l3_csum_err || rx_hdr->l4_csum_err) |
---|
| 3587 | + return; |
---|
| 3588 | + |
---|
| 3589 | + /* It must be a TCP or UDP packet with a valid checksum */ |
---|
| 3590 | + if ((rx_hdr->l4_type == AX_RXHDR_L4_TYPE_TCP) || |
---|
| 3591 | + (rx_hdr->l4_type == AX_RXHDR_L4_TYPE_UDP)) { |
---|
| 3592 | + skb->ip_summed = CHECKSUM_UNNECESSARY; |
---|
| 3593 | + } |
---|
| 3594 | +} |
---|
| 3595 | + |
---|
| 3596 | +static int ax88772b_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
---|
| 3597 | +{ |
---|
| 3598 | + struct ax88772b_rx_header rx_hdr; |
---|
| 3599 | + struct sk_buff *ax_skb = NULL; |
---|
| 3600 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 3601 | + |
---|
| 3602 | + while (skb->len > 0) { |
---|
| 3603 | + |
---|
| 3604 | + le16_to_cpus((u16 *)skb->data); |
---|
| 3605 | + le16_to_cpus(((u16 *)skb->data) + 1); |
---|
| 3606 | + |
---|
| 3607 | + memcpy(&rx_hdr, skb->data, sizeof(struct ax88772b_rx_header)); |
---|
| 3608 | + |
---|
| 3609 | + if ((short)rx_hdr.len != (~((short)rx_hdr.len_bar) & 0x7FF)) |
---|
| 3610 | + return 0; |
---|
| 3611 | + |
---|
| 3612 | + if (rx_hdr.len > (ETH_FRAME_LEN + 4)) { |
---|
| 3613 | + deverr(dev, "invalid rx length %d", rx_hdr.len); |
---|
| 3614 | + return 0; |
---|
| 3615 | + } |
---|
| 3616 | + |
---|
| 3617 | + if (skb->len - ((rx_hdr.len + |
---|
| 3618 | + sizeof(struct ax88772b_rx_header) + 3) & |
---|
| 3619 | + 0xfffc) == 0) { |
---|
| 3620 | + skb_pull(skb, sizeof(struct ax88772b_rx_header)); |
---|
| 3621 | + skb->len = rx_hdr.len; |
---|
| 3622 | + |
---|
| 3623 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3624 | + skb->tail = skb->data + rx_hdr.len; |
---|
| 3625 | +#else |
---|
| 3626 | + skb_set_tail_pointer(skb, rx_hdr.len); |
---|
| 3627 | +#endif |
---|
| 3628 | + skb->truesize = rx_hdr.len + sizeof(struct sk_buff); |
---|
| 3629 | + |
---|
| 3630 | + if (ax772b_data->checksum & AX_RX_CHECKSUM) |
---|
| 3631 | + ax88772b_rx_checksum(skb, &rx_hdr); |
---|
| 3632 | + |
---|
| 3633 | + return 2; |
---|
| 3634 | + } |
---|
| 3635 | +#ifndef RX_SKB_COPY |
---|
| 3636 | + ax_skb = skb_clone(skb, GFP_ATOMIC); |
---|
| 3637 | +#else |
---|
| 3638 | + ax_skb = alloc_skb(rx_hdr.len + NET_IP_ALIGN, GFP_ATOMIC); |
---|
| 3639 | + skb_reserve(ax_skb, NET_IP_ALIGN); |
---|
| 3640 | +#endif |
---|
| 3641 | + if (ax_skb) { |
---|
| 3642 | +#ifndef RX_SKB_COPY |
---|
| 3643 | + ax_skb->len = rx_hdr.len; |
---|
| 3644 | + ax_skb->data = skb->data + |
---|
| 3645 | + sizeof(struct ax88772b_rx_header); |
---|
| 3646 | + |
---|
| 3647 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3648 | + ax_skb->tail = ax_skb->data + rx_hdr.len; |
---|
| 3649 | +#else |
---|
| 3650 | + skb_set_tail_pointer(ax_skb, rx_hdr.len); |
---|
| 3651 | +#endif |
---|
| 3652 | + |
---|
| 3653 | +#else |
---|
| 3654 | + skb_put(ax_skb, rx_hdr.len); |
---|
| 3655 | + memcpy(ax_skb->data, skb->data + sizeof(struct ax88772b_rx_header), rx_hdr.len); |
---|
| 3656 | +#endif |
---|
| 3657 | + |
---|
| 3658 | + ax_skb->truesize = rx_hdr.len + sizeof(struct sk_buff); |
---|
| 3659 | + |
---|
| 3660 | + if (ax772b_data->checksum & AX_RX_CHECKSUM) |
---|
| 3661 | + ax88772b_rx_checksum(ax_skb, &rx_hdr); |
---|
| 3662 | + |
---|
| 3663 | + axusbnet_skb_return(dev, ax_skb); |
---|
| 3664 | + |
---|
| 3665 | + } else { |
---|
| 3666 | + return 0; |
---|
| 3667 | + } |
---|
| 3668 | + |
---|
| 3669 | + skb_pull(skb, ((rx_hdr.len + |
---|
| 3670 | + sizeof(struct ax88772b_rx_header) + 3) |
---|
| 3671 | + & 0xfffc)); |
---|
| 3672 | + } |
---|
| 3673 | + |
---|
| 3674 | + if (skb->len < 0) { |
---|
| 3675 | + deverr(dev, "invalid rx length %d", skb->len); |
---|
| 3676 | + return 0; |
---|
| 3677 | + } |
---|
| 3678 | + return 1; |
---|
| 3679 | +} |
---|
| 3680 | + |
---|
| 3681 | +static struct sk_buff * |
---|
| 3682 | +ax88772b_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) |
---|
| 3683 | +{ |
---|
| 3684 | + int padlen = ((skb->len + 4) % 512) ? 0 : 4; |
---|
| 3685 | + u32 packet_len; |
---|
| 3686 | + u32 padbytes = 0xffff0000; |
---|
| 3687 | + |
---|
| 3688 | +#if (!AX_FORCE_BUFF_ALIGN) |
---|
| 3689 | + int headroom = skb_headroom(skb); |
---|
| 3690 | + int tailroom = skb_tailroom(skb); |
---|
| 3691 | + |
---|
| 3692 | + if ((!skb_cloned(skb)) |
---|
| 3693 | + && ((headroom + tailroom) >= (4 + padlen))) { |
---|
| 3694 | + if ((headroom < 4) || (tailroom < padlen)) { |
---|
| 3695 | + skb->data = memmove(skb->head + 4, skb->data, skb->len); |
---|
| 3696 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3697 | + skb->tail = skb->data + skb->len; |
---|
| 3698 | +#else |
---|
| 3699 | + skb_set_tail_pointer(skb, skb->len); |
---|
| 3700 | +#endif |
---|
| 3701 | + } |
---|
| 3702 | + } else |
---|
| 3703 | +#endif |
---|
| 3704 | + { |
---|
| 3705 | + struct sk_buff *skb2; |
---|
| 3706 | + skb2 = skb_copy_expand(skb, 4, padlen, flags); |
---|
| 3707 | + dev_kfree_skb_any(skb); |
---|
| 3708 | + skb = skb2; |
---|
| 3709 | + if (!skb) |
---|
| 3710 | + return NULL; |
---|
| 3711 | + } |
---|
| 3712 | + |
---|
| 3713 | + skb_push(skb, 4); |
---|
| 3714 | + packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); |
---|
| 3715 | + |
---|
| 3716 | + cpu_to_le32s(&packet_len); |
---|
| 3717 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3718 | + memcpy(skb->data, &packet_len, sizeof(packet_len)); |
---|
| 3719 | +#else |
---|
| 3720 | + skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); |
---|
| 3721 | +#endif |
---|
| 3722 | + |
---|
| 3723 | + if ((skb->len % 512) == 0) { |
---|
| 3724 | + cpu_to_le32s(&padbytes); |
---|
| 3725 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3726 | + memcpy(skb->tail, &padbytes, sizeof(padbytes)); |
---|
| 3727 | +#else |
---|
| 3728 | + memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); |
---|
| 3729 | +#endif |
---|
| 3730 | + skb_put(skb, sizeof(padbytes)); |
---|
| 3731 | + } |
---|
| 3732 | + |
---|
| 3733 | + return skb; |
---|
| 3734 | +} |
---|
| 3735 | + |
---|
| 3736 | +static const u8 chkcntsel[6][3] = { |
---|
| 3737 | + {12, 23, 31}, |
---|
| 3738 | + {12, 31, 23}, |
---|
| 3739 | + {23, 31, 12}, |
---|
| 3740 | + {23, 12, 31}, |
---|
| 3741 | + {31, 12, 23}, |
---|
| 3742 | + {31, 23, 12} |
---|
| 3743 | +}; |
---|
| 3744 | + |
---|
| 3745 | +static void ax88772_save_bmcr_anar(struct usbnet *dev) |
---|
| 3746 | +{ |
---|
| 3747 | + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; |
---|
| 3748 | + |
---|
| 3749 | + if (ax772_data) { |
---|
| 3750 | + /* Preserve BMCR for restoring */ |
---|
| 3751 | + ax772_data->presvd_phy_bmcr = |
---|
| 3752 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_BMCR); |
---|
| 3753 | + |
---|
| 3754 | + /* Preserve Advertisement control reg for restoring */ |
---|
| 3755 | + ax772_data->presvd_phy_advertise = |
---|
| 3756 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 3757 | + } |
---|
| 3758 | +} |
---|
| 3759 | + |
---|
| 3760 | +static void ax88772_restore_bmcr_anar(struct usbnet *dev) |
---|
| 3761 | +{ |
---|
| 3762 | + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; |
---|
| 3763 | + |
---|
| 3764 | + if (ax772_data && ax772_data->presvd_phy_advertise && ax772_data->presvd_phy_bmcr) { |
---|
| 3765 | + /* Restore Advertisement control reg */ |
---|
| 3766 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 3767 | + ax772_data->presvd_phy_advertise); |
---|
| 3768 | + /* Restore BMCR */ |
---|
| 3769 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, |
---|
| 3770 | + ax772_data->presvd_phy_bmcr); |
---|
| 3771 | + ax772_data->presvd_phy_advertise = 0; |
---|
| 3772 | + ax772_data->presvd_phy_bmcr = 0; |
---|
| 3773 | + } |
---|
| 3774 | +} |
---|
| 3775 | + |
---|
| 3776 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 3777 | +static void ax88772_link_reset(void *data) |
---|
| 3778 | +{ |
---|
| 3779 | + struct usbnet *dev = (struct usbnet *)data; |
---|
| 3780 | + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; |
---|
| 3781 | +#else |
---|
| 3782 | +static void ax88772_link_reset(struct work_struct *work) |
---|
| 3783 | +{ |
---|
| 3784 | + struct ax88772_data *ax772_data = container_of(work, |
---|
| 3785 | + struct ax88772_data, |
---|
| 3786 | + check_link); |
---|
| 3787 | + struct usbnet *dev = ax772_data->dev; |
---|
| 3788 | +#endif |
---|
| 3789 | + if (ax772_data->Event == AX_SET_RX_CFG) { |
---|
| 3790 | + u16 bmcr; |
---|
| 3791 | + u16 mode; |
---|
| 3792 | + |
---|
| 3793 | + ax772_data->Event = AX_NOP; |
---|
| 3794 | + |
---|
| 3795 | + mode = AX88772_MEDIUM_DEFAULT; |
---|
| 3796 | + |
---|
| 3797 | + bmcr = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 3798 | + MII_BMCR); |
---|
| 3799 | + if (!(bmcr & BMCR_FULLDPLX)) |
---|
| 3800 | + mode &= ~AX88772_MEDIUM_FULL_DUPLEX; |
---|
| 3801 | + if (!(bmcr & BMCR_SPEED100)) |
---|
| 3802 | + mode &= ~AX88772_MEDIUM_100MB; |
---|
| 3803 | + |
---|
| 3804 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 3805 | + mode, 0, 0, NULL); |
---|
| 3806 | + return; |
---|
| 3807 | + } |
---|
| 3808 | + |
---|
| 3809 | + switch (ax772_data->Event) { |
---|
| 3810 | + case WAIT_AUTONEG_COMPLETE: |
---|
| 3811 | + if (jiffies > (ax772_data->autoneg_start + 5 * HZ)) { |
---|
| 3812 | + ax772_data->Event = PHY_POWER_DOWN; |
---|
| 3813 | + ax772_data->TickToExpire = 23; |
---|
| 3814 | + } |
---|
| 3815 | + break; |
---|
| 3816 | + case PHY_POWER_DOWN: |
---|
| 3817 | + if (ax772_data->TickToExpire == 23) { |
---|
| 3818 | + ax88772_save_bmcr_anar(dev); |
---|
| 3819 | + /* Set Phy Power Down */ |
---|
| 3820 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, |
---|
| 3821 | + 0, 0, NULL); |
---|
| 3822 | + --ax772_data->TickToExpire; |
---|
| 3823 | + } else if (--ax772_data->TickToExpire == 0) { |
---|
| 3824 | + /* Set Phy Power Up */ |
---|
| 3825 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3826 | + AX_SWRESET_IPRL, 0, 0, NULL); |
---|
| 3827 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3828 | + AX_SWRESET_IPPD | AX_SWRESET_IPRL, 0, 0, NULL); |
---|
| 3829 | + msleep(10); |
---|
| 3830 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3831 | + AX_SWRESET_IPRL, 0, 0, NULL); |
---|
| 3832 | + msleep(60); |
---|
| 3833 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3834 | + AX_SWRESET_CLEAR, 0, 0, NULL); |
---|
| 3835 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3836 | + AX_SWRESET_IPRL, 0, 0, NULL); |
---|
| 3837 | + |
---|
| 3838 | + if (ax772_data->presvd_phy_advertise && ax772_data->presvd_phy_bmcr) { |
---|
| 3839 | + ax88772_restore_bmcr_anar(dev); |
---|
| 3840 | + |
---|
| 3841 | + } else { |
---|
| 3842 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 3843 | + MII_ADVERTISE, |
---|
| 3844 | + ADVERTISE_ALL | ADVERTISE_CSMA | |
---|
| 3845 | + ADVERTISE_PAUSE_CAP); |
---|
| 3846 | + mii_nway_restart(&dev->mii); |
---|
| 3847 | + } |
---|
| 3848 | + |
---|
| 3849 | + ax772_data->Event = PHY_POWER_UP; |
---|
| 3850 | + ax772_data->TickToExpire = 47; |
---|
| 3851 | + } |
---|
| 3852 | + break; |
---|
| 3853 | + case PHY_POWER_UP: |
---|
| 3854 | + if (--ax772_data->TickToExpire == 0) { |
---|
| 3855 | + ax772_data->Event = PHY_POWER_DOWN; |
---|
| 3856 | + ax772_data->TickToExpire = 23; |
---|
| 3857 | + } |
---|
| 3858 | + break; |
---|
| 3859 | + default: |
---|
| 3860 | + break; |
---|
| 3861 | + } |
---|
| 3862 | + return; |
---|
| 3863 | +} |
---|
| 3864 | + |
---|
| 3865 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 3866 | +static void ax88772a_link_reset(void *data) |
---|
| 3867 | +{ |
---|
| 3868 | + struct usbnet *dev = (struct usbnet *)data; |
---|
| 3869 | + struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv; |
---|
| 3870 | +#else |
---|
| 3871 | +static void ax88772a_link_reset(struct work_struct *work) |
---|
| 3872 | +{ |
---|
| 3873 | + struct ax88772a_data *ax772a_data = container_of(work, |
---|
| 3874 | + struct ax88772a_data, |
---|
| 3875 | + check_link); |
---|
| 3876 | + struct usbnet *dev = ax772a_data->dev; |
---|
| 3877 | +#endif |
---|
| 3878 | + int powsave = (ax772a_data->EepromData >> 14); |
---|
| 3879 | + u16 phy_reg; |
---|
| 3880 | + |
---|
| 3881 | + if (ax772a_data->Event == AX_SET_RX_CFG) { |
---|
| 3882 | + u16 bmcr; |
---|
| 3883 | + u16 mode; |
---|
| 3884 | + |
---|
| 3885 | + ax772a_data->Event = AX_NOP; |
---|
| 3886 | + |
---|
| 3887 | + mode = AX88772_MEDIUM_DEFAULT; |
---|
| 3888 | + |
---|
| 3889 | + bmcr = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 3890 | + MII_BMCR); |
---|
| 3891 | + if (!(bmcr & BMCR_FULLDPLX)) |
---|
| 3892 | + mode &= ~AX88772_MEDIUM_FULL_DUPLEX; |
---|
| 3893 | + if (!(bmcr & BMCR_SPEED100)) |
---|
| 3894 | + mode &= ~AX88772_MEDIUM_100MB; |
---|
| 3895 | + |
---|
| 3896 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, |
---|
| 3897 | + 0, 0, NULL); |
---|
| 3898 | + |
---|
| 3899 | + if (ax772a_data->presvd_phy_advertise && ax772a_data->presvd_phy_bmcr) { |
---|
| 3900 | + |
---|
| 3901 | + /* Restore Advertisement control reg */ |
---|
| 3902 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 3903 | + ax772a_data->presvd_phy_advertise); |
---|
| 3904 | + /* Restore BMCR */ |
---|
| 3905 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, |
---|
| 3906 | + ax772a_data->presvd_phy_bmcr); |
---|
| 3907 | + ax772a_data->presvd_phy_advertise = 0; |
---|
| 3908 | + ax772a_data->presvd_phy_bmcr = 0; |
---|
| 3909 | + } |
---|
| 3910 | + |
---|
| 3911 | + return; |
---|
| 3912 | + } |
---|
| 3913 | + |
---|
| 3914 | + switch (ax772a_data->Event) { |
---|
| 3915 | + case WAIT_AUTONEG_COMPLETE: |
---|
| 3916 | + if (jiffies > (ax772a_data->autoneg_start + 5 * HZ)) { |
---|
| 3917 | + ax772a_data->Event = CHK_CABLE_EXIST; |
---|
| 3918 | + ax772a_data->TickToExpire = 14; |
---|
| 3919 | + } |
---|
| 3920 | + break; |
---|
| 3921 | + case CHK_CABLE_EXIST: |
---|
| 3922 | + phy_reg = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); |
---|
| 3923 | + if ((phy_reg != 0x8012) && (phy_reg != 0x8013)) { |
---|
| 3924 | + ax8817x_mdio_write_le(dev->net, |
---|
| 3925 | + dev->mii.phy_id, 0x16, 0x4040); |
---|
| 3926 | + mii_nway_restart(&dev->mii); |
---|
| 3927 | + ax772a_data->Event = CHK_CABLE_STATUS; |
---|
| 3928 | + ax772a_data->TickToExpire = 31; |
---|
| 3929 | + } else if (--ax772a_data->TickToExpire == 0) { |
---|
| 3930 | + mii_nway_restart(&dev->mii); |
---|
| 3931 | + ax772a_data->Event = CHK_CABLE_EXIST_AGAIN; |
---|
| 3932 | + if (powsave == 0x03) { |
---|
| 3933 | + ax772a_data->TickToExpire = 47; |
---|
| 3934 | + } else if (powsave == 0x01) { |
---|
| 3935 | + ax772a_data->DlyIndex = (u8)(jiffies % 6); |
---|
| 3936 | + ax772a_data->DlySel = 0; |
---|
| 3937 | + ax772a_data->TickToExpire = |
---|
| 3938 | + chkcntsel[ax772a_data->DlyIndex][ax772a_data->DlySel]; |
---|
| 3939 | + } |
---|
| 3940 | + } |
---|
| 3941 | + break; |
---|
| 3942 | + case CHK_CABLE_EXIST_AGAIN: |
---|
| 3943 | + /* if cable disconnected */ |
---|
| 3944 | + phy_reg = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); |
---|
| 3945 | + if ((phy_reg != 0x8012) && (phy_reg != 0x8013)) { |
---|
| 3946 | + mii_nway_restart(&dev->mii); |
---|
| 3947 | + ax772a_data->Event = CHK_CABLE_STATUS; |
---|
| 3948 | + ax772a_data->TickToExpire = 31; |
---|
| 3949 | + } else if (--ax772a_data->TickToExpire == 0) { |
---|
| 3950 | + if (!ax772a_data->presvd_phy_advertise && !ax772a_data->presvd_phy_bmcr) { |
---|
| 3951 | + /* Preserve BMCR for restoring */ |
---|
| 3952 | + ax772a_data->presvd_phy_bmcr = |
---|
| 3953 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_BMCR); |
---|
| 3954 | + |
---|
| 3955 | + /* Preserve Advertisement control reg for restoring */ |
---|
| 3956 | + ax772a_data->presvd_phy_advertise = |
---|
| 3957 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 3958 | + } |
---|
| 3959 | + |
---|
| 3960 | + |
---|
| 3961 | + /* Power down PHY */ |
---|
| 3962 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3963 | + AX_SWRESET_IPPD, |
---|
| 3964 | + 0, 0, NULL); |
---|
| 3965 | + ax772a_data->Event = PHY_POWER_DOWN; |
---|
| 3966 | + if (powsave == 0x03) |
---|
| 3967 | + ax772a_data->TickToExpire = 23; |
---|
| 3968 | + else if (powsave == 0x01) |
---|
| 3969 | + ax772a_data->TickToExpire = 31; |
---|
| 3970 | + } |
---|
| 3971 | + break; |
---|
| 3972 | + case PHY_POWER_DOWN: |
---|
| 3973 | + if (--ax772a_data->TickToExpire == 0) |
---|
| 3974 | + ax772a_data->Event = PHY_POWER_UP; |
---|
| 3975 | + break; |
---|
| 3976 | + case CHK_CABLE_STATUS: |
---|
| 3977 | + if (--ax772a_data->TickToExpire == 0) { |
---|
| 3978 | + ax8817x_mdio_write_le(dev->net, |
---|
| 3979 | + dev->mii.phy_id, 0x16, 0x4040); |
---|
| 3980 | + mii_nway_restart(&dev->mii); |
---|
| 3981 | + ax772a_data->Event = CHK_CABLE_EXIST_AGAIN; |
---|
| 3982 | + if (powsave == 0x03) { |
---|
| 3983 | + ax772a_data->TickToExpire = 47; |
---|
| 3984 | + } else if (powsave == 0x01) { |
---|
| 3985 | + ax772a_data->DlyIndex = (u8)(jiffies % 6); |
---|
| 3986 | + ax772a_data->DlySel = 0; |
---|
| 3987 | + ax772a_data->TickToExpire = |
---|
| 3988 | + chkcntsel[ax772a_data->DlyIndex][ax772a_data->DlySel]; |
---|
| 3989 | + } |
---|
| 3990 | + } |
---|
| 3991 | + break; |
---|
| 3992 | + case PHY_POWER_UP: |
---|
| 3993 | + |
---|
| 3994 | + if (!ax772a_data->presvd_phy_advertise && !ax772a_data->presvd_phy_bmcr) { |
---|
| 3995 | + /* Preserve BMCR for restoring */ |
---|
| 3996 | + ax772a_data->presvd_phy_bmcr = |
---|
| 3997 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_BMCR); |
---|
| 3998 | + |
---|
| 3999 | + /* Preserve Advertisement control reg for restoring */ |
---|
| 4000 | + ax772a_data->presvd_phy_advertise = |
---|
| 4001 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 4002 | + } |
---|
| 4003 | + |
---|
| 4004 | + ax88772a_phy_powerup(dev); |
---|
| 4005 | + |
---|
| 4006 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 4007 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); |
---|
| 4008 | + |
---|
| 4009 | + mii_nway_restart(&dev->mii); |
---|
| 4010 | + |
---|
| 4011 | + ax772a_data->Event = CHK_CABLE_EXIST_AGAIN; |
---|
| 4012 | + |
---|
| 4013 | + if (powsave == 0x03) { |
---|
| 4014 | + ax772a_data->TickToExpire = 47; |
---|
| 4015 | + } else if (powsave == 0x01) { |
---|
| 4016 | + if (++ax772a_data->DlySel >= 3) { |
---|
| 4017 | + ax772a_data->DlyIndex = (u8)(jiffies % 6); |
---|
| 4018 | + ax772a_data->DlySel = 0; |
---|
| 4019 | + } |
---|
| 4020 | + ax772a_data->TickToExpire = |
---|
| 4021 | + chkcntsel[ax772a_data->DlyIndex][ax772a_data->DlySel]; |
---|
| 4022 | + } |
---|
| 4023 | + break; |
---|
| 4024 | + default: |
---|
| 4025 | + break; |
---|
| 4026 | + } |
---|
| 4027 | + |
---|
| 4028 | + return; |
---|
| 4029 | +} |
---|
| 4030 | + |
---|
| 4031 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 4032 | +static void ax88772b_link_reset(void *data) |
---|
| 4033 | +{ |
---|
| 4034 | + struct usbnet *dev = (struct usbnet *)data; |
---|
| 4035 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 4036 | +#else |
---|
| 4037 | +static void ax88772b_link_reset(struct work_struct *work) |
---|
| 4038 | +{ |
---|
| 4039 | + struct ax88772b_data *ax772b_data = container_of(work, |
---|
| 4040 | + struct ax88772b_data, |
---|
| 4041 | + check_link); |
---|
| 4042 | + struct usbnet *dev = ax772b_data->dev; |
---|
| 4043 | +#endif |
---|
| 4044 | + |
---|
| 4045 | + switch (ax772b_data->Event) { |
---|
| 4046 | + |
---|
| 4047 | + case AX_SET_RX_CFG: |
---|
| 4048 | + { |
---|
| 4049 | + u16 bmcr = ax8817x_mdio_read_le(dev->net, |
---|
| 4050 | + dev->mii.phy_id, MII_BMCR); |
---|
| 4051 | + u16 mode = AX88772_MEDIUM_DEFAULT; |
---|
| 4052 | + |
---|
| 4053 | + if (!(bmcr & BMCR_FULLDPLX)) |
---|
| 4054 | + mode &= ~AX88772_MEDIUM_FULL_DUPLEX; |
---|
| 4055 | + if (!(bmcr & BMCR_SPEED100)) |
---|
| 4056 | + mode &= ~AX88772_MEDIUM_100MB; |
---|
| 4057 | + |
---|
| 4058 | + if (ax772b_data->ext_phy_oui == EXTPHY_BROADCOM_OUI) { |
---|
| 4059 | + if(ax772b_data->ext_phy_model == EXTPHY_BCM89811_MODEL) { |
---|
| 4060 | + mode = AX88772_MEDIUM_DEFAULT; |
---|
| 4061 | + } |
---|
| 4062 | + } |
---|
| 4063 | + |
---|
| 4064 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, |
---|
| 4065 | + 0, 0, NULL); |
---|
| 4066 | + break; |
---|
| 4067 | + } |
---|
| 4068 | + case PHY_POWER_UP: |
---|
| 4069 | + { |
---|
| 4070 | + u16 tmp16; |
---|
| 4071 | + |
---|
| 4072 | + if (!ax772b_data->presvd_phy_advertise && !ax772b_data->presvd_phy_bmcr) { |
---|
| 4073 | + /* Preserve BMCR for restoring */ |
---|
| 4074 | + ax772b_data->presvd_phy_bmcr = |
---|
| 4075 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_BMCR); |
---|
| 4076 | + |
---|
| 4077 | + /* Preserve Advertisement control reg for restoring */ |
---|
| 4078 | + ax772b_data->presvd_phy_advertise = |
---|
| 4079 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 4080 | + } |
---|
| 4081 | + |
---|
| 4082 | + ax88772a_phy_powerup(dev); |
---|
| 4083 | + tmp16 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); |
---|
| 4084 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, 0x12, |
---|
| 4085 | + ((tmp16 & 0xFF9F) | 0x0040)); |
---|
| 4086 | + |
---|
| 4087 | + /* Restore Advertisement control reg */ |
---|
| 4088 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 4089 | + ax772b_data->presvd_phy_advertise); |
---|
| 4090 | + /* Restore BMCR */ |
---|
| 4091 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, |
---|
| 4092 | + ax772b_data->presvd_phy_bmcr); |
---|
| 4093 | + ax772b_data->presvd_phy_advertise = 0; |
---|
| 4094 | + ax772b_data->presvd_phy_bmcr = 0; |
---|
| 4095 | + |
---|
| 4096 | + break; |
---|
| 4097 | + } |
---|
| 4098 | + |
---|
| 4099 | + case AX_CHK_AUTODETACH: |
---|
| 4100 | + { |
---|
| 4101 | + int ret; |
---|
| 4102 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 4103 | + AX_SWRESET_IPRL | |
---|
| 4104 | + (ax772b_data->psc & 0x7FFF), |
---|
| 4105 | + 0, 0, NULL); |
---|
| 4106 | + if (ret < 0) { |
---|
| 4107 | + deverr(dev, "Failed to configure PHY power saving: %d", |
---|
| 4108 | + ret); |
---|
| 4109 | + } |
---|
| 4110 | + |
---|
| 4111 | + break; |
---|
| 4112 | + } |
---|
| 4113 | + default: |
---|
| 4114 | + break; |
---|
| 4115 | + } |
---|
| 4116 | + |
---|
| 4117 | + ax772b_data->Event = AX_NOP; |
---|
| 4118 | + |
---|
| 4119 | + return; |
---|
| 4120 | +} |
---|
| 4121 | + |
---|
| 4122 | +static int ax88178_set_media(struct usbnet *dev) |
---|
| 4123 | +{ |
---|
| 4124 | + int ret; |
---|
| 4125 | + struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv; |
---|
| 4126 | + int media; |
---|
| 4127 | + |
---|
| 4128 | + media = ax88178_media_check(dev, ax178dataptr); |
---|
| 4129 | + if (media < 0) |
---|
| 4130 | + return media; |
---|
| 4131 | + |
---|
| 4132 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, media, 0, |
---|
| 4133 | + 0, NULL); |
---|
| 4134 | + if (ret < 0) { |
---|
| 4135 | + deverr(dev, "write mode medium reg failed: %d", ret); |
---|
| 4136 | + return ret; |
---|
| 4137 | + } |
---|
| 4138 | + |
---|
| 4139 | + return 0; |
---|
| 4140 | +} |
---|
| 4141 | + |
---|
| 4142 | +static int ax88178_link_reset(struct usbnet *dev) |
---|
| 4143 | +{ |
---|
| 4144 | + return ax88178_set_media(dev); |
---|
| 4145 | +} |
---|
| 4146 | + |
---|
| 4147 | +static int ax_suspend(struct usb_interface *intf, |
---|
| 4148 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) |
---|
| 4149 | + pm_message_t message) |
---|
| 4150 | +#else |
---|
| 4151 | + u32 message) |
---|
| 4152 | +#endif |
---|
| 4153 | +{ |
---|
| 4154 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 4155 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 4156 | + |
---|
| 4157 | + return data->suspend(intf, message); |
---|
| 4158 | +} |
---|
| 4159 | + |
---|
| 4160 | +static int ax_resume(struct usb_interface *intf) |
---|
| 4161 | +{ |
---|
| 4162 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 4163 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 4164 | + |
---|
| 4165 | + return data->resume(intf); |
---|
| 4166 | +} |
---|
| 4167 | + |
---|
| 4168 | +static const struct driver_info ax88178_info = { |
---|
| 4169 | + .description = "ASIX AX88178 USB 2.0 Ethernet", |
---|
| 4170 | + .bind = ax88178_bind, |
---|
| 4171 | + .unbind = ax88178_unbind, |
---|
| 4172 | + .status = ax88178_status, |
---|
| 4173 | + .link_reset = ax88178_link_reset, |
---|
| 4174 | + .reset = ax88178_link_reset, |
---|
| 4175 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4176 | + .stop = ax88772b_stop, |
---|
| 4177 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS, |
---|
| 4178 | +#else |
---|
| 4179 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
---|
| 4180 | +#endif |
---|
| 4181 | + .rx_fixup = ax88772_rx_fixup, |
---|
| 4182 | + .tx_fixup = ax88772_tx_fixup, |
---|
| 4183 | +}; |
---|
| 4184 | + |
---|
| 4185 | +static const struct driver_info belkin178_info = { |
---|
| 4186 | + .description = "Belkin Gigabit USB 2.0 Network Adapter", |
---|
| 4187 | + .bind = ax88178_bind, |
---|
| 4188 | + .unbind = ax88178_unbind, |
---|
| 4189 | + .status = ax88178_status, |
---|
| 4190 | + .link_reset = ax88178_link_reset, |
---|
| 4191 | + .reset = ax88178_link_reset, |
---|
| 4192 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4193 | + .stop = ax88772b_stop, |
---|
| 4194 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS, |
---|
| 4195 | +#else |
---|
| 4196 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
---|
| 4197 | +#endif |
---|
| 4198 | + .rx_fixup = ax88772_rx_fixup, |
---|
| 4199 | + .tx_fixup = ax88772_tx_fixup, |
---|
| 4200 | +}; |
---|
| 4201 | + |
---|
| 4202 | +static const struct driver_info ax8817x_info = { |
---|
| 4203 | + .description = "ASIX AX8817x USB 2.0 Ethernet", |
---|
| 4204 | + .bind = ax8817x_bind, |
---|
| 4205 | + .status = ax8817x_status, |
---|
| 4206 | + .link_reset = ax88172_link_reset, |
---|
| 4207 | + .reset = ax88172_link_reset, |
---|
| 4208 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4209 | + .stop = ax88772b_stop, |
---|
| 4210 | + .flags = FLAG_ETHER | FLAG_AVOID_UNLINK_URBS, |
---|
| 4211 | +#else |
---|
| 4212 | + .flags = FLAG_ETHER, |
---|
| 4213 | +#endif |
---|
| 4214 | +}; |
---|
| 4215 | + |
---|
| 4216 | +static const struct driver_info dlink_dub_e100_info = { |
---|
| 4217 | + .description = "DLink DUB-E100 USB Ethernet", |
---|
| 4218 | + .bind = ax8817x_bind, |
---|
| 4219 | + .status = ax8817x_status, |
---|
| 4220 | + .link_reset = ax88172_link_reset, |
---|
| 4221 | + .reset = ax88172_link_reset, |
---|
| 4222 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4223 | + .stop = ax88772b_stop, |
---|
| 4224 | + .flags = FLAG_ETHER | FLAG_AVOID_UNLINK_URBS, |
---|
| 4225 | +#else |
---|
| 4226 | + .flags = FLAG_ETHER, |
---|
| 4227 | +#endif |
---|
| 4228 | +}; |
---|
| 4229 | + |
---|
| 4230 | +static const struct driver_info netgear_fa120_info = { |
---|
| 4231 | + .description = "Netgear FA-120 USB Ethernet", |
---|
| 4232 | + .bind = ax8817x_bind, |
---|
| 4233 | + .status = ax8817x_status, |
---|
| 4234 | + .link_reset = ax88172_link_reset, |
---|
| 4235 | + .reset = ax88172_link_reset, |
---|
| 4236 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4237 | + .stop = ax88772b_stop, |
---|
| 4238 | + .flags = FLAG_ETHER | FLAG_AVOID_UNLINK_URBS, |
---|
| 4239 | +#else |
---|
| 4240 | + .flags = FLAG_ETHER, |
---|
| 4241 | +#endif |
---|
| 4242 | +}; |
---|
| 4243 | + |
---|
| 4244 | +static const struct driver_info hawking_uf200_info = { |
---|
| 4245 | + .description = "Hawking UF200 USB Ethernet", |
---|
| 4246 | + .bind = ax8817x_bind, |
---|
| 4247 | + .status = ax8817x_status, |
---|
| 4248 | + .link_reset = ax88172_link_reset, |
---|
| 4249 | + .reset = ax88172_link_reset, |
---|
| 4250 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4251 | + .stop = ax88772b_stop, |
---|
| 4252 | + .flags = FLAG_ETHER | FLAG_AVOID_UNLINK_URBS, |
---|
| 4253 | +#else |
---|
| 4254 | + .flags = FLAG_ETHER, |
---|
| 4255 | +#endif |
---|
| 4256 | +}; |
---|
| 4257 | + |
---|
| 4258 | +static const struct driver_info ax88772_info = { |
---|
| 4259 | + .description = "ASIX AX88772 USB 2.0 Ethernet", |
---|
| 4260 | + .bind = ax88772_bind, |
---|
| 4261 | + .unbind = ax88772_unbind, |
---|
| 4262 | + .status = ax88772_status, |
---|
| 4263 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4264 | + .stop = ax88772b_stop, |
---|
| 4265 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS, |
---|
| 4266 | +#else |
---|
| 4267 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
---|
| 4268 | +#endif |
---|
| 4269 | + .rx_fixup = ax88772_rx_fixup, |
---|
| 4270 | + .tx_fixup = ax88772_tx_fixup, |
---|
| 4271 | + .reset = ax88772b_reset, |
---|
| 4272 | +}; |
---|
| 4273 | + |
---|
| 4274 | +static const struct driver_info dlink_dub_e100b_info = { |
---|
| 4275 | + .description = "D-Link DUB-E100 USB 2.0 Fast Ethernet Adapter", |
---|
| 4276 | + .bind = ax88772_bind, |
---|
| 4277 | + .unbind = ax88772_unbind, |
---|
| 4278 | + .status = ax88772_status, |
---|
| 4279 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4280 | + .stop = ax88772b_stop, |
---|
| 4281 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS, |
---|
| 4282 | +#else |
---|
| 4283 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
---|
| 4284 | +#endif |
---|
| 4285 | + .rx_fixup = ax88772_rx_fixup, |
---|
| 4286 | + .tx_fixup = ax88772_tx_fixup, |
---|
| 4287 | + .reset = ax88772b_reset, |
---|
| 4288 | +}; |
---|
| 4289 | + |
---|
| 4290 | +static const struct driver_info dlink_dub_e100_772b_info = { |
---|
| 4291 | + .description = "D-Link DUB-E100 USB 2.0 Fast Ethernet Adapter", |
---|
| 4292 | + .bind = ax88772b_bind, |
---|
| 4293 | + .unbind = ax88772b_unbind, |
---|
| 4294 | + .status = ax88772b_status, |
---|
| 4295 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4296 | + .stop = ax88772b_stop, |
---|
| 4297 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT | FLAG_AVOID_UNLINK_URBS, |
---|
| 4298 | +#else |
---|
| 4299 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT, |
---|
| 4300 | +#endif |
---|
| 4301 | + .rx_fixup = ax88772b_rx_fixup, |
---|
| 4302 | + .tx_fixup = ax88772b_tx_fixup, |
---|
| 4303 | + .reset = ax88772b_reset, |
---|
| 4304 | +}; |
---|
| 4305 | + |
---|
| 4306 | +static const struct driver_info dlink_dub_e100_772c_info = { |
---|
| 4307 | + .description = "D-Link DUB-E100 USB 2.0 Fast Ethernet Adapter", |
---|
| 4308 | + .bind = ax88772b_bind, |
---|
| 4309 | + .unbind = ax88772b_unbind, |
---|
| 4310 | + .status = ax88772b_status, |
---|
| 4311 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4312 | + .stop = ax88772b_stop, |
---|
| 4313 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT | FLAG_AVOID_UNLINK_URBS, |
---|
| 4314 | +#else |
---|
| 4315 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT, |
---|
| 4316 | +#endif |
---|
| 4317 | + .rx_fixup = ax88772b_rx_fixup, |
---|
| 4318 | + .tx_fixup = ax88772b_tx_fixup, |
---|
| 4319 | + .reset = ax88772b_reset, |
---|
| 4320 | +}; |
---|
| 4321 | + |
---|
| 4322 | +static const struct driver_info ax88772a_info = { |
---|
| 4323 | + .description = "ASIX AX88772A USB 2.0 Ethernet", |
---|
| 4324 | + .bind = ax88772a_bind, |
---|
| 4325 | + .unbind = ax88772a_unbind, |
---|
| 4326 | + .status = ax88772a_status, |
---|
| 4327 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4328 | + .stop = ax88772b_stop, |
---|
| 4329 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS, |
---|
| 4330 | +#else |
---|
| 4331 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
---|
| 4332 | +#endif |
---|
| 4333 | + .rx_fixup = ax88772_rx_fixup, |
---|
| 4334 | + .tx_fixup = ax88772_tx_fixup, |
---|
| 4335 | + .reset = ax88772b_reset, |
---|
| 4336 | +}; |
---|
| 4337 | + |
---|
| 4338 | +static const struct driver_info ax88772b_info = { |
---|
| 4339 | + .description = "ASIX AX88772B USB 2.0 Ethernet", |
---|
| 4340 | + .bind = ax88772b_bind, |
---|
| 4341 | + .unbind = ax88772b_unbind, |
---|
| 4342 | + .status = ax88772b_status, |
---|
| 4343 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4344 | + .stop = ax88772b_stop, |
---|
| 4345 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT | FLAG_AVOID_UNLINK_URBS, |
---|
| 4346 | +#else |
---|
| 4347 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT, |
---|
| 4348 | +#endif |
---|
| 4349 | + .rx_fixup = ax88772b_rx_fixup, |
---|
| 4350 | + .tx_fixup = ax88772b_tx_fixup, |
---|
| 4351 | + .reset = ax88772b_reset, |
---|
| 4352 | +}; |
---|
| 4353 | + |
---|
| 4354 | +static const struct driver_info ax88772c_info = { |
---|
| 4355 | + .description = "ASIX AX88772C USB 2.0 Ethernet", |
---|
| 4356 | + .bind = ax88772b_bind, |
---|
| 4357 | + .unbind = ax88772b_unbind, |
---|
| 4358 | + .status = ax88772c_status, |
---|
| 4359 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4360 | + .stop = ax88772b_stop, |
---|
| 4361 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT | FLAG_AVOID_UNLINK_URBS, |
---|
| 4362 | +#else |
---|
| 4363 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT, |
---|
| 4364 | +#endif |
---|
| 4365 | + .rx_fixup = ax88772b_rx_fixup, |
---|
| 4366 | + .tx_fixup = ax88772b_tx_fixup, |
---|
| 4367 | + .reset = ax88772b_reset, |
---|
| 4368 | +}; |
---|
| 4369 | + |
---|
| 4370 | +static const struct usb_device_id products[] = { |
---|
| 4371 | +{ |
---|
| 4372 | + /* 88178 */ |
---|
| 4373 | + USB_DEVICE(0x0b95, 0x1780), |
---|
| 4374 | + .driver_info = (unsigned long) &ax88178_info, |
---|
| 4375 | +}, { |
---|
| 4376 | + /* 88178 for billianton linksys */ |
---|
| 4377 | + USB_DEVICE(0x077b, 0x2226), |
---|
| 4378 | + .driver_info = (unsigned long) &ax88178_info, |
---|
| 4379 | +}, { |
---|
| 4380 | + /* ABOCOM for linksys */ |
---|
| 4381 | + USB_DEVICE(0x1737, 0x0039), |
---|
| 4382 | + .driver_info = (unsigned long) &ax88178_info, |
---|
| 4383 | +}, { |
---|
| 4384 | + /* ABOCOM for pci */ |
---|
| 4385 | + USB_DEVICE(0x14ea, 0xab11), |
---|
| 4386 | + .driver_info = (unsigned long) &ax88178_info, |
---|
| 4387 | +}, { |
---|
| 4388 | + /* Belkin */ |
---|
| 4389 | + USB_DEVICE(0x050d, 0x5055), |
---|
| 4390 | + .driver_info = (unsigned long) &belkin178_info, |
---|
| 4391 | +}, { |
---|
| 4392 | + /* Linksys USB200M */ |
---|
| 4393 | + USB_DEVICE(0x077b, 0x2226), |
---|
| 4394 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4395 | +}, { |
---|
| 4396 | + /* Netgear FA120 */ |
---|
| 4397 | + USB_DEVICE(0x0846, 0x1040), |
---|
| 4398 | + .driver_info = (unsigned long) &netgear_fa120_info, |
---|
| 4399 | +}, { |
---|
| 4400 | + /* DLink DUB-E100 */ |
---|
| 4401 | + USB_DEVICE(0x2001, 0x1a00), |
---|
| 4402 | + .driver_info = (unsigned long) &dlink_dub_e100_info, |
---|
| 4403 | +}, { |
---|
| 4404 | + /* DLink DUB-E100B */ |
---|
| 4405 | + USB_DEVICE(0x2001, 0x3c05), |
---|
| 4406 | + .driver_info = (unsigned long) &dlink_dub_e100b_info, |
---|
| 4407 | +}, { |
---|
| 4408 | + /* DLink DUB-E100B */ |
---|
| 4409 | + USB_DEVICE(0x07d1, 0x3c05), |
---|
| 4410 | + .driver_info = (unsigned long) &dlink_dub_e100b_info, |
---|
| 4411 | +}, { |
---|
| 4412 | + /* DLink DUB-E100 (AX88772B)*/ |
---|
| 4413 | + USB_DEVICE_VER(0x2001, 0x1a02, 0, 1), |
---|
| 4414 | + .driver_info = (unsigned long) &dlink_dub_e100_772b_info, |
---|
| 4415 | +}, { |
---|
| 4416 | + /* DLink DUB-E100 (AX88772C)*/ |
---|
| 4417 | + USB_DEVICE_VER(0x2001, 0x1a02, 0, 2), |
---|
| 4418 | + .driver_info = (unsigned long) &dlink_dub_e100_772c_info, |
---|
| 4419 | +}, { |
---|
| 4420 | + /* Intellinet, ST Lab USB Ethernet */ |
---|
| 4421 | + USB_DEVICE(0x0b95, 0x1720), |
---|
| 4422 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4423 | +}, { |
---|
| 4424 | + /* Hawking UF200, TrendNet TU2-ET100 */ |
---|
| 4425 | + USB_DEVICE(0x07b8, 0x420a), |
---|
| 4426 | + .driver_info = (unsigned long) &hawking_uf200_info, |
---|
| 4427 | +}, { |
---|
| 4428 | + /* Billionton Systems, USB2AR */ |
---|
| 4429 | + USB_DEVICE(0x08dd, 0x90ff), |
---|
| 4430 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4431 | +}, { |
---|
| 4432 | + /* ATEN UC210T */ |
---|
| 4433 | + USB_DEVICE(0x0557, 0x2009), |
---|
| 4434 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4435 | +}, { |
---|
| 4436 | + /* Buffalo LUA-U2-KTX */ |
---|
| 4437 | + USB_DEVICE(0x0411, 0x003d), |
---|
| 4438 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4439 | +}, { |
---|
| 4440 | + /* Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" */ |
---|
| 4441 | + USB_DEVICE(0x6189, 0x182d), |
---|
| 4442 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4443 | +}, { |
---|
| 4444 | + /* corega FEther USB2-TX */ |
---|
| 4445 | + USB_DEVICE(0x07aa, 0x0017), |
---|
| 4446 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4447 | +}, { |
---|
| 4448 | + /* Surecom EP-1427X-2 */ |
---|
| 4449 | + USB_DEVICE(0x1189, 0x0893), |
---|
| 4450 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4451 | +}, { |
---|
| 4452 | + /* goodway corp usb gwusb2e */ |
---|
| 4453 | + USB_DEVICE(0x1631, 0x6200), |
---|
| 4454 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4455 | +}, { |
---|
| 4456 | + /* ASIX AX88772 10/100 */ |
---|
| 4457 | + USB_DEVICE(0x0b95, 0x7720), |
---|
| 4458 | + .driver_info = (unsigned long) &ax88772_info, |
---|
| 4459 | +}, { |
---|
| 4460 | + /* ASIX AX88772 10/100 */ |
---|
| 4461 | + USB_DEVICE(0x125E, 0x180D), |
---|
| 4462 | + .driver_info = (unsigned long) &ax88772_info, |
---|
| 4463 | +}, { |
---|
| 4464 | + /* ASIX AX88772A 10/100 */ |
---|
| 4465 | + USB_DEVICE(0x0b95, 0x772A), |
---|
| 4466 | + .driver_info = (unsigned long) &ax88772a_info, |
---|
| 4467 | +}, { |
---|
| 4468 | + /* ASIX AX88772A 10/100 */ |
---|
| 4469 | + USB_DEVICE(0x0db0, 0xA877), |
---|
| 4470 | + .driver_info = (unsigned long) &ax88772a_info, |
---|
| 4471 | +}, { |
---|
| 4472 | + /* ASIX AX88772A 10/100 */ |
---|
| 4473 | + USB_DEVICE(0x0421, 0x772A), |
---|
| 4474 | + .driver_info = (unsigned long) &ax88772a_info, |
---|
| 4475 | +}, { |
---|
| 4476 | + /* Linksys 200M */ |
---|
| 4477 | + USB_DEVICE(0x13B1, 0x0018), |
---|
| 4478 | + .driver_info = (unsigned long) &ax88772a_info, |
---|
| 4479 | +}, { |
---|
| 4480 | + USB_DEVICE(0x05ac, 0x1402), |
---|
| 4481 | + .driver_info = (unsigned long) &ax88772a_info, |
---|
| 4482 | +}, { |
---|
| 4483 | + /* ASIX AX88772B 10/100 */ |
---|
| 4484 | + USB_DEVICE_VER(0x0b95, 0x772B, 0, 1), |
---|
| 4485 | + .driver_info = (unsigned long) &ax88772b_info, |
---|
| 4486 | +}, { |
---|
| 4487 | + /* Asus AX88772B 10/100 */ |
---|
| 4488 | + USB_DEVICE_VER(0x0b95, 0x7e2b, 0, 1), |
---|
| 4489 | + .driver_info = (unsigned long) &ax88772b_info, |
---|
| 4490 | +}, { |
---|
| 4491 | + /* Lenovo AX88772B 10/100 */ |
---|
| 4492 | + USB_DEVICE_VER(0x17ef, 0x7203, 0, 1), |
---|
| 4493 | + .driver_info = (unsigned long) &ax88772b_info, |
---|
| 4494 | +},{ |
---|
| 4495 | + /* ASIX AX88772B ver.2 10/100 */ |
---|
| 4496 | + USB_DEVICE_VER(0x0b95, 0x772B, 0, 2), |
---|
| 4497 | + .driver_info = (unsigned long) &ax88772c_info, |
---|
| 4498 | +}, |
---|
| 4499 | + { }, /* END */ |
---|
| 4500 | +}; |
---|
| 4501 | +MODULE_DEVICE_TABLE(usb, products); |
---|
| 4502 | + |
---|
| 4503 | +static struct usb_driver asix_driver = { |
---|
| 4504 | + /* .owner = THIS_MODULE, */ |
---|
| 4505 | + .name = "asix", |
---|
| 4506 | + .id_table = products, |
---|
| 4507 | + .probe = axusbnet_probe, |
---|
| 4508 | + .suspend = ax_suspend, |
---|
| 4509 | + .resume = ax_resume, |
---|
| 4510 | + .disconnect = axusbnet_disconnect, |
---|
| 4511 | +}; |
---|
| 4512 | + |
---|
| 4513 | +static int __init asix_init(void) |
---|
| 4514 | +{ |
---|
| 4515 | + return usb_register(&asix_driver); |
---|
| 4516 | +} |
---|
| 4517 | +module_init(asix_init); |
---|
| 4518 | + |
---|
| 4519 | +static void __exit asix_exit(void) |
---|
| 4520 | +{ |
---|
| 4521 | + usb_deregister(&asix_driver); |
---|
| 4522 | +} |
---|
| 4523 | +module_exit(asix_exit); |
---|
| 4524 | + |
---|
| 4525 | +MODULE_AUTHOR("David Hollis"); |
---|
| 4526 | +MODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); |
---|
| 4527 | +MODULE_LICENSE("GPL"); |
---|
| 4528 | + |
---|
.. | .. |
---|
| 1 | +#ifndef __LINUX_USBNET_ASIX_H |
---|
| 2 | +#define __LINUX_USBNET_ASIX_H |
---|
| 3 | + |
---|
| 4 | +/* |
---|
| 5 | + * Turn on this flag if the implementation of your USB host controller |
---|
| 6 | + * cannot handle non-double word aligned buffer. |
---|
| 7 | + * When turn on this flag, driver will fixup egress packet aligned on double |
---|
| 8 | + * word boundary before deliver to USB host controller. And will Disable the |
---|
| 9 | + * function "skb_reserve (skb, NET_IP_ALIGN)" to retain the buffer aligned on |
---|
| 10 | + * double word alignment for ingress packets. |
---|
| 11 | + */ |
---|
| 12 | +#define AX_FORCE_BUFF_ALIGN 0 |
---|
| 13 | + |
---|
| 14 | +//#define RX_SKB_COPY |
---|
| 15 | + |
---|
| 16 | +#define AX_MONITOR_MODE 0x01 |
---|
| 17 | +#define AX_MONITOR_LINK 0x02 |
---|
| 18 | +#define AX_MONITOR_MAGIC 0x04 |
---|
| 19 | +#define AX_MONITOR_HSFS 0x10 |
---|
| 20 | + |
---|
| 21 | +/* AX88172 Medium Status Register values */ |
---|
| 22 | +#define AX_MEDIUM_FULL_DUPLEX 0x02 |
---|
| 23 | +#define AX_MEDIUM_TX_ABORT_ALLOW 0x04 |
---|
| 24 | +#define AX_MEDIUM_FLOW_CONTROL_EN 0x10 |
---|
| 25 | +#define AX_MCAST_FILTER_SIZE 8 |
---|
| 26 | +#define AX_MAX_MCAST 64 |
---|
| 27 | + |
---|
| 28 | +#define AX_EEPROM_LEN 0x40 |
---|
| 29 | + |
---|
| 30 | +#define AX_SWRESET_CLEAR 0x00 |
---|
| 31 | +#define AX_SWRESET_RR 0x01 |
---|
| 32 | +#define AX_SWRESET_RT 0x02 |
---|
| 33 | +#define AX_SWRESET_PRTE 0x04 |
---|
| 34 | +#define AX_SWRESET_PRL 0x08 |
---|
| 35 | +#define AX_SWRESET_BZ 0x10 |
---|
| 36 | +#define AX_SWRESET_IPRL 0x20 |
---|
| 37 | +#define AX_SWRESET_IPPD 0x40 |
---|
| 38 | +#define AX_SWRESET_IPOSC 0x0080 |
---|
| 39 | +#define AX_SWRESET_IPPSL_0 0x0100 |
---|
| 40 | +#define AX_SWRESET_IPPSL_1 0x0200 |
---|
| 41 | +#define AX_SWRESET_IPCOPS 0x0400 |
---|
| 42 | +#define AX_SWRESET_IPCOPSC 0x0800 |
---|
| 43 | +#define AX_SWRESET_AUTODETACH 0x1000 |
---|
| 44 | +#define AX_SWRESET_WOLLP 0x8000 |
---|
| 45 | + |
---|
| 46 | +#define AX88772_IPG0_DEFAULT 0x15 |
---|
| 47 | +#define AX88772_IPG1_DEFAULT 0x0c |
---|
| 48 | +#define AX88772_IPG2_DEFAULT 0x0E |
---|
| 49 | + |
---|
| 50 | +#define AX88772A_IPG0_DEFAULT 0x15 |
---|
| 51 | +#define AX88772A_IPG1_DEFAULT 0x16 |
---|
| 52 | +#define AX88772A_IPG2_DEFAULT 0x1A |
---|
| 53 | + |
---|
| 54 | +#define AX88772_MEDIUM_FULL_DUPLEX 0x0002 |
---|
| 55 | +#define AX88772_MEDIUM_RESERVED 0x0004 |
---|
| 56 | +#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010 |
---|
| 57 | +#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020 |
---|
| 58 | +#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080 |
---|
| 59 | +#define AX88772_MEDIUM_RX_ENABLE 0x0100 |
---|
| 60 | +#define AX88772_MEDIUM_100MB 0x0200 |
---|
| 61 | +#define AX88772_MEDIUM_DEFAULT \ |
---|
| 62 | + (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \ |
---|
| 63 | + AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \ |
---|
| 64 | + AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE) |
---|
| 65 | + |
---|
| 66 | +#define AX_CMD_SET_SW_MII 0x06 |
---|
| 67 | +#define AX_CMD_READ_MII_REG 0x07 |
---|
| 68 | +#define AX_CMD_WRITE_MII_REG 0x08 |
---|
| 69 | +#define AX_CMD_READ_STATMNGSTS_REG 0x09 |
---|
| 70 | + #define AX_HOST_EN 0x01 |
---|
| 71 | + |
---|
| 72 | +#define AX_CMD_SET_HW_MII 0x0a |
---|
| 73 | +#define AX_CMD_READ_EEPROM 0x0b |
---|
| 74 | +#define AX_CMD_WRITE_EEPROM 0x0c |
---|
| 75 | +#define AX_CMD_WRITE_EEPROM_EN 0x0d |
---|
| 76 | +#define AX_CMD_WRITE_EEPROM_DIS 0x0e |
---|
| 77 | +#define AX_CMD_WRITE_RX_CTL 0x10 |
---|
| 78 | +#define AX_CMD_READ_IPG012 0x11 |
---|
| 79 | +#define AX_CMD_WRITE_IPG0 0x12 |
---|
| 80 | +#define AX_CMD_WRITE_IPG1 0x13 |
---|
| 81 | +#define AX_CMD_WRITE_IPG2 0x14 |
---|
| 82 | +#define AX_CMD_WRITE_MULTI_FILTER 0x16 |
---|
| 83 | +#define AX_CMD_READ_NODE_ID 0x17 |
---|
| 84 | +#define AX_CMD_READ_PHY_ID 0x19 |
---|
| 85 | +#define AX_CMD_READ_MEDIUM_MODE 0x1a |
---|
| 86 | +#define AX_CMD_WRITE_MEDIUM_MODE 0x1b |
---|
| 87 | +#define AX_CMD_READ_MONITOR_MODE 0x1c |
---|
| 88 | +#define AX_CMD_WRITE_MONITOR_MODE 0x1d |
---|
| 89 | +#define AX_CMD_WRITE_GPIOS 0x1f |
---|
| 90 | +#define AX_CMD_SW_RESET 0x20 |
---|
| 91 | +#define AX_CMD_SW_PHY_STATUS 0x21 |
---|
| 92 | +#define AX_CMD_SW_PHY_SELECT 0x22 |
---|
| 93 | + #define AX_PHYSEL_PSEL (1 << 0) |
---|
| 94 | + #define AX_PHYSEL_ASEL (1 << 1) |
---|
| 95 | + #define AX_PHYSEL_SSMII (0 << 2) |
---|
| 96 | + #define AX_PHYSEL_SSRMII (1 << 2) |
---|
| 97 | + #define AX_PHYSEL_SSRRMII (3 << 2) |
---|
| 98 | + #define AX_PHYSEL_SSEN (1 << 4) |
---|
| 99 | +#define AX88772_CMD_READ_NODE_ID 0x13 |
---|
| 100 | +#define AX88772_CMD_WRITE_NODE_ID 0x14 |
---|
| 101 | +#define AX_CMD_READ_WKFARY 0x23 |
---|
| 102 | +#define AX_CMD_WRITE_WKFARY 0x24 |
---|
| 103 | +#define AX_CMD_READ_RXCOE_CTL 0x2b |
---|
| 104 | +#define AX_CMD_WRITE_RXCOE_CTL 0x2c |
---|
| 105 | +#define AX_CMD_READ_TXCOE_CTL 0x2d |
---|
| 106 | +#define AX_CMD_WRITE_TXCOE_CTL 0x2e |
---|
| 107 | + |
---|
| 108 | +#define REG_LENGTH 2 |
---|
| 109 | +#define PHY_ID_MASK 0x1f |
---|
| 110 | + |
---|
| 111 | +#define AX_RXCOE_IPCE 0x0001 |
---|
| 112 | +#define AX_RXCOE_IPVE 0x0002 |
---|
| 113 | +#define AX_RXCOE_V6VE 0x0004 |
---|
| 114 | +#define AX_RXCOE_TCPE 0x0008 |
---|
| 115 | +#define AX_RXCOE_UDPE 0x0010 |
---|
| 116 | +#define AX_RXCOE_ICMP 0x0020 |
---|
| 117 | +#define AX_RXCOE_IGMP 0x0040 |
---|
| 118 | +#define AX_RXCOE_ICV6 0x0080 |
---|
| 119 | +#define AX_RXCOE_TCPV6 0x0100 |
---|
| 120 | +#define AX_RXCOE_UDPV6 0x0200 |
---|
| 121 | +#define AX_RXCOE_ICMV6 0x0400 |
---|
| 122 | +#define AX_RXCOE_IGMV6 0x0800 |
---|
| 123 | +#define AX_RXCOE_ICV6V6 0x1000 |
---|
| 124 | +#define AX_RXCOE_FOPC 0x8000 |
---|
| 125 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) |
---|
| 126 | +#define AX_RXCOE_DEF_CSUM (AX_RXCOE_IPCE | AX_RXCOE_IPVE | \ |
---|
| 127 | + AX_RXCOE_V6VE | AX_RXCOE_TCPE | \ |
---|
| 128 | + AX_RXCOE_UDPE | AX_RXCOE_ICV6 | \ |
---|
| 129 | + AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6) |
---|
| 130 | +#else |
---|
| 131 | +#define AX_RXCOE_DEF_CSUM (AX_RXCOE_IPCE | AX_RXCOE_IPVE | \ |
---|
| 132 | + AX_RXCOE_TCPE | AX_RXCOE_UDPE) |
---|
| 133 | +#endif |
---|
| 134 | + |
---|
| 135 | +#define AX_RXCOE_64TE 0x0100 |
---|
| 136 | +#define AX_RXCOE_PPPOE 0x0200 |
---|
| 137 | +#define AX_RXCOE_RPCE 0x8000 |
---|
| 138 | + |
---|
| 139 | +#define AX_TXCOE_IP 0x0001 |
---|
| 140 | +#define AX_TXCOE_TCP 0x0002 |
---|
| 141 | +#define AX_TXCOE_UDP 0x0004 |
---|
| 142 | +#define AX_TXCOE_ICMP 0x0008 |
---|
| 143 | +#define AX_TXCOE_IGMP 0x0010 |
---|
| 144 | +#define AX_TXCOE_ICV6 0x0020 |
---|
| 145 | + |
---|
| 146 | +#define AX_TXCOE_TCPV6 0x0100 |
---|
| 147 | +#define AX_TXCOE_UDPV6 0x0200 |
---|
| 148 | +#define AX_TXCOE_ICMV6 0x0400 |
---|
| 149 | +#define AX_TXCOE_IGMV6 0x0800 |
---|
| 150 | +#define AX_TXCOE_ICV6V6 0x1000 |
---|
| 151 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) |
---|
| 152 | +#define AX_TXCOE_DEF_CSUM (AX_TXCOE_TCP | AX_TXCOE_UDP | \ |
---|
| 153 | + AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6) |
---|
| 154 | +#else |
---|
| 155 | +#define AX_TXCOE_DEF_CSUM (AX_TXCOE_TCP | AX_TXCOE_UDP) |
---|
| 156 | +#endif |
---|
| 157 | + |
---|
| 158 | +#define AX_TXCOE_64TE 0x0001 |
---|
| 159 | +#define AX_TXCOE_PPPE 0x0002 |
---|
| 160 | + |
---|
| 161 | +#define AX88772B_MAX_BULKIN_2K 0 |
---|
| 162 | +#define AX88772B_MAX_BULKIN_4K 1 |
---|
| 163 | +#define AX88772B_MAX_BULKIN_6K 2 |
---|
| 164 | +#define AX88772B_MAX_BULKIN_8K 3 |
---|
| 165 | +#define AX88772B_MAX_BULKIN_16K 4 |
---|
| 166 | +#define AX88772B_MAX_BULKIN_20K 5 |
---|
| 167 | +#define AX88772B_MAX_BULKIN_24K 6 |
---|
| 168 | +#define AX88772B_MAX_BULKIN_32K 7 |
---|
| 169 | +struct {unsigned short size, byte_cnt, threshold; } AX88772B_BULKIN_SIZE[] = { |
---|
| 170 | + /* 2k */ |
---|
| 171 | + {2048, 0x8000, 0x8001}, |
---|
| 172 | + /* 4k */ |
---|
| 173 | + {4096, 0x8100, 0x8147}, |
---|
| 174 | + /* 6k */ |
---|
| 175 | + {6144, 0x8200, 0x81EB}, |
---|
| 176 | + /* 8k */ |
---|
| 177 | + {8192, 0x8300, 0x83D7}, |
---|
| 178 | + /* 16 */ |
---|
| 179 | + {16384, 0x8400, 0x851E}, |
---|
| 180 | + /* 20k */ |
---|
| 181 | + {20480, 0x8500, 0x8666}, |
---|
| 182 | + /* 24k */ |
---|
| 183 | + {24576, 0x8600, 0x87AE}, |
---|
| 184 | + /* 32k */ |
---|
| 185 | + {32768, 0x8700, 0x8A3D}, |
---|
| 186 | +}; |
---|
| 187 | + |
---|
| 188 | + |
---|
| 189 | +#define AX_RX_CTL_RH1M 0x0100 /* Enable RX-Header mode 0 */ |
---|
| 190 | +#define AX_RX_CTL_RH2M 0x0200 /* Enable IP header in receive buffer aligned on 32-bit aligment */ |
---|
| 191 | +#define AX_RX_CTL_RH3M 0x0400 /* checksum value in rx header 3 */ |
---|
| 192 | +#define AX_RX_HEADER_DEFAULT (AX_RX_CTL_RH1M | AX_RX_CTL_RH2M) |
---|
| 193 | + |
---|
| 194 | +#define AX_RX_CTL_MFB 0x0300 /* Maximum Frame size 16384bytes */ |
---|
| 195 | +#define AX_RX_CTL_START 0x0080 /* Ethernet MAC start */ |
---|
| 196 | +#define AX_RX_CTL_AP 0x0020 /* Accept physcial address from Multicast array */ |
---|
| 197 | +#define AX_RX_CTL_AM 0x0010 |
---|
| 198 | +#define AX_RX_CTL_AB 0x0008 /* Accetp Brocadcast frames*/ |
---|
| 199 | +#define AX_RX_CTL_SEP 0x0004 /* Save error packets */ |
---|
| 200 | +#define AX_RX_CTL_AMALL 0x0002 /* Accetp all multicast frames */ |
---|
| 201 | +#define AX_RX_CTL_PRO 0x0001 /* Promiscuous Mode */ |
---|
| 202 | +#define AX_RX_CTL_STOP 0x0000 /* Stop MAC */ |
---|
| 203 | + |
---|
| 204 | +#define AX_MONITOR_MODE 0x01 |
---|
| 205 | +#define AX_MONITOR_LINK 0x02 |
---|
| 206 | +#define AX_MONITOR_MAGIC 0x04 |
---|
| 207 | +#define AX_MONITOR_HSFS 0x10 |
---|
| 208 | + |
---|
| 209 | +#define AX_MCAST_FILTER_SIZE 8 |
---|
| 210 | +#define AX_MAX_MCAST 64 |
---|
| 211 | +#define AX_INTERRUPT_BUFSIZE 8 |
---|
| 212 | + |
---|
| 213 | +#define AX_EEPROM_LEN 0x40 |
---|
| 214 | +#define AX_EEPROM_MAGIC 0xdeadbeef |
---|
| 215 | +#define EEPROMMASK 0x7f |
---|
| 216 | + |
---|
| 217 | +/* GPIO REGISTER */ |
---|
| 218 | +#define AXGPIOS_GPO0EN 0X01 /* 1 << 0 */ |
---|
| 219 | +#define AXGPIOS_GPO0 0X02 /* 1 << 1 */ |
---|
| 220 | +#define AXGPIOS_GPO1EN 0X04 /* 1 << 2 */ |
---|
| 221 | +#define AXGPIOS_GPO1 0X08 /* 1 << 3 */ |
---|
| 222 | +#define AXGPIOS_GPO2EN 0X10 /* 1 << 4 */ |
---|
| 223 | +#define AXGPIOS_GPO2 0X20 /* 1 << 5 */ |
---|
| 224 | +#define AXGPIOS_RSE 0X80 /* 1 << 7 */ |
---|
| 225 | + |
---|
| 226 | +/* TX-header format */ |
---|
| 227 | +#define AX_TX_HDR_CPHI 0x4000 |
---|
| 228 | +#define AX_TX_HDR_DICF 0x8000 |
---|
| 229 | + |
---|
| 230 | +/* GMII register definitions */ |
---|
| 231 | +#define GMII_PHY_CONTROL 0x00 /* control reg */ |
---|
| 232 | +#define GMII_PHY_STATUS 0x01 /* status reg */ |
---|
| 233 | +#define GMII_PHY_OUI 0x02 /* most of the OUI bits */ |
---|
| 234 | +#define GMII_PHY_MODEL 0x03 /* model/rev bits, and rest of OUI */ |
---|
| 235 | +#define GMII_PHY_ANAR 0x04 /* AN advertisement reg */ |
---|
| 236 | +#define GMII_PHY_ANLPAR 0x05 /* AN Link Partner */ |
---|
| 237 | +#define GMII_PHY_ANER 0x06 /* AN expansion reg */ |
---|
| 238 | +#define GMII_PHY_1000BT_CONTROL 0x09 /* control reg for 1000BT */ |
---|
| 239 | +#define GMII_PHY_1000BT_STATUS 0x0A /* status reg for 1000BT */ |
---|
| 240 | + |
---|
| 241 | +/* Bit definitions: GMII Control */ |
---|
| 242 | +#define GMII_CONTROL_RESET 0x8000 /* reset bit in control reg */ |
---|
| 243 | +#define GMII_CONTROL_LOOPBACK 0x4000 /* loopback bit in control reg */ |
---|
| 244 | +#define GMII_CONTROL_10MB 0x0000 /* 10 Mbit */ |
---|
| 245 | +#define GMII_CONTROL_100MB 0x2000 /* 100Mbit */ |
---|
| 246 | +#define GMII_CONTROL_1000MB 0x0040 /* 1000Mbit */ |
---|
| 247 | +#define GMII_CONTROL_SPEED_BITS 0x2040 /* speed bit mask */ |
---|
| 248 | +#define GMII_CONTROL_ENABLE_AUTO 0x1000 /* autonegotiate enable */ |
---|
| 249 | +#define GMII_CONTROL_POWER_DOWN 0x0800 |
---|
| 250 | +#define GMII_CONTROL_ISOLATE 0x0400 /* islolate bit */ |
---|
| 251 | +#define GMII_CONTROL_START_AUTO 0x0200 /* restart autonegotiate */ |
---|
| 252 | +#define GMII_CONTROL_FULL_DUPLEX 0x0100 |
---|
| 253 | + |
---|
| 254 | +/* Bit definitions: GMII Status */ |
---|
| 255 | +#define GMII_STATUS_100MB_MASK 0xE000 /* any of these indicate 100 Mbit */ |
---|
| 256 | +#define GMII_STATUS_10MB_MASK 0x1800 /* either of these indicate 10 Mbit */ |
---|
| 257 | +#define GMII_STATUS_AUTO_DONE 0x0020 /* auto negotiation complete */ |
---|
| 258 | +#define GMII_STATUS_AUTO 0x0008 /* auto negotiation is available */ |
---|
| 259 | +#define GMII_STATUS_LINK_UP 0x0004 /* link status bit */ |
---|
| 260 | +#define GMII_STATUS_EXTENDED 0x0001 /* extended regs exist */ |
---|
| 261 | +#define GMII_STATUS_100T4 0x8000 /* capable of 100BT4 */ |
---|
| 262 | +#define GMII_STATUS_100TXFD 0x4000 /* capable of 100BTX full duplex */ |
---|
| 263 | +#define GMII_STATUS_100TX 0x2000 /* capable of 100BTX */ |
---|
| 264 | +#define GMII_STATUS_10TFD 0x1000 /* capable of 10BT full duplex */ |
---|
| 265 | +#define GMII_STATUS_10T 0x0800 /* capable of 10BT */ |
---|
| 266 | + |
---|
| 267 | +/* Bit definitions: Auto-Negotiation Advertisement */ |
---|
| 268 | +#define GMII_ANAR_ASYM_PAUSE 0x0800 /* support asymetric pause */ |
---|
| 269 | +#define GMII_ANAR_PAUSE 0x0400 /* support pause packets */ |
---|
| 270 | +#define GMII_ANAR_100T4 0x0200 /* support 100BT4 */ |
---|
| 271 | +#define GMII_ANAR_100TXFD 0x0100 /* support 100BTX full duplex */ |
---|
| 272 | +#define GMII_ANAR_100TX 0x0080 /* support 100BTX half duplex */ |
---|
| 273 | +#define GMII_ANAR_10TFD 0x0040 /* support 10BT full duplex */ |
---|
| 274 | +#define GMII_ANAR_10T 0x0020 /* support 10BT half duplex */ |
---|
| 275 | +#define GMII_SELECTOR_FIELD 0x001F /* selector field. */ |
---|
| 276 | + |
---|
| 277 | +/* Bit definitions: Auto-Negotiation Link Partner Ability */ |
---|
| 278 | +#define GMII_ANLPAR_100T4 0x0200 /* support 100BT4 */ |
---|
| 279 | +#define GMII_ANLPAR_100TXFD 0x0100 /* support 100BTX full duplex */ |
---|
| 280 | +#define GMII_ANLPAR_100TX 0x0080 /* support 100BTX half duplex */ |
---|
| 281 | +#define GMII_ANLPAR_10TFD 0x0040 /* support 10BT full duplex */ |
---|
| 282 | +#define GMII_ANLPAR_10T 0x0020 /* support 10BT half duplex */ |
---|
| 283 | +#define GMII_ANLPAR_PAUSE 0x0400 /* support pause packets */ |
---|
| 284 | +#define GMII_ANLPAR_ASYM_PAUSE 0x0800 /* support asymetric pause */ |
---|
| 285 | +#define GMII_ANLPAR_ACK 0x4000 /* means LCB was successfully rx'd */ |
---|
| 286 | +#define GMII_SELECTOR_8023 0x0001; |
---|
| 287 | + |
---|
| 288 | +/* Bit definitions: 1000BaseT AUX Control */ |
---|
| 289 | +#define GMII_1000_AUX_CTRL_MASTER_SLAVE 0x1000 |
---|
| 290 | +#define GMII_1000_AUX_CTRL_FD_CAPABLE 0x0200 /* full duplex capable */ |
---|
| 291 | +#define GMII_1000_AUX_CTRL_HD_CAPABLE 0x0100 /* half duplex capable */ |
---|
| 292 | + |
---|
| 293 | +/* Bit definitions: 1000BaseT AUX Status */ |
---|
| 294 | +#define GMII_1000_AUX_STATUS_FD_CAPABLE 0x0800 /* full duplex capable */ |
---|
| 295 | +#define GMII_1000_AUX_STATUS_HD_CAPABLE 0x0400 /* half duplex capable */ |
---|
| 296 | + |
---|
| 297 | +/* Cicada MII Registers */ |
---|
| 298 | +#define GMII_AUX_CTRL_STATUS 0x1C |
---|
| 299 | +#define GMII_AUX_ANEG_CPLT 0x8000 |
---|
| 300 | +#define GMII_AUX_FDX 0x0020 |
---|
| 301 | +#define GMII_AUX_SPEED_1000 0x0010 |
---|
| 302 | +#define GMII_AUX_SPEED_100 0x0008 |
---|
| 303 | + |
---|
| 304 | +#ifndef ADVERTISE_PAUSE_CAP |
---|
| 305 | +#define ADVERTISE_PAUSE_CAP 0x0400 |
---|
| 306 | +#endif |
---|
| 307 | + |
---|
| 308 | +#ifndef MII_STAT1000 |
---|
| 309 | +#define MII_STAT1000 0x000A |
---|
| 310 | +#endif |
---|
| 311 | + |
---|
| 312 | +#ifndef LPA_1000FULL |
---|
| 313 | +#define LPA_1000FULL 0x0800 |
---|
| 314 | +#endif |
---|
| 315 | + |
---|
| 316 | +/* medium mode register */ |
---|
| 317 | +#define MEDIUM_GIGA_MODE 0x0001 |
---|
| 318 | +#define MEDIUM_FULL_DUPLEX_MODE 0x0002 |
---|
| 319 | +#define MEDIUM_TX_ABORT_MODE 0x0004 |
---|
| 320 | +#define MEDIUM_ENABLE_125MHZ 0x0008 |
---|
| 321 | +#define MEDIUM_ENABLE_RX_FLOWCTRL 0x0010 |
---|
| 322 | +#define MEDIUM_ENABLE_TX_FLOWCTRL 0x0020 |
---|
| 323 | +#define MEDIUM_ENABLE_JUMBO_FRAME 0x0040 |
---|
| 324 | +#define MEDIUM_CHECK_PAUSE_FRAME_MODE 0x0080 |
---|
| 325 | +#define MEDIUM_ENABLE_RECEIVE 0x0100 |
---|
| 326 | +#define MEDIUM_MII_100M_MODE 0x0200 |
---|
| 327 | +#define MEDIUM_ENABLE_JAM_PATTERN 0x0400 |
---|
| 328 | +#define MEDIUM_ENABLE_STOP_BACKPRESSURE 0x0800 |
---|
| 329 | +#define MEDIUM_ENABLE_SUPPER_MAC_SUPPORT 0x1000 |
---|
| 330 | + |
---|
| 331 | +/* PHY mode */ |
---|
| 332 | +#define PHY_MODE_MARVELL 0 |
---|
| 333 | +#define PHY_MODE_CICADA_FAMILY 1 |
---|
| 334 | +#define PHY_MODE_CICADA_V1 1 |
---|
| 335 | +#define PHY_MODE_AGERE_FAMILY 2 |
---|
| 336 | +#define PHY_MODE_AGERE_V0 2 |
---|
| 337 | +#define PHY_MODE_CICADA_V2 5 |
---|
| 338 | +#define PHY_MODE_AGERE_V0_GMII 6 |
---|
| 339 | +#define PHY_MODE_CICADA_V2_ASIX 9 |
---|
| 340 | +#define PHY_MODE_VSC8601 10 |
---|
| 341 | +#define PHY_MODE_RTL8211CL 12 |
---|
| 342 | +#define PHY_MODE_RTL8211BN 13 |
---|
| 343 | +#define PHY_MODE_RTL8251CL 14 |
---|
| 344 | +#define PHY_MODE_ATTANSIC_V0 0x40 |
---|
| 345 | +#define PHY_MODE_ATTANSIC_FAMILY 0x40 |
---|
| 346 | +#define PHY_MODE_MAC_TO_MAC_GMII 0x7C |
---|
| 347 | + |
---|
| 348 | +/* */ |
---|
| 349 | +#define LED_MODE_MARVELL 0 |
---|
| 350 | +#define LED_MODE_CAMEO 1 |
---|
| 351 | + |
---|
| 352 | +#define MARVELL_LED_CTRL 0x18 |
---|
| 353 | +#define MARVELL_MANUAL_LED 0x19 |
---|
| 354 | + |
---|
| 355 | +#define PHY_IDENTIFIER 0x0002 |
---|
| 356 | +#define PHY_AGERE_IDENTIFIER 0x0282 |
---|
| 357 | +#define PHY_CICADA_IDENTIFIER 0x000f |
---|
| 358 | +#define PHY_MARVELL_IDENTIFIER 0x0141 |
---|
| 359 | + |
---|
| 360 | +#define PHY_MARVELL_STATUS 0x001b |
---|
| 361 | +#define MARVELL_STATUS_HWCFG 0x0004 /* SGMII without clock */ |
---|
| 362 | + |
---|
| 363 | +#define PHY_MARVELL_CTRL 0x0014 |
---|
| 364 | +#define MARVELL_CTRL_RXDELAY 0x0080 |
---|
| 365 | +#define MARVELL_CTRL_TXDELAY 0x0002 |
---|
| 366 | + |
---|
| 367 | +#define PHY_CICADA_EXTPAGE 0x001f |
---|
| 368 | +#define CICADA_EXTPAGE_EN 0x0001 |
---|
| 369 | +#define CICADA_EXTPAGE_DIS 0x0000 |
---|
| 370 | + |
---|
| 371 | +/* External ethernet phy */ |
---|
| 372 | +#define EXTPHY_ID_MASK_OUI(phyid1, phyid2) ((phyid1 << 6) | ((phyid2 & 0xFC00) >> 10)) |
---|
| 373 | +#define EXTPHY_ID_MASK_MODEL(phyid2) ((phyid2 & 0x3F0) >> 4) |
---|
| 374 | + |
---|
| 375 | +#define EXTPHY_BROADCOM_OUI 0x2B8094 |
---|
| 376 | +#define EXTPHY_BCM89811_MODEL 0x02 |
---|
| 377 | + |
---|
| 378 | +struct {unsigned short value, offset; } CICADA_FAMILY_HWINIT[] = { |
---|
| 379 | + {0x0001, 0x001f}, {0x1c25, 0x0017}, {0x2a30, 0x001f}, {0x234c, 0x0010}, |
---|
| 380 | + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0xa7fa, 0x0000}, |
---|
| 381 | + {0x0012, 0x0002}, {0x3002, 0x0001}, {0x87fa, 0x0000}, {0x52b5, 0x001f}, |
---|
| 382 | + {0xafac, 0x0000}, {0x000d, 0x0002}, {0x001c, 0x0001}, {0x8fac, 0x0000}, |
---|
| 383 | + {0x2a30, 0x001f}, {0x0012, 0x0008}, {0x2a30, 0x001f}, {0x0400, 0x0014}, |
---|
| 384 | + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0xa760, 0x0000}, |
---|
| 385 | + {0x0000, 0x0002}, {0xfaff, 0x0001}, {0x8760, 0x0000}, {0x52b5, 0x001f}, |
---|
| 386 | + {0xa760, 0x0000}, {0x0000, 0x0002}, {0xfaff, 0x0001}, {0x8760, 0x0000}, |
---|
| 387 | + {0x52b5, 0x001f}, {0xafae, 0x0000}, {0x0004, 0x0002}, {0x0671, 0x0001}, |
---|
| 388 | + {0x8fae, 0x0000}, {0x2a30, 0x001f}, {0x0012, 0x0008}, {0x0000, 0x001f}, |
---|
| 389 | +}; |
---|
| 390 | + |
---|
| 391 | +struct {unsigned short value, offset; } CICADA_V2_HWINIT[] = { |
---|
| 392 | + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0x000f, 0x0002}, |
---|
| 393 | + {0x472a, 0x0001}, {0x8fa4, 0x0000}, {0x2a30, 0x001f}, {0x0212, 0x0008}, |
---|
| 394 | + {0x0000, 0x001f}, |
---|
| 395 | +}; |
---|
| 396 | + |
---|
| 397 | +struct {unsigned short value, offset; } CICADA_V2_ASIX_HWINIT[] = { |
---|
| 398 | + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0x0012, 0x0002}, |
---|
| 399 | + {0x3002, 0x0001}, {0x87fa, 0x0000}, {0x52b5, 0x001f}, {0x000f, 0x0002}, |
---|
| 400 | + {0x472a, 0x0001}, {0x8fa4, 0x0000}, {0x2a30, 0x001f}, {0x0212, 0x0008}, |
---|
| 401 | + {0x0000, 0x001f}, |
---|
| 402 | +}; |
---|
| 403 | + |
---|
| 404 | +struct {unsigned short value, offset; } AGERE_FAMILY_HWINIT[] = { |
---|
| 405 | + {0x0800, 0x0000}, {0x0007, 0x0012}, {0x8805, 0x0010}, {0xb03e, 0x0011}, |
---|
| 406 | + {0x8808, 0x0010}, {0xe110, 0x0011}, {0x8806, 0x0010}, {0xb03e, 0x0011}, |
---|
| 407 | + {0x8807, 0x0010}, {0xff00, 0x0011}, {0x880e, 0x0010}, {0xb4d3, 0x0011}, |
---|
| 408 | + {0x880f, 0x0010}, {0xb4d3, 0x0011}, {0x8810, 0x0010}, {0xb4d3, 0x0011}, |
---|
| 409 | + {0x8817, 0x0010}, {0x1c00, 0x0011}, {0x300d, 0x0010}, {0x0001, 0x0011}, |
---|
| 410 | + {0x0002, 0x0012}, |
---|
| 411 | +}; |
---|
| 412 | + |
---|
| 413 | +struct ax88178_data { |
---|
| 414 | + u16 EepromData; |
---|
| 415 | + u16 MediaLink; |
---|
| 416 | + int UseGpio0; |
---|
| 417 | + int UseRgmii; |
---|
| 418 | + u8 PhyMode; |
---|
| 419 | + u8 LedMode; |
---|
| 420 | + u8 BuffaloOld; |
---|
| 421 | +}; |
---|
| 422 | + |
---|
| 423 | +enum watchdog_state { |
---|
| 424 | + AX_NOP = 0, |
---|
| 425 | + CHK_LINK, /* Routine A */ |
---|
| 426 | + CHK_CABLE_EXIST, /* Called by A */ |
---|
| 427 | + CHK_CABLE_EXIST_AGAIN, /* Routine B */ |
---|
| 428 | + PHY_POWER_UP, /* Called by B */ |
---|
| 429 | + PHY_POWER_UP_BH, |
---|
| 430 | + PHY_POWER_DOWN, |
---|
| 431 | + CHK_CABLE_STATUS, /* Routine C */ |
---|
| 432 | + WAIT_AUTONEG_COMPLETE, |
---|
| 433 | + AX_SET_RX_CFG, |
---|
| 434 | + AX_CHK_AUTODETACH, |
---|
| 435 | +}; |
---|
| 436 | + |
---|
| 437 | +struct ax88772b_data { |
---|
| 438 | + struct usbnet *dev; |
---|
| 439 | + struct workqueue_struct *ax_work; |
---|
| 440 | + struct work_struct check_link; |
---|
| 441 | + unsigned long time_to_chk; |
---|
| 442 | + u16 psc; |
---|
| 443 | + u8 pw_enabled; |
---|
| 444 | + u8 Event; |
---|
| 445 | + u8 checksum; |
---|
| 446 | + u8 PhySelect:1; |
---|
| 447 | + u8 OperationMode:1; |
---|
| 448 | + u16 presvd_phy_advertise; |
---|
| 449 | + u16 presvd_phy_bmcr; |
---|
| 450 | + |
---|
| 451 | + u32 ext_phy_oui; |
---|
| 452 | + u8 ext_phy_model; |
---|
| 453 | +}; |
---|
| 454 | + |
---|
| 455 | +/* define for MAC or PHY mode */ |
---|
| 456 | +#define OPERATION_MAC_MODE 0 |
---|
| 457 | +#define OPERATION_PHY_MODE 1 |
---|
| 458 | + |
---|
| 459 | +struct ax88772a_data { |
---|
| 460 | + struct usbnet *dev; |
---|
| 461 | + struct workqueue_struct *ax_work; |
---|
| 462 | + struct work_struct check_link; |
---|
| 463 | + unsigned long autoneg_start; |
---|
| 464 | +#define AX88772B_WATCHDOG (6 * HZ) |
---|
| 465 | + u8 Event; |
---|
| 466 | + u8 TickToExpire; |
---|
| 467 | + u8 DlyIndex; |
---|
| 468 | + u8 DlySel; |
---|
| 469 | + u16 EepromData; |
---|
| 470 | + u16 presvd_phy_advertise; |
---|
| 471 | + u16 presvd_phy_bmcr; |
---|
| 472 | +}; |
---|
| 473 | + |
---|
| 474 | +struct ax88772_data { |
---|
| 475 | + struct usbnet *dev; |
---|
| 476 | + struct workqueue_struct *ax_work; |
---|
| 477 | + struct work_struct check_link; |
---|
| 478 | + unsigned long autoneg_start; |
---|
| 479 | + u8 Event; |
---|
| 480 | + u8 TickToExpire; |
---|
| 481 | + u16 presvd_phy_advertise; |
---|
| 482 | + u16 presvd_phy_bmcr; |
---|
| 483 | +}; |
---|
| 484 | + |
---|
| 485 | +#define AX_RX_CHECKSUM 1 |
---|
| 486 | +#define AX_TX_CHECKSUM 2 |
---|
| 487 | + |
---|
| 488 | +/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ |
---|
| 489 | +struct ax8817x_data { |
---|
| 490 | + u8 multi_filter[AX_MCAST_FILTER_SIZE]; |
---|
| 491 | + int (*resume) (struct usb_interface *intf); |
---|
| 492 | + int (*suspend) (struct usb_interface *intf, |
---|
| 493 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) |
---|
| 494 | + pm_message_t message); |
---|
| 495 | +#else |
---|
| 496 | + u32 message); |
---|
| 497 | +#endif |
---|
| 498 | +}; |
---|
| 499 | + |
---|
| 500 | +struct ax88172_int_data { |
---|
| 501 | + u16 res1; |
---|
| 502 | +#define AX_INT_PPLS_LINK (1 << 0) |
---|
| 503 | +#define AX_INT_SPLS_LINK (1 << 1) |
---|
| 504 | +#define AX_INT_CABOFF_UNPLUG (1 << 7) |
---|
| 505 | + u8 link; |
---|
| 506 | + u16 res2; |
---|
| 507 | + u8 status; |
---|
| 508 | + u16 res3; |
---|
| 509 | +} __attribute__ ((packed)); |
---|
| 510 | + |
---|
| 511 | +#define AX_RXHDR_L4_ERR (1 << 8) |
---|
| 512 | +#define AX_RXHDR_L3_ERR (1 << 9) |
---|
| 513 | + |
---|
| 514 | +#define AX_RXHDR_L4_TYPE_UDP 1 |
---|
| 515 | +#define AX_RXHDR_L4_TYPE_ICMP 2 |
---|
| 516 | +#define AX_RXHDR_L4_TYPE_IGMP 3 |
---|
| 517 | +#define AX_RXHDR_L4_TYPE_TCP 4 |
---|
| 518 | +#define AX_RXHDR_L4_TYPE_TCMPV6 5 |
---|
| 519 | +#define AX_RXHDR_L4_TYPE_MASK 7 |
---|
| 520 | + |
---|
| 521 | +#define AX_RXHDR_L3_TYPE_IP 1 |
---|
| 522 | +#define AX_RXHDR_L3_TYPE_IPV6 2 |
---|
| 523 | + |
---|
| 524 | +struct ax88772b_rx_header { |
---|
| 525 | +#if defined(__LITTLE_ENDIAN_BITFIELD) |
---|
| 526 | + u16 len:11, |
---|
| 527 | + res1:1, |
---|
| 528 | + crc:1, |
---|
| 529 | + mii:1, |
---|
| 530 | + runt:1, |
---|
| 531 | + mc_bc:1; |
---|
| 532 | + |
---|
| 533 | + u16 len_bar:11, |
---|
| 534 | + res2:5; |
---|
| 535 | + |
---|
| 536 | + u8 vlan_ind:3, |
---|
| 537 | + vlan_tag_striped:1, |
---|
| 538 | + pri:3, |
---|
| 539 | + res3:1; |
---|
| 540 | + |
---|
| 541 | + u8 l4_csum_err:1, |
---|
| 542 | + l3_csum_err:1, |
---|
| 543 | + l4_type:3, |
---|
| 544 | + l3_type:2, |
---|
| 545 | + ce:1; |
---|
| 546 | +#elif defined(__BIG_ENDIAN_BITFIELD) |
---|
| 547 | + u16 mc_bc:1, |
---|
| 548 | + runt:1, |
---|
| 549 | + mii:1, |
---|
| 550 | + crc:1, |
---|
| 551 | + res1:1, |
---|
| 552 | + len:11; |
---|
| 553 | + |
---|
| 554 | + u16 res2:5, |
---|
| 555 | + len_bar:11; |
---|
| 556 | + |
---|
| 557 | + u8 res3:1, |
---|
| 558 | + pri:3, |
---|
| 559 | + vlan_tag_striped:1, |
---|
| 560 | + vlan_ind:3; |
---|
| 561 | + |
---|
| 562 | + u8 ce:1, |
---|
| 563 | + l3_type:2, |
---|
| 564 | + l4_type:3, |
---|
| 565 | + l3_csum_err:1, |
---|
| 566 | + l4_csum_err:1; |
---|
| 567 | +#else |
---|
| 568 | +#error "Please fix <asm/byteorder.h>" |
---|
| 569 | +#endif |
---|
| 570 | + |
---|
| 571 | +} __attribute__ ((packed)); |
---|
| 572 | + |
---|
| 573 | + |
---|
| 574 | +#endif /* __LINUX_USBNET_ASIX_H */ |
---|
| 575 | + |
---|
.. | .. |
---|
| 1 | +/* |
---|
| 2 | + * USB Network driver infrastructure |
---|
| 3 | + * Copyright (C) 2000-2005 by David Brownell |
---|
| 4 | + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> |
---|
| 5 | + * |
---|
| 6 | + * This program is free software; you can redistribute it and/or modify |
---|
| 7 | + * it under the terms of the GNU General Public License as published by |
---|
| 8 | + * the Free Software Foundation; either version 2 of the License, or |
---|
| 9 | + * (at your option) any later version. |
---|
| 10 | + * |
---|
| 11 | + * This program is distributed in the hope that it will be useful, |
---|
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 14 | + * GNU General Public License for more details. |
---|
| 15 | + * |
---|
| 16 | + * You should have received a copy of the GNU General Public License |
---|
| 17 | + * along with this program; if not, write to the Free Software |
---|
| 18 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 19 | + */ |
---|
| 20 | + |
---|
| 21 | +/* |
---|
| 22 | + * This is a generic "USB networking" framework that works with several |
---|
| 23 | + * kinds of full and high speed networking devices: host-to-host cables, |
---|
| 24 | + * smart usb peripherals, and actual Ethernet adapters. |
---|
| 25 | + * |
---|
| 26 | + * These devices usually differ in terms of control protocols (if they |
---|
| 27 | + * even have one!) and sometimes they define new framing to wrap or batch |
---|
| 28 | + * Ethernet packets. Otherwise, they talk to USB pretty much the same, |
---|
| 29 | + * so interface (un)binding, endpoint I/O queues, fault handling, and other |
---|
| 30 | + * issues can usefully be addressed by this framework. |
---|
| 31 | + */ |
---|
| 32 | + |
---|
| 33 | +/* error path messages, extra info */ |
---|
| 34 | +#define DEBUG |
---|
| 35 | +/* more; success messages */ |
---|
| 36 | +/* #define VERBOSE */ |
---|
| 37 | + |
---|
| 38 | +#include <linux/module.h> |
---|
| 39 | +#include <linux/init.h> |
---|
| 40 | +#include <linux/netdevice.h> |
---|
| 41 | +#include <linux/etherdevice.h> |
---|
| 42 | +#include <linux/ctype.h> |
---|
| 43 | +#include <linux/ethtool.h> |
---|
| 44 | +#include <linux/workqueue.h> |
---|
| 45 | +#include <linux/mii.h> |
---|
| 46 | +#include <linux/usb.h> |
---|
| 47 | +/*#include <linux/usb/usbnet.h>*/ |
---|
| 48 | + |
---|
| 49 | +#include "asix.h" |
---|
| 50 | +#include "axusbnet.h" |
---|
| 51 | + |
---|
| 52 | +#define DRIVER_VERSION "22-Aug-2005" |
---|
| 53 | + |
---|
| 54 | +static void axusbnet_unlink_rx_urbs(struct usbnet *); |
---|
| 55 | + |
---|
| 56 | +static void |
---|
| 57 | +ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
---|
| 58 | + u16 size, void *data); |
---|
| 59 | + |
---|
| 60 | +/*-------------------------------------------------------------------------*/ |
---|
| 61 | + |
---|
| 62 | +/* |
---|
| 63 | + * Nineteen USB 1.1 max size bulk transactions per frame (ms), max. |
---|
| 64 | + * Several dozen bytes of IPv4 data can fit in two such transactions. |
---|
| 65 | + * One maximum size Ethernet packet takes twenty four of them. |
---|
| 66 | + * For high speed, each frame comfortably fits almost 36 max size |
---|
| 67 | + * Ethernet packets (so queues should be bigger). |
---|
| 68 | + * |
---|
| 69 | + * REVISIT qlens should be members of 'struct usbnet'; the goal is to |
---|
| 70 | + * let the USB host controller be busy for 5msec or more before an irq |
---|
| 71 | + * is required, under load. Jumbograms change the equation. |
---|
| 72 | + */ |
---|
| 73 | +#define RX_MAX_QUEUE_MEMORY (60 * 1518) |
---|
| 74 | +#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ |
---|
| 75 | + (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4) |
---|
| 76 | +#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ |
---|
| 77 | + (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4) |
---|
| 78 | + |
---|
| 79 | +/* reawaken network queue this soon after stopping; else watchdog barks */ |
---|
| 80 | +/* #define TX_TIMEOUT_JIFFIES (5 * HZ) */ |
---|
| 81 | +#define TX_TIMEOUT_JIFFIES (30 * HZ) |
---|
| 82 | + |
---|
| 83 | +/* throttle rx/tx briefly after some faults, so khubd might disconnect() */ |
---|
| 84 | +/* us (it polls at HZ/4 usually) before we report too many false errors. */ |
---|
| 85 | +#define THROTTLE_JIFFIES (HZ / 8) |
---|
| 86 | + |
---|
| 87 | +/* between wakeups */ |
---|
| 88 | +#define UNLINK_TIMEOUT_MS 3 |
---|
| 89 | + |
---|
| 90 | +/*-------------------------------------------------------------------------*/ |
---|
| 91 | + |
---|
| 92 | +static const char driver_name[] = "axusbnet"; |
---|
| 93 | + |
---|
| 94 | +/* use ethtool to change the level for any given device */ |
---|
| 95 | +static int msg_level = -1; |
---|
| 96 | +module_param(msg_level, int, 0); |
---|
| 97 | +MODULE_PARM_DESC(msg_level, "Override default message level"); |
---|
| 98 | + |
---|
| 99 | +/*-------------------------------------------------------------------------*/ |
---|
| 100 | + |
---|
| 101 | +/* handles CDC Ethernet and many other network "bulk data" interfaces */ |
---|
| 102 | +static |
---|
| 103 | +int axusbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) |
---|
| 104 | +{ |
---|
| 105 | + int tmp; |
---|
| 106 | + struct usb_host_interface *alt = NULL; |
---|
| 107 | + struct usb_host_endpoint *in = NULL, *out = NULL; |
---|
| 108 | + struct usb_host_endpoint *status = NULL; |
---|
| 109 | + |
---|
| 110 | + for (tmp = 0; tmp < intf->num_altsetting; tmp++) { |
---|
| 111 | + unsigned ep; |
---|
| 112 | + |
---|
| 113 | + in = out = status = NULL; |
---|
| 114 | + alt = intf->altsetting + tmp; |
---|
| 115 | + |
---|
| 116 | + /* take the first altsetting with in-bulk + out-bulk; |
---|
| 117 | + * remember any status endpoint, just in case; |
---|
| 118 | + * ignore other endpoints and altsetttings. |
---|
| 119 | + */ |
---|
| 120 | + for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { |
---|
| 121 | + struct usb_host_endpoint *e; |
---|
| 122 | + int intr = 0; |
---|
| 123 | + |
---|
| 124 | + e = alt->endpoint + ep; |
---|
| 125 | + switch (e->desc.bmAttributes) { |
---|
| 126 | + case USB_ENDPOINT_XFER_INT: |
---|
| 127 | + if (!(e->desc.bEndpointAddress & USB_DIR_IN)) |
---|
| 128 | + continue; |
---|
| 129 | + intr = 1; |
---|
| 130 | + /* FALLTHROUGH */ |
---|
| 131 | + case USB_ENDPOINT_XFER_BULK: |
---|
| 132 | + break; |
---|
| 133 | + default: |
---|
| 134 | + continue; |
---|
| 135 | + } |
---|
| 136 | + if (e->desc.bEndpointAddress & USB_DIR_IN) { |
---|
| 137 | + if (!intr && !in) { |
---|
| 138 | + in = e; |
---|
| 139 | + } else if (intr && !status) { |
---|
| 140 | + status = e; |
---|
| 141 | + } |
---|
| 142 | + } else { |
---|
| 143 | + if (!out) { |
---|
| 144 | + out = e; |
---|
| 145 | + } |
---|
| 146 | + } |
---|
| 147 | + } |
---|
| 148 | + if (in && out) |
---|
| 149 | + break; |
---|
| 150 | + } |
---|
| 151 | + if (!alt || !in || !out) |
---|
| 152 | + return -EINVAL; |
---|
| 153 | + |
---|
| 154 | + if (alt->desc.bAlternateSetting != 0 |
---|
| 155 | + || !(dev->driver_info->flags & FLAG_NO_SETINT)) { |
---|
| 156 | + tmp = usb_set_interface(dev->udev, alt->desc.bInterfaceNumber, |
---|
| 157 | + alt->desc.bAlternateSetting); |
---|
| 158 | + if (tmp < 0) |
---|
| 159 | + return tmp; |
---|
| 160 | + } |
---|
| 161 | + |
---|
| 162 | + dev->in = usb_rcvbulkpipe(dev->udev, |
---|
| 163 | + in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); |
---|
| 164 | + dev->out = usb_sndbulkpipe(dev->udev, |
---|
| 165 | + out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); |
---|
| 166 | + dev->status = status; |
---|
| 167 | + return 0; |
---|
| 168 | +} |
---|
| 169 | + |
---|
| 170 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) |
---|
| 171 | +static void intr_complete(struct urb *urb, struct pt_regs *regs); |
---|
| 172 | +#else |
---|
| 173 | +static void intr_complete(struct urb *urb); |
---|
| 174 | +#endif |
---|
| 175 | + |
---|
| 176 | +static int init_status(struct usbnet *dev, struct usb_interface *intf) |
---|
| 177 | +{ |
---|
| 178 | + char *buf = NULL; |
---|
| 179 | + unsigned pipe = 0; |
---|
| 180 | + unsigned maxp; |
---|
| 181 | + unsigned period; |
---|
| 182 | + |
---|
| 183 | + if (!dev->driver_info->status) |
---|
| 184 | + return 0; |
---|
| 185 | + |
---|
| 186 | + pipe = usb_rcvintpipe(dev->udev, |
---|
| 187 | + dev->status->desc.bEndpointAddress |
---|
| 188 | + & USB_ENDPOINT_NUMBER_MASK); |
---|
| 189 | + maxp = usb_maxpacket(dev->udev, pipe, 0); |
---|
| 190 | + |
---|
| 191 | + /* avoid 1 msec chatter: min 8 msec poll rate */ |
---|
| 192 | + period = max((int) dev->status->desc.bInterval, |
---|
| 193 | + (dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3); |
---|
| 194 | + |
---|
| 195 | + buf = kmalloc(maxp, GFP_KERNEL); |
---|
| 196 | + if (buf) { |
---|
| 197 | + dev->interrupt = usb_alloc_urb(0, GFP_KERNEL); |
---|
| 198 | + if (!dev->interrupt) { |
---|
| 199 | + kfree(buf); |
---|
| 200 | + return -ENOMEM; |
---|
| 201 | + } else { |
---|
| 202 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) |
---|
| 203 | + dev->interrupt->transfer_flags |= URB_ASYNC_UNLINK; |
---|
| 204 | +#endif |
---|
| 205 | + usb_fill_int_urb(dev->interrupt, dev->udev, pipe, |
---|
| 206 | + buf, maxp, intr_complete, dev, period); |
---|
| 207 | + devdbg(dev, |
---|
| 208 | + "status ep%din, %d bytes period %d", |
---|
| 209 | + usb_pipeendpoint(pipe), maxp, period); |
---|
| 210 | + } |
---|
| 211 | + } |
---|
| 212 | + return 0; |
---|
| 213 | +} |
---|
| 214 | + |
---|
| 215 | +/* Passes this packet up the stack, updating its accounting. |
---|
| 216 | + * Some link protocols batch packets, so their rx_fixup paths |
---|
| 217 | + * can return clones as well as just modify the original skb. |
---|
| 218 | + */ |
---|
| 219 | +static |
---|
| 220 | +void axusbnet_skb_return(struct usbnet *dev, struct sk_buff *skb) |
---|
| 221 | +{ |
---|
| 222 | + int status; |
---|
| 223 | + |
---|
| 224 | + skb->dev = dev->net; |
---|
| 225 | + skb->protocol = eth_type_trans(skb, dev->net); |
---|
| 226 | + dev->stats.rx_packets++; |
---|
| 227 | + dev->stats.rx_bytes += skb->len; |
---|
| 228 | + |
---|
| 229 | + if (netif_msg_rx_status(dev)) |
---|
| 230 | + devdbg(dev, "< rx, len %zu, type 0x%x", |
---|
| 231 | + skb->len + sizeof(struct ethhdr), skb->protocol); |
---|
| 232 | + memset(skb->cb, 0, sizeof(struct skb_data)); |
---|
| 233 | + status = netif_rx(skb); |
---|
| 234 | + if (status != NET_RX_SUCCESS && netif_msg_rx_err(dev)) |
---|
| 235 | + devdbg(dev, "netif_rx status %d", status); |
---|
| 236 | +} |
---|
| 237 | + |
---|
| 238 | +/*------------------------------------------------------------------------- |
---|
| 239 | + * |
---|
| 240 | + * Network Device Driver (peer link to "Host Device", from USB host) |
---|
| 241 | + * |
---|
| 242 | + *-------------------------------------------------------------------------*/ |
---|
| 243 | + |
---|
| 244 | +static |
---|
| 245 | +int axusbnet_change_mtu(struct net_device *net, int new_mtu) |
---|
| 246 | +{ |
---|
| 247 | + struct usbnet *dev = netdev_priv(net); |
---|
| 248 | + int ll_mtu = new_mtu + net->hard_header_len; |
---|
| 249 | + int old_hard_mtu = dev->hard_mtu; |
---|
| 250 | + int old_rx_urb_size = dev->rx_urb_size; |
---|
| 251 | + |
---|
| 252 | + if (new_mtu <= 0) |
---|
| 253 | + return -EINVAL; |
---|
| 254 | + /* no second zero-length packet read wanted after mtu-sized packets */ |
---|
| 255 | + if ((ll_mtu % dev->maxpacket) == 0) |
---|
| 256 | + return -EDOM; |
---|
| 257 | + net->mtu = new_mtu; |
---|
| 258 | + |
---|
| 259 | + dev->hard_mtu = net->mtu + net->hard_header_len; |
---|
| 260 | + if (dev->rx_urb_size == old_hard_mtu) { |
---|
| 261 | + dev->rx_urb_size = dev->hard_mtu; |
---|
| 262 | + if (dev->rx_urb_size > old_rx_urb_size) |
---|
| 263 | + axusbnet_unlink_rx_urbs(dev); |
---|
| 264 | + } |
---|
| 265 | + |
---|
| 266 | + return 0; |
---|
| 267 | +} |
---|
| 268 | + |
---|
| 269 | +static struct net_device_stats *axusbnet_get_stats(struct net_device *net) |
---|
| 270 | +{ |
---|
| 271 | + struct usbnet *dev = netdev_priv(net); |
---|
| 272 | + return &dev->stats; |
---|
| 273 | +} |
---|
| 274 | + |
---|
| 275 | +/*-------------------------------------------------------------------------*/ |
---|
| 276 | + |
---|
| 277 | +/* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from |
---|
| 278 | + * completion callbacks. 2.5 should have fixed those bugs... |
---|
| 279 | + */ |
---|
| 280 | + |
---|
| 281 | +static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb, |
---|
| 282 | + struct sk_buff_head *list, enum skb_state state) |
---|
| 283 | +{ |
---|
| 284 | + unsigned long flags; |
---|
| 285 | + enum skb_state old_state; |
---|
| 286 | + struct skb_data *entry = (struct skb_data *) skb->cb; |
---|
| 287 | + |
---|
| 288 | + spin_lock_irqsave(&list->lock, flags); |
---|
| 289 | + old_state = entry->state; |
---|
| 290 | + entry->state = state; |
---|
| 291 | + __skb_unlink(skb, list); |
---|
| 292 | + |
---|
| 293 | + /* defer_bh() is never called with list == &dev->done. |
---|
| 294 | + * spin_lock_nested() tells lockdep that it is OK to take |
---|
| 295 | + * dev->done.lock here with list->lock held. |
---|
| 296 | + */ |
---|
| 297 | + spin_lock_nested(&dev->done.lock, SINGLE_DEPTH_NESTING); |
---|
| 298 | + |
---|
| 299 | + __skb_queue_tail(&dev->done, skb); |
---|
| 300 | + if (dev->done.qlen == 1) |
---|
| 301 | + tasklet_schedule(&dev->bh); |
---|
| 302 | + |
---|
| 303 | + spin_unlock(&dev->done.lock); |
---|
| 304 | + spin_unlock_irqrestore(&list->lock, flags); |
---|
| 305 | + |
---|
| 306 | + return old_state; |
---|
| 307 | +} |
---|
| 308 | + |
---|
| 309 | +/* some work can't be done in tasklets, so we use keventd |
---|
| 310 | + * |
---|
| 311 | + * NOTE: annoying asymmetry: if it's active, schedule_work() fails, |
---|
| 312 | + * but tasklet_schedule() doesn't. hope the failure is rare. |
---|
| 313 | + */ |
---|
| 314 | +static |
---|
| 315 | +void axusbnet_defer_kevent(struct usbnet *dev, int work) |
---|
| 316 | +{ |
---|
| 317 | + set_bit(work, &dev->flags); |
---|
| 318 | + if (!schedule_work(&dev->kevent)) |
---|
| 319 | + deverr(dev, "kevent %d may have been dropped", work); |
---|
| 320 | + else |
---|
| 321 | + devdbg(dev, "kevent %d scheduled", work); |
---|
| 322 | +} |
---|
| 323 | + |
---|
| 324 | +/*-------------------------------------------------------------------------*/ |
---|
| 325 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) |
---|
| 326 | +static void rx_complete(struct urb *urb, struct pt_regs *regs); |
---|
| 327 | +#else |
---|
| 328 | +static void rx_complete(struct urb *urb); |
---|
| 329 | +#endif |
---|
| 330 | + |
---|
| 331 | +static void rx_submit(struct usbnet *dev, struct urb *urb, gfp_t flags) |
---|
| 332 | +{ |
---|
| 333 | + struct sk_buff *skb; |
---|
| 334 | + struct skb_data *entry; |
---|
| 335 | + int retval = 0; |
---|
| 336 | + unsigned long lockflags; |
---|
| 337 | + size_t size = dev->rx_urb_size; |
---|
| 338 | + struct driver_info *info = dev->driver_info; |
---|
| 339 | + u8 align; |
---|
| 340 | + |
---|
| 341 | + /* prevent rx skb allocation when error ratio is high */ |
---|
| 342 | + if (test_bit(EVENT_RX_KILL, &dev->flags)) { |
---|
| 343 | + usb_free_urb(urb); |
---|
| 344 | + return; |
---|
| 345 | + } |
---|
| 346 | + |
---|
| 347 | +#if (AX_FORCE_BUFF_ALIGN) |
---|
| 348 | + align = 0; |
---|
| 349 | +#else |
---|
| 350 | + if (!(info->flags & FLAG_HW_IP_ALIGNMENT)) |
---|
| 351 | + align = NET_IP_ALIGN; |
---|
| 352 | + else |
---|
| 353 | + align = 0; |
---|
| 354 | +#endif |
---|
| 355 | + skb = alloc_skb(size + align, flags); |
---|
| 356 | + if (skb == NULL) { |
---|
| 357 | + |
---|
| 358 | + if (netif_msg_rx_err(dev)) |
---|
| 359 | + devdbg(dev, "no rx skb"); |
---|
| 360 | + |
---|
| 361 | + if ((dev->rx_urb_size > 2048) && dev->rx_size) { |
---|
| 362 | + dev->rx_size--; |
---|
| 363 | + dev->rx_urb_size = |
---|
| 364 | + AX88772B_BULKIN_SIZE[dev->rx_size].size; |
---|
| 365 | + |
---|
| 366 | + ax8817x_write_cmd_async(dev, 0x2A, |
---|
| 367 | + AX88772B_BULKIN_SIZE[dev->rx_size].byte_cnt, |
---|
| 368 | + AX88772B_BULKIN_SIZE[dev->rx_size].threshold, |
---|
| 369 | + 0, NULL); |
---|
| 370 | + } |
---|
| 371 | + |
---|
| 372 | + if (!(dev->flags & EVENT_RX_MEMORY)) |
---|
| 373 | + axusbnet_defer_kevent(dev, EVENT_RX_MEMORY); |
---|
| 374 | + usb_free_urb(urb); |
---|
| 375 | + return; |
---|
| 376 | + } |
---|
| 377 | + |
---|
| 378 | + if (align) |
---|
| 379 | + skb_reserve(skb, NET_IP_ALIGN); |
---|
| 380 | + |
---|
| 381 | + entry = (struct skb_data *) skb->cb; |
---|
| 382 | + entry->urb = urb; |
---|
| 383 | + entry->dev = dev; |
---|
| 384 | + entry->state = rx_start; |
---|
| 385 | + entry->length = 0; |
---|
| 386 | + |
---|
| 387 | + usb_fill_bulk_urb(urb, dev->udev, dev->in, skb->data, |
---|
| 388 | + size, rx_complete, skb); |
---|
| 389 | + |
---|
| 390 | + spin_lock_irqsave(&dev->rxq.lock, lockflags); |
---|
| 391 | + |
---|
| 392 | + if (netif_running(dev->net) |
---|
| 393 | + && netif_device_present(dev->net) |
---|
| 394 | + && !test_bit(EVENT_RX_HALT, &dev->flags)) { |
---|
| 395 | + switch (retval = usb_submit_urb(urb, GFP_ATOMIC)) { |
---|
| 396 | + case -EPIPE: |
---|
| 397 | + axusbnet_defer_kevent(dev, EVENT_RX_HALT); |
---|
| 398 | + break; |
---|
| 399 | + case -ENOMEM: |
---|
| 400 | + axusbnet_defer_kevent(dev, EVENT_RX_MEMORY); |
---|
| 401 | + break; |
---|
| 402 | + case -ENODEV: |
---|
| 403 | + if (netif_msg_ifdown(dev)) |
---|
| 404 | + devdbg(dev, "device gone"); |
---|
| 405 | + netif_device_detach(dev->net); |
---|
| 406 | + break; |
---|
| 407 | + default: |
---|
| 408 | + if (netif_msg_rx_err(dev)) |
---|
| 409 | + devdbg(dev, "rx submit, %d", retval); |
---|
| 410 | + tasklet_schedule(&dev->bh); |
---|
| 411 | + break; |
---|
| 412 | + case 0: |
---|
| 413 | + __skb_queue_tail(&dev->rxq, skb); |
---|
| 414 | + } |
---|
| 415 | + } else { |
---|
| 416 | + if (netif_msg_ifdown(dev)) |
---|
| 417 | + devdbg(dev, "rx: stopped"); |
---|
| 418 | + retval = -ENOLINK; |
---|
| 419 | + } |
---|
| 420 | + spin_unlock_irqrestore(&dev->rxq.lock, lockflags); |
---|
| 421 | + if (retval) { |
---|
| 422 | + dev_kfree_skb_any(skb); |
---|
| 423 | + usb_free_urb(urb); |
---|
| 424 | + } |
---|
| 425 | +} |
---|
| 426 | + |
---|
| 427 | + |
---|
| 428 | +/*-------------------------------------------------------------------------*/ |
---|
| 429 | + |
---|
| 430 | +static inline void rx_process(struct usbnet *dev, struct sk_buff *skb) |
---|
| 431 | +{ |
---|
| 432 | + if (dev->driver_info->rx_fixup |
---|
| 433 | + && !dev->driver_info->rx_fixup(dev, skb)) |
---|
| 434 | + goto error; |
---|
| 435 | + /* else network stack removes extra byte if we forced a short packet */ |
---|
| 436 | + |
---|
| 437 | + if (skb->len) |
---|
| 438 | + axusbnet_skb_return(dev, skb); |
---|
| 439 | + else { |
---|
| 440 | + if (netif_msg_rx_err(dev)) |
---|
| 441 | + devdbg(dev, "drop"); |
---|
| 442 | +error: |
---|
| 443 | + dev->stats.rx_errors++; |
---|
| 444 | + skb_queue_tail(&dev->done, skb); |
---|
| 445 | + } |
---|
| 446 | +} |
---|
| 447 | + |
---|
| 448 | +/*-------------------------------------------------------------------------*/ |
---|
| 449 | + |
---|
| 450 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) |
---|
| 451 | +static void rx_complete(struct urb *urb, struct pt_regs *regs) |
---|
| 452 | +#else |
---|
| 453 | +static void rx_complete(struct urb *urb) |
---|
| 454 | +#endif |
---|
| 455 | +{ |
---|
| 456 | + struct sk_buff *skb = (struct sk_buff *) urb->context; |
---|
| 457 | + struct skb_data *entry = (struct skb_data *) skb->cb; |
---|
| 458 | + struct usbnet *dev = entry->dev; |
---|
| 459 | + int urb_status = urb->status; |
---|
| 460 | + enum skb_state state; |
---|
| 461 | + |
---|
| 462 | + skb_put(skb, urb->actual_length); |
---|
| 463 | + state = rx_done; |
---|
| 464 | + entry->urb = NULL; |
---|
| 465 | + |
---|
| 466 | + switch (urb_status) { |
---|
| 467 | + /* success */ |
---|
| 468 | + case 0: |
---|
| 469 | + if (skb->len < dev->net->hard_header_len) { |
---|
| 470 | + entry->state = rx_cleanup; |
---|
| 471 | + dev->stats.rx_errors++; |
---|
| 472 | + dev->stats.rx_length_errors++; |
---|
| 473 | + if (netif_msg_rx_err(dev)) |
---|
| 474 | + devdbg(dev, "rx length %d", skb->len); |
---|
| 475 | + } |
---|
| 476 | + break; |
---|
| 477 | + |
---|
| 478 | + /* stalls need manual reset. this is rare ... except that |
---|
| 479 | + * when going through USB 2.0 TTs, unplug appears this way. |
---|
| 480 | + * we avoid the highspeed version of the ETIMEDOUT/EILSEQ |
---|
| 481 | + * storm, recovering as needed. |
---|
| 482 | + */ |
---|
| 483 | + case -EPIPE: |
---|
| 484 | + dev->stats.rx_errors++; |
---|
| 485 | + axusbnet_defer_kevent(dev, EVENT_RX_HALT); |
---|
| 486 | + /* FALLTHROUGH */ |
---|
| 487 | + |
---|
| 488 | + /* software-driven interface shutdown */ |
---|
| 489 | + case -ECONNRESET: /* async unlink */ |
---|
| 490 | + case -ESHUTDOWN: /* hardware gone */ |
---|
| 491 | + if (netif_msg_ifdown(dev)) |
---|
| 492 | + devdbg(dev, "rx shutdown, code %d", urb_status); |
---|
| 493 | + goto block; |
---|
| 494 | + |
---|
| 495 | + /* we get controller i/o faults during khubd disconnect() delays. |
---|
| 496 | + * throttle down resubmits, to avoid log floods; just temporarily, |
---|
| 497 | + * so we still recover when the fault isn't a khubd delay. |
---|
| 498 | + */ |
---|
| 499 | + case -EPROTO: |
---|
| 500 | + case -ETIME: |
---|
| 501 | + case -EILSEQ: |
---|
| 502 | + dev->stats.rx_errors++; |
---|
| 503 | + if (!timer_pending(&dev->delay)) { |
---|
| 504 | + mod_timer(&dev->delay, jiffies + THROTTLE_JIFFIES); |
---|
| 505 | + if (netif_msg_link(dev)) |
---|
| 506 | + devdbg(dev, "rx throttle %d", urb_status); |
---|
| 507 | + } |
---|
| 508 | +block: |
---|
| 509 | + state = rx_cleanup; |
---|
| 510 | + entry->urb = urb; |
---|
| 511 | + urb = NULL; |
---|
| 512 | + break; |
---|
| 513 | + |
---|
| 514 | + /* data overrun ... flush fifo? */ |
---|
| 515 | + case -EOVERFLOW: |
---|
| 516 | + dev->stats.rx_over_errors++; |
---|
| 517 | + /* FALLTHROUGH */ |
---|
| 518 | + |
---|
| 519 | + default: |
---|
| 520 | + state = rx_cleanup; |
---|
| 521 | + dev->stats.rx_errors++; |
---|
| 522 | + if (netif_msg_rx_err(dev)) |
---|
| 523 | + devdbg(dev, "rx status %d", urb_status); |
---|
| 524 | + break; |
---|
| 525 | + } |
---|
| 526 | + |
---|
| 527 | + /* stop rx if packet error rate is high */ |
---|
| 528 | + if (++dev->pkt_cnt > 30) { |
---|
| 529 | + dev->pkt_cnt = 0; |
---|
| 530 | + dev->pkt_err = 0; |
---|
| 531 | + } else { |
---|
| 532 | + if (state == rx_cleanup) |
---|
| 533 | + dev->pkt_err++; |
---|
| 534 | + if (dev->pkt_err > 20) |
---|
| 535 | + set_bit(EVENT_RX_KILL, &dev->flags); |
---|
| 536 | + } |
---|
| 537 | + |
---|
| 538 | + state = defer_bh(dev, skb, &dev->rxq, state); |
---|
| 539 | + |
---|
| 540 | + if (urb) { |
---|
| 541 | + if (netif_running(dev->net) && |
---|
| 542 | + !test_bit(EVENT_RX_HALT, &dev->flags) && |
---|
| 543 | + state != unlink_start) { |
---|
| 544 | + rx_submit(dev, urb, GFP_ATOMIC); |
---|
| 545 | + return; |
---|
| 546 | + } |
---|
| 547 | + usb_free_urb(urb); |
---|
| 548 | + } |
---|
| 549 | + if (netif_msg_rx_err(dev)) |
---|
| 550 | + devdbg(dev, "no read resubmitted"); |
---|
| 551 | +} |
---|
| 552 | + |
---|
| 553 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) |
---|
| 554 | +static void intr_complete(struct urb *urb, struct pt_regs *regs) |
---|
| 555 | +#else |
---|
| 556 | +static void intr_complete(struct urb *urb) |
---|
| 557 | +#endif |
---|
| 558 | +{ |
---|
| 559 | + struct usbnet *dev = urb->context; |
---|
| 560 | + int status = urb->status; |
---|
| 561 | + |
---|
| 562 | + switch (status) { |
---|
| 563 | + /* success */ |
---|
| 564 | + case 0: |
---|
| 565 | + dev->driver_info->status(dev, urb); |
---|
| 566 | + break; |
---|
| 567 | + |
---|
| 568 | + /* software-driven interface shutdown */ |
---|
| 569 | + case -ENOENT: /* urb killed */ |
---|
| 570 | + case -ESHUTDOWN: /* hardware gone */ |
---|
| 571 | + if (netif_msg_ifdown(dev)) |
---|
| 572 | + devdbg(dev, "intr shutdown, code %d", status); |
---|
| 573 | + return; |
---|
| 574 | + |
---|
| 575 | + /* NOTE: not throttling like RX/TX, since this endpoint |
---|
| 576 | + * already polls infrequently |
---|
| 577 | + */ |
---|
| 578 | + default: |
---|
| 579 | + devdbg(dev, "intr status %d", status); |
---|
| 580 | + break; |
---|
| 581 | + } |
---|
| 582 | + |
---|
| 583 | + if (!netif_running(dev->net)) |
---|
| 584 | + return; |
---|
| 585 | + |
---|
| 586 | + memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); |
---|
| 587 | + status = usb_submit_urb(urb, GFP_ATOMIC); |
---|
| 588 | + if (status != 0 && netif_msg_timer(dev)) |
---|
| 589 | + deverr(dev, "intr resubmit --> %d", status); |
---|
| 590 | +} |
---|
| 591 | + |
---|
| 592 | +/*-------------------------------------------------------------------------*/ |
---|
| 593 | + |
---|
| 594 | +/* unlink pending rx/tx; completion handlers do all other cleanup */ |
---|
| 595 | + |
---|
| 596 | +static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) |
---|
| 597 | +{ |
---|
| 598 | + unsigned long flags; |
---|
| 599 | + struct sk_buff *skb = NULL; |
---|
| 600 | + int count = 0; |
---|
| 601 | + |
---|
| 602 | + spin_lock_irqsave (&q->lock, flags); |
---|
| 603 | + while (!skb_queue_empty(q)) { |
---|
| 604 | + struct skb_data *entry; |
---|
| 605 | + struct urb *urb; |
---|
| 606 | + int retval; |
---|
| 607 | + |
---|
| 608 | + skb_queue_walk(q, skb) { |
---|
| 609 | + entry = (struct skb_data *) skb->cb; |
---|
| 610 | + if (entry->state != unlink_start) |
---|
| 611 | + goto found; |
---|
| 612 | + } |
---|
| 613 | + break; |
---|
| 614 | +found: |
---|
| 615 | + entry->state = unlink_start; |
---|
| 616 | + urb = entry->urb; |
---|
| 617 | + |
---|
| 618 | + /* |
---|
| 619 | + * Get reference count of the URB to avoid it to be |
---|
| 620 | + * freed during usb_unlink_urb, which may trigger |
---|
| 621 | + * use-after-free problem inside usb_unlink_urb since |
---|
| 622 | + * usb_unlink_urb is always racing with .complete |
---|
| 623 | + * handler(include defer_bh). |
---|
| 624 | + */ |
---|
| 625 | + usb_get_urb(urb); |
---|
| 626 | + spin_unlock_irqrestore(&q->lock, flags); |
---|
| 627 | + // during some PM-driven resume scenarios, |
---|
| 628 | + // these (async) unlinks complete immediately |
---|
| 629 | + retval = usb_unlink_urb (urb); |
---|
| 630 | + if (retval != -EINPROGRESS && retval != 0) |
---|
| 631 | + printk(DEBUG "unlink urb err, %d\n", retval); |
---|
| 632 | + else |
---|
| 633 | + count++; |
---|
| 634 | + usb_put_urb(urb); |
---|
| 635 | + spin_lock_irqsave(&q->lock, flags); |
---|
| 636 | + } |
---|
| 637 | + spin_unlock_irqrestore (&q->lock, flags); |
---|
| 638 | + |
---|
| 639 | + return count; |
---|
| 640 | +} |
---|
| 641 | + |
---|
| 642 | +/* Flush all pending rx urbs */ |
---|
| 643 | +/* minidrivers may need to do this when the MTU changes */ |
---|
| 644 | + |
---|
| 645 | +static |
---|
| 646 | +void axusbnet_unlink_rx_urbs(struct usbnet *dev) |
---|
| 647 | +{ |
---|
| 648 | + if (netif_running(dev->net)) { |
---|
| 649 | + (void) unlink_urbs(dev, &dev->rxq); |
---|
| 650 | + tasklet_schedule(&dev->bh); |
---|
| 651 | + } |
---|
| 652 | +} |
---|
| 653 | + |
---|
| 654 | +/*-------------------------------------------------------------------------*/ |
---|
| 655 | + |
---|
| 656 | +/* precondition: never called in_interrupt */ |
---|
| 657 | + |
---|
| 658 | +static |
---|
| 659 | +int axusbnet_stop(struct net_device *net) |
---|
| 660 | +{ |
---|
| 661 | + struct usbnet *dev = netdev_priv(net); |
---|
| 662 | + struct driver_info *info = dev->driver_info; |
---|
| 663 | + |
---|
| 664 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) |
---|
| 665 | + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup); |
---|
| 666 | +#else |
---|
| 667 | + DECLARE_WAIT_QUEUE_HEAD(unlink_wakeup); |
---|
| 668 | +#endif |
---|
| 669 | + DECLARE_WAITQUEUE(wait, current); |
---|
| 670 | + |
---|
| 671 | + netif_stop_queue(net); |
---|
| 672 | + |
---|
| 673 | + if (netif_msg_ifdown(dev)) |
---|
| 674 | + devinfo(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld", |
---|
| 675 | + dev->stats.rx_packets, dev->stats.tx_packets, |
---|
| 676 | + dev->stats.rx_errors, dev->stats.tx_errors); |
---|
| 677 | + |
---|
| 678 | + /* allow minidriver to stop correctly (wireless devices to turn off |
---|
| 679 | + * radio etc) */ |
---|
| 680 | + if (info->stop) { |
---|
| 681 | + int retval; |
---|
| 682 | + retval = info->stop(dev); |
---|
| 683 | + if (retval < 0 && netif_msg_ifdown(dev)) |
---|
| 684 | + devinfo(dev, |
---|
| 685 | + "stop fail (%d) usbnet usb-%s-%s, %s", |
---|
| 686 | + retval, |
---|
| 687 | + dev->udev->bus->bus_name, dev->udev->devpath, |
---|
| 688 | + info->description); |
---|
| 689 | + } |
---|
| 690 | + |
---|
| 691 | + if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { |
---|
| 692 | + int temp; |
---|
| 693 | + /* ensure there are no more active urbs */ |
---|
| 694 | + add_wait_queue(&unlink_wakeup, &wait); |
---|
| 695 | + dev->wait = &unlink_wakeup; |
---|
| 696 | + temp = unlink_urbs(dev, &dev->txq) + |
---|
| 697 | + unlink_urbs(dev, &dev->rxq); |
---|
| 698 | + |
---|
| 699 | + /* maybe wait for deletions to finish. */ |
---|
| 700 | + while (!skb_queue_empty(&dev->rxq) |
---|
| 701 | + && !skb_queue_empty(&dev->txq) |
---|
| 702 | + && !skb_queue_empty(&dev->done)) { |
---|
| 703 | + msleep(UNLINK_TIMEOUT_MS); |
---|
| 704 | + if (netif_msg_ifdown(dev)) |
---|
| 705 | + devdbg(dev, "waited for %d urb completions", |
---|
| 706 | + temp); |
---|
| 707 | + } |
---|
| 708 | + dev->wait = NULL; |
---|
| 709 | + remove_wait_queue(&unlink_wakeup, &wait); |
---|
| 710 | + } |
---|
| 711 | + |
---|
| 712 | + usb_kill_urb(dev->interrupt); |
---|
| 713 | + |
---|
| 714 | + /* deferred work (task, timer, softirq) must also stop. |
---|
| 715 | + * can't flush_scheduled_work() until we drop rtnl (later), |
---|
| 716 | + * else workers could deadlock; so make workers a NOP. |
---|
| 717 | + */ |
---|
| 718 | + dev->flags = 0; |
---|
| 719 | + del_timer_sync(&dev->delay); |
---|
| 720 | + tasklet_kill(&dev->bh); |
---|
| 721 | + |
---|
| 722 | + return 0; |
---|
| 723 | +} |
---|
| 724 | + |
---|
| 725 | +/*-------------------------------------------------------------------------*/ |
---|
| 726 | + |
---|
| 727 | +/* posts reads, and enables write queuing */ |
---|
| 728 | + |
---|
| 729 | +/* precondition: never called in_interrupt */ |
---|
| 730 | + |
---|
| 731 | +static |
---|
| 732 | +int axusbnet_open(struct net_device *net) |
---|
| 733 | +{ |
---|
| 734 | + struct usbnet *dev = netdev_priv(net); |
---|
| 735 | + int retval = 0; |
---|
| 736 | + struct driver_info *info = dev->driver_info; |
---|
| 737 | + |
---|
| 738 | + /* put into "known safe" state */ |
---|
| 739 | + if (info->reset) { |
---|
| 740 | + retval = info->reset(dev); |
---|
| 741 | + if (retval < 0) { |
---|
| 742 | + if (netif_msg_ifup(dev)) |
---|
| 743 | + devinfo(dev, |
---|
| 744 | + "open reset fail (%d) usbnet usb-%s-%s, %s", |
---|
| 745 | + retval, |
---|
| 746 | + dev->udev->bus->bus_name, |
---|
| 747 | + dev->udev->devpath, |
---|
| 748 | + info->description); |
---|
| 749 | + goto done; |
---|
| 750 | + } |
---|
| 751 | + } |
---|
| 752 | + |
---|
| 753 | + /* insist peer be connected */ |
---|
| 754 | + if (info->check_connect) { |
---|
| 755 | + retval = info->check_connect(dev); |
---|
| 756 | + if (retval < 0) { |
---|
| 757 | + if (netif_msg_ifup(dev)) |
---|
| 758 | + devdbg(dev, "can't open; %d", retval); |
---|
| 759 | + goto done; |
---|
| 760 | + } |
---|
| 761 | + } |
---|
| 762 | + |
---|
| 763 | + /* start any status interrupt transfer */ |
---|
| 764 | + if (dev->interrupt) { |
---|
| 765 | + retval = usb_submit_urb(dev->interrupt, GFP_KERNEL); |
---|
| 766 | + if (retval < 0) { |
---|
| 767 | + if (netif_msg_ifup(dev)) |
---|
| 768 | + deverr(dev, "intr submit %d", retval); |
---|
| 769 | + goto done; |
---|
| 770 | + } |
---|
| 771 | + } |
---|
| 772 | + |
---|
| 773 | + /* reset rx error state */ |
---|
| 774 | + dev->pkt_cnt = 0; |
---|
| 775 | + dev->pkt_err = 0; |
---|
| 776 | + clear_bit(EVENT_RX_KILL, &dev->flags); |
---|
| 777 | + |
---|
| 778 | + netif_start_queue(net); |
---|
| 779 | + if (netif_msg_ifup(dev)) { |
---|
| 780 | + char *framing; |
---|
| 781 | + |
---|
| 782 | + if (dev->driver_info->flags & FLAG_FRAMING_NC) |
---|
| 783 | + framing = "NetChip"; |
---|
| 784 | + else if (dev->driver_info->flags & FLAG_FRAMING_GL) |
---|
| 785 | + framing = "GeneSys"; |
---|
| 786 | + else if (dev->driver_info->flags & FLAG_FRAMING_Z) |
---|
| 787 | + framing = "Zaurus"; |
---|
| 788 | + else if (dev->driver_info->flags & FLAG_FRAMING_RN) |
---|
| 789 | + framing = "RNDIS"; |
---|
| 790 | + else if (dev->driver_info->flags & FLAG_FRAMING_AX) |
---|
| 791 | + framing = "ASIX"; |
---|
| 792 | + else |
---|
| 793 | + framing = "simple"; |
---|
| 794 | + |
---|
| 795 | + devinfo(dev, "open: enable queueing (rx %d, tx %d) mtu %d %s framing", |
---|
| 796 | + (int)RX_QLEN(dev), (int)TX_QLEN(dev), dev->net->mtu, |
---|
| 797 | + framing); |
---|
| 798 | + } |
---|
| 799 | + |
---|
| 800 | + /* delay posting reads until we're fully open */ |
---|
| 801 | + tasklet_schedule(&dev->bh); |
---|
| 802 | + return retval; |
---|
| 803 | +done: |
---|
| 804 | + return retval; |
---|
| 805 | +} |
---|
| 806 | + |
---|
| 807 | +/*-------------------------------------------------------------------------*/ |
---|
| 808 | + |
---|
| 809 | +/* ethtool methods; minidrivers may need to add some more, but |
---|
| 810 | + * they'll probably want to use this base set. |
---|
| 811 | + */ |
---|
| 812 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0) |
---|
| 813 | +static |
---|
| 814 | +int axusbnet_get_settings(struct net_device *net, struct ethtool_cmd *cmd) |
---|
| 815 | +{ |
---|
| 816 | + struct usbnet *dev = netdev_priv(net); |
---|
| 817 | + |
---|
| 818 | + if (!dev->mii.mdio_read) |
---|
| 819 | + return -EOPNOTSUPP; |
---|
| 820 | + |
---|
| 821 | + return mii_ethtool_gset(&dev->mii, cmd); |
---|
| 822 | +} |
---|
| 823 | + |
---|
| 824 | +static |
---|
| 825 | +int axusbnet_set_settings(struct net_device *net, struct ethtool_cmd *cmd) |
---|
| 826 | +{ |
---|
| 827 | + struct usbnet *dev = netdev_priv(net); |
---|
| 828 | + int retval; |
---|
| 829 | + |
---|
| 830 | + if (!dev->mii.mdio_write) |
---|
| 831 | + return -EOPNOTSUPP; |
---|
| 832 | + |
---|
| 833 | + retval = mii_ethtool_sset(&dev->mii, cmd); |
---|
| 834 | + |
---|
| 835 | + /* link speed/duplex might have changed */ |
---|
| 836 | + if (dev->driver_info->link_reset) |
---|
| 837 | + dev->driver_info->link_reset(dev); |
---|
| 838 | + |
---|
| 839 | + return retval; |
---|
| 840 | + |
---|
| 841 | +} |
---|
| 842 | +#endif |
---|
| 843 | +static |
---|
| 844 | +u32 axusbnet_get_link(struct net_device *net) |
---|
| 845 | +{ |
---|
| 846 | + struct usbnet *dev = netdev_priv(net); |
---|
| 847 | + |
---|
| 848 | + /* If a check_connect is defined, return its result */ |
---|
| 849 | + if (dev->driver_info->check_connect) |
---|
| 850 | + return dev->driver_info->check_connect(dev) == 0; |
---|
| 851 | + |
---|
| 852 | + /* if the device has mii operations, use those */ |
---|
| 853 | + if (dev->mii.mdio_read) |
---|
| 854 | + return mii_link_ok(&dev->mii); |
---|
| 855 | + |
---|
| 856 | + /* Otherwise, dtrt for drivers calling netif_carrier_{on,off} */ |
---|
| 857 | + return ethtool_op_get_link(net); |
---|
| 858 | +} |
---|
| 859 | + |
---|
| 860 | +static |
---|
| 861 | +int axusbnet_nway_reset(struct net_device *net) |
---|
| 862 | +{ |
---|
| 863 | + struct usbnet *dev = netdev_priv(net); |
---|
| 864 | + |
---|
| 865 | + if (!dev->mii.mdio_write) |
---|
| 866 | + return -EOPNOTSUPP; |
---|
| 867 | + |
---|
| 868 | + return mii_nway_restart(&dev->mii); |
---|
| 869 | +} |
---|
| 870 | + |
---|
| 871 | +static |
---|
| 872 | +void axusbnet_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) |
---|
| 873 | +{ |
---|
| 874 | + struct usbnet *dev = netdev_priv(net); |
---|
| 875 | + |
---|
| 876 | + strncpy(info->driver, dev->driver_name, sizeof(info->driver)); |
---|
| 877 | + strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); |
---|
| 878 | + strncpy(info->fw_version, dev->driver_info->description, |
---|
| 879 | + sizeof(info->fw_version)); |
---|
| 880 | + usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info)); |
---|
| 881 | +} |
---|
| 882 | + |
---|
| 883 | +static |
---|
| 884 | +u32 axusbnet_get_msglevel(struct net_device *net) |
---|
| 885 | +{ |
---|
| 886 | + struct usbnet *dev = netdev_priv(net); |
---|
| 887 | + |
---|
| 888 | + return dev->msg_enable; |
---|
| 889 | +} |
---|
| 890 | + |
---|
| 891 | +static |
---|
| 892 | +void axusbnet_set_msglevel(struct net_device *net, u32 level) |
---|
| 893 | +{ |
---|
| 894 | + struct usbnet *dev = netdev_priv(net); |
---|
| 895 | + |
---|
| 896 | + dev->msg_enable = level; |
---|
| 897 | +} |
---|
| 898 | + |
---|
| 899 | +/* drivers may override default ethtool_ops in their bind() routine */ |
---|
| 900 | +static struct ethtool_ops axusbnet_ethtool_ops = { |
---|
| 901 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0) |
---|
| 902 | + .get_settings = axusbnet_get_settings, |
---|
| 903 | + .set_settings = axusbnet_set_settings, |
---|
| 904 | +#endif |
---|
| 905 | + .get_link = axusbnet_get_link, |
---|
| 906 | + .nway_reset = axusbnet_nway_reset, |
---|
| 907 | + .get_drvinfo = axusbnet_get_drvinfo, |
---|
| 908 | + .get_msglevel = axusbnet_get_msglevel, |
---|
| 909 | + .set_msglevel = axusbnet_set_msglevel, |
---|
| 910 | +}; |
---|
| 911 | + |
---|
| 912 | +/*-------------------------------------------------------------------------*/ |
---|
| 913 | + |
---|
| 914 | +/* work that cannot be done in interrupt context uses keventd. |
---|
| 915 | + * |
---|
| 916 | + * NOTE: with 2.5 we could do more of this using completion callbacks, |
---|
| 917 | + * especially now that control transfers can be queued. |
---|
| 918 | + */ |
---|
| 919 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 920 | +static void kevent(void *data) |
---|
| 921 | +{ |
---|
| 922 | + struct usbnet *dev = (struct usbnet *)data; |
---|
| 923 | +#else |
---|
| 924 | +static void kevent(struct work_struct *work) |
---|
| 925 | +{ |
---|
| 926 | + struct usbnet *dev = |
---|
| 927 | + container_of(work, struct usbnet, kevent); |
---|
| 928 | +#endif |
---|
| 929 | + int status; |
---|
| 930 | + |
---|
| 931 | + /* usb_clear_halt() needs a thread context */ |
---|
| 932 | + if (test_bit(EVENT_TX_HALT, &dev->flags)) { |
---|
| 933 | + |
---|
| 934 | + unlink_urbs(dev, &dev->txq); |
---|
| 935 | + status = usb_clear_halt(dev->udev, dev->out); |
---|
| 936 | + if (status < 0 |
---|
| 937 | + && status != -EPIPE |
---|
| 938 | + && status != -ESHUTDOWN) { |
---|
| 939 | + if (netif_msg_tx_err(dev)) |
---|
| 940 | + deverr(dev, "can't clear tx halt, status %d", |
---|
| 941 | + status); |
---|
| 942 | + } else { |
---|
| 943 | + clear_bit(EVENT_TX_HALT, &dev->flags); |
---|
| 944 | + if (status != -ESHUTDOWN) |
---|
| 945 | + netif_wake_queue(dev->net); |
---|
| 946 | + } |
---|
| 947 | + } |
---|
| 948 | + if (test_bit(EVENT_RX_HALT, &dev->flags)) { |
---|
| 949 | + |
---|
| 950 | + unlink_urbs(dev, &dev->rxq); |
---|
| 951 | + status = usb_clear_halt(dev->udev, dev->in); |
---|
| 952 | + if (status < 0 |
---|
| 953 | + && status != -EPIPE |
---|
| 954 | + && status != -ESHUTDOWN) { |
---|
| 955 | + if (netif_msg_rx_err(dev)) |
---|
| 956 | + deverr(dev, "can't clear rx halt, status %d", |
---|
| 957 | + status); |
---|
| 958 | + } else { |
---|
| 959 | + clear_bit(EVENT_RX_HALT, &dev->flags); |
---|
| 960 | + tasklet_schedule(&dev->bh); |
---|
| 961 | + } |
---|
| 962 | + } |
---|
| 963 | + |
---|
| 964 | + /* tasklet could resubmit itself forever if memory is tight */ |
---|
| 965 | + if (test_bit(EVENT_RX_MEMORY, &dev->flags)) { |
---|
| 966 | + struct urb *urb = NULL; |
---|
| 967 | + |
---|
| 968 | + if (netif_running(dev->net)) |
---|
| 969 | + urb = usb_alloc_urb(0, GFP_KERNEL); |
---|
| 970 | + else |
---|
| 971 | + clear_bit(EVENT_RX_MEMORY, &dev->flags); |
---|
| 972 | + if (urb != NULL) { |
---|
| 973 | + clear_bit(EVENT_RX_MEMORY, &dev->flags); |
---|
| 974 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) |
---|
| 975 | + urb->transfer_flags |= URB_ASYNC_UNLINK; |
---|
| 976 | +#endif |
---|
| 977 | + rx_submit(dev, urb, GFP_KERNEL); |
---|
| 978 | + tasklet_schedule(&dev->bh); |
---|
| 979 | + } |
---|
| 980 | + } |
---|
| 981 | + |
---|
| 982 | + if (test_bit(EVENT_LINK_RESET, &dev->flags)) { |
---|
| 983 | + struct driver_info *info = dev->driver_info; |
---|
| 984 | + |
---|
| 985 | + clear_bit(EVENT_LINK_RESET, &dev->flags); |
---|
| 986 | + if (info->link_reset) { |
---|
| 987 | + int retval; |
---|
| 988 | + retval = info->link_reset(dev); |
---|
| 989 | + if (retval < 0) { |
---|
| 990 | + devinfo(dev, |
---|
| 991 | + "link reset failed (%d) usbnet usb-%s-%s, %s", |
---|
| 992 | + retval, |
---|
| 993 | + dev->udev->bus->bus_name, |
---|
| 994 | + dev->udev->devpath, |
---|
| 995 | + info->description); |
---|
| 996 | + } |
---|
| 997 | + } |
---|
| 998 | + } |
---|
| 999 | + |
---|
| 1000 | + if (dev->flags) |
---|
| 1001 | + devdbg(dev, "kevent done, flags = 0x%lx", dev->flags); |
---|
| 1002 | +} |
---|
| 1003 | + |
---|
| 1004 | +/*-------------------------------------------------------------------------*/ |
---|
| 1005 | + |
---|
| 1006 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) |
---|
| 1007 | +static void tx_complete(struct urb *urb, struct pt_regs *regs) |
---|
| 1008 | +#else |
---|
| 1009 | +static void tx_complete(struct urb *urb) |
---|
| 1010 | +#endif |
---|
| 1011 | +{ |
---|
| 1012 | + struct sk_buff *skb = (struct sk_buff *) urb->context; |
---|
| 1013 | + struct skb_data *entry = (struct skb_data *) skb->cb; |
---|
| 1014 | + struct usbnet *dev = entry->dev; |
---|
| 1015 | + |
---|
| 1016 | + if (urb->status == 0) { |
---|
| 1017 | + dev->stats.tx_packets++; |
---|
| 1018 | + dev->stats.tx_bytes += entry->length; |
---|
| 1019 | + } else { |
---|
| 1020 | + dev->stats.tx_errors++; |
---|
| 1021 | + |
---|
| 1022 | + switch (urb->status) { |
---|
| 1023 | + case -EPIPE: |
---|
| 1024 | + axusbnet_defer_kevent(dev, EVENT_TX_HALT); |
---|
| 1025 | + break; |
---|
| 1026 | + |
---|
| 1027 | + /* software-driven interface shutdown */ |
---|
| 1028 | + case -ECONNRESET: /* async unlink */ |
---|
| 1029 | + case -ESHUTDOWN: /* hardware gone */ |
---|
| 1030 | + break; |
---|
| 1031 | + |
---|
| 1032 | + /* like rx, tx gets controller i/o faults during khubd delays */ |
---|
| 1033 | + /* and so it uses the same throttling mechanism. */ |
---|
| 1034 | + case -EPROTO: |
---|
| 1035 | + case -ETIME: |
---|
| 1036 | + case -EILSEQ: |
---|
| 1037 | + if (!timer_pending(&dev->delay)) { |
---|
| 1038 | + mod_timer(&dev->delay, |
---|
| 1039 | + jiffies + THROTTLE_JIFFIES); |
---|
| 1040 | + if (netif_msg_link(dev)) |
---|
| 1041 | + devdbg(dev, "tx throttle %d", |
---|
| 1042 | + urb->status); |
---|
| 1043 | + } |
---|
| 1044 | + netif_stop_queue(dev->net); |
---|
| 1045 | + break; |
---|
| 1046 | + default: |
---|
| 1047 | + if (netif_msg_tx_err(dev)) |
---|
| 1048 | + devdbg(dev, "tx err %d", entry->urb->status); |
---|
| 1049 | + break; |
---|
| 1050 | + } |
---|
| 1051 | + } |
---|
| 1052 | + |
---|
| 1053 | + urb->dev = NULL; |
---|
| 1054 | + entry->state = tx_done; |
---|
| 1055 | + (void) defer_bh(dev, skb, &dev->txq, tx_done); |
---|
| 1056 | +} |
---|
| 1057 | + |
---|
| 1058 | +/*-------------------------------------------------------------------------*/ |
---|
| 1059 | + |
---|
| 1060 | +static |
---|
| 1061 | +void axusbnet_tx_timeout(struct net_device *net) |
---|
| 1062 | +{ |
---|
| 1063 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1064 | + struct driver_info *info = dev->driver_info; |
---|
| 1065 | + |
---|
| 1066 | + if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { |
---|
| 1067 | + unlink_urbs(dev, &dev->txq); |
---|
| 1068 | + } |
---|
| 1069 | + tasklet_schedule(&dev->bh); |
---|
| 1070 | + |
---|
| 1071 | + /* FIXME: device recovery -- reset? */ |
---|
| 1072 | +} |
---|
| 1073 | + |
---|
| 1074 | +/*-------------------------------------------------------------------------*/ |
---|
| 1075 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) |
---|
| 1076 | +static int |
---|
| 1077 | +#else |
---|
| 1078 | +static netdev_tx_t |
---|
| 1079 | +#endif |
---|
| 1080 | +axusbnet_start_xmit(struct sk_buff *skb, struct net_device *net) |
---|
| 1081 | +{ |
---|
| 1082 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1083 | + int length; |
---|
| 1084 | + struct urb *urb = NULL; |
---|
| 1085 | + struct skb_data *entry; |
---|
| 1086 | + struct driver_info *info = dev->driver_info; |
---|
| 1087 | + unsigned long flags; |
---|
| 1088 | + int retval; |
---|
| 1089 | + |
---|
| 1090 | + /* some devices want funky USB-level framing, for */ |
---|
| 1091 | + /* win32 driver (usually) and/or hardware quirks */ |
---|
| 1092 | + if (info->tx_fixup) { |
---|
| 1093 | + skb = info->tx_fixup(dev, skb, GFP_ATOMIC); |
---|
| 1094 | + if (!skb) { |
---|
| 1095 | + if (netif_msg_tx_err(dev)) |
---|
| 1096 | + devdbg(dev, "can't tx_fixup skb"); |
---|
| 1097 | + goto drop; |
---|
| 1098 | + } |
---|
| 1099 | + } |
---|
| 1100 | + length = skb->len; |
---|
| 1101 | + |
---|
| 1102 | + urb = usb_alloc_urb(0, GFP_ATOMIC); |
---|
| 1103 | + if (!urb) { |
---|
| 1104 | + if (netif_msg_tx_err(dev)) |
---|
| 1105 | + devdbg(dev, "no urb"); |
---|
| 1106 | + goto drop; |
---|
| 1107 | + } |
---|
| 1108 | + |
---|
| 1109 | + entry = (struct skb_data *) skb->cb; |
---|
| 1110 | + entry->urb = urb; |
---|
| 1111 | + entry->dev = dev; |
---|
| 1112 | + entry->state = tx_start; |
---|
| 1113 | + entry->length = length; |
---|
| 1114 | + |
---|
| 1115 | + usb_fill_bulk_urb(urb, dev->udev, dev->out, skb->data, |
---|
| 1116 | + skb->len, tx_complete, skb); |
---|
| 1117 | + |
---|
| 1118 | + /* don't assume the hardware handles USB_ZERO_PACKET |
---|
| 1119 | + * NOTE: strictly conforming cdc-ether devices should expect |
---|
| 1120 | + * the ZLP here, but ignore the one-byte packet. |
---|
| 1121 | + */ |
---|
| 1122 | + if (!(info->flags & FLAG_SEND_ZLP) && (length % dev->maxpacket) == 0) { |
---|
| 1123 | + urb->transfer_buffer_length++; |
---|
| 1124 | + if (skb_tailroom(skb)) { |
---|
| 1125 | + skb->data[skb->len] = 0; |
---|
| 1126 | + __skb_put(skb, 1); |
---|
| 1127 | + } |
---|
| 1128 | + } |
---|
| 1129 | + |
---|
| 1130 | + spin_lock_irqsave(&dev->txq.lock, flags); |
---|
| 1131 | + |
---|
| 1132 | + switch ((retval = usb_submit_urb(urb, GFP_ATOMIC))) { |
---|
| 1133 | + case -EPIPE: |
---|
| 1134 | + netif_stop_queue(net); |
---|
| 1135 | + axusbnet_defer_kevent(dev, EVENT_TX_HALT); |
---|
| 1136 | + break; |
---|
| 1137 | + default: |
---|
| 1138 | + if (netif_msg_tx_err(dev)) |
---|
| 1139 | + devdbg(dev, "tx: submit urb err %d", retval); |
---|
| 1140 | + break; |
---|
| 1141 | + case 0: |
---|
| 1142 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) |
---|
| 1143 | + net->trans_start = jiffies; |
---|
| 1144 | +#else |
---|
| 1145 | + netif_trans_update(net); |
---|
| 1146 | +#endif |
---|
| 1147 | + __skb_queue_tail(&dev->txq, skb); |
---|
| 1148 | + if (dev->txq.qlen >= TX_QLEN(dev)) |
---|
| 1149 | + netif_stop_queue(net); |
---|
| 1150 | + } |
---|
| 1151 | + spin_unlock_irqrestore(&dev->txq.lock, flags); |
---|
| 1152 | + |
---|
| 1153 | + if (retval) { |
---|
| 1154 | + if (netif_msg_tx_err(dev)) |
---|
| 1155 | + devdbg(dev, "drop, code %d", retval); |
---|
| 1156 | +drop: |
---|
| 1157 | + dev->stats.tx_dropped++; |
---|
| 1158 | + if (skb) |
---|
| 1159 | + dev_kfree_skb_any(skb); |
---|
| 1160 | + usb_free_urb(urb); |
---|
| 1161 | + } else if (netif_msg_tx_queued(dev)) { |
---|
| 1162 | + devdbg(dev, "> tx, len %d, type 0x%x", |
---|
| 1163 | + length, skb->protocol); |
---|
| 1164 | + } |
---|
| 1165 | + return NETDEV_TX_OK; |
---|
| 1166 | +} |
---|
| 1167 | + |
---|
| 1168 | +/*-------------------------------------------------------------------------*/ |
---|
| 1169 | + |
---|
| 1170 | +/* tasklet (work deferred from completions, in_irq) or timer */ |
---|
| 1171 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) |
---|
| 1172 | +static void axusbnet_bh(unsigned long param) |
---|
| 1173 | +#else |
---|
| 1174 | +static void axusbnet_bh (struct timer_list *t) |
---|
| 1175 | +#endif |
---|
| 1176 | +{ |
---|
| 1177 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) |
---|
| 1178 | + struct usbnet *dev = (struct usbnet *) param; |
---|
| 1179 | +#else |
---|
| 1180 | + struct usbnet *dev = from_timer(dev, t, delay); |
---|
| 1181 | +#endif |
---|
| 1182 | + struct sk_buff *skb; |
---|
| 1183 | + struct skb_data *entry = NULL; |
---|
| 1184 | + |
---|
| 1185 | + while ((skb = skb_dequeue(&dev->done))) { |
---|
| 1186 | + entry = (struct skb_data *) skb->cb; |
---|
| 1187 | + switch (entry->state) { |
---|
| 1188 | + case rx_done: |
---|
| 1189 | + entry->state = rx_cleanup; |
---|
| 1190 | + rx_process(dev, skb); |
---|
| 1191 | + continue; |
---|
| 1192 | + case tx_done: |
---|
| 1193 | + case rx_cleanup: |
---|
| 1194 | + usb_free_urb(entry->urb); |
---|
| 1195 | + dev_kfree_skb(skb); |
---|
| 1196 | + continue; |
---|
| 1197 | + default: |
---|
| 1198 | + devdbg(dev, "bogus skb state %d", entry->state); |
---|
| 1199 | + } |
---|
| 1200 | + } |
---|
| 1201 | + |
---|
| 1202 | + /* restart RX again after disabling due to high error rate */ |
---|
| 1203 | + clear_bit(EVENT_RX_KILL, &dev->flags); |
---|
| 1204 | + |
---|
| 1205 | + /* waiting for all pending urbs to complete? */ |
---|
| 1206 | + if (dev->wait) { |
---|
| 1207 | + if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) |
---|
| 1208 | + wake_up(dev->wait); |
---|
| 1209 | + |
---|
| 1210 | + /* or are we maybe short a few urbs? */ |
---|
| 1211 | + } else if (netif_running(dev->net) |
---|
| 1212 | + && netif_device_present(dev->net) |
---|
| 1213 | + && !timer_pending(&dev->delay) |
---|
| 1214 | + && !test_bit(EVENT_RX_HALT, &dev->flags)) { |
---|
| 1215 | + int temp = dev->rxq.qlen; |
---|
| 1216 | + int qlen = RX_QLEN(dev); |
---|
| 1217 | + |
---|
| 1218 | + if (temp < qlen) { |
---|
| 1219 | + struct urb *urb = NULL; |
---|
| 1220 | + int i; |
---|
| 1221 | + |
---|
| 1222 | + /* don't refill the queue all at once */ |
---|
| 1223 | + for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { |
---|
| 1224 | + urb = usb_alloc_urb(0, GFP_ATOMIC); |
---|
| 1225 | + if (urb != NULL) { |
---|
| 1226 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) |
---|
| 1227 | + urb->transfer_flags |= URB_ASYNC_UNLINK; |
---|
| 1228 | +#endif |
---|
| 1229 | + rx_submit(dev, urb, GFP_ATOMIC); |
---|
| 1230 | + } |
---|
| 1231 | + } |
---|
| 1232 | + if (temp != dev->rxq.qlen && netif_msg_link(dev)) |
---|
| 1233 | + devdbg(dev, "rxqlen %d --> %d", |
---|
| 1234 | + temp, dev->rxq.qlen); |
---|
| 1235 | + if (dev->rxq.qlen < qlen) |
---|
| 1236 | + tasklet_schedule(&dev->bh); |
---|
| 1237 | + } |
---|
| 1238 | + if (dev->txq.qlen < TX_QLEN(dev)) |
---|
| 1239 | + netif_wake_queue(dev->net); |
---|
| 1240 | + } |
---|
| 1241 | +} |
---|
| 1242 | + |
---|
| 1243 | + |
---|
| 1244 | +/*------------------------------------------------------------------------- |
---|
| 1245 | + * |
---|
| 1246 | + * USB Device Driver support |
---|
| 1247 | + * |
---|
| 1248 | + *-------------------------------------------------------------------------*/ |
---|
| 1249 | + |
---|
| 1250 | +/* precondition: never called in_interrupt */ |
---|
| 1251 | + |
---|
| 1252 | +static |
---|
| 1253 | +void axusbnet_disconnect(struct usb_interface *intf) |
---|
| 1254 | +{ |
---|
| 1255 | + struct usbnet *dev; |
---|
| 1256 | + struct usb_device *xdev; |
---|
| 1257 | + struct net_device *net; |
---|
| 1258 | + |
---|
| 1259 | + dev = usb_get_intfdata(intf); |
---|
| 1260 | + usb_set_intfdata(intf, NULL); |
---|
| 1261 | + if (!dev) |
---|
| 1262 | + return; |
---|
| 1263 | + |
---|
| 1264 | + xdev = interface_to_usbdev(intf); |
---|
| 1265 | + |
---|
| 1266 | + if (netif_msg_probe(dev)) |
---|
| 1267 | + devinfo(dev, "unregister '%s' usb-%s-%s, %s", |
---|
| 1268 | + intf->dev.driver->name, |
---|
| 1269 | + xdev->bus->bus_name, xdev->devpath, |
---|
| 1270 | + dev->driver_info->description); |
---|
| 1271 | + |
---|
| 1272 | + net = dev->net; |
---|
| 1273 | + unregister_netdev(net); |
---|
| 1274 | + |
---|
| 1275 | + /* we don't hold rtnl here ... */ |
---|
| 1276 | + flush_scheduled_work(); |
---|
| 1277 | + |
---|
| 1278 | + if (dev->driver_info->unbind) |
---|
| 1279 | + dev->driver_info->unbind(dev, intf); |
---|
| 1280 | + |
---|
| 1281 | + free_netdev(net); |
---|
| 1282 | + usb_put_dev(xdev); |
---|
| 1283 | +} |
---|
| 1284 | + |
---|
| 1285 | +/*-------------------------------------------------------------------------*/ |
---|
| 1286 | + |
---|
| 1287 | +/* precondition: never called in_interrupt */ |
---|
| 1288 | + |
---|
| 1289 | +static int |
---|
| 1290 | +axusbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod) |
---|
| 1291 | +{ |
---|
| 1292 | + struct usbnet *dev; |
---|
| 1293 | + struct net_device *net; |
---|
| 1294 | + struct usb_host_interface *interface; |
---|
| 1295 | + struct driver_info *info; |
---|
| 1296 | + struct usb_device *xdev; |
---|
| 1297 | + int status; |
---|
| 1298 | + const char *name; |
---|
| 1299 | + |
---|
| 1300 | + name = udev->dev.driver->name; |
---|
| 1301 | + info = (struct driver_info *) prod->driver_info; |
---|
| 1302 | + if (!info) { |
---|
| 1303 | + printk(KERN_ERR "blacklisted by %s\n", name); |
---|
| 1304 | + return -ENODEV; |
---|
| 1305 | + } |
---|
| 1306 | + xdev = interface_to_usbdev(udev); |
---|
| 1307 | + interface = udev->cur_altsetting; |
---|
| 1308 | + |
---|
| 1309 | + usb_get_dev(xdev); |
---|
| 1310 | + |
---|
| 1311 | + status = -ENOMEM; |
---|
| 1312 | + |
---|
| 1313 | + /* set up our own records */ |
---|
| 1314 | + net = alloc_etherdev(sizeof(*dev)); |
---|
| 1315 | + if (!net) { |
---|
| 1316 | + printk(KERN_ERR "can't kmalloc dev"); |
---|
| 1317 | + goto out; |
---|
| 1318 | + } |
---|
| 1319 | + |
---|
| 1320 | + dev = netdev_priv(net); |
---|
| 1321 | + dev->udev = xdev; |
---|
| 1322 | + dev->intf = udev; |
---|
| 1323 | + dev->driver_info = info; |
---|
| 1324 | + dev->driver_name = name; |
---|
| 1325 | + dev->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV | |
---|
| 1326 | + NETIF_MSG_PROBE | NETIF_MSG_LINK); |
---|
| 1327 | + skb_queue_head_init(&dev->rxq); |
---|
| 1328 | + skb_queue_head_init(&dev->txq); |
---|
| 1329 | + skb_queue_head_init(&dev->done); |
---|
| 1330 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) |
---|
| 1331 | + dev->bh.func = axusbnet_bh; |
---|
| 1332 | + dev->bh.data = (unsigned long) dev; |
---|
| 1333 | +#else |
---|
| 1334 | + dev->bh.func = (void (*)(unsigned long))axusbnet_bh; |
---|
| 1335 | + dev->bh.data = (unsigned long)&dev->delay; |
---|
| 1336 | +#endif |
---|
| 1337 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 1338 | + INIT_WORK(&dev->kevent, kevent, dev); |
---|
| 1339 | +#else |
---|
| 1340 | + INIT_WORK(&dev->kevent, kevent); |
---|
| 1341 | +#endif |
---|
| 1342 | + |
---|
| 1343 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) |
---|
| 1344 | + dev->delay.function = axusbnet_bh; |
---|
| 1345 | + dev->delay.data = (unsigned long) dev; |
---|
| 1346 | + init_timer(&dev->delay); |
---|
| 1347 | +#else |
---|
| 1348 | + timer_setup(&dev->delay, axusbnet_bh, 0); |
---|
| 1349 | +#endif |
---|
| 1350 | + /* mutex_init(&dev->phy_mutex); */ |
---|
| 1351 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) |
---|
| 1352 | + init_MUTEX (&dev->sem); |
---|
| 1353 | +#else |
---|
| 1354 | + sema_init(&dev->sem,1); |
---|
| 1355 | +#endif |
---|
| 1356 | + dev->net = net; |
---|
| 1357 | + |
---|
| 1358 | + /* rx and tx sides can use different message sizes; |
---|
| 1359 | + * bind() should set rx_urb_size in that case. |
---|
| 1360 | + */ |
---|
| 1361 | + dev->hard_mtu = net->mtu + net->hard_header_len; |
---|
| 1362 | + |
---|
| 1363 | +#if 0 |
---|
| 1364 | + /* dma_supported() is deeply broken on almost all architectures */ |
---|
| 1365 | + /* possible with some EHCI controllers */ |
---|
| 1366 | + if (dma_supported(&udev->dev, DMA_BIT_MASK(64))) |
---|
| 1367 | + net->features |= NETIF_F_HIGHDMA; |
---|
| 1368 | +#endif |
---|
| 1369 | + |
---|
| 1370 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 1371 | + net->open = axusbnet_open, |
---|
| 1372 | + net->stop = axusbnet_stop, |
---|
| 1373 | + net->hard_start_xmit = axusbnet_start_xmit, |
---|
| 1374 | + net->tx_timeout = axusbnet_tx_timeout, |
---|
| 1375 | + net->get_stats = axusbnet_get_stats; |
---|
| 1376 | +#endif |
---|
| 1377 | + |
---|
| 1378 | + net->watchdog_timeo = TX_TIMEOUT_JIFFIES; |
---|
| 1379 | + net->ethtool_ops = &axusbnet_ethtool_ops; |
---|
| 1380 | + |
---|
| 1381 | + /* allow device-specific bind/init procedures */ |
---|
| 1382 | + /* NOTE net->name still not usable ... */ |
---|
| 1383 | + status = info->bind(dev, udev); |
---|
| 1384 | + if (status < 0) { |
---|
| 1385 | + deverr(dev, "Binding device failed: %d", status); |
---|
| 1386 | + goto out1; |
---|
| 1387 | + } |
---|
| 1388 | + |
---|
| 1389 | + /* maybe the remote can't receive an Ethernet MTU */ |
---|
| 1390 | + if (net->mtu > (dev->hard_mtu - net->hard_header_len)) |
---|
| 1391 | + net->mtu = dev->hard_mtu - net->hard_header_len; |
---|
| 1392 | + |
---|
| 1393 | + status = init_status(dev, udev); |
---|
| 1394 | + if (status < 0) |
---|
| 1395 | + goto out3; |
---|
| 1396 | + |
---|
| 1397 | + if (!dev->rx_urb_size) |
---|
| 1398 | + dev->rx_urb_size = dev->hard_mtu; |
---|
| 1399 | + dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1); |
---|
| 1400 | + |
---|
| 1401 | + SET_NETDEV_DEV(net, &udev->dev); |
---|
| 1402 | + status = register_netdev(net); |
---|
| 1403 | + if (status) { |
---|
| 1404 | + deverr(dev, "net device registration failed: %d", status); |
---|
| 1405 | + goto out3; |
---|
| 1406 | + } |
---|
| 1407 | + |
---|
| 1408 | + if (netif_msg_probe(dev)) |
---|
| 1409 | + devinfo(dev, "register '%s' at usb-%s-%s, %s, %pM", |
---|
| 1410 | + udev->dev.driver->name, |
---|
| 1411 | + xdev->bus->bus_name, xdev->devpath, |
---|
| 1412 | + dev->driver_info->description, |
---|
| 1413 | + net->dev_addr); |
---|
| 1414 | + |
---|
| 1415 | + /* ok, it's ready to go. */ |
---|
| 1416 | + usb_set_intfdata(udev, dev); |
---|
| 1417 | + |
---|
| 1418 | + /* start as if the link is up */ |
---|
| 1419 | + netif_device_attach(net); |
---|
| 1420 | + |
---|
| 1421 | + return 0; |
---|
| 1422 | + |
---|
| 1423 | +out3: |
---|
| 1424 | + if (info->unbind) |
---|
| 1425 | + info->unbind(dev, udev); |
---|
| 1426 | +out1: |
---|
| 1427 | + free_netdev(net); |
---|
| 1428 | +out: |
---|
| 1429 | + usb_put_dev(xdev); |
---|
| 1430 | + return status; |
---|
| 1431 | +} |
---|
| 1432 | + |
---|
| 1433 | +/*-------------------------------------------------------------------------*/ |
---|
| 1434 | + |
---|
| 1435 | +/* |
---|
| 1436 | + * suspend the whole driver as soon as the first interface is suspended |
---|
| 1437 | + * resume only when the last interface is resumed |
---|
| 1438 | + */ |
---|
| 1439 | + |
---|
| 1440 | +static int axusbnet_suspend(struct usb_interface *intf, |
---|
| 1441 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) |
---|
| 1442 | +pm_message_t message) |
---|
| 1443 | +#else |
---|
| 1444 | +u32 message) |
---|
| 1445 | +#endif |
---|
| 1446 | +{ |
---|
| 1447 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 1448 | + |
---|
| 1449 | + if (!dev->suspend_count++) { |
---|
| 1450 | + /* |
---|
| 1451 | + * accelerate emptying of the rx and queues, to avoid |
---|
| 1452 | + * having everything error out. |
---|
| 1453 | + */ |
---|
| 1454 | + netif_device_detach(dev->net); |
---|
| 1455 | + (void) unlink_urbs(dev, &dev->rxq); |
---|
| 1456 | + (void) unlink_urbs(dev, &dev->txq); |
---|
| 1457 | + usb_kill_urb(dev->interrupt); |
---|
| 1458 | + /* |
---|
| 1459 | + * reattach so runtime management can use and |
---|
| 1460 | + * wake the device |
---|
| 1461 | + */ |
---|
| 1462 | + netif_device_attach(dev->net); |
---|
| 1463 | + } |
---|
| 1464 | + return 0; |
---|
| 1465 | +} |
---|
| 1466 | + |
---|
| 1467 | +static int |
---|
| 1468 | +axusbnet_resume(struct usb_interface *intf) |
---|
| 1469 | +{ |
---|
| 1470 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 1471 | + int retval = 0; |
---|
| 1472 | + |
---|
| 1473 | + if (!--dev->suspend_count) |
---|
| 1474 | + tasklet_schedule(&dev->bh); |
---|
| 1475 | + |
---|
| 1476 | + retval = init_status(dev, intf); |
---|
| 1477 | + if (retval < 0) |
---|
| 1478 | + return retval; |
---|
| 1479 | + |
---|
| 1480 | + if (dev->interrupt) { |
---|
| 1481 | + retval = usb_submit_urb(dev->interrupt, GFP_KERNEL); |
---|
| 1482 | + if (retval < 0 && netif_msg_ifup(dev)) |
---|
| 1483 | + deverr(dev, "intr submit %d", retval); |
---|
| 1484 | + } |
---|
| 1485 | + |
---|
| 1486 | + return retval; |
---|
| 1487 | +} |
---|
| 1488 | + |
---|
.. | .. |
---|
| 1 | +/* |
---|
| 2 | + * USB Networking Link Interface |
---|
| 3 | + * |
---|
| 4 | + * Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net> |
---|
| 5 | + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> |
---|
| 6 | + * |
---|
| 7 | + * This program is free software; you can redistribute it and/or modify |
---|
| 8 | + * it under the terms of the GNU General Public License as published by |
---|
| 9 | + * the Free Software Foundation; either version 2 of the License, or |
---|
| 10 | + * (at your option) any later version. |
---|
| 11 | + * |
---|
| 12 | + * This program is distributed in the hope that it will be useful, |
---|
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 15 | + * GNU General Public License for more details. |
---|
| 16 | + * |
---|
| 17 | + * You should have received a copy of the GNU General Public License |
---|
| 18 | + * along with this program; if not, write to the Free Software |
---|
| 19 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 20 | + */ |
---|
| 21 | + |
---|
| 22 | +#ifndef __LINUX_USB_USBNET_H |
---|
| 23 | +#define __LINUX_USB_USBNET_H |
---|
| 24 | + |
---|
| 25 | +#ifndef gfp_t |
---|
| 26 | +#define gfp_t int |
---|
| 27 | +#endif |
---|
| 28 | + |
---|
| 29 | +/* interface from usbnet core to each USB networking link we handle */ |
---|
| 30 | +struct usbnet { |
---|
| 31 | + /* housekeeping */ |
---|
| 32 | + struct usb_device *udev; |
---|
| 33 | + struct usb_interface *intf; |
---|
| 34 | + struct driver_info *driver_info; |
---|
| 35 | + const char *driver_name; |
---|
| 36 | + void *driver_priv; |
---|
| 37 | + wait_queue_head_t *wait; |
---|
| 38 | + /* struct mutex phy_mutex; */ |
---|
| 39 | + unsigned char suspend_count; |
---|
| 40 | + unsigned char pkt_cnt, pkt_err; |
---|
| 41 | + |
---|
| 42 | + /* i/o info: pipes etc */ |
---|
| 43 | + unsigned in, out; |
---|
| 44 | + struct usb_host_endpoint *status; |
---|
| 45 | + unsigned maxpacket; |
---|
| 46 | + struct timer_list delay; |
---|
| 47 | + |
---|
| 48 | + /* protocol/interface state */ |
---|
| 49 | + struct net_device *net; |
---|
| 50 | + struct net_device_stats stats; |
---|
| 51 | + int msg_enable; |
---|
| 52 | + unsigned long data[5]; |
---|
| 53 | + u32 xid; |
---|
| 54 | + u32 hard_mtu; /* count any extra framing */ |
---|
| 55 | + size_t rx_urb_size; /* size for rx urbs */ |
---|
| 56 | + struct mii_if_info mii; |
---|
| 57 | + |
---|
| 58 | + /* various kinds of pending driver work */ |
---|
| 59 | + struct sk_buff_head rxq; |
---|
| 60 | + struct sk_buff_head txq; |
---|
| 61 | + struct sk_buff_head done; |
---|
| 62 | + struct sk_buff_head rxq_pause; |
---|
| 63 | + struct urb *interrupt; |
---|
| 64 | + struct tasklet_struct bh; |
---|
| 65 | + |
---|
| 66 | + struct work_struct kevent; |
---|
| 67 | + struct semaphore sem; |
---|
| 68 | + unsigned long flags; |
---|
| 69 | +# define EVENT_TX_HALT 0 |
---|
| 70 | +# define EVENT_RX_HALT 1 |
---|
| 71 | +# define EVENT_RX_MEMORY 2 |
---|
| 72 | +# define EVENT_STS_SPLIT 3 |
---|
| 73 | +# define EVENT_LINK_RESET 4 |
---|
| 74 | +# define EVENT_RX_PAUSED 5 |
---|
| 75 | +# define EVENT_RX_KILL 10 |
---|
| 76 | + |
---|
| 77 | + void *priv; /* point to minidriver private data */ |
---|
| 78 | + unsigned char rx_size; |
---|
| 79 | +}; |
---|
| 80 | + |
---|
| 81 | +static inline struct usb_driver *driver_of(struct usb_interface *intf) |
---|
| 82 | +{ |
---|
| 83 | + return to_usb_driver(intf->dev.driver); |
---|
| 84 | +} |
---|
| 85 | + |
---|
| 86 | +/* interface from the device/framing level "minidriver" to core */ |
---|
| 87 | +struct driver_info { |
---|
| 88 | + char *description; |
---|
| 89 | + |
---|
| 90 | + int flags; |
---|
| 91 | +/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */ |
---|
| 92 | +#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */ |
---|
| 93 | +#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ |
---|
| 94 | +#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ |
---|
| 95 | +#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */ |
---|
| 96 | + |
---|
| 97 | +#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */ |
---|
| 98 | +#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */ |
---|
| 99 | + |
---|
| 100 | +#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ |
---|
| 101 | +#define FLAG_WLAN 0x0080 /* use "wlan%d" names */ |
---|
| 102 | +#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */ |
---|
| 103 | +#define FLAG_SEND_ZLP 0x0200 /* hw requires ZLPs are sent */ |
---|
| 104 | +#define FLAG_HW_IP_ALIGNMENT 0x0400 /* AX88772B support hardware IP alignment */ |
---|
| 105 | + |
---|
| 106 | + |
---|
| 107 | + /* init device ... can sleep, or cause probe() failure */ |
---|
| 108 | + int (*bind)(struct usbnet *, struct usb_interface *); |
---|
| 109 | + |
---|
| 110 | + /* cleanup device ... can sleep, but can't fail */ |
---|
| 111 | + void (*unbind)(struct usbnet *, struct usb_interface *); |
---|
| 112 | + |
---|
| 113 | + /* reset device ... can sleep */ |
---|
| 114 | + int (*reset)(struct usbnet *); |
---|
| 115 | + |
---|
| 116 | + /* stop device ... can sleep */ |
---|
| 117 | + int (*stop)(struct usbnet *); |
---|
| 118 | + |
---|
| 119 | + /* see if peer is connected ... can sleep */ |
---|
| 120 | + int (*check_connect)(struct usbnet *); |
---|
| 121 | + |
---|
| 122 | + /* for status polling */ |
---|
| 123 | + void (*status)(struct usbnet *, struct urb *); |
---|
| 124 | + |
---|
| 125 | + /* link reset handling, called from defer_kevent */ |
---|
| 126 | + int (*link_reset)(struct usbnet *); |
---|
| 127 | + |
---|
| 128 | + /* fixup rx packet (strip framing) */ |
---|
| 129 | + int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); |
---|
| 130 | + |
---|
| 131 | + /* fixup tx packet (add framing) */ |
---|
| 132 | + struct sk_buff *(*tx_fixup)(struct usbnet *dev, |
---|
| 133 | + struct sk_buff *skb, gfp_t flags); |
---|
| 134 | + |
---|
| 135 | + /* early initialization code, can sleep. This is for minidrivers |
---|
| 136 | + * having 'subminidrivers' that need to do extra initialization |
---|
| 137 | + * right after minidriver have initialized hardware. */ |
---|
| 138 | + int (*early_init)(struct usbnet *dev); |
---|
| 139 | + |
---|
| 140 | + /* called by minidriver when receiving indication */ |
---|
| 141 | + void (*indication)(struct usbnet *dev, void *ind, int indlen); |
---|
| 142 | + |
---|
| 143 | + /* for new devices, use the descriptor-reading code instead */ |
---|
| 144 | + int in; /* rx endpoint */ |
---|
| 145 | + int out; /* tx endpoint */ |
---|
| 146 | + |
---|
| 147 | + unsigned long data; /* Misc driver specific data */ |
---|
| 148 | +}; |
---|
| 149 | + |
---|
| 150 | +/* Drivers that reuse some of the standard USB CDC infrastructure |
---|
| 151 | + * (notably, using multiple interfaces according to the CDC |
---|
| 152 | + * union descriptor) get some helper code. |
---|
| 153 | + */ |
---|
| 154 | +struct cdc_state { |
---|
| 155 | + struct usb_cdc_header_desc *header; |
---|
| 156 | + struct usb_cdc_union_desc *u; |
---|
| 157 | + struct usb_cdc_ether_desc *ether; |
---|
| 158 | + struct usb_interface *control; |
---|
| 159 | + struct usb_interface *data; |
---|
| 160 | +}; |
---|
| 161 | + |
---|
| 162 | +/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */ |
---|
| 163 | +#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ |
---|
| 164 | + |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ |
---|
| 165 | + |USB_CDC_PACKET_TYPE_PROMISCUOUS \ |
---|
| 166 | + |USB_CDC_PACKET_TYPE_DIRECTED) |
---|
| 167 | + |
---|
| 168 | + |
---|
| 169 | +/* we record the state for each of our queued skbs */ |
---|
| 170 | +enum skb_state { |
---|
| 171 | + illegal = 0, |
---|
| 172 | + tx_start, tx_done, |
---|
| 173 | + rx_start, rx_done, rx_cleanup, |
---|
| 174 | + unlink_start |
---|
| 175 | +}; |
---|
| 176 | + |
---|
| 177 | +struct skb_data { /* skb->cb is one of these */ |
---|
| 178 | + struct urb *urb; |
---|
| 179 | + struct usbnet *dev; |
---|
| 180 | + enum skb_state state; |
---|
| 181 | + size_t length; |
---|
| 182 | +}; |
---|
| 183 | + |
---|
| 184 | +#ifndef skb_queue_walk_safe |
---|
| 185 | +#define skb_queue_walk_safe(queue, skb, tmp) \ |
---|
| 186 | + for (skb = (queue)->next, tmp = skb->next; \ |
---|
| 187 | + skb != (struct sk_buff *)(queue); \ |
---|
| 188 | + skb = tmp, tmp = skb->next) |
---|
| 189 | +#endif |
---|
| 190 | + |
---|
| 191 | +/* messaging support includes the interface name, so it must not be |
---|
| 192 | + * used before it has one ... notably, in minidriver bind() calls. |
---|
| 193 | + */ |
---|
| 194 | +#ifdef DEBUG |
---|
| 195 | +#define devdbg(usbnet, fmt, arg...) \ |
---|
| 196 | + printk("%s: " fmt "\n" , (usbnet)->net->name , ## arg) |
---|
| 197 | +#else |
---|
| 198 | +#define devdbg(usbnet, fmt, arg...) \ |
---|
| 199 | + ({ if (0) printk("%s: " fmt "\n" , (usbnet)->net->name , \ |
---|
| 200 | + ## arg); 0; }) |
---|
| 201 | +#endif |
---|
| 202 | + |
---|
| 203 | +#define deverr(usbnet, fmt, arg...) \ |
---|
| 204 | + printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg) |
---|
| 205 | +#define devwarn(usbnet, fmt, arg...) \ |
---|
| 206 | + printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg) |
---|
| 207 | + |
---|
| 208 | +#define devinfo(usbnet, fmt, arg...) \ |
---|
| 209 | + printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \ |
---|
| 210 | + |
---|
| 211 | + |
---|
| 212 | +#endif /* __LINUX_USB_USBNET_H */ |
---|
.. | .. |
---|
| 1 | +/* |
---|
| 2 | + ********************************************************************************* |
---|
| 3 | + * Copyright (c) 2005 ASIX Electronic Corporation All rights reserved. |
---|
| 4 | + * |
---|
| 5 | + * This is unpublished proprietary source code of ASIX Electronic Corporation |
---|
| 6 | + * |
---|
| 7 | + * The copyright notice above does not evidence any actual or intended |
---|
| 8 | + * publication of such source code. |
---|
| 9 | + ********************************************************************************* |
---|
| 10 | + */ |
---|
| 11 | + |
---|
| 12 | +#ifndef __COMMAND_H__ |
---|
| 13 | +#define __COMMAND_H__ |
---|
| 14 | + |
---|
| 15 | +/* |
---|
| 16 | + |
---|
| 17 | +#include <linux/module.h> |
---|
| 18 | +#include <linux/version.h> |
---|
| 19 | +#include <linux/kernel.h> |
---|
| 20 | +#include <linux/errno.h> |
---|
| 21 | +#include <linux/pci.h> |
---|
| 22 | +#include <linux/init.h> |
---|
| 23 | +#include <linux/interrupt.h> |
---|
| 24 | +#include <linux/ethtool.h> |
---|
| 25 | +#include <linux/netdevice.h> |
---|
| 26 | +#include <linux/etherdevice.h> |
---|
| 27 | +#include <linux/delay.h> |
---|
| 28 | +#include <linux/random.h> |
---|
| 29 | +#include <linux/mii.h> |
---|
| 30 | + |
---|
| 31 | +#include <linux/in.h> |
---|
| 32 | + |
---|
| 33 | +#include <asm/system.h> |
---|
| 34 | +#include <asm/io.h> |
---|
| 35 | +#include <asm/uaccess.h> |
---|
| 36 | +*/ |
---|
| 37 | +/* NAMING CONSTANT DECLARATIONS */ |
---|
| 38 | +#define AX88772B_SIGNATURE "AX88772B" |
---|
| 39 | +#define AX88772B_DRV_NAME "AX88772B" |
---|
| 40 | + |
---|
| 41 | +#define DEBUG_PARAM (DEB_NONE) |
---|
| 42 | +#define DEB_NONE (0) |
---|
| 43 | +#define DEB_TOOL (1 << 0) |
---|
| 44 | +#define DEB_DRIVER (1 << 1) |
---|
| 45 | +#define DPRINT_D(...) while (1) { \ |
---|
| 46 | + if (DEBUG_PARAM & DEB_DRIVER) \ |
---|
| 47 | + printk(__VA_ARGS__); \ |
---|
| 48 | + break; \ |
---|
| 49 | + } |
---|
| 50 | + |
---|
| 51 | +/* ioctl Command Definition */ |
---|
| 52 | +#define AX_PRIVATE SIOCDEVPRIVATE |
---|
| 53 | + |
---|
| 54 | +/* private Command Definition */ |
---|
| 55 | +#define AX_SIGNATURE 0 |
---|
| 56 | +#define AX_READ_EEPROM 1 |
---|
| 57 | +#define AX_WRITE_EEPROM 2 |
---|
| 58 | + |
---|
| 59 | +typedef struct _AX_IOCTL_COMMAND { |
---|
| 60 | + unsigned short ioctl_cmd; |
---|
| 61 | + unsigned char sig[16]; |
---|
| 62 | + unsigned short *buf; |
---|
| 63 | + unsigned short size; |
---|
| 64 | + unsigned char delay; |
---|
| 65 | +}AX_IOCTL_COMMAND; |
---|
| 66 | + |
---|
| 67 | +#endif /* end of command.h */ |
---|
.. | .. |
---|
| 1 | +/*========================================================================== |
---|
| 2 | + * Module Name : console_debug.c |
---|
| 3 | + * Purpose : |
---|
| 4 | + * Author : |
---|
| 5 | + * Date : |
---|
| 6 | + * Notes : |
---|
| 7 | + * $Log$ |
---|
| 8 | + *========================================================================== |
---|
| 9 | + */ |
---|
| 10 | + |
---|
| 11 | +/* INCLUDE FILE DECLARATIONS */ |
---|
| 12 | +#include <string.h> |
---|
| 13 | +#include <sys/socket.h> |
---|
| 14 | +#include <sys/ioctl.h> |
---|
| 15 | +#include <net/if.h> |
---|
| 16 | +#include <stdio.h> |
---|
| 17 | +#include <sys/types.h> |
---|
| 18 | +#include <sys/stat.h> |
---|
| 19 | +#include <fcntl.h> |
---|
| 20 | +#include <termios.h> |
---|
| 21 | +#include <netinet/in.h> |
---|
| 22 | +#include <arpa/inet.h> |
---|
| 23 | +#include <linux/sockios.h> |
---|
| 24 | +#include <ctype.h> |
---|
| 25 | +#include <stdlib.h> |
---|
| 26 | +#if NET_INTERFACE == INTERFACE_SCAN |
---|
| 27 | +#include <ifaddrs.h> |
---|
| 28 | +#endif |
---|
| 29 | +#include "ioctl.h" |
---|
| 30 | + |
---|
| 31 | +/* STATIC VARIABLE DECLARATIONS */ |
---|
| 32 | +#define AX88772C_IOCTL_VERSION "AX88772C/AX88772B/AX88772A/AX88760/AX88772/AX88178 Linux SROM IOCTL Tool version 1.6.0" |
---|
| 33 | + |
---|
| 34 | +/* LOCAL SUBPROGRAM DECLARATIONS */ |
---|
| 35 | +static unsigned long STR_TO_U32(const char *cp,char **endp,unsigned int base); |
---|
| 36 | + |
---|
| 37 | + |
---|
| 38 | +/* LOCAL SUBPROGRAM BODIES */ |
---|
| 39 | +static void debug_func(char *func_name, unsigned short *buf, unsigned long wLen) |
---|
| 40 | +{ |
---|
| 41 | +#if (DEBUG_PARAM & DEB_TOOL) |
---|
| 42 | + int i; |
---|
| 43 | + char str_buf[50]; |
---|
| 44 | + printf("%s :\n", func_name); |
---|
| 45 | + printf("---------------------------------------\n"); |
---|
| 46 | + for (i = 0; i < wLen / 8; i++) { |
---|
| 47 | + int j = 8 * i; |
---|
| 48 | + snprintf(str_buf, 50, |
---|
| 49 | + "%04x %04x %04x %04x %04x %04x " |
---|
| 50 | + "%04x %04x\n", |
---|
| 51 | + *(buf + j + 0), *(buf + j + 1), |
---|
| 52 | + *(buf + j + 2), *(buf + j + 3), |
---|
| 53 | + *(buf + j + 4), *(buf + j + 5), |
---|
| 54 | + *(buf + j + 6), *(buf + j + 7)); |
---|
| 55 | + printf("%s", str_buf); |
---|
| 56 | + } |
---|
| 57 | + printf("------------------------------------%3ld\n", wLen); |
---|
| 58 | +#endif |
---|
| 59 | +} |
---|
| 60 | + |
---|
| 61 | + |
---|
| 62 | +static void show_usage(void) |
---|
| 63 | +{ |
---|
| 64 | + int i; |
---|
| 65 | + printf ("\n%s\n",AX88772C_IOCTL_VERSION); |
---|
| 66 | + printf ("Usage:\n"); |
---|
| 67 | + for (i = 0; command_list[i].cmd != NULL; i++) |
---|
| 68 | + printf ("%s\n", command_list[i].help_ins); |
---|
| 69 | +} |
---|
| 70 | + |
---|
| 71 | +static unsigned long STR_TO_U32(const char *cp,char **endp,unsigned int base) |
---|
| 72 | +{ |
---|
| 73 | + unsigned long result = 0,value; |
---|
| 74 | + |
---|
| 75 | + if (*cp == '0') { |
---|
| 76 | + cp++; |
---|
| 77 | + if ((*cp == 'x') && isxdigit(cp[1])) { |
---|
| 78 | + base = 16; |
---|
| 79 | + cp++; |
---|
| 80 | + } |
---|
| 81 | + if (!base) { |
---|
| 82 | + base = 8; |
---|
| 83 | + } |
---|
| 84 | + } |
---|
| 85 | + if (!base) { |
---|
| 86 | + base = 10; |
---|
| 87 | + } |
---|
| 88 | + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) |
---|
| 89 | + ? toupper(*cp) : *cp)-'A'+10) < base) { |
---|
| 90 | + result = result*base + value; |
---|
| 91 | + cp++; |
---|
| 92 | + } |
---|
| 93 | + if (endp) |
---|
| 94 | + *endp = (char *)cp; |
---|
| 95 | + |
---|
| 96 | + return result; |
---|
| 97 | +} |
---|
| 98 | + |
---|
| 99 | +void help_func (struct ax_command_info *info) |
---|
| 100 | +{ |
---|
| 101 | + int i; |
---|
| 102 | + |
---|
| 103 | + if (info->argv[2] == NULL) { |
---|
| 104 | + for(i=0; command_list[i].cmd != NULL; i++) { |
---|
| 105 | + printf ("%s%s\n", command_list[i].help_ins, command_list[i].help_desc); |
---|
| 106 | + } |
---|
| 107 | + } |
---|
| 108 | + |
---|
| 109 | + for (i = 0; command_list[i].cmd != NULL; i++) |
---|
| 110 | + { |
---|
| 111 | + if (strncmp(info->argv[1], command_list[i].cmd, strlen(command_list[i].cmd)) == 0 ) { |
---|
| 112 | + printf ("%s%s\n", command_list[i].help_ins, command_list[i].help_desc); |
---|
| 113 | + return; |
---|
| 114 | + } |
---|
| 115 | + } |
---|
| 116 | + |
---|
| 117 | +} |
---|
| 118 | + |
---|
| 119 | +int compare_file(struct ax_command_info *info) |
---|
| 120 | +{ |
---|
| 121 | + struct ifreq *ifr = (struct ifreq *)info->ifr; |
---|
| 122 | + unsigned short *rout_buf; |
---|
| 123 | + unsigned short *ori_buf; |
---|
| 124 | + AX_IOCTL_COMMAND *ioctl_cmd = (AX_IOCTL_COMMAND *)(ifr->ifr_data); |
---|
| 125 | + int i; |
---|
| 126 | + |
---|
| 127 | + rout_buf = malloc(sizeof(unsigned short) * ioctl_cmd->size); |
---|
| 128 | + |
---|
| 129 | + ori_buf = ioctl_cmd->buf; |
---|
| 130 | + |
---|
| 131 | + ioctl_cmd->ioctl_cmd = AX_READ_EEPROM; |
---|
| 132 | + ioctl_cmd->buf = rout_buf; |
---|
| 133 | + |
---|
| 134 | + if (ioctl(info->inet_sock, AX_PRIVATE, ifr) < 0) { |
---|
| 135 | + perror("ioctl"); |
---|
| 136 | + return -1; |
---|
| 137 | + } |
---|
| 138 | + |
---|
| 139 | + |
---|
| 140 | + |
---|
| 141 | + for (i = 0; i < ioctl_cmd->size; i++) { |
---|
| 142 | + if (*(ioctl_cmd->buf + i) != *(ori_buf + i)) { |
---|
| 143 | + debug_func("compare_file reeprom", rout_buf, ioctl_cmd->size); |
---|
| 144 | + ioctl_cmd->buf = ori_buf; |
---|
| 145 | + free(rout_buf); |
---|
| 146 | + return -2; |
---|
| 147 | + } |
---|
| 148 | + } |
---|
| 149 | + |
---|
| 150 | + ioctl_cmd->buf = ori_buf; |
---|
| 151 | + free(rout_buf); |
---|
| 152 | + return 0; |
---|
| 153 | +} |
---|
| 154 | + |
---|
| 155 | +void readeeprom_func(struct ax_command_info *info) |
---|
| 156 | +{ |
---|
| 157 | + struct ifreq *ifr = (struct ifreq *)info->ifr; |
---|
| 158 | + AX_IOCTL_COMMAND ioctl_cmd; |
---|
| 159 | + unsigned short *buf; |
---|
| 160 | + unsigned short wLen; |
---|
| 161 | + char str_buf[50]; |
---|
| 162 | + FILE *pFile; |
---|
| 163 | + int i; |
---|
| 164 | + |
---|
| 165 | + if (info->argc < 4) { |
---|
| 166 | + for(i=0; command_list[i].cmd != NULL; i++) { |
---|
| 167 | + if (strncmp(info->argv[1], command_list[i].cmd, |
---|
| 168 | + strlen(command_list[i].cmd)) == 0 ) { |
---|
| 169 | + printf ("%s%s\n", command_list[i].help_ins, |
---|
| 170 | + command_list[i].help_desc); |
---|
| 171 | + return; |
---|
| 172 | + } |
---|
| 173 | + } |
---|
| 174 | + } |
---|
| 175 | + |
---|
| 176 | + wLen = STR_TO_U32(info->argv[3], NULL, 0) / 2; |
---|
| 177 | + |
---|
| 178 | + pFile = fopen(info->argv[2],"w"); |
---|
| 179 | + buf = (unsigned short *)malloc((sizeof(unsigned short) * wLen)); |
---|
| 180 | + |
---|
| 181 | + ioctl_cmd.ioctl_cmd = info->ioctl_cmd; |
---|
| 182 | + ioctl_cmd.size = wLen; |
---|
| 183 | + ioctl_cmd.buf = buf; |
---|
| 184 | + ioctl_cmd.delay = 0; |
---|
| 185 | + |
---|
| 186 | + ifr->ifr_data = (caddr_t)&ioctl_cmd; |
---|
| 187 | + if (ioctl(info->inet_sock, AX_PRIVATE, ifr) < 0) { |
---|
| 188 | + perror("ioctl"); |
---|
| 189 | + free(buf); |
---|
| 190 | + fclose(pFile); |
---|
| 191 | + return; |
---|
| 192 | + } |
---|
| 193 | + for (i = 0; i < wLen / 8; i++) { |
---|
| 194 | + int j = 8 * i; |
---|
| 195 | + snprintf(str_buf, 50, |
---|
| 196 | + "%04x %04x %04x %04x %04x %04x " |
---|
| 197 | + "%04x %04x\n", |
---|
| 198 | + *(buf + j + 0), *(buf + j + 1), |
---|
| 199 | + *(buf + j + 2), *(buf + j + 3), |
---|
| 200 | + *(buf + j + 4), *(buf + j + 5), |
---|
| 201 | + *(buf + j + 6), *(buf + j + 7)); |
---|
| 202 | + fputs(str_buf, pFile); |
---|
| 203 | + } |
---|
| 204 | + printf("Read completely\n\n"); |
---|
| 205 | + free(buf); |
---|
| 206 | + fclose(pFile); |
---|
| 207 | + return; |
---|
| 208 | +} |
---|
| 209 | + |
---|
| 210 | +void writeeeprom_func(struct ax_command_info *info) |
---|
| 211 | +{ |
---|
| 212 | + struct ifreq *ifr = (struct ifreq *)info->ifr; |
---|
| 213 | + AX_IOCTL_COMMAND ioctl_cmd; |
---|
| 214 | + int i; |
---|
| 215 | + unsigned short *buf; |
---|
| 216 | + unsigned short wLen; |
---|
| 217 | + char c[2] = {'\0'}; |
---|
| 218 | + FILE *pFile; |
---|
| 219 | + unsigned char retried = 0; |
---|
| 220 | + |
---|
| 221 | + if (info->argc < 4) { |
---|
| 222 | + for(i=0; command_list[i].cmd != NULL; i++) { |
---|
| 223 | + if (strncmp(info->argv[1], command_list[i].cmd, |
---|
| 224 | + strlen(command_list[i].cmd)) == 0) { |
---|
| 225 | + printf ("%s%s\n", command_list[i].help_ins, |
---|
| 226 | + command_list[i].help_desc); |
---|
| 227 | + return; |
---|
| 228 | + } |
---|
| 229 | + } |
---|
| 230 | + } |
---|
| 231 | + |
---|
| 232 | + pFile = fopen(info->argv[2], "r"); |
---|
| 233 | + |
---|
| 234 | + wLen = STR_TO_U32(info->argv[3], NULL, 0) / 2; |
---|
| 235 | + |
---|
| 236 | + buf = (unsigned short *)malloc(sizeof(unsigned short) * wLen); |
---|
| 237 | + |
---|
| 238 | + for (i = 0; i < wLen / 8; i++) { |
---|
| 239 | + int j = 8 * i; |
---|
| 240 | + fscanf(pFile, "%04X %04X %04X %04X %04X %04X %04X %04X%c", |
---|
| 241 | + (unsigned int *)&buf[j + 0], (unsigned int *)&buf[j + 1], |
---|
| 242 | + (unsigned int *)&buf[j + 2], (unsigned int *)&buf[j + 3], |
---|
| 243 | + (unsigned int *)&buf[j + 4], (unsigned int *)&buf[j + 5], |
---|
| 244 | + (unsigned int *)&buf[j + 6], (unsigned int *)&buf[j + 7], c); |
---|
| 245 | + } |
---|
| 246 | + |
---|
| 247 | + ioctl_cmd.ioctl_cmd = info->ioctl_cmd; |
---|
| 248 | + ioctl_cmd.size = wLen; |
---|
| 249 | + ioctl_cmd.buf = buf; |
---|
| 250 | + ioctl_cmd.delay = 5; |
---|
| 251 | +io: |
---|
| 252 | + ifr->ifr_data = (caddr_t)&ioctl_cmd; |
---|
| 253 | + |
---|
| 254 | +debug_func("writeeeprom_func", buf, wLen); |
---|
| 255 | + |
---|
| 256 | + if (ioctl(info->inet_sock, AX_PRIVATE, ifr) < 0) { |
---|
| 257 | + free(buf); |
---|
| 258 | + fclose(pFile); |
---|
| 259 | + perror("ioctl"); |
---|
| 260 | + return; |
---|
| 261 | + } |
---|
| 262 | + else { |
---|
| 263 | + if (compare_file(info) && retried < 3) { |
---|
| 264 | + ioctl_cmd.delay += 5; |
---|
| 265 | + ioctl_cmd.ioctl_cmd = info->ioctl_cmd; |
---|
| 266 | + retried++; |
---|
| 267 | + goto io; |
---|
| 268 | + } |
---|
| 269 | + if (retried == 3) { |
---|
| 270 | + printf("Failure to write\n\n"); |
---|
| 271 | + free(buf); |
---|
| 272 | + fclose(pFile); |
---|
| 273 | + return; |
---|
| 274 | + } |
---|
| 275 | + } |
---|
| 276 | + |
---|
| 277 | + printf("Write completely\n\n"); |
---|
| 278 | + free(buf); |
---|
| 279 | + fclose(pFile); |
---|
| 280 | + return; |
---|
| 281 | +} |
---|
| 282 | + |
---|
| 283 | +void chgmac_func(struct ax_command_info *info) |
---|
| 284 | +{ |
---|
| 285 | + struct ifreq *ifr = (struct ifreq *)info->ifr; |
---|
| 286 | + AX_IOCTL_COMMAND ioctl_cmd; |
---|
| 287 | + int i; |
---|
| 288 | + unsigned short *buf; |
---|
| 289 | + unsigned int tmp; |
---|
| 290 | + unsigned short wLen; |
---|
| 291 | + unsigned char retried = 0; |
---|
| 292 | + char * pch; |
---|
| 293 | + unsigned int MAC[6] = {0}; |
---|
| 294 | + int ret = 0; |
---|
| 295 | + |
---|
| 296 | + if (info->argc < 4) { |
---|
| 297 | + for(i=0; command_list[i].cmd != NULL; i++) { |
---|
| 298 | + if (strncmp(info->argv[1], command_list[i].cmd, |
---|
| 299 | + strlen(command_list[i].cmd)) == 0) { |
---|
| 300 | + printf ("%s%s\n", command_list[i].help_ins, |
---|
| 301 | + command_list[i].help_desc); |
---|
| 302 | + return; |
---|
| 303 | + } |
---|
| 304 | + } |
---|
| 305 | + } |
---|
| 306 | + |
---|
| 307 | + wLen = STR_TO_U32(info->argv[3], NULL, 0) / 2; |
---|
| 308 | + |
---|
| 309 | + buf = (unsigned short *)malloc(sizeof(unsigned short) * wLen); |
---|
| 310 | + |
---|
| 311 | + ioctl_cmd.ioctl_cmd = AX_READ_EEPROM; |
---|
| 312 | + ioctl_cmd.size = wLen; |
---|
| 313 | + ioctl_cmd.buf = buf; |
---|
| 314 | + ioctl_cmd.delay = 0; |
---|
| 315 | + |
---|
| 316 | + ifr->ifr_data = (caddr_t)&ioctl_cmd; |
---|
| 317 | + |
---|
| 318 | + if (ioctl(info->inet_sock, AX_PRIVATE, ifr) < 0) { |
---|
| 319 | + perror("ioctl"); |
---|
| 320 | + free(buf); |
---|
| 321 | + return; |
---|
| 322 | + } |
---|
| 323 | + |
---|
| 324 | + ret = sscanf(info->argv[2], "%02X:%02X:%02X:%02X:%02X:%02X",(unsigned int*)&MAC[0], |
---|
| 325 | + (unsigned int*)&MAC[1], |
---|
| 326 | + (unsigned int*)&MAC[2], |
---|
| 327 | + (unsigned int*)&MAC[3], |
---|
| 328 | + (unsigned int*)&MAC[4], |
---|
| 329 | + (unsigned int*)&MAC[5]); |
---|
| 330 | + if (6 != ret) { |
---|
| 331 | + printf("Invalid MAC address\n\n"); |
---|
| 332 | + return; |
---|
| 333 | + } |
---|
| 334 | + |
---|
| 335 | + if (*buf == 0x1500) { |
---|
| 336 | + printf("No eeprom exists!\n"); |
---|
| 337 | + printf("Or you must burn the default value first!\n\n"); |
---|
| 338 | + return; |
---|
| 339 | + } |
---|
| 340 | + |
---|
| 341 | + *(((char*)buf) + 8) = (unsigned char)MAC[1]; |
---|
| 342 | + *(((char*)buf) + 9) = (unsigned char)MAC[0]; |
---|
| 343 | + *(((char*)buf) + 10) = (unsigned char)MAC[3]; |
---|
| 344 | + *(((char*)buf) + 11) = (unsigned char)MAC[2]; |
---|
| 345 | + *(((char*)buf) + 12) = (unsigned char)MAC[5]; |
---|
| 346 | + *(((char*)buf) + 13) = (unsigned char)MAC[4]; |
---|
| 347 | + |
---|
| 348 | + ioctl_cmd.ioctl_cmd = info->ioctl_cmd; |
---|
| 349 | + ioctl_cmd.size = wLen; |
---|
| 350 | + ioctl_cmd.buf = buf; |
---|
| 351 | + ioctl_cmd.delay = 5; |
---|
| 352 | + |
---|
| 353 | +io: |
---|
| 354 | + ifr->ifr_data = (caddr_t)&ioctl_cmd; |
---|
| 355 | + |
---|
| 356 | +debug_func("chgmac_func", buf, wLen); |
---|
| 357 | + |
---|
| 358 | + if (ioctl(info->inet_sock, AX_PRIVATE, ifr) < 0) { |
---|
| 359 | + perror("ioctl"); |
---|
| 360 | + free(buf); |
---|
| 361 | + return; |
---|
| 362 | + } |
---|
| 363 | + |
---|
| 364 | + else { |
---|
| 365 | + if (compare_file(info) && retried < 3) { |
---|
| 366 | + ioctl_cmd.delay += 5; |
---|
| 367 | + ioctl_cmd.ioctl_cmd = info->ioctl_cmd; |
---|
| 368 | + retried++; |
---|
| 369 | + goto io; |
---|
| 370 | + } |
---|
| 371 | + if (retried == 3) { |
---|
| 372 | + printf("Failure to write\n\n"); |
---|
| 373 | + free(buf); |
---|
| 374 | + return; |
---|
| 375 | + } |
---|
| 376 | + } |
---|
| 377 | + |
---|
| 378 | + printf("Write completely\n\n"); |
---|
| 379 | + free(buf); |
---|
| 380 | + return; |
---|
| 381 | +} |
---|
| 382 | + |
---|
| 383 | +/* EXPORTED SUBPROGRAM BODIES */ |
---|
| 384 | +int main(int argc, char **argv) |
---|
| 385 | +{ |
---|
| 386 | +#if NET_INTERFACE == INTERFACE_SCAN |
---|
| 387 | + struct ifaddrs *addrs, *tmp; |
---|
| 388 | + unsigned char dev_exist; |
---|
| 389 | +#endif |
---|
| 390 | + struct ifreq ifr; |
---|
| 391 | + struct ax_command_info info; |
---|
| 392 | + AX_IOCTL_COMMAND ioctl_cmd; |
---|
| 393 | + int inet_sock; |
---|
| 394 | + unsigned char i; |
---|
| 395 | + |
---|
| 396 | + if (argc < 2) { |
---|
| 397 | + show_usage(); |
---|
| 398 | + return 0; |
---|
| 399 | + } |
---|
| 400 | + |
---|
| 401 | + inet_sock = socket(AF_INET, SOCK_DGRAM, 0); |
---|
| 402 | + |
---|
| 403 | +#if NET_INTERFACE == INTERFACE_SCAN |
---|
| 404 | + /* Get Device */ |
---|
| 405 | + getifaddrs(&addrs); |
---|
| 406 | + tmp = addrs; |
---|
| 407 | + dev_exist = 0; |
---|
| 408 | + |
---|
| 409 | + while (tmp) { |
---|
| 410 | + memset (&ioctl_cmd, 0, sizeof (AX_IOCTL_COMMAND)); |
---|
| 411 | + ioctl_cmd.ioctl_cmd = AX_SIGNATURE; |
---|
| 412 | + // get network interface name |
---|
| 413 | + sprintf (ifr.ifr_name, "%s", tmp->ifa_name); |
---|
| 414 | + |
---|
| 415 | + ifr.ifr_data = (caddr_t)&ioctl_cmd; |
---|
| 416 | + tmp = tmp->ifa_next; |
---|
| 417 | + |
---|
| 418 | + |
---|
| 419 | + if (ioctl (inet_sock, AX_PRIVATE, &ifr) < 0) { |
---|
| 420 | + continue; |
---|
| 421 | + } |
---|
| 422 | + |
---|
| 423 | + if (strncmp (ioctl_cmd.sig, AX88772B_DRV_NAME, strlen(AX88772B_DRV_NAME)) == 0 ) { |
---|
| 424 | + dev_exist = 1; |
---|
| 425 | + break; |
---|
| 426 | + } |
---|
| 427 | + } |
---|
| 428 | + |
---|
| 429 | + freeifaddrs(addrs); |
---|
| 430 | + |
---|
| 431 | + if (dev_exist == 0) { |
---|
| 432 | + printf ("\n%s\n",AX88772C_IOCTL_VERSION); |
---|
| 433 | + printf("No %s found\n\n", AX88772B_SIGNATURE); |
---|
| 434 | + return 0; |
---|
| 435 | + } |
---|
| 436 | +#else |
---|
| 437 | + for (i = 0; i < 255; i++) { |
---|
| 438 | + |
---|
| 439 | + memset (&ioctl_cmd, 0, sizeof (AX_IOCTL_COMMAND)); |
---|
| 440 | + ioctl_cmd.ioctl_cmd = AX_SIGNATURE; |
---|
| 441 | + |
---|
| 442 | + sprintf (ifr.ifr_name, "eth%d", i); |
---|
| 443 | + ifr.ifr_data = (caddr_t)&ioctl_cmd; |
---|
| 444 | + |
---|
| 445 | + if (ioctl (inet_sock, AX_PRIVATE, &ifr) < 0) { |
---|
| 446 | + continue; |
---|
| 447 | + } |
---|
| 448 | + |
---|
| 449 | + if (strncmp (ioctl_cmd.sig, AX88772B_DRV_NAME, strlen(AX88772B_DRV_NAME)) == 0 ) { |
---|
| 450 | + break; |
---|
| 451 | + } |
---|
| 452 | + |
---|
| 453 | + } |
---|
| 454 | + |
---|
| 455 | + if (i == 255) { |
---|
| 456 | + printf ("\n%s\n",AX88772C_IOCTL_VERSION); |
---|
| 457 | + printf ("No %s found\n\n", AX88772B_SIGNATURE); |
---|
| 458 | + return 0; |
---|
| 459 | + } |
---|
| 460 | +#endif |
---|
| 461 | + for(i=0; command_list[i].cmd != NULL; i++) |
---|
| 462 | + { |
---|
| 463 | + if (strncmp(argv[1], command_list[i].cmd, strlen(command_list[i].cmd)) == 0 ) { |
---|
| 464 | + printf ("\n%s\n",AX88772C_IOCTL_VERSION); |
---|
| 465 | + info.help_ins = command_list[i].help_ins; |
---|
| 466 | + info.help_desc = command_list[i].help_desc; |
---|
| 467 | + info.ifr = 𝔦 |
---|
| 468 | + info.argc = argc; |
---|
| 469 | + info.argv = argv; |
---|
| 470 | + info.inet_sock = inet_sock; |
---|
| 471 | + info.ioctl_cmd = command_list[i].ioctl_cmd; |
---|
| 472 | + (command_list[i].OptFunc)(&info); |
---|
| 473 | + return 0; |
---|
| 474 | + } |
---|
| 475 | + } |
---|
| 476 | + |
---|
| 477 | + printf ("Wrong command\n\n"); |
---|
| 478 | + |
---|
| 479 | + return 0; |
---|
| 480 | +} |
---|
| 481 | + |
---|
.. | .. |
---|
| 1 | +#ifndef ioctl_h |
---|
| 2 | +#define ioctl_h |
---|
| 3 | + |
---|
| 4 | +/* INCLUDE FILE DECLARATIONS */ |
---|
| 5 | +#include "command.h" |
---|
| 6 | + |
---|
| 7 | +/* CHANGE NETWORK INTERFACE WAY */ |
---|
| 8 | +// DEFAULT_SCAN : scan "eth0" - "eth255" |
---|
| 9 | +// INTERFACE_SCAN : scan all available network interfaces |
---|
| 10 | +#define NET_INTERFACE INTERFACE_SCAN |
---|
| 11 | +#define DEFAULT_SCAN 0x00 |
---|
| 12 | +#define INTERFACE_SCAN 0x01 |
---|
| 13 | + |
---|
| 14 | +/* NAMING CONSTANT DECLARATIONS */ |
---|
| 15 | +struct ax_command_info { |
---|
| 16 | + int inet_sock; |
---|
| 17 | + struct ifreq *ifr; |
---|
| 18 | + int argc; |
---|
| 19 | + char **argv; |
---|
| 20 | + unsigned short ioctl_cmd; |
---|
| 21 | + const char *help_ins; |
---|
| 22 | + const char *help_desc; |
---|
| 23 | +}; |
---|
| 24 | + |
---|
| 25 | +const char help_str1[] = |
---|
| 26 | +"./ioctl help [command]\n" |
---|
| 27 | +" -- command description\n"; |
---|
| 28 | +const char help_str2[] = |
---|
| 29 | +" [command] - Display usage of specified command\n"; |
---|
| 30 | + |
---|
| 31 | +const char readeeprom_str1[] = |
---|
| 32 | +"./ioctl reeprom [file] [size]\n" |
---|
| 33 | +" -- AX88772B EEPROM read tool\n"; |
---|
| 34 | +const char readeeprom_str2[] = |
---|
| 35 | +" [file] - Output file\n" |
---|
| 36 | +" [size] - EEPROM SIZE in bytes\n"; |
---|
| 37 | + |
---|
| 38 | +const char writeeeprom_str1[] = |
---|
| 39 | +"./ioctl weeprom [file] [size]\n" |
---|
| 40 | +" -- AX88772B EEPROM write tool\n"; |
---|
| 41 | +const char writeeeprom_str2[] = |
---|
| 42 | +" [file] - Input file\n" |
---|
| 43 | +" [size] - EEPROM SIZE in bytes\n"; |
---|
| 44 | + |
---|
| 45 | +const char chgmac_str1[] = |
---|
| 46 | +"./ioctl chgmac [mac_addr] [size]\n" |
---|
| 47 | +" -- AX88772B EEPROM write tool (specify MAC address)\n"; |
---|
| 48 | +const char chgmac_str2[] = |
---|
| 49 | +" [mac_addr]- MAC address (xx:xx:xx:xx:xx:xx)\n" |
---|
| 50 | +" [size] - EEPROM SIZE in bytes\n"; |
---|
| 51 | + |
---|
| 52 | +/* EXPORTED SUBPROGRAM SPECIFICATIONS */ |
---|
| 53 | +void help_func (struct ax_command_info *info); |
---|
| 54 | +void readeeprom_func(struct ax_command_info *info); |
---|
| 55 | +void writeeeprom_func(struct ax_command_info *info); |
---|
| 56 | +void chgmac_func(struct ax_command_info *info); |
---|
| 57 | +/* TYPE DECLARATIONS */ |
---|
| 58 | + |
---|
| 59 | +typedef void (*MENU_FUNC)(struct ax_command_info *info); |
---|
| 60 | + |
---|
| 61 | +struct { |
---|
| 62 | + char *cmd; |
---|
| 63 | + unsigned short ioctl_cmd; |
---|
| 64 | + MENU_FUNC OptFunc; |
---|
| 65 | + const char *help_ins; |
---|
| 66 | + const char *help_desc; |
---|
| 67 | +} command_list[] = { |
---|
| 68 | + {"help", AX_SIGNATURE, help_func, help_str1, help_str2}, |
---|
| 69 | + {"reeprom", AX_READ_EEPROM, readeeprom_func, readeeprom_str1, readeeprom_str2}, |
---|
| 70 | + {"weeprom", AX_WRITE_EEPROM, writeeeprom_func, writeeeprom_str1, writeeeprom_str2}, |
---|
| 71 | + {"chgmac", AX_WRITE_EEPROM, chgmac_func, chgmac_str1, chgmac_str2}, |
---|
| 72 | + {NULL}, |
---|
| 73 | +}; |
---|
| 74 | + |
---|
| 75 | +#endif /* End of console_debug_h */ |
---|
.. | .. |
---|
| 1 | +AX88772C/AX88772B/AX88772A/AX88760/AX88772/AX88178 Linux SROM tool. |
---|
| 2 | + |
---|
| 3 | +This tool can be used to read/write the EEPROM of AX88772C/AX88772B/AX88772A/AX88760/AX88772/AX88178. |
---|
| 4 | +================ |
---|
| 5 | +Getting Start |
---|
| 6 | +================ |
---|
| 7 | + |
---|
| 8 | +1. Extract the compressed driver source file to your template directory by the |
---|
| 9 | + following command: |
---|
| 10 | + |
---|
| 11 | + [root@localhost template]# tar -xf AX88772B_772A_760_772_178_Linux_EEPROM_Programming_Tool_Source_v1.x.0.tar.bz2 |
---|
| 12 | + |
---|
| 13 | +2. Now, the driver source files should be extracted under the current directory. |
---|
| 14 | + Executing the following command to compile the driver: |
---|
| 15 | + |
---|
| 16 | + [root@localhost template]# make |
---|
| 17 | + |
---|
| 18 | +3. If the compilation is well, the ioctl will be created under the current |
---|
| 19 | + directory. |
---|
| 20 | + |
---|
| 21 | +Note: The default way to find the interface is to scan the ASIX device using the ethx |
---|
| 22 | + (x: 0~255).It is defined in the file, ioctl.h. |
---|
| 23 | + |
---|
| 24 | + (As follows) |
---|
| 25 | + ... |
---|
| 26 | + // DEFAULT_SCAN : scan "eth0" - "eth255" |
---|
| 27 | + // INTERFACE_SCAN : scan all available network interfaces |
---|
| 28 | + #define NET_INTERFACE DEFAULT_SCAN |
---|
| 29 | + #define DEFAULT_SCAN 0x00 |
---|
| 30 | + #define INTERFACE_SCAN 0x01 |
---|
| 31 | + ... |
---|
| 32 | + |
---|
| 33 | + Adjust the contents of #define NET_INTERFACE to select the method you want. |
---|
| 34 | + |
---|
| 35 | +================ |
---|
| 36 | +Usage |
---|
| 37 | +================ |
---|
| 38 | + |
---|
| 39 | +1. If you want to read out values of the EEPROM to a file, go to the driver directory and |
---|
| 40 | + execute the following command: |
---|
| 41 | + |
---|
| 42 | + [root@localhost driver_dir]# ./ioctl reeprom file_name eeprom_size |
---|
| 43 | + |
---|
| 44 | +2. If you want to write values of a file to the EEPROM, go to the driver directory and |
---|
| 45 | + execute the following command: |
---|
| 46 | + |
---|
| 47 | + [root@localhost driver_dir]# ./ioctl weeprom file_name eeprom_size |
---|
| 48 | + |
---|
| 49 | +3. If you want to change the MAC address of a dongle, go to the driver directory and |
---|
| 50 | + execute the following command: |
---|
| 51 | + |
---|
| 52 | + [root@localhost driver_dir]# ./ioctl chgmac mac_addr eeprom_size |
---|
| 53 | + |
---|
| 54 | +4. If you need more information about the instructions, go to the driver directory and |
---|
| 55 | + execute the following commands: |
---|
| 56 | + |
---|
| 57 | + [root@localhost driver_dir]# ./ioctl reeprom help |
---|
| 58 | + |
---|
| 59 | +or |
---|
| 60 | + |
---|
| 61 | + [root@localhost driver_dir]# ./ioctl weeprom help |
---|
.. | .. |
---|
| 1 | +============================================================================ |
---|
| 2 | +ASIX AX88178 USB 2.0 Gigabit Ethernet Network Adapter |
---|
| 3 | +ASIX AX88772 USB 2.0 Fast Ethernet Network Adapter |
---|
| 4 | +ASIX AX88772A USB 2.0 Fast Ethernet Network Adapter |
---|
| 5 | +ASIX AX88760 USB 2.0 MTT HUB and USB 2.0 to Fast Ethernet Combo Controller |
---|
| 6 | +ASIX AX88772B USB 2.0 Fast Ethernet Network Adapter |
---|
| 7 | +ASIX AX88772C USB 2.0 Fast Ethernet Network Adapter |
---|
| 8 | +Driver Compilation & Configuration on the Linux |
---|
| 9 | +============================================================================ |
---|
| 10 | + |
---|
| 11 | +This driver has been verified on Linux kernel 2.6.14 and later. |
---|
| 12 | + |
---|
| 13 | +================ |
---|
| 14 | +Prerequisites |
---|
| 15 | +================ |
---|
| 16 | + |
---|
| 17 | +Prepare to build the driver, you need the Linux kernel sources installed on the |
---|
| 18 | +build machine, and make sure that the version of the running kernel must match |
---|
| 19 | +the installed kernel sources. If you don't have the kernel sources, you can get |
---|
| 20 | +it from www.kernel.org or contact to your Linux distributor. If you don't know |
---|
| 21 | +how to do, please refer to KERNEL-HOWTO. |
---|
| 22 | + |
---|
| 23 | +Note: Please make sure the kernel is built with one of the "Support for |
---|
| 24 | + Host-side, EHCI, OHCI, or UHCI" option support. |
---|
| 25 | + |
---|
| 26 | + |
---|
| 27 | +=========================== |
---|
| 28 | +Conditional Compilation Flag |
---|
| 29 | +=========================== |
---|
| 30 | +[AX_FORCE_BUFF_ALIGN] |
---|
| 31 | +Description: |
---|
| 32 | + There are alignment issues of USB buffer in some USB host controllers. |
---|
| 33 | + Turn on this flag if the implementation of your USB host controller |
---|
| 34 | + cannot handle non-double word aligned buffer. |
---|
| 35 | + When turn on this flag, driver will fixup egress packet aligned on double |
---|
| 36 | + word boundary before deliver to USB host controller. |
---|
| 37 | +Setting: |
---|
| 38 | + 1 -> Enable TX buffers forced on double word alignment. |
---|
| 39 | + 0 -> Disable TX buffers forced on double word alignment. |
---|
| 40 | +Default: |
---|
| 41 | + 0 |
---|
| 42 | + |
---|
| 43 | + |
---|
| 44 | +================ |
---|
| 45 | +Getting Start |
---|
| 46 | +================ |
---|
| 47 | + |
---|
| 48 | +1. Extract the compressed driver source file to your template directory by the |
---|
| 49 | + following command: |
---|
| 50 | + |
---|
| 51 | + [root@localhost template]# tar -xf DRIVER_SOURCE_PACKAGE.tar.bz2 |
---|
| 52 | + |
---|
| 53 | +2. Now, the driver source files should be extracted under the current directory. |
---|
| 54 | + Executing the following command to compile the driver: |
---|
| 55 | + |
---|
| 56 | + [root@localhost template]# make |
---|
| 57 | + |
---|
| 58 | +3. If the compilation is well, the asix.ko will be created under the current |
---|
| 59 | + directory. |
---|
| 60 | + |
---|
| 61 | +4. If you want to use modprobe command to mount the driver, executing the |
---|
| 62 | + following command to install the driver into your Linux: |
---|
| 63 | + |
---|
| 64 | + [root@localhost template]# make install |
---|
| 65 | + |
---|
| 66 | + |
---|
| 67 | +================ |
---|
| 68 | +Usage |
---|
| 69 | +================ |
---|
| 70 | + |
---|
| 71 | +1. If you want to load the driver manually, go to the driver directory and |
---|
| 72 | + execute the following commands: |
---|
| 73 | + |
---|
| 74 | + [root@localhost template]# insmod asix.ko |
---|
| 75 | + |
---|
| 76 | +2. If you had installed the driver during driver compilation, then you can use |
---|
| 77 | + the following command to load the driver automatically. |
---|
| 78 | + |
---|
| 79 | + [root@localhost anywhere]# modprobe asix |
---|
| 80 | + |
---|
| 81 | +If you want to unload the driver, just executing the following command: |
---|
| 82 | + |
---|
| 83 | + [root@localhost anywhere]# rmmod asix |
---|
| 84 | + |
---|
| 85 | +================ |
---|
| 86 | +Special define |
---|
| 87 | +================ |
---|
| 88 | +There is a RX_SKB_COPY preprocessor define in asix.h can solve rx_throttle problem |
---|
| 89 | +in some version of 3.4 Linux kernel. Removing the comment before the define can enable |
---|
| 90 | +this feature. |
---|
| 91 | + |
---|
| 92 | + |
---|
.. | .. |
---|
41 | 41 | obj-$(CONFIG_USB_NET_CDC_MBIM) += cdc_mbim.o |
---|
42 | 42 | obj-$(CONFIG_USB_NET_CH9200) += ch9200.o |
---|
43 | 43 | obj-$(CONFIG_USB_NET_AQC111) += aqc111.o |
---|
| 44 | +#obj-y += AX88772C_eeprom/ |
---|
| 45 | +obj-y += ax88772C/ |
---|
.. | .. |
---|
| 1 | +/* |
---|
| 2 | + * ASIX AX8817X based USB 2.0 Ethernet Devices |
---|
| 3 | + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> |
---|
| 4 | + * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> |
---|
| 5 | + * Copyright (c) 2002-2003 TiVo Inc. |
---|
| 6 | + * |
---|
| 7 | + * This program is free software; you can redistribute it and/or modify |
---|
| 8 | + * it under the terms of the GNU General Public License as published by |
---|
| 9 | + * the Free Software Foundation; either version 2 of the License, or |
---|
| 10 | + * (at your option) any later version. |
---|
| 11 | + * |
---|
| 12 | + * This program is distributed in the hope that it will be useful, |
---|
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 15 | + * GNU General Public License for more details. |
---|
| 16 | + * |
---|
| 17 | + * You should have received a copy of the GNU General Public License |
---|
| 18 | + * along with this program; if not, write to the Free Software |
---|
| 19 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 20 | + */ |
---|
| 21 | + |
---|
| 22 | +/* debug messages, extra info */ |
---|
| 23 | +/* #define DEBUG */ |
---|
| 24 | + |
---|
| 25 | +#include <linux/version.h> |
---|
| 26 | +/* #include <linux/config.h> */ |
---|
| 27 | +#ifdef CONFIG_USB_DEBUG |
---|
| 28 | +# define DEBUG |
---|
| 29 | +#endif |
---|
| 30 | +#include <linux/module.h> |
---|
| 31 | +#include <linux/kmod.h> |
---|
| 32 | +#include <linux/sched.h> |
---|
| 33 | +#include <linux/init.h> |
---|
| 34 | +#include <linux/netdevice.h> |
---|
| 35 | +#include <linux/etherdevice.h> |
---|
| 36 | +#include <linux/ethtool.h> |
---|
| 37 | +#include <linux/workqueue.h> |
---|
| 38 | +#include <linux/mii.h> |
---|
| 39 | +#include <linux/usb.h> |
---|
| 40 | +#include <linux/crc32.h> |
---|
| 41 | + |
---|
| 42 | +#include "axusbnet.c" |
---|
| 43 | +#include "asix.h" |
---|
| 44 | + |
---|
| 45 | +static char version[] = |
---|
| 46 | +KERN_INFO "ASIX USB Ethernet Adapter:v" DRIVER_VERSION |
---|
| 47 | + " http://www.asix.com.tw\n"; |
---|
| 48 | + |
---|
| 49 | +/* configuration of maximum bulk in size */ |
---|
| 50 | +static int bsize = AX88772B_MAX_BULKIN_16K; |
---|
| 51 | +module_param(bsize, int, 0); |
---|
| 52 | +MODULE_PARM_DESC(bsize, "Maximum transfer size per bulk"); |
---|
| 53 | + |
---|
| 54 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 55 | +static void ax88772b_link_reset(void *data); |
---|
| 56 | +static void ax88772a_link_reset(void *data); |
---|
| 57 | +static void ax88772_link_reset(void *data); |
---|
| 58 | +#else |
---|
| 59 | +static void ax88772b_link_reset(struct work_struct *work); |
---|
| 60 | +static void ax88772a_link_reset(struct work_struct *work); |
---|
| 61 | +static void ax88772_link_reset(struct work_struct *work); |
---|
| 62 | +#endif |
---|
| 63 | +static int ax88772a_phy_powerup(struct usbnet *dev); |
---|
| 64 | +static void ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, |
---|
| 65 | + int loc, int val); |
---|
| 66 | +static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc); |
---|
| 67 | +static int ax88772b_set_csums(struct usbnet *dev); |
---|
| 68 | +static int ax88772b_external_phyinit(struct usbnet *dev); |
---|
| 69 | + |
---|
| 70 | +/* ASIX AX8817X based USB 2.0 Ethernet Devices */ |
---|
| 71 | + |
---|
| 72 | +static int ax8817x_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
---|
| 73 | + u16 size, void *data) |
---|
| 74 | +{ |
---|
| 75 | + return usb_control_msg( |
---|
| 76 | + dev->udev, |
---|
| 77 | + usb_rcvctrlpipe(dev->udev, 0), |
---|
| 78 | + cmd, |
---|
| 79 | + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
---|
| 80 | + value, |
---|
| 81 | + index, |
---|
| 82 | + data, |
---|
| 83 | + size, |
---|
| 84 | + USB_CTRL_GET_TIMEOUT); |
---|
| 85 | +} |
---|
| 86 | + |
---|
| 87 | +static int ax8817x_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
---|
| 88 | + u16 size, void *data) |
---|
| 89 | +{ |
---|
| 90 | + return usb_control_msg( |
---|
| 91 | + dev->udev, |
---|
| 92 | + usb_sndctrlpipe(dev->udev, 0), |
---|
| 93 | + cmd, |
---|
| 94 | + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
---|
| 95 | + value, |
---|
| 96 | + index, |
---|
| 97 | + data, |
---|
| 98 | + size, |
---|
| 99 | + USB_CTRL_SET_TIMEOUT); |
---|
| 100 | +} |
---|
| 101 | + |
---|
| 102 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 103 | +static void ax8817x_async_cmd_callback(struct urb *urb, struct pt_regs *regs) |
---|
| 104 | +#else |
---|
| 105 | +static void ax8817x_async_cmd_callback(struct urb *urb) |
---|
| 106 | +#endif |
---|
| 107 | +{ |
---|
| 108 | + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; |
---|
| 109 | + |
---|
| 110 | + if (urb->status < 0) |
---|
| 111 | + printk(KERN_DEBUG "ax8817x_async_cmd_callback() failed with %d", |
---|
| 112 | + urb->status); |
---|
| 113 | + |
---|
| 114 | + kfree(req); |
---|
| 115 | + usb_free_urb(urb); |
---|
| 116 | +} |
---|
| 117 | + |
---|
| 118 | +static int ax8817x_set_mac_addr(struct net_device *net, void *p) |
---|
| 119 | +{ |
---|
| 120 | + struct usbnet *dev = netdev_priv(net); |
---|
| 121 | + struct sockaddr *addr = p; |
---|
| 122 | + int ret; |
---|
| 123 | + |
---|
| 124 | + memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); |
---|
| 125 | + |
---|
| 126 | + /* Set the MAC address */ |
---|
| 127 | + ret = ax8817x_write_cmd(dev, AX88772_CMD_WRITE_NODE_ID, |
---|
| 128 | + 0, 0, ETH_ALEN, net->dev_addr); |
---|
| 129 | + if (ret < 0) |
---|
| 130 | + return ret; |
---|
| 131 | + |
---|
| 132 | + return 0; |
---|
| 133 | +} |
---|
| 134 | + |
---|
| 135 | +static void ax88178_status(struct usbnet *dev, struct urb *urb) |
---|
| 136 | +{ |
---|
| 137 | + struct ax88172_int_data *event; |
---|
| 138 | + struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv; |
---|
| 139 | + int link; |
---|
| 140 | + |
---|
| 141 | + if (urb->actual_length < 8) |
---|
| 142 | + return; |
---|
| 143 | + |
---|
| 144 | + if (ax178dataptr->EepromData == PHY_MODE_MAC_TO_MAC_GMII) |
---|
| 145 | + return; |
---|
| 146 | + |
---|
| 147 | + event = urb->transfer_buffer; |
---|
| 148 | + link = event->link & 0x01; |
---|
| 149 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 150 | + if (link) { |
---|
| 151 | + netif_carrier_on(dev->net); |
---|
| 152 | + axusbnet_defer_kevent(dev, EVENT_LINK_RESET); |
---|
| 153 | + } else |
---|
| 154 | + netif_carrier_off(dev->net); |
---|
| 155 | + devwarn(dev, "ax88178 - Link status is: %d", link); |
---|
| 156 | + } |
---|
| 157 | +} |
---|
| 158 | + |
---|
| 159 | +static void ax8817x_status(struct usbnet *dev, struct urb *urb) |
---|
| 160 | +{ |
---|
| 161 | + struct ax88172_int_data *event; |
---|
| 162 | + int link; |
---|
| 163 | + |
---|
| 164 | + if (urb->actual_length < 8) |
---|
| 165 | + return; |
---|
| 166 | + |
---|
| 167 | + event = urb->transfer_buffer; |
---|
| 168 | + link = event->link & 0x01; |
---|
| 169 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 170 | + if (link) { |
---|
| 171 | + netif_carrier_on(dev->net); |
---|
| 172 | + axusbnet_defer_kevent(dev, EVENT_LINK_RESET); |
---|
| 173 | + } else |
---|
| 174 | + netif_carrier_off(dev->net); |
---|
| 175 | + devwarn(dev, "ax8817x - Link status is: %d", link); |
---|
| 176 | + } |
---|
| 177 | +} |
---|
| 178 | + |
---|
| 179 | +static void ax88772_status(struct usbnet *dev, struct urb *urb) |
---|
| 180 | +{ |
---|
| 181 | + struct ax88172_int_data *event; |
---|
| 182 | + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; |
---|
| 183 | + int link; |
---|
| 184 | + |
---|
| 185 | + if (urb->actual_length < 8) |
---|
| 186 | + return; |
---|
| 187 | + |
---|
| 188 | + event = urb->transfer_buffer; |
---|
| 189 | + link = event->link & 0x01; |
---|
| 190 | + |
---|
| 191 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 192 | + if (link) { |
---|
| 193 | + netif_carrier_on(dev->net); |
---|
| 194 | + ax772_data->Event = AX_SET_RX_CFG; |
---|
| 195 | + } else { |
---|
| 196 | + netif_carrier_off(dev->net); |
---|
| 197 | + if (ax772_data->Event == AX_NOP) { |
---|
| 198 | + ax772_data->Event = PHY_POWER_DOWN; |
---|
| 199 | + ax772_data->TickToExpire = 25; |
---|
| 200 | + } |
---|
| 201 | + } |
---|
| 202 | + |
---|
| 203 | + devwarn(dev, "ax88772 - Link status is: %d", link); |
---|
| 204 | + } |
---|
| 205 | + |
---|
| 206 | + if (ax772_data->Event) |
---|
| 207 | + queue_work(ax772_data->ax_work, &ax772_data->check_link); |
---|
| 208 | +} |
---|
| 209 | + |
---|
| 210 | +static void ax88772a_status(struct usbnet *dev, struct urb *urb) |
---|
| 211 | +{ |
---|
| 212 | + struct ax88172_int_data *event; |
---|
| 213 | + struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv; |
---|
| 214 | + int link; |
---|
| 215 | + int powsave = (ax772a_data->EepromData >> 14); |
---|
| 216 | + |
---|
| 217 | + if (urb->actual_length < 8) |
---|
| 218 | + return; |
---|
| 219 | + |
---|
| 220 | + event = urb->transfer_buffer; |
---|
| 221 | + link = event->link & 0x01; |
---|
| 222 | + |
---|
| 223 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 224 | + |
---|
| 225 | + if (link) { |
---|
| 226 | + netif_carrier_on(dev->net); |
---|
| 227 | + ax772a_data->Event = AX_SET_RX_CFG; |
---|
| 228 | + } else if ((powsave == 0x3) || (powsave == 0x1)) { |
---|
| 229 | + netif_carrier_off(dev->net); |
---|
| 230 | + if (ax772a_data->Event == AX_NOP) { |
---|
| 231 | + ax772a_data->Event = CHK_CABLE_EXIST; |
---|
| 232 | + ax772a_data->TickToExpire = 14; |
---|
| 233 | + } |
---|
| 234 | + } else { |
---|
| 235 | + netif_carrier_off(dev->net); |
---|
| 236 | + ax772a_data->Event = AX_NOP; |
---|
| 237 | + } |
---|
| 238 | + |
---|
| 239 | + devwarn(dev, "ax88772a - Link status is: %d", link); |
---|
| 240 | + } |
---|
| 241 | + |
---|
| 242 | + if (ax772a_data->Event) |
---|
| 243 | + queue_work(ax772a_data->ax_work, &ax772a_data->check_link); |
---|
| 244 | +} |
---|
| 245 | + |
---|
| 246 | +static int ax88772b_stop(struct usbnet *dev) |
---|
| 247 | +{ |
---|
| 248 | + u16 *medium; |
---|
| 249 | + |
---|
| 250 | + medium = kmalloc(2, GFP_ATOMIC); |
---|
| 251 | + if (medium) { |
---|
| 252 | + ax8817x_read_cmd(dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, medium); |
---|
| 253 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 254 | + (*medium & ~AX88772_MEDIUM_RX_ENABLE), |
---|
| 255 | + 0, 0, NULL); |
---|
| 256 | + |
---|
| 257 | + kfree(medium); |
---|
| 258 | + return 0; |
---|
| 259 | + } |
---|
| 260 | + return -EINVAL; |
---|
| 261 | +} |
---|
| 262 | + |
---|
| 263 | +static int ax88772b_reset(struct usbnet *dev) |
---|
| 264 | +{ |
---|
| 265 | + int ret; |
---|
| 266 | + |
---|
| 267 | + /* Set the MAC address */ |
---|
| 268 | + ret = ax8817x_write_cmd(dev, AX88772_CMD_WRITE_NODE_ID, |
---|
| 269 | + 0, 0, ETH_ALEN, dev->net->dev_addr); |
---|
| 270 | + if (ret < 0) |
---|
| 271 | + deverr(dev, "set MAC address failed: %d", ret); |
---|
| 272 | + |
---|
| 273 | + /* stop MAC operation */ |
---|
| 274 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, AX_RX_CTL_STOP, |
---|
| 275 | + 0, 0, NULL); |
---|
| 276 | + if (ret < 0) |
---|
| 277 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 278 | + |
---|
| 279 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 280 | + AX88772_MEDIUM_DEFAULT, 0, 0, |
---|
| 281 | + NULL); |
---|
| 282 | + if (ret < 0) |
---|
| 283 | + deverr(dev, "Write medium mode register: %d", ret); |
---|
| 284 | + |
---|
| 285 | + return ret; |
---|
| 286 | +} |
---|
| 287 | + |
---|
| 288 | +static void ax88772b_status(struct usbnet *dev, struct urb *urb) |
---|
| 289 | +{ |
---|
| 290 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 291 | + struct ax88172_int_data *event; |
---|
| 292 | + int link; |
---|
| 293 | + |
---|
| 294 | + if (urb->actual_length < 8) |
---|
| 295 | + return; |
---|
| 296 | + |
---|
| 297 | + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) |
---|
| 298 | + return; |
---|
| 299 | + |
---|
| 300 | + event = urb->transfer_buffer; |
---|
| 301 | + if (ax772b_data->PhySelect == 0 && |
---|
| 302 | + ax772b_data->OperationMode == OPERATION_MAC_MODE) |
---|
| 303 | + link = (event->link & AX_INT_SPLS_LINK) >> 1; |
---|
| 304 | + else |
---|
| 305 | + link = event->link & AX_INT_PPLS_LINK; |
---|
| 306 | + |
---|
| 307 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 308 | + if (link) { |
---|
| 309 | + netif_carrier_on(dev->net); |
---|
| 310 | + ax772b_data->Event = AX_SET_RX_CFG; |
---|
| 311 | + } else { |
---|
| 312 | + netif_carrier_off(dev->net); |
---|
| 313 | + ax772b_data->time_to_chk = jiffies; |
---|
| 314 | + } |
---|
| 315 | + devwarn(dev, "ax88772b - Link status is: %d", link); |
---|
| 316 | + } |
---|
| 317 | + |
---|
| 318 | + if (!link) { |
---|
| 319 | + |
---|
| 320 | + int no_cable = (event->link & AX_INT_CABOFF_UNPLUG) ? 1 : 0; |
---|
| 321 | + |
---|
| 322 | + if (no_cable) { |
---|
| 323 | + if ((ax772b_data->psc & |
---|
| 324 | + (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) && |
---|
| 325 | + !ax772b_data->pw_enabled) { |
---|
| 326 | + /* |
---|
| 327 | + * AX88772B already entered power saving state |
---|
| 328 | + */ |
---|
| 329 | + ax772b_data->pw_enabled = 1; |
---|
| 330 | + } |
---|
| 331 | + if (ax772b_data->psc & AX_SWRESET_AUTODETACH) |
---|
| 332 | + ax772b_data->Event = AX_CHK_AUTODETACH; |
---|
| 333 | + |
---|
| 334 | + } else { |
---|
| 335 | + /* AX88772B resumed from power saving state */ |
---|
| 336 | + if (ax772b_data->pw_enabled || |
---|
| 337 | + (jiffies > (ax772b_data->time_to_chk + |
---|
| 338 | + AX88772B_WATCHDOG))) { |
---|
| 339 | + if (ax772b_data->pw_enabled) |
---|
| 340 | + ax772b_data->pw_enabled = 0; |
---|
| 341 | + ax772b_data->Event = PHY_POWER_UP; |
---|
| 342 | + ax772b_data->time_to_chk = jiffies; |
---|
| 343 | + } |
---|
| 344 | + } |
---|
| 345 | + } |
---|
| 346 | + |
---|
| 347 | + if (ax772b_data->Event) |
---|
| 348 | + queue_work(ax772b_data->ax_work, &ax772b_data->check_link); |
---|
| 349 | +} |
---|
| 350 | + |
---|
| 351 | +static void ax88772c_status(struct usbnet *dev, struct urb *urb) |
---|
| 352 | +{ |
---|
| 353 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 354 | + struct ax88172_int_data *event; |
---|
| 355 | + int link; |
---|
| 356 | + |
---|
| 357 | + if (urb->actual_length < 8) |
---|
| 358 | + return; |
---|
| 359 | + |
---|
| 360 | + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) |
---|
| 361 | + return; |
---|
| 362 | + |
---|
| 363 | + event = urb->transfer_buffer; |
---|
| 364 | + if (ax772b_data->PhySelect == 0 && |
---|
| 365 | + ax772b_data->OperationMode == OPERATION_MAC_MODE) |
---|
| 366 | + link = (event->link & AX_INT_SPLS_LINK) >> 1; |
---|
| 367 | + else |
---|
| 368 | + link = event->link & AX_INT_PPLS_LINK; |
---|
| 369 | + |
---|
| 370 | + if (netif_carrier_ok(dev->net) != link) { |
---|
| 371 | + if (link) { |
---|
| 372 | + netif_carrier_on(dev->net); |
---|
| 373 | + ax772b_data->Event = AX_SET_RX_CFG; |
---|
| 374 | + } else { |
---|
| 375 | + netif_carrier_off(dev->net); |
---|
| 376 | + ax772b_data->time_to_chk = jiffies; |
---|
| 377 | + } |
---|
| 378 | + devwarn(dev, "ax88772c - Link status is: %d", link); |
---|
| 379 | + } |
---|
| 380 | + |
---|
| 381 | + if (!link) { |
---|
| 382 | + |
---|
| 383 | + int no_cable = (event->link & AX_INT_CABOFF_UNPLUG) ? 1 : 0; |
---|
| 384 | + |
---|
| 385 | + if (no_cable) { |
---|
| 386 | + if ((ax772b_data->psc & |
---|
| 387 | + (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) && |
---|
| 388 | + !ax772b_data->pw_enabled) { |
---|
| 389 | + /* |
---|
| 390 | + * AX88772B already entered power saving state |
---|
| 391 | + */ |
---|
| 392 | + ax772b_data->pw_enabled = 1; |
---|
| 393 | + } |
---|
| 394 | + if (ax772b_data->psc & AX_SWRESET_AUTODETACH) |
---|
| 395 | + ax772b_data->Event = AX_CHK_AUTODETACH; |
---|
| 396 | + } else { |
---|
| 397 | + /* AX88772B resumed from power saving state */ |
---|
| 398 | + if (ax772b_data->pw_enabled || |
---|
| 399 | + (jiffies > (ax772b_data->time_to_chk + |
---|
| 400 | + AX88772B_WATCHDOG))) { |
---|
| 401 | + if (ax772b_data->pw_enabled) |
---|
| 402 | + ax772b_data->pw_enabled = 0; |
---|
| 403 | + ax772b_data->Event = PHY_POWER_UP; |
---|
| 404 | + ax772b_data->time_to_chk = jiffies; |
---|
| 405 | + } |
---|
| 406 | + } |
---|
| 407 | + } |
---|
| 408 | + |
---|
| 409 | + if (ax772b_data->Event) |
---|
| 410 | + queue_work(ax772b_data->ax_work, &ax772b_data->check_link); |
---|
| 411 | +} |
---|
| 412 | + |
---|
| 413 | +void |
---|
| 414 | +ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
---|
| 415 | + u16 size, void *data) |
---|
| 416 | +{ |
---|
| 417 | + struct usb_ctrlrequest *req; |
---|
| 418 | + int status; |
---|
| 419 | + struct urb *urb; |
---|
| 420 | + |
---|
| 421 | + urb = usb_alloc_urb(0, GFP_ATOMIC); |
---|
| 422 | + if (urb == NULL) { |
---|
| 423 | + deverr(dev, "Error allocating URB in write_cmd_async!"); |
---|
| 424 | + return; |
---|
| 425 | + } |
---|
| 426 | + |
---|
| 427 | + req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); |
---|
| 428 | + if (req == NULL) { |
---|
| 429 | + deverr(dev, "Failed to allocate memory for control request"); |
---|
| 430 | + usb_free_urb(urb); |
---|
| 431 | + return; |
---|
| 432 | + } |
---|
| 433 | + |
---|
| 434 | + req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; |
---|
| 435 | + req->bRequest = cmd; |
---|
| 436 | + req->wValue = cpu_to_le16(value); |
---|
| 437 | + req->wIndex = cpu_to_le16(index); |
---|
| 438 | + req->wLength = cpu_to_le16(size); |
---|
| 439 | + |
---|
| 440 | + usb_fill_control_urb(urb, dev->udev, |
---|
| 441 | + usb_sndctrlpipe(dev->udev, 0), |
---|
| 442 | + (void *)req, data, size, |
---|
| 443 | + ax8817x_async_cmd_callback, req); |
---|
| 444 | + |
---|
| 445 | + status = usb_submit_urb(urb, GFP_ATOMIC); |
---|
| 446 | + if (status < 0) { |
---|
| 447 | + deverr(dev, "Error submitting the control message: status=%d", |
---|
| 448 | + status); |
---|
| 449 | + kfree(req); |
---|
| 450 | + usb_free_urb(urb); |
---|
| 451 | + } |
---|
| 452 | +} |
---|
| 453 | + |
---|
| 454 | +static void ax8817x_set_multicast(struct net_device *net) |
---|
| 455 | +{ |
---|
| 456 | + struct usbnet *dev = netdev_priv(net); |
---|
| 457 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 458 | + u8 rx_ctl = AX_RX_CTL_START | AX_RX_CTL_AB; |
---|
| 459 | + int mc_count; |
---|
| 460 | + |
---|
| 461 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 462 | + mc_count = net->mc_count; |
---|
| 463 | +#else |
---|
| 464 | + mc_count = netdev_mc_count(net); |
---|
| 465 | +#endif |
---|
| 466 | + |
---|
| 467 | + if (net->flags & IFF_PROMISC) { |
---|
| 468 | + rx_ctl |= AX_RX_CTL_PRO; |
---|
| 469 | + } else if (net->flags & IFF_ALLMULTI |
---|
| 470 | + || mc_count > AX_MAX_MCAST) { |
---|
| 471 | + rx_ctl |= AX_RX_CTL_AMALL; |
---|
| 472 | + } else if (mc_count == 0) { |
---|
| 473 | + /* just broadcast and directed */ |
---|
| 474 | + } else { |
---|
| 475 | + /* We use the 20 byte dev->data |
---|
| 476 | + * for our 8 byte filter buffer |
---|
| 477 | + * to avoid allocating memory that |
---|
| 478 | + * is tricky to free later */ |
---|
| 479 | + u32 crc_bits; |
---|
| 480 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 481 | + struct dev_mc_list *mc_list = net->mc_list; |
---|
| 482 | + int i; |
---|
| 483 | + |
---|
| 484 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 485 | + |
---|
| 486 | + /* Build the multicast hash filter. */ |
---|
| 487 | + for (i = 0; i < net->mc_count; i++) { |
---|
| 488 | + crc_bits = |
---|
| 489 | + ether_crc(ETH_ALEN, |
---|
| 490 | + mc_list->dmi_addr) >> 26; |
---|
| 491 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 492 | + 1 << (crc_bits & 7); |
---|
| 493 | + mc_list = mc_list->next; |
---|
| 494 | + } |
---|
| 495 | +#else |
---|
| 496 | + struct netdev_hw_addr *ha = NULL; |
---|
| 497 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 498 | + netdev_for_each_mc_addr(ha, net) { |
---|
| 499 | + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; |
---|
| 500 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 501 | + 1 << (crc_bits & 7); |
---|
| 502 | + } |
---|
| 503 | +#endif |
---|
| 504 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, |
---|
| 505 | + AX_MCAST_FILTER_SIZE, data->multi_filter); |
---|
| 506 | + |
---|
| 507 | + rx_ctl |= AX_RX_CTL_AM; |
---|
| 508 | + } |
---|
| 509 | + |
---|
| 510 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); |
---|
| 511 | +} |
---|
| 512 | + |
---|
| 513 | +static void ax88178_set_multicast(struct net_device *net) |
---|
| 514 | +{ |
---|
| 515 | + struct usbnet *dev = netdev_priv(net); |
---|
| 516 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 517 | + u16 rx_ctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_CTL_MFB); |
---|
| 518 | + int mc_count; |
---|
| 519 | + |
---|
| 520 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 521 | + mc_count = net->mc_count; |
---|
| 522 | +#else |
---|
| 523 | + mc_count = netdev_mc_count(net); |
---|
| 524 | +#endif |
---|
| 525 | + |
---|
| 526 | + if (net->flags & IFF_PROMISC) { |
---|
| 527 | + rx_ctl |= AX_RX_CTL_PRO; |
---|
| 528 | + } else if (net->flags & IFF_ALLMULTI |
---|
| 529 | + || mc_count > AX_MAX_MCAST) { |
---|
| 530 | + rx_ctl |= AX_RX_CTL_AMALL; |
---|
| 531 | + } else if (mc_count == 0) { |
---|
| 532 | + /* just broadcast and directed */ |
---|
| 533 | + } else { |
---|
| 534 | + /* We use the 20 byte dev->data |
---|
| 535 | + * for our 8 byte filter buffer |
---|
| 536 | + * to avoid allocating memory that |
---|
| 537 | + * is tricky to free later */ |
---|
| 538 | + u32 crc_bits; |
---|
| 539 | + |
---|
| 540 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 541 | + struct dev_mc_list *mc_list = net->mc_list; |
---|
| 542 | + int i; |
---|
| 543 | + |
---|
| 544 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 545 | + |
---|
| 546 | + /* Build the multicast hash filter. */ |
---|
| 547 | + for (i = 0; i < net->mc_count; i++) { |
---|
| 548 | + crc_bits = |
---|
| 549 | + ether_crc(ETH_ALEN, |
---|
| 550 | + mc_list->dmi_addr) >> 26; |
---|
| 551 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 552 | + 1 << (crc_bits & 7); |
---|
| 553 | + mc_list = mc_list->next; |
---|
| 554 | + } |
---|
| 555 | +#else |
---|
| 556 | + struct netdev_hw_addr *ha = NULL; |
---|
| 557 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 558 | + netdev_for_each_mc_addr(ha, net) { |
---|
| 559 | + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; |
---|
| 560 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 561 | + 1 << (crc_bits & 7); |
---|
| 562 | + } |
---|
| 563 | +#endif |
---|
| 564 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, |
---|
| 565 | + AX_MCAST_FILTER_SIZE, data->multi_filter); |
---|
| 566 | + |
---|
| 567 | + rx_ctl |= AX_RX_CTL_AM; |
---|
| 568 | + } |
---|
| 569 | + |
---|
| 570 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); |
---|
| 571 | +} |
---|
| 572 | + |
---|
| 573 | +static void ax88772b_set_multicast(struct net_device *net) |
---|
| 574 | +{ |
---|
| 575 | + struct usbnet *dev = netdev_priv(net); |
---|
| 576 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 577 | + u16 rx_ctl = (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_HEADER_DEFAULT); |
---|
| 578 | + int mc_count; |
---|
| 579 | + |
---|
| 580 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 581 | + mc_count = net->mc_count; |
---|
| 582 | +#else |
---|
| 583 | + mc_count = netdev_mc_count(net); |
---|
| 584 | +#endif |
---|
| 585 | + |
---|
| 586 | + if (net->flags & IFF_PROMISC) { |
---|
| 587 | + rx_ctl |= AX_RX_CTL_PRO; |
---|
| 588 | + } else if (net->flags & IFF_ALLMULTI |
---|
| 589 | + || mc_count > AX_MAX_MCAST) { |
---|
| 590 | + rx_ctl |= AX_RX_CTL_AMALL; |
---|
| 591 | + } else if (mc_count == 0) { |
---|
| 592 | + /* just broadcast and directed */ |
---|
| 593 | + } else { |
---|
| 594 | + /* We use the 20 byte dev->data |
---|
| 595 | + * for our 8 byte filter buffer |
---|
| 596 | + * to avoid allocating memory that |
---|
| 597 | + * is tricky to free later */ |
---|
| 598 | + u32 crc_bits; |
---|
| 599 | + |
---|
| 600 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
---|
| 601 | + struct dev_mc_list *mc_list = net->mc_list; |
---|
| 602 | + int i; |
---|
| 603 | + |
---|
| 604 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 605 | + |
---|
| 606 | + /* Build the multicast hash filter. */ |
---|
| 607 | + for (i = 0; i < net->mc_count; i++) { |
---|
| 608 | + crc_bits = |
---|
| 609 | + ether_crc(ETH_ALEN, |
---|
| 610 | + mc_list->dmi_addr) >> 26; |
---|
| 611 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 612 | + 1 << (crc_bits & 7); |
---|
| 613 | + mc_list = mc_list->next; |
---|
| 614 | + } |
---|
| 615 | +#else |
---|
| 616 | + struct netdev_hw_addr *ha = NULL; |
---|
| 617 | + memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); |
---|
| 618 | + netdev_for_each_mc_addr(ha, net) { |
---|
| 619 | + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; |
---|
| 620 | + data->multi_filter[crc_bits >> 3] |= |
---|
| 621 | + 1 << (crc_bits & 7); |
---|
| 622 | + } |
---|
| 623 | +#endif |
---|
| 624 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, |
---|
| 625 | + AX_MCAST_FILTER_SIZE, data->multi_filter); |
---|
| 626 | + |
---|
| 627 | + rx_ctl |= AX_RX_CTL_AM; |
---|
| 628 | + } |
---|
| 629 | + |
---|
| 630 | + ax8817x_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); |
---|
| 631 | +} |
---|
| 632 | + |
---|
| 633 | +static int ax8817x_mdio_read(struct net_device *netdev, int phy_id, int loc) |
---|
| 634 | +{ |
---|
| 635 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 636 | + u16 *res, ret; |
---|
| 637 | + u8* smsr; |
---|
| 638 | + int i = 0; |
---|
| 639 | + |
---|
| 640 | + res = kmalloc(2, GFP_ATOMIC); |
---|
| 641 | + if (!res) |
---|
| 642 | + return 0; |
---|
| 643 | + |
---|
| 644 | + do { |
---|
| 645 | + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 646 | + |
---|
| 647 | + msleep(1); |
---|
| 648 | + |
---|
| 649 | + smsr = (u8*) res; |
---|
| 650 | + ax8817x_read_cmd(dev, AX_CMD_READ_STATMNGSTS_REG, 0, 0, 1, smsr); |
---|
| 651 | + } while (!(*smsr & AX_HOST_EN) && (i++ < 30)); |
---|
| 652 | + |
---|
| 653 | + ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, res); |
---|
| 654 | + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); |
---|
| 655 | + |
---|
| 656 | + ret = *res & 0xffff; |
---|
| 657 | + kfree(res); |
---|
| 658 | + |
---|
| 659 | + return ret; |
---|
| 660 | +} |
---|
| 661 | + |
---|
| 662 | +static int |
---|
| 663 | +ax8817x_swmii_mdio_read(struct net_device *netdev, int phy_id, int loc) |
---|
| 664 | +{ |
---|
| 665 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 666 | + u16 *res; |
---|
| 667 | + u16 ret; |
---|
| 668 | + |
---|
| 669 | + res = kmalloc(2, GFP_ATOMIC); |
---|
| 670 | + if (!res) |
---|
| 671 | + return 0; |
---|
| 672 | + |
---|
| 673 | + ax8817x_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, |
---|
| 674 | + (__u16)loc, 2, res); |
---|
| 675 | + |
---|
| 676 | + ret = *res & 0xffff; |
---|
| 677 | + kfree(res); |
---|
| 678 | + |
---|
| 679 | + return ret; |
---|
| 680 | +} |
---|
| 681 | + |
---|
| 682 | +/* same as above, but converts resulting value to cpu byte order */ |
---|
| 683 | +static int ax8817x_mdio_read_le(struct net_device *netdev, int phy_id, int loc) |
---|
| 684 | +{ |
---|
| 685 | + return le16_to_cpu(ax8817x_mdio_read(netdev, phy_id, loc)); |
---|
| 686 | +} |
---|
| 687 | + |
---|
| 688 | +static int |
---|
| 689 | +ax8817x_swmii_mdio_read_le(struct net_device *netdev, int phy_id, int loc) |
---|
| 690 | +{ |
---|
| 691 | + return le16_to_cpu(ax8817x_swmii_mdio_read(netdev, phy_id, loc)); |
---|
| 692 | +} |
---|
| 693 | + |
---|
| 694 | +static void |
---|
| 695 | +ax8817x_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) |
---|
| 696 | +{ |
---|
| 697 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 698 | + u16 *res; |
---|
| 699 | + u8* smsr; |
---|
| 700 | + int i = 0; |
---|
| 701 | + |
---|
| 702 | + res = kmalloc(2, GFP_ATOMIC); |
---|
| 703 | + if (!res) |
---|
| 704 | + return; |
---|
| 705 | + smsr = (u8 *) res; |
---|
| 706 | + |
---|
| 707 | + do { |
---|
| 708 | + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 709 | + |
---|
| 710 | + msleep(1); |
---|
| 711 | + |
---|
| 712 | + ax8817x_read_cmd(dev, AX_CMD_READ_STATMNGSTS_REG, 0, 0, 1, smsr); |
---|
| 713 | + } while (!(*smsr & AX_HOST_EN) && (i++ < 30)); |
---|
| 714 | + |
---|
| 715 | + *res = val; |
---|
| 716 | + |
---|
| 717 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, |
---|
| 718 | + (__u16)loc, 2, res); |
---|
| 719 | + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); |
---|
| 720 | + |
---|
| 721 | + kfree(res); |
---|
| 722 | +} |
---|
| 723 | + |
---|
| 724 | +static void ax8817x_swmii_mdio_write(struct net_device *netdev, int phy_id, |
---|
| 725 | + int loc, int val) |
---|
| 726 | +{ |
---|
| 727 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 728 | + u16 *res; |
---|
| 729 | + |
---|
| 730 | + res = kmalloc(2, GFP_ATOMIC); |
---|
| 731 | + if (!res) |
---|
| 732 | + return; |
---|
| 733 | + *res = val; |
---|
| 734 | + |
---|
| 735 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, |
---|
| 736 | + (__u16)loc, 2, res); |
---|
| 737 | + |
---|
| 738 | + kfree(res); |
---|
| 739 | +} |
---|
| 740 | + |
---|
| 741 | +static void |
---|
| 742 | +ax88772b_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) |
---|
| 743 | +{ |
---|
| 744 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 745 | + u16 *res; |
---|
| 746 | + |
---|
| 747 | + res = kmalloc(2, GFP_ATOMIC); |
---|
| 748 | + if (!res) |
---|
| 749 | + return; |
---|
| 750 | + *res = val; |
---|
| 751 | + |
---|
| 752 | + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 753 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, |
---|
| 754 | + (__u16)loc, 2, res); |
---|
| 755 | + |
---|
| 756 | + if (loc == MII_ADVERTISE) { |
---|
| 757 | + *res = cpu_to_le16(BMCR_ANENABLE | BMCR_ANRESTART); |
---|
| 758 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, |
---|
| 759 | + (__u16)MII_BMCR, 2, res); |
---|
| 760 | + } |
---|
| 761 | + |
---|
| 762 | + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); |
---|
| 763 | + |
---|
| 764 | + kfree(res); |
---|
| 765 | +} |
---|
| 766 | + |
---|
| 767 | +/* same as above, but converts new value to le16 byte order before writing */ |
---|
| 768 | +static void |
---|
| 769 | +ax8817x_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val) |
---|
| 770 | +{ |
---|
| 771 | + ax8817x_mdio_write(netdev, phy_id, loc, cpu_to_le16(val)); |
---|
| 772 | +} |
---|
| 773 | + |
---|
| 774 | +static void ax8817x_swmii_mdio_write_le(struct net_device *netdev, |
---|
| 775 | + int phy_id, int loc, int val) |
---|
| 776 | +{ |
---|
| 777 | + ax8817x_swmii_mdio_write(netdev, phy_id, loc, cpu_to_le16(val)); |
---|
| 778 | +} |
---|
| 779 | + |
---|
| 780 | +static void |
---|
| 781 | +ax88772b_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val) |
---|
| 782 | +{ |
---|
| 783 | + ax88772b_mdio_write(netdev, phy_id, loc, cpu_to_le16(val)); |
---|
| 784 | +} |
---|
| 785 | + |
---|
| 786 | +static int ax88772_suspend(struct usb_interface *intf, |
---|
| 787 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) |
---|
| 788 | + pm_message_t message) |
---|
| 789 | +#else |
---|
| 790 | + u32 message) |
---|
| 791 | +#endif |
---|
| 792 | +{ |
---|
| 793 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 794 | + u16 *medium; |
---|
| 795 | + |
---|
| 796 | + medium = kmalloc(2, GFP_ATOMIC); |
---|
| 797 | + if (!medium) |
---|
| 798 | + return axusbnet_suspend(intf, message); |
---|
| 799 | + |
---|
| 800 | + ax8817x_read_cmd(dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, medium); |
---|
| 801 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 802 | + (*medium & ~AX88772_MEDIUM_RX_ENABLE), 0, 0, NULL); |
---|
| 803 | + |
---|
| 804 | + kfree(medium); |
---|
| 805 | + return axusbnet_suspend(intf, message); |
---|
| 806 | +} |
---|
| 807 | + |
---|
| 808 | +static int ax88772b_suspend(struct usb_interface *intf, |
---|
| 809 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) |
---|
| 810 | + pm_message_t message) |
---|
| 811 | +#else |
---|
| 812 | + u32 message) |
---|
| 813 | +#endif |
---|
| 814 | +{ |
---|
| 815 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 816 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 817 | + u16 *tmp16; |
---|
| 818 | + u8 *opt; |
---|
| 819 | + |
---|
| 820 | + tmp16 = kmalloc(2, GFP_ATOMIC); |
---|
| 821 | + if (!tmp16) |
---|
| 822 | + return axusbnet_suspend(intf, message); |
---|
| 823 | + opt = (u8 *)tmp16; |
---|
| 824 | +#if 0 |
---|
| 825 | + /* Read Wake-up Frame Array Register (Mask Wakeup Timer) */ |
---|
| 826 | + ax8817x_read_cmd(dev, AX_CMD_READ_WKFARY, 0x11, 0, 4, &tmp32); |
---|
| 827 | + tmp32 &= 0xFFF0FFFF; |
---|
| 828 | + /* 8 second */ |
---|
| 829 | + tmp32 |= 0x00020000; |
---|
| 830 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_WKFARY, 0x11, 0, 4, &tmp32); |
---|
| 831 | +#endif |
---|
| 832 | + /* Preserve BMCR for restoring */ |
---|
| 833 | + ax772b_data->presvd_phy_bmcr = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_BMCR); |
---|
| 834 | + |
---|
| 835 | + /* Preserve Advertisement control reg for restoring */ |
---|
| 836 | + ax772b_data->presvd_phy_advertise = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 837 | + |
---|
| 838 | + ax8817x_read_cmd(dev, AX_CMD_READ_MEDIUM_MODE, 0, 0, 2, tmp16); |
---|
| 839 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 840 | + (*tmp16 & ~AX88772_MEDIUM_RX_ENABLE), |
---|
| 841 | + 0, 0, NULL); |
---|
| 842 | + |
---|
| 843 | + ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, opt); |
---|
| 844 | + if (!(*opt & AX_MONITOR_LINK) && !(*opt & AX_MONITOR_MAGIC)) { |
---|
| 845 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 846 | + AX_SWRESET_IPRL | AX_SWRESET_IPPD, |
---|
| 847 | + 0, 0, NULL); |
---|
| 848 | + |
---|
| 849 | + } else { |
---|
| 850 | + |
---|
| 851 | + if (ax772b_data->psc & AX_SWRESET_WOLLP) { |
---|
| 852 | + *tmp16 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 853 | + MII_BMCR); |
---|
| 854 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 855 | + MII_BMCR, *tmp16 | BMCR_ANENABLE); |
---|
| 856 | + |
---|
| 857 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 858 | + AX_SWRESET_IPRL | ax772b_data->psc, |
---|
| 859 | + 0, 0, NULL); |
---|
| 860 | + } |
---|
| 861 | + |
---|
| 862 | + if (ax772b_data->psc & |
---|
| 863 | + (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) { |
---|
| 864 | + *opt |= AX_MONITOR_LINK; |
---|
| 865 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, *opt, |
---|
| 866 | + 0, 0, NULL); |
---|
| 867 | + } |
---|
| 868 | + } |
---|
| 869 | + |
---|
| 870 | + dev->reg_monitor = *opt; |
---|
| 871 | + |
---|
| 872 | + kfree(tmp16); |
---|
| 873 | + return axusbnet_suspend(intf, message); |
---|
| 874 | +} |
---|
| 875 | + |
---|
| 876 | +static int ax88772_resume(struct usb_interface *intf) |
---|
| 877 | +{ |
---|
| 878 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 879 | + |
---|
| 880 | + netif_carrier_off(dev->net); |
---|
| 881 | + |
---|
| 882 | + return axusbnet_resume(intf); |
---|
| 883 | +} |
---|
| 884 | + |
---|
| 885 | +static int ax88772b_resume(struct usb_interface *intf) |
---|
| 886 | +{ |
---|
| 887 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 888 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 889 | + |
---|
| 890 | + if (ax772b_data->psc & AX_SWRESET_WOLLP) { |
---|
| 891 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 892 | + AX_SWRESET_IPRL | (ax772b_data->psc & 0x7FFF), |
---|
| 893 | + 0, 0, NULL); |
---|
| 894 | + } |
---|
| 895 | + |
---|
| 896 | + if (ax772b_data->psc & (AX_SWRESET_IPPSL_0 | AX_SWRESET_IPPSL_1)) |
---|
| 897 | + ax88772a_phy_powerup(dev); |
---|
| 898 | + |
---|
| 899 | + netif_carrier_off(dev->net); |
---|
| 900 | + |
---|
| 901 | + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) |
---|
| 902 | + netif_carrier_on(dev->net); |
---|
| 903 | + |
---|
| 904 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, dev->reg_monitor, |
---|
| 905 | + 0, 0, NULL); |
---|
| 906 | + |
---|
| 907 | + return axusbnet_resume(intf); |
---|
| 908 | +} |
---|
| 909 | + |
---|
| 910 | +static int ax88172_link_reset(struct usbnet *dev) |
---|
| 911 | +{ |
---|
| 912 | + u16 lpa; |
---|
| 913 | + u16 adv; |
---|
| 914 | + u16 res; |
---|
| 915 | + u8 mode; |
---|
| 916 | + |
---|
| 917 | + mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN; |
---|
| 918 | + lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); |
---|
| 919 | + adv = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 920 | + res = mii_nway_result(lpa|adv); |
---|
| 921 | + if (res & LPA_DUPLEX) |
---|
| 922 | + mode |= AX_MEDIUM_FULL_DUPLEX; |
---|
| 923 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); |
---|
| 924 | + |
---|
| 925 | + return 0; |
---|
| 926 | +} |
---|
| 927 | + |
---|
| 928 | +static void |
---|
| 929 | +ax8817x_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) |
---|
| 930 | +{ |
---|
| 931 | + struct usbnet *dev = netdev_priv(net); |
---|
| 932 | + u8 *opt; |
---|
| 933 | + |
---|
| 934 | + wolinfo->supported = 0; |
---|
| 935 | + wolinfo->wolopts = 0; |
---|
| 936 | + |
---|
| 937 | + opt = kmalloc(1, GFP_KERNEL); |
---|
| 938 | + if (!opt) |
---|
| 939 | + return; |
---|
| 940 | + |
---|
| 941 | + if (ax8817x_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, opt) < 0) { |
---|
| 942 | + kfree(opt); |
---|
| 943 | + return; |
---|
| 944 | + } |
---|
| 945 | + |
---|
| 946 | + wolinfo->supported = WAKE_PHY | WAKE_MAGIC; |
---|
| 947 | + |
---|
| 948 | + if (*opt & AX_MONITOR_LINK) |
---|
| 949 | + wolinfo->wolopts |= WAKE_PHY; |
---|
| 950 | + if (*opt & AX_MONITOR_MAGIC) |
---|
| 951 | + wolinfo->wolopts |= WAKE_MAGIC; |
---|
| 952 | + |
---|
| 953 | + kfree(opt); |
---|
| 954 | +} |
---|
| 955 | + |
---|
| 956 | +static int |
---|
| 957 | +ax8817x_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) |
---|
| 958 | +{ |
---|
| 959 | + struct usbnet *dev = netdev_priv(net); |
---|
| 960 | + u8 opt; |
---|
| 961 | + |
---|
| 962 | + opt = 0; |
---|
| 963 | + if (wolinfo->wolopts & WAKE_PHY) |
---|
| 964 | + opt |= AX_MONITOR_LINK; |
---|
| 965 | + if (wolinfo->wolopts & WAKE_MAGIC) |
---|
| 966 | + opt |= AX_MONITOR_MAGIC; |
---|
| 967 | + |
---|
| 968 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, opt, 0, 0, NULL); |
---|
| 969 | + |
---|
| 970 | + return 0; |
---|
| 971 | +} |
---|
| 972 | + |
---|
| 973 | +static int ax8817x_get_eeprom_len(struct net_device *net) |
---|
| 974 | +{ |
---|
| 975 | + return AX_EEPROM_LEN; |
---|
| 976 | +} |
---|
| 977 | + |
---|
| 978 | +static int ax8817x_get_eeprom(struct net_device *net, |
---|
| 979 | + struct ethtool_eeprom *eeprom, u8 *data) |
---|
| 980 | +{ |
---|
| 981 | + struct usbnet *dev = netdev_priv(net); |
---|
| 982 | + u16 *ebuf = (u16 *)data; |
---|
| 983 | + int i; |
---|
| 984 | + |
---|
| 985 | + /* Crude hack to ensure that we don't overwrite memory |
---|
| 986 | + * if an odd length is supplied |
---|
| 987 | + */ |
---|
| 988 | + if (eeprom->len % 2) |
---|
| 989 | + return -EINVAL; |
---|
| 990 | + |
---|
| 991 | + eeprom->magic = AX_EEPROM_MAGIC; |
---|
| 992 | + |
---|
| 993 | + /* ax8817x returns 2 bytes from eeprom on read */ |
---|
| 994 | + for (i = 0; i < eeprom->len / 2; i++) { |
---|
| 995 | + if (ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, |
---|
| 996 | + eeprom->offset + i, 0, 2, |
---|
| 997 | + &ebuf[i]) < 0) |
---|
| 998 | + return -EINVAL; |
---|
| 999 | + } |
---|
| 1000 | + return 0; |
---|
| 1001 | +} |
---|
| 1002 | + |
---|
| 1003 | +static void ax8817x_get_drvinfo(struct net_device *net, |
---|
| 1004 | + struct ethtool_drvinfo *info) |
---|
| 1005 | +{ |
---|
| 1006 | + /* Inherit standard device info */ |
---|
| 1007 | + axusbnet_get_drvinfo(net, info); |
---|
| 1008 | + info->eedump_len = 0x3e; |
---|
| 1009 | +} |
---|
| 1010 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) |
---|
| 1011 | +static int ax8817x_get_settings(struct net_device *net, struct ethtool_cmd *cmd) |
---|
| 1012 | +{ |
---|
| 1013 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1014 | + return mii_ethtool_gset(&dev->mii, cmd); |
---|
| 1015 | +} |
---|
| 1016 | + |
---|
| 1017 | +static int ax8817x_set_settings(struct net_device *net, struct ethtool_cmd *cmd) |
---|
| 1018 | +{ |
---|
| 1019 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1020 | + return mii_ethtool_sset(&dev->mii, cmd); |
---|
| 1021 | +} |
---|
| 1022 | +#else |
---|
| 1023 | +static int ax8817x_get_link_ksettings(struct net_device *net, |
---|
| 1024 | + struct ethtool_link_ksettings *cmd) |
---|
| 1025 | +{ |
---|
| 1026 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1027 | + |
---|
| 1028 | + if (!dev->mii.mdio_read) |
---|
| 1029 | + return -EOPNOTSUPP; |
---|
| 1030 | + |
---|
| 1031 | + mii_ethtool_get_link_ksettings(&dev->mii, cmd); |
---|
| 1032 | + |
---|
| 1033 | + return 0; |
---|
| 1034 | +} |
---|
| 1035 | + |
---|
| 1036 | +static int ax8817x_set_link_ksettings(struct net_device *net, |
---|
| 1037 | + const struct ethtool_link_ksettings *cmd) |
---|
| 1038 | +{ |
---|
| 1039 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1040 | + |
---|
| 1041 | + if (!dev->mii.mdio_write) |
---|
| 1042 | + return -EOPNOTSUPP; |
---|
| 1043 | + |
---|
| 1044 | + return mii_ethtool_set_link_ksettings(&dev->mii, cmd); |
---|
| 1045 | +} |
---|
| 1046 | +#endif |
---|
| 1047 | +/* We need to override some ethtool_ops so we require our |
---|
| 1048 | + own structure so we don't interfere with other usbnet |
---|
| 1049 | + devices that may be connected at the same time. */ |
---|
| 1050 | +static struct ethtool_ops ax8817x_ethtool_ops = { |
---|
| 1051 | + .get_drvinfo = ax8817x_get_drvinfo, |
---|
| 1052 | + .get_link = ethtool_op_get_link, |
---|
| 1053 | + .get_msglevel = axusbnet_get_msglevel, |
---|
| 1054 | + .set_msglevel = axusbnet_set_msglevel, |
---|
| 1055 | + .get_wol = ax8817x_get_wol, |
---|
| 1056 | + .set_wol = ax8817x_set_wol, |
---|
| 1057 | + .get_eeprom_len = ax8817x_get_eeprom_len, |
---|
| 1058 | + .get_eeprom = ax8817x_get_eeprom, |
---|
| 1059 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) |
---|
| 1060 | + .get_settings = ax8817x_get_settings, |
---|
| 1061 | + .set_settings = ax8817x_set_settings, |
---|
| 1062 | +#else |
---|
| 1063 | + .get_link_ksettings = ax8817x_get_link_ksettings, |
---|
| 1064 | + .set_link_ksettings = ax8817x_set_link_ksettings, |
---|
| 1065 | +#endif |
---|
| 1066 | +}; |
---|
| 1067 | + |
---|
| 1068 | +static int ax8817x_ioctl(struct net_device *net, struct ifreq *rq, int cmd) |
---|
| 1069 | +{ |
---|
| 1070 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1071 | + |
---|
| 1072 | + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); |
---|
| 1073 | +} |
---|
| 1074 | + |
---|
| 1075 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29) |
---|
| 1076 | +static const struct net_device_ops ax88x72_netdev_ops = { |
---|
| 1077 | + .ndo_open = axusbnet_open, |
---|
| 1078 | + .ndo_stop = axusbnet_stop, |
---|
| 1079 | + .ndo_start_xmit = axusbnet_start_xmit, |
---|
| 1080 | + .ndo_tx_timeout = axusbnet_tx_timeout, |
---|
| 1081 | + .ndo_change_mtu = axusbnet_change_mtu, |
---|
| 1082 | + .ndo_get_stats = axusbnet_get_stats, |
---|
| 1083 | + .ndo_do_ioctl = ax8817x_ioctl, |
---|
| 1084 | + .ndo_set_mac_address = ax8817x_set_mac_addr, |
---|
| 1085 | + .ndo_validate_addr = eth_validate_addr, |
---|
| 1086 | +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 0) |
---|
| 1087 | + .ndo_set_multicast_list = ax8817x_set_multicast, |
---|
| 1088 | +#else |
---|
| 1089 | + .ndo_set_rx_mode = ax8817x_set_multicast, |
---|
| 1090 | +#endif |
---|
| 1091 | +}; |
---|
| 1092 | +#endif |
---|
| 1093 | + |
---|
| 1094 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29) |
---|
| 1095 | +static const struct net_device_ops ax88178_netdev_ops = { |
---|
| 1096 | + .ndo_open = axusbnet_open, |
---|
| 1097 | + .ndo_stop = axusbnet_stop, |
---|
| 1098 | + .ndo_start_xmit = axusbnet_start_xmit, |
---|
| 1099 | + .ndo_tx_timeout = axusbnet_tx_timeout, |
---|
| 1100 | + .ndo_change_mtu = axusbnet_change_mtu, |
---|
| 1101 | + .ndo_get_stats = axusbnet_get_stats, |
---|
| 1102 | + .ndo_do_ioctl = ax8817x_ioctl, |
---|
| 1103 | + .ndo_set_mac_address = ax8817x_set_mac_addr, |
---|
| 1104 | + .ndo_validate_addr = eth_validate_addr, |
---|
| 1105 | +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 0) |
---|
| 1106 | + .ndo_set_multicast_list = ax88178_set_multicast, |
---|
| 1107 | +#else |
---|
| 1108 | + .ndo_set_rx_mode = ax88178_set_multicast, |
---|
| 1109 | +#endif |
---|
| 1110 | +}; |
---|
| 1111 | +#endif |
---|
| 1112 | + |
---|
| 1113 | +static int access_eeprom_mac(struct usbnet *dev, u8 *buf, u8 offset, bool wflag) |
---|
| 1114 | +{ |
---|
| 1115 | + int ret = 0, i; |
---|
| 1116 | + u16* tmp = (u16*)buf; |
---|
| 1117 | + |
---|
| 1118 | + if (wflag) { |
---|
| 1119 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM_EN, |
---|
| 1120 | + 0, 0, 0, NULL); |
---|
| 1121 | + if (ret < 0) |
---|
| 1122 | + return ret; |
---|
| 1123 | + |
---|
| 1124 | + mdelay(15); |
---|
| 1125 | + } |
---|
| 1126 | + |
---|
| 1127 | + for (i = 0; i < (ETH_ALEN >> 1); i++) { |
---|
| 1128 | + if (wflag) { |
---|
| 1129 | + u16 wd = cpu_to_le16(*(tmp + i)); |
---|
| 1130 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM, offset + i, |
---|
| 1131 | + wd, 0, NULL); |
---|
| 1132 | + if (ret < 0) |
---|
| 1133 | + break; |
---|
| 1134 | + |
---|
| 1135 | + mdelay(15); |
---|
| 1136 | + } |
---|
| 1137 | + else { |
---|
| 1138 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, |
---|
| 1139 | + offset + i, 0, 2, tmp + i); |
---|
| 1140 | + if (ret < 0) |
---|
| 1141 | + break; |
---|
| 1142 | + } |
---|
| 1143 | + } |
---|
| 1144 | + |
---|
| 1145 | + if (!wflag) { |
---|
| 1146 | + if (ret < 0) { |
---|
| 1147 | + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) |
---|
| 1148 | + netdev_dbg(dev->net, "Failed to read MAC address from EEPROM: %d\n", ret); |
---|
| 1149 | + #else |
---|
| 1150 | + devdbg(dev, "Failed to read MAC address from EEPROM: %d\n", ret); |
---|
| 1151 | + #endif |
---|
| 1152 | + return ret; |
---|
| 1153 | + } |
---|
| 1154 | + memcpy(dev->net->dev_addr, buf, ETH_ALEN); |
---|
| 1155 | + } |
---|
| 1156 | + else { |
---|
| 1157 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_EEPROM_DIS, |
---|
| 1158 | + 0, 0, 0, NULL); |
---|
| 1159 | + if (ret < 0) |
---|
| 1160 | + return ret; |
---|
| 1161 | + |
---|
| 1162 | + /* reload eeprom data */ |
---|
| 1163 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 1164 | + AXGPIOS_RSE, 0, 0, NULL); |
---|
| 1165 | + if (ret < 0) |
---|
| 1166 | + return ret; |
---|
| 1167 | + } |
---|
| 1168 | + |
---|
| 1169 | + return 0; |
---|
| 1170 | +} |
---|
| 1171 | + |
---|
| 1172 | +static int ax8817x_check_ether_addr(struct usbnet *dev) |
---|
| 1173 | +{ |
---|
| 1174 | + unsigned char *tmp = (unsigned char*)dev->net->dev_addr; |
---|
| 1175 | + u8 default_mac[6] = {0, 0x0e, 0xc6, 0x87, 0x72, 0x01}; |
---|
| 1176 | + |
---|
| 1177 | + if (((*((u8*)tmp) == 0) && (*((u8*)tmp + 1) == 0) && (*((u8*)tmp + 2) == 0)) || |
---|
| 1178 | + !is_valid_ether_addr((u8*)tmp) || |
---|
| 1179 | + !memcmp(dev->net->dev_addr, default_mac, ETH_ALEN)) { |
---|
| 1180 | + printk("Found invalid EEPROM MAC address value "); |
---|
| 1181 | + printk("%02X-%02X-%02X-%02X-%02X-%02X\n", *((u8*)tmp + 0), |
---|
| 1182 | + *((u8*)tmp + 1), |
---|
| 1183 | + *((u8*)tmp + 2), |
---|
| 1184 | + *((u8*)tmp + 3), |
---|
| 1185 | + *((u8*)tmp + 4), |
---|
| 1186 | + *((u8*)tmp + 5)); |
---|
| 1187 | + |
---|
| 1188 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0) |
---|
| 1189 | + eth_hw_addr_random(dev->net); |
---|
| 1190 | +#else |
---|
| 1191 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) |
---|
| 1192 | + dev->net->addr_assign_type |= NET_ADDR_RANDOM; |
---|
| 1193 | +#endif |
---|
| 1194 | + random_ether_addr(dev->net->dev_addr); |
---|
| 1195 | +#endif |
---|
| 1196 | + *tmp = 0; |
---|
| 1197 | + *(tmp + 1) = 0x0E; |
---|
| 1198 | + *(tmp + 2) = 0xC6; |
---|
| 1199 | + *(tmp + 3) = 0x8F; |
---|
| 1200 | + |
---|
| 1201 | + return -EADDRNOTAVAIL; |
---|
| 1202 | + } |
---|
| 1203 | + return 0; |
---|
| 1204 | +} |
---|
| 1205 | + |
---|
| 1206 | +static int ax8817x_get_mac(struct usbnet *dev, u8* buf) |
---|
| 1207 | +{ |
---|
| 1208 | + int ret, i; |
---|
| 1209 | + |
---|
| 1210 | + |
---|
| 1211 | + ret = access_eeprom_mac(dev, buf, 0x04, 0); |
---|
| 1212 | + if (ret < 0) |
---|
| 1213 | + goto out; |
---|
| 1214 | + |
---|
| 1215 | + if (ax8817x_check_ether_addr(dev)) { |
---|
| 1216 | + ret = access_eeprom_mac(dev, dev->net->dev_addr, 0x04, 1); |
---|
| 1217 | + if (ret < 0) { |
---|
| 1218 | + deverr(dev, "Failed to write MAC to EEPROM: %d", ret); |
---|
| 1219 | + goto out; |
---|
| 1220 | + } |
---|
| 1221 | + |
---|
| 1222 | + msleep(5); |
---|
| 1223 | + |
---|
| 1224 | + ret = ax8817x_read_cmd(dev, AX88772_CMD_READ_NODE_ID, |
---|
| 1225 | + 0, 0, ETH_ALEN, buf); |
---|
| 1226 | + if (ret < 0) { |
---|
| 1227 | + deverr(dev, "Failed to read MAC address: %d", ret); |
---|
| 1228 | + goto out; |
---|
| 1229 | + } |
---|
| 1230 | + |
---|
| 1231 | + for (i = 0; i < ETH_ALEN; i++) |
---|
| 1232 | + if (*(dev->net->dev_addr + i) != *((u8*)buf + i)) { |
---|
| 1233 | + devwarn(dev, "Found invalid EEPROM part or non-EEPROM"); |
---|
| 1234 | + break; |
---|
| 1235 | + } |
---|
| 1236 | + } |
---|
| 1237 | + |
---|
| 1238 | + memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN); |
---|
| 1239 | + |
---|
| 1240 | + /* Set the MAC address */ |
---|
| 1241 | + ax8817x_write_cmd (dev, AX88772_CMD_WRITE_NODE_ID, 0, 0, |
---|
| 1242 | + ETH_ALEN, dev->net->dev_addr); |
---|
| 1243 | + |
---|
| 1244 | + if (ret < 0) { |
---|
| 1245 | + deverr(dev, "Failed to write MAC address: %d", ret); |
---|
| 1246 | + goto out; |
---|
| 1247 | + } |
---|
| 1248 | + |
---|
| 1249 | + return 0; |
---|
| 1250 | +out: |
---|
| 1251 | + return ret; |
---|
| 1252 | +} |
---|
| 1253 | + |
---|
| 1254 | +static int ax8817x_bind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 1255 | +{ |
---|
| 1256 | + int ret = 0; |
---|
| 1257 | + void *buf; |
---|
| 1258 | + int i; |
---|
| 1259 | + unsigned long gpio_bits = dev->driver_info->data; |
---|
| 1260 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 1261 | + |
---|
| 1262 | + axusbnet_get_endpoints(dev, intf); |
---|
| 1263 | + |
---|
| 1264 | + buf = kmalloc(ETH_ALEN, GFP_KERNEL); |
---|
| 1265 | + if (!buf) { |
---|
| 1266 | + ret = -ENOMEM; |
---|
| 1267 | + goto out1; |
---|
| 1268 | + } |
---|
| 1269 | + |
---|
| 1270 | + /* Toggle the GPIOs in a manufacturer/model specific way */ |
---|
| 1271 | + for (i = 2; i >= 0; i--) { |
---|
| 1272 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 1273 | + (gpio_bits >> (i * 8)) & 0xff, |
---|
| 1274 | + 0, 0, NULL); |
---|
| 1275 | + if (ret < 0) |
---|
| 1276 | + goto out2; |
---|
| 1277 | + |
---|
| 1278 | + msleep(5); |
---|
| 1279 | + } |
---|
| 1280 | + |
---|
| 1281 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x80, 0, 0, NULL); |
---|
| 1282 | + if (ret < 0) { |
---|
| 1283 | + deverr(dev, "send AX_CMD_WRITE_RX_CTL failed: %d", ret); |
---|
| 1284 | + goto out2; |
---|
| 1285 | + } |
---|
| 1286 | + |
---|
| 1287 | + /* Get the MAC address */ |
---|
| 1288 | + memset(buf, 0, ETH_ALEN); |
---|
| 1289 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, 6, buf); |
---|
| 1290 | + if (ret < 0) { |
---|
| 1291 | + deverr(dev, "read AX_CMD_READ_NODE_ID failed: %d", ret); |
---|
| 1292 | + goto out2; |
---|
| 1293 | + } |
---|
| 1294 | + memcpy(dev->net->dev_addr, buf, ETH_ALEN); |
---|
| 1295 | + |
---|
| 1296 | + /* Get the PHY id */ |
---|
| 1297 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); |
---|
| 1298 | + if (ret < 0) { |
---|
| 1299 | + deverr(dev, "error on read AX_CMD_READ_PHY_ID: %02x", ret); |
---|
| 1300 | + goto out2; |
---|
| 1301 | + } else if (ret < 2) { |
---|
| 1302 | + /* this should always return 2 bytes */ |
---|
| 1303 | + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", |
---|
| 1304 | + ret); |
---|
| 1305 | + ret = -EIO; |
---|
| 1306 | + goto out2; |
---|
| 1307 | + } |
---|
| 1308 | + |
---|
| 1309 | + /* Initialize MII structure */ |
---|
| 1310 | + dev->mii.dev = dev->net; |
---|
| 1311 | + dev->mii.mdio_read = ax8817x_mdio_read_le; |
---|
| 1312 | + dev->mii.mdio_write = ax8817x_mdio_write_le; |
---|
| 1313 | + dev->mii.phy_id_mask = 0x3f; |
---|
| 1314 | + dev->mii.reg_num_mask = 0x1f; |
---|
| 1315 | + dev->mii.phy_id = *((u8 *)buf + 1); |
---|
| 1316 | + |
---|
| 1317 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 1318 | + dev->net->do_ioctl = ax8817x_ioctl; |
---|
| 1319 | + dev->net->set_multicast_list = ax8817x_set_multicast; |
---|
| 1320 | + dev->net->set_mac_address = ax8817x_set_mac_addr; |
---|
| 1321 | +#else |
---|
| 1322 | + dev->net->netdev_ops = &ax88x72_netdev_ops; |
---|
| 1323 | +#endif |
---|
| 1324 | + |
---|
| 1325 | + dev->net->ethtool_ops = &ax8817x_ethtool_ops; |
---|
| 1326 | + |
---|
| 1327 | + /* Register suspend and resume functions */ |
---|
| 1328 | + data->suspend = axusbnet_suspend; |
---|
| 1329 | + data->resume = axusbnet_resume; |
---|
| 1330 | + |
---|
| 1331 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); |
---|
| 1332 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 1333 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); |
---|
| 1334 | + mii_nway_restart(&dev->mii); |
---|
| 1335 | + |
---|
| 1336 | + printk(version); |
---|
| 1337 | + |
---|
| 1338 | + return 0; |
---|
| 1339 | +out2: |
---|
| 1340 | + kfree(buf); |
---|
| 1341 | +out1: |
---|
| 1342 | + return ret; |
---|
| 1343 | +} |
---|
| 1344 | + |
---|
| 1345 | +static struct ethtool_ops ax88772_ethtool_ops = { |
---|
| 1346 | + .get_drvinfo = ax8817x_get_drvinfo, |
---|
| 1347 | + .get_link = ethtool_op_get_link, |
---|
| 1348 | + .get_msglevel = axusbnet_get_msglevel, |
---|
| 1349 | + .set_msglevel = axusbnet_set_msglevel, |
---|
| 1350 | + .get_wol = ax8817x_get_wol, |
---|
| 1351 | + .set_wol = ax8817x_set_wol, |
---|
| 1352 | + .get_eeprom_len = ax8817x_get_eeprom_len, |
---|
| 1353 | + .get_eeprom = ax8817x_get_eeprom, |
---|
| 1354 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) |
---|
| 1355 | + .get_settings = ax8817x_get_settings, |
---|
| 1356 | + .set_settings = ax8817x_set_settings, |
---|
| 1357 | +#else |
---|
| 1358 | + .get_link_ksettings = ax8817x_get_link_ksettings, |
---|
| 1359 | + .set_link_ksettings = ax8817x_set_link_ksettings, |
---|
| 1360 | +#endif |
---|
| 1361 | +}; |
---|
| 1362 | + |
---|
| 1363 | +static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 1364 | +{ |
---|
| 1365 | + int ret; |
---|
| 1366 | + void *buf; |
---|
| 1367 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 1368 | + struct ax88772_data *ax772_data = NULL; |
---|
| 1369 | + |
---|
| 1370 | + axusbnet_get_endpoints(dev, intf); |
---|
| 1371 | + |
---|
| 1372 | + buf = kmalloc(6, GFP_KERNEL); |
---|
| 1373 | + if (!buf) { |
---|
| 1374 | + deverr(dev, "Cannot allocate memory for buffer"); |
---|
| 1375 | + ret = -ENOMEM; |
---|
| 1376 | + goto out1; |
---|
| 1377 | + } |
---|
| 1378 | + |
---|
| 1379 | + ax772_data = kmalloc(sizeof(*ax772_data), GFP_KERNEL); |
---|
| 1380 | + if (!ax772_data) { |
---|
| 1381 | + deverr(dev, "Cannot allocate memory for AX88772 data"); |
---|
| 1382 | + kfree(buf); |
---|
| 1383 | + return -ENOMEM; |
---|
| 1384 | + } |
---|
| 1385 | + |
---|
| 1386 | + memset(ax772_data, 0, sizeof(*ax772_data)); |
---|
| 1387 | + dev->priv = ax772_data; |
---|
| 1388 | + |
---|
| 1389 | + ax772_data->ax_work = create_singlethread_workqueue("ax88772"); |
---|
| 1390 | + if (!ax772_data->ax_work) { |
---|
| 1391 | + kfree(ax772_data); |
---|
| 1392 | + kfree(buf); |
---|
| 1393 | + return -ENOMEM; |
---|
| 1394 | + } |
---|
| 1395 | + |
---|
| 1396 | + ax772_data->dev = dev; |
---|
| 1397 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 1398 | + INIT_WORK(&ax772_data->check_link, ax88772_link_reset, dev); |
---|
| 1399 | +#else |
---|
| 1400 | + INIT_WORK(&ax772_data->check_link, ax88772_link_reset); |
---|
| 1401 | +#endif |
---|
| 1402 | + |
---|
| 1403 | + /* reload eeprom data */ |
---|
| 1404 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, 0x00B0, 0, 0, NULL); |
---|
| 1405 | + if (ret < 0) |
---|
| 1406 | + goto out2; |
---|
| 1407 | + |
---|
| 1408 | + msleep(5); |
---|
| 1409 | + |
---|
| 1410 | + /* Initialize MII structure */ |
---|
| 1411 | + dev->mii.dev = dev->net; |
---|
| 1412 | + dev->mii.mdio_read = ax8817x_mdio_read_le; |
---|
| 1413 | + dev->mii.mdio_write = ax8817x_mdio_write_le; |
---|
| 1414 | + dev->mii.phy_id_mask = 0xff; |
---|
| 1415 | + dev->mii.reg_num_mask = 0xff; |
---|
| 1416 | + |
---|
| 1417 | + /* Get the PHY id */ |
---|
| 1418 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); |
---|
| 1419 | + if (ret < 0) { |
---|
| 1420 | + deverr(dev, "Error reading PHY ID: %02x", ret); |
---|
| 1421 | + goto out2; |
---|
| 1422 | + } else if (ret < 2) { |
---|
| 1423 | + /* this should always return 2 bytes */ |
---|
| 1424 | + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", |
---|
| 1425 | + ret); |
---|
| 1426 | + ret = -EIO; |
---|
| 1427 | + goto out2; |
---|
| 1428 | + } |
---|
| 1429 | + dev->mii.phy_id = *((u8 *)buf + 1); |
---|
| 1430 | + |
---|
| 1431 | + if (dev->mii.phy_id == 0x10) { |
---|
| 1432 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, |
---|
| 1433 | + 0x0001, 0, 0, NULL); |
---|
| 1434 | + if (ret < 0) { |
---|
| 1435 | + deverr(dev, "Select PHY #1 failed: %d", ret); |
---|
| 1436 | + goto out2; |
---|
| 1437 | + } |
---|
| 1438 | + |
---|
| 1439 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, |
---|
| 1440 | + 0, 0, NULL); |
---|
| 1441 | + if (ret < 0) { |
---|
| 1442 | + deverr(dev, "Failed to power down PHY: %d", ret); |
---|
| 1443 | + goto out2; |
---|
| 1444 | + } |
---|
| 1445 | + |
---|
| 1446 | + msleep(150); |
---|
| 1447 | + |
---|
| 1448 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, |
---|
| 1449 | + 0, 0, NULL); |
---|
| 1450 | + if (ret < 0) { |
---|
| 1451 | + deverr(dev, "Failed to perform software reset: %d", |
---|
| 1452 | + ret); |
---|
| 1453 | + goto out2; |
---|
| 1454 | + } |
---|
| 1455 | + |
---|
| 1456 | + msleep(150); |
---|
| 1457 | + |
---|
| 1458 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 1459 | + AX_SWRESET_IPRL | AX_SWRESET_PRL, |
---|
| 1460 | + 0, 0, NULL); |
---|
| 1461 | + if (ret < 0) { |
---|
| 1462 | + deverr(dev, |
---|
| 1463 | + "Failed to set PHY reset control: %d", ret); |
---|
| 1464 | + goto out2; |
---|
| 1465 | + } |
---|
| 1466 | + } else { |
---|
| 1467 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, |
---|
| 1468 | + 0x0000, 0, 0, NULL); |
---|
| 1469 | + if (ret < 0) { |
---|
| 1470 | + deverr(dev, "Select PHY #1 failed: %d", ret); |
---|
| 1471 | + goto out2; |
---|
| 1472 | + } |
---|
| 1473 | + |
---|
| 1474 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 1475 | + AX_SWRESET_IPPD | AX_SWRESET_PRL, |
---|
| 1476 | + 0, 0, NULL); |
---|
| 1477 | + if (ret < 0) { |
---|
| 1478 | + deverr(dev, "Failed to power down internal PHY: %d", |
---|
| 1479 | + ret); |
---|
| 1480 | + goto out2; |
---|
| 1481 | + } |
---|
| 1482 | + } |
---|
| 1483 | + |
---|
| 1484 | + msleep(150); |
---|
| 1485 | + |
---|
| 1486 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 1487 | + 0x0000, 0, 0, NULL); |
---|
| 1488 | + if (ret < 0) { |
---|
| 1489 | + deverr(dev, "Failed to reset RX_CTL: %d", ret); |
---|
| 1490 | + goto out2; |
---|
| 1491 | + } |
---|
| 1492 | + |
---|
| 1493 | + /* Get the MAC address */ |
---|
| 1494 | + memset(buf, 0, ETH_ALEN); |
---|
| 1495 | + ret = ax8817x_get_mac(dev, buf); |
---|
| 1496 | + if (ret < 0) { |
---|
| 1497 | + deverr(dev, "Get HW address failed: %d", ret); |
---|
| 1498 | + goto out2; |
---|
| 1499 | + } |
---|
| 1500 | + |
---|
| 1501 | + ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 1502 | + if (ret < 0) { |
---|
| 1503 | + deverr(dev, "Enabling software MII failed: %d", ret); |
---|
| 1504 | + goto out2; |
---|
| 1505 | + } |
---|
| 1506 | + |
---|
| 1507 | + if (dev->mii.phy_id == 0x10) { |
---|
| 1508 | + ret = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 2); |
---|
| 1509 | + if (ret != 0x003b) { |
---|
| 1510 | + deverr(dev, "Read PHY register 2 must be 0x3b00: %d", |
---|
| 1511 | + ret); |
---|
| 1512 | + goto out2; |
---|
| 1513 | + } |
---|
| 1514 | + |
---|
| 1515 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_PRL, |
---|
| 1516 | + 0, 0, NULL); |
---|
| 1517 | + if (ret < 0) { |
---|
| 1518 | + deverr(dev, "Set external PHY reset pin level: %d", |
---|
| 1519 | + ret); |
---|
| 1520 | + goto out2; |
---|
| 1521 | + } |
---|
| 1522 | + msleep(150); |
---|
| 1523 | + |
---|
| 1524 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 1525 | + AX_SWRESET_IPRL | AX_SWRESET_PRL, |
---|
| 1526 | + 0, 0, NULL); |
---|
| 1527 | + if (ret < 0) { |
---|
| 1528 | + deverr(dev, |
---|
| 1529 | + "Set Internal/External PHY reset control: %d", |
---|
| 1530 | + ret); |
---|
| 1531 | + goto out2; |
---|
| 1532 | + } |
---|
| 1533 | + msleep(150); |
---|
| 1534 | + } |
---|
| 1535 | + |
---|
| 1536 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 1537 | + dev->net->do_ioctl = ax8817x_ioctl; |
---|
| 1538 | + dev->net->set_multicast_list = ax8817x_set_multicast; |
---|
| 1539 | + dev->net->set_mac_address = ax8817x_set_mac_addr; |
---|
| 1540 | +#else |
---|
| 1541 | + dev->net->netdev_ops = &ax88x72_netdev_ops; |
---|
| 1542 | +#endif |
---|
| 1543 | + |
---|
| 1544 | + dev->net->ethtool_ops = &ax88772_ethtool_ops; |
---|
| 1545 | + |
---|
| 1546 | + /* Register suspend and resume functions */ |
---|
| 1547 | + data->suspend = ax88772_suspend; |
---|
| 1548 | + data->resume = ax88772_resume; |
---|
| 1549 | + |
---|
| 1550 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); |
---|
| 1551 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 1552 | + ADVERTISE_ALL | ADVERTISE_CSMA); |
---|
| 1553 | + |
---|
| 1554 | + mii_nway_restart(&dev->mii); |
---|
| 1555 | + ax772_data->autoneg_start = jiffies; |
---|
| 1556 | + ax772_data->Event = WAIT_AUTONEG_COMPLETE; |
---|
| 1557 | + |
---|
| 1558 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, 0, 0, 0, NULL); |
---|
| 1559 | + if (ret < 0) { |
---|
| 1560 | + deverr(dev, "Write medium mode register: %d", ret); |
---|
| 1561 | + goto out2; |
---|
| 1562 | + } |
---|
| 1563 | + |
---|
| 1564 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, |
---|
| 1565 | + AX88772_IPG0_DEFAULT | |
---|
| 1566 | + (AX88772_IPG1_DEFAULT << 8), |
---|
| 1567 | + AX88772_IPG2_DEFAULT, 0, NULL); |
---|
| 1568 | + if (ret < 0) { |
---|
| 1569 | + deverr(dev, "Write IPG,IPG1,IPG2 failed: %d", ret); |
---|
| 1570 | + goto out2; |
---|
| 1571 | + } |
---|
| 1572 | + |
---|
| 1573 | + ret = ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); |
---|
| 1574 | + if (ret < 0) { |
---|
| 1575 | + deverr(dev, "Failed to set hardware MII: %02x", ret); |
---|
| 1576 | + goto out2; |
---|
| 1577 | + } |
---|
| 1578 | + |
---|
| 1579 | + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ |
---|
| 1580 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0x0088, 0, 0, NULL); |
---|
| 1581 | + if (ret < 0) { |
---|
| 1582 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 1583 | + goto out2; |
---|
| 1584 | + } |
---|
| 1585 | + |
---|
| 1586 | + /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ |
---|
| 1587 | + if (dev->driver_info->flags & FLAG_FRAMING_AX) { |
---|
| 1588 | + /* hard_mtu is still the default - the device does not support |
---|
| 1589 | + jumbo eth frames */ |
---|
| 1590 | + dev->rx_urb_size = 2048; |
---|
| 1591 | + } |
---|
| 1592 | + |
---|
| 1593 | + kfree(buf); |
---|
| 1594 | + printk(version); |
---|
| 1595 | + return 0; |
---|
| 1596 | + |
---|
| 1597 | +out2: |
---|
| 1598 | + destroy_workqueue(ax772_data->ax_work); |
---|
| 1599 | + kfree(ax772_data); |
---|
| 1600 | + kfree(buf); |
---|
| 1601 | +out1: |
---|
| 1602 | + return ret; |
---|
| 1603 | +} |
---|
| 1604 | + |
---|
| 1605 | +static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 1606 | +{ |
---|
| 1607 | + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; |
---|
| 1608 | + |
---|
| 1609 | + if (ax772_data) { |
---|
| 1610 | + flush_workqueue(ax772_data->ax_work); |
---|
| 1611 | + destroy_workqueue(ax772_data->ax_work); |
---|
| 1612 | + |
---|
| 1613 | + /* stop MAC operation */ |
---|
| 1614 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, AX_RX_CTL_STOP, |
---|
| 1615 | + 0, 0, NULL); |
---|
| 1616 | + |
---|
| 1617 | + /* Power down PHY */ |
---|
| 1618 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, |
---|
| 1619 | + 0, 0, NULL); |
---|
| 1620 | + |
---|
| 1621 | + kfree(ax772_data); |
---|
| 1622 | + } |
---|
| 1623 | +} |
---|
| 1624 | + |
---|
| 1625 | +static int ax88772a_phy_powerup(struct usbnet *dev) |
---|
| 1626 | +{ |
---|
| 1627 | + int ret; |
---|
| 1628 | + /* set the embedded Ethernet PHY in power-down state */ |
---|
| 1629 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 1630 | + AX_SWRESET_IPPD | AX_SWRESET_IPRL, 0, 0, NULL); |
---|
| 1631 | + if (ret < 0) { |
---|
| 1632 | + deverr(dev, "Failed to power down PHY: %d", ret); |
---|
| 1633 | + return ret; |
---|
| 1634 | + } |
---|
| 1635 | + |
---|
| 1636 | + msleep(10); |
---|
| 1637 | + |
---|
| 1638 | + /* set the embedded Ethernet PHY in power-up state */ |
---|
| 1639 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL, |
---|
| 1640 | + 0, 0, NULL); |
---|
| 1641 | + if (ret < 0) { |
---|
| 1642 | + deverr(dev, "Failed to reset PHY: %d", ret); |
---|
| 1643 | + return ret; |
---|
| 1644 | + } |
---|
| 1645 | + |
---|
| 1646 | + msleep(600); |
---|
| 1647 | + |
---|
| 1648 | + /* set the embedded Ethernet PHY in reset state */ |
---|
| 1649 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_CLEAR, |
---|
| 1650 | + 0, 0, NULL); |
---|
| 1651 | + if (ret < 0) { |
---|
| 1652 | + deverr(dev, "Failed to power up PHY: %d", ret); |
---|
| 1653 | + return ret; |
---|
| 1654 | + } |
---|
| 1655 | + |
---|
| 1656 | + /* set the embedded Ethernet PHY in power-up state */ |
---|
| 1657 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL, |
---|
| 1658 | + 0, 0, NULL); |
---|
| 1659 | + if (ret < 0) { |
---|
| 1660 | + deverr(dev, "Failed to reset PHY: %d", ret); |
---|
| 1661 | + return ret; |
---|
| 1662 | + } |
---|
| 1663 | + |
---|
| 1664 | + return 0; |
---|
| 1665 | +} |
---|
| 1666 | + |
---|
| 1667 | +static int ax88772a_bind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 1668 | +{ |
---|
| 1669 | + int ret = -EIO; |
---|
| 1670 | + void *buf; |
---|
| 1671 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 1672 | + struct ax88772a_data *ax772a_data = NULL; |
---|
| 1673 | + |
---|
| 1674 | + printk(version); |
---|
| 1675 | + |
---|
| 1676 | + axusbnet_get_endpoints(dev, intf); |
---|
| 1677 | + |
---|
| 1678 | + buf = kmalloc(6, GFP_KERNEL); |
---|
| 1679 | + if (!buf) { |
---|
| 1680 | + deverr(dev, "Cannot allocate memory for buffer"); |
---|
| 1681 | + ret = -ENOMEM; |
---|
| 1682 | + goto out1; |
---|
| 1683 | + } |
---|
| 1684 | + |
---|
| 1685 | + ax772a_data = kmalloc(sizeof(*ax772a_data), GFP_KERNEL); |
---|
| 1686 | + if (!ax772a_data) { |
---|
| 1687 | + deverr(dev, "Cannot allocate memory for AX88772A data"); |
---|
| 1688 | + kfree(buf); |
---|
| 1689 | + return -ENOMEM; |
---|
| 1690 | + } |
---|
| 1691 | + memset(ax772a_data, 0, sizeof(*ax772a_data)); |
---|
| 1692 | + dev->priv = ax772a_data; |
---|
| 1693 | + |
---|
| 1694 | + ax772a_data->ax_work = create_singlethread_workqueue("ax88772a"); |
---|
| 1695 | + if (!ax772a_data->ax_work) { |
---|
| 1696 | + kfree(ax772a_data); |
---|
| 1697 | + kfree(buf); |
---|
| 1698 | + return -ENOMEM; |
---|
| 1699 | + } |
---|
| 1700 | + |
---|
| 1701 | + ax772a_data->dev = dev; |
---|
| 1702 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 1703 | + INIT_WORK(&ax772a_data->check_link, ax88772a_link_reset, dev); |
---|
| 1704 | +#else |
---|
| 1705 | + INIT_WORK(&ax772a_data->check_link, ax88772a_link_reset); |
---|
| 1706 | +#endif |
---|
| 1707 | + |
---|
| 1708 | + /* Get the EEPROM data*/ |
---|
| 1709 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, |
---|
| 1710 | + (void *)&ax772a_data->EepromData); |
---|
| 1711 | + if (ret < 0) { |
---|
| 1712 | + deverr(dev, "read SROM address 17h failed: %d", ret); |
---|
| 1713 | + goto out2; |
---|
| 1714 | + } |
---|
| 1715 | + le16_to_cpus(&ax772a_data->EepromData); |
---|
| 1716 | + /* End of get EEPROM data */ |
---|
| 1717 | + |
---|
| 1718 | + /* reload eeprom data */ |
---|
| 1719 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 1720 | + AXGPIOS_RSE, 0, 0, NULL); |
---|
| 1721 | + if (ret < 0) |
---|
| 1722 | + goto out2; |
---|
| 1723 | + |
---|
| 1724 | + msleep(5); |
---|
| 1725 | + |
---|
| 1726 | + /* Initialize MII structure */ |
---|
| 1727 | + dev->mii.dev = dev->net; |
---|
| 1728 | + dev->mii.mdio_read = ax8817x_mdio_read_le; |
---|
| 1729 | + dev->mii.mdio_write = ax8817x_mdio_write_le; |
---|
| 1730 | + dev->mii.phy_id_mask = 0xff; |
---|
| 1731 | + dev->mii.reg_num_mask = 0xff; |
---|
| 1732 | + |
---|
| 1733 | + /* Get the PHY id */ |
---|
| 1734 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); |
---|
| 1735 | + if (ret < 0) { |
---|
| 1736 | + deverr(dev, "Error reading PHY ID: %02x", ret); |
---|
| 1737 | + goto out2; |
---|
| 1738 | + } else if (ret < 2) { |
---|
| 1739 | + /* this should always return 2 bytes */ |
---|
| 1740 | + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", |
---|
| 1741 | + ret); |
---|
| 1742 | + goto out2; |
---|
| 1743 | + } |
---|
| 1744 | + dev->mii.phy_id = *((u8 *)buf + 1); |
---|
| 1745 | + |
---|
| 1746 | + if (dev->mii.phy_id != 0x10) { |
---|
| 1747 | + deverr(dev, "Got wrong PHY ID: %02x", dev->mii.phy_id); |
---|
| 1748 | + goto out2; |
---|
| 1749 | + } |
---|
| 1750 | + |
---|
| 1751 | + /* select the embedded 10/100 Ethernet PHY */ |
---|
| 1752 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, |
---|
| 1753 | + AX_PHYSEL_SSEN | AX_PHYSEL_PSEL | AX_PHYSEL_SSMII, |
---|
| 1754 | + 0, 0, NULL); |
---|
| 1755 | + if (ret < 0) { |
---|
| 1756 | + deverr(dev, "Select PHY #1 failed: %d", ret); |
---|
| 1757 | + goto out2; |
---|
| 1758 | + } |
---|
| 1759 | + |
---|
| 1760 | + ret = ax88772a_phy_powerup(dev); |
---|
| 1761 | + if (ret < 0) |
---|
| 1762 | + goto out2; |
---|
| 1763 | + |
---|
| 1764 | + /* stop MAC operation */ |
---|
| 1765 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, AX_RX_CTL_STOP, |
---|
| 1766 | + 0, 0, NULL); |
---|
| 1767 | + if (ret < 0) { |
---|
| 1768 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 1769 | + goto out2; |
---|
| 1770 | + } |
---|
| 1771 | + |
---|
| 1772 | + /* Get the MAC address */ |
---|
| 1773 | + memset(buf, 0, ETH_ALEN); |
---|
| 1774 | + ret = ax8817x_get_mac(dev, buf); |
---|
| 1775 | + if (ret < 0) { |
---|
| 1776 | + deverr(dev, "Get HW address failed: %d", ret); |
---|
| 1777 | + goto out2; |
---|
| 1778 | + } |
---|
| 1779 | + |
---|
| 1780 | + /* make sure the driver can enable sw mii operation */ |
---|
| 1781 | + ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 1782 | + if (ret < 0) { |
---|
| 1783 | + deverr(dev, "Enabling software MII failed: %d", ret); |
---|
| 1784 | + goto out2; |
---|
| 1785 | + } |
---|
| 1786 | + |
---|
| 1787 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 1788 | + dev->net->do_ioctl = ax8817x_ioctl; |
---|
| 1789 | + dev->net->set_multicast_list = ax8817x_set_multicast; |
---|
| 1790 | + dev->net->set_mac_address = ax8817x_set_mac_addr; |
---|
| 1791 | +#else |
---|
| 1792 | + dev->net->netdev_ops = &ax88x72_netdev_ops; |
---|
| 1793 | +#endif |
---|
| 1794 | + |
---|
| 1795 | + dev->net->ethtool_ops = &ax88772_ethtool_ops; |
---|
| 1796 | + |
---|
| 1797 | + /* Register suspend and resume functions */ |
---|
| 1798 | + data->suspend = ax88772_suspend; |
---|
| 1799 | + data->resume = ax88772_resume; |
---|
| 1800 | + |
---|
| 1801 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); |
---|
| 1802 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 1803 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); |
---|
| 1804 | + |
---|
| 1805 | + mii_nway_restart(&dev->mii); |
---|
| 1806 | + ax772a_data->autoneg_start = jiffies; |
---|
| 1807 | + ax772a_data->Event = WAIT_AUTONEG_COMPLETE; |
---|
| 1808 | + |
---|
| 1809 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 1810 | + 0, 0, 0, NULL); |
---|
| 1811 | + if (ret < 0) { |
---|
| 1812 | + deverr(dev, "Write medium mode register: %d", ret); |
---|
| 1813 | + goto out2; |
---|
| 1814 | + } |
---|
| 1815 | + |
---|
| 1816 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, |
---|
| 1817 | + AX88772A_IPG0_DEFAULT | AX88772A_IPG1_DEFAULT << 8, |
---|
| 1818 | + AX88772A_IPG2_DEFAULT, 0, NULL); |
---|
| 1819 | + if (ret < 0) { |
---|
| 1820 | + deverr(dev, "Write IPG,IPG1,IPG2 failed: %d", ret); |
---|
| 1821 | + goto out2; |
---|
| 1822 | + } |
---|
| 1823 | + |
---|
| 1824 | + memset(buf, 0, 4); |
---|
| 1825 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_IPG012, 0, 0, 3, buf); |
---|
| 1826 | + *((u8 *)buf + 3) = 0x00; |
---|
| 1827 | + if (ret < 0) { |
---|
| 1828 | + deverr(dev, "Failed to read IPG,IPG1,IPG2 failed: %d", ret); |
---|
| 1829 | + goto out2; |
---|
| 1830 | + } else { |
---|
| 1831 | + __u32 tmp32 = *((u32*)buf); |
---|
| 1832 | + le32_to_cpus(&tmp32); |
---|
| 1833 | + if (tmp32 != (AX88772A_IPG2_DEFAULT << 16 | |
---|
| 1834 | + AX88772A_IPG1_DEFAULT << 8 | AX88772A_IPG0_DEFAULT)) { |
---|
| 1835 | + printk("Non-authentic ASIX product\nASIX does not support it\n"); |
---|
| 1836 | + ret = -ENODEV; |
---|
| 1837 | + goto out2; |
---|
| 1838 | + } |
---|
| 1839 | + } |
---|
| 1840 | + |
---|
| 1841 | + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ |
---|
| 1842 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 1843 | + (AX_RX_CTL_START | AX_RX_CTL_AB), |
---|
| 1844 | + 0, 0, NULL); |
---|
| 1845 | + if (ret < 0) { |
---|
| 1846 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 1847 | + goto out2; |
---|
| 1848 | + } |
---|
| 1849 | + |
---|
| 1850 | + /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ |
---|
| 1851 | + if (dev->driver_info->flags & FLAG_FRAMING_AX) { |
---|
| 1852 | + /* hard_mtu is still the default - the device does not support |
---|
| 1853 | + jumbo eth frames */ |
---|
| 1854 | + dev->rx_urb_size = 2048; |
---|
| 1855 | + } |
---|
| 1856 | + |
---|
| 1857 | + kfree(buf); |
---|
| 1858 | + |
---|
| 1859 | + return ret; |
---|
| 1860 | +out2: |
---|
| 1861 | + destroy_workqueue(ax772a_data->ax_work); |
---|
| 1862 | + kfree(ax772a_data); |
---|
| 1863 | + kfree(buf); |
---|
| 1864 | +out1: |
---|
| 1865 | + return ret; |
---|
| 1866 | +} |
---|
| 1867 | + |
---|
| 1868 | +static void ax88772a_unbind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 1869 | +{ |
---|
| 1870 | + struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv; |
---|
| 1871 | + |
---|
| 1872 | + if (ax772a_data) { |
---|
| 1873 | + |
---|
| 1874 | + flush_workqueue(ax772a_data->ax_work); |
---|
| 1875 | + destroy_workqueue(ax772a_data->ax_work); |
---|
| 1876 | + |
---|
| 1877 | + /* stop MAC operation */ |
---|
| 1878 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 1879 | + AX_RX_CTL_STOP, 0, 0, NULL); |
---|
| 1880 | + |
---|
| 1881 | + /* Power down PHY */ |
---|
| 1882 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 1883 | + AX_SWRESET_IPPD, 0, 0, NULL); |
---|
| 1884 | + |
---|
| 1885 | + kfree(ax772a_data); |
---|
| 1886 | + } |
---|
| 1887 | +} |
---|
| 1888 | + |
---|
| 1889 | +static int ax88772b_set_csums(struct usbnet *dev) |
---|
| 1890 | +{ |
---|
| 1891 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 1892 | + u16 checksum; |
---|
| 1893 | + |
---|
| 1894 | + if (ax772b_data->checksum & AX_RX_CHECKSUM) |
---|
| 1895 | + checksum = AX_RXCOE_DEF_CSUM; |
---|
| 1896 | + else |
---|
| 1897 | + checksum = 0; |
---|
| 1898 | + |
---|
| 1899 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_RXCOE_CTL, |
---|
| 1900 | + checksum, 0, 0, NULL); |
---|
| 1901 | + |
---|
| 1902 | + if (ax772b_data->checksum & AX_TX_CHECKSUM) |
---|
| 1903 | + checksum = AX_TXCOE_DEF_CSUM; |
---|
| 1904 | + else |
---|
| 1905 | + checksum = 0; |
---|
| 1906 | + |
---|
| 1907 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_TXCOE_CTL, |
---|
| 1908 | + checksum, 0, 0, NULL); |
---|
| 1909 | + |
---|
| 1910 | + return 0; |
---|
| 1911 | +} |
---|
| 1912 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) |
---|
| 1913 | +static u32 ax88772b_get_tx_csum(struct net_device *netdev) |
---|
| 1914 | +{ |
---|
| 1915 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 1916 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 1917 | + |
---|
| 1918 | + return ax772b_data->checksum & AX_TX_CHECKSUM; |
---|
| 1919 | +} |
---|
| 1920 | + |
---|
| 1921 | +static u32 ax88772b_get_rx_csum(struct net_device *netdev) |
---|
| 1922 | +{ |
---|
| 1923 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 1924 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 1925 | + |
---|
| 1926 | + return ax772b_data->checksum & AX_RX_CHECKSUM; |
---|
| 1927 | +} |
---|
| 1928 | + |
---|
| 1929 | +static int ax88772b_set_rx_csum(struct net_device *netdev, u32 val) |
---|
| 1930 | +{ |
---|
| 1931 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 1932 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 1933 | + |
---|
| 1934 | + if (val) |
---|
| 1935 | + ax772b_data->checksum |= AX_RX_CHECKSUM; |
---|
| 1936 | + else |
---|
| 1937 | + ax772b_data->checksum &= ~AX_RX_CHECKSUM; |
---|
| 1938 | + |
---|
| 1939 | + return ax88772b_set_csums(dev); |
---|
| 1940 | +} |
---|
| 1941 | + |
---|
| 1942 | +static int ax88772b_set_tx_csum(struct net_device *netdev, u32 val) |
---|
| 1943 | +{ |
---|
| 1944 | + struct usbnet *dev = netdev_priv(netdev); |
---|
| 1945 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 1946 | + |
---|
| 1947 | + if (val) |
---|
| 1948 | + ax772b_data->checksum |= AX_TX_CHECKSUM; |
---|
| 1949 | + else |
---|
| 1950 | + ax772b_data->checksum &= ~AX_TX_CHECKSUM; |
---|
| 1951 | + |
---|
| 1952 | + ethtool_op_set_tx_csum(netdev, val); |
---|
| 1953 | + |
---|
| 1954 | + return ax88772b_set_csums(dev); |
---|
| 1955 | +} |
---|
| 1956 | +#endif |
---|
| 1957 | +static struct ethtool_ops ax88772b_ethtool_ops = { |
---|
| 1958 | + .get_drvinfo = ax8817x_get_drvinfo, |
---|
| 1959 | + .get_link = ethtool_op_get_link, |
---|
| 1960 | + .get_msglevel = axusbnet_get_msglevel, |
---|
| 1961 | + .set_msglevel = axusbnet_set_msglevel, |
---|
| 1962 | + .get_wol = ax8817x_get_wol, |
---|
| 1963 | + .set_wol = ax8817x_set_wol, |
---|
| 1964 | + .get_eeprom_len = ax8817x_get_eeprom_len, |
---|
| 1965 | + .get_eeprom = ax8817x_get_eeprom, |
---|
| 1966 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) |
---|
| 1967 | + .get_settings = ax8817x_get_settings, |
---|
| 1968 | + .set_settings = ax8817x_set_settings, |
---|
| 1969 | +#else |
---|
| 1970 | + .get_link_ksettings = ax8817x_get_link_ksettings, |
---|
| 1971 | + .set_link_ksettings = ax8817x_set_link_ksettings, |
---|
| 1972 | +#endif |
---|
| 1973 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) |
---|
| 1974 | + .set_tx_csum = ax88772b_set_tx_csum, |
---|
| 1975 | + .get_tx_csum = ax88772b_get_tx_csum, |
---|
| 1976 | + .get_rx_csum = ax88772b_get_rx_csum, |
---|
| 1977 | + .set_rx_csum = ax88772b_set_rx_csum, |
---|
| 1978 | +#endif |
---|
| 1979 | +}; |
---|
| 1980 | + |
---|
| 1981 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29) |
---|
| 1982 | +static const struct net_device_ops ax88772b_netdev_ops = { |
---|
| 1983 | + .ndo_open = axusbnet_open, |
---|
| 1984 | + .ndo_stop = axusbnet_stop, |
---|
| 1985 | + .ndo_start_xmit = axusbnet_start_xmit, |
---|
| 1986 | + .ndo_tx_timeout = axusbnet_tx_timeout, |
---|
| 1987 | + .ndo_change_mtu = axusbnet_change_mtu, |
---|
| 1988 | + .ndo_do_ioctl = ax8817x_ioctl, |
---|
| 1989 | + .ndo_get_stats = axusbnet_get_stats, |
---|
| 1990 | + .ndo_set_mac_address = ax8817x_set_mac_addr, |
---|
| 1991 | + .ndo_validate_addr = eth_validate_addr, |
---|
| 1992 | +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 0) |
---|
| 1993 | + .ndo_set_multicast_list = ax88772b_set_multicast, |
---|
| 1994 | +#else |
---|
| 1995 | + .ndo_set_rx_mode = ax88772b_set_multicast, |
---|
| 1996 | +#endif |
---|
| 1997 | +}; |
---|
| 1998 | +#endif |
---|
| 1999 | + |
---|
| 2000 | +static int ax88772b_bind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 2001 | +{ |
---|
| 2002 | + int ret; |
---|
| 2003 | + void *buf; |
---|
| 2004 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 2005 | + struct ax88772b_data *ax772b_data; |
---|
| 2006 | + u16 *tmp16; |
---|
| 2007 | + u8 *tmp8; |
---|
| 2008 | + u8 tempphyselect; |
---|
| 2009 | + bool internalphy; |
---|
| 2010 | + |
---|
| 2011 | + printk(version); |
---|
| 2012 | + axusbnet_get_endpoints(dev, intf); |
---|
| 2013 | + buf = kmalloc(6, GFP_KERNEL); |
---|
| 2014 | + if (!buf) { |
---|
| 2015 | + deverr(dev, "Cannot allocate memory for buffer"); |
---|
| 2016 | + return -ENOMEM; |
---|
| 2017 | + } |
---|
| 2018 | + tmp16 = (u16 *)buf; |
---|
| 2019 | + ax772b_data = kmalloc(sizeof(*ax772b_data), GFP_KERNEL); |
---|
| 2020 | + if (!ax772b_data) { |
---|
| 2021 | + deverr(dev, "Cannot allocate memory for AX88772B data"); |
---|
| 2022 | + kfree(buf); |
---|
| 2023 | + return -ENOMEM; |
---|
| 2024 | + } |
---|
| 2025 | + memset(ax772b_data, 0, sizeof(*ax772b_data)); |
---|
| 2026 | + dev->priv = ax772b_data; |
---|
| 2027 | + ax772b_data->ax_work = create_singlethread_workqueue("ax88772b"); |
---|
| 2028 | + if (!ax772b_data->ax_work) { |
---|
| 2029 | + kfree(buf); |
---|
| 2030 | + kfree(ax772b_data); |
---|
| 2031 | + return -ENOMEM; |
---|
| 2032 | + } |
---|
| 2033 | + |
---|
| 2034 | + ax772b_data->dev = dev; |
---|
| 2035 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 2036 | + INIT_WORK(&ax772b_data->check_link, ax88772b_link_reset, dev); |
---|
| 2037 | +#else |
---|
| 2038 | + INIT_WORK(&ax772b_data->check_link, ax88772b_link_reset); |
---|
| 2039 | +#endif |
---|
| 2040 | + |
---|
| 2041 | + tmp8 = (u8 *)buf; |
---|
| 2042 | + ret = ax8817x_read_cmd(dev, AX_CMD_SW_PHY_STATUS, |
---|
| 2043 | + 0, 0, 1, tmp8); |
---|
| 2044 | + |
---|
| 2045 | + if (ret < 0) { |
---|
| 2046 | + deverr(dev, |
---|
| 2047 | + "read SW interface selection status register failed: %d\n", |
---|
| 2048 | + ret); |
---|
| 2049 | + goto err_out; |
---|
| 2050 | + } |
---|
| 2051 | + tempphyselect = *tmp8; |
---|
| 2052 | + tempphyselect &= 0x0C; |
---|
| 2053 | + |
---|
| 2054 | + if (tempphyselect == AX_PHYSEL_SSRMII) { |
---|
| 2055 | + internalphy = false; |
---|
| 2056 | + ax772b_data->OperationMode = OPERATION_MAC_MODE; |
---|
| 2057 | + ax772b_data->PhySelect = 0x00; |
---|
| 2058 | + } else if (tempphyselect == AX_PHYSEL_SSRRMII) { |
---|
| 2059 | + internalphy = true; |
---|
| 2060 | + ax772b_data->OperationMode = OPERATION_PHY_MODE; |
---|
| 2061 | + ax772b_data->PhySelect = 0x00; |
---|
| 2062 | + } else if (tempphyselect == AX_PHYSEL_SSMII) { |
---|
| 2063 | + internalphy = true; |
---|
| 2064 | + ax772b_data->OperationMode = OPERATION_MAC_MODE; |
---|
| 2065 | + ax772b_data->PhySelect = 0x01; |
---|
| 2066 | + } else { |
---|
| 2067 | + deverr(dev, "Unknown MII type\n"); |
---|
| 2068 | + goto err_out; |
---|
| 2069 | + } |
---|
| 2070 | + |
---|
| 2071 | + /* reload eeprom data */ |
---|
| 2072 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, AXGPIOS_RSE, |
---|
| 2073 | + 0, 0, NULL); |
---|
| 2074 | + if (ret < 0) { |
---|
| 2075 | + deverr(dev, "Failed to enable GPIO function: %d", ret); |
---|
| 2076 | + goto err_out; |
---|
| 2077 | + } |
---|
| 2078 | + msleep(5); |
---|
| 2079 | + |
---|
| 2080 | + /* Get the EEPROM data*/ |
---|
| 2081 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, 0x18, 0, 2, |
---|
| 2082 | + (void *)tmp16); |
---|
| 2083 | + if (ret < 0) { |
---|
| 2084 | + deverr(dev, "read SROM address 18h failed: %d", ret); |
---|
| 2085 | + goto err_out; |
---|
| 2086 | + } |
---|
| 2087 | + le16_to_cpus(tmp16); |
---|
| 2088 | + ax772b_data->psc = *tmp16 & 0xFF00; |
---|
| 2089 | + /* End of get EEPROM data */ |
---|
| 2090 | + |
---|
| 2091 | + /* Get the MAC address */ |
---|
| 2092 | + memset(buf, 0, ETH_ALEN); |
---|
| 2093 | + ret = ax8817x_get_mac(dev, buf); |
---|
| 2094 | + if (ret < 0) { |
---|
| 2095 | + deverr(dev, "Get HW address failed: %d", ret); |
---|
| 2096 | + goto err_out; |
---|
| 2097 | + } |
---|
| 2098 | + |
---|
| 2099 | + /* Initialize MII structure */ |
---|
| 2100 | + dev->mii.dev = dev->net; |
---|
| 2101 | + dev->mii.mdio_read = ax8817x_mdio_read_le; |
---|
| 2102 | + dev->mii.mdio_write = ax88772b_mdio_write_le; |
---|
| 2103 | + dev->mii.phy_id_mask = 0xff; |
---|
| 2104 | + dev->mii.reg_num_mask = 0xff; |
---|
| 2105 | + |
---|
| 2106 | + /* Get the PHY id */ |
---|
| 2107 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); |
---|
| 2108 | + if (ret < 0) { |
---|
| 2109 | + deverr(dev, "Error reading PHY ID: %02x", ret); |
---|
| 2110 | + goto err_out; |
---|
| 2111 | + } else if (ret < 2) { |
---|
| 2112 | + /* this should always return 2 bytes */ |
---|
| 2113 | + deverr(dev, "Read PHYID returned less than 2 bytes: ret=%02x", |
---|
| 2114 | + ret); |
---|
| 2115 | + ret = -EIO; |
---|
| 2116 | + goto err_out; |
---|
| 2117 | + } |
---|
| 2118 | + |
---|
| 2119 | + if (internalphy) |
---|
| 2120 | + dev->mii.phy_id = *((u8 *)buf + 1); |
---|
| 2121 | + else |
---|
| 2122 | + dev->mii.phy_id = *((u8 *)buf); |
---|
| 2123 | + |
---|
| 2124 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, |
---|
| 2125 | + ax772b_data->PhySelect, 0, 0, NULL); |
---|
| 2126 | + if (ret < 0) { |
---|
| 2127 | + deverr(dev, "Select PHY #1 failed: %d", ret); |
---|
| 2128 | + goto err_out; |
---|
| 2129 | + } |
---|
| 2130 | + |
---|
| 2131 | +#if 0 |
---|
| 2132 | + /* select the embedded 10/100 Ethernet PHY */ |
---|
| 2133 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, |
---|
| 2134 | + AX_PHYSEL_SSEN | AX_PHYSEL_PSEL | AX_PHYSEL_SSMII, |
---|
| 2135 | + 0, 0, NULL); |
---|
| 2136 | + if (ret < 0) { |
---|
| 2137 | + deverr(dev, "Select PHY #1 failed: %d", ret); |
---|
| 2138 | + goto err_out; |
---|
| 2139 | + } |
---|
| 2140 | + |
---|
| 2141 | + if (dev->mii.phy_id != 0x10) { |
---|
| 2142 | + deverr(dev, "Got wrong PHY ID: %02x", dev->mii.phy_id); |
---|
| 2143 | + ret = -EIO; |
---|
| 2144 | + goto err_out; |
---|
| 2145 | + } |
---|
| 2146 | +#endif |
---|
| 2147 | + ret = ax88772a_phy_powerup(dev); |
---|
| 2148 | + if (ret < 0) |
---|
| 2149 | + goto err_out; |
---|
| 2150 | + |
---|
| 2151 | + /* stop MAC operation */ |
---|
| 2152 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 2153 | + AX_RX_CTL_STOP, 0, 0, NULL); |
---|
| 2154 | + if (ret < 0) { |
---|
| 2155 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 2156 | + goto err_out; |
---|
| 2157 | + } |
---|
| 2158 | + |
---|
| 2159 | + /* make sure the driver can enable sw mii operation */ |
---|
| 2160 | + ret = ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0, 0, 0, NULL); |
---|
| 2161 | + if (ret < 0) { |
---|
| 2162 | + deverr(dev, "Enabling software MII failed: %d", ret); |
---|
| 2163 | + goto err_out; |
---|
| 2164 | + } |
---|
| 2165 | + |
---|
| 2166 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 2167 | + dev->net->do_ioctl = ax8817x_ioctl; |
---|
| 2168 | + dev->net->set_multicast_list = ax88772b_set_multicast; |
---|
| 2169 | + dev->net->set_mac_address = ax8817x_set_mac_addr; |
---|
| 2170 | +#else |
---|
| 2171 | + dev->net->netdev_ops = &ax88772b_netdev_ops; |
---|
| 2172 | +#endif |
---|
| 2173 | + |
---|
| 2174 | + dev->net->ethtool_ops = &ax88772b_ethtool_ops; |
---|
| 2175 | + |
---|
| 2176 | + /* Register suspend and resume functions */ |
---|
| 2177 | + data->suspend = ax88772b_suspend; |
---|
| 2178 | + data->resume = ax88772b_resume; |
---|
| 2179 | + |
---|
| 2180 | + if ((ax772b_data->OperationMode == OPERATION_MAC_MODE) && |
---|
| 2181 | + (ax772b_data->PhySelect == 0x00)) { |
---|
| 2182 | + if (ax88772b_external_phyinit(dev) != 0x00) { |
---|
| 2183 | + deverr(dev, "Failed to initial the external phy"); |
---|
| 2184 | + goto err_out; |
---|
| 2185 | + } |
---|
| 2186 | + } |
---|
| 2187 | + |
---|
| 2188 | + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) |
---|
| 2189 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id |
---|
| 2190 | + , MII_BMCR, 0x3900); |
---|
| 2191 | + |
---|
| 2192 | + if (dev->mii.phy_id != 0x10) |
---|
| 2193 | + ax8817x_mdio_write_le(dev->net, 0x10, MII_BMCR, 0x3900); |
---|
| 2194 | + |
---|
| 2195 | + if (dev->mii.phy_id == 0x10 && ax772b_data->OperationMode |
---|
| 2196 | + != OPERATION_PHY_MODE) { |
---|
| 2197 | + |
---|
| 2198 | + *tmp16 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); |
---|
| 2199 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, 0x12, |
---|
| 2200 | + ((*tmp16 & 0xFF9F) | 0x0040)); |
---|
| 2201 | + } |
---|
| 2202 | + |
---|
| 2203 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 2204 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); |
---|
| 2205 | + |
---|
| 2206 | + mii_nway_restart(&dev->mii); |
---|
| 2207 | + |
---|
| 2208 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 2209 | + 0, 0, 0, NULL); |
---|
| 2210 | + if (ret < 0) { |
---|
| 2211 | + deverr(dev, "Failed to write medium mode: %d", ret); |
---|
| 2212 | + goto err_out; |
---|
| 2213 | + } |
---|
| 2214 | + |
---|
| 2215 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, |
---|
| 2216 | + AX88772A_IPG0_DEFAULT | AX88772A_IPG1_DEFAULT << 8, |
---|
| 2217 | + AX88772A_IPG2_DEFAULT, 0, NULL); |
---|
| 2218 | + if (ret < 0) { |
---|
| 2219 | + deverr(dev, "Failed to write interframe gap: %d", ret); |
---|
| 2220 | + goto err_out; |
---|
| 2221 | + } |
---|
| 2222 | + |
---|
| 2223 | + memset(buf, 0, 4); |
---|
| 2224 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_IPG012, 0, 0, 3, buf); |
---|
| 2225 | + *((u8 *)buf + 3) = 0x00; |
---|
| 2226 | + if (ret < 0) { |
---|
| 2227 | + deverr(dev, "Failed to read IPG,IPG1,IPG2 failed: %d", ret); |
---|
| 2228 | + goto err_out; |
---|
| 2229 | + } else { |
---|
| 2230 | + __u32 tmp32 = *((u32*)buf); |
---|
| 2231 | + le32_to_cpus(&tmp32); |
---|
| 2232 | + if (tmp32 != (AX88772A_IPG2_DEFAULT << 16 | |
---|
| 2233 | + AX88772A_IPG1_DEFAULT << 8 | AX88772A_IPG0_DEFAULT)) { |
---|
| 2234 | + printk("Non-authentic ASIX product\nASIX does not support it\n"); |
---|
| 2235 | + ret = -ENODEV; |
---|
| 2236 | + goto err_out; |
---|
| 2237 | + } |
---|
| 2238 | + } |
---|
| 2239 | + |
---|
| 2240 | + dev->net->features |= NETIF_F_IP_CSUM; |
---|
| 2241 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) |
---|
| 2242 | + dev->net->features |= NETIF_F_IPV6_CSUM; |
---|
| 2243 | +#endif |
---|
| 2244 | + |
---|
| 2245 | + ax772b_data->checksum = AX_RX_CHECKSUM | AX_TX_CHECKSUM; |
---|
| 2246 | + ret = ax88772b_set_csums(dev); |
---|
| 2247 | + if (ret < 0) { |
---|
| 2248 | + deverr(dev, "Write RX_COE/TX_COE failed: %d", ret); |
---|
| 2249 | + goto err_out; |
---|
| 2250 | + } |
---|
| 2251 | + |
---|
| 2252 | + dev->rx_size = bsize & 0x07; |
---|
| 2253 | + if (dev->udev->speed == USB_SPEED_HIGH) { |
---|
| 2254 | + |
---|
| 2255 | + ret = ax8817x_write_cmd(dev, 0x2A, |
---|
| 2256 | + AX88772B_BULKIN_SIZE[dev->rx_size].byte_cnt, |
---|
| 2257 | + AX88772B_BULKIN_SIZE[dev->rx_size].threshold, |
---|
| 2258 | + 0, NULL); |
---|
| 2259 | + if (ret < 0) { |
---|
| 2260 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 2261 | + goto err_out; |
---|
| 2262 | + } |
---|
| 2263 | + |
---|
| 2264 | + dev->rx_urb_size = AX88772B_BULKIN_SIZE[dev->rx_size].size; |
---|
| 2265 | + } else { |
---|
| 2266 | + ret = ax8817x_write_cmd(dev, 0x2A, |
---|
| 2267 | + 0x8000, 0x8001, 0, NULL); |
---|
| 2268 | + if (ret < 0) { |
---|
| 2269 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 2270 | + goto err_out; |
---|
| 2271 | + } |
---|
| 2272 | + dev->rx_urb_size = 2048; |
---|
| 2273 | + } |
---|
| 2274 | + |
---|
| 2275 | + /* Configure RX header type */ |
---|
| 2276 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 2277 | + (AX_RX_CTL_START | AX_RX_CTL_AB | AX_RX_HEADER_DEFAULT), |
---|
| 2278 | + 0, 0, NULL); |
---|
| 2279 | + if (ret < 0) { |
---|
| 2280 | + deverr(dev, "Reset RX_CTL failed: %d", ret); |
---|
| 2281 | + goto err_out; |
---|
| 2282 | + } |
---|
| 2283 | + |
---|
| 2284 | + /* Overwrite power saving configuration from eeprom */ |
---|
| 2285 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPRL | |
---|
| 2286 | + (ax772b_data->psc & 0x7FFF), 0, 0, NULL); |
---|
| 2287 | + |
---|
| 2288 | + if (ret < 0) { |
---|
| 2289 | + deverr(dev, "Failed to configure PHY power saving: %d", ret); |
---|
| 2290 | + goto err_out; |
---|
| 2291 | + } |
---|
| 2292 | + |
---|
| 2293 | + if (ax772b_data->OperationMode == OPERATION_PHY_MODE) |
---|
| 2294 | + netif_carrier_on(dev->net); |
---|
| 2295 | + |
---|
| 2296 | + kfree(buf); |
---|
| 2297 | + |
---|
| 2298 | + return ret; |
---|
| 2299 | +err_out: |
---|
| 2300 | + destroy_workqueue(ax772b_data->ax_work); |
---|
| 2301 | + kfree(buf); |
---|
| 2302 | + kfree(ax772b_data); |
---|
| 2303 | + return ret; |
---|
| 2304 | +} |
---|
| 2305 | + |
---|
| 2306 | +static int ax88772b_external_phyinit(struct usbnet *dev) { |
---|
| 2307 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 2308 | + u16 phyid1, phyid2; |
---|
| 2309 | + |
---|
| 2310 | + phyid1 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x02); |
---|
| 2311 | + phyid2 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x03); |
---|
| 2312 | + ax772b_data->ext_phy_oui = EXTPHY_ID_MASK_OUI(phyid1, phyid2); |
---|
| 2313 | + ax772b_data->ext_phy_model = EXTPHY_ID_MASK_MODEL(phyid2); |
---|
| 2314 | + |
---|
| 2315 | + if (ax772b_data->ext_phy_oui == EXTPHY_BROADCOM_OUI) { |
---|
| 2316 | + if(ax772b_data->ext_phy_model == EXTPHY_BCM89811_MODEL) { |
---|
| 2317 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x0, 0x8000); |
---|
| 2318 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2319 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2320 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2321 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2322 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2323 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2324 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1F, 0x0c00); |
---|
| 2325 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1E, 0x030A); |
---|
| 2326 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1F, 0x3440); |
---|
| 2327 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1E, 0x0166); |
---|
| 2328 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1F, 0x0020); |
---|
| 2329 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x012D); |
---|
| 2330 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x9B52); |
---|
| 2331 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x012E); |
---|
| 2332 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0xA04D); |
---|
| 2333 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0123); |
---|
| 2334 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x00c0); |
---|
| 2335 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0154); |
---|
| 2336 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x81C4); |
---|
| 2337 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0811); |
---|
| 2338 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x0000); |
---|
| 2339 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x01D3); |
---|
| 2340 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x0064); |
---|
| 2341 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x01C1); |
---|
| 2342 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0xA5F7); |
---|
| 2343 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0028); |
---|
| 2344 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x0400); |
---|
| 2345 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x001D); |
---|
| 2346 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x3411); |
---|
| 2347 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0820); |
---|
| 2348 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x0401); |
---|
| 2349 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x002F); |
---|
| 2350 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0xF167); |
---|
| 2351 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1e, 0x0045); |
---|
| 2352 | + ax88772b_mdio_write_le(dev->net, dev->mii.phy_id, 0x1f, 0x0500); |
---|
| 2353 | + return 0; |
---|
| 2354 | + } |
---|
| 2355 | + } |
---|
| 2356 | + |
---|
| 2357 | + return 0; |
---|
| 2358 | +} |
---|
| 2359 | + |
---|
| 2360 | +static void ax88772b_unbind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 2361 | +{ |
---|
| 2362 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 2363 | + |
---|
| 2364 | + if (ax772b_data) { |
---|
| 2365 | + |
---|
| 2366 | + flush_workqueue(ax772b_data->ax_work); |
---|
| 2367 | + destroy_workqueue(ax772b_data->ax_work); |
---|
| 2368 | + |
---|
| 2369 | + /* stop MAC operation */ |
---|
| 2370 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 2371 | + AX_RX_CTL_STOP, 0, 0, NULL); |
---|
| 2372 | + |
---|
| 2373 | + /* Power down PHY */ |
---|
| 2374 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 2375 | + AX_SWRESET_IPPD, 0, 0, NULL); |
---|
| 2376 | + |
---|
| 2377 | + kfree(ax772b_data); |
---|
| 2378 | + } |
---|
| 2379 | +} |
---|
| 2380 | + |
---|
| 2381 | +static int |
---|
| 2382 | +ax88178_media_check(struct usbnet *dev, struct ax88178_data *ax178dataptr) |
---|
| 2383 | +{ |
---|
| 2384 | + int fullduplex, i = 0; |
---|
| 2385 | + u16 tempshort = 0; |
---|
| 2386 | + u16 media; |
---|
| 2387 | + u16 advertise, lpa, result, stat1000, _lpa, _stat1000, delay = 5 * HZ; |
---|
| 2388 | + unsigned long jtimeout; |
---|
| 2389 | + |
---|
| 2390 | + jtimeout = jiffies + delay; |
---|
| 2391 | + do { |
---|
| 2392 | + _lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); |
---|
| 2393 | + _stat1000 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 2394 | + MII_STAT1000); |
---|
| 2395 | + |
---|
| 2396 | + lpa = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA); |
---|
| 2397 | + stat1000 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 2398 | + MII_STAT1000); |
---|
| 2399 | + |
---|
| 2400 | + if (time_after(jiffies, jtimeout)) |
---|
| 2401 | + break; |
---|
| 2402 | + |
---|
| 2403 | + } while ((_lpa != lpa) || (_stat1000 != stat1000) || i++ < 3); |
---|
| 2404 | + |
---|
| 2405 | + advertise = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 2406 | + MII_ADVERTISE); |
---|
| 2407 | + result = advertise & lpa; |
---|
| 2408 | + |
---|
| 2409 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2410 | + (ax178dataptr->LedMode == 1)) { |
---|
| 2411 | + tempshort = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 2412 | + MARVELL_MANUAL_LED) & 0xfc0f; |
---|
| 2413 | + } |
---|
| 2414 | + |
---|
| 2415 | + fullduplex = 1; |
---|
| 2416 | + if (stat1000 & LPA_1000FULL) { |
---|
| 2417 | + media = MEDIUM_GIGA_MODE | MEDIUM_FULL_DUPLEX_MODE | |
---|
| 2418 | + MEDIUM_ENABLE_125MHZ | MEDIUM_ENABLE_RECEIVE; |
---|
| 2419 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2420 | + (ax178dataptr->LedMode == 1)) |
---|
| 2421 | + tempshort |= 0x3e0; |
---|
| 2422 | + } else if (result & LPA_100FULL) { |
---|
| 2423 | + media = MEDIUM_FULL_DUPLEX_MODE | MEDIUM_ENABLE_RECEIVE | |
---|
| 2424 | + MEDIUM_MII_100M_MODE; |
---|
| 2425 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2426 | + (ax178dataptr->LedMode == 1)) |
---|
| 2427 | + tempshort |= 0x3b0; |
---|
| 2428 | + } else if (result & LPA_100HALF) { |
---|
| 2429 | + fullduplex = 0; |
---|
| 2430 | + media = MEDIUM_ENABLE_RECEIVE | MEDIUM_MII_100M_MODE; |
---|
| 2431 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2432 | + (ax178dataptr->LedMode == 1)) |
---|
| 2433 | + tempshort |= 0x3b0; |
---|
| 2434 | + } else if (result & LPA_10FULL) { |
---|
| 2435 | + media = MEDIUM_FULL_DUPLEX_MODE | MEDIUM_ENABLE_RECEIVE; |
---|
| 2436 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2437 | + (ax178dataptr->LedMode == 1)) |
---|
| 2438 | + tempshort |= 0x2f0; |
---|
| 2439 | + } else { |
---|
| 2440 | + media = MEDIUM_ENABLE_RECEIVE; |
---|
| 2441 | + fullduplex = 0; |
---|
| 2442 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2443 | + (ax178dataptr->LedMode == 1)) |
---|
| 2444 | + tempshort |= 0x02f0; |
---|
| 2445 | + } |
---|
| 2446 | + |
---|
| 2447 | + if ((ax178dataptr->PhyMode == PHY_MODE_MARVELL) && |
---|
| 2448 | + (ax178dataptr->LedMode == 1)) { |
---|
| 2449 | + ax8817x_mdio_write_le(dev->net, |
---|
| 2450 | + dev->mii.phy_id, MARVELL_MANUAL_LED, tempshort); |
---|
| 2451 | + } |
---|
| 2452 | + |
---|
| 2453 | + media |= 0x0004; |
---|
| 2454 | + if (ax178dataptr->UseRgmii) |
---|
| 2455 | + media |= 0x0008; |
---|
| 2456 | + if (fullduplex) { |
---|
| 2457 | + media |= 0x0020; /* ebable tx flow control as default; */ |
---|
| 2458 | + media |= 0x0010; /* ebable rx flow control as default; */ |
---|
| 2459 | + } |
---|
| 2460 | + |
---|
| 2461 | + return media; |
---|
| 2462 | +} |
---|
| 2463 | + |
---|
| 2464 | +static void Vitess_8601_Init(struct usbnet *dev, int state) |
---|
| 2465 | +{ |
---|
| 2466 | + u16 reg; |
---|
| 2467 | + |
---|
| 2468 | + switch (state) { |
---|
| 2469 | + case 0: /* tx, rx clock skew */ |
---|
| 2470 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, 31, 1); |
---|
| 2471 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, 28, 0); |
---|
| 2472 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, 31, 0); |
---|
| 2473 | + break; |
---|
| 2474 | + |
---|
| 2475 | + case 1: |
---|
| 2476 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2477 | + dev->mii.phy_id, 31, 0x52B5); |
---|
| 2478 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2479 | + dev->mii.phy_id, 18, 0x009E); |
---|
| 2480 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2481 | + dev->mii.phy_id, 17, 0xDD39); |
---|
| 2482 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2483 | + dev->mii.phy_id, 16, 0x87AA); |
---|
| 2484 | + |
---|
| 2485 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2486 | + dev->mii.phy_id, 16, 0xA7B4); |
---|
| 2487 | + |
---|
| 2488 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2489 | + dev->mii.phy_id, 18, |
---|
| 2490 | + ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2491 | + dev->mii.phy_id, 18)); |
---|
| 2492 | + |
---|
| 2493 | + reg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2494 | + dev->mii.phy_id, 17) & ~0x003f) | 0x003c; |
---|
| 2495 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2496 | + dev->mii.phy_id, 17, reg); |
---|
| 2497 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2498 | + dev->mii.phy_id, 16, 0x87B4); |
---|
| 2499 | + |
---|
| 2500 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2501 | + dev->mii.phy_id, 16, 0xa794); |
---|
| 2502 | + |
---|
| 2503 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2504 | + dev->mii.phy_id, 18, |
---|
| 2505 | + ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2506 | + dev->mii.phy_id, 18)); |
---|
| 2507 | + |
---|
| 2508 | + reg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2509 | + dev->mii.phy_id, 17) & ~0x003f) | 0x003e; |
---|
| 2510 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2511 | + dev->mii.phy_id, 17, reg); |
---|
| 2512 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2513 | + dev->mii.phy_id, 16, 0x8794); |
---|
| 2514 | + |
---|
| 2515 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2516 | + dev->mii.phy_id, 18, 0x00f7); |
---|
| 2517 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2518 | + dev->mii.phy_id, 17, 0xbe36); |
---|
| 2519 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2520 | + dev->mii.phy_id, 16, 0x879e); |
---|
| 2521 | + |
---|
| 2522 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2523 | + dev->mii.phy_id, 16, 0xa7a0); |
---|
| 2524 | + |
---|
| 2525 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2526 | + dev->mii.phy_id, 18, |
---|
| 2527 | + ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2528 | + dev->mii.phy_id, 18)); |
---|
| 2529 | + |
---|
| 2530 | + reg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2531 | + dev->mii.phy_id, 17) & ~0x003f) | 0x0034; |
---|
| 2532 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2533 | + dev->mii.phy_id, 17, reg); |
---|
| 2534 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2535 | + dev->mii.phy_id, 16, 0x87a0); |
---|
| 2536 | + |
---|
| 2537 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2538 | + dev->mii.phy_id, 18, 0x003c); |
---|
| 2539 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2540 | + dev->mii.phy_id, 17, 0xf3cf); |
---|
| 2541 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2542 | + dev->mii.phy_id, 16, 0x87a2); |
---|
| 2543 | + |
---|
| 2544 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2545 | + dev->mii.phy_id, 18, 0x003c); |
---|
| 2546 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2547 | + dev->mii.phy_id, 17, 0xf3cf); |
---|
| 2548 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2549 | + dev->mii.phy_id, 16, 0x87a4); |
---|
| 2550 | + |
---|
| 2551 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2552 | + dev->mii.phy_id, 18, 0x003c); |
---|
| 2553 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2554 | + dev->mii.phy_id, 17, 0xd287); |
---|
| 2555 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2556 | + dev->mii.phy_id, 16, 0x87a6); |
---|
| 2557 | + |
---|
| 2558 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2559 | + dev->mii.phy_id, 16, 0xa7a8); |
---|
| 2560 | + |
---|
| 2561 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2562 | + dev->mii.phy_id, 18, |
---|
| 2563 | + ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2564 | + dev->mii.phy_id, 18)); |
---|
| 2565 | + |
---|
| 2566 | + reg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2567 | + dev->mii.phy_id, 17) & ~0x0fff) | 0x0125; |
---|
| 2568 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2569 | + dev->mii.phy_id, 17, reg); |
---|
| 2570 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2571 | + dev->mii.phy_id, 16, 0x87a8); |
---|
| 2572 | + |
---|
| 2573 | + /* Enable Smart Pre-emphasis */ |
---|
| 2574 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2575 | + dev->mii.phy_id, 16, 0xa7fa); |
---|
| 2576 | + |
---|
| 2577 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2578 | + dev->mii.phy_id, 18, |
---|
| 2579 | + ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2580 | + dev->mii.phy_id, 18)); |
---|
| 2581 | + |
---|
| 2582 | + reg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2583 | + dev->mii.phy_id, 17) & ~0x0008) | 0x0008; |
---|
| 2584 | + |
---|
| 2585 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2586 | + dev->mii.phy_id, 17, reg); |
---|
| 2587 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2588 | + dev->mii.phy_id, 16, 0x87fa); |
---|
| 2589 | + |
---|
| 2590 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2591 | + dev->mii.phy_id, 31, 0); |
---|
| 2592 | + |
---|
| 2593 | + break; |
---|
| 2594 | + } |
---|
| 2595 | +} |
---|
| 2596 | + |
---|
| 2597 | +static void |
---|
| 2598 | +marvell_88E1510_magic_init(struct usbnet *dev) |
---|
| 2599 | +{ |
---|
| 2600 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2601 | + dev->mii.phy_id, 22, 0xff); |
---|
| 2602 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2603 | + dev->mii.phy_id, 17, 0x214b); |
---|
| 2604 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2605 | + dev->mii.phy_id, 16, 0x2144); |
---|
| 2606 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2607 | + dev->mii.phy_id, 17, 0x0c28); |
---|
| 2608 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2609 | + dev->mii.phy_id, 16, 0x2146); |
---|
| 2610 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2611 | + dev->mii.phy_id, 17, 0xb233); |
---|
| 2612 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2613 | + dev->mii.phy_id, 16, 0x214d); |
---|
| 2614 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2615 | + dev->mii.phy_id, 17, 0xcc0c); |
---|
| 2616 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2617 | + dev->mii.phy_id, 16, 0x2159); |
---|
| 2618 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2619 | + dev->mii.phy_id, 22, 0x00fb); |
---|
| 2620 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2621 | + dev->mii.phy_id, 7, 0xc00d); |
---|
| 2622 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2623 | + dev->mii.phy_id, 22, 0); |
---|
| 2624 | +} |
---|
| 2625 | + |
---|
| 2626 | +static int |
---|
| 2627 | +ax88178_phy_init(struct usbnet *dev, struct ax88178_data *ax178dataptr) |
---|
| 2628 | +{ |
---|
| 2629 | + int i; |
---|
| 2630 | + u16 phyanar, phyauxctrl, phyctrl, tempshort, phyid1; |
---|
| 2631 | + u16 phyreg = 0; |
---|
| 2632 | + |
---|
| 2633 | + /* Disable MII operation of AX88178 Hardware */ |
---|
| 2634 | + ax8817x_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); |
---|
| 2635 | + |
---|
| 2636 | + |
---|
| 2637 | + /* Read SROM - MiiPhy Address (ID) */ |
---|
| 2638 | + ax8817x_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, &dev->mii.phy_id); |
---|
| 2639 | + le32_to_cpus(&dev->mii.phy_id); |
---|
| 2640 | + |
---|
| 2641 | + /* Initialize MII structure */ |
---|
| 2642 | + dev->mii.phy_id >>= 8; |
---|
| 2643 | + dev->mii.phy_id &= PHY_ID_MASK; |
---|
| 2644 | + dev->mii.dev = dev->net; |
---|
| 2645 | + dev->mii.mdio_read = ax8817x_mdio_read_le; |
---|
| 2646 | + dev->mii.mdio_write = ax8817x_mdio_write_le; |
---|
| 2647 | + dev->mii.phy_id_mask = 0x3f; |
---|
| 2648 | + dev->mii.reg_num_mask = 0x1f; |
---|
| 2649 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 11) |
---|
| 2650 | + dev->mii.supports_gmii = 1; |
---|
| 2651 | +#endif |
---|
| 2652 | + |
---|
| 2653 | + if (ax178dataptr->PhyMode == PHY_MODE_MAC_TO_MAC_GMII) { |
---|
| 2654 | + ax178dataptr->UseRgmii = 0; |
---|
| 2655 | + ax178dataptr->MediaLink = MEDIUM_GIGA_MODE | |
---|
| 2656 | + MEDIUM_FULL_DUPLEX_MODE | |
---|
| 2657 | + MEDIUM_ENABLE_125MHZ | |
---|
| 2658 | + MEDIUM_ENABLE_RECEIVE | |
---|
| 2659 | + MEDIUM_ENABLE_RX_FLOWCTRL | |
---|
| 2660 | + MEDIUM_ENABLE_TX_FLOWCTRL; |
---|
| 2661 | + goto SKIPPHYSETTING; |
---|
| 2662 | + } |
---|
| 2663 | + |
---|
| 2664 | + /* test read phy register 2 */ |
---|
| 2665 | + if (!ax178dataptr->UseGpio0) { |
---|
| 2666 | + i = 1000; |
---|
| 2667 | + while (i--) { |
---|
| 2668 | + phyid1 = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2669 | + dev->mii.phy_id, GMII_PHY_OUI); |
---|
| 2670 | + if ((phyid1 == 0x000f) || (phyid1 == 0x0141) || |
---|
| 2671 | + (phyid1 == 0x0282) || (phyid1 == 0x004d) || |
---|
| 2672 | + (phyid1 == 0x0243) || (phyid1 == 0x001C) || |
---|
| 2673 | + (phyid1 == 0x0007)) |
---|
| 2674 | + break; |
---|
| 2675 | + msleep(5); |
---|
| 2676 | + } |
---|
| 2677 | + if (i < 0) |
---|
| 2678 | + return -EIO; |
---|
| 2679 | + } |
---|
| 2680 | + |
---|
| 2681 | + ax178dataptr->UseRgmii = 0; |
---|
| 2682 | + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { |
---|
| 2683 | + phyreg = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2684 | + dev->mii.phy_id, 27); |
---|
| 2685 | + if (!(phyreg & 4) && !(ax178dataptr->LedMode & 0x10)) { |
---|
| 2686 | + ax178dataptr->UseRgmii = 1; |
---|
| 2687 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2688 | + dev->mii.phy_id, 20, 0x82); |
---|
| 2689 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2690 | + } else if (ax178dataptr->LedMode & 0x10) { |
---|
| 2691 | + |
---|
| 2692 | + ax178dataptr->UseRgmii = 1; |
---|
| 2693 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2694 | + marvell_88E1510_magic_init(dev); |
---|
| 2695 | + |
---|
| 2696 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2697 | + dev->mii.phy_id, 22, 2); |
---|
| 2698 | + |
---|
| 2699 | + phyreg = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2700 | + dev->mii.phy_id, 21); |
---|
| 2701 | + |
---|
| 2702 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2703 | + dev->mii.phy_id, 21, phyreg | 0x30); |
---|
| 2704 | + |
---|
| 2705 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2706 | + dev->mii.phy_id, 22, 0); |
---|
| 2707 | + } |
---|
| 2708 | + } else if ((ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) || |
---|
| 2709 | + (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0_GMII)) { |
---|
| 2710 | + if (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) { |
---|
| 2711 | + ax178dataptr->UseRgmii = 1; |
---|
| 2712 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2713 | + } |
---|
| 2714 | + } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V1) { |
---|
| 2715 | + /* not Cameo */ |
---|
| 2716 | + if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode) { |
---|
| 2717 | + ax178dataptr->UseRgmii = 1; |
---|
| 2718 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2719 | + } |
---|
| 2720 | + |
---|
| 2721 | + for (i = 0; i < (sizeof(CICADA_FAMILY_HWINIT) / |
---|
| 2722 | + sizeof(CICADA_FAMILY_HWINIT[0])); i++) { |
---|
| 2723 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2724 | + dev->mii.phy_id, |
---|
| 2725 | + CICADA_FAMILY_HWINIT[i].offset, |
---|
| 2726 | + CICADA_FAMILY_HWINIT[i].value); |
---|
| 2727 | + } |
---|
| 2728 | + |
---|
| 2729 | + } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2) { |
---|
| 2730 | + /* not Cameo */ |
---|
| 2731 | + if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode) { |
---|
| 2732 | + ax178dataptr->UseRgmii = 1; |
---|
| 2733 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2734 | + } |
---|
| 2735 | + |
---|
| 2736 | + for (i = 0; i < (sizeof(CICADA_V2_HWINIT) / |
---|
| 2737 | + sizeof(CICADA_V2_HWINIT[0])); i++) { |
---|
| 2738 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2739 | + dev->mii.phy_id, CICADA_V2_HWINIT[i].offset, |
---|
| 2740 | + CICADA_V2_HWINIT[i].value); |
---|
| 2741 | + } |
---|
| 2742 | + } else if (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2_ASIX) { |
---|
| 2743 | + /* not Cameo */ |
---|
| 2744 | + if (!ax178dataptr->UseGpio0 || ax178dataptr->LedMode) { |
---|
| 2745 | + ax178dataptr->UseRgmii = 1; |
---|
| 2746 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2747 | + } |
---|
| 2748 | + |
---|
| 2749 | + for (i = 0; i < (sizeof(CICADA_V2_HWINIT) / |
---|
| 2750 | + sizeof(CICADA_V2_HWINIT[0])); i++) { |
---|
| 2751 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2752 | + dev->mii.phy_id, CICADA_V2_HWINIT[i].offset, |
---|
| 2753 | + CICADA_V2_HWINIT[i].value); |
---|
| 2754 | + } |
---|
| 2755 | + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211CL) { |
---|
| 2756 | + ax178dataptr->UseRgmii = 1; |
---|
| 2757 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2758 | + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211BN) { |
---|
| 2759 | + ax178dataptr->UseRgmii = 1; |
---|
| 2760 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2761 | + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8251CL) { |
---|
| 2762 | + ax178dataptr->UseRgmii = 1; |
---|
| 2763 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2764 | + } else if (ax178dataptr->PhyMode == PHY_MODE_VSC8601) { |
---|
| 2765 | + ax178dataptr->UseRgmii = 1; |
---|
| 2766 | + ax178dataptr->MediaLink |= MEDIUM_ENABLE_125MHZ; |
---|
| 2767 | + /* Vitess_8601_Init (dev, 0); */ |
---|
| 2768 | + } |
---|
| 2769 | + |
---|
| 2770 | + if (ax178dataptr->PhyMode != PHY_MODE_ATTANSIC_V0) { |
---|
| 2771 | + /* software reset */ |
---|
| 2772 | + ax8817x_swmii_mdio_write_le( |
---|
| 2773 | + dev->net, dev->mii.phy_id, GMII_PHY_CONTROL, |
---|
| 2774 | + ax8817x_swmii_mdio_read_le( |
---|
| 2775 | + dev->net, dev->mii.phy_id, GMII_PHY_CONTROL) |
---|
| 2776 | + | GMII_CONTROL_RESET); |
---|
| 2777 | + msleep(1); |
---|
| 2778 | + } |
---|
| 2779 | + |
---|
| 2780 | + if ((ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) || |
---|
| 2781 | + (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0_GMII)) { |
---|
| 2782 | + if (ax178dataptr->PhyMode == PHY_MODE_AGERE_V0) { |
---|
| 2783 | + i = 1000; |
---|
| 2784 | + while (i--) { |
---|
| 2785 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2786 | + dev->mii.phy_id, 21, 0x1001); |
---|
| 2787 | + |
---|
| 2788 | + phyreg = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2789 | + dev->mii.phy_id, 21); |
---|
| 2790 | + if ((phyreg & 0xf00f) == 0x1001) |
---|
| 2791 | + break; |
---|
| 2792 | + } |
---|
| 2793 | + if (i < 0) |
---|
| 2794 | + return -EIO; |
---|
| 2795 | + } |
---|
| 2796 | + |
---|
| 2797 | + if (ax178dataptr->LedMode == 4) { |
---|
| 2798 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2799 | + dev->mii.phy_id, 28, 0x7417); |
---|
| 2800 | + } else if (ax178dataptr->LedMode == 9) { |
---|
| 2801 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2802 | + dev->mii.phy_id, 28, 0x7a10); |
---|
| 2803 | + } else if (ax178dataptr->LedMode == 10) { |
---|
| 2804 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2805 | + dev->mii.phy_id, 28, 0x7a13); |
---|
| 2806 | + } |
---|
| 2807 | + |
---|
| 2808 | + for (i = 0; i < (sizeof(AGERE_FAMILY_HWINIT) / |
---|
| 2809 | + sizeof(AGERE_FAMILY_HWINIT[0])); i++) { |
---|
| 2810 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2811 | + dev->mii.phy_id, AGERE_FAMILY_HWINIT[i].offset, |
---|
| 2812 | + AGERE_FAMILY_HWINIT[i].value); |
---|
| 2813 | + } |
---|
| 2814 | + } else if (ax178dataptr->PhyMode == PHY_MODE_RTL8211CL) { |
---|
| 2815 | + |
---|
| 2816 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2817 | + dev->mii.phy_id, 0x1f, 0x0005); |
---|
| 2818 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2819 | + dev->mii.phy_id, 0x0c, 0); |
---|
| 2820 | + |
---|
| 2821 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, 0x01, |
---|
| 2822 | + (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2823 | + dev->mii.phy_id, 0x01) | 0x0080)); |
---|
| 2824 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2825 | + dev->mii.phy_id, 0x1f, 0); |
---|
| 2826 | + |
---|
| 2827 | + if (ax178dataptr->LedMode == 12) { |
---|
| 2828 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2829 | + dev->mii.phy_id, 0x1f, 0x0002); |
---|
| 2830 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2831 | + dev->mii.phy_id, 0x1a, 0x00cb); |
---|
| 2832 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2833 | + dev->mii.phy_id, 0x1f, 0); |
---|
| 2834 | + } |
---|
| 2835 | + } else if (ax178dataptr->PhyMode == PHY_MODE_VSC8601) { |
---|
| 2836 | + Vitess_8601_Init(dev, 1); |
---|
| 2837 | + } |
---|
| 2838 | + |
---|
| 2839 | + /* read phy register 0 */ |
---|
| 2840 | + phyctrl = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2841 | + dev->mii.phy_id, GMII_PHY_CONTROL); |
---|
| 2842 | + tempshort = phyctrl; |
---|
| 2843 | + phyctrl &= ~(GMII_CONTROL_POWER_DOWN | GMII_CONTROL_ISOLATE); |
---|
| 2844 | + if (phyctrl != tempshort) { |
---|
| 2845 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2846 | + dev->mii.phy_id, GMII_PHY_CONTROL, phyctrl); |
---|
| 2847 | + } |
---|
| 2848 | + |
---|
| 2849 | + /* LED */ |
---|
| 2850 | + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { |
---|
| 2851 | + if (ax178dataptr->LedMode == 1) { |
---|
| 2852 | + |
---|
| 2853 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2854 | + dev->mii.phy_id, 24) & 0xf8ff) | (1 + 0x100); |
---|
| 2855 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2856 | + dev->mii.phy_id, 24, phyreg); |
---|
| 2857 | + phyreg = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2858 | + dev->mii.phy_id, 25) & 0xfc0f; |
---|
| 2859 | + } else if (ax178dataptr->LedMode == 2) { |
---|
| 2860 | + |
---|
| 2861 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2862 | + dev->mii.phy_id, 24) & 0xf886) | |
---|
| 2863 | + (1 + 0x10 + 0x300); |
---|
| 2864 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2865 | + dev->mii.phy_id, 24, phyreg); |
---|
| 2866 | + } else if (ax178dataptr->LedMode == 5) { |
---|
| 2867 | + |
---|
| 2868 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2869 | + dev->mii.phy_id, 24) & 0xf8be) | |
---|
| 2870 | + (1 + 0x40 + 0x300); |
---|
| 2871 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2872 | + dev->mii.phy_id, 24, phyreg); |
---|
| 2873 | + } else if (ax178dataptr->LedMode == 7) { |
---|
| 2874 | + |
---|
| 2875 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2876 | + dev->mii.phy_id, 24) & 0xf8ff) | |
---|
| 2877 | + (1 + 0x100); |
---|
| 2878 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2879 | + dev->mii.phy_id, 24, phyreg); |
---|
| 2880 | + |
---|
| 2881 | + } else if (ax178dataptr->LedMode == 8) { |
---|
| 2882 | + |
---|
| 2883 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2884 | + dev->mii.phy_id, 24) & 0xf8be) | |
---|
| 2885 | + (1 + 0x40 + 0x100); |
---|
| 2886 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2887 | + dev->mii.phy_id, 24, phyreg); |
---|
| 2888 | + |
---|
| 2889 | + } else if (ax178dataptr->LedMode == 11) { |
---|
| 2890 | + |
---|
| 2891 | + phyreg = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2892 | + dev->mii.phy_id, 24) & 0x4106; |
---|
| 2893 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2894 | + dev->mii.phy_id, 24, phyreg); |
---|
| 2895 | + } else if (ax178dataptr->LedMode == 0x10) { |
---|
| 2896 | + /* MARVEL 88e1510 use default led setting */ |
---|
| 2897 | + } |
---|
| 2898 | + |
---|
| 2899 | + } else if ((ax178dataptr->PhyMode == PHY_MODE_CICADA_V1) || |
---|
| 2900 | + (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2) || |
---|
| 2901 | + (ax178dataptr->PhyMode == PHY_MODE_CICADA_V2_ASIX)) { |
---|
| 2902 | + |
---|
| 2903 | + if (ax178dataptr->LedMode == 3) { |
---|
| 2904 | + |
---|
| 2905 | + phyreg = (ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2906 | + dev->mii.phy_id, 27) & 0xFCFF) | 0x0100; |
---|
| 2907 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2908 | + dev->mii.phy_id, 27, phyreg); |
---|
| 2909 | + } |
---|
| 2910 | + |
---|
| 2911 | + } |
---|
| 2912 | + |
---|
| 2913 | + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { |
---|
| 2914 | + if (ax178dataptr->LedMode == 1) |
---|
| 2915 | + phyreg |= 0x3f0; |
---|
| 2916 | + } |
---|
| 2917 | + |
---|
| 2918 | + phyanar = 1 | (GMII_ANAR_PAUSE | GMII_ANAR_100TXFD | GMII_ANAR_100TX | |
---|
| 2919 | + GMII_ANAR_10TFD | GMII_ANAR_10T | GMII_ANAR_ASYM_PAUSE); |
---|
| 2920 | + |
---|
| 2921 | + phyauxctrl = GMII_1000_AUX_CTRL_FD_CAPABLE; |
---|
| 2922 | + |
---|
| 2923 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2924 | + dev->mii.phy_id, GMII_PHY_ANAR, phyanar); |
---|
| 2925 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2926 | + dev->mii.phy_id, GMII_PHY_1000BT_CONTROL, phyauxctrl); |
---|
| 2927 | + |
---|
| 2928 | + if (ax178dataptr->PhyMode == PHY_MODE_VSC8601) { |
---|
| 2929 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 2930 | + 31, 0x52B5); |
---|
| 2931 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 2932 | + 16, 0xA7F8); |
---|
| 2933 | + |
---|
| 2934 | + tempshort = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2935 | + dev->mii.phy_id, 17) & (~0x0018); |
---|
| 2936 | + |
---|
| 2937 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 2938 | + 17, tempshort); |
---|
| 2939 | + |
---|
| 2940 | + tempshort = ax8817x_swmii_mdio_read_le(dev->net, |
---|
| 2941 | + dev->mii.phy_id, 18); |
---|
| 2942 | + |
---|
| 2943 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, 18, |
---|
| 2944 | + tempshort); |
---|
| 2945 | + |
---|
| 2946 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 2947 | + 16, 0x87F8); |
---|
| 2948 | + ax8817x_swmii_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 2949 | + 31, 0); |
---|
| 2950 | + } |
---|
| 2951 | + |
---|
| 2952 | + if (ax178dataptr->PhyMode == PHY_MODE_ATTANSIC_V0) { |
---|
| 2953 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2954 | + dev->mii.phy_id, GMII_PHY_CONTROL, 0x9000); |
---|
| 2955 | + |
---|
| 2956 | + } else { |
---|
| 2957 | + phyctrl &= ~GMII_CONTROL_LOOPBACK; |
---|
| 2958 | + phyctrl |= (GMII_CONTROL_ENABLE_AUTO | GMII_CONTROL_START_AUTO); |
---|
| 2959 | + |
---|
| 2960 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2961 | + dev->mii.phy_id, GMII_PHY_CONTROL, phyctrl); |
---|
| 2962 | + } |
---|
| 2963 | + |
---|
| 2964 | + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { |
---|
| 2965 | + if (ax178dataptr->LedMode == 1) |
---|
| 2966 | + ax8817x_swmii_mdio_write_le(dev->net, |
---|
| 2967 | + dev->mii.phy_id, 25, phyreg); |
---|
| 2968 | + } |
---|
| 2969 | + |
---|
| 2970 | +SKIPPHYSETTING: |
---|
| 2971 | + |
---|
| 2972 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 2973 | + ax178dataptr->MediaLink, 0, 0, NULL); |
---|
| 2974 | + |
---|
| 2975 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_IPG0, |
---|
| 2976 | + AX88772_IPG0_DEFAULT | (AX88772_IPG1_DEFAULT << 8), |
---|
| 2977 | + AX88772_IPG2_DEFAULT, 0, NULL); |
---|
| 2978 | + |
---|
| 2979 | + msleep(1); |
---|
| 2980 | + |
---|
| 2981 | + ax8817x_write_cmd(dev, AX_CMD_SET_HW_MII, 0, 0, 0, NULL); |
---|
| 2982 | + |
---|
| 2983 | + return 0; |
---|
| 2984 | +} |
---|
| 2985 | + |
---|
| 2986 | +static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 2987 | +{ |
---|
| 2988 | + int ret; |
---|
| 2989 | + void *buf; |
---|
| 2990 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 2991 | + struct ax88178_data *ax178dataptr = NULL; |
---|
| 2992 | + |
---|
| 2993 | + axusbnet_get_endpoints(dev, intf); |
---|
| 2994 | + |
---|
| 2995 | + buf = kmalloc(6, GFP_KERNEL); |
---|
| 2996 | + if (!buf) { |
---|
| 2997 | + deverr(dev, "Cannot allocate memory for buffer"); |
---|
| 2998 | + return -ENOMEM; |
---|
| 2999 | + } |
---|
| 3000 | + |
---|
| 3001 | + /* allocate 178 data */ |
---|
| 3002 | + ax178dataptr = kmalloc(sizeof(*ax178dataptr), GFP_KERNEL); |
---|
| 3003 | + if (!ax178dataptr) { |
---|
| 3004 | + deverr(dev, "Cannot allocate memory for AX88178 data"); |
---|
| 3005 | + ret = -ENOMEM; |
---|
| 3006 | + goto error_out; |
---|
| 3007 | + } |
---|
| 3008 | + memset(ax178dataptr, 0, sizeof(struct ax88178_data)); |
---|
| 3009 | + dev->priv = ax178dataptr; |
---|
| 3010 | + /* end of allocate 178 data */ |
---|
| 3011 | + |
---|
| 3012 | + /* Get the EEPROM data*/ |
---|
| 3013 | + ret = ax8817x_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, |
---|
| 3014 | + (void *)(&ax178dataptr->EepromData)); |
---|
| 3015 | + if (ret < 0) { |
---|
| 3016 | + deverr(dev, "read SROM address 17h failed: %d", ret); |
---|
| 3017 | + goto error_out; |
---|
| 3018 | + } |
---|
| 3019 | + le16_to_cpus(&ax178dataptr->EepromData); |
---|
| 3020 | + /* End of get EEPROM data */ |
---|
| 3021 | + |
---|
| 3022 | + if (ax178dataptr->EepromData == 0xffff) { |
---|
| 3023 | + ax178dataptr->PhyMode = PHY_MODE_MARVELL; |
---|
| 3024 | + ax178dataptr->LedMode = 0; |
---|
| 3025 | + ax178dataptr->UseGpio0 = 1; /* True */ |
---|
| 3026 | + } else { |
---|
| 3027 | + ax178dataptr->PhyMode = (u8)(ax178dataptr->EepromData & |
---|
| 3028 | + EEPROMMASK); |
---|
| 3029 | + ax178dataptr->LedMode = (u8)(ax178dataptr->EepromData >> 8); |
---|
| 3030 | + |
---|
| 3031 | + /* for buffalo new (use gpio2) */ |
---|
| 3032 | + if (ax178dataptr->LedMode == 6) |
---|
| 3033 | + ax178dataptr->LedMode = 1; |
---|
| 3034 | + else if (ax178dataptr->LedMode == 1) |
---|
| 3035 | + ax178dataptr->BuffaloOld = 1; |
---|
| 3036 | + |
---|
| 3037 | + |
---|
| 3038 | + if (ax178dataptr->EepromData & 0x80) |
---|
| 3039 | + ax178dataptr->UseGpio0 = 0; /* MARVEL se and other */ |
---|
| 3040 | + else |
---|
| 3041 | + ax178dataptr->UseGpio0 = 1; /* cameo */ |
---|
| 3042 | + } |
---|
| 3043 | + |
---|
| 3044 | + if (ax178dataptr->UseGpio0) { |
---|
| 3045 | + |
---|
| 3046 | + if (ax178dataptr->PhyMode == PHY_MODE_MARVELL) { |
---|
| 3047 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3048 | + AXGPIOS_GPO0EN | AXGPIOS_RSE, |
---|
| 3049 | + 0, 0, NULL); |
---|
| 3050 | + if (ret < 0) { |
---|
| 3051 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3052 | + goto error_out; |
---|
| 3053 | + } |
---|
| 3054 | + |
---|
| 3055 | + msleep(25); |
---|
| 3056 | + |
---|
| 3057 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3058 | + (AXGPIOS_GPO2 | AXGPIOS_GPO2EN | |
---|
| 3059 | + AXGPIOS_GPO0EN), 0, 0, NULL); |
---|
| 3060 | + if (ret < 0) { |
---|
| 3061 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3062 | + goto error_out; |
---|
| 3063 | + } |
---|
| 3064 | + |
---|
| 3065 | + msleep(15); |
---|
| 3066 | + |
---|
| 3067 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3068 | + AXGPIOS_GPO2EN | AXGPIOS_GPO0EN, |
---|
| 3069 | + 0, 0, NULL); |
---|
| 3070 | + if (ret < 0) { |
---|
| 3071 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3072 | + goto error_out; |
---|
| 3073 | + } |
---|
| 3074 | + |
---|
| 3075 | + msleep(245); |
---|
| 3076 | + |
---|
| 3077 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3078 | + (AXGPIOS_GPO2 | AXGPIOS_GPO2EN | |
---|
| 3079 | + AXGPIOS_GPO0EN), 0, 0, NULL); |
---|
| 3080 | + if (ret < 0) { |
---|
| 3081 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3082 | + goto error_out; |
---|
| 3083 | + } |
---|
| 3084 | + |
---|
| 3085 | + } else { /* vitesse */ |
---|
| 3086 | + |
---|
| 3087 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3088 | + (AXGPIOS_RSE | AXGPIOS_GPO0EN | |
---|
| 3089 | + AXGPIOS_GPO0), 0, 0, NULL); |
---|
| 3090 | + if (ret < 0) { |
---|
| 3091 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3092 | + goto error_out; |
---|
| 3093 | + } |
---|
| 3094 | + |
---|
| 3095 | + msleep(25); |
---|
| 3096 | + |
---|
| 3097 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3098 | + (AXGPIOS_GPO0EN | AXGPIOS_GPO0 | |
---|
| 3099 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), |
---|
| 3100 | + 0, 0, NULL); |
---|
| 3101 | + if (ret < 0) { |
---|
| 3102 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3103 | + goto error_out; |
---|
| 3104 | + } |
---|
| 3105 | + |
---|
| 3106 | + msleep(25); |
---|
| 3107 | + |
---|
| 3108 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3109 | + (AXGPIOS_GPO0EN | AXGPIOS_GPO0 | |
---|
| 3110 | + AXGPIOS_GPO2EN), 0, 0, NULL); |
---|
| 3111 | + if (ret < 0) { |
---|
| 3112 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3113 | + goto error_out; |
---|
| 3114 | + } |
---|
| 3115 | + |
---|
| 3116 | + msleep(245); |
---|
| 3117 | + |
---|
| 3118 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3119 | + (AXGPIOS_GPO0EN | AXGPIOS_GPO0 | |
---|
| 3120 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), |
---|
| 3121 | + 0, 0, NULL); |
---|
| 3122 | + if (ret < 0) { |
---|
| 3123 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3124 | + goto error_out; |
---|
| 3125 | + } |
---|
| 3126 | + } |
---|
| 3127 | + } else { /* use gpio1 */ |
---|
| 3128 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3129 | + (AXGPIOS_GPO1 | AXGPIOS_GPO1EN | |
---|
| 3130 | + AXGPIOS_RSE), 0, 0, NULL); |
---|
| 3131 | + if (ret < 0) { |
---|
| 3132 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3133 | + goto error_out; |
---|
| 3134 | + } |
---|
| 3135 | + |
---|
| 3136 | + if (ax178dataptr->BuffaloOld) { |
---|
| 3137 | + msleep(350); |
---|
| 3138 | + |
---|
| 3139 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3140 | + AXGPIOS_GPO1EN, 0, 0, NULL); |
---|
| 3141 | + if (ret < 0) { |
---|
| 3142 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3143 | + goto error_out; |
---|
| 3144 | + } |
---|
| 3145 | + |
---|
| 3146 | + msleep(350); |
---|
| 3147 | + |
---|
| 3148 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3149 | + AXGPIOS_GPO1EN | AXGPIOS_GPO1, |
---|
| 3150 | + 0, 0, NULL); |
---|
| 3151 | + if (ret < 0) { |
---|
| 3152 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3153 | + goto error_out; |
---|
| 3154 | + } |
---|
| 3155 | + } else { |
---|
| 3156 | + msleep(25); |
---|
| 3157 | + |
---|
| 3158 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3159 | + (AXGPIOS_GPO1EN | AXGPIOS_GPO1 | |
---|
| 3160 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), |
---|
| 3161 | + 0, 0, NULL); |
---|
| 3162 | + if (ret < 0) { |
---|
| 3163 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3164 | + goto error_out; |
---|
| 3165 | + } |
---|
| 3166 | + |
---|
| 3167 | + msleep(25); |
---|
| 3168 | + |
---|
| 3169 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3170 | + (AXGPIOS_GPO1EN | AXGPIOS_GPO1 | |
---|
| 3171 | + AXGPIOS_GPO2EN), 0, 0, NULL); |
---|
| 3172 | + if (ret < 0) { |
---|
| 3173 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3174 | + goto error_out; |
---|
| 3175 | + } |
---|
| 3176 | + |
---|
| 3177 | + msleep(245); |
---|
| 3178 | + |
---|
| 3179 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_GPIOS, |
---|
| 3180 | + (AXGPIOS_GPO1EN | AXGPIOS_GPO1 | |
---|
| 3181 | + AXGPIOS_GPO2EN | AXGPIOS_GPO2), |
---|
| 3182 | + 0, 0, NULL); |
---|
| 3183 | + if (ret < 0) { |
---|
| 3184 | + deverr(dev, "write GPIO failed: %d", ret); |
---|
| 3185 | + goto error_out; |
---|
| 3186 | + } |
---|
| 3187 | + } |
---|
| 3188 | + } |
---|
| 3189 | + |
---|
| 3190 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); |
---|
| 3191 | + if (ret < 0) { |
---|
| 3192 | + deverr(dev, "Select PHY failed: %d", ret); |
---|
| 3193 | + goto error_out; |
---|
| 3194 | + } |
---|
| 3195 | + |
---|
| 3196 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD | |
---|
| 3197 | + AX_SWRESET_PRL, 0, 0, NULL); |
---|
| 3198 | + if (ret < 0) { |
---|
| 3199 | + deverr(dev, "Issue sw reset failed: %d", ret); |
---|
| 3200 | + goto error_out; |
---|
| 3201 | + } |
---|
| 3202 | + |
---|
| 3203 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, 0, 0, 0, NULL); |
---|
| 3204 | + if (ret < 0) { |
---|
| 3205 | + deverr(dev, "Issue rx ctrl failed: %d", ret); |
---|
| 3206 | + goto error_out; |
---|
| 3207 | + } |
---|
| 3208 | + |
---|
| 3209 | + /* Get the MAC address */ |
---|
| 3210 | + memset(buf, 0, ETH_ALEN); |
---|
| 3211 | + ax8817x_get_mac(dev, buf); |
---|
| 3212 | + if (ret < 0) |
---|
| 3213 | + goto error_out; |
---|
| 3214 | + /* End of get MAC address */ |
---|
| 3215 | + |
---|
| 3216 | + ret = ax88178_phy_init(dev, ax178dataptr); |
---|
| 3217 | + if (ret < 0) |
---|
| 3218 | + goto error_out; |
---|
| 3219 | + |
---|
| 3220 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 3221 | + dev->net->do_ioctl = ax8817x_ioctl; |
---|
| 3222 | + dev->net->set_multicast_list = ax88178_set_multicast; |
---|
| 3223 | + dev->net->set_mac_address = ax8817x_set_mac_addr; |
---|
| 3224 | +#else |
---|
| 3225 | + dev->net->netdev_ops = &ax88178_netdev_ops; |
---|
| 3226 | +#endif |
---|
| 3227 | + dev->net->ethtool_ops = &ax8817x_ethtool_ops; |
---|
| 3228 | + |
---|
| 3229 | + /* Register suspend and resume functions */ |
---|
| 3230 | + data->suspend = ax88772_suspend; |
---|
| 3231 | + data->resume = ax88772_resume; |
---|
| 3232 | + |
---|
| 3233 | + if (dev->driver_info->flags & FLAG_FRAMING_AX) |
---|
| 3234 | + dev->rx_urb_size = 16384; |
---|
| 3235 | + |
---|
| 3236 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, (AX_RX_CTL_MFB | |
---|
| 3237 | + AX_RX_CTL_START | AX_RX_CTL_AB), 0, 0, NULL); |
---|
| 3238 | + if (ret < 0) { |
---|
| 3239 | + deverr(dev, "write RX ctrl reg failed: %d", ret); |
---|
| 3240 | + goto error_out; |
---|
| 3241 | + } |
---|
| 3242 | + |
---|
| 3243 | + kfree(buf); |
---|
| 3244 | + printk(version); |
---|
| 3245 | + return ret; |
---|
| 3246 | + |
---|
| 3247 | +error_out: |
---|
| 3248 | + kfree(ax178dataptr); |
---|
| 3249 | + kfree(buf); |
---|
| 3250 | + return ret; |
---|
| 3251 | +} |
---|
| 3252 | + |
---|
| 3253 | +static void ax88178_unbind(struct usbnet *dev, struct usb_interface *intf) |
---|
| 3254 | +{ |
---|
| 3255 | + struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv; |
---|
| 3256 | + |
---|
| 3257 | + if (ax178dataptr) { |
---|
| 3258 | + |
---|
| 3259 | + /* stop MAC operation */ |
---|
| 3260 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_RX_CTL, |
---|
| 3261 | + AX_RX_CTL_STOP, 0, 0, NULL); |
---|
| 3262 | + |
---|
| 3263 | + kfree(ax178dataptr); |
---|
| 3264 | + } |
---|
| 3265 | +} |
---|
| 3266 | + |
---|
| 3267 | +static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
---|
| 3268 | +{ |
---|
| 3269 | + u8 *head; |
---|
| 3270 | + u32 header; |
---|
| 3271 | + char *packet; |
---|
| 3272 | + struct sk_buff *ax_skb = NULL; |
---|
| 3273 | + u16 size; |
---|
| 3274 | + |
---|
| 3275 | + head = (u8 *) skb->data; |
---|
| 3276 | + memcpy(&header, head, sizeof(header)); |
---|
| 3277 | + le32_to_cpus(&header); |
---|
| 3278 | + packet = head + sizeof(header); |
---|
| 3279 | + |
---|
| 3280 | + skb_pull(skb, 4); |
---|
| 3281 | + |
---|
| 3282 | + while (skb->len > 0) { |
---|
| 3283 | + if ((short)(header & 0x00007ff) != |
---|
| 3284 | + ~((short)(((header & 0xffff0000) | 0xf8000000) >> 16))) { |
---|
| 3285 | + deverr(dev, "header length data is error 0x%08x, %d\n", |
---|
| 3286 | + header, skb->len); |
---|
| 3287 | + } |
---|
| 3288 | + /* get the packet length */ |
---|
| 3289 | + size = (u16) (header & 0x00007ff); |
---|
| 3290 | + |
---|
| 3291 | + if ((skb->len) - ((size + 1) & 0xfffe) == 0) { |
---|
| 3292 | + |
---|
| 3293 | + /* Make sure ip header is aligned on 32-bit boundary */ |
---|
| 3294 | + if (!((unsigned long)skb->data & 0x02)) { |
---|
| 3295 | + memmove(skb->data - 2, skb->data, size); |
---|
| 3296 | + skb->data -= 2; |
---|
| 3297 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3298 | + skb->tail = skb->data + size; |
---|
| 3299 | +#else |
---|
| 3300 | + skb_set_tail_pointer(skb, size); |
---|
| 3301 | +#endif |
---|
| 3302 | + } |
---|
| 3303 | + skb->truesize = size + sizeof(struct sk_buff); |
---|
| 3304 | + skb->len = size; |
---|
| 3305 | + |
---|
| 3306 | + return 2; |
---|
| 3307 | + } |
---|
| 3308 | + |
---|
| 3309 | + if (size > ETH_FRAME_LEN) { |
---|
| 3310 | + deverr(dev, "invalid rx length %d", size); |
---|
| 3311 | + return 0; |
---|
| 3312 | + } |
---|
| 3313 | +#ifndef RX_SKB_COPY |
---|
| 3314 | + ax_skb = skb_clone(skb, GFP_ATOMIC); |
---|
| 3315 | +#else |
---|
| 3316 | + ax_skb = alloc_skb(size + NET_IP_ALIGN, GFP_ATOMIC); |
---|
| 3317 | + skb_reserve(ax_skb, NET_IP_ALIGN); |
---|
| 3318 | +#endif |
---|
| 3319 | + if (ax_skb) { |
---|
| 3320 | +#ifndef RX_SKB_COPY |
---|
| 3321 | + /* Make sure ip header is aligned on 32-bit boundary */ |
---|
| 3322 | + if (!((unsigned long)packet & 0x02)) { |
---|
| 3323 | + memmove(packet - 2, packet, size); |
---|
| 3324 | + packet -= 2; |
---|
| 3325 | + } |
---|
| 3326 | + ax_skb->data = packet; |
---|
| 3327 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3328 | + ax_skb->tail = packet + size; |
---|
| 3329 | +#else |
---|
| 3330 | + skb_set_tail_pointer(ax_skb, size); |
---|
| 3331 | +#endif |
---|
| 3332 | + |
---|
| 3333 | +#else |
---|
| 3334 | + skb_put(ax_skb, size); |
---|
| 3335 | + memcpy(ax_skb->data, packet , size); |
---|
| 3336 | +#endif |
---|
| 3337 | + ax_skb->truesize = size + sizeof(struct sk_buff); |
---|
| 3338 | + axusbnet_skb_return(dev, ax_skb); |
---|
| 3339 | + |
---|
| 3340 | + } else { |
---|
| 3341 | + return 0; |
---|
| 3342 | + } |
---|
| 3343 | + |
---|
| 3344 | + skb_pull(skb, (size + 1) & 0xfffe); |
---|
| 3345 | + |
---|
| 3346 | + if (skb->len == 0) |
---|
| 3347 | + break; |
---|
| 3348 | + |
---|
| 3349 | + head = (u8 *) skb->data; |
---|
| 3350 | + memcpy(&header, head, sizeof(header)); |
---|
| 3351 | + le32_to_cpus(&header); |
---|
| 3352 | + packet = head + sizeof(header); |
---|
| 3353 | + skb_pull(skb, 4); |
---|
| 3354 | + } |
---|
| 3355 | + |
---|
| 3356 | + if (skb->len < 0) { |
---|
| 3357 | + deverr(dev, "invalid rx length %d", skb->len); |
---|
| 3358 | + return 0; |
---|
| 3359 | + } |
---|
| 3360 | + return 1; |
---|
| 3361 | +} |
---|
| 3362 | + |
---|
| 3363 | +static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb, |
---|
| 3364 | + gfp_t flags) |
---|
| 3365 | +{ |
---|
| 3366 | + int padlen = ((skb->len + 4) % 512) ? 0 : 4; |
---|
| 3367 | + u32 packet_len; |
---|
| 3368 | + u32 padbytes = 0xffff0000; |
---|
| 3369 | + |
---|
| 3370 | +#if (!AX_FORCE_BUFF_ALIGN) |
---|
| 3371 | + int headroom = skb_headroom(skb); |
---|
| 3372 | + int tailroom = skb_tailroom(skb); |
---|
| 3373 | + |
---|
| 3374 | + if ((!skb_cloned(skb)) |
---|
| 3375 | + && ((headroom + tailroom) >= (4 + padlen))) { |
---|
| 3376 | + if ((headroom < 4) || (tailroom < padlen)) { |
---|
| 3377 | + skb->data = memmove(skb->head + 4, skb->data, skb->len); |
---|
| 3378 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3379 | + skb->tail = skb->data + skb->len; |
---|
| 3380 | +#else |
---|
| 3381 | + skb_set_tail_pointer(skb, skb->len); |
---|
| 3382 | +#endif |
---|
| 3383 | + } |
---|
| 3384 | + } else |
---|
| 3385 | +#endif |
---|
| 3386 | + { |
---|
| 3387 | + struct sk_buff *skb2; |
---|
| 3388 | + skb2 = skb_copy_expand(skb, 4, padlen, flags); |
---|
| 3389 | + dev_kfree_skb_any(skb); |
---|
| 3390 | + skb = skb2; |
---|
| 3391 | + if (!skb) |
---|
| 3392 | + return NULL; |
---|
| 3393 | + } |
---|
| 3394 | + |
---|
| 3395 | + skb_push(skb, 4); |
---|
| 3396 | + packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); |
---|
| 3397 | + cpu_to_le32s(&packet_len); |
---|
| 3398 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3399 | + memcpy(skb->data, &packet_len, sizeof(packet_len)); |
---|
| 3400 | +#else |
---|
| 3401 | + skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); |
---|
| 3402 | +#endif |
---|
| 3403 | + |
---|
| 3404 | + if ((skb->len % 512) == 0) { |
---|
| 3405 | + cpu_to_le32s(&padbytes); |
---|
| 3406 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3407 | + memcpy(skb->tail, &padbytes, sizeof(padbytes)); |
---|
| 3408 | +#else |
---|
| 3409 | + memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); |
---|
| 3410 | +#endif |
---|
| 3411 | + skb_put(skb, sizeof(padbytes)); |
---|
| 3412 | + } |
---|
| 3413 | + return skb; |
---|
| 3414 | +} |
---|
| 3415 | + |
---|
| 3416 | +static void |
---|
| 3417 | +ax88772b_rx_checksum(struct sk_buff *skb, struct ax88772b_rx_header *rx_hdr) |
---|
| 3418 | +{ |
---|
| 3419 | + skb->ip_summed = CHECKSUM_NONE; |
---|
| 3420 | + |
---|
| 3421 | + /* checksum error bit is set */ |
---|
| 3422 | + if (rx_hdr->l3_csum_err || rx_hdr->l4_csum_err) |
---|
| 3423 | + return; |
---|
| 3424 | + |
---|
| 3425 | + /* It must be a TCP or UDP packet with a valid checksum */ |
---|
| 3426 | + if ((rx_hdr->l4_type == AX_RXHDR_L4_TYPE_TCP) || |
---|
| 3427 | + (rx_hdr->l4_type == AX_RXHDR_L4_TYPE_UDP)) { |
---|
| 3428 | + skb->ip_summed = CHECKSUM_UNNECESSARY; |
---|
| 3429 | + } |
---|
| 3430 | +} |
---|
| 3431 | + |
---|
| 3432 | +static int ax88772b_rx_fixup(struct usbnet *dev, struct sk_buff *skb) |
---|
| 3433 | +{ |
---|
| 3434 | + struct ax88772b_rx_header rx_hdr; |
---|
| 3435 | + struct sk_buff *ax_skb = NULL; |
---|
| 3436 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 3437 | + |
---|
| 3438 | + while (skb->len > 0) { |
---|
| 3439 | + |
---|
| 3440 | + le16_to_cpus((u16 *)skb->data); |
---|
| 3441 | + le16_to_cpus(((u16 *)skb->data) + 1); |
---|
| 3442 | + |
---|
| 3443 | + memcpy(&rx_hdr, skb->data, sizeof(struct ax88772b_rx_header)); |
---|
| 3444 | + |
---|
| 3445 | + if ((short)rx_hdr.len != (~((short)rx_hdr.len_bar) & 0x7FF)) |
---|
| 3446 | + return 0; |
---|
| 3447 | + |
---|
| 3448 | + if (rx_hdr.len > (ETH_FRAME_LEN + 4)) { |
---|
| 3449 | + deverr(dev, "invalid rx length %d", rx_hdr.len); |
---|
| 3450 | + return 0; |
---|
| 3451 | + } |
---|
| 3452 | + |
---|
| 3453 | + if (skb->len - ((rx_hdr.len + |
---|
| 3454 | + sizeof(struct ax88772b_rx_header) + 3) & |
---|
| 3455 | + 0xfffc) == 0) { |
---|
| 3456 | + skb_pull(skb, sizeof(struct ax88772b_rx_header)); |
---|
| 3457 | + skb->len = rx_hdr.len; |
---|
| 3458 | + |
---|
| 3459 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3460 | + skb->tail = skb->data + rx_hdr.len; |
---|
| 3461 | +#else |
---|
| 3462 | + skb_set_tail_pointer(skb, rx_hdr.len); |
---|
| 3463 | +#endif |
---|
| 3464 | + skb->truesize = rx_hdr.len + sizeof(struct sk_buff); |
---|
| 3465 | + |
---|
| 3466 | + if (ax772b_data->checksum & AX_RX_CHECKSUM) |
---|
| 3467 | + ax88772b_rx_checksum(skb, &rx_hdr); |
---|
| 3468 | + |
---|
| 3469 | + return 2; |
---|
| 3470 | + } |
---|
| 3471 | +#ifndef RX_SKB_COPY |
---|
| 3472 | + ax_skb = skb_clone(skb, GFP_ATOMIC); |
---|
| 3473 | +#else |
---|
| 3474 | + ax_skb = alloc_skb(rx_hdr.len + NET_IP_ALIGN, GFP_ATOMIC); |
---|
| 3475 | + skb_reserve(ax_skb, NET_IP_ALIGN); |
---|
| 3476 | +#endif |
---|
| 3477 | + if (ax_skb) { |
---|
| 3478 | +#ifndef RX_SKB_COPY |
---|
| 3479 | + ax_skb->len = rx_hdr.len; |
---|
| 3480 | + ax_skb->data = skb->data + |
---|
| 3481 | + sizeof(struct ax88772b_rx_header); |
---|
| 3482 | + |
---|
| 3483 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3484 | + ax_skb->tail = ax_skb->data + rx_hdr.len; |
---|
| 3485 | +#else |
---|
| 3486 | + skb_set_tail_pointer(ax_skb, rx_hdr.len); |
---|
| 3487 | +#endif |
---|
| 3488 | + |
---|
| 3489 | +#else |
---|
| 3490 | + skb_put(ax_skb, rx_hdr.len); |
---|
| 3491 | + memcpy(ax_skb->data, skb->data + sizeof(struct ax88772b_rx_header), rx_hdr.len); |
---|
| 3492 | +#endif |
---|
| 3493 | + |
---|
| 3494 | + ax_skb->truesize = rx_hdr.len + sizeof(struct sk_buff); |
---|
| 3495 | + |
---|
| 3496 | + if (ax772b_data->checksum & AX_RX_CHECKSUM) |
---|
| 3497 | + ax88772b_rx_checksum(ax_skb, &rx_hdr); |
---|
| 3498 | + |
---|
| 3499 | + axusbnet_skb_return(dev, ax_skb); |
---|
| 3500 | + |
---|
| 3501 | + } else { |
---|
| 3502 | + return 0; |
---|
| 3503 | + } |
---|
| 3504 | + |
---|
| 3505 | + skb_pull(skb, ((rx_hdr.len + |
---|
| 3506 | + sizeof(struct ax88772b_rx_header) + 3) |
---|
| 3507 | + & 0xfffc)); |
---|
| 3508 | + } |
---|
| 3509 | + |
---|
| 3510 | + if (skb->len < 0) { |
---|
| 3511 | + deverr(dev, "invalid rx length %d", skb->len); |
---|
| 3512 | + return 0; |
---|
| 3513 | + } |
---|
| 3514 | + return 1; |
---|
| 3515 | +} |
---|
| 3516 | + |
---|
| 3517 | +static struct sk_buff * |
---|
| 3518 | +ax88772b_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) |
---|
| 3519 | +{ |
---|
| 3520 | + int padlen = ((skb->len + 4) % 512) ? 0 : 4; |
---|
| 3521 | + u32 packet_len; |
---|
| 3522 | + u32 padbytes = 0xffff0000; |
---|
| 3523 | + |
---|
| 3524 | +#if (!AX_FORCE_BUFF_ALIGN) |
---|
| 3525 | + int headroom = skb_headroom(skb); |
---|
| 3526 | + int tailroom = skb_tailroom(skb); |
---|
| 3527 | + |
---|
| 3528 | + if ((!skb_cloned(skb)) |
---|
| 3529 | + && ((headroom + tailroom) >= (4 + padlen))) { |
---|
| 3530 | + if ((headroom < 4) || (tailroom < padlen)) { |
---|
| 3531 | + skb->data = memmove(skb->head + 4, skb->data, skb->len); |
---|
| 3532 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3533 | + skb->tail = skb->data + skb->len; |
---|
| 3534 | +#else |
---|
| 3535 | + skb_set_tail_pointer(skb, skb->len); |
---|
| 3536 | +#endif |
---|
| 3537 | + } |
---|
| 3538 | + } else |
---|
| 3539 | +#endif |
---|
| 3540 | + { |
---|
| 3541 | + struct sk_buff *skb2; |
---|
| 3542 | + skb2 = skb_copy_expand(skb, 4, padlen, flags); |
---|
| 3543 | + dev_kfree_skb_any(skb); |
---|
| 3544 | + skb = skb2; |
---|
| 3545 | + if (!skb) |
---|
| 3546 | + return NULL; |
---|
| 3547 | + } |
---|
| 3548 | + |
---|
| 3549 | + skb_push(skb, 4); |
---|
| 3550 | + packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); |
---|
| 3551 | + |
---|
| 3552 | + cpu_to_le32s(&packet_len); |
---|
| 3553 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3554 | + memcpy(skb->data, &packet_len, sizeof(packet_len)); |
---|
| 3555 | +#else |
---|
| 3556 | + skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); |
---|
| 3557 | +#endif |
---|
| 3558 | + |
---|
| 3559 | + if ((skb->len % 512) == 0) { |
---|
| 3560 | + cpu_to_le32s(&padbytes); |
---|
| 3561 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) |
---|
| 3562 | + memcpy(skb->tail, &padbytes, sizeof(padbytes)); |
---|
| 3563 | +#else |
---|
| 3564 | + memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); |
---|
| 3565 | +#endif |
---|
| 3566 | + skb_put(skb, sizeof(padbytes)); |
---|
| 3567 | + } |
---|
| 3568 | + |
---|
| 3569 | + return skb; |
---|
| 3570 | +} |
---|
| 3571 | + |
---|
| 3572 | +static const u8 chkcntsel[6][3] = { |
---|
| 3573 | + {12, 23, 31}, |
---|
| 3574 | + {12, 31, 23}, |
---|
| 3575 | + {23, 31, 12}, |
---|
| 3576 | + {23, 12, 31}, |
---|
| 3577 | + {31, 12, 23}, |
---|
| 3578 | + {31, 23, 12} |
---|
| 3579 | +}; |
---|
| 3580 | + |
---|
| 3581 | +static void ax88772_save_bmcr_anar(struct usbnet *dev) |
---|
| 3582 | +{ |
---|
| 3583 | + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; |
---|
| 3584 | + |
---|
| 3585 | + if (ax772_data) { |
---|
| 3586 | + /* Preserve BMCR for restoring */ |
---|
| 3587 | + ax772_data->presvd_phy_bmcr = |
---|
| 3588 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_BMCR); |
---|
| 3589 | + |
---|
| 3590 | + /* Preserve Advertisement control reg for restoring */ |
---|
| 3591 | + ax772_data->presvd_phy_advertise = |
---|
| 3592 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 3593 | + } |
---|
| 3594 | +} |
---|
| 3595 | + |
---|
| 3596 | +static void ax88772_restore_bmcr_anar(struct usbnet *dev) |
---|
| 3597 | +{ |
---|
| 3598 | + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; |
---|
| 3599 | + |
---|
| 3600 | + if (ax772_data && ax772_data->presvd_phy_advertise && ax772_data->presvd_phy_bmcr) { |
---|
| 3601 | + /* Restore Advertisement control reg */ |
---|
| 3602 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 3603 | + ax772_data->presvd_phy_advertise); |
---|
| 3604 | + /* Restore BMCR */ |
---|
| 3605 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, |
---|
| 3606 | + ax772_data->presvd_phy_bmcr); |
---|
| 3607 | + ax772_data->presvd_phy_advertise = 0; |
---|
| 3608 | + ax772_data->presvd_phy_bmcr = 0; |
---|
| 3609 | + } |
---|
| 3610 | +} |
---|
| 3611 | + |
---|
| 3612 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 3613 | +static void ax88772_link_reset(void *data) |
---|
| 3614 | +{ |
---|
| 3615 | + struct usbnet *dev = (struct usbnet *)data; |
---|
| 3616 | + struct ax88772_data *ax772_data = (struct ax88772_data *)dev->priv; |
---|
| 3617 | +#else |
---|
| 3618 | +static void ax88772_link_reset(struct work_struct *work) |
---|
| 3619 | +{ |
---|
| 3620 | + struct ax88772_data *ax772_data = container_of(work, |
---|
| 3621 | + struct ax88772_data, |
---|
| 3622 | + check_link); |
---|
| 3623 | + struct usbnet *dev = ax772_data->dev; |
---|
| 3624 | +#endif |
---|
| 3625 | + if (ax772_data->Event == AX_SET_RX_CFG) { |
---|
| 3626 | + u16 bmcr; |
---|
| 3627 | + u16 mode; |
---|
| 3628 | + |
---|
| 3629 | + ax772_data->Event = AX_NOP; |
---|
| 3630 | + |
---|
| 3631 | + mode = AX88772_MEDIUM_DEFAULT; |
---|
| 3632 | + |
---|
| 3633 | + bmcr = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 3634 | + MII_BMCR); |
---|
| 3635 | + if (!(bmcr & BMCR_FULLDPLX)) |
---|
| 3636 | + mode &= ~AX88772_MEDIUM_FULL_DUPLEX; |
---|
| 3637 | + if (!(bmcr & BMCR_SPEED100)) |
---|
| 3638 | + mode &= ~AX88772_MEDIUM_100MB; |
---|
| 3639 | + |
---|
| 3640 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, |
---|
| 3641 | + mode, 0, 0, NULL); |
---|
| 3642 | + return; |
---|
| 3643 | + } |
---|
| 3644 | + |
---|
| 3645 | + switch (ax772_data->Event) { |
---|
| 3646 | + case WAIT_AUTONEG_COMPLETE: |
---|
| 3647 | + if (jiffies > (ax772_data->autoneg_start + 5 * HZ)) { |
---|
| 3648 | + ax772_data->Event = PHY_POWER_DOWN; |
---|
| 3649 | + ax772_data->TickToExpire = 23; |
---|
| 3650 | + } |
---|
| 3651 | + break; |
---|
| 3652 | + case PHY_POWER_DOWN: |
---|
| 3653 | + if (ax772_data->TickToExpire == 23) { |
---|
| 3654 | + ax88772_save_bmcr_anar(dev); |
---|
| 3655 | + /* Set Phy Power Down */ |
---|
| 3656 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, AX_SWRESET_IPPD, |
---|
| 3657 | + 0, 0, NULL); |
---|
| 3658 | + --ax772_data->TickToExpire; |
---|
| 3659 | + } else if (--ax772_data->TickToExpire == 0) { |
---|
| 3660 | + /* Set Phy Power Up */ |
---|
| 3661 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3662 | + AX_SWRESET_IPRL, 0, 0, NULL); |
---|
| 3663 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3664 | + AX_SWRESET_IPPD | AX_SWRESET_IPRL, 0, 0, NULL); |
---|
| 3665 | + msleep(10); |
---|
| 3666 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3667 | + AX_SWRESET_IPRL, 0, 0, NULL); |
---|
| 3668 | + msleep(60); |
---|
| 3669 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3670 | + AX_SWRESET_CLEAR, 0, 0, NULL); |
---|
| 3671 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3672 | + AX_SWRESET_IPRL, 0, 0, NULL); |
---|
| 3673 | + |
---|
| 3674 | + if (ax772_data->presvd_phy_advertise && ax772_data->presvd_phy_bmcr) { |
---|
| 3675 | + ax88772_restore_bmcr_anar(dev); |
---|
| 3676 | + |
---|
| 3677 | + } else { |
---|
| 3678 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, |
---|
| 3679 | + MII_ADVERTISE, |
---|
| 3680 | + ADVERTISE_ALL | ADVERTISE_CSMA | |
---|
| 3681 | + ADVERTISE_PAUSE_CAP); |
---|
| 3682 | + mii_nway_restart(&dev->mii); |
---|
| 3683 | + } |
---|
| 3684 | + |
---|
| 3685 | + ax772_data->Event = PHY_POWER_UP; |
---|
| 3686 | + ax772_data->TickToExpire = 47; |
---|
| 3687 | + } |
---|
| 3688 | + break; |
---|
| 3689 | + case PHY_POWER_UP: |
---|
| 3690 | + if (--ax772_data->TickToExpire == 0) { |
---|
| 3691 | + ax772_data->Event = PHY_POWER_DOWN; |
---|
| 3692 | + ax772_data->TickToExpire = 23; |
---|
| 3693 | + } |
---|
| 3694 | + break; |
---|
| 3695 | + default: |
---|
| 3696 | + break; |
---|
| 3697 | + } |
---|
| 3698 | + return; |
---|
| 3699 | +} |
---|
| 3700 | + |
---|
| 3701 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 3702 | +static void ax88772a_link_reset(void *data) |
---|
| 3703 | +{ |
---|
| 3704 | + struct usbnet *dev = (struct usbnet *)data; |
---|
| 3705 | + struct ax88772a_data *ax772a_data = (struct ax88772a_data *)dev->priv; |
---|
| 3706 | +#else |
---|
| 3707 | +static void ax88772a_link_reset(struct work_struct *work) |
---|
| 3708 | +{ |
---|
| 3709 | + struct ax88772a_data *ax772a_data = container_of(work, |
---|
| 3710 | + struct ax88772a_data, |
---|
| 3711 | + check_link); |
---|
| 3712 | + struct usbnet *dev = ax772a_data->dev; |
---|
| 3713 | +#endif |
---|
| 3714 | + int powsave = (ax772a_data->EepromData >> 14); |
---|
| 3715 | + u16 phy_reg; |
---|
| 3716 | + |
---|
| 3717 | + if (ax772a_data->Event == AX_SET_RX_CFG) { |
---|
| 3718 | + u16 bmcr; |
---|
| 3719 | + u16 mode; |
---|
| 3720 | + |
---|
| 3721 | + ax772a_data->Event = AX_NOP; |
---|
| 3722 | + |
---|
| 3723 | + mode = AX88772_MEDIUM_DEFAULT; |
---|
| 3724 | + |
---|
| 3725 | + bmcr = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, |
---|
| 3726 | + MII_BMCR); |
---|
| 3727 | + if (!(bmcr & BMCR_FULLDPLX)) |
---|
| 3728 | + mode &= ~AX88772_MEDIUM_FULL_DUPLEX; |
---|
| 3729 | + if (!(bmcr & BMCR_SPEED100)) |
---|
| 3730 | + mode &= ~AX88772_MEDIUM_100MB; |
---|
| 3731 | + |
---|
| 3732 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, |
---|
| 3733 | + 0, 0, NULL); |
---|
| 3734 | + |
---|
| 3735 | + if (ax772a_data->presvd_phy_advertise && ax772a_data->presvd_phy_bmcr) { |
---|
| 3736 | + |
---|
| 3737 | + /* Restore Advertisement control reg */ |
---|
| 3738 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 3739 | + ax772a_data->presvd_phy_advertise); |
---|
| 3740 | + /* Restore BMCR */ |
---|
| 3741 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, |
---|
| 3742 | + ax772a_data->presvd_phy_bmcr); |
---|
| 3743 | + ax772a_data->presvd_phy_advertise = 0; |
---|
| 3744 | + ax772a_data->presvd_phy_bmcr = 0; |
---|
| 3745 | + } |
---|
| 3746 | + |
---|
| 3747 | + return; |
---|
| 3748 | + } |
---|
| 3749 | + |
---|
| 3750 | + switch (ax772a_data->Event) { |
---|
| 3751 | + case WAIT_AUTONEG_COMPLETE: |
---|
| 3752 | + if (jiffies > (ax772a_data->autoneg_start + 5 * HZ)) { |
---|
| 3753 | + ax772a_data->Event = CHK_CABLE_EXIST; |
---|
| 3754 | + ax772a_data->TickToExpire = 14; |
---|
| 3755 | + } |
---|
| 3756 | + break; |
---|
| 3757 | + case CHK_CABLE_EXIST: |
---|
| 3758 | + phy_reg = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); |
---|
| 3759 | + if ((phy_reg != 0x8012) && (phy_reg != 0x8013)) { |
---|
| 3760 | + ax8817x_mdio_write_le(dev->net, |
---|
| 3761 | + dev->mii.phy_id, 0x16, 0x4040); |
---|
| 3762 | + mii_nway_restart(&dev->mii); |
---|
| 3763 | + ax772a_data->Event = CHK_CABLE_STATUS; |
---|
| 3764 | + ax772a_data->TickToExpire = 31; |
---|
| 3765 | + } else if (--ax772a_data->TickToExpire == 0) { |
---|
| 3766 | + mii_nway_restart(&dev->mii); |
---|
| 3767 | + ax772a_data->Event = CHK_CABLE_EXIST_AGAIN; |
---|
| 3768 | + if (powsave == 0x03) { |
---|
| 3769 | + ax772a_data->TickToExpire = 47; |
---|
| 3770 | + } else if (powsave == 0x01) { |
---|
| 3771 | + ax772a_data->DlyIndex = (u8)(jiffies % 6); |
---|
| 3772 | + ax772a_data->DlySel = 0; |
---|
| 3773 | + ax772a_data->TickToExpire = |
---|
| 3774 | + chkcntsel[ax772a_data->DlyIndex][ax772a_data->DlySel]; |
---|
| 3775 | + } |
---|
| 3776 | + } |
---|
| 3777 | + break; |
---|
| 3778 | + case CHK_CABLE_EXIST_AGAIN: |
---|
| 3779 | + /* if cable disconnected */ |
---|
| 3780 | + phy_reg = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); |
---|
| 3781 | + if ((phy_reg != 0x8012) && (phy_reg != 0x8013)) { |
---|
| 3782 | + mii_nway_restart(&dev->mii); |
---|
| 3783 | + ax772a_data->Event = CHK_CABLE_STATUS; |
---|
| 3784 | + ax772a_data->TickToExpire = 31; |
---|
| 3785 | + } else if (--ax772a_data->TickToExpire == 0) { |
---|
| 3786 | + if (!ax772a_data->presvd_phy_advertise && !ax772a_data->presvd_phy_bmcr) { |
---|
| 3787 | + /* Preserve BMCR for restoring */ |
---|
| 3788 | + ax772a_data->presvd_phy_bmcr = |
---|
| 3789 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_BMCR); |
---|
| 3790 | + |
---|
| 3791 | + /* Preserve Advertisement control reg for restoring */ |
---|
| 3792 | + ax772a_data->presvd_phy_advertise = |
---|
| 3793 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 3794 | + } |
---|
| 3795 | + |
---|
| 3796 | + |
---|
| 3797 | + /* Power down PHY */ |
---|
| 3798 | + ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3799 | + AX_SWRESET_IPPD, |
---|
| 3800 | + 0, 0, NULL); |
---|
| 3801 | + ax772a_data->Event = PHY_POWER_DOWN; |
---|
| 3802 | + if (powsave == 0x03) |
---|
| 3803 | + ax772a_data->TickToExpire = 23; |
---|
| 3804 | + else if (powsave == 0x01) |
---|
| 3805 | + ax772a_data->TickToExpire = 31; |
---|
| 3806 | + } |
---|
| 3807 | + break; |
---|
| 3808 | + case PHY_POWER_DOWN: |
---|
| 3809 | + if (--ax772a_data->TickToExpire == 0) |
---|
| 3810 | + ax772a_data->Event = PHY_POWER_UP; |
---|
| 3811 | + break; |
---|
| 3812 | + case CHK_CABLE_STATUS: |
---|
| 3813 | + if (--ax772a_data->TickToExpire == 0) { |
---|
| 3814 | + ax8817x_mdio_write_le(dev->net, |
---|
| 3815 | + dev->mii.phy_id, 0x16, 0x4040); |
---|
| 3816 | + mii_nway_restart(&dev->mii); |
---|
| 3817 | + ax772a_data->Event = CHK_CABLE_EXIST_AGAIN; |
---|
| 3818 | + if (powsave == 0x03) { |
---|
| 3819 | + ax772a_data->TickToExpire = 47; |
---|
| 3820 | + } else if (powsave == 0x01) { |
---|
| 3821 | + ax772a_data->DlyIndex = (u8)(jiffies % 6); |
---|
| 3822 | + ax772a_data->DlySel = 0; |
---|
| 3823 | + ax772a_data->TickToExpire = |
---|
| 3824 | + chkcntsel[ax772a_data->DlyIndex][ax772a_data->DlySel]; |
---|
| 3825 | + } |
---|
| 3826 | + } |
---|
| 3827 | + break; |
---|
| 3828 | + case PHY_POWER_UP: |
---|
| 3829 | + |
---|
| 3830 | + if (!ax772a_data->presvd_phy_advertise && !ax772a_data->presvd_phy_bmcr) { |
---|
| 3831 | + /* Preserve BMCR for restoring */ |
---|
| 3832 | + ax772a_data->presvd_phy_bmcr = |
---|
| 3833 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_BMCR); |
---|
| 3834 | + |
---|
| 3835 | + /* Preserve Advertisement control reg for restoring */ |
---|
| 3836 | + ax772a_data->presvd_phy_advertise = |
---|
| 3837 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 3838 | + } |
---|
| 3839 | + |
---|
| 3840 | + ax88772a_phy_powerup(dev); |
---|
| 3841 | + |
---|
| 3842 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 3843 | + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); |
---|
| 3844 | + |
---|
| 3845 | + mii_nway_restart(&dev->mii); |
---|
| 3846 | + |
---|
| 3847 | + ax772a_data->Event = CHK_CABLE_EXIST_AGAIN; |
---|
| 3848 | + |
---|
| 3849 | + if (powsave == 0x03) { |
---|
| 3850 | + ax772a_data->TickToExpire = 47; |
---|
| 3851 | + } else if (powsave == 0x01) { |
---|
| 3852 | + if (++ax772a_data->DlySel >= 3) { |
---|
| 3853 | + ax772a_data->DlyIndex = (u8)(jiffies % 6); |
---|
| 3854 | + ax772a_data->DlySel = 0; |
---|
| 3855 | + } |
---|
| 3856 | + ax772a_data->TickToExpire = |
---|
| 3857 | + chkcntsel[ax772a_data->DlyIndex][ax772a_data->DlySel]; |
---|
| 3858 | + } |
---|
| 3859 | + break; |
---|
| 3860 | + default: |
---|
| 3861 | + break; |
---|
| 3862 | + } |
---|
| 3863 | + |
---|
| 3864 | + return; |
---|
| 3865 | +} |
---|
| 3866 | + |
---|
| 3867 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 3868 | +static void ax88772b_link_reset(void *data) |
---|
| 3869 | +{ |
---|
| 3870 | + struct usbnet *dev = (struct usbnet *)data; |
---|
| 3871 | + struct ax88772b_data *ax772b_data = (struct ax88772b_data *)dev->priv; |
---|
| 3872 | +#else |
---|
| 3873 | +static void ax88772b_link_reset(struct work_struct *work) |
---|
| 3874 | +{ |
---|
| 3875 | + struct ax88772b_data *ax772b_data = container_of(work, |
---|
| 3876 | + struct ax88772b_data, |
---|
| 3877 | + check_link); |
---|
| 3878 | + struct usbnet *dev = ax772b_data->dev; |
---|
| 3879 | +#endif |
---|
| 3880 | + |
---|
| 3881 | + switch (ax772b_data->Event) { |
---|
| 3882 | + |
---|
| 3883 | + case AX_SET_RX_CFG: |
---|
| 3884 | + { |
---|
| 3885 | + u16 bmcr = ax8817x_mdio_read_le(dev->net, |
---|
| 3886 | + dev->mii.phy_id, MII_BMCR); |
---|
| 3887 | + u16 mode = AX88772_MEDIUM_DEFAULT; |
---|
| 3888 | + |
---|
| 3889 | + if (!(bmcr & BMCR_FULLDPLX)) |
---|
| 3890 | + mode &= ~AX88772_MEDIUM_FULL_DUPLEX; |
---|
| 3891 | + if (!(bmcr & BMCR_SPEED100)) |
---|
| 3892 | + mode &= ~AX88772_MEDIUM_100MB; |
---|
| 3893 | + |
---|
| 3894 | + if (ax772b_data->ext_phy_oui == EXTPHY_BROADCOM_OUI) { |
---|
| 3895 | + if(ax772b_data->ext_phy_model == EXTPHY_BCM89811_MODEL) { |
---|
| 3896 | + mode = AX88772_MEDIUM_DEFAULT; |
---|
| 3897 | + } |
---|
| 3898 | + } |
---|
| 3899 | + |
---|
| 3900 | + ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, |
---|
| 3901 | + 0, 0, NULL); |
---|
| 3902 | + break; |
---|
| 3903 | + } |
---|
| 3904 | + case PHY_POWER_UP: |
---|
| 3905 | + { |
---|
| 3906 | + u16 tmp16; |
---|
| 3907 | + |
---|
| 3908 | + if (!ax772b_data->presvd_phy_advertise && !ax772b_data->presvd_phy_bmcr) { |
---|
| 3909 | + /* Preserve BMCR for restoring */ |
---|
| 3910 | + ax772b_data->presvd_phy_bmcr = |
---|
| 3911 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_BMCR); |
---|
| 3912 | + |
---|
| 3913 | + /* Preserve Advertisement control reg for restoring */ |
---|
| 3914 | + ax772b_data->presvd_phy_advertise = |
---|
| 3915 | + ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE); |
---|
| 3916 | + } |
---|
| 3917 | + |
---|
| 3918 | + ax88772a_phy_powerup(dev); |
---|
| 3919 | + tmp16 = ax8817x_mdio_read_le(dev->net, dev->mii.phy_id, 0x12); |
---|
| 3920 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, 0x12, |
---|
| 3921 | + ((tmp16 & 0xFF9F) | 0x0040)); |
---|
| 3922 | + |
---|
| 3923 | + /* Restore Advertisement control reg */ |
---|
| 3924 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE, |
---|
| 3925 | + ax772b_data->presvd_phy_advertise); |
---|
| 3926 | + /* Restore BMCR */ |
---|
| 3927 | + ax8817x_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, |
---|
| 3928 | + ax772b_data->presvd_phy_bmcr); |
---|
| 3929 | + ax772b_data->presvd_phy_advertise = 0; |
---|
| 3930 | + ax772b_data->presvd_phy_bmcr = 0; |
---|
| 3931 | + |
---|
| 3932 | + break; |
---|
| 3933 | + } |
---|
| 3934 | + |
---|
| 3935 | + case AX_CHK_AUTODETACH: |
---|
| 3936 | + { |
---|
| 3937 | + int ret; |
---|
| 3938 | + ret = ax8817x_write_cmd(dev, AX_CMD_SW_RESET, |
---|
| 3939 | + AX_SWRESET_IPRL | |
---|
| 3940 | + (ax772b_data->psc & 0x7FFF), |
---|
| 3941 | + 0, 0, NULL); |
---|
| 3942 | + if (ret < 0) { |
---|
| 3943 | + deverr(dev, "Failed to configure PHY power saving: %d", |
---|
| 3944 | + ret); |
---|
| 3945 | + } |
---|
| 3946 | + |
---|
| 3947 | + break; |
---|
| 3948 | + } |
---|
| 3949 | + default: |
---|
| 3950 | + break; |
---|
| 3951 | + } |
---|
| 3952 | + |
---|
| 3953 | + ax772b_data->Event = AX_NOP; |
---|
| 3954 | + |
---|
| 3955 | + return; |
---|
| 3956 | +} |
---|
| 3957 | + |
---|
| 3958 | +static int ax88178_set_media(struct usbnet *dev) |
---|
| 3959 | +{ |
---|
| 3960 | + int ret; |
---|
| 3961 | + struct ax88178_data *ax178dataptr = (struct ax88178_data *)dev->priv; |
---|
| 3962 | + int media; |
---|
| 3963 | + |
---|
| 3964 | + media = ax88178_media_check(dev, ax178dataptr); |
---|
| 3965 | + if (media < 0) |
---|
| 3966 | + return media; |
---|
| 3967 | + |
---|
| 3968 | + ret = ax8817x_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, media, 0, |
---|
| 3969 | + 0, NULL); |
---|
| 3970 | + if (ret < 0) { |
---|
| 3971 | + deverr(dev, "write mode medium reg failed: %d", ret); |
---|
| 3972 | + return ret; |
---|
| 3973 | + } |
---|
| 3974 | + |
---|
| 3975 | + return 0; |
---|
| 3976 | +} |
---|
| 3977 | + |
---|
| 3978 | +static int ax88178_link_reset(struct usbnet *dev) |
---|
| 3979 | +{ |
---|
| 3980 | + return ax88178_set_media(dev); |
---|
| 3981 | +} |
---|
| 3982 | + |
---|
| 3983 | +static int ax_suspend(struct usb_interface *intf, |
---|
| 3984 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) |
---|
| 3985 | + pm_message_t message) |
---|
| 3986 | +#else |
---|
| 3987 | + u32 message) |
---|
| 3988 | +#endif |
---|
| 3989 | +{ |
---|
| 3990 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 3991 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 3992 | + |
---|
| 3993 | + return data->suspend(intf, message); |
---|
| 3994 | +} |
---|
| 3995 | + |
---|
| 3996 | +static int ax_resume(struct usb_interface *intf) |
---|
| 3997 | +{ |
---|
| 3998 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 3999 | + struct ax8817x_data *data = (struct ax8817x_data *)&dev->data; |
---|
| 4000 | + |
---|
| 4001 | + return data->resume(intf); |
---|
| 4002 | +} |
---|
| 4003 | + |
---|
| 4004 | +static const struct driver_info ax88178_info = { |
---|
| 4005 | + .description = "", |
---|
| 4006 | +// .description = "ASIX AX88178 USB 2.0 Ethernet", |
---|
| 4007 | + .bind = ax88178_bind, |
---|
| 4008 | + .unbind = ax88178_unbind, |
---|
| 4009 | + .status = ax88178_status, |
---|
| 4010 | + .link_reset = ax88178_link_reset, |
---|
| 4011 | + .reset = ax88178_link_reset, |
---|
| 4012 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4013 | + .stop = ax88772b_stop, |
---|
| 4014 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS, |
---|
| 4015 | +#else |
---|
| 4016 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
---|
| 4017 | +#endif |
---|
| 4018 | + .rx_fixup = ax88772_rx_fixup, |
---|
| 4019 | + .tx_fixup = ax88772_tx_fixup, |
---|
| 4020 | +}; |
---|
| 4021 | + |
---|
| 4022 | +static const struct driver_info belkin178_info = { |
---|
| 4023 | + .description = "Belkin Gigabit USB 2.0 Network Adapter", |
---|
| 4024 | + .bind = ax88178_bind, |
---|
| 4025 | + .unbind = ax88178_unbind, |
---|
| 4026 | + .status = ax88178_status, |
---|
| 4027 | + .link_reset = ax88178_link_reset, |
---|
| 4028 | + .reset = ax88178_link_reset, |
---|
| 4029 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4030 | + .stop = ax88772b_stop, |
---|
| 4031 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS, |
---|
| 4032 | +#else |
---|
| 4033 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
---|
| 4034 | +#endif |
---|
| 4035 | + .rx_fixup = ax88772_rx_fixup, |
---|
| 4036 | + .tx_fixup = ax88772_tx_fixup, |
---|
| 4037 | +}; |
---|
| 4038 | + |
---|
| 4039 | +static const struct driver_info ax8817x_info = { |
---|
| 4040 | + .description = "", |
---|
| 4041 | +// .description = "ASIX AX8817x USB 2.0 Ethernet", |
---|
| 4042 | + .bind = ax8817x_bind, |
---|
| 4043 | + .status = ax8817x_status, |
---|
| 4044 | + .link_reset = ax88172_link_reset, |
---|
| 4045 | + .reset = ax88172_link_reset, |
---|
| 4046 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4047 | + .stop = ax88772b_stop, |
---|
| 4048 | + .flags = FLAG_ETHER | FLAG_AVOID_UNLINK_URBS, |
---|
| 4049 | +#else |
---|
| 4050 | + .flags = FLAG_ETHER, |
---|
| 4051 | +#endif |
---|
| 4052 | +}; |
---|
| 4053 | + |
---|
| 4054 | +static const struct driver_info dlink_dub_e100_info = { |
---|
| 4055 | + .description = "DLink DUB-E100 USB Ethernet", |
---|
| 4056 | + .bind = ax8817x_bind, |
---|
| 4057 | + .status = ax8817x_status, |
---|
| 4058 | + .link_reset = ax88172_link_reset, |
---|
| 4059 | + .reset = ax88172_link_reset, |
---|
| 4060 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4061 | + .stop = ax88772b_stop, |
---|
| 4062 | + .flags = FLAG_ETHER | FLAG_AVOID_UNLINK_URBS, |
---|
| 4063 | +#else |
---|
| 4064 | + .flags = FLAG_ETHER, |
---|
| 4065 | +#endif |
---|
| 4066 | +}; |
---|
| 4067 | + |
---|
| 4068 | +static const struct driver_info netgear_fa120_info = { |
---|
| 4069 | + .description = "Netgear FA-120 USB Ethernet", |
---|
| 4070 | + .bind = ax8817x_bind, |
---|
| 4071 | + .status = ax8817x_status, |
---|
| 4072 | + .link_reset = ax88172_link_reset, |
---|
| 4073 | + .reset = ax88172_link_reset, |
---|
| 4074 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4075 | + .stop = ax88772b_stop, |
---|
| 4076 | + .flags = FLAG_ETHER | FLAG_AVOID_UNLINK_URBS, |
---|
| 4077 | +#else |
---|
| 4078 | + .flags = FLAG_ETHER, |
---|
| 4079 | +#endif |
---|
| 4080 | +}; |
---|
| 4081 | + |
---|
| 4082 | +static const struct driver_info hawking_uf200_info = { |
---|
| 4083 | + .description = "Hawking UF200 USB Ethernet", |
---|
| 4084 | + .bind = ax8817x_bind, |
---|
| 4085 | + .status = ax8817x_status, |
---|
| 4086 | + .link_reset = ax88172_link_reset, |
---|
| 4087 | + .reset = ax88172_link_reset, |
---|
| 4088 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4089 | + .stop = ax88772b_stop, |
---|
| 4090 | + .flags = FLAG_ETHER | FLAG_AVOID_UNLINK_URBS, |
---|
| 4091 | +#else |
---|
| 4092 | + .flags = FLAG_ETHER, |
---|
| 4093 | +#endif |
---|
| 4094 | +}; |
---|
| 4095 | + |
---|
| 4096 | +static const struct driver_info ax88772_info = { |
---|
| 4097 | + .description = "", |
---|
| 4098 | +// .description = "ASIX AX88772 USB 2.0 Ethernet", |
---|
| 4099 | + .bind = ax88772_bind, |
---|
| 4100 | + .unbind = ax88772_unbind, |
---|
| 4101 | + .status = ax88772_status, |
---|
| 4102 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4103 | + .stop = ax88772b_stop, |
---|
| 4104 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS, |
---|
| 4105 | +#else |
---|
| 4106 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
---|
| 4107 | +#endif |
---|
| 4108 | + .rx_fixup = ax88772_rx_fixup, |
---|
| 4109 | + .tx_fixup = ax88772_tx_fixup, |
---|
| 4110 | + .reset = ax88772b_reset, |
---|
| 4111 | +}; |
---|
| 4112 | + |
---|
| 4113 | +static const struct driver_info dlink_dub_e100b_info = { |
---|
| 4114 | + .description = "D-Link DUB-E100 USB 2.0 Fast Ethernet Adapter", |
---|
| 4115 | + .bind = ax88772_bind, |
---|
| 4116 | + .unbind = ax88772_unbind, |
---|
| 4117 | + .status = ax88772_status, |
---|
| 4118 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4119 | + .stop = ax88772b_stop, |
---|
| 4120 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS, |
---|
| 4121 | +#else |
---|
| 4122 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
---|
| 4123 | +#endif |
---|
| 4124 | + .rx_fixup = ax88772_rx_fixup, |
---|
| 4125 | + .tx_fixup = ax88772_tx_fixup, |
---|
| 4126 | + .reset = ax88772b_reset, |
---|
| 4127 | +}; |
---|
| 4128 | + |
---|
| 4129 | +static const struct driver_info dlink_dub_e100_772b_info = { |
---|
| 4130 | + .description = "D-Link DUB-E100 USB 2.0 Fast Ethernet Adapter", |
---|
| 4131 | + .bind = ax88772b_bind, |
---|
| 4132 | + .unbind = ax88772b_unbind, |
---|
| 4133 | + .status = ax88772b_status, |
---|
| 4134 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4135 | + .stop = ax88772b_stop, |
---|
| 4136 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT | FLAG_AVOID_UNLINK_URBS, |
---|
| 4137 | +#else |
---|
| 4138 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT, |
---|
| 4139 | +#endif |
---|
| 4140 | + .rx_fixup = ax88772b_rx_fixup, |
---|
| 4141 | + .tx_fixup = ax88772b_tx_fixup, |
---|
| 4142 | + .reset = ax88772b_reset, |
---|
| 4143 | +}; |
---|
| 4144 | + |
---|
| 4145 | +static const struct driver_info dlink_dub_e100_772c_info = { |
---|
| 4146 | + .description = "D-Link DUB-E100 USB 2.0 Fast Ethernet Adapter", |
---|
| 4147 | + .bind = ax88772b_bind, |
---|
| 4148 | + .unbind = ax88772b_unbind, |
---|
| 4149 | + .status = ax88772b_status, |
---|
| 4150 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4151 | + .stop = ax88772b_stop, |
---|
| 4152 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT | FLAG_AVOID_UNLINK_URBS, |
---|
| 4153 | +#else |
---|
| 4154 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT, |
---|
| 4155 | +#endif |
---|
| 4156 | + .rx_fixup = ax88772b_rx_fixup, |
---|
| 4157 | + .tx_fixup = ax88772b_tx_fixup, |
---|
| 4158 | + .reset = ax88772b_reset, |
---|
| 4159 | +}; |
---|
| 4160 | + |
---|
| 4161 | +static const struct driver_info ax88772a_info = { |
---|
| 4162 | + .description = "", |
---|
| 4163 | +// .description = "ASIX AX88772A USB 2.0 Ethernet", |
---|
| 4164 | + .bind = ax88772a_bind, |
---|
| 4165 | + .unbind = ax88772a_unbind, |
---|
| 4166 | + .status = ax88772a_status, |
---|
| 4167 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4168 | + .stop = ax88772b_stop, |
---|
| 4169 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS, |
---|
| 4170 | +#else |
---|
| 4171 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX, |
---|
| 4172 | +#endif |
---|
| 4173 | + .rx_fixup = ax88772_rx_fixup, |
---|
| 4174 | + .tx_fixup = ax88772_tx_fixup, |
---|
| 4175 | + .reset = ax88772b_reset, |
---|
| 4176 | +}; |
---|
| 4177 | + |
---|
| 4178 | +static const struct driver_info ax88772b_info = { |
---|
| 4179 | + .description = "", |
---|
| 4180 | +// .description = "ASIX AX88772B USB 2.0 Ethernet", |
---|
| 4181 | + .bind = ax88772b_bind, |
---|
| 4182 | + .unbind = ax88772b_unbind, |
---|
| 4183 | + .status = ax88772b_status, |
---|
| 4184 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4185 | + .stop = ax88772b_stop, |
---|
| 4186 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT | FLAG_AVOID_UNLINK_URBS, |
---|
| 4187 | +#else |
---|
| 4188 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT, |
---|
| 4189 | +#endif |
---|
| 4190 | + .rx_fixup = ax88772b_rx_fixup, |
---|
| 4191 | + .tx_fixup = ax88772b_tx_fixup, |
---|
| 4192 | + .reset = ax88772b_reset, |
---|
| 4193 | +}; |
---|
| 4194 | + |
---|
| 4195 | +static const struct driver_info ax88772c_info = { |
---|
| 4196 | + .description = "", |
---|
| 4197 | +// .description = "ASIX AX88772C USB 2.0 Ethernet", |
---|
| 4198 | + .bind = ax88772b_bind, |
---|
| 4199 | + .unbind = ax88772b_unbind, |
---|
| 4200 | + .status = ax88772c_status, |
---|
| 4201 | +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
---|
| 4202 | + .stop = ax88772b_stop, |
---|
| 4203 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT | FLAG_AVOID_UNLINK_URBS, |
---|
| 4204 | +#else |
---|
| 4205 | + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_HW_IP_ALIGNMENT, |
---|
| 4206 | +#endif |
---|
| 4207 | + .rx_fixup = ax88772b_rx_fixup, |
---|
| 4208 | + .tx_fixup = ax88772b_tx_fixup, |
---|
| 4209 | + .reset = ax88772b_reset, |
---|
| 4210 | +}; |
---|
| 4211 | + |
---|
| 4212 | +static const struct usb_device_id products[] = { |
---|
| 4213 | +{ |
---|
| 4214 | + /* 88178 */ |
---|
| 4215 | + USB_DEVICE(0x0b95, 0x1780), |
---|
| 4216 | + .driver_info = (unsigned long) &ax88178_info, |
---|
| 4217 | +}, { |
---|
| 4218 | + /* 88178 for billianton linksys */ |
---|
| 4219 | + USB_DEVICE(0x077b, 0x2226), |
---|
| 4220 | + .driver_info = (unsigned long) &ax88178_info, |
---|
| 4221 | +}, { |
---|
| 4222 | + /* ABOCOM for linksys */ |
---|
| 4223 | + USB_DEVICE(0x1737, 0x0039), |
---|
| 4224 | + .driver_info = (unsigned long) &ax88178_info, |
---|
| 4225 | +}, { |
---|
| 4226 | + /* ABOCOM for pci */ |
---|
| 4227 | + USB_DEVICE(0x14ea, 0xab11), |
---|
| 4228 | + .driver_info = (unsigned long) &ax88178_info, |
---|
| 4229 | +}, { |
---|
| 4230 | + /* Belkin */ |
---|
| 4231 | + USB_DEVICE(0x050d, 0x5055), |
---|
| 4232 | + .driver_info = (unsigned long) &belkin178_info, |
---|
| 4233 | +}, { |
---|
| 4234 | + /* Linksys USB200M */ |
---|
| 4235 | + USB_DEVICE(0x077b, 0x2226), |
---|
| 4236 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4237 | +}, { |
---|
| 4238 | + /* Netgear FA120 */ |
---|
| 4239 | + USB_DEVICE(0x0846, 0x1040), |
---|
| 4240 | + .driver_info = (unsigned long) &netgear_fa120_info, |
---|
| 4241 | +}, { |
---|
| 4242 | + /* DLink DUB-E100 */ |
---|
| 4243 | + USB_DEVICE(0x2001, 0x1a00), |
---|
| 4244 | + .driver_info = (unsigned long) &dlink_dub_e100_info, |
---|
| 4245 | +}, { |
---|
| 4246 | + /* DLink DUB-E100B */ |
---|
| 4247 | + USB_DEVICE(0x2001, 0x3c05), |
---|
| 4248 | + .driver_info = (unsigned long) &dlink_dub_e100b_info, |
---|
| 4249 | +}, { |
---|
| 4250 | + /* DLink DUB-E100B */ |
---|
| 4251 | + USB_DEVICE(0x07d1, 0x3c05), |
---|
| 4252 | + .driver_info = (unsigned long) &dlink_dub_e100b_info, |
---|
| 4253 | +}, { |
---|
| 4254 | + /* DLink DUB-E100 (AX88772B)*/ |
---|
| 4255 | + USB_DEVICE_VER(0x2001, 0x1a02, 0, 1), |
---|
| 4256 | + .driver_info = (unsigned long) &dlink_dub_e100_772b_info, |
---|
| 4257 | +}, { |
---|
| 4258 | + /* DLink DUB-E100 (AX88772C)*/ |
---|
| 4259 | + USB_DEVICE_VER(0x2001, 0x1a02, 0, 2), |
---|
| 4260 | + .driver_info = (unsigned long) &dlink_dub_e100_772c_info, |
---|
| 4261 | +}, { |
---|
| 4262 | + /* Intellinet, ST Lab USB Ethernet */ |
---|
| 4263 | + USB_DEVICE(0x0b95, 0x1720), |
---|
| 4264 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4265 | +}, { |
---|
| 4266 | + /* Hawking UF200, TrendNet TU2-ET100 */ |
---|
| 4267 | + USB_DEVICE(0x07b8, 0x420a), |
---|
| 4268 | + .driver_info = (unsigned long) &hawking_uf200_info, |
---|
| 4269 | +}, { |
---|
| 4270 | + /* Billionton Systems, USB2AR */ |
---|
| 4271 | + USB_DEVICE(0x08dd, 0x90ff), |
---|
| 4272 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4273 | +}, { |
---|
| 4274 | + /* ATEN UC210T */ |
---|
| 4275 | + USB_DEVICE(0x0557, 0x2009), |
---|
| 4276 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4277 | +}, { |
---|
| 4278 | + /* Buffalo LUA-U2-KTX */ |
---|
| 4279 | + USB_DEVICE(0x0411, 0x003d), |
---|
| 4280 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4281 | +}, { |
---|
| 4282 | + /* Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" */ |
---|
| 4283 | + USB_DEVICE(0x6189, 0x182d), |
---|
| 4284 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4285 | +}, { |
---|
| 4286 | + /* corega FEther USB2-TX */ |
---|
| 4287 | + USB_DEVICE(0x07aa, 0x0017), |
---|
| 4288 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4289 | +}, { |
---|
| 4290 | + /* Surecom EP-1427X-2 */ |
---|
| 4291 | + USB_DEVICE(0x1189, 0x0893), |
---|
| 4292 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4293 | +}, { |
---|
| 4294 | + /* goodway corp usb gwusb2e */ |
---|
| 4295 | + USB_DEVICE(0x1631, 0x6200), |
---|
| 4296 | + .driver_info = (unsigned long) &ax8817x_info, |
---|
| 4297 | +}, { |
---|
| 4298 | + /* ASIX AX88772 10/100 */ |
---|
| 4299 | + USB_DEVICE(0x0b95, 0x7720), |
---|
| 4300 | + .driver_info = (unsigned long) &ax88772_info, |
---|
| 4301 | +}, { |
---|
| 4302 | + /* ASIX AX88772 10/100 */ |
---|
| 4303 | + USB_DEVICE(0x125E, 0x180D), |
---|
| 4304 | + .driver_info = (unsigned long) &ax88772_info, |
---|
| 4305 | +}, { |
---|
| 4306 | + /* ASIX AX88772A 10/100 */ |
---|
| 4307 | + USB_DEVICE(0x0b95, 0x772A), |
---|
| 4308 | + .driver_info = (unsigned long) &ax88772a_info, |
---|
| 4309 | +}, { |
---|
| 4310 | + /* ASIX AX88772A 10/100 */ |
---|
| 4311 | + USB_DEVICE(0x0db0, 0xA877), |
---|
| 4312 | + .driver_info = (unsigned long) &ax88772a_info, |
---|
| 4313 | +}, { |
---|
| 4314 | + /* ASIX AX88772A 10/100 */ |
---|
| 4315 | + USB_DEVICE(0x0421, 0x772A), |
---|
| 4316 | + .driver_info = (unsigned long) &ax88772a_info, |
---|
| 4317 | +}, { |
---|
| 4318 | + /* Linksys 200M */ |
---|
| 4319 | + USB_DEVICE(0x13B1, 0x0018), |
---|
| 4320 | + .driver_info = (unsigned long) &ax88772a_info, |
---|
| 4321 | +}, { |
---|
| 4322 | + USB_DEVICE(0x05ac, 0x1402), |
---|
| 4323 | + .driver_info = (unsigned long) &ax88772a_info, |
---|
| 4324 | +}, { |
---|
| 4325 | + /* ASIX AX88772B 10/100 */ |
---|
| 4326 | + USB_DEVICE_VER(0x0b95, 0x772B, 0, 1), |
---|
| 4327 | + .driver_info = (unsigned long) &ax88772b_info, |
---|
| 4328 | +}, { |
---|
| 4329 | + /* Asus AX88772B 10/100 */ |
---|
| 4330 | + USB_DEVICE_VER(0x0b95, 0x7e2b, 0, 1), |
---|
| 4331 | + .driver_info = (unsigned long) &ax88772b_info, |
---|
| 4332 | +}, { |
---|
| 4333 | + /* Lenovo AX88772B 10/100 */ |
---|
| 4334 | + USB_DEVICE_VER(0x17ef, 0x7203, 0, 1), |
---|
| 4335 | + .driver_info = (unsigned long) &ax88772b_info, |
---|
| 4336 | +},{ |
---|
| 4337 | + /* ASIX AX88772B ver.2 10/100 */ |
---|
| 4338 | + USB_DEVICE_VER(0x0b95, 0x772B, 0, 2), |
---|
| 4339 | + .driver_info = (unsigned long) &ax88772c_info, |
---|
| 4340 | +}, |
---|
| 4341 | + { }, /* END */ |
---|
| 4342 | +}; |
---|
| 4343 | +MODULE_DEVICE_TABLE(usb, products); |
---|
| 4344 | + |
---|
| 4345 | +static struct usb_driver asix_driver = { |
---|
| 4346 | + /* .owner = THIS_MODULE, */ |
---|
| 4347 | + .name = "asix", |
---|
| 4348 | + .id_table = products, |
---|
| 4349 | + .probe = axusbnet_probe, |
---|
| 4350 | + .suspend = ax_suspend, |
---|
| 4351 | + .resume = ax_resume, |
---|
| 4352 | + .disconnect = axusbnet_disconnect, |
---|
| 4353 | +}; |
---|
| 4354 | + |
---|
| 4355 | +static int __init asix_init(void) |
---|
| 4356 | +{ |
---|
| 4357 | + return usb_register(&asix_driver); |
---|
| 4358 | +} |
---|
| 4359 | +module_init(asix_init); |
---|
| 4360 | + |
---|
| 4361 | +static void __exit asix_exit(void) |
---|
| 4362 | +{ |
---|
| 4363 | + usb_deregister(&asix_driver); |
---|
| 4364 | +} |
---|
| 4365 | +module_exit(asix_exit); |
---|
| 4366 | + |
---|
| 4367 | +MODULE_AUTHOR(DRIVER_AUTHOR); |
---|
| 4368 | +MODULE_DESCRIPTION(DRIVER_DESCRIPTION); |
---|
| 4369 | +MODULE_LICENSE(DRIVER_LICENSE); |
---|
.. | .. |
---|
| 1 | +#ifndef __LINUX_USBNET_ASIX_H |
---|
| 2 | +#define __LINUX_USBNET_ASIX_H |
---|
| 3 | + |
---|
| 4 | +/* |
---|
| 5 | + * Turn on this flag if the implementation of your USB host controller |
---|
| 6 | + * cannot handle non-double word aligned buffer. |
---|
| 7 | + * When turn on this flag, driver will fixup egress packet aligned on double |
---|
| 8 | + * word boundary before deliver to USB host controller. And will Disable the |
---|
| 9 | + * function "skb_reserve (skb, NET_IP_ALIGN)" to retain the buffer aligned on |
---|
| 10 | + * double word alignment for ingress packets. |
---|
| 11 | + */ |
---|
| 12 | +#define AX_FORCE_BUFF_ALIGN 0 |
---|
| 13 | + |
---|
| 14 | +//#define RX_SKB_COPY |
---|
| 15 | + |
---|
| 16 | +#define AX_MONITOR_MODE 0x01 |
---|
| 17 | +#define AX_MONITOR_LINK 0x02 |
---|
| 18 | +#define AX_MONITOR_MAGIC 0x04 |
---|
| 19 | +#define AX_MONITOR_HSFS 0x10 |
---|
| 20 | + |
---|
| 21 | +/* AX88172 Medium Status Register values */ |
---|
| 22 | +#define AX_MEDIUM_FULL_DUPLEX 0x02 |
---|
| 23 | +#define AX_MEDIUM_TX_ABORT_ALLOW 0x04 |
---|
| 24 | +#define AX_MEDIUM_FLOW_CONTROL_EN 0x10 |
---|
| 25 | +#define AX_MCAST_FILTER_SIZE 8 |
---|
| 26 | +#define AX_MAX_MCAST 64 |
---|
| 27 | + |
---|
| 28 | +#define AX_EEPROM_LEN 0x40 |
---|
| 29 | + |
---|
| 30 | +#define AX_SWRESET_CLEAR 0x00 |
---|
| 31 | +#define AX_SWRESET_RR 0x01 |
---|
| 32 | +#define AX_SWRESET_RT 0x02 |
---|
| 33 | +#define AX_SWRESET_PRTE 0x04 |
---|
| 34 | +#define AX_SWRESET_PRL 0x08 |
---|
| 35 | +#define AX_SWRESET_BZ 0x10 |
---|
| 36 | +#define AX_SWRESET_IPRL 0x20 |
---|
| 37 | +#define AX_SWRESET_IPPD 0x40 |
---|
| 38 | +#define AX_SWRESET_IPOSC 0x0080 |
---|
| 39 | +#define AX_SWRESET_IPPSL_0 0x0100 |
---|
| 40 | +#define AX_SWRESET_IPPSL_1 0x0200 |
---|
| 41 | +#define AX_SWRESET_IPCOPS 0x0400 |
---|
| 42 | +#define AX_SWRESET_IPCOPSC 0x0800 |
---|
| 43 | +#define AX_SWRESET_AUTODETACH 0x1000 |
---|
| 44 | +#define AX_SWRESET_WOLLP 0x8000 |
---|
| 45 | + |
---|
| 46 | +#define AX88772_IPG0_DEFAULT 0x15 |
---|
| 47 | +#define AX88772_IPG1_DEFAULT 0x0c |
---|
| 48 | +#define AX88772_IPG2_DEFAULT 0x0E |
---|
| 49 | + |
---|
| 50 | +#define AX88772A_IPG0_DEFAULT 0x15 |
---|
| 51 | +#define AX88772A_IPG1_DEFAULT 0x16 |
---|
| 52 | +#define AX88772A_IPG2_DEFAULT 0x1A |
---|
| 53 | + |
---|
| 54 | +#define AX88772_MEDIUM_FULL_DUPLEX 0x0002 |
---|
| 55 | +#define AX88772_MEDIUM_RESERVED 0x0004 |
---|
| 56 | +#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010 |
---|
| 57 | +#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020 |
---|
| 58 | +#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080 |
---|
| 59 | +#define AX88772_MEDIUM_RX_ENABLE 0x0100 |
---|
| 60 | +#define AX88772_MEDIUM_100MB 0x0200 |
---|
| 61 | +#define AX88772_MEDIUM_DEFAULT \ |
---|
| 62 | + (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \ |
---|
| 63 | + AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \ |
---|
| 64 | + AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE) |
---|
| 65 | + |
---|
| 66 | +#define AX_CMD_SET_SW_MII 0x06 |
---|
| 67 | +#define AX_CMD_READ_MII_REG 0x07 |
---|
| 68 | +#define AX_CMD_WRITE_MII_REG 0x08 |
---|
| 69 | +#define AX_CMD_READ_STATMNGSTS_REG 0x09 |
---|
| 70 | + #define AX_HOST_EN 0x01 |
---|
| 71 | + |
---|
| 72 | +#define AX_CMD_SET_HW_MII 0x0a |
---|
| 73 | +#define AX_CMD_READ_EEPROM 0x0b |
---|
| 74 | +#define AX_CMD_WRITE_EEPROM 0x0c |
---|
| 75 | +#define AX_CMD_WRITE_EEPROM_EN 0x0d |
---|
| 76 | +#define AX_CMD_WRITE_EEPROM_DIS 0x0e |
---|
| 77 | +#define AX_CMD_WRITE_RX_CTL 0x10 |
---|
| 78 | +#define AX_CMD_READ_IPG012 0x11 |
---|
| 79 | +#define AX_CMD_WRITE_IPG0 0x12 |
---|
| 80 | +#define AX_CMD_WRITE_IPG1 0x13 |
---|
| 81 | +#define AX_CMD_WRITE_IPG2 0x14 |
---|
| 82 | +#define AX_CMD_WRITE_MULTI_FILTER 0x16 |
---|
| 83 | +#define AX_CMD_READ_NODE_ID 0x17 |
---|
| 84 | +#define AX_CMD_READ_PHY_ID 0x19 |
---|
| 85 | +#define AX_CMD_READ_MEDIUM_MODE 0x1a |
---|
| 86 | +#define AX_CMD_WRITE_MEDIUM_MODE 0x1b |
---|
| 87 | +#define AX_CMD_READ_MONITOR_MODE 0x1c |
---|
| 88 | +#define AX_CMD_WRITE_MONITOR_MODE 0x1d |
---|
| 89 | +#define AX_CMD_WRITE_GPIOS 0x1f |
---|
| 90 | +#define AX_CMD_SW_RESET 0x20 |
---|
| 91 | +#define AX_CMD_SW_PHY_STATUS 0x21 |
---|
| 92 | +#define AX_CMD_SW_PHY_SELECT 0x22 |
---|
| 93 | + #define AX_PHYSEL_PSEL (1 << 0) |
---|
| 94 | + #define AX_PHYSEL_ASEL (1 << 1) |
---|
| 95 | + #define AX_PHYSEL_SSMII (0 << 2) |
---|
| 96 | + #define AX_PHYSEL_SSRMII (1 << 2) |
---|
| 97 | + #define AX_PHYSEL_SSRRMII (3 << 2) |
---|
| 98 | + #define AX_PHYSEL_SSEN (1 << 4) |
---|
| 99 | +#define AX88772_CMD_READ_NODE_ID 0x13 |
---|
| 100 | +#define AX88772_CMD_WRITE_NODE_ID 0x14 |
---|
| 101 | +#define AX_CMD_READ_WKFARY 0x23 |
---|
| 102 | +#define AX_CMD_WRITE_WKFARY 0x24 |
---|
| 103 | +#define AX_CMD_READ_RXCOE_CTL 0x2b |
---|
| 104 | +#define AX_CMD_WRITE_RXCOE_CTL 0x2c |
---|
| 105 | +#define AX_CMD_READ_TXCOE_CTL 0x2d |
---|
| 106 | +#define AX_CMD_WRITE_TXCOE_CTL 0x2e |
---|
| 107 | + |
---|
| 108 | +#define REG_LENGTH 2 |
---|
| 109 | +#define PHY_ID_MASK 0x1f |
---|
| 110 | + |
---|
| 111 | +#define AX_RXCOE_IPCE 0x0001 |
---|
| 112 | +#define AX_RXCOE_IPVE 0x0002 |
---|
| 113 | +#define AX_RXCOE_V6VE 0x0004 |
---|
| 114 | +#define AX_RXCOE_TCPE 0x0008 |
---|
| 115 | +#define AX_RXCOE_UDPE 0x0010 |
---|
| 116 | +#define AX_RXCOE_ICMP 0x0020 |
---|
| 117 | +#define AX_RXCOE_IGMP 0x0040 |
---|
| 118 | +#define AX_RXCOE_ICV6 0x0080 |
---|
| 119 | +#define AX_RXCOE_TCPV6 0x0100 |
---|
| 120 | +#define AX_RXCOE_UDPV6 0x0200 |
---|
| 121 | +#define AX_RXCOE_ICMV6 0x0400 |
---|
| 122 | +#define AX_RXCOE_IGMV6 0x0800 |
---|
| 123 | +#define AX_RXCOE_ICV6V6 0x1000 |
---|
| 124 | +#define AX_RXCOE_FOPC 0x8000 |
---|
| 125 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) |
---|
| 126 | +#define AX_RXCOE_DEF_CSUM (AX_RXCOE_IPCE | AX_RXCOE_IPVE | \ |
---|
| 127 | + AX_RXCOE_V6VE | AX_RXCOE_TCPE | \ |
---|
| 128 | + AX_RXCOE_UDPE | AX_RXCOE_ICV6 | \ |
---|
| 129 | + AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6) |
---|
| 130 | +#else |
---|
| 131 | +#define AX_RXCOE_DEF_CSUM (AX_RXCOE_IPCE | AX_RXCOE_IPVE | \ |
---|
| 132 | + AX_RXCOE_TCPE | AX_RXCOE_UDPE) |
---|
| 133 | +#endif |
---|
| 134 | + |
---|
| 135 | +#define AX_RXCOE_64TE 0x0100 |
---|
| 136 | +#define AX_RXCOE_PPPOE 0x0200 |
---|
| 137 | +#define AX_RXCOE_RPCE 0x8000 |
---|
| 138 | + |
---|
| 139 | +#define AX_TXCOE_IP 0x0001 |
---|
| 140 | +#define AX_TXCOE_TCP 0x0002 |
---|
| 141 | +#define AX_TXCOE_UDP 0x0004 |
---|
| 142 | +#define AX_TXCOE_ICMP 0x0008 |
---|
| 143 | +#define AX_TXCOE_IGMP 0x0010 |
---|
| 144 | +#define AX_TXCOE_ICV6 0x0020 |
---|
| 145 | + |
---|
| 146 | +#define AX_TXCOE_TCPV6 0x0100 |
---|
| 147 | +#define AX_TXCOE_UDPV6 0x0200 |
---|
| 148 | +#define AX_TXCOE_ICMV6 0x0400 |
---|
| 149 | +#define AX_TXCOE_IGMV6 0x0800 |
---|
| 150 | +#define AX_TXCOE_ICV6V6 0x1000 |
---|
| 151 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22) |
---|
| 152 | +#define AX_TXCOE_DEF_CSUM (AX_TXCOE_TCP | AX_TXCOE_UDP | \ |
---|
| 153 | + AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6) |
---|
| 154 | +#else |
---|
| 155 | +#define AX_TXCOE_DEF_CSUM (AX_TXCOE_TCP | AX_TXCOE_UDP) |
---|
| 156 | +#endif |
---|
| 157 | + |
---|
| 158 | +#define AX_TXCOE_64TE 0x0001 |
---|
| 159 | +#define AX_TXCOE_PPPE 0x0002 |
---|
| 160 | + |
---|
| 161 | +#define AX88772B_MAX_BULKIN_2K 0 |
---|
| 162 | +#define AX88772B_MAX_BULKIN_4K 1 |
---|
| 163 | +#define AX88772B_MAX_BULKIN_6K 2 |
---|
| 164 | +#define AX88772B_MAX_BULKIN_8K 3 |
---|
| 165 | +#define AX88772B_MAX_BULKIN_16K 4 |
---|
| 166 | +#define AX88772B_MAX_BULKIN_20K 5 |
---|
| 167 | +#define AX88772B_MAX_BULKIN_24K 6 |
---|
| 168 | +#define AX88772B_MAX_BULKIN_32K 7 |
---|
| 169 | +struct {unsigned short size, byte_cnt, threshold; } AX88772B_BULKIN_SIZE[] = { |
---|
| 170 | + /* 2k */ |
---|
| 171 | + {2048, 0x8000, 0x8001}, |
---|
| 172 | + /* 4k */ |
---|
| 173 | + {4096, 0x8100, 0x8147}, |
---|
| 174 | + /* 6k */ |
---|
| 175 | + {6144, 0x8200, 0x81EB}, |
---|
| 176 | + /* 8k */ |
---|
| 177 | + {8192, 0x8300, 0x83D7}, |
---|
| 178 | + /* 16 */ |
---|
| 179 | + {16384, 0x8400, 0x851E}, |
---|
| 180 | + /* 20k */ |
---|
| 181 | + {20480, 0x8500, 0x8666}, |
---|
| 182 | + /* 24k */ |
---|
| 183 | + {24576, 0x8600, 0x87AE}, |
---|
| 184 | + /* 32k */ |
---|
| 185 | + {32768, 0x8700, 0x8A3D}, |
---|
| 186 | +}; |
---|
| 187 | + |
---|
| 188 | + |
---|
| 189 | +#define AX_RX_CTL_RH1M 0x0100 /* Enable RX-Header mode 0 */ |
---|
| 190 | +#define AX_RX_CTL_RH2M 0x0200 /* Enable IP header in receive buffer aligned on 32-bit aligment */ |
---|
| 191 | +#define AX_RX_CTL_RH3M 0x0400 /* checksum value in rx header 3 */ |
---|
| 192 | +#define AX_RX_HEADER_DEFAULT (AX_RX_CTL_RH1M | AX_RX_CTL_RH2M) |
---|
| 193 | + |
---|
| 194 | +#define AX_RX_CTL_MFB 0x0300 /* Maximum Frame size 16384bytes */ |
---|
| 195 | +#define AX_RX_CTL_START 0x0080 /* Ethernet MAC start */ |
---|
| 196 | +#define AX_RX_CTL_AP 0x0020 /* Accept physcial address from Multicast array */ |
---|
| 197 | +#define AX_RX_CTL_AM 0x0010 |
---|
| 198 | +#define AX_RX_CTL_AB 0x0008 /* Accetp Brocadcast frames*/ |
---|
| 199 | +#define AX_RX_CTL_SEP 0x0004 /* Save error packets */ |
---|
| 200 | +#define AX_RX_CTL_AMALL 0x0002 /* Accetp all multicast frames */ |
---|
| 201 | +#define AX_RX_CTL_PRO 0x0001 /* Promiscuous Mode */ |
---|
| 202 | +#define AX_RX_CTL_STOP 0x0000 /* Stop MAC */ |
---|
| 203 | + |
---|
| 204 | +#define AX_MONITOR_MODE 0x01 |
---|
| 205 | +#define AX_MONITOR_LINK 0x02 |
---|
| 206 | +#define AX_MONITOR_MAGIC 0x04 |
---|
| 207 | +#define AX_MONITOR_HSFS 0x10 |
---|
| 208 | + |
---|
| 209 | +#define AX_MCAST_FILTER_SIZE 8 |
---|
| 210 | +#define AX_MAX_MCAST 64 |
---|
| 211 | +#define AX_INTERRUPT_BUFSIZE 8 |
---|
| 212 | + |
---|
| 213 | +#define AX_EEPROM_LEN 0x40 |
---|
| 214 | +#define AX_EEPROM_MAGIC 0xdeadbeef |
---|
| 215 | +#define EEPROMMASK 0x7f |
---|
| 216 | + |
---|
| 217 | +/* GPIO REGISTER */ |
---|
| 218 | +#define AXGPIOS_GPO0EN 0X01 /* 1 << 0 */ |
---|
| 219 | +#define AXGPIOS_GPO0 0X02 /* 1 << 1 */ |
---|
| 220 | +#define AXGPIOS_GPO1EN 0X04 /* 1 << 2 */ |
---|
| 221 | +#define AXGPIOS_GPO1 0X08 /* 1 << 3 */ |
---|
| 222 | +#define AXGPIOS_GPO2EN 0X10 /* 1 << 4 */ |
---|
| 223 | +#define AXGPIOS_GPO2 0X20 /* 1 << 5 */ |
---|
| 224 | +#define AXGPIOS_RSE 0X80 /* 1 << 7 */ |
---|
| 225 | + |
---|
| 226 | +/* TX-header format */ |
---|
| 227 | +#define AX_TX_HDR_CPHI 0x4000 |
---|
| 228 | +#define AX_TX_HDR_DICF 0x8000 |
---|
| 229 | + |
---|
| 230 | +/* GMII register definitions */ |
---|
| 231 | +#define GMII_PHY_CONTROL 0x00 /* control reg */ |
---|
| 232 | +#define GMII_PHY_STATUS 0x01 /* status reg */ |
---|
| 233 | +#define GMII_PHY_OUI 0x02 /* most of the OUI bits */ |
---|
| 234 | +#define GMII_PHY_MODEL 0x03 /* model/rev bits, and rest of OUI */ |
---|
| 235 | +#define GMII_PHY_ANAR 0x04 /* AN advertisement reg */ |
---|
| 236 | +#define GMII_PHY_ANLPAR 0x05 /* AN Link Partner */ |
---|
| 237 | +#define GMII_PHY_ANER 0x06 /* AN expansion reg */ |
---|
| 238 | +#define GMII_PHY_1000BT_CONTROL 0x09 /* control reg for 1000BT */ |
---|
| 239 | +#define GMII_PHY_1000BT_STATUS 0x0A /* status reg for 1000BT */ |
---|
| 240 | + |
---|
| 241 | +/* Bit definitions: GMII Control */ |
---|
| 242 | +#define GMII_CONTROL_RESET 0x8000 /* reset bit in control reg */ |
---|
| 243 | +#define GMII_CONTROL_LOOPBACK 0x4000 /* loopback bit in control reg */ |
---|
| 244 | +#define GMII_CONTROL_10MB 0x0000 /* 10 Mbit */ |
---|
| 245 | +#define GMII_CONTROL_100MB 0x2000 /* 100Mbit */ |
---|
| 246 | +#define GMII_CONTROL_1000MB 0x0040 /* 1000Mbit */ |
---|
| 247 | +#define GMII_CONTROL_SPEED_BITS 0x2040 /* speed bit mask */ |
---|
| 248 | +#define GMII_CONTROL_ENABLE_AUTO 0x1000 /* autonegotiate enable */ |
---|
| 249 | +#define GMII_CONTROL_POWER_DOWN 0x0800 |
---|
| 250 | +#define GMII_CONTROL_ISOLATE 0x0400 /* islolate bit */ |
---|
| 251 | +#define GMII_CONTROL_START_AUTO 0x0200 /* restart autonegotiate */ |
---|
| 252 | +#define GMII_CONTROL_FULL_DUPLEX 0x0100 |
---|
| 253 | + |
---|
| 254 | +/* Bit definitions: GMII Status */ |
---|
| 255 | +#define GMII_STATUS_100MB_MASK 0xE000 /* any of these indicate 100 Mbit */ |
---|
| 256 | +#define GMII_STATUS_10MB_MASK 0x1800 /* either of these indicate 10 Mbit */ |
---|
| 257 | +#define GMII_STATUS_AUTO_DONE 0x0020 /* auto negotiation complete */ |
---|
| 258 | +#define GMII_STATUS_AUTO 0x0008 /* auto negotiation is available */ |
---|
| 259 | +#define GMII_STATUS_LINK_UP 0x0004 /* link status bit */ |
---|
| 260 | +#define GMII_STATUS_EXTENDED 0x0001 /* extended regs exist */ |
---|
| 261 | +#define GMII_STATUS_100T4 0x8000 /* capable of 100BT4 */ |
---|
| 262 | +#define GMII_STATUS_100TXFD 0x4000 /* capable of 100BTX full duplex */ |
---|
| 263 | +#define GMII_STATUS_100TX 0x2000 /* capable of 100BTX */ |
---|
| 264 | +#define GMII_STATUS_10TFD 0x1000 /* capable of 10BT full duplex */ |
---|
| 265 | +#define GMII_STATUS_10T 0x0800 /* capable of 10BT */ |
---|
| 266 | + |
---|
| 267 | +/* Bit definitions: Auto-Negotiation Advertisement */ |
---|
| 268 | +#define GMII_ANAR_ASYM_PAUSE 0x0800 /* support asymetric pause */ |
---|
| 269 | +#define GMII_ANAR_PAUSE 0x0400 /* support pause packets */ |
---|
| 270 | +#define GMII_ANAR_100T4 0x0200 /* support 100BT4 */ |
---|
| 271 | +#define GMII_ANAR_100TXFD 0x0100 /* support 100BTX full duplex */ |
---|
| 272 | +#define GMII_ANAR_100TX 0x0080 /* support 100BTX half duplex */ |
---|
| 273 | +#define GMII_ANAR_10TFD 0x0040 /* support 10BT full duplex */ |
---|
| 274 | +#define GMII_ANAR_10T 0x0020 /* support 10BT half duplex */ |
---|
| 275 | +#define GMII_SELECTOR_FIELD 0x001F /* selector field. */ |
---|
| 276 | + |
---|
| 277 | +/* Bit definitions: Auto-Negotiation Link Partner Ability */ |
---|
| 278 | +#define GMII_ANLPAR_100T4 0x0200 /* support 100BT4 */ |
---|
| 279 | +#define GMII_ANLPAR_100TXFD 0x0100 /* support 100BTX full duplex */ |
---|
| 280 | +#define GMII_ANLPAR_100TX 0x0080 /* support 100BTX half duplex */ |
---|
| 281 | +#define GMII_ANLPAR_10TFD 0x0040 /* support 10BT full duplex */ |
---|
| 282 | +#define GMII_ANLPAR_10T 0x0020 /* support 10BT half duplex */ |
---|
| 283 | +#define GMII_ANLPAR_PAUSE 0x0400 /* support pause packets */ |
---|
| 284 | +#define GMII_ANLPAR_ASYM_PAUSE 0x0800 /* support asymetric pause */ |
---|
| 285 | +#define GMII_ANLPAR_ACK 0x4000 /* means LCB was successfully rx'd */ |
---|
| 286 | +#define GMII_SELECTOR_8023 0x0001; |
---|
| 287 | + |
---|
| 288 | +/* Bit definitions: 1000BaseT AUX Control */ |
---|
| 289 | +#define GMII_1000_AUX_CTRL_MASTER_SLAVE 0x1000 |
---|
| 290 | +#define GMII_1000_AUX_CTRL_FD_CAPABLE 0x0200 /* full duplex capable */ |
---|
| 291 | +#define GMII_1000_AUX_CTRL_HD_CAPABLE 0x0100 /* half duplex capable */ |
---|
| 292 | + |
---|
| 293 | +/* Bit definitions: 1000BaseT AUX Status */ |
---|
| 294 | +#define GMII_1000_AUX_STATUS_FD_CAPABLE 0x0800 /* full duplex capable */ |
---|
| 295 | +#define GMII_1000_AUX_STATUS_HD_CAPABLE 0x0400 /* half duplex capable */ |
---|
| 296 | + |
---|
| 297 | +/* Cicada MII Registers */ |
---|
| 298 | +#define GMII_AUX_CTRL_STATUS 0x1C |
---|
| 299 | +#define GMII_AUX_ANEG_CPLT 0x8000 |
---|
| 300 | +#define GMII_AUX_FDX 0x0020 |
---|
| 301 | +#define GMII_AUX_SPEED_1000 0x0010 |
---|
| 302 | +#define GMII_AUX_SPEED_100 0x0008 |
---|
| 303 | + |
---|
| 304 | +#ifndef ADVERTISE_PAUSE_CAP |
---|
| 305 | +#define ADVERTISE_PAUSE_CAP 0x0400 |
---|
| 306 | +#endif |
---|
| 307 | + |
---|
| 308 | +#ifndef MII_STAT1000 |
---|
| 309 | +#define MII_STAT1000 0x000A |
---|
| 310 | +#endif |
---|
| 311 | + |
---|
| 312 | +#ifndef LPA_1000FULL |
---|
| 313 | +#define LPA_1000FULL 0x0800 |
---|
| 314 | +#endif |
---|
| 315 | + |
---|
| 316 | +/* medium mode register */ |
---|
| 317 | +#define MEDIUM_GIGA_MODE 0x0001 |
---|
| 318 | +#define MEDIUM_FULL_DUPLEX_MODE 0x0002 |
---|
| 319 | +#define MEDIUM_TX_ABORT_MODE 0x0004 |
---|
| 320 | +#define MEDIUM_ENABLE_125MHZ 0x0008 |
---|
| 321 | +#define MEDIUM_ENABLE_RX_FLOWCTRL 0x0010 |
---|
| 322 | +#define MEDIUM_ENABLE_TX_FLOWCTRL 0x0020 |
---|
| 323 | +#define MEDIUM_ENABLE_JUMBO_FRAME 0x0040 |
---|
| 324 | +#define MEDIUM_CHECK_PAUSE_FRAME_MODE 0x0080 |
---|
| 325 | +#define MEDIUM_ENABLE_RECEIVE 0x0100 |
---|
| 326 | +#define MEDIUM_MII_100M_MODE 0x0200 |
---|
| 327 | +#define MEDIUM_ENABLE_JAM_PATTERN 0x0400 |
---|
| 328 | +#define MEDIUM_ENABLE_STOP_BACKPRESSURE 0x0800 |
---|
| 329 | +#define MEDIUM_ENABLE_SUPPER_MAC_SUPPORT 0x1000 |
---|
| 330 | + |
---|
| 331 | +/* PHY mode */ |
---|
| 332 | +#define PHY_MODE_MARVELL 0 |
---|
| 333 | +#define PHY_MODE_CICADA_FAMILY 1 |
---|
| 334 | +#define PHY_MODE_CICADA_V1 1 |
---|
| 335 | +#define PHY_MODE_AGERE_FAMILY 2 |
---|
| 336 | +#define PHY_MODE_AGERE_V0 2 |
---|
| 337 | +#define PHY_MODE_CICADA_V2 5 |
---|
| 338 | +#define PHY_MODE_AGERE_V0_GMII 6 |
---|
| 339 | +#define PHY_MODE_CICADA_V2_ASIX 9 |
---|
| 340 | +#define PHY_MODE_VSC8601 10 |
---|
| 341 | +#define PHY_MODE_RTL8211CL 12 |
---|
| 342 | +#define PHY_MODE_RTL8211BN 13 |
---|
| 343 | +#define PHY_MODE_RTL8251CL 14 |
---|
| 344 | +#define PHY_MODE_ATTANSIC_V0 0x40 |
---|
| 345 | +#define PHY_MODE_ATTANSIC_FAMILY 0x40 |
---|
| 346 | +#define PHY_MODE_MAC_TO_MAC_GMII 0x7C |
---|
| 347 | + |
---|
| 348 | +/* */ |
---|
| 349 | +#define LED_MODE_MARVELL 0 |
---|
| 350 | +#define LED_MODE_CAMEO 1 |
---|
| 351 | + |
---|
| 352 | +#define MARVELL_LED_CTRL 0x18 |
---|
| 353 | +#define MARVELL_MANUAL_LED 0x19 |
---|
| 354 | + |
---|
| 355 | +#define PHY_IDENTIFIER 0x0002 |
---|
| 356 | +#define PHY_AGERE_IDENTIFIER 0x0282 |
---|
| 357 | +#define PHY_CICADA_IDENTIFIER 0x000f |
---|
| 358 | +#define PHY_MARVELL_IDENTIFIER 0x0141 |
---|
| 359 | + |
---|
| 360 | +#define PHY_MARVELL_STATUS 0x001b |
---|
| 361 | +#define MARVELL_STATUS_HWCFG 0x0004 /* SGMII without clock */ |
---|
| 362 | + |
---|
| 363 | +#define PHY_MARVELL_CTRL 0x0014 |
---|
| 364 | +#define MARVELL_CTRL_RXDELAY 0x0080 |
---|
| 365 | +#define MARVELL_CTRL_TXDELAY 0x0002 |
---|
| 366 | + |
---|
| 367 | +#define PHY_CICADA_EXTPAGE 0x001f |
---|
| 368 | +#define CICADA_EXTPAGE_EN 0x0001 |
---|
| 369 | +#define CICADA_EXTPAGE_DIS 0x0000 |
---|
| 370 | + |
---|
| 371 | +/* External ethernet phy */ |
---|
| 372 | +#define EXTPHY_ID_MASK_OUI(phyid1, phyid2) ((phyid1 << 6) | ((phyid2 & 0xFC00) >> 10)) |
---|
| 373 | +#define EXTPHY_ID_MASK_MODEL(phyid2) ((phyid2 & 0x3F0) >> 4) |
---|
| 374 | + |
---|
| 375 | +#define EXTPHY_BROADCOM_OUI 0x2B8094 |
---|
| 376 | +#define EXTPHY_BCM89811_MODEL 0x02 |
---|
| 377 | + |
---|
| 378 | +struct {unsigned short value, offset; } CICADA_FAMILY_HWINIT[] = { |
---|
| 379 | + {0x0001, 0x001f}, {0x1c25, 0x0017}, {0x2a30, 0x001f}, {0x234c, 0x0010}, |
---|
| 380 | + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0xa7fa, 0x0000}, |
---|
| 381 | + {0x0012, 0x0002}, {0x3002, 0x0001}, {0x87fa, 0x0000}, {0x52b5, 0x001f}, |
---|
| 382 | + {0xafac, 0x0000}, {0x000d, 0x0002}, {0x001c, 0x0001}, {0x8fac, 0x0000}, |
---|
| 383 | + {0x2a30, 0x001f}, {0x0012, 0x0008}, {0x2a30, 0x001f}, {0x0400, 0x0014}, |
---|
| 384 | + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0xa760, 0x0000}, |
---|
| 385 | + {0x0000, 0x0002}, {0xfaff, 0x0001}, {0x8760, 0x0000}, {0x52b5, 0x001f}, |
---|
| 386 | + {0xa760, 0x0000}, {0x0000, 0x0002}, {0xfaff, 0x0001}, {0x8760, 0x0000}, |
---|
| 387 | + {0x52b5, 0x001f}, {0xafae, 0x0000}, {0x0004, 0x0002}, {0x0671, 0x0001}, |
---|
| 388 | + {0x8fae, 0x0000}, {0x2a30, 0x001f}, {0x0012, 0x0008}, {0x0000, 0x001f}, |
---|
| 389 | +}; |
---|
| 390 | + |
---|
| 391 | +struct {unsigned short value, offset; } CICADA_V2_HWINIT[] = { |
---|
| 392 | + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0x000f, 0x0002}, |
---|
| 393 | + {0x472a, 0x0001}, {0x8fa4, 0x0000}, {0x2a30, 0x001f}, {0x0212, 0x0008}, |
---|
| 394 | + {0x0000, 0x001f}, |
---|
| 395 | +}; |
---|
| 396 | + |
---|
| 397 | +struct {unsigned short value, offset; } CICADA_V2_ASIX_HWINIT[] = { |
---|
| 398 | + {0x2a30, 0x001f}, {0x0212, 0x0008}, {0x52b5, 0x001f}, {0x0012, 0x0002}, |
---|
| 399 | + {0x3002, 0x0001}, {0x87fa, 0x0000}, {0x52b5, 0x001f}, {0x000f, 0x0002}, |
---|
| 400 | + {0x472a, 0x0001}, {0x8fa4, 0x0000}, {0x2a30, 0x001f}, {0x0212, 0x0008}, |
---|
| 401 | + {0x0000, 0x001f}, |
---|
| 402 | +}; |
---|
| 403 | + |
---|
| 404 | +struct {unsigned short value, offset; } AGERE_FAMILY_HWINIT[] = { |
---|
| 405 | + {0x0800, 0x0000}, {0x0007, 0x0012}, {0x8805, 0x0010}, {0xb03e, 0x0011}, |
---|
| 406 | + {0x8808, 0x0010}, {0xe110, 0x0011}, {0x8806, 0x0010}, {0xb03e, 0x0011}, |
---|
| 407 | + {0x8807, 0x0010}, {0xff00, 0x0011}, {0x880e, 0x0010}, {0xb4d3, 0x0011}, |
---|
| 408 | + {0x880f, 0x0010}, {0xb4d3, 0x0011}, {0x8810, 0x0010}, {0xb4d3, 0x0011}, |
---|
| 409 | + {0x8817, 0x0010}, {0x1c00, 0x0011}, {0x300d, 0x0010}, {0x0001, 0x0011}, |
---|
| 410 | + {0x0002, 0x0012}, |
---|
| 411 | +}; |
---|
| 412 | + |
---|
| 413 | +struct ax88178_data { |
---|
| 414 | + u16 EepromData; |
---|
| 415 | + u16 MediaLink; |
---|
| 416 | + int UseGpio0; |
---|
| 417 | + int UseRgmii; |
---|
| 418 | + u8 PhyMode; |
---|
| 419 | + u8 LedMode; |
---|
| 420 | + u8 BuffaloOld; |
---|
| 421 | +}; |
---|
| 422 | + |
---|
| 423 | +enum watchdog_state { |
---|
| 424 | + AX_NOP = 0, |
---|
| 425 | + CHK_LINK, /* Routine A */ |
---|
| 426 | + CHK_CABLE_EXIST, /* Called by A */ |
---|
| 427 | + CHK_CABLE_EXIST_AGAIN, /* Routine B */ |
---|
| 428 | + PHY_POWER_UP, /* Called by B */ |
---|
| 429 | + PHY_POWER_UP_BH, |
---|
| 430 | + PHY_POWER_DOWN, |
---|
| 431 | + CHK_CABLE_STATUS, /* Routine C */ |
---|
| 432 | + WAIT_AUTONEG_COMPLETE, |
---|
| 433 | + AX_SET_RX_CFG, |
---|
| 434 | + AX_CHK_AUTODETACH, |
---|
| 435 | +}; |
---|
| 436 | + |
---|
| 437 | +struct ax88772b_data { |
---|
| 438 | + struct usbnet *dev; |
---|
| 439 | + struct workqueue_struct *ax_work; |
---|
| 440 | + struct work_struct check_link; |
---|
| 441 | + unsigned long time_to_chk; |
---|
| 442 | + u16 psc; |
---|
| 443 | + u8 pw_enabled; |
---|
| 444 | + u8 Event; |
---|
| 445 | + u8 checksum; |
---|
| 446 | + u8 PhySelect:1; |
---|
| 447 | + u8 OperationMode:1; |
---|
| 448 | + u16 presvd_phy_advertise; |
---|
| 449 | + u16 presvd_phy_bmcr; |
---|
| 450 | + |
---|
| 451 | + u32 ext_phy_oui; |
---|
| 452 | + u8 ext_phy_model; |
---|
| 453 | +}; |
---|
| 454 | + |
---|
| 455 | +/* define for MAC or PHY mode */ |
---|
| 456 | +#define OPERATION_MAC_MODE 0 |
---|
| 457 | +#define OPERATION_PHY_MODE 1 |
---|
| 458 | + |
---|
| 459 | +struct ax88772a_data { |
---|
| 460 | + struct usbnet *dev; |
---|
| 461 | + struct workqueue_struct *ax_work; |
---|
| 462 | + struct work_struct check_link; |
---|
| 463 | + unsigned long autoneg_start; |
---|
| 464 | +#define AX88772B_WATCHDOG (6 * HZ) |
---|
| 465 | + u8 Event; |
---|
| 466 | + u8 TickToExpire; |
---|
| 467 | + u8 DlyIndex; |
---|
| 468 | + u8 DlySel; |
---|
| 469 | + u16 EepromData; |
---|
| 470 | + u16 presvd_phy_advertise; |
---|
| 471 | + u16 presvd_phy_bmcr; |
---|
| 472 | +}; |
---|
| 473 | + |
---|
| 474 | +struct ax88772_data { |
---|
| 475 | + struct usbnet *dev; |
---|
| 476 | + struct workqueue_struct *ax_work; |
---|
| 477 | + struct work_struct check_link; |
---|
| 478 | + unsigned long autoneg_start; |
---|
| 479 | + u8 Event; |
---|
| 480 | + u8 TickToExpire; |
---|
| 481 | + u16 presvd_phy_advertise; |
---|
| 482 | + u16 presvd_phy_bmcr; |
---|
| 483 | +}; |
---|
| 484 | + |
---|
| 485 | +#define AX_RX_CHECKSUM 1 |
---|
| 486 | +#define AX_TX_CHECKSUM 2 |
---|
| 487 | + |
---|
| 488 | +/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ |
---|
| 489 | +struct ax8817x_data { |
---|
| 490 | + u8 multi_filter[AX_MCAST_FILTER_SIZE]; |
---|
| 491 | + int (*resume) (struct usb_interface *intf); |
---|
| 492 | + int (*suspend) (struct usb_interface *intf, |
---|
| 493 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) |
---|
| 494 | + pm_message_t message); |
---|
| 495 | +#else |
---|
| 496 | + u32 message); |
---|
| 497 | +#endif |
---|
| 498 | +}; |
---|
| 499 | + |
---|
| 500 | +struct ax88172_int_data { |
---|
| 501 | + u16 res1; |
---|
| 502 | +#define AX_INT_PPLS_LINK (1 << 0) |
---|
| 503 | +#define AX_INT_SPLS_LINK (1 << 1) |
---|
| 504 | +#define AX_INT_CABOFF_UNPLUG (1 << 7) |
---|
| 505 | + u8 link; |
---|
| 506 | + u16 res2; |
---|
| 507 | + u8 status; |
---|
| 508 | + u16 res3; |
---|
| 509 | +} __attribute__ ((packed)); |
---|
| 510 | + |
---|
| 511 | +#define AX_RXHDR_L4_ERR (1 << 8) |
---|
| 512 | +#define AX_RXHDR_L3_ERR (1 << 9) |
---|
| 513 | + |
---|
| 514 | +#define AX_RXHDR_L4_TYPE_UDP 1 |
---|
| 515 | +#define AX_RXHDR_L4_TYPE_ICMP 2 |
---|
| 516 | +#define AX_RXHDR_L4_TYPE_IGMP 3 |
---|
| 517 | +#define AX_RXHDR_L4_TYPE_TCP 4 |
---|
| 518 | +#define AX_RXHDR_L4_TYPE_TCMPV6 5 |
---|
| 519 | +#define AX_RXHDR_L4_TYPE_MASK 7 |
---|
| 520 | + |
---|
| 521 | +#define AX_RXHDR_L3_TYPE_IP 1 |
---|
| 522 | +#define AX_RXHDR_L3_TYPE_IPV6 2 |
---|
| 523 | + |
---|
| 524 | +struct ax88772b_rx_header { |
---|
| 525 | +#if defined(__LITTLE_ENDIAN_BITFIELD) |
---|
| 526 | + u16 len:11, |
---|
| 527 | + res1:1, |
---|
| 528 | + crc:1, |
---|
| 529 | + mii:1, |
---|
| 530 | + runt:1, |
---|
| 531 | + mc_bc:1; |
---|
| 532 | + |
---|
| 533 | + u16 len_bar:11, |
---|
| 534 | + res2:5; |
---|
| 535 | + |
---|
| 536 | + u8 vlan_ind:3, |
---|
| 537 | + vlan_tag_striped:1, |
---|
| 538 | + pri:3, |
---|
| 539 | + res3:1; |
---|
| 540 | + |
---|
| 541 | + u8 l4_csum_err:1, |
---|
| 542 | + l3_csum_err:1, |
---|
| 543 | + l4_type:3, |
---|
| 544 | + l3_type:2, |
---|
| 545 | + ce:1; |
---|
| 546 | +#elif defined(__BIG_ENDIAN_BITFIELD) |
---|
| 547 | + u16 mc_bc:1, |
---|
| 548 | + runt:1, |
---|
| 549 | + mii:1, |
---|
| 550 | + crc:1, |
---|
| 551 | + res1:1, |
---|
| 552 | + len:11; |
---|
| 553 | + |
---|
| 554 | + u16 res2:5, |
---|
| 555 | + len_bar:11; |
---|
| 556 | + |
---|
| 557 | + u8 res3:1, |
---|
| 558 | + pri:3, |
---|
| 559 | + vlan_tag_striped:1, |
---|
| 560 | + vlan_ind:3; |
---|
| 561 | + |
---|
| 562 | + u8 ce:1, |
---|
| 563 | + l3_type:2, |
---|
| 564 | + l4_type:3, |
---|
| 565 | + l3_csum_err:1, |
---|
| 566 | + l4_csum_err:1; |
---|
| 567 | +#else |
---|
| 568 | +#error "Please fix <asm/byteorder.h>" |
---|
| 569 | +#endif |
---|
| 570 | + |
---|
| 571 | +} __attribute__ ((packed)); |
---|
| 572 | + |
---|
| 573 | + |
---|
| 574 | +#endif /* __LINUX_USBNET_ASIX_H */ |
---|
| 575 | + |
---|
.. | .. |
---|
| 1 | +/* |
---|
| 2 | + * USB Network driver infrastructure |
---|
| 3 | + * Copyright (C) 2000-2005 by David Brownell |
---|
| 4 | + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> |
---|
| 5 | + * |
---|
| 6 | + * This program is free software; you can redistribute it and/or modify |
---|
| 7 | + * it under the terms of the GNU General Public License as published by |
---|
| 8 | + * the Free Software Foundation; either version 2 of the License, or |
---|
| 9 | + * (at your option) any later version. |
---|
| 10 | + * |
---|
| 11 | + * This program is distributed in the hope that it will be useful, |
---|
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 14 | + * GNU General Public License for more details. |
---|
| 15 | + * |
---|
| 16 | + * You should have received a copy of the GNU General Public License |
---|
| 17 | + * along with this program; if not, write to the Free Software |
---|
| 18 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 19 | + */ |
---|
| 20 | + |
---|
| 21 | +/* |
---|
| 22 | + * This is a generic "USB networking" framework that works with several |
---|
| 23 | + * kinds of full and high speed networking devices: host-to-host cables, |
---|
| 24 | + * smart usb peripherals, and actual Ethernet adapters. |
---|
| 25 | + * |
---|
| 26 | + * These devices usually differ in terms of control protocols (if they |
---|
| 27 | + * even have one!) and sometimes they define new framing to wrap or batch |
---|
| 28 | + * Ethernet packets. Otherwise, they talk to USB pretty much the same, |
---|
| 29 | + * so interface (un)binding, endpoint I/O queues, fault handling, and other |
---|
| 30 | + * issues can usefully be addressed by this framework. |
---|
| 31 | + */ |
---|
| 32 | + |
---|
| 33 | +/* error path messages, extra info */ |
---|
| 34 | +#define DEBUG |
---|
| 35 | +/* more; success messages */ |
---|
| 36 | +/* #define VERBOSE */ |
---|
| 37 | + |
---|
| 38 | +#include <linux/module.h> |
---|
| 39 | +#include <linux/init.h> |
---|
| 40 | +#include <linux/netdevice.h> |
---|
| 41 | +#include <linux/etherdevice.h> |
---|
| 42 | +#include <linux/ctype.h> |
---|
| 43 | +#include <linux/ethtool.h> |
---|
| 44 | +#include <linux/workqueue.h> |
---|
| 45 | +#include <linux/mii.h> |
---|
| 46 | +#include <linux/usb.h> |
---|
| 47 | +/*#include <linux/usb/usbnet.h>*/ |
---|
| 48 | + |
---|
| 49 | +#include "asix.h" |
---|
| 50 | +#include "axusbnet.h" |
---|
| 51 | + |
---|
| 52 | +#define DRIVER_VERSION "4.24.0" |
---|
| 53 | +#define DRIVER_AUTHOR "David Hollis" |
---|
| 54 | +#define DRIVER_DESCRIPTION "ASIX AX88772C_772B_772A_760_772_178 USB 2.0 \ |
---|
| 55 | +Ethernet Devices" |
---|
| 56 | +#define DRIVER_LICENSE "GPL" |
---|
| 57 | + |
---|
| 58 | +static void axusbnet_unlink_rx_urbs(struct usbnet *); |
---|
| 59 | + |
---|
| 60 | +static void |
---|
| 61 | +ax8817x_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, |
---|
| 62 | + u16 size, void *data); |
---|
| 63 | + |
---|
| 64 | +/*-------------------------------------------------------------------------*/ |
---|
| 65 | + |
---|
| 66 | +/* |
---|
| 67 | + * Nineteen USB 1.1 max size bulk transactions per frame (ms), max. |
---|
| 68 | + * Several dozen bytes of IPv4 data can fit in two such transactions. |
---|
| 69 | + * One maximum size Ethernet packet takes twenty four of them. |
---|
| 70 | + * For high speed, each frame comfortably fits almost 36 max size |
---|
| 71 | + * Ethernet packets (so queues should be bigger). |
---|
| 72 | + * |
---|
| 73 | + * REVISIT qlens should be members of 'struct usbnet'; the goal is to |
---|
| 74 | + * let the USB host controller be busy for 5msec or more before an irq |
---|
| 75 | + * is required, under load. Jumbograms change the equation. |
---|
| 76 | + */ |
---|
| 77 | +#define RX_MAX_QUEUE_MEMORY (60 * 1518) |
---|
| 78 | +#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ |
---|
| 79 | + (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4) |
---|
| 80 | +#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \ |
---|
| 81 | + (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4) |
---|
| 82 | + |
---|
| 83 | +/* reawaken network queue this soon after stopping; else watchdog barks */ |
---|
| 84 | +/* #define TX_TIMEOUT_JIFFIES (5 * HZ) */ |
---|
| 85 | +#define TX_TIMEOUT_JIFFIES (30 * HZ) |
---|
| 86 | + |
---|
| 87 | +/* throttle rx/tx briefly after some faults, so khubd might disconnect() */ |
---|
| 88 | +/* us (it polls at HZ/4 usually) before we report too many false errors. */ |
---|
| 89 | +#define THROTTLE_JIFFIES (HZ / 8) |
---|
| 90 | + |
---|
| 91 | +/* between wakeups */ |
---|
| 92 | +#define UNLINK_TIMEOUT_MS 3 |
---|
| 93 | + |
---|
| 94 | +/*-------------------------------------------------------------------------*/ |
---|
| 95 | + |
---|
| 96 | +static const char driver_name[] = "axusbnet"; |
---|
| 97 | + |
---|
| 98 | +/* use ethtool to change the level for any given device */ |
---|
| 99 | +static int msg_level = -1; |
---|
| 100 | +module_param(msg_level, int, 0); |
---|
| 101 | +MODULE_PARM_DESC(msg_level, "Override default message level"); |
---|
| 102 | + |
---|
| 103 | +/*-------------------------------------------------------------------------*/ |
---|
| 104 | + |
---|
| 105 | +/* handles CDC Ethernet and many other network "bulk data" interfaces */ |
---|
| 106 | +static |
---|
| 107 | +int axusbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) |
---|
| 108 | +{ |
---|
| 109 | + int tmp; |
---|
| 110 | + struct usb_host_interface *alt = NULL; |
---|
| 111 | + struct usb_host_endpoint *in = NULL, *out = NULL; |
---|
| 112 | + struct usb_host_endpoint *status = NULL; |
---|
| 113 | + |
---|
| 114 | + for (tmp = 0; tmp < intf->num_altsetting; tmp++) { |
---|
| 115 | + unsigned ep; |
---|
| 116 | + |
---|
| 117 | + in = out = status = NULL; |
---|
| 118 | + alt = intf->altsetting + tmp; |
---|
| 119 | + |
---|
| 120 | + /* take the first altsetting with in-bulk + out-bulk; |
---|
| 121 | + * remember any status endpoint, just in case; |
---|
| 122 | + * ignore other endpoints and altsetttings. |
---|
| 123 | + */ |
---|
| 124 | + for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) { |
---|
| 125 | + struct usb_host_endpoint *e; |
---|
| 126 | + int intr = 0; |
---|
| 127 | + |
---|
| 128 | + e = alt->endpoint + ep; |
---|
| 129 | + switch (e->desc.bmAttributes) { |
---|
| 130 | + case USB_ENDPOINT_XFER_INT: |
---|
| 131 | + if (!(e->desc.bEndpointAddress & USB_DIR_IN)) |
---|
| 132 | + continue; |
---|
| 133 | + intr = 1; |
---|
| 134 | + /* FALLTHROUGH */ |
---|
| 135 | + case USB_ENDPOINT_XFER_BULK: |
---|
| 136 | + break; |
---|
| 137 | + default: |
---|
| 138 | + continue; |
---|
| 139 | + } |
---|
| 140 | + if (e->desc.bEndpointAddress & USB_DIR_IN) { |
---|
| 141 | + if (!intr && !in) { |
---|
| 142 | + in = e; |
---|
| 143 | + } else if (intr && !status) { |
---|
| 144 | + status = e; |
---|
| 145 | + } |
---|
| 146 | + } else { |
---|
| 147 | + if (!out) { |
---|
| 148 | + out = e; |
---|
| 149 | + } |
---|
| 150 | + } |
---|
| 151 | + } |
---|
| 152 | + if (in && out) |
---|
| 153 | + break; |
---|
| 154 | + } |
---|
| 155 | + if (!alt || !in || !out) |
---|
| 156 | + return -EINVAL; |
---|
| 157 | + |
---|
| 158 | + if (alt->desc.bAlternateSetting != 0 |
---|
| 159 | + || !(dev->driver_info->flags & FLAG_NO_SETINT)) { |
---|
| 160 | + tmp = usb_set_interface(dev->udev, alt->desc.bInterfaceNumber, |
---|
| 161 | + alt->desc.bAlternateSetting); |
---|
| 162 | + if (tmp < 0) |
---|
| 163 | + return tmp; |
---|
| 164 | + } |
---|
| 165 | + |
---|
| 166 | + dev->in = usb_rcvbulkpipe(dev->udev, |
---|
| 167 | + in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); |
---|
| 168 | + dev->out = usb_sndbulkpipe(dev->udev, |
---|
| 169 | + out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); |
---|
| 170 | + dev->status = status; |
---|
| 171 | + return 0; |
---|
| 172 | +} |
---|
| 173 | + |
---|
| 174 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) |
---|
| 175 | +static void intr_complete(struct urb *urb, struct pt_regs *regs); |
---|
| 176 | +#else |
---|
| 177 | +static void intr_complete(struct urb *urb); |
---|
| 178 | +#endif |
---|
| 179 | + |
---|
| 180 | +static int init_status(struct usbnet *dev, struct usb_interface *intf) |
---|
| 181 | +{ |
---|
| 182 | + char *buf = NULL; |
---|
| 183 | + unsigned pipe = 0; |
---|
| 184 | + unsigned maxp; |
---|
| 185 | + unsigned period; |
---|
| 186 | + |
---|
| 187 | + if (!dev->driver_info->status) |
---|
| 188 | + return 0; |
---|
| 189 | + |
---|
| 190 | + pipe = usb_rcvintpipe(dev->udev, |
---|
| 191 | + dev->status->desc.bEndpointAddress |
---|
| 192 | + & USB_ENDPOINT_NUMBER_MASK); |
---|
| 193 | + maxp = usb_maxpacket(dev->udev, pipe, 0); |
---|
| 194 | + |
---|
| 195 | + /* avoid 1 msec chatter: min 8 msec poll rate */ |
---|
| 196 | + period = max((int) dev->status->desc.bInterval, |
---|
| 197 | + (dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3); |
---|
| 198 | + |
---|
| 199 | + buf = kmalloc(maxp, GFP_KERNEL); |
---|
| 200 | + if (buf) { |
---|
| 201 | + dev->interrupt = usb_alloc_urb(0, GFP_KERNEL); |
---|
| 202 | + if (!dev->interrupt) { |
---|
| 203 | + kfree(buf); |
---|
| 204 | + return -ENOMEM; |
---|
| 205 | + } else { |
---|
| 206 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) |
---|
| 207 | + dev->interrupt->transfer_flags |= URB_ASYNC_UNLINK; |
---|
| 208 | +#endif |
---|
| 209 | + usb_fill_int_urb(dev->interrupt, dev->udev, pipe, |
---|
| 210 | + buf, maxp, intr_complete, dev, period); |
---|
| 211 | + devdbg(dev, |
---|
| 212 | + "status ep%din, %d bytes period %d", |
---|
| 213 | + usb_pipeendpoint(pipe), maxp, period); |
---|
| 214 | + } |
---|
| 215 | + } |
---|
| 216 | + return 0; |
---|
| 217 | +} |
---|
| 218 | + |
---|
| 219 | +/* Passes this packet up the stack, updating its accounting. |
---|
| 220 | + * Some link protocols batch packets, so their rx_fixup paths |
---|
| 221 | + * can return clones as well as just modify the original skb. |
---|
| 222 | + */ |
---|
| 223 | +static |
---|
| 224 | +void axusbnet_skb_return(struct usbnet *dev, struct sk_buff *skb) |
---|
| 225 | +{ |
---|
| 226 | + int status; |
---|
| 227 | + |
---|
| 228 | + skb->dev = dev->net; |
---|
| 229 | + skb->protocol = eth_type_trans(skb, dev->net); |
---|
| 230 | + dev->stats.rx_packets++; |
---|
| 231 | + dev->stats.rx_bytes += skb->len; |
---|
| 232 | + |
---|
| 233 | + if (netif_msg_rx_status(dev)) |
---|
| 234 | + devdbg(dev, "< rx, len %zu, type 0x%x", |
---|
| 235 | + skb->len + sizeof(struct ethhdr), skb->protocol); |
---|
| 236 | + memset(skb->cb, 0, sizeof(struct skb_data)); |
---|
| 237 | + status = netif_rx(skb); |
---|
| 238 | + if (status != NET_RX_SUCCESS && netif_msg_rx_err(dev)) |
---|
| 239 | + devdbg(dev, "netif_rx status %d", status); |
---|
| 240 | +} |
---|
| 241 | + |
---|
| 242 | +/*------------------------------------------------------------------------- |
---|
| 243 | + * |
---|
| 244 | + * Network Device Driver (peer link to "Host Device", from USB host) |
---|
| 245 | + * |
---|
| 246 | + *-------------------------------------------------------------------------*/ |
---|
| 247 | + |
---|
| 248 | +static |
---|
| 249 | +int axusbnet_change_mtu(struct net_device *net, int new_mtu) |
---|
| 250 | +{ |
---|
| 251 | + struct usbnet *dev = netdev_priv(net); |
---|
| 252 | + int ll_mtu = new_mtu + net->hard_header_len; |
---|
| 253 | + int old_hard_mtu = dev->hard_mtu; |
---|
| 254 | + int old_rx_urb_size = dev->rx_urb_size; |
---|
| 255 | + |
---|
| 256 | + if (new_mtu <= 0) |
---|
| 257 | + return -EINVAL; |
---|
| 258 | + /* no second zero-length packet read wanted after mtu-sized packets */ |
---|
| 259 | + if ((ll_mtu % dev->maxpacket) == 0) |
---|
| 260 | + return -EDOM; |
---|
| 261 | + net->mtu = new_mtu; |
---|
| 262 | + |
---|
| 263 | + dev->hard_mtu = net->mtu + net->hard_header_len; |
---|
| 264 | + if (dev->rx_urb_size == old_hard_mtu) { |
---|
| 265 | + dev->rx_urb_size = dev->hard_mtu; |
---|
| 266 | + if (dev->rx_urb_size > old_rx_urb_size) |
---|
| 267 | + axusbnet_unlink_rx_urbs(dev); |
---|
| 268 | + } |
---|
| 269 | + |
---|
| 270 | + return 0; |
---|
| 271 | +} |
---|
| 272 | + |
---|
| 273 | +static struct net_device_stats *axusbnet_get_stats(struct net_device *net) |
---|
| 274 | +{ |
---|
| 275 | + struct usbnet *dev = netdev_priv(net); |
---|
| 276 | + return &dev->stats; |
---|
| 277 | +} |
---|
| 278 | + |
---|
| 279 | +/*-------------------------------------------------------------------------*/ |
---|
| 280 | + |
---|
| 281 | +/* some LK 2.4 HCDs oopsed if we freed or resubmitted urbs from |
---|
| 282 | + * completion callbacks. 2.5 should have fixed those bugs... |
---|
| 283 | + */ |
---|
| 284 | + |
---|
| 285 | +static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb, |
---|
| 286 | + struct sk_buff_head *list, enum skb_state state) |
---|
| 287 | +{ |
---|
| 288 | + unsigned long flags; |
---|
| 289 | + enum skb_state old_state; |
---|
| 290 | + struct skb_data *entry = (struct skb_data *) skb->cb; |
---|
| 291 | + |
---|
| 292 | + spin_lock_irqsave(&list->lock, flags); |
---|
| 293 | + old_state = entry->state; |
---|
| 294 | + entry->state = state; |
---|
| 295 | + __skb_unlink(skb, list); |
---|
| 296 | + |
---|
| 297 | + /* defer_bh() is never called with list == &dev->done. |
---|
| 298 | + * spin_lock_nested() tells lockdep that it is OK to take |
---|
| 299 | + * dev->done.lock here with list->lock held. |
---|
| 300 | + */ |
---|
| 301 | + spin_lock_nested(&dev->done.lock, SINGLE_DEPTH_NESTING); |
---|
| 302 | + |
---|
| 303 | + __skb_queue_tail(&dev->done, skb); |
---|
| 304 | + if (dev->done.qlen == 1) |
---|
| 305 | + tasklet_schedule(&dev->bh); |
---|
| 306 | + |
---|
| 307 | + spin_unlock(&dev->done.lock); |
---|
| 308 | + spin_unlock_irqrestore(&list->lock, flags); |
---|
| 309 | + |
---|
| 310 | + return old_state; |
---|
| 311 | +} |
---|
| 312 | + |
---|
| 313 | +/* some work can't be done in tasklets, so we use keventd |
---|
| 314 | + * |
---|
| 315 | + * NOTE: annoying asymmetry: if it's active, schedule_work() fails, |
---|
| 316 | + * but tasklet_schedule() doesn't. hope the failure is rare. |
---|
| 317 | + */ |
---|
| 318 | +static |
---|
| 319 | +void axusbnet_defer_kevent(struct usbnet *dev, int work) |
---|
| 320 | +{ |
---|
| 321 | + set_bit(work, &dev->flags); |
---|
| 322 | + if (!schedule_work(&dev->kevent)) |
---|
| 323 | + deverr(dev, "kevent %d may have been dropped", work); |
---|
| 324 | + else |
---|
| 325 | + devdbg(dev, "kevent %d scheduled", work); |
---|
| 326 | +} |
---|
| 327 | + |
---|
| 328 | +/*-------------------------------------------------------------------------*/ |
---|
| 329 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) |
---|
| 330 | +static void rx_complete(struct urb *urb, struct pt_regs *regs); |
---|
| 331 | +#else |
---|
| 332 | +static void rx_complete(struct urb *urb); |
---|
| 333 | +#endif |
---|
| 334 | + |
---|
| 335 | +static void rx_submit(struct usbnet *dev, struct urb *urb, gfp_t flags) |
---|
| 336 | +{ |
---|
| 337 | + struct sk_buff *skb; |
---|
| 338 | + struct skb_data *entry; |
---|
| 339 | + int retval = 0; |
---|
| 340 | + unsigned long lockflags; |
---|
| 341 | + size_t size = dev->rx_urb_size; |
---|
| 342 | + struct driver_info *info = dev->driver_info; |
---|
| 343 | + u8 align; |
---|
| 344 | + |
---|
| 345 | + /* prevent rx skb allocation when error ratio is high */ |
---|
| 346 | + if (test_bit(EVENT_RX_KILL, &dev->flags)) { |
---|
| 347 | + usb_free_urb(urb); |
---|
| 348 | + return; |
---|
| 349 | + } |
---|
| 350 | + |
---|
| 351 | +#if (AX_FORCE_BUFF_ALIGN) |
---|
| 352 | + align = 0; |
---|
| 353 | +#else |
---|
| 354 | + if (!(info->flags & FLAG_HW_IP_ALIGNMENT)) |
---|
| 355 | + align = NET_IP_ALIGN; |
---|
| 356 | + else |
---|
| 357 | + align = 0; |
---|
| 358 | +#endif |
---|
| 359 | + skb = alloc_skb(size + align, flags); |
---|
| 360 | + if (skb == NULL) { |
---|
| 361 | + |
---|
| 362 | + if (netif_msg_rx_err(dev)) |
---|
| 363 | + devdbg(dev, "no rx skb"); |
---|
| 364 | + |
---|
| 365 | + if ((dev->rx_urb_size > 2048) && dev->rx_size) { |
---|
| 366 | + dev->rx_size--; |
---|
| 367 | + dev->rx_urb_size = |
---|
| 368 | + AX88772B_BULKIN_SIZE[dev->rx_size].size; |
---|
| 369 | + |
---|
| 370 | + ax8817x_write_cmd_async(dev, 0x2A, |
---|
| 371 | + AX88772B_BULKIN_SIZE[dev->rx_size].byte_cnt, |
---|
| 372 | + AX88772B_BULKIN_SIZE[dev->rx_size].threshold, |
---|
| 373 | + 0, NULL); |
---|
| 374 | + } |
---|
| 375 | + |
---|
| 376 | + if (!(dev->flags & EVENT_RX_MEMORY)) |
---|
| 377 | + axusbnet_defer_kevent(dev, EVENT_RX_MEMORY); |
---|
| 378 | + usb_free_urb(urb); |
---|
| 379 | + return; |
---|
| 380 | + } |
---|
| 381 | + |
---|
| 382 | + if (align) |
---|
| 383 | + skb_reserve(skb, NET_IP_ALIGN); |
---|
| 384 | + |
---|
| 385 | + entry = (struct skb_data *) skb->cb; |
---|
| 386 | + entry->urb = urb; |
---|
| 387 | + entry->dev = dev; |
---|
| 388 | + entry->state = rx_start; |
---|
| 389 | + entry->length = 0; |
---|
| 390 | + |
---|
| 391 | + usb_fill_bulk_urb(urb, dev->udev, dev->in, skb->data, |
---|
| 392 | + size, rx_complete, skb); |
---|
| 393 | + |
---|
| 394 | + spin_lock_irqsave(&dev->rxq.lock, lockflags); |
---|
| 395 | + |
---|
| 396 | + if (netif_running(dev->net) |
---|
| 397 | + && netif_device_present(dev->net) |
---|
| 398 | + && !test_bit(EVENT_RX_HALT, &dev->flags)) { |
---|
| 399 | + switch (retval = usb_submit_urb(urb, GFP_ATOMIC)) { |
---|
| 400 | + case -EPIPE: |
---|
| 401 | + axusbnet_defer_kevent(dev, EVENT_RX_HALT); |
---|
| 402 | + break; |
---|
| 403 | + case -ENOMEM: |
---|
| 404 | + axusbnet_defer_kevent(dev, EVENT_RX_MEMORY); |
---|
| 405 | + break; |
---|
| 406 | + case -ENODEV: |
---|
| 407 | + if (netif_msg_ifdown(dev)) |
---|
| 408 | + devdbg(dev, "device gone"); |
---|
| 409 | + netif_device_detach(dev->net); |
---|
| 410 | + break; |
---|
| 411 | + default: |
---|
| 412 | + if (netif_msg_rx_err(dev)) |
---|
| 413 | + devdbg(dev, "rx submit, %d", retval); |
---|
| 414 | + tasklet_schedule(&dev->bh); |
---|
| 415 | + break; |
---|
| 416 | + case 0: |
---|
| 417 | + __skb_queue_tail(&dev->rxq, skb); |
---|
| 418 | + } |
---|
| 419 | + } else { |
---|
| 420 | + if (netif_msg_ifdown(dev)) |
---|
| 421 | + devdbg(dev, "rx: stopped"); |
---|
| 422 | + retval = -ENOLINK; |
---|
| 423 | + } |
---|
| 424 | + spin_unlock_irqrestore(&dev->rxq.lock, lockflags); |
---|
| 425 | + if (retval) { |
---|
| 426 | + dev_kfree_skb_any(skb); |
---|
| 427 | + usb_free_urb(urb); |
---|
| 428 | + } |
---|
| 429 | +} |
---|
| 430 | + |
---|
| 431 | + |
---|
| 432 | +/*-------------------------------------------------------------------------*/ |
---|
| 433 | + |
---|
| 434 | +static inline void rx_process(struct usbnet *dev, struct sk_buff *skb) |
---|
| 435 | +{ |
---|
| 436 | + if (dev->driver_info->rx_fixup |
---|
| 437 | + && !dev->driver_info->rx_fixup(dev, skb)) |
---|
| 438 | + goto error; |
---|
| 439 | + /* else network stack removes extra byte if we forced a short packet */ |
---|
| 440 | + |
---|
| 441 | + if (skb->len) |
---|
| 442 | + axusbnet_skb_return(dev, skb); |
---|
| 443 | + else { |
---|
| 444 | + if (netif_msg_rx_err(dev)) |
---|
| 445 | + devdbg(dev, "drop"); |
---|
| 446 | +error: |
---|
| 447 | + dev->stats.rx_errors++; |
---|
| 448 | + skb_queue_tail(&dev->done, skb); |
---|
| 449 | + } |
---|
| 450 | +} |
---|
| 451 | + |
---|
| 452 | +/*-------------------------------------------------------------------------*/ |
---|
| 453 | + |
---|
| 454 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) |
---|
| 455 | +static void rx_complete(struct urb *urb, struct pt_regs *regs) |
---|
| 456 | +#else |
---|
| 457 | +static void rx_complete(struct urb *urb) |
---|
| 458 | +#endif |
---|
| 459 | +{ |
---|
| 460 | + struct sk_buff *skb = (struct sk_buff *) urb->context; |
---|
| 461 | + struct skb_data *entry = (struct skb_data *) skb->cb; |
---|
| 462 | + struct usbnet *dev = entry->dev; |
---|
| 463 | + int urb_status = urb->status; |
---|
| 464 | + enum skb_state state; |
---|
| 465 | + |
---|
| 466 | + skb_put(skb, urb->actual_length); |
---|
| 467 | + state = rx_done; |
---|
| 468 | + entry->urb = NULL; |
---|
| 469 | + |
---|
| 470 | + switch (urb_status) { |
---|
| 471 | + /* success */ |
---|
| 472 | + case 0: |
---|
| 473 | + if (skb->len < dev->net->hard_header_len) { |
---|
| 474 | + entry->state = rx_cleanup; |
---|
| 475 | + dev->stats.rx_errors++; |
---|
| 476 | + dev->stats.rx_length_errors++; |
---|
| 477 | + if (netif_msg_rx_err(dev)) |
---|
| 478 | + devdbg(dev, "rx length %d", skb->len); |
---|
| 479 | + } |
---|
| 480 | + break; |
---|
| 481 | + |
---|
| 482 | + /* stalls need manual reset. this is rare ... except that |
---|
| 483 | + * when going through USB 2.0 TTs, unplug appears this way. |
---|
| 484 | + * we avoid the highspeed version of the ETIMEDOUT/EILSEQ |
---|
| 485 | + * storm, recovering as needed. |
---|
| 486 | + */ |
---|
| 487 | + case -EPIPE: |
---|
| 488 | + dev->stats.rx_errors++; |
---|
| 489 | + axusbnet_defer_kevent(dev, EVENT_RX_HALT); |
---|
| 490 | + /* FALLTHROUGH */ |
---|
| 491 | + |
---|
| 492 | + /* software-driven interface shutdown */ |
---|
| 493 | + case -ECONNRESET: /* async unlink */ |
---|
| 494 | + case -ESHUTDOWN: /* hardware gone */ |
---|
| 495 | + if (netif_msg_ifdown(dev)) |
---|
| 496 | + devdbg(dev, "rx shutdown, code %d", urb_status); |
---|
| 497 | + goto block; |
---|
| 498 | + |
---|
| 499 | + /* we get controller i/o faults during khubd disconnect() delays. |
---|
| 500 | + * throttle down resubmits, to avoid log floods; just temporarily, |
---|
| 501 | + * so we still recover when the fault isn't a khubd delay. |
---|
| 502 | + */ |
---|
| 503 | + case -EPROTO: |
---|
| 504 | + case -ETIME: |
---|
| 505 | + case -EILSEQ: |
---|
| 506 | + dev->stats.rx_errors++; |
---|
| 507 | + if (!timer_pending(&dev->delay)) { |
---|
| 508 | + mod_timer(&dev->delay, jiffies + THROTTLE_JIFFIES); |
---|
| 509 | + if (netif_msg_link(dev)) |
---|
| 510 | + devdbg(dev, "rx throttle %d", urb_status); |
---|
| 511 | + } |
---|
| 512 | +block: |
---|
| 513 | + state = rx_cleanup; |
---|
| 514 | + entry->urb = urb; |
---|
| 515 | + urb = NULL; |
---|
| 516 | + break; |
---|
| 517 | + |
---|
| 518 | + /* data overrun ... flush fifo? */ |
---|
| 519 | + case -EOVERFLOW: |
---|
| 520 | + dev->stats.rx_over_errors++; |
---|
| 521 | + /* FALLTHROUGH */ |
---|
| 522 | + |
---|
| 523 | + default: |
---|
| 524 | + state = rx_cleanup; |
---|
| 525 | + dev->stats.rx_errors++; |
---|
| 526 | + if (netif_msg_rx_err(dev)) |
---|
| 527 | + devdbg(dev, "rx status %d", urb_status); |
---|
| 528 | + break; |
---|
| 529 | + } |
---|
| 530 | + |
---|
| 531 | + /* stop rx if packet error rate is high */ |
---|
| 532 | + if (++dev->pkt_cnt > 30) { |
---|
| 533 | + dev->pkt_cnt = 0; |
---|
| 534 | + dev->pkt_err = 0; |
---|
| 535 | + } else { |
---|
| 536 | + if (state == rx_cleanup) |
---|
| 537 | + dev->pkt_err++; |
---|
| 538 | + if (dev->pkt_err > 20) |
---|
| 539 | + set_bit(EVENT_RX_KILL, &dev->flags); |
---|
| 540 | + } |
---|
| 541 | + |
---|
| 542 | + state = defer_bh(dev, skb, &dev->rxq, state); |
---|
| 543 | + |
---|
| 544 | + if (urb) { |
---|
| 545 | + if (netif_running(dev->net) && |
---|
| 546 | + !test_bit(EVENT_RX_HALT, &dev->flags) && |
---|
| 547 | + state != unlink_start) { |
---|
| 548 | + rx_submit(dev, urb, GFP_ATOMIC); |
---|
| 549 | + return; |
---|
| 550 | + } |
---|
| 551 | + usb_free_urb(urb); |
---|
| 552 | + } |
---|
| 553 | + if (netif_msg_rx_err(dev)) |
---|
| 554 | + devdbg(dev, "no read resubmitted"); |
---|
| 555 | +} |
---|
| 556 | + |
---|
| 557 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) |
---|
| 558 | +static void intr_complete(struct urb *urb, struct pt_regs *regs) |
---|
| 559 | +#else |
---|
| 560 | +static void intr_complete(struct urb *urb) |
---|
| 561 | +#endif |
---|
| 562 | +{ |
---|
| 563 | + struct usbnet *dev = urb->context; |
---|
| 564 | + int status = urb->status; |
---|
| 565 | + |
---|
| 566 | + switch (status) { |
---|
| 567 | + /* success */ |
---|
| 568 | + case 0: |
---|
| 569 | + dev->driver_info->status(dev, urb); |
---|
| 570 | + break; |
---|
| 571 | + |
---|
| 572 | + /* software-driven interface shutdown */ |
---|
| 573 | + case -ENOENT: /* urb killed */ |
---|
| 574 | + case -ESHUTDOWN: /* hardware gone */ |
---|
| 575 | + if (netif_msg_ifdown(dev)) |
---|
| 576 | + devdbg(dev, "intr shutdown, code %d", status); |
---|
| 577 | + return; |
---|
| 578 | + |
---|
| 579 | + /* NOTE: not throttling like RX/TX, since this endpoint |
---|
| 580 | + * already polls infrequently |
---|
| 581 | + */ |
---|
| 582 | + default: |
---|
| 583 | + devdbg(dev, "intr status %d", status); |
---|
| 584 | + break; |
---|
| 585 | + } |
---|
| 586 | + |
---|
| 587 | + if (!netif_running(dev->net)) |
---|
| 588 | + return; |
---|
| 589 | + |
---|
| 590 | + memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); |
---|
| 591 | + status = usb_submit_urb(urb, GFP_ATOMIC); |
---|
| 592 | + if (status != 0 && netif_msg_timer(dev)) |
---|
| 593 | + deverr(dev, "intr resubmit --> %d", status); |
---|
| 594 | +} |
---|
| 595 | + |
---|
| 596 | +/*-------------------------------------------------------------------------*/ |
---|
| 597 | + |
---|
| 598 | +/* unlink pending rx/tx; completion handlers do all other cleanup */ |
---|
| 599 | + |
---|
| 600 | +static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) |
---|
| 601 | +{ |
---|
| 602 | + unsigned long flags; |
---|
| 603 | + struct sk_buff *skb = NULL; |
---|
| 604 | + int count = 0; |
---|
| 605 | + |
---|
| 606 | + spin_lock_irqsave (&q->lock, flags); |
---|
| 607 | + while (!skb_queue_empty(q)) { |
---|
| 608 | + struct skb_data *entry; |
---|
| 609 | + struct urb *urb; |
---|
| 610 | + int retval; |
---|
| 611 | + |
---|
| 612 | + skb_queue_walk(q, skb) { |
---|
| 613 | + entry = (struct skb_data *) skb->cb; |
---|
| 614 | + if (entry->state != unlink_start) |
---|
| 615 | + goto found; |
---|
| 616 | + } |
---|
| 617 | + break; |
---|
| 618 | +found: |
---|
| 619 | + entry->state = unlink_start; |
---|
| 620 | + urb = entry->urb; |
---|
| 621 | + |
---|
| 622 | + /* |
---|
| 623 | + * Get reference count of the URB to avoid it to be |
---|
| 624 | + * freed during usb_unlink_urb, which may trigger |
---|
| 625 | + * use-after-free problem inside usb_unlink_urb since |
---|
| 626 | + * usb_unlink_urb is always racing with .complete |
---|
| 627 | + * handler(include defer_bh). |
---|
| 628 | + */ |
---|
| 629 | + usb_get_urb(urb); |
---|
| 630 | + spin_unlock_irqrestore(&q->lock, flags); |
---|
| 631 | + // during some PM-driven resume scenarios, |
---|
| 632 | + // these (async) unlinks complete immediately |
---|
| 633 | + retval = usb_unlink_urb (urb); |
---|
| 634 | + if (retval != -EINPROGRESS && retval != 0) |
---|
| 635 | + printk(DEBUG "unlink urb err, %d\n", retval); |
---|
| 636 | + else |
---|
| 637 | + count++; |
---|
| 638 | + usb_put_urb(urb); |
---|
| 639 | + spin_lock_irqsave(&q->lock, flags); |
---|
| 640 | + } |
---|
| 641 | + spin_unlock_irqrestore (&q->lock, flags); |
---|
| 642 | + |
---|
| 643 | + return count; |
---|
| 644 | +} |
---|
| 645 | + |
---|
| 646 | +/* Flush all pending rx urbs */ |
---|
| 647 | +/* minidrivers may need to do this when the MTU changes */ |
---|
| 648 | + |
---|
| 649 | +static |
---|
| 650 | +void axusbnet_unlink_rx_urbs(struct usbnet *dev) |
---|
| 651 | +{ |
---|
| 652 | + if (netif_running(dev->net)) { |
---|
| 653 | + (void) unlink_urbs(dev, &dev->rxq); |
---|
| 654 | + tasklet_schedule(&dev->bh); |
---|
| 655 | + } |
---|
| 656 | +} |
---|
| 657 | + |
---|
| 658 | +/*-------------------------------------------------------------------------*/ |
---|
| 659 | + |
---|
| 660 | +/* precondition: never called in_interrupt */ |
---|
| 661 | + |
---|
| 662 | +static |
---|
| 663 | +int axusbnet_stop(struct net_device *net) |
---|
| 664 | +{ |
---|
| 665 | + struct usbnet *dev = netdev_priv(net); |
---|
| 666 | + struct driver_info *info = dev->driver_info; |
---|
| 667 | + |
---|
| 668 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18) |
---|
| 669 | + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(unlink_wakeup); |
---|
| 670 | +#else |
---|
| 671 | + DECLARE_WAIT_QUEUE_HEAD(unlink_wakeup); |
---|
| 672 | +#endif |
---|
| 673 | + DECLARE_WAITQUEUE(wait, current); |
---|
| 674 | + |
---|
| 675 | + netif_stop_queue(net); |
---|
| 676 | + |
---|
| 677 | + if (netif_msg_ifdown(dev)) |
---|
| 678 | + devinfo(dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld", |
---|
| 679 | + dev->stats.rx_packets, dev->stats.tx_packets, |
---|
| 680 | + dev->stats.rx_errors, dev->stats.tx_errors); |
---|
| 681 | + |
---|
| 682 | + /* allow minidriver to stop correctly (wireless devices to turn off |
---|
| 683 | + * radio etc) */ |
---|
| 684 | + if (info->stop) { |
---|
| 685 | + int retval; |
---|
| 686 | + retval = info->stop(dev); |
---|
| 687 | + if (retval < 0 && netif_msg_ifdown(dev)) |
---|
| 688 | + devinfo(dev, |
---|
| 689 | + "stop fail (%d) usbnet usb-%s-%s, %s", |
---|
| 690 | + retval, |
---|
| 691 | + dev->udev->bus->bus_name, dev->udev->devpath, |
---|
| 692 | + info->description); |
---|
| 693 | + } |
---|
| 694 | + |
---|
| 695 | + if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { |
---|
| 696 | + int temp; |
---|
| 697 | + /* ensure there are no more active urbs */ |
---|
| 698 | + add_wait_queue(&unlink_wakeup, &wait); |
---|
| 699 | + dev->wait = &unlink_wakeup; |
---|
| 700 | + temp = unlink_urbs(dev, &dev->txq) + |
---|
| 701 | + unlink_urbs(dev, &dev->rxq); |
---|
| 702 | + |
---|
| 703 | + /* maybe wait for deletions to finish. */ |
---|
| 704 | + while (!skb_queue_empty(&dev->rxq) |
---|
| 705 | + && !skb_queue_empty(&dev->txq) |
---|
| 706 | + && !skb_queue_empty(&dev->done)) { |
---|
| 707 | + msleep(UNLINK_TIMEOUT_MS); |
---|
| 708 | + if (netif_msg_ifdown(dev)) |
---|
| 709 | + devdbg(dev, "waited for %d urb completions", |
---|
| 710 | + temp); |
---|
| 711 | + } |
---|
| 712 | + dev->wait = NULL; |
---|
| 713 | + remove_wait_queue(&unlink_wakeup, &wait); |
---|
| 714 | + } |
---|
| 715 | + |
---|
| 716 | + usb_kill_urb(dev->interrupt); |
---|
| 717 | + |
---|
| 718 | + /* deferred work (task, timer, softirq) must also stop. |
---|
| 719 | + * can't flush_scheduled_work() until we drop rtnl (later), |
---|
| 720 | + * else workers could deadlock; so make workers a NOP. |
---|
| 721 | + */ |
---|
| 722 | + dev->flags = 0; |
---|
| 723 | + del_timer_sync(&dev->delay); |
---|
| 724 | + tasklet_kill(&dev->bh); |
---|
| 725 | + |
---|
| 726 | + return 0; |
---|
| 727 | +} |
---|
| 728 | + |
---|
| 729 | +/*-------------------------------------------------------------------------*/ |
---|
| 730 | + |
---|
| 731 | +/* posts reads, and enables write queuing */ |
---|
| 732 | + |
---|
| 733 | +/* precondition: never called in_interrupt */ |
---|
| 734 | + |
---|
| 735 | +static |
---|
| 736 | +int axusbnet_open(struct net_device *net) |
---|
| 737 | +{ |
---|
| 738 | + struct usbnet *dev = netdev_priv(net); |
---|
| 739 | + int retval = 0; |
---|
| 740 | + struct driver_info *info = dev->driver_info; |
---|
| 741 | + |
---|
| 742 | + /* put into "known safe" state */ |
---|
| 743 | + if (info->reset) { |
---|
| 744 | + retval = info->reset(dev); |
---|
| 745 | + if (retval < 0) { |
---|
| 746 | + if (netif_msg_ifup(dev)) |
---|
| 747 | + devinfo(dev, |
---|
| 748 | + "open reset fail (%d) usbnet usb-%s-%s, %s", |
---|
| 749 | + retval, |
---|
| 750 | + dev->udev->bus->bus_name, |
---|
| 751 | + dev->udev->devpath, |
---|
| 752 | + info->description); |
---|
| 753 | + goto done; |
---|
| 754 | + } |
---|
| 755 | + } |
---|
| 756 | + |
---|
| 757 | + /* insist peer be connected */ |
---|
| 758 | + if (info->check_connect) { |
---|
| 759 | + retval = info->check_connect(dev); |
---|
| 760 | + if (retval < 0) { |
---|
| 761 | + if (netif_msg_ifup(dev)) |
---|
| 762 | + devdbg(dev, "can't open; %d", retval); |
---|
| 763 | + goto done; |
---|
| 764 | + } |
---|
| 765 | + } |
---|
| 766 | + |
---|
| 767 | + /* start any status interrupt transfer */ |
---|
| 768 | + if (dev->interrupt) { |
---|
| 769 | + retval = usb_submit_urb(dev->interrupt, GFP_KERNEL); |
---|
| 770 | + if (retval < 0) { |
---|
| 771 | + if (netif_msg_ifup(dev)) |
---|
| 772 | + deverr(dev, "intr submit %d", retval); |
---|
| 773 | + goto done; |
---|
| 774 | + } |
---|
| 775 | + } |
---|
| 776 | + |
---|
| 777 | + /* reset rx error state */ |
---|
| 778 | + dev->pkt_cnt = 0; |
---|
| 779 | + dev->pkt_err = 0; |
---|
| 780 | + clear_bit(EVENT_RX_KILL, &dev->flags); |
---|
| 781 | + |
---|
| 782 | + netif_start_queue(net); |
---|
| 783 | + if (netif_msg_ifup(dev)) { |
---|
| 784 | + char *framing; |
---|
| 785 | + |
---|
| 786 | + if (dev->driver_info->flags & FLAG_FRAMING_NC) |
---|
| 787 | + framing = "NetChip"; |
---|
| 788 | + else if (dev->driver_info->flags & FLAG_FRAMING_GL) |
---|
| 789 | + framing = "GeneSys"; |
---|
| 790 | + else if (dev->driver_info->flags & FLAG_FRAMING_Z) |
---|
| 791 | + framing = "Zaurus"; |
---|
| 792 | + else if (dev->driver_info->flags & FLAG_FRAMING_RN) |
---|
| 793 | + framing = "RNDIS"; |
---|
| 794 | + else if (dev->driver_info->flags & FLAG_FRAMING_AX) |
---|
| 795 | + framing = "ASIX"; |
---|
| 796 | + else |
---|
| 797 | + framing = "simple"; |
---|
| 798 | + |
---|
| 799 | + devinfo(dev, "open: enable queueing (rx %d, tx %d) mtu %d %s framing", |
---|
| 800 | + (int)RX_QLEN(dev), (int)TX_QLEN(dev), dev->net->mtu, |
---|
| 801 | + framing); |
---|
| 802 | + } |
---|
| 803 | + |
---|
| 804 | + /* delay posting reads until we're fully open */ |
---|
| 805 | + tasklet_schedule(&dev->bh); |
---|
| 806 | + return retval; |
---|
| 807 | +done: |
---|
| 808 | + return retval; |
---|
| 809 | +} |
---|
| 810 | + |
---|
| 811 | +/*-------------------------------------------------------------------------*/ |
---|
| 812 | + |
---|
| 813 | +/* ethtool methods; minidrivers may need to add some more, but |
---|
| 814 | + * they'll probably want to use this base set. |
---|
| 815 | + */ |
---|
| 816 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0) |
---|
| 817 | +static |
---|
| 818 | +int axusbnet_get_settings(struct net_device *net, struct ethtool_cmd *cmd) |
---|
| 819 | +{ |
---|
| 820 | + struct usbnet *dev = netdev_priv(net); |
---|
| 821 | + |
---|
| 822 | + if (!dev->mii.mdio_read) |
---|
| 823 | + return -EOPNOTSUPP; |
---|
| 824 | + |
---|
| 825 | + return mii_ethtool_gset(&dev->mii, cmd); |
---|
| 826 | +} |
---|
| 827 | + |
---|
| 828 | +static |
---|
| 829 | +int axusbnet_set_settings(struct net_device *net, struct ethtool_cmd *cmd) |
---|
| 830 | +{ |
---|
| 831 | + struct usbnet *dev = netdev_priv(net); |
---|
| 832 | + int retval; |
---|
| 833 | + |
---|
| 834 | + if (!dev->mii.mdio_write) |
---|
| 835 | + return -EOPNOTSUPP; |
---|
| 836 | + |
---|
| 837 | + retval = mii_ethtool_sset(&dev->mii, cmd); |
---|
| 838 | + |
---|
| 839 | + /* link speed/duplex might have changed */ |
---|
| 840 | + if (dev->driver_info->link_reset) |
---|
| 841 | + dev->driver_info->link_reset(dev); |
---|
| 842 | + |
---|
| 843 | + return retval; |
---|
| 844 | + |
---|
| 845 | +} |
---|
| 846 | +#endif |
---|
| 847 | +static |
---|
| 848 | +u32 axusbnet_get_link(struct net_device *net) |
---|
| 849 | +{ |
---|
| 850 | + struct usbnet *dev = netdev_priv(net); |
---|
| 851 | + |
---|
| 852 | + /* If a check_connect is defined, return its result */ |
---|
| 853 | + if (dev->driver_info->check_connect) |
---|
| 854 | + return dev->driver_info->check_connect(dev) == 0; |
---|
| 855 | + |
---|
| 856 | + /* if the device has mii operations, use those */ |
---|
| 857 | + if (dev->mii.mdio_read) |
---|
| 858 | + return mii_link_ok(&dev->mii); |
---|
| 859 | + |
---|
| 860 | + /* Otherwise, dtrt for drivers calling netif_carrier_{on,off} */ |
---|
| 861 | + return ethtool_op_get_link(net); |
---|
| 862 | +} |
---|
| 863 | + |
---|
| 864 | +static |
---|
| 865 | +int axusbnet_nway_reset(struct net_device *net) |
---|
| 866 | +{ |
---|
| 867 | + struct usbnet *dev = netdev_priv(net); |
---|
| 868 | + |
---|
| 869 | + if (!dev->mii.mdio_write) |
---|
| 870 | + return -EOPNOTSUPP; |
---|
| 871 | + |
---|
| 872 | + return mii_nway_restart(&dev->mii); |
---|
| 873 | +} |
---|
| 874 | + |
---|
| 875 | +static |
---|
| 876 | +void axusbnet_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) |
---|
| 877 | +{ |
---|
| 878 | + struct usbnet *dev = netdev_priv(net); |
---|
| 879 | + |
---|
| 880 | + strncpy(info->driver, dev->driver_name, sizeof(info->driver)); |
---|
| 881 | + strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); |
---|
| 882 | + strncpy(info->fw_version, dev->driver_info->description, |
---|
| 883 | + sizeof(info->fw_version)); |
---|
| 884 | + usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info)); |
---|
| 885 | +} |
---|
| 886 | + |
---|
| 887 | +static |
---|
| 888 | +u32 axusbnet_get_msglevel(struct net_device *net) |
---|
| 889 | +{ |
---|
| 890 | + struct usbnet *dev = netdev_priv(net); |
---|
| 891 | + |
---|
| 892 | + return dev->msg_enable; |
---|
| 893 | +} |
---|
| 894 | + |
---|
| 895 | +static |
---|
| 896 | +void axusbnet_set_msglevel(struct net_device *net, u32 level) |
---|
| 897 | +{ |
---|
| 898 | + struct usbnet *dev = netdev_priv(net); |
---|
| 899 | + |
---|
| 900 | + dev->msg_enable = level; |
---|
| 901 | +} |
---|
| 902 | + |
---|
| 903 | +/* drivers may override default ethtool_ops in their bind() routine */ |
---|
| 904 | +static struct ethtool_ops axusbnet_ethtool_ops = { |
---|
| 905 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0) |
---|
| 906 | + .get_settings = axusbnet_get_settings, |
---|
| 907 | + .set_settings = axusbnet_set_settings, |
---|
| 908 | +#endif |
---|
| 909 | + .get_link = axusbnet_get_link, |
---|
| 910 | + .nway_reset = axusbnet_nway_reset, |
---|
| 911 | + .get_drvinfo = axusbnet_get_drvinfo, |
---|
| 912 | + .get_msglevel = axusbnet_get_msglevel, |
---|
| 913 | + .set_msglevel = axusbnet_set_msglevel, |
---|
| 914 | +}; |
---|
| 915 | + |
---|
| 916 | +/*-------------------------------------------------------------------------*/ |
---|
| 917 | + |
---|
| 918 | +/* work that cannot be done in interrupt context uses keventd. |
---|
| 919 | + * |
---|
| 920 | + * NOTE: with 2.5 we could do more of this using completion callbacks, |
---|
| 921 | + * especially now that control transfers can be queued. |
---|
| 922 | + */ |
---|
| 923 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 924 | +static void kevent(void *data) |
---|
| 925 | +{ |
---|
| 926 | + struct usbnet *dev = (struct usbnet *)data; |
---|
| 927 | +#else |
---|
| 928 | +static void kevent(struct work_struct *work) |
---|
| 929 | +{ |
---|
| 930 | + struct usbnet *dev = |
---|
| 931 | + container_of(work, struct usbnet, kevent); |
---|
| 932 | +#endif |
---|
| 933 | + int status; |
---|
| 934 | + |
---|
| 935 | + /* usb_clear_halt() needs a thread context */ |
---|
| 936 | + if (test_bit(EVENT_TX_HALT, &dev->flags)) { |
---|
| 937 | + |
---|
| 938 | + unlink_urbs(dev, &dev->txq); |
---|
| 939 | + status = usb_clear_halt(dev->udev, dev->out); |
---|
| 940 | + if (status < 0 |
---|
| 941 | + && status != -EPIPE |
---|
| 942 | + && status != -ESHUTDOWN) { |
---|
| 943 | + if (netif_msg_tx_err(dev)) |
---|
| 944 | + deverr(dev, "can't clear tx halt, status %d", |
---|
| 945 | + status); |
---|
| 946 | + } else { |
---|
| 947 | + clear_bit(EVENT_TX_HALT, &dev->flags); |
---|
| 948 | + if (status != -ESHUTDOWN) |
---|
| 949 | + netif_wake_queue(dev->net); |
---|
| 950 | + } |
---|
| 951 | + } |
---|
| 952 | + if (test_bit(EVENT_RX_HALT, &dev->flags)) { |
---|
| 953 | + |
---|
| 954 | + unlink_urbs(dev, &dev->rxq); |
---|
| 955 | + status = usb_clear_halt(dev->udev, dev->in); |
---|
| 956 | + if (status < 0 |
---|
| 957 | + && status != -EPIPE |
---|
| 958 | + && status != -ESHUTDOWN) { |
---|
| 959 | + if (netif_msg_rx_err(dev)) |
---|
| 960 | + deverr(dev, "can't clear rx halt, status %d", |
---|
| 961 | + status); |
---|
| 962 | + } else { |
---|
| 963 | + clear_bit(EVENT_RX_HALT, &dev->flags); |
---|
| 964 | + tasklet_schedule(&dev->bh); |
---|
| 965 | + } |
---|
| 966 | + } |
---|
| 967 | + |
---|
| 968 | + /* tasklet could resubmit itself forever if memory is tight */ |
---|
| 969 | + if (test_bit(EVENT_RX_MEMORY, &dev->flags)) { |
---|
| 970 | + struct urb *urb = NULL; |
---|
| 971 | + |
---|
| 972 | + if (netif_running(dev->net)) |
---|
| 973 | + urb = usb_alloc_urb(0, GFP_KERNEL); |
---|
| 974 | + else |
---|
| 975 | + clear_bit(EVENT_RX_MEMORY, &dev->flags); |
---|
| 976 | + if (urb != NULL) { |
---|
| 977 | + clear_bit(EVENT_RX_MEMORY, &dev->flags); |
---|
| 978 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) |
---|
| 979 | + urb->transfer_flags |= URB_ASYNC_UNLINK; |
---|
| 980 | +#endif |
---|
| 981 | + rx_submit(dev, urb, GFP_KERNEL); |
---|
| 982 | + tasklet_schedule(&dev->bh); |
---|
| 983 | + } |
---|
| 984 | + } |
---|
| 985 | + |
---|
| 986 | + if (test_bit(EVENT_LINK_RESET, &dev->flags)) { |
---|
| 987 | + struct driver_info *info = dev->driver_info; |
---|
| 988 | + |
---|
| 989 | + clear_bit(EVENT_LINK_RESET, &dev->flags); |
---|
| 990 | + if (info->link_reset) { |
---|
| 991 | + int retval; |
---|
| 992 | + retval = info->link_reset(dev); |
---|
| 993 | + if (retval < 0) { |
---|
| 994 | + devinfo(dev, |
---|
| 995 | + "link reset failed (%d) usbnet usb-%s-%s, %s", |
---|
| 996 | + retval, |
---|
| 997 | + dev->udev->bus->bus_name, |
---|
| 998 | + dev->udev->devpath, |
---|
| 999 | + info->description); |
---|
| 1000 | + } |
---|
| 1001 | + } |
---|
| 1002 | + } |
---|
| 1003 | + |
---|
| 1004 | + if (dev->flags) |
---|
| 1005 | + devdbg(dev, "kevent done, flags = 0x%lx", dev->flags); |
---|
| 1006 | +} |
---|
| 1007 | + |
---|
| 1008 | +/*-------------------------------------------------------------------------*/ |
---|
| 1009 | + |
---|
| 1010 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) |
---|
| 1011 | +static void tx_complete(struct urb *urb, struct pt_regs *regs) |
---|
| 1012 | +#else |
---|
| 1013 | +static void tx_complete(struct urb *urb) |
---|
| 1014 | +#endif |
---|
| 1015 | +{ |
---|
| 1016 | + struct sk_buff *skb = (struct sk_buff *) urb->context; |
---|
| 1017 | + struct skb_data *entry = (struct skb_data *) skb->cb; |
---|
| 1018 | + struct usbnet *dev = entry->dev; |
---|
| 1019 | + |
---|
| 1020 | + if (urb->status == 0) { |
---|
| 1021 | + dev->stats.tx_packets++; |
---|
| 1022 | + dev->stats.tx_bytes += entry->length; |
---|
| 1023 | + } else { |
---|
| 1024 | + dev->stats.tx_errors++; |
---|
| 1025 | + |
---|
| 1026 | + switch (urb->status) { |
---|
| 1027 | + case -EPIPE: |
---|
| 1028 | + axusbnet_defer_kevent(dev, EVENT_TX_HALT); |
---|
| 1029 | + break; |
---|
| 1030 | + |
---|
| 1031 | + /* software-driven interface shutdown */ |
---|
| 1032 | + case -ECONNRESET: /* async unlink */ |
---|
| 1033 | + case -ESHUTDOWN: /* hardware gone */ |
---|
| 1034 | + break; |
---|
| 1035 | + |
---|
| 1036 | + /* like rx, tx gets controller i/o faults during khubd delays */ |
---|
| 1037 | + /* and so it uses the same throttling mechanism. */ |
---|
| 1038 | + case -EPROTO: |
---|
| 1039 | + case -ETIME: |
---|
| 1040 | + case -EILSEQ: |
---|
| 1041 | + if (!timer_pending(&dev->delay)) { |
---|
| 1042 | + mod_timer(&dev->delay, |
---|
| 1043 | + jiffies + THROTTLE_JIFFIES); |
---|
| 1044 | + if (netif_msg_link(dev)) |
---|
| 1045 | + devdbg(dev, "tx throttle %d", |
---|
| 1046 | + urb->status); |
---|
| 1047 | + } |
---|
| 1048 | + netif_stop_queue(dev->net); |
---|
| 1049 | + break; |
---|
| 1050 | + default: |
---|
| 1051 | + if (netif_msg_tx_err(dev)) |
---|
| 1052 | + devdbg(dev, "tx err %d", entry->urb->status); |
---|
| 1053 | + break; |
---|
| 1054 | + } |
---|
| 1055 | + } |
---|
| 1056 | + |
---|
| 1057 | + urb->dev = NULL; |
---|
| 1058 | + entry->state = tx_done; |
---|
| 1059 | + (void) defer_bh(dev, skb, &dev->txq, tx_done); |
---|
| 1060 | +} |
---|
| 1061 | + |
---|
| 1062 | +/*-------------------------------------------------------------------------*/ |
---|
| 1063 | + |
---|
| 1064 | +static |
---|
| 1065 | +void axusbnet_tx_timeout(struct net_device *net) |
---|
| 1066 | +{ |
---|
| 1067 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1068 | + struct driver_info *info = dev->driver_info; |
---|
| 1069 | + |
---|
| 1070 | + if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) { |
---|
| 1071 | + unlink_urbs(dev, &dev->txq); |
---|
| 1072 | + } |
---|
| 1073 | + tasklet_schedule(&dev->bh); |
---|
| 1074 | + |
---|
| 1075 | + /* FIXME: device recovery -- reset? */ |
---|
| 1076 | +} |
---|
| 1077 | + |
---|
| 1078 | +/*-------------------------------------------------------------------------*/ |
---|
| 1079 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) |
---|
| 1080 | +static int |
---|
| 1081 | +#else |
---|
| 1082 | +static netdev_tx_t |
---|
| 1083 | +#endif |
---|
| 1084 | +axusbnet_start_xmit(struct sk_buff *skb, struct net_device *net) |
---|
| 1085 | +{ |
---|
| 1086 | + struct usbnet *dev = netdev_priv(net); |
---|
| 1087 | + int length; |
---|
| 1088 | + struct urb *urb = NULL; |
---|
| 1089 | + struct skb_data *entry; |
---|
| 1090 | + struct driver_info *info = dev->driver_info; |
---|
| 1091 | + unsigned long flags; |
---|
| 1092 | + int retval; |
---|
| 1093 | + |
---|
| 1094 | + /* some devices want funky USB-level framing, for */ |
---|
| 1095 | + /* win32 driver (usually) and/or hardware quirks */ |
---|
| 1096 | + if (info->tx_fixup) { |
---|
| 1097 | + skb = info->tx_fixup(dev, skb, GFP_ATOMIC); |
---|
| 1098 | + if (!skb) { |
---|
| 1099 | + if (netif_msg_tx_err(dev)) |
---|
| 1100 | + devdbg(dev, "can't tx_fixup skb"); |
---|
| 1101 | + goto drop; |
---|
| 1102 | + } |
---|
| 1103 | + } |
---|
| 1104 | + length = skb->len; |
---|
| 1105 | + |
---|
| 1106 | + urb = usb_alloc_urb(0, GFP_ATOMIC); |
---|
| 1107 | + if (!urb) { |
---|
| 1108 | + if (netif_msg_tx_err(dev)) |
---|
| 1109 | + devdbg(dev, "no urb"); |
---|
| 1110 | + goto drop; |
---|
| 1111 | + } |
---|
| 1112 | + |
---|
| 1113 | + entry = (struct skb_data *) skb->cb; |
---|
| 1114 | + entry->urb = urb; |
---|
| 1115 | + entry->dev = dev; |
---|
| 1116 | + entry->state = tx_start; |
---|
| 1117 | + entry->length = length; |
---|
| 1118 | + |
---|
| 1119 | + usb_fill_bulk_urb(urb, dev->udev, dev->out, skb->data, |
---|
| 1120 | + skb->len, tx_complete, skb); |
---|
| 1121 | + |
---|
| 1122 | + /* don't assume the hardware handles USB_ZERO_PACKET |
---|
| 1123 | + * NOTE: strictly conforming cdc-ether devices should expect |
---|
| 1124 | + * the ZLP here, but ignore the one-byte packet. |
---|
| 1125 | + */ |
---|
| 1126 | + if (!(info->flags & FLAG_SEND_ZLP) && (length % dev->maxpacket) == 0) { |
---|
| 1127 | + urb->transfer_buffer_length++; |
---|
| 1128 | + if (skb_tailroom(skb)) { |
---|
| 1129 | + skb->data[skb->len] = 0; |
---|
| 1130 | + __skb_put(skb, 1); |
---|
| 1131 | + } |
---|
| 1132 | + } |
---|
| 1133 | + |
---|
| 1134 | + spin_lock_irqsave(&dev->txq.lock, flags); |
---|
| 1135 | + |
---|
| 1136 | + switch ((retval = usb_submit_urb(urb, GFP_ATOMIC))) { |
---|
| 1137 | + case -EPIPE: |
---|
| 1138 | + netif_stop_queue(net); |
---|
| 1139 | + axusbnet_defer_kevent(dev, EVENT_TX_HALT); |
---|
| 1140 | + break; |
---|
| 1141 | + default: |
---|
| 1142 | + if (netif_msg_tx_err(dev)) |
---|
| 1143 | + devdbg(dev, "tx: submit urb err %d", retval); |
---|
| 1144 | + break; |
---|
| 1145 | + case 0: |
---|
| 1146 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0) |
---|
| 1147 | + net->trans_start = jiffies; |
---|
| 1148 | +#else |
---|
| 1149 | + netif_trans_update(net); |
---|
| 1150 | +#endif |
---|
| 1151 | + __skb_queue_tail(&dev->txq, skb); |
---|
| 1152 | + if (dev->txq.qlen >= TX_QLEN(dev)) |
---|
| 1153 | + netif_stop_queue(net); |
---|
| 1154 | + } |
---|
| 1155 | + spin_unlock_irqrestore(&dev->txq.lock, flags); |
---|
| 1156 | + |
---|
| 1157 | + if (retval) { |
---|
| 1158 | + if (netif_msg_tx_err(dev)) |
---|
| 1159 | + devdbg(dev, "drop, code %d", retval); |
---|
| 1160 | +drop: |
---|
| 1161 | + dev->stats.tx_dropped++; |
---|
| 1162 | + if (skb) |
---|
| 1163 | + dev_kfree_skb_any(skb); |
---|
| 1164 | + usb_free_urb(urb); |
---|
| 1165 | + } else if (netif_msg_tx_queued(dev)) { |
---|
| 1166 | + devdbg(dev, "> tx, len %d, type 0x%x", |
---|
| 1167 | + length, skb->protocol); |
---|
| 1168 | + } |
---|
| 1169 | + return NETDEV_TX_OK; |
---|
| 1170 | +} |
---|
| 1171 | + |
---|
| 1172 | +/*-------------------------------------------------------------------------*/ |
---|
| 1173 | + |
---|
| 1174 | +/* tasklet (work deferred from completions, in_irq) or timer */ |
---|
| 1175 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) |
---|
| 1176 | +static void axusbnet_bh(unsigned long param) |
---|
| 1177 | +#else |
---|
| 1178 | +static void axusbnet_bh (struct timer_list *t) |
---|
| 1179 | +#endif |
---|
| 1180 | +{ |
---|
| 1181 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) |
---|
| 1182 | + struct usbnet *dev = (struct usbnet *) param; |
---|
| 1183 | +#else |
---|
| 1184 | + struct usbnet *dev = from_timer(dev, t, delay); |
---|
| 1185 | +#endif |
---|
| 1186 | + struct sk_buff *skb; |
---|
| 1187 | + struct skb_data *entry = NULL; |
---|
| 1188 | + |
---|
| 1189 | + while ((skb = skb_dequeue(&dev->done))) { |
---|
| 1190 | + entry = (struct skb_data *) skb->cb; |
---|
| 1191 | + switch (entry->state) { |
---|
| 1192 | + case rx_done: |
---|
| 1193 | + entry->state = rx_cleanup; |
---|
| 1194 | + rx_process(dev, skb); |
---|
| 1195 | + continue; |
---|
| 1196 | + case tx_done: |
---|
| 1197 | + case rx_cleanup: |
---|
| 1198 | + usb_free_urb(entry->urb); |
---|
| 1199 | + dev_kfree_skb(skb); |
---|
| 1200 | + continue; |
---|
| 1201 | + default: |
---|
| 1202 | + devdbg(dev, "bogus skb state %d", entry->state); |
---|
| 1203 | + } |
---|
| 1204 | + } |
---|
| 1205 | + |
---|
| 1206 | + /* restart RX again after disabling due to high error rate */ |
---|
| 1207 | + clear_bit(EVENT_RX_KILL, &dev->flags); |
---|
| 1208 | + |
---|
| 1209 | + /* waiting for all pending urbs to complete? */ |
---|
| 1210 | + if (dev->wait) { |
---|
| 1211 | + if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) |
---|
| 1212 | + wake_up(dev->wait); |
---|
| 1213 | + |
---|
| 1214 | + /* or are we maybe short a few urbs? */ |
---|
| 1215 | + } else if (netif_running(dev->net) |
---|
| 1216 | + && netif_device_present(dev->net) |
---|
| 1217 | + && !timer_pending(&dev->delay) |
---|
| 1218 | + && !test_bit(EVENT_RX_HALT, &dev->flags)) { |
---|
| 1219 | + int temp = dev->rxq.qlen; |
---|
| 1220 | + int qlen = RX_QLEN(dev); |
---|
| 1221 | + |
---|
| 1222 | + if (temp < qlen) { |
---|
| 1223 | + struct urb *urb = NULL; |
---|
| 1224 | + int i; |
---|
| 1225 | + |
---|
| 1226 | + /* don't refill the queue all at once */ |
---|
| 1227 | + for (i = 0; i < 10 && dev->rxq.qlen < qlen; i++) { |
---|
| 1228 | + urb = usb_alloc_urb(0, GFP_ATOMIC); |
---|
| 1229 | + if (urb != NULL) { |
---|
| 1230 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) |
---|
| 1231 | + urb->transfer_flags |= URB_ASYNC_UNLINK; |
---|
| 1232 | +#endif |
---|
| 1233 | + rx_submit(dev, urb, GFP_ATOMIC); |
---|
| 1234 | + } |
---|
| 1235 | + } |
---|
| 1236 | + if (temp != dev->rxq.qlen && netif_msg_link(dev)) |
---|
| 1237 | + devdbg(dev, "rxqlen %d --> %d", |
---|
| 1238 | + temp, dev->rxq.qlen); |
---|
| 1239 | + if (dev->rxq.qlen < qlen) |
---|
| 1240 | + tasklet_schedule(&dev->bh); |
---|
| 1241 | + } |
---|
| 1242 | + if (dev->txq.qlen < TX_QLEN(dev)) |
---|
| 1243 | + netif_wake_queue(dev->net); |
---|
| 1244 | + } |
---|
| 1245 | +} |
---|
| 1246 | + |
---|
| 1247 | + |
---|
| 1248 | +/*------------------------------------------------------------------------- |
---|
| 1249 | + * |
---|
| 1250 | + * USB Device Driver support |
---|
| 1251 | + * |
---|
| 1252 | + *-------------------------------------------------------------------------*/ |
---|
| 1253 | + |
---|
| 1254 | +/* precondition: never called in_interrupt */ |
---|
| 1255 | + |
---|
| 1256 | +static |
---|
| 1257 | +void axusbnet_disconnect(struct usb_interface *intf) |
---|
| 1258 | +{ |
---|
| 1259 | + struct usbnet *dev; |
---|
| 1260 | + struct usb_device *xdev; |
---|
| 1261 | + struct net_device *net; |
---|
| 1262 | + |
---|
| 1263 | + dev = usb_get_intfdata(intf); |
---|
| 1264 | + usb_set_intfdata(intf, NULL); |
---|
| 1265 | + if (!dev) |
---|
| 1266 | + return; |
---|
| 1267 | + |
---|
| 1268 | + xdev = interface_to_usbdev(intf); |
---|
| 1269 | + |
---|
| 1270 | + if (netif_msg_probe(dev)) |
---|
| 1271 | + devinfo(dev, "unregister '%s' usb-%s-%s, %s", |
---|
| 1272 | + intf->dev.driver->name, |
---|
| 1273 | + xdev->bus->bus_name, xdev->devpath, |
---|
| 1274 | + dev->driver_info->description); |
---|
| 1275 | + |
---|
| 1276 | + net = dev->net; |
---|
| 1277 | + unregister_netdev(net); |
---|
| 1278 | + |
---|
| 1279 | + /* we don't hold rtnl here ... */ |
---|
| 1280 | + flush_scheduled_work(); |
---|
| 1281 | + |
---|
| 1282 | + if (dev->driver_info->unbind) |
---|
| 1283 | + dev->driver_info->unbind(dev, intf); |
---|
| 1284 | + |
---|
| 1285 | + free_netdev(net); |
---|
| 1286 | + usb_put_dev(xdev); |
---|
| 1287 | +} |
---|
| 1288 | + |
---|
| 1289 | +/*-------------------------------------------------------------------------*/ |
---|
| 1290 | + |
---|
| 1291 | +/* precondition: never called in_interrupt */ |
---|
| 1292 | + |
---|
| 1293 | +static int |
---|
| 1294 | +axusbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod) |
---|
| 1295 | +{ |
---|
| 1296 | + struct usbnet *dev; |
---|
| 1297 | + struct net_device *net; |
---|
| 1298 | + struct usb_host_interface *interface; |
---|
| 1299 | + struct driver_info *info; |
---|
| 1300 | + struct usb_device *xdev; |
---|
| 1301 | + int status; |
---|
| 1302 | + const char *name; |
---|
| 1303 | + |
---|
| 1304 | + name = udev->dev.driver->name; |
---|
| 1305 | + info = (struct driver_info *) prod->driver_info; |
---|
| 1306 | + if (!info) { |
---|
| 1307 | + printk(KERN_ERR "blacklisted by %s\n", name); |
---|
| 1308 | + return -ENODEV; |
---|
| 1309 | + } |
---|
| 1310 | + xdev = interface_to_usbdev(udev); |
---|
| 1311 | + interface = udev->cur_altsetting; |
---|
| 1312 | + |
---|
| 1313 | + usb_get_dev(xdev); |
---|
| 1314 | + |
---|
| 1315 | + status = -ENOMEM; |
---|
| 1316 | + |
---|
| 1317 | + /* set up our own records */ |
---|
| 1318 | + net = alloc_etherdev(sizeof(*dev)); |
---|
| 1319 | + if (!net) { |
---|
| 1320 | + printk(KERN_ERR "can't kmalloc dev"); |
---|
| 1321 | + goto out; |
---|
| 1322 | + } |
---|
| 1323 | + |
---|
| 1324 | + dev = netdev_priv(net); |
---|
| 1325 | + dev->udev = xdev; |
---|
| 1326 | + dev->intf = udev; |
---|
| 1327 | + dev->driver_info = info; |
---|
| 1328 | + dev->driver_name = name; |
---|
| 1329 | + dev->msg_enable = netif_msg_init(msg_level, NETIF_MSG_DRV | |
---|
| 1330 | + NETIF_MSG_PROBE | NETIF_MSG_LINK); |
---|
| 1331 | + skb_queue_head_init(&dev->rxq); |
---|
| 1332 | + skb_queue_head_init(&dev->txq); |
---|
| 1333 | + skb_queue_head_init(&dev->done); |
---|
| 1334 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) |
---|
| 1335 | + dev->bh.func = axusbnet_bh; |
---|
| 1336 | + dev->bh.data = (unsigned long) dev; |
---|
| 1337 | +#else |
---|
| 1338 | + dev->bh.func = (void (*)(unsigned long))axusbnet_bh; |
---|
| 1339 | + dev->bh.data = (unsigned long)&dev->delay; |
---|
| 1340 | +#endif |
---|
| 1341 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
---|
| 1342 | + INIT_WORK(&dev->kevent, kevent, dev); |
---|
| 1343 | +#else |
---|
| 1344 | + INIT_WORK(&dev->kevent, kevent); |
---|
| 1345 | +#endif |
---|
| 1346 | + |
---|
| 1347 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) |
---|
| 1348 | + dev->delay.function = axusbnet_bh; |
---|
| 1349 | + dev->delay.data = (unsigned long) dev; |
---|
| 1350 | + init_timer(&dev->delay); |
---|
| 1351 | +#else |
---|
| 1352 | + timer_setup(&dev->delay, axusbnet_bh, 0); |
---|
| 1353 | +#endif |
---|
| 1354 | + /* mutex_init(&dev->phy_mutex); */ |
---|
| 1355 | + |
---|
| 1356 | + dev->net = net; |
---|
| 1357 | + |
---|
| 1358 | + /* rx and tx sides can use different message sizes; |
---|
| 1359 | + * bind() should set rx_urb_size in that case. |
---|
| 1360 | + */ |
---|
| 1361 | + dev->hard_mtu = net->mtu + net->hard_header_len; |
---|
| 1362 | + |
---|
| 1363 | +#if 0 |
---|
| 1364 | + /* dma_supported() is deeply broken on almost all architectures */ |
---|
| 1365 | + /* possible with some EHCI controllers */ |
---|
| 1366 | + if (dma_supported(&udev->dev, DMA_BIT_MASK(64))) |
---|
| 1367 | + net->features |= NETIF_F_HIGHDMA; |
---|
| 1368 | +#endif |
---|
| 1369 | + |
---|
| 1370 | +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30) |
---|
| 1371 | + net->open = axusbnet_open, |
---|
| 1372 | + net->stop = axusbnet_stop, |
---|
| 1373 | + net->hard_start_xmit = axusbnet_start_xmit, |
---|
| 1374 | + net->tx_timeout = axusbnet_tx_timeout, |
---|
| 1375 | + net->get_stats = axusbnet_get_stats; |
---|
| 1376 | +#endif |
---|
| 1377 | + |
---|
| 1378 | + net->watchdog_timeo = TX_TIMEOUT_JIFFIES; |
---|
| 1379 | + net->ethtool_ops = &axusbnet_ethtool_ops; |
---|
| 1380 | + |
---|
| 1381 | + /* allow device-specific bind/init procedures */ |
---|
| 1382 | + /* NOTE net->name still not usable ... */ |
---|
| 1383 | + status = info->bind(dev, udev); |
---|
| 1384 | + if (status < 0) { |
---|
| 1385 | + deverr(dev, "Binding device failed: %d", status); |
---|
| 1386 | + goto out1; |
---|
| 1387 | + } |
---|
| 1388 | + |
---|
| 1389 | + /* maybe the remote can't receive an Ethernet MTU */ |
---|
| 1390 | + if (net->mtu > (dev->hard_mtu - net->hard_header_len)) |
---|
| 1391 | + net->mtu = dev->hard_mtu - net->hard_header_len; |
---|
| 1392 | + |
---|
| 1393 | + status = init_status(dev, udev); |
---|
| 1394 | + if (status < 0) |
---|
| 1395 | + goto out3; |
---|
| 1396 | + |
---|
| 1397 | + if (!dev->rx_urb_size) |
---|
| 1398 | + dev->rx_urb_size = dev->hard_mtu; |
---|
| 1399 | + dev->maxpacket = usb_maxpacket(dev->udev, dev->out, 1); |
---|
| 1400 | + |
---|
| 1401 | + SET_NETDEV_DEV(net, &udev->dev); |
---|
| 1402 | + status = register_netdev(net); |
---|
| 1403 | + if (status) { |
---|
| 1404 | + deverr(dev, "net device registration failed: %d", status); |
---|
| 1405 | + goto out3; |
---|
| 1406 | + } |
---|
| 1407 | + |
---|
| 1408 | + if (netif_msg_probe(dev)) |
---|
| 1409 | + devinfo(dev, "register '%s' at usb-%s-%s, %s, %pM", |
---|
| 1410 | + udev->dev.driver->name, |
---|
| 1411 | + xdev->bus->bus_name, xdev->devpath, |
---|
| 1412 | + dev->driver_info->description, |
---|
| 1413 | + net->dev_addr); |
---|
| 1414 | + |
---|
| 1415 | + /* ok, it's ready to go. */ |
---|
| 1416 | + usb_set_intfdata(udev, dev); |
---|
| 1417 | + |
---|
| 1418 | + /* start as if the link is up */ |
---|
| 1419 | + netif_device_attach(net); |
---|
| 1420 | + |
---|
| 1421 | + return 0; |
---|
| 1422 | + |
---|
| 1423 | +out3: |
---|
| 1424 | + if (info->unbind) |
---|
| 1425 | + info->unbind(dev, udev); |
---|
| 1426 | +out1: |
---|
| 1427 | + free_netdev(net); |
---|
| 1428 | +out: |
---|
| 1429 | + usb_put_dev(xdev); |
---|
| 1430 | + return status; |
---|
| 1431 | +} |
---|
| 1432 | + |
---|
| 1433 | +/*-------------------------------------------------------------------------*/ |
---|
| 1434 | + |
---|
| 1435 | +/* |
---|
| 1436 | + * suspend the whole driver as soon as the first interface is suspended |
---|
| 1437 | + * resume only when the last interface is resumed |
---|
| 1438 | + */ |
---|
| 1439 | + |
---|
| 1440 | +static int axusbnet_suspend(struct usb_interface *intf, |
---|
| 1441 | +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10) |
---|
| 1442 | +pm_message_t message) |
---|
| 1443 | +#else |
---|
| 1444 | +u32 message) |
---|
| 1445 | +#endif |
---|
| 1446 | +{ |
---|
| 1447 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 1448 | + |
---|
| 1449 | + if (!dev->suspend_count++) { |
---|
| 1450 | + /* |
---|
| 1451 | + * accelerate emptying of the rx and queues, to avoid |
---|
| 1452 | + * having everything error out. |
---|
| 1453 | + */ |
---|
| 1454 | + netif_device_detach(dev->net); |
---|
| 1455 | + (void) unlink_urbs(dev, &dev->rxq); |
---|
| 1456 | + (void) unlink_urbs(dev, &dev->txq); |
---|
| 1457 | + usb_kill_urb(dev->interrupt); |
---|
| 1458 | + /* |
---|
| 1459 | + * reattach so runtime management can use and |
---|
| 1460 | + * wake the device |
---|
| 1461 | + */ |
---|
| 1462 | + netif_device_attach(dev->net); |
---|
| 1463 | + } |
---|
| 1464 | + return 0; |
---|
| 1465 | +} |
---|
| 1466 | + |
---|
| 1467 | +static int |
---|
| 1468 | +axusbnet_resume(struct usb_interface *intf) |
---|
| 1469 | +{ |
---|
| 1470 | + struct usbnet *dev = usb_get_intfdata(intf); |
---|
| 1471 | + int retval = 0; |
---|
| 1472 | + |
---|
| 1473 | + if (!--dev->suspend_count) |
---|
| 1474 | + tasklet_schedule(&dev->bh); |
---|
| 1475 | + |
---|
| 1476 | + retval = init_status(dev, intf); |
---|
| 1477 | + if (retval < 0) |
---|
| 1478 | + return retval; |
---|
| 1479 | + |
---|
| 1480 | + if (dev->interrupt) { |
---|
| 1481 | + retval = usb_submit_urb(dev->interrupt, GFP_KERNEL); |
---|
| 1482 | + if (retval < 0 && netif_msg_ifup(dev)) |
---|
| 1483 | + deverr(dev, "intr submit %d", retval); |
---|
| 1484 | + } |
---|
| 1485 | + |
---|
| 1486 | + return retval; |
---|
| 1487 | +} |
---|
| 1488 | + |
---|
.. | .. |
---|
| 1 | +/* |
---|
| 2 | + * USB Networking Link Interface |
---|
| 3 | + * |
---|
| 4 | + * Copyright (C) 2000-2005 by David Brownell <dbrownell@users.sourceforge.net> |
---|
| 5 | + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> |
---|
| 6 | + * |
---|
| 7 | + * This program is free software; you can redistribute it and/or modify |
---|
| 8 | + * it under the terms of the GNU General Public License as published by |
---|
| 9 | + * the Free Software Foundation; either version 2 of the License, or |
---|
| 10 | + * (at your option) any later version. |
---|
| 11 | + * |
---|
| 12 | + * This program is distributed in the hope that it will be useful, |
---|
| 13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 15 | + * GNU General Public License for more details. |
---|
| 16 | + * |
---|
| 17 | + * You should have received a copy of the GNU General Public License |
---|
| 18 | + * along with this program; if not, write to the Free Software |
---|
| 19 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 20 | + */ |
---|
| 21 | + |
---|
| 22 | +#ifndef __LINUX_USB_USBNET_H |
---|
| 23 | +#define __LINUX_USB_USBNET_H |
---|
| 24 | + |
---|
| 25 | +#ifndef gfp_t |
---|
| 26 | +#define gfp_t int |
---|
| 27 | +#endif |
---|
| 28 | + |
---|
| 29 | +/* interface from usbnet core to each USB networking link we handle */ |
---|
| 30 | +struct usbnet { |
---|
| 31 | + /* housekeeping */ |
---|
| 32 | + struct usb_device *udev; |
---|
| 33 | + struct usb_interface *intf; |
---|
| 34 | + struct driver_info *driver_info; |
---|
| 35 | + const char *driver_name; |
---|
| 36 | + void *driver_priv; |
---|
| 37 | + wait_queue_head_t *wait; |
---|
| 38 | + /* struct mutex phy_mutex; */ |
---|
| 39 | + unsigned char suspend_count; |
---|
| 40 | + unsigned char pkt_cnt, pkt_err; |
---|
| 41 | + |
---|
| 42 | + /* i/o info: pipes etc */ |
---|
| 43 | + unsigned in, out; |
---|
| 44 | + struct usb_host_endpoint *status; |
---|
| 45 | + unsigned maxpacket; |
---|
| 46 | + struct timer_list delay; |
---|
| 47 | + |
---|
| 48 | + /* protocol/interface state */ |
---|
| 49 | + struct net_device *net; |
---|
| 50 | + struct net_device_stats stats; |
---|
| 51 | + int msg_enable; |
---|
| 52 | + unsigned long data[5]; |
---|
| 53 | + u32 xid; |
---|
| 54 | + u32 hard_mtu; /* count any extra framing */ |
---|
| 55 | + size_t rx_urb_size; /* size for rx urbs */ |
---|
| 56 | + struct mii_if_info mii; |
---|
| 57 | + |
---|
| 58 | + /* various kinds of pending driver work */ |
---|
| 59 | + struct sk_buff_head rxq; |
---|
| 60 | + struct sk_buff_head txq; |
---|
| 61 | + struct sk_buff_head done; |
---|
| 62 | + struct sk_buff_head rxq_pause; |
---|
| 63 | + struct urb *interrupt; |
---|
| 64 | + struct tasklet_struct bh; |
---|
| 65 | + |
---|
| 66 | + struct work_struct kevent; |
---|
| 67 | + unsigned long flags; |
---|
| 68 | +# define EVENT_TX_HALT 0 |
---|
| 69 | +# define EVENT_RX_HALT 1 |
---|
| 70 | +# define EVENT_RX_MEMORY 2 |
---|
| 71 | +# define EVENT_STS_SPLIT 3 |
---|
| 72 | +# define EVENT_LINK_RESET 4 |
---|
| 73 | +# define EVENT_RX_PAUSED 5 |
---|
| 74 | +# define EVENT_RX_KILL 10 |
---|
| 75 | + |
---|
| 76 | + void *priv; /* point to minidriver private data */ |
---|
| 77 | + unsigned char rx_size; |
---|
| 78 | + unsigned char reg_monitor; |
---|
| 79 | +}; |
---|
| 80 | + |
---|
| 81 | +static inline struct usb_driver *driver_of(struct usb_interface *intf) |
---|
| 82 | +{ |
---|
| 83 | + return to_usb_driver(intf->dev.driver); |
---|
| 84 | +} |
---|
| 85 | + |
---|
| 86 | +/* interface from the device/framing level "minidriver" to core */ |
---|
| 87 | +struct driver_info { |
---|
| 88 | + char *description; |
---|
| 89 | + |
---|
| 90 | + int flags; |
---|
| 91 | +/* framing is CDC Ethernet, not writing ZLPs (hw issues), or optionally: */ |
---|
| 92 | +#define FLAG_FRAMING_NC 0x0001 /* guard against device dropouts */ |
---|
| 93 | +#define FLAG_FRAMING_GL 0x0002 /* genelink batches packets */ |
---|
| 94 | +#define FLAG_FRAMING_Z 0x0004 /* zaurus adds a trailer */ |
---|
| 95 | +#define FLAG_FRAMING_RN 0x0008 /* RNDIS batches, plus huge header */ |
---|
| 96 | + |
---|
| 97 | +#define FLAG_NO_SETINT 0x0010 /* device can't set_interface() */ |
---|
| 98 | +#define FLAG_ETHER 0x0020 /* maybe use "eth%d" names */ |
---|
| 99 | + |
---|
| 100 | +#define FLAG_FRAMING_AX 0x0040 /* AX88772/178 packets */ |
---|
| 101 | +#define FLAG_WLAN 0x0080 /* use "wlan%d" names */ |
---|
| 102 | +#define FLAG_AVOID_UNLINK_URBS 0x0100 /* don't unlink urbs at usbnet_stop() */ |
---|
| 103 | +#define FLAG_SEND_ZLP 0x0200 /* hw requires ZLPs are sent */ |
---|
| 104 | +#define FLAG_HW_IP_ALIGNMENT 0x0400 /* AX88772B support hardware IP alignment */ |
---|
| 105 | + |
---|
| 106 | + |
---|
| 107 | + /* init device ... can sleep, or cause probe() failure */ |
---|
| 108 | + int (*bind)(struct usbnet *, struct usb_interface *); |
---|
| 109 | + |
---|
| 110 | + /* cleanup device ... can sleep, but can't fail */ |
---|
| 111 | + void (*unbind)(struct usbnet *, struct usb_interface *); |
---|
| 112 | + |
---|
| 113 | + /* reset device ... can sleep */ |
---|
| 114 | + int (*reset)(struct usbnet *); |
---|
| 115 | + |
---|
| 116 | + /* stop device ... can sleep */ |
---|
| 117 | + int (*stop)(struct usbnet *); |
---|
| 118 | + |
---|
| 119 | + /* see if peer is connected ... can sleep */ |
---|
| 120 | + int (*check_connect)(struct usbnet *); |
---|
| 121 | + |
---|
| 122 | + /* for status polling */ |
---|
| 123 | + void (*status)(struct usbnet *, struct urb *); |
---|
| 124 | + |
---|
| 125 | + /* link reset handling, called from defer_kevent */ |
---|
| 126 | + int (*link_reset)(struct usbnet *); |
---|
| 127 | + |
---|
| 128 | + /* fixup rx packet (strip framing) */ |
---|
| 129 | + int (*rx_fixup)(struct usbnet *dev, struct sk_buff *skb); |
---|
| 130 | + |
---|
| 131 | + /* fixup tx packet (add framing) */ |
---|
| 132 | + struct sk_buff *(*tx_fixup)(struct usbnet *dev, |
---|
| 133 | + struct sk_buff *skb, gfp_t flags); |
---|
| 134 | + |
---|
| 135 | + /* early initialization code, can sleep. This is for minidrivers |
---|
| 136 | + * having 'subminidrivers' that need to do extra initialization |
---|
| 137 | + * right after minidriver have initialized hardware. */ |
---|
| 138 | + int (*early_init)(struct usbnet *dev); |
---|
| 139 | + |
---|
| 140 | + /* called by minidriver when receiving indication */ |
---|
| 141 | + void (*indication)(struct usbnet *dev, void *ind, int indlen); |
---|
| 142 | + |
---|
| 143 | + /* for new devices, use the descriptor-reading code instead */ |
---|
| 144 | + int in; /* rx endpoint */ |
---|
| 145 | + int out; /* tx endpoint */ |
---|
| 146 | + |
---|
| 147 | + unsigned long data; /* Misc driver specific data */ |
---|
| 148 | +}; |
---|
| 149 | + |
---|
| 150 | +/* Drivers that reuse some of the standard USB CDC infrastructure |
---|
| 151 | + * (notably, using multiple interfaces according to the CDC |
---|
| 152 | + * union descriptor) get some helper code. |
---|
| 153 | + */ |
---|
| 154 | +struct cdc_state { |
---|
| 155 | + struct usb_cdc_header_desc *header; |
---|
| 156 | + struct usb_cdc_union_desc *u; |
---|
| 157 | + struct usb_cdc_ether_desc *ether; |
---|
| 158 | + struct usb_interface *control; |
---|
| 159 | + struct usb_interface *data; |
---|
| 160 | +}; |
---|
| 161 | + |
---|
| 162 | +/* CDC and RNDIS support the same host-chosen packet filters for IN transfers */ |
---|
| 163 | +#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ |
---|
| 164 | + |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ |
---|
| 165 | + |USB_CDC_PACKET_TYPE_PROMISCUOUS \ |
---|
| 166 | + |USB_CDC_PACKET_TYPE_DIRECTED) |
---|
| 167 | + |
---|
| 168 | + |
---|
| 169 | +/* we record the state for each of our queued skbs */ |
---|
| 170 | +enum skb_state { |
---|
| 171 | + illegal = 0, |
---|
| 172 | + tx_start, tx_done, |
---|
| 173 | + rx_start, rx_done, rx_cleanup, |
---|
| 174 | + unlink_start |
---|
| 175 | +}; |
---|
| 176 | + |
---|
| 177 | +struct skb_data { /* skb->cb is one of these */ |
---|
| 178 | + struct urb *urb; |
---|
| 179 | + struct usbnet *dev; |
---|
| 180 | + enum skb_state state; |
---|
| 181 | + size_t length; |
---|
| 182 | +}; |
---|
| 183 | + |
---|
| 184 | +#ifndef skb_queue_walk_safe |
---|
| 185 | +#define skb_queue_walk_safe(queue, skb, tmp) \ |
---|
| 186 | + for (skb = (queue)->next, tmp = skb->next; \ |
---|
| 187 | + skb != (struct sk_buff *)(queue); \ |
---|
| 188 | + skb = tmp, tmp = skb->next) |
---|
| 189 | +#endif |
---|
| 190 | + |
---|
| 191 | +/* messaging support includes the interface name, so it must not be |
---|
| 192 | + * used before it has one ... notably, in minidriver bind() calls. |
---|
| 193 | + */ |
---|
| 194 | +#ifdef DEBUG |
---|
| 195 | +#define devdbg(usbnet, fmt, arg...) \ |
---|
| 196 | + printk("%s: " fmt "\n" , (usbnet)->net->name , ## arg) |
---|
| 197 | +#else |
---|
| 198 | +#define devdbg(usbnet, fmt, arg...) \ |
---|
| 199 | + ({ if (0) printk("%s: " fmt "\n" , (usbnet)->net->name , \ |
---|
| 200 | + ## arg); 0; }) |
---|
| 201 | +#endif |
---|
| 202 | + |
---|
| 203 | +#define deverr(usbnet, fmt, arg...) \ |
---|
| 204 | + printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg) |
---|
| 205 | +#define devwarn(usbnet, fmt, arg...) \ |
---|
| 206 | + printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg) |
---|
| 207 | + |
---|
| 208 | +#define devinfo(usbnet, fmt, arg...) \ |
---|
| 209 | + printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \ |
---|
| 210 | + |
---|
| 211 | + |
---|
| 212 | +#endif /* __LINUX_USB_USBNET_H */ |
---|
.. | .. |
---|
| 1 | +============================================================================ |
---|
| 2 | +ASIX AX88178 USB 2.0 Gigabit Ethernet Network Adapter |
---|
| 3 | +ASIX AX88772 USB 2.0 Fast Ethernet Network Adapter |
---|
| 4 | +ASIX AX88772A USB 2.0 Fast Ethernet Network Adapter |
---|
| 5 | +ASIX AX88760 USB 2.0 MTT HUB and USB 2.0 to Fast Ethernet Combo Controller |
---|
| 6 | +ASIX AX88772B USB 2.0 Fast Ethernet Network Adapter |
---|
| 7 | +ASIX AX88772C USB 2.0 Fast Ethernet Network Adapter |
---|
| 8 | +Driver Compilation & Configuration on the Linux |
---|
| 9 | +============================================================================ |
---|
| 10 | + |
---|
| 11 | +This driver has been verified on Linux kernel 2.6.14 and later. |
---|
| 12 | + |
---|
| 13 | +================ |
---|
| 14 | +Prerequisites |
---|
| 15 | +================ |
---|
| 16 | + |
---|
| 17 | +Prepare to build the driver, you need the Linux kernel sources installed on the |
---|
| 18 | +build machine, and make sure that the version of the running kernel must match |
---|
| 19 | +the installed kernel sources. If you don't have the kernel sources, you can get |
---|
| 20 | +it from www.kernel.org or contact to your Linux distributor. If you don't know |
---|
| 21 | +how to do, please refer to KERNEL-HOWTO. |
---|
| 22 | + |
---|
| 23 | +Note: Please make sure the kernel is built with one of the "Support for |
---|
| 24 | + Host-side, EHCI, OHCI, or UHCI" option support. |
---|
| 25 | + |
---|
| 26 | + |
---|
| 27 | +=========================== |
---|
| 28 | +Conditional Compilation Flag |
---|
| 29 | +=========================== |
---|
| 30 | +[AX_FORCE_BUFF_ALIGN] |
---|
| 31 | +Description: |
---|
| 32 | + There are alignment issues of USB buffer in some USB host controllers. |
---|
| 33 | + Turn on this flag if the implementation of your USB host controller |
---|
| 34 | + cannot handle non-double word aligned buffer. |
---|
| 35 | + When turn on this flag, driver will fixup egress packet aligned on double |
---|
| 36 | + word boundary before deliver to USB host controller. |
---|
| 37 | +Setting: |
---|
| 38 | + 1 -> Enable TX buffers forced on double word alignment. |
---|
| 39 | + 0 -> Disable TX buffers forced on double word alignment. |
---|
| 40 | +Default: |
---|
| 41 | + 0 |
---|
| 42 | + |
---|
| 43 | + |
---|
| 44 | +================ |
---|
| 45 | +Getting Start |
---|
| 46 | +================ |
---|
| 47 | + |
---|
| 48 | +1. Extract the compressed driver source file to your template directory by the |
---|
| 49 | + following command: |
---|
| 50 | + |
---|
| 51 | + [root@localhost template]# tar -xf DRIVER_SOURCE_PACKAGE.tar.bz2 |
---|
| 52 | + |
---|
| 53 | +2. Now, the driver source files should be extracted under the current directory. |
---|
| 54 | + Executing the following command to compile the driver: |
---|
| 55 | + |
---|
| 56 | + [root@localhost template]# make |
---|
| 57 | + |
---|
| 58 | +3. If the compilation is well, the asix.ko will be created under the current |
---|
| 59 | + directory. |
---|
| 60 | + |
---|
| 61 | +4. If you want to use modprobe command to mount the driver, executing the |
---|
| 62 | + following command to install the driver into your Linux: |
---|
| 63 | + |
---|
| 64 | + [root@localhost template]# make install |
---|
| 65 | + |
---|
| 66 | + |
---|
| 67 | +================ |
---|
| 68 | +Usage |
---|
| 69 | +================ |
---|
| 70 | + |
---|
| 71 | +1. If you want to load the driver manually, go to the driver directory and |
---|
| 72 | + execute the following commands: |
---|
| 73 | + |
---|
| 74 | + [root@localhost template]# insmod asix.ko |
---|
| 75 | + |
---|
| 76 | +2. If you had installed the driver during driver compilation, then you can use |
---|
| 77 | + the following command to load the driver automatically. |
---|
| 78 | + |
---|
| 79 | + [root@localhost anywhere]# modprobe asix |
---|
| 80 | + |
---|
| 81 | +If you want to unload the driver, just executing the following command: |
---|
| 82 | + |
---|
| 83 | + [root@localhost anywhere]# rmmod asix |
---|
| 84 | + |
---|
| 85 | +================ |
---|
| 86 | +Special define |
---|
| 87 | +================ |
---|
| 88 | +There is a RX_SKB_COPY preprocessor define in asix.h can solve rx_throttle problem |
---|
| 89 | +in some version of 3.4 Linux kernel. Removing the comment before the define can enable |
---|
| 90 | +this feature. |
---|
| 91 | + |
---|
| 92 | + |
---|