12e55cc7210fef90f88201e860d8767594974574eDavid Brownell/* 22e55cc7210fef90f88201e860d8767594974574eDavid Brownell * ASIX AX8817X based USB 2.0 Ethernet Devices 3933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com> 42e55cc7210fef90f88201e860d8767594974574eDavid Brownell * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> 5933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis * Copyright (C) 2006 James Painter <jamie.painter@iname.com> 62e55cc7210fef90f88201e860d8767594974574eDavid Brownell * Copyright (c) 2002-2003 TiVo Inc. 72e55cc7210fef90f88201e860d8767594974574eDavid Brownell * 82e55cc7210fef90f88201e860d8767594974574eDavid Brownell * This program is free software; you can redistribute it and/or modify 92e55cc7210fef90f88201e860d8767594974574eDavid Brownell * it under the terms of the GNU General Public License as published by 102e55cc7210fef90f88201e860d8767594974574eDavid Brownell * the Free Software Foundation; either version 2 of the License, or 112e55cc7210fef90f88201e860d8767594974574eDavid Brownell * (at your option) any later version. 122e55cc7210fef90f88201e860d8767594974574eDavid Brownell * 132e55cc7210fef90f88201e860d8767594974574eDavid Brownell * This program is distributed in the hope that it will be useful, 142e55cc7210fef90f88201e860d8767594974574eDavid Brownell * but WITHOUT ANY WARRANTY; without even the implied warranty of 152e55cc7210fef90f88201e860d8767594974574eDavid Brownell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 162e55cc7210fef90f88201e860d8767594974574eDavid Brownell * GNU General Public License for more details. 172e55cc7210fef90f88201e860d8767594974574eDavid Brownell * 182e55cc7210fef90f88201e860d8767594974574eDavid Brownell * You should have received a copy of the GNU General Public License 192e55cc7210fef90f88201e860d8767594974574eDavid Brownell * along with this program; if not, write to the Free Software 202e55cc7210fef90f88201e860d8767594974574eDavid Brownell * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 212e55cc7210fef90f88201e860d8767594974574eDavid Brownell */ 222e55cc7210fef90f88201e860d8767594974574eDavid Brownell 232e55cc7210fef90f88201e860d8767594974574eDavid Brownell// #define DEBUG // error path messages, extra info 242e55cc7210fef90f88201e860d8767594974574eDavid Brownell// #define VERBOSE // more; success messages 252e55cc7210fef90f88201e860d8767594974574eDavid Brownell 262e55cc7210fef90f88201e860d8767594974574eDavid Brownell#include <linux/module.h> 272e55cc7210fef90f88201e860d8767594974574eDavid Brownell#include <linux/kmod.h> 282e55cc7210fef90f88201e860d8767594974574eDavid Brownell#include <linux/init.h> 292e55cc7210fef90f88201e860d8767594974574eDavid Brownell#include <linux/netdevice.h> 302e55cc7210fef90f88201e860d8767594974574eDavid Brownell#include <linux/etherdevice.h> 312e55cc7210fef90f88201e860d8767594974574eDavid Brownell#include <linux/ethtool.h> 322e55cc7210fef90f88201e860d8767594974574eDavid Brownell#include <linux/workqueue.h> 332e55cc7210fef90f88201e860d8767594974574eDavid Brownell#include <linux/mii.h> 342e55cc7210fef90f88201e860d8767594974574eDavid Brownell#include <linux/usb.h> 352e55cc7210fef90f88201e860d8767594974574eDavid Brownell#include <linux/crc32.h> 363692e94f1559523b84a5a0e65929ee84b276e83fJussi Kivilinna#include <linux/usb/usbnet.h> 375a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 38630ec1481b8aa0f6f66d521f04feacd74bfc19f5Eric Dumazet#include <linux/if_vlan.h> 392e55cc7210fef90f88201e860d8767594974574eDavid Brownell 40f87ce5b254d4eb5b5ec2bfcc78d714fa0e249288allan#define DRIVER_VERSION "22-Dec-2011" 4183e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define DRIVER_NAME "asix" 42933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 432e55cc7210fef90f88201e860d8767594974574eDavid Brownell/* ASIX AX8817X based USB 2.0 Ethernet Devices */ 442e55cc7210fef90f88201e860d8767594974574eDavid Brownell 452e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_SET_SW_MII 0x06 462e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_READ_MII_REG 0x07 472e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_MII_REG 0x08 482e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_SET_HW_MII 0x0a 492e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_READ_EEPROM 0x0b 502e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_EEPROM 0x0c 512e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_ENABLE 0x0d 522e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_DISABLE 0x0e 53933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_CMD_READ_RX_CTL 0x0f 542e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_RX_CTL 0x10 552e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_READ_IPG012 0x11 562e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_IPG0 0x12 572e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_IPG1 0x13 58933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_CMD_READ_NODE_ID 0x13 597f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna#define AX_CMD_WRITE_NODE_ID 0x14 602e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_IPG2 0x14 612e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_MULTI_FILTER 0x16 62933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX88172_CMD_READ_NODE_ID 0x17 632e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_READ_PHY_ID 0x19 642e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_READ_MEDIUM_STATUS 0x1a 652e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_MEDIUM_MODE 0x1b 662e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_READ_MONITOR_MODE 0x1c 672e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_MONITOR_MODE 0x1d 68933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_CMD_READ_GPIOS 0x1e 692e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_WRITE_GPIOS 0x1f 702e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_SW_RESET 0x20 712e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_SW_PHY_STATUS 0x21 722e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_CMD_SW_PHY_SELECT 0x22 732e55cc7210fef90f88201e860d8767594974574eDavid Brownell 742e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_MONITOR_MODE 0x01 752e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_MONITOR_LINK 0x02 762e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_MONITOR_MAGIC 0x04 772e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_MONITOR_HSFS 0x10 782e55cc7210fef90f88201e860d8767594974574eDavid Brownell 792e55cc7210fef90f88201e860d8767594974574eDavid Brownell/* AX88172 Medium Status Register values */ 80933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX88172_MEDIUM_FD 0x02 81933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX88172_MEDIUM_TX 0x04 82933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX88172_MEDIUM_FC 0x10 83933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX88172_MEDIUM_DEFAULT \ 84933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC ) 852e55cc7210fef90f88201e860d8767594974574eDavid Brownell 862e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_MCAST_FILTER_SIZE 8 872e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_MAX_MCAST 64 882e55cc7210fef90f88201e860d8767594974574eDavid Brownell 892e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_SWRESET_CLEAR 0x00 902e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_SWRESET_RR 0x01 912e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_SWRESET_RT 0x02 922e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_SWRESET_PRTE 0x04 932e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_SWRESET_PRL 0x08 942e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_SWRESET_BZ 0x10 952e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_SWRESET_IPRL 0x20 962e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX_SWRESET_IPPD 0x40 972e55cc7210fef90f88201e860d8767594974574eDavid Brownell 982e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX88772_IPG0_DEFAULT 0x15 992e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX88772_IPG1_DEFAULT 0x0c 1002e55cc7210fef90f88201e860d8767594974574eDavid Brownell#define AX88772_IPG2_DEFAULT 0x12 1012e55cc7210fef90f88201e860d8767594974574eDavid Brownell 102933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis/* AX88772 & AX88178 Medium Mode Register */ 103933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_PF 0x0080 104933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_JFE 0x0040 105933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_TFC 0x0020 106933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_RFC 0x0010 107933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_ENCK 0x0008 108933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_AC 0x0004 109933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_FD 0x0002 110933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_GM 0x0001 111933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_SM 0x1000 112933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_SBP 0x0800 113933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_PS 0x0200 114933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_MEDIUM_RE 0x0100 115933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 116933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX88178_MEDIUM_DEFAULT \ 117933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \ 118933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \ 11983e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler AX_MEDIUM_RE) 1202e55cc7210fef90f88201e860d8767594974574eDavid Brownell 121933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX88772_MEDIUM_DEFAULT \ 122933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis (AX_MEDIUM_FD | AX_MEDIUM_RFC | \ 123933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis AX_MEDIUM_TFC | AX_MEDIUM_PS | \ 12483e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler AX_MEDIUM_AC | AX_MEDIUM_RE) 125933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 126933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis/* AX88772 & AX88178 RX_CTL values */ 12783e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_RX_CTL_SO 0x0080 12883e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_RX_CTL_AP 0x0020 12983e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_RX_CTL_AM 0x0010 13083e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_RX_CTL_AB 0x0008 13183e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_RX_CTL_SEP 0x0004 13283e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_RX_CTL_AMALL 0x0002 13383e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_RX_CTL_PRO 0x0001 13483e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_RX_CTL_MFB_2048 0x0000 13583e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_RX_CTL_MFB_4096 0x0100 13683e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_RX_CTL_MFB_8192 0x0200 13783e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_RX_CTL_MFB_16384 0x0300 13883e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler 13983e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler#define AX_DEFAULT_RX_CTL (AX_RX_CTL_SO | AX_RX_CTL_AB) 140933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 141933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis/* GPIO 0 .. 2 toggles */ 142933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */ 143933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */ 144933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */ 145933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */ 146933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */ 147933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */ 148933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_GPIO_RESERVED 0x40 /* Reserved */ 149933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */ 150933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 151933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX_EEPROM_MAGIC 0xdeadbeef 152933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX88172_EEPROM_LEN 0x40 153933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define AX88772_EEPROM_LEN 0xff 154933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 155933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define PHY_MODE_MARVELL 0x0000 156933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define MII_MARVELL_LED_CTRL 0x0018 157933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define MII_MARVELL_STATUS 0x001b 158933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define MII_MARVELL_CTRL 0x0014 159933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 160933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define MARVELL_LED_MANUAL 0x0019 161933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 162933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define MARVELL_STATUS_HWCFG 0x0004 163933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 164933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define MARVELL_CTRL_TXDELAY 0x0002 165933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis#define MARVELL_CTRL_RXDELAY 0x0080 1662e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1673486140e30fcc16c0b8cd9545fbe5e2e66bf6941Grant Grundler#define PHY_MODE_RTL8211CL 0x000C 168610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1692e55cc7210fef90f88201e860d8767594974574eDavid Brownell/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ 17048b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstruct asix_data { 1712e55cc7210fef90f88201e860d8767594974574eDavid Brownell u8 multi_filter[AX_MCAST_FILTER_SIZE]; 1727f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna u8 mac_addr[ETH_ALEN]; 173933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u8 phymode; 174933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u8 ledmode; 175933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u8 eeprom_len; 1762e55cc7210fef90f88201e860d8767594974574eDavid Brownell}; 1772e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1782e55cc7210fef90f88201e860d8767594974574eDavid Brownellstruct ax88172_int_data { 17951bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro __le16 res1; 1802e55cc7210fef90f88201e860d8767594974574eDavid Brownell u8 link; 18151bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro __le16 res2; 1822e55cc7210fef90f88201e860d8767594974574eDavid Brownell u8 status; 18351bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro __le16 res3; 184ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 1852e55cc7210fef90f88201e860d8767594974574eDavid Brownell 18648b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, 1872e55cc7210fef90f88201e860d8767594974574eDavid Brownell u16 size, void *data) 1882e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 18951bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro void *buf; 19051bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro int err = -ENOMEM; 19151bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro 19260b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", 19360b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches cmd, value, index, size); 19451bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro 19551bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro buf = kmalloc(size, GFP_KERNEL); 19651bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro if (!buf) 19751bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 19851bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro 19951bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro err = usb_control_msg( 2002e55cc7210fef90f88201e860d8767594974574eDavid Brownell dev->udev, 2012e55cc7210fef90f88201e860d8767594974574eDavid Brownell usb_rcvctrlpipe(dev->udev, 0), 2022e55cc7210fef90f88201e860d8767594974574eDavid Brownell cmd, 2032e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 2042e55cc7210fef90f88201e860d8767594974574eDavid Brownell value, 2052e55cc7210fef90f88201e860d8767594974574eDavid Brownell index, 20651bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro buf, 2072e55cc7210fef90f88201e860d8767594974574eDavid Brownell size, 2082e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_CTRL_GET_TIMEOUT); 20994d433630a1e63d383d592d488f60581e0d98190Russ Dill if (err == size) 21051bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro memcpy(data, buf, size); 21194d433630a1e63d383d592d488f60581e0d98190Russ Dill else if (err >= 0) 21294d433630a1e63d383d592d488f60581e0d98190Russ Dill err = -EINVAL; 21351bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro kfree(buf); 21451bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro 21551bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viroout: 21651bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro return err; 2172e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 2182e55cc7210fef90f88201e860d8767594974574eDavid Brownell 21948b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, 2202e55cc7210fef90f88201e860d8767594974574eDavid Brownell u16 size, void *data) 2212e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 22251bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro void *buf = NULL; 22351bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro int err = -ENOMEM; 22451bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro 22560b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", 22660b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches cmd, value, index, size); 22751bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro 22851bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro if (data) { 22999bf236612801351834b441314379bc5304d62ceJulia Lawall buf = kmemdup(data, size, GFP_KERNEL); 23051bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro if (!buf) 23151bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 23251bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro } 23351bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro 23451bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro err = usb_control_msg( 2352e55cc7210fef90f88201e860d8767594974574eDavid Brownell dev->udev, 2362e55cc7210fef90f88201e860d8767594974574eDavid Brownell usb_sndctrlpipe(dev->udev, 0), 2372e55cc7210fef90f88201e860d8767594974574eDavid Brownell cmd, 2382e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 2392e55cc7210fef90f88201e860d8767594974574eDavid Brownell value, 2402e55cc7210fef90f88201e860d8767594974574eDavid Brownell index, 24151bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro buf, 2422e55cc7210fef90f88201e860d8767594974574eDavid Brownell size, 2432e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_CTRL_SET_TIMEOUT); 24451bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro kfree(buf); 24551bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro 24651bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viroout: 24751bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro return err; 2482e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 2492e55cc7210fef90f88201e860d8767594974574eDavid Brownell 2507d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void asix_async_cmd_callback(struct urb *urb) 2512e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 2522e55cc7210fef90f88201e860d8767594974574eDavid Brownell struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; 253c94cb314503a69492bf4455dce4f6d300cff0851Oliver Neukum int status = urb->status; 2542e55cc7210fef90f88201e860d8767594974574eDavid Brownell 255c94cb314503a69492bf4455dce4f6d300cff0851Oliver Neukum if (status < 0) 25648b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", 257c94cb314503a69492bf4455dce4f6d300cff0851Oliver Neukum status); 2582e55cc7210fef90f88201e860d8767594974574eDavid Brownell 2592e55cc7210fef90f88201e860d8767594974574eDavid Brownell kfree(req); 2602e55cc7210fef90f88201e860d8767594974574eDavid Brownell usb_free_urb(urb); 2612e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 2622e55cc7210fef90f88201e860d8767594974574eDavid Brownell 263933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic void 264933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisasix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, 265933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u16 size, void *data) 266933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 267933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct usb_ctrlrequest *req; 268933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis int status; 269933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct urb *urb; 270933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 27160b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d\n", 27260b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches cmd, value, index, size); 27383e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler 27483e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler urb = usb_alloc_urb(0, GFP_ATOMIC); 27583e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (!urb) { 27660b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Error allocating URB in write_cmd_async!\n"); 277933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return; 278933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 279933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 28083e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); 28183e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (!req) { 28260b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Failed to allocate memory for control request\n"); 283933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis usb_free_urb(urb); 284933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return; 285933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 286933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 287933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; 288933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis req->bRequest = cmd; 2899aa742ef7c1a7ff8e6df92a93ce3688e99fa66e3Oliver Neukum req->wValue = cpu_to_le16(value); 2909aa742ef7c1a7ff8e6df92a93ce3688e99fa66e3Oliver Neukum req->wIndex = cpu_to_le16(index); 2919aa742ef7c1a7ff8e6df92a93ce3688e99fa66e3Oliver Neukum req->wLength = cpu_to_le16(size); 292933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 293933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis usb_fill_control_urb(urb, dev->udev, 294933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis usb_sndctrlpipe(dev->udev, 0), 295933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis (void *)req, data, size, 296933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_async_cmd_callback, req); 297933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 29883e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler status = usb_submit_urb(urb, GFP_ATOMIC); 29983e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (status < 0) { 30060b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Error submitting the control message: status=%d\n", 30160b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches status); 302933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis kfree(req); 303933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis usb_free_urb(urb); 304933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 305933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 306933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 307933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 308933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 309a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet int offset = 0; 310933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 311a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet while (offset + sizeof(u32) < skb->len) { 312a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet struct sk_buff *ax_skb; 313a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet u16 size; 314a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet u32 header = get_unaligned_le32(skb->data + offset); 315933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 316a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet offset += sizeof(u32); 317bc466e678d0a98f445bf3f9c76fedf18e7dcc6b0Marek Vasut 318933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis /* get the packet length */ 319a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet size = (u16) (header & 0x7ff); 320a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet if (size != ((~header >> 16) & 0x07ff)) { 321a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); 322a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet return 0; 3233f78d1f210ff89af77f042ab7f4a8fee39feb1c9Neil Jones } 3243f78d1f210ff89af77f042ab7f4a8fee39feb1c9Neil Jones 325630ec1481b8aa0f6f66d521f04feacd74bfc19f5Eric Dumazet if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || 326a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet (size + offset > skb->len)) { 32760b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n", 32860b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches size); 329933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 0; 330933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 331a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet ax_skb = netdev_alloc_skb_ip_align(dev->net, size); 332a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet if (!ax_skb) 333933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 0; 334933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 335a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet skb_put(ax_skb, size); 336a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet memcpy(ax_skb->data, skb->data + offset, size); 337a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet usbnet_skb_return(dev, ax_skb); 338933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 339a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet offset += (size + 1) & 0xfffe; 340933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 341933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 342a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet if (skb->len != offset) { 34360b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d\n", 34460b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches skb->len); 345933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 0; 346933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 347933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 1; 348933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 349933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 350933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb, 351933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis gfp_t flags) 352933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 353933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis int padlen; 354933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis int headroom = skb_headroom(skb); 355933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis int tailroom = skb_tailroom(skb); 356933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u32 packet_len; 357933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u32 padbytes = 0xffff0000; 358933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 3592a5809499e35b53a6044fd34e72b242688b7a862Ingo van Lil padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4; 360933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 3618e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches if ((!skb_cloned(skb)) && 3628e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches ((headroom + tailroom) >= (4 + padlen))) { 363933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if ((headroom < 4) || (tailroom < padlen)) { 364933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis skb->data = memmove(skb->head + 4, skb->data, skb->len); 36527a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo skb_set_tail_pointer(skb, skb->len); 366933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 367933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } else { 368933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct sk_buff *skb2; 369933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis skb2 = skb_copy_expand(skb, 4, padlen, flags); 370933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev_kfree_skb_any(skb); 371933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis skb = skb2; 372933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (!skb) 373933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return NULL; 374933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 375933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 376933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis skb_push(skb, 4); 377933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); 37857e4f041bfffa191a318dab44eb991d79a6a9d5cDavid Hollis cpu_to_le32s(&packet_len); 37927d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); 380933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 3812a5809499e35b53a6044fd34e72b242688b7a862Ingo van Lil if (padlen) { 38257e4f041bfffa191a318dab44eb991d79a6a9d5cDavid Hollis cpu_to_le32s(&padbytes); 38327a884dc3cb63b93c2b3b643f5b31eed5f8a4d26Arnaldo Carvalho de Melo memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); 384933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis skb_put(skb, sizeof(padbytes)); 385933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 386933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return skb; 387933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 388933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 389933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic void asix_status(struct usbnet *dev, struct urb *urb) 390933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 391933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct ax88172_int_data *event; 392933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis int link; 393933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 394933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (urb->actual_length < 8) 395933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return; 396933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 397933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis event = urb->transfer_buffer; 398933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis link = event->link & 0x01; 399933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (netif_carrier_ok(dev->net) != link) { 400933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (link) { 401933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis netif_carrier_on(dev->net); 402933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis usbnet_defer_kevent (dev, EVENT_LINK_RESET ); 403933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } else 404933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis netif_carrier_off(dev->net); 40560b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "Link Status is: %d\n", link); 406933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 407933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 408933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 40948b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic inline int asix_set_sw_mii(struct usbnet *dev) 41048b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis{ 41148b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis int ret; 41248b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); 41348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis if (ret < 0) 41460b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Failed to enable software MII access\n"); 41548b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis return ret; 41648b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis} 41748b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis 41848b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic inline int asix_set_hw_mii(struct usbnet *dev) 41948b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis{ 42048b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis int ret; 42148b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); 42248b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis if (ret < 0) 42360b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Failed to enable hardware MII access\n"); 42448b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis return ret; 42548b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis} 42648b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis 427933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic inline int asix_get_phy_addr(struct usbnet *dev) 42848b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis{ 42951bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro u8 buf[2]; 43051bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); 43148b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis 43260b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "asix_get_phy_addr()\n"); 433933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 43451bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro if (ret < 0) { 43560b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret); 43651bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 43748b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis } 43860b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n", 43960b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches *((__le16 *)buf)); 44051bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro ret = buf[1]; 44151bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro 44251bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viroout: 44348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis return ret; 44448b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis} 44548b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis 44648b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic int asix_sw_reset(struct usbnet *dev, u8 flags) 44748b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis{ 44848b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis int ret; 44948b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis 45048b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); 45148b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis if (ret < 0) 45260b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); 453933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 454933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return ret; 455933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 45648b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis 457933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic u16 asix_read_rx_ctl(struct usbnet *dev) 458933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 45951bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro __le16 v; 46051bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); 461933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 46251bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro if (ret < 0) { 46360b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); 46451bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 465933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 46651bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro ret = le16_to_cpu(v); 46751bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viroout: 46848b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis return ret; 46948b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis} 47048b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis 47148b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic int asix_write_rx_ctl(struct usbnet *dev, u16 mode) 47248b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis{ 47348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis int ret; 47448b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis 47560b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); 47648b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); 47748b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis if (ret < 0) 47860b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", 47960b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches mode, ret); 48048b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis 48148b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis return ret; 48248b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis} 48348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis 484933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic u16 asix_read_medium_status(struct usbnet *dev) 4852e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 48651bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro __le16 v; 48751bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); 4882e55cc7210fef90f88201e860d8767594974574eDavid Brownell 48951bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro if (ret < 0) { 49060b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Error reading Medium Status register: %02x\n", 49160b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches ret); 49283e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler return ret; /* TODO: callers not checking for error ret */ 4932e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 49483e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler 49583e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler return le16_to_cpu(v); 49683e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler 4972e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 4982e55cc7210fef90f88201e860d8767594974574eDavid Brownell 499933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic int asix_write_medium_mode(struct usbnet *dev, u16 mode) 5002e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 501933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis int ret; 5022e55cc7210fef90f88201e860d8767594974574eDavid Brownell 50360b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); 504933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); 505933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (ret < 0) 50660b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", 50760b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches mode, ret); 5082e55cc7210fef90f88201e860d8767594974574eDavid Brownell 509933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return ret; 510933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 5112e55cc7210fef90f88201e860d8767594974574eDavid Brownell 512933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) 513933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 514933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis int ret; 5152e55cc7210fef90f88201e860d8767594974574eDavid Brownell 51660b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); 517933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); 518933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (ret < 0) 51960b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", 52060b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches value, ret); 5212e55cc7210fef90f88201e860d8767594974574eDavid Brownell 522933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (sleep) 523933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis msleep(sleep); 524933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 525933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return ret; 5262e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 5272e55cc7210fef90f88201e860d8767594974574eDavid Brownell 528933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis/* 529933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis * AX88772 & AX88178 have a 16-bit RX_CTL value 530933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis */ 53148b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic void asix_set_multicast(struct net_device *net) 5322e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 5332e55cc7210fef90f88201e860d8767594974574eDavid Brownell struct usbnet *dev = netdev_priv(net); 53448b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis struct asix_data *data = (struct asix_data *)&dev->data; 535933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u16 rx_ctl = AX_DEFAULT_RX_CTL; 5362e55cc7210fef90f88201e860d8767594974574eDavid Brownell 5372e55cc7210fef90f88201e860d8767594974574eDavid Brownell if (net->flags & IFF_PROMISC) { 538933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis rx_ctl |= AX_RX_CTL_PRO; 5398e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches } else if (net->flags & IFF_ALLMULTI || 5404cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko netdev_mc_count(net) > AX_MAX_MCAST) { 541933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis rx_ctl |= AX_RX_CTL_AMALL; 5424cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko } else if (netdev_mc_empty(net)) { 5432e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* just broadcast and directed */ 5442e55cc7210fef90f88201e860d8767594974574eDavid Brownell } else { 5452e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* We use the 20 byte dev->data 5462e55cc7210fef90f88201e860d8767594974574eDavid Brownell * for our 8 byte filter buffer 5472e55cc7210fef90f88201e860d8767594974574eDavid Brownell * to avoid allocating memory that 5482e55cc7210fef90f88201e860d8767594974574eDavid Brownell * is tricky to free later */ 54922bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 5502e55cc7210fef90f88201e860d8767594974574eDavid Brownell u32 crc_bits; 5512e55cc7210fef90f88201e860d8767594974574eDavid Brownell 5522e55cc7210fef90f88201e860d8767594974574eDavid Brownell memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); 5532e55cc7210fef90f88201e860d8767594974574eDavid Brownell 5542e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* Build the multicast hash filter. */ 55522bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_for_each_mc_addr(ha, net) { 55622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; 5572e55cc7210fef90f88201e860d8767594974574eDavid Brownell data->multi_filter[crc_bits >> 3] |= 5582e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1 << (crc_bits & 7); 5592e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 5602e55cc7210fef90f88201e860d8767594974574eDavid Brownell 56148b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, 5622e55cc7210fef90f88201e860d8767594974574eDavid Brownell AX_MCAST_FILTER_SIZE, data->multi_filter); 5632e55cc7210fef90f88201e860d8767594974574eDavid Brownell 564933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis rx_ctl |= AX_RX_CTL_AM; 5652e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 5662e55cc7210fef90f88201e860d8767594974574eDavid Brownell 56748b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); 5682e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 5692e55cc7210fef90f88201e860d8767594974574eDavid Brownell 57048b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) 5712e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 5722e55cc7210fef90f88201e860d8767594974574eDavid Brownell struct usbnet *dev = netdev_priv(netdev); 57351bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro __le16 res; 5742e55cc7210fef90f88201e860d8767594974574eDavid Brownell 575a9fc6338bd51a3d5735839e756fe7b741c2e6fadArnd Bergmann mutex_lock(&dev->phy_mutex); 57648b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis asix_set_sw_mii(dev); 57748b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, 57851bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro (__u16)loc, 2, &res); 57948b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis asix_set_hw_mii(dev); 580a9fc6338bd51a3d5735839e756fe7b741c2e6fadArnd Bergmann mutex_unlock(&dev->phy_mutex); 5812e55cc7210fef90f88201e860d8767594974574eDavid Brownell 58260b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", 58360b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches phy_id, loc, le16_to_cpu(res)); 5842e55cc7210fef90f88201e860d8767594974574eDavid Brownell 58551bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro return le16_to_cpu(res); 5862e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 5872e55cc7210fef90f88201e860d8767594974574eDavid Brownell 5882e55cc7210fef90f88201e860d8767594974574eDavid Brownellstatic void 58948b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisasix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) 5902e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 5912e55cc7210fef90f88201e860d8767594974574eDavid Brownell struct usbnet *dev = netdev_priv(netdev); 59251bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro __le16 res = cpu_to_le16(val); 5932e55cc7210fef90f88201e860d8767594974574eDavid Brownell 59460b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", 59560b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches phy_id, loc, val); 596a9fc6338bd51a3d5735839e756fe7b741c2e6fadArnd Bergmann mutex_lock(&dev->phy_mutex); 59748b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis asix_set_sw_mii(dev); 59851bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); 59948b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis asix_set_hw_mii(dev); 600a9fc6338bd51a3d5735839e756fe7b741c2e6fadArnd Bergmann mutex_unlock(&dev->phy_mutex); 6012e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 6022e55cc7210fef90f88201e860d8767594974574eDavid Brownell 603933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ 604933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic u32 asix_get_phyid(struct usbnet *dev) 6052e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 606933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis int phy_reg; 607933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u32 phy_id; 608a77929a278651d4451c872178d4d7aac8908aa8eGrant Grundler int i; 6092e55cc7210fef90f88201e860d8767594974574eDavid Brownell 610a77929a278651d4451c872178d4d7aac8908aa8eGrant Grundler /* Poll for the rare case the FW or phy isn't ready yet. */ 611a77929a278651d4451c872178d4d7aac8908aa8eGrant Grundler for (i = 0; i < 100; i++) { 612a77929a278651d4451c872178d4d7aac8908aa8eGrant Grundler phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); 613a77929a278651d4451c872178d4d7aac8908aa8eGrant Grundler if (phy_reg != 0 && phy_reg != 0xFFFF) 614a77929a278651d4451c872178d4d7aac8908aa8eGrant Grundler break; 615a77929a278651d4451c872178d4d7aac8908aa8eGrant Grundler mdelay(1); 616a77929a278651d4451c872178d4d7aac8908aa8eGrant Grundler } 617a77929a278651d4451c872178d4d7aac8908aa8eGrant Grundler 618a77929a278651d4451c872178d4d7aac8908aa8eGrant Grundler if (phy_reg <= 0 || phy_reg == 0xFFFF) 619933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 0; 6202e55cc7210fef90f88201e860d8767594974574eDavid Brownell 621933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis phy_id = (phy_reg & 0xffff) << 16; 6222e55cc7210fef90f88201e860d8767594974574eDavid Brownell 623933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); 624933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (phy_reg < 0) 625933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 0; 626933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 627933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis phy_id |= (phy_reg & 0xffff); 628933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 629933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return phy_id; 6302e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 6312e55cc7210fef90f88201e860d8767594974574eDavid Brownell 6322e55cc7210fef90f88201e860d8767594974574eDavid Brownellstatic void 63348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisasix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) 6342e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 6352e55cc7210fef90f88201e860d8767594974574eDavid Brownell struct usbnet *dev = netdev_priv(net); 6362e55cc7210fef90f88201e860d8767594974574eDavid Brownell u8 opt; 6372e55cc7210fef90f88201e860d8767594974574eDavid Brownell 63848b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { 6392e55cc7210fef90f88201e860d8767594974574eDavid Brownell wolinfo->supported = 0; 6402e55cc7210fef90f88201e860d8767594974574eDavid Brownell wolinfo->wolopts = 0; 6412e55cc7210fef90f88201e860d8767594974574eDavid Brownell return; 6422e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 6432e55cc7210fef90f88201e860d8767594974574eDavid Brownell wolinfo->supported = WAKE_PHY | WAKE_MAGIC; 6442e55cc7210fef90f88201e860d8767594974574eDavid Brownell wolinfo->wolopts = 0; 645f87ce5b254d4eb5b5ec2bfcc78d714fa0e249288allan if (opt & AX_MONITOR_LINK) 646f87ce5b254d4eb5b5ec2bfcc78d714fa0e249288allan wolinfo->wolopts |= WAKE_PHY; 647f87ce5b254d4eb5b5ec2bfcc78d714fa0e249288allan if (opt & AX_MONITOR_MAGIC) 648f87ce5b254d4eb5b5ec2bfcc78d714fa0e249288allan wolinfo->wolopts |= WAKE_MAGIC; 6492e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 6502e55cc7210fef90f88201e860d8767594974574eDavid Brownell 6512e55cc7210fef90f88201e860d8767594974574eDavid Brownellstatic int 65248b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisasix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) 6532e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 6542e55cc7210fef90f88201e860d8767594974574eDavid Brownell struct usbnet *dev = netdev_priv(net); 6552e55cc7210fef90f88201e860d8767594974574eDavid Brownell u8 opt = 0; 6562e55cc7210fef90f88201e860d8767594974574eDavid Brownell 6572e55cc7210fef90f88201e860d8767594974574eDavid Brownell if (wolinfo->wolopts & WAKE_PHY) 6582e55cc7210fef90f88201e860d8767594974574eDavid Brownell opt |= AX_MONITOR_LINK; 6592e55cc7210fef90f88201e860d8767594974574eDavid Brownell if (wolinfo->wolopts & WAKE_MAGIC) 6602e55cc7210fef90f88201e860d8767594974574eDavid Brownell opt |= AX_MONITOR_MAGIC; 6612e55cc7210fef90f88201e860d8767594974574eDavid Brownell 66248b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, 66351bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro opt, 0, 0, NULL) < 0) 6642e55cc7210fef90f88201e860d8767594974574eDavid Brownell return -EINVAL; 6652e55cc7210fef90f88201e860d8767594974574eDavid Brownell 6662e55cc7210fef90f88201e860d8767594974574eDavid Brownell return 0; 6672e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 6682e55cc7210fef90f88201e860d8767594974574eDavid Brownell 66948b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic int asix_get_eeprom_len(struct net_device *net) 6702e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 671933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct usbnet *dev = netdev_priv(net); 672933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct asix_data *data = (struct asix_data *)&dev->data; 673933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 674933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return data->eeprom_len; 6752e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 6762e55cc7210fef90f88201e860d8767594974574eDavid Brownell 67748b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic int asix_get_eeprom(struct net_device *net, 6782e55cc7210fef90f88201e860d8767594974574eDavid Brownell struct ethtool_eeprom *eeprom, u8 *data) 6792e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 6802e55cc7210fef90f88201e860d8767594974574eDavid Brownell struct usbnet *dev = netdev_priv(net); 68151bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro __le16 *ebuf = (__le16 *)data; 6822e55cc7210fef90f88201e860d8767594974574eDavid Brownell int i; 6832e55cc7210fef90f88201e860d8767594974574eDavid Brownell 6842e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* Crude hack to ensure that we don't overwrite memory 6852e55cc7210fef90f88201e860d8767594974574eDavid Brownell * if an odd length is supplied 6862e55cc7210fef90f88201e860d8767594974574eDavid Brownell */ 6872e55cc7210fef90f88201e860d8767594974574eDavid Brownell if (eeprom->len % 2) 6882e55cc7210fef90f88201e860d8767594974574eDavid Brownell return -EINVAL; 6892e55cc7210fef90f88201e860d8767594974574eDavid Brownell 6902e55cc7210fef90f88201e860d8767594974574eDavid Brownell eeprom->magic = AX_EEPROM_MAGIC; 6912e55cc7210fef90f88201e860d8767594974574eDavid Brownell 6922e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* ax8817x returns 2 bytes from eeprom on read */ 6932e55cc7210fef90f88201e860d8767594974574eDavid Brownell for (i=0; i < eeprom->len / 2; i++) { 69448b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, 6952e55cc7210fef90f88201e860d8767594974574eDavid Brownell eeprom->offset + i, 0, 2, &ebuf[i]) < 0) 6962e55cc7210fef90f88201e860d8767594974574eDavid Brownell return -EINVAL; 6972e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 6982e55cc7210fef90f88201e860d8767594974574eDavid Brownell return 0; 6992e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 7002e55cc7210fef90f88201e860d8767594974574eDavid Brownell 70148b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic void asix_get_drvinfo (struct net_device *net, 7022e55cc7210fef90f88201e860d8767594974574eDavid Brownell struct ethtool_drvinfo *info) 7032e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 704933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct usbnet *dev = netdev_priv(net); 705933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct asix_data *data = (struct asix_data *)&dev->data; 706933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 7072e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* Inherit standard device info */ 7082e55cc7210fef90f88201e860d8767594974574eDavid Brownell usbnet_get_drvinfo(net, info); 70983e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler strncpy (info->driver, DRIVER_NAME, sizeof info->driver); 710933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis strncpy (info->version, DRIVER_VERSION, sizeof info->version); 711933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis info->eedump_len = data->eeprom_len; 7122e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 7132e55cc7210fef90f88201e860d8767594974574eDavid Brownell 714933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic u32 asix_get_link(struct net_device *net) 715933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 716933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct usbnet *dev = netdev_priv(net); 717933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 718933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return mii_link_ok(&dev->mii); 719933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 720933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 721933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) 722933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 723933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct usbnet *dev = netdev_priv(net); 724933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 725933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); 726933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 727933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 7287f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinnastatic int asix_set_mac_address(struct net_device *net, void *p) 7297f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna{ 7307f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna struct usbnet *dev = netdev_priv(net); 7317f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna struct asix_data *data = (struct asix_data *)&dev->data; 7327f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna struct sockaddr *addr = p; 7337f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna 7347f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna if (netif_running(net)) 7357f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna return -EBUSY; 7367f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna if (!is_valid_ether_addr(addr->sa_data)) 7377f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna return -EADDRNOTAVAIL; 7387f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna 7397f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); 7407f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna 7417f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna /* We use the 20 byte dev->data 7427f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna * for our 6 byte mac buffer 7437f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna * to avoid allocating memory that 7447f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna * is tricky to free later */ 7457f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); 7467f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, 7477f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna data->mac_addr); 7487f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna 7497f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna return 0; 7507f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna} 7517f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna 752933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis/* We need to override some ethtool_ops so we require our 753933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis own structure so we don't interfere with other usbnet 754933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis devices that may be connected at the same time. */ 7550fc0b732eaa38beb93a6fb62f77c7bd9622c76ecStephen Hemmingerstatic const struct ethtool_ops ax88172_ethtool_ops = { 756933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .get_drvinfo = asix_get_drvinfo, 757933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .get_link = asix_get_link, 758933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .get_msglevel = usbnet_get_msglevel, 7592e55cc7210fef90f88201e860d8767594974574eDavid Brownell .set_msglevel = usbnet_set_msglevel, 76048b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .get_wol = asix_get_wol, 76148b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .set_wol = asix_set_wol, 76248b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .get_eeprom_len = asix_get_eeprom_len, 76348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .get_eeprom = asix_get_eeprom, 764c41286fd42f3545513f8de9f61028120b6d38e89Arnd Bergmann .get_settings = usbnet_get_settings, 765c41286fd42f3545513f8de9f61028120b6d38e89Arnd Bergmann .set_settings = usbnet_set_settings, 766c41286fd42f3545513f8de9f61028120b6d38e89Arnd Bergmann .nway_reset = usbnet_nway_reset, 7672e55cc7210fef90f88201e860d8767594974574eDavid Brownell}; 7682e55cc7210fef90f88201e860d8767594974574eDavid Brownell 769933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic void ax88172_set_multicast(struct net_device *net) 7702e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 7712e55cc7210fef90f88201e860d8767594974574eDavid Brownell struct usbnet *dev = netdev_priv(net); 772933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct asix_data *data = (struct asix_data *)&dev->data; 773933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u8 rx_ctl = 0x8c; 7742e55cc7210fef90f88201e860d8767594974574eDavid Brownell 775933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (net->flags & IFF_PROMISC) { 776933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis rx_ctl |= 0x01; 7778e95a2026f3b43f7c3d676adaccd2de9532e8dccJoe Perches } else if (net->flags & IFF_ALLMULTI || 7784cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko netdev_mc_count(net) > AX_MAX_MCAST) { 779933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis rx_ctl |= 0x02; 7804cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko } else if (netdev_mc_empty(net)) { 781933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis /* just broadcast and directed */ 782933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } else { 783933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis /* We use the 20 byte dev->data 784933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis * for our 8 byte filter buffer 785933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis * to avoid allocating memory that 786933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis * is tricky to free later */ 78722bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 788933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u32 crc_bits; 789933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 790933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE); 791933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 792933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis /* Build the multicast hash filter. */ 79322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_for_each_mc_addr(ha, net) { 79422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; 795933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis data->multi_filter[crc_bits >> 3] |= 796933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1 << (crc_bits & 7); 797933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 798933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 799933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0, 800933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis AX_MCAST_FILTER_SIZE, data->multi_filter); 801933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 802933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis rx_ctl |= 0x10; 803933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 804933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 805933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); 806933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 807933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 808933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic int ax88172_link_reset(struct usbnet *dev) 809933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 810933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u8 mode; 8118ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 812933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 813933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mii_check_media(&dev->mii, 1, 1); 814933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mii_ethtool_gset(&dev->mii, &ecmd); 815933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mode = AX88172_MEDIUM_DEFAULT; 816933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 817933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (ecmd.duplex != DUPLEX_FULL) 818933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mode |= ~AX88172_MEDIUM_FD; 819933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 8208ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 8218ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); 822933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 823933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_write_medium_mode(dev, mode); 824933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 825933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 0; 8262e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 8272e55cc7210fef90f88201e860d8767594974574eDavid Brownell 8281703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemmingerstatic const struct net_device_ops ax88172_netdev_ops = { 8291703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_open = usbnet_open, 8301703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_stop = usbnet_stop, 8311703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_start_xmit = usbnet_start_xmit, 8321703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_tx_timeout = usbnet_tx_timeout, 8331703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_change_mtu = usbnet_change_mtu, 8341703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_set_mac_address = eth_mac_addr, 8351703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_validate_addr = eth_validate_addr, 8361703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_do_ioctl = asix_ioctl, 837afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = ax88172_set_multicast, 8381703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger}; 8391703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger 84048b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollisstatic int ax88172_bind(struct usbnet *dev, struct usb_interface *intf) 8412e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 8422e55cc7210fef90f88201e860d8767594974574eDavid Brownell int ret = 0; 84351bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro u8 buf[ETH_ALEN]; 8442e55cc7210fef90f88201e860d8767594974574eDavid Brownell int i; 8452e55cc7210fef90f88201e860d8767594974574eDavid Brownell unsigned long gpio_bits = dev->driver_info->data; 846933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct asix_data *data = (struct asix_data *)&dev->data; 847933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 848933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis data->eeprom_len = AX88172_EEPROM_LEN; 8492e55cc7210fef90f88201e860d8767594974574eDavid Brownell 8502e55cc7210fef90f88201e860d8767594974574eDavid Brownell usbnet_get_endpoints(dev,intf); 8512e55cc7210fef90f88201e860d8767594974574eDavid Brownell 8522e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* Toggle the GPIOs in a manufacturer/model specific way */ 8532e55cc7210fef90f88201e860d8767594974574eDavid Brownell for (i = 2; i >= 0; i--) { 85483e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, 85583e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler (gpio_bits >> (i * 8)) & 0xff, 0, 0, NULL); 85683e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 85751bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 8582e55cc7210fef90f88201e860d8767594974574eDavid Brownell msleep(5); 8592e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 8602e55cc7210fef90f88201e860d8767594974574eDavid Brownell 86183e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_write_rx_ctl(dev, 0x80); 86283e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 86351bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 8642e55cc7210fef90f88201e860d8767594974574eDavid Brownell 8652e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* Get the MAC address */ 86683e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); 86783e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) { 8682e55cc7210fef90f88201e860d8767594974574eDavid Brownell dbg("read AX_CMD_READ_NODE_ID failed: %d", ret); 86951bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 8702e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 8712e55cc7210fef90f88201e860d8767594974574eDavid Brownell memcpy(dev->net->dev_addr, buf, ETH_ALEN); 8722e55cc7210fef90f88201e860d8767594974574eDavid Brownell 8732e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* Initialize MII structure */ 8742e55cc7210fef90f88201e860d8767594974574eDavid Brownell dev->mii.dev = dev->net; 87548b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis dev->mii.mdio_read = asix_mdio_read; 87648b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis dev->mii.mdio_write = asix_mdio_write; 8772e55cc7210fef90f88201e860d8767594974574eDavid Brownell dev->mii.phy_id_mask = 0x3f; 8782e55cc7210fef90f88201e860d8767594974574eDavid Brownell dev->mii.reg_num_mask = 0x1f; 879933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->mii.phy_id = asix_get_phy_addr(dev); 8802e55cc7210fef90f88201e860d8767594974574eDavid Brownell 8811703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger dev->net->netdev_ops = &ax88172_netdev_ops; 88248b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis dev->net->ethtool_ops = &ax88172_ethtool_ops; 8832e55cc7210fef90f88201e860d8767594974574eDavid Brownell 884933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); 885933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, 8862e55cc7210fef90f88201e860d8767594974574eDavid Brownell ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); 8872e55cc7210fef90f88201e860d8767594974574eDavid Brownell mii_nway_restart(&dev->mii); 8882e55cc7210fef90f88201e860d8767594974574eDavid Brownell 8892e55cc7210fef90f88201e860d8767594974574eDavid Brownell return 0; 89051bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro 89151bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viroout: 8922e55cc7210fef90f88201e860d8767594974574eDavid Brownell return ret; 8932e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 8942e55cc7210fef90f88201e860d8767594974574eDavid Brownell 8950fc0b732eaa38beb93a6fb62f77c7bd9622c76ecStephen Hemmingerstatic const struct ethtool_ops ax88772_ethtool_ops = { 89648b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .get_drvinfo = asix_get_drvinfo, 897933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .get_link = asix_get_link, 8982e55cc7210fef90f88201e860d8767594974574eDavid Brownell .get_msglevel = usbnet_get_msglevel, 8992e55cc7210fef90f88201e860d8767594974574eDavid Brownell .set_msglevel = usbnet_set_msglevel, 90048b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .get_wol = asix_get_wol, 90148b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .set_wol = asix_set_wol, 90248b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .get_eeprom_len = asix_get_eeprom_len, 90348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .get_eeprom = asix_get_eeprom, 904c41286fd42f3545513f8de9f61028120b6d38e89Arnd Bergmann .get_settings = usbnet_get_settings, 905c41286fd42f3545513f8de9f61028120b6d38e89Arnd Bergmann .set_settings = usbnet_set_settings, 906c41286fd42f3545513f8de9f61028120b6d38e89Arnd Bergmann .nway_reset = usbnet_nway_reset, 9072e55cc7210fef90f88201e860d8767594974574eDavid Brownell}; 9082e55cc7210fef90f88201e860d8767594974574eDavid Brownell 909933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic int ax88772_link_reset(struct usbnet *dev) 910933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 911933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u16 mode; 9128ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 913933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 914933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mii_check_media(&dev->mii, 1, 1); 915933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mii_ethtool_gset(&dev->mii, &ecmd); 916933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mode = AX88772_MEDIUM_DEFAULT; 917933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 9188ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny if (ethtool_cmd_speed(&ecmd) != SPEED_100) 919933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mode &= ~AX_MEDIUM_PS; 920933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 921933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (ecmd.duplex != DUPLEX_FULL) 922933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mode &= ~AX_MEDIUM_FD; 923933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 9248ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 9258ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); 926933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 927933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_write_medium_mode(dev, mode); 928933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 929933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 0; 930933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 931933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 9324ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundlerstatic int ax88772_reset(struct usbnet *dev) 9332e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 9348ef66bdc4bda6aac2dae73b84d79dc8c2db33637Jussi Kivilinna struct asix_data *data = (struct asix_data *)&dev->data; 935d0ffff8fddd5853e4b2b101790ac0c3690655af5Andres Salomon int ret, embd_phy; 936933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u16 rx_ctl; 9372e55cc7210fef90f88201e860d8767594974574eDavid Brownell 93883e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_write_gpio(dev, 93983e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5); 94083e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 94151bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 9422e55cc7210fef90f88201e860d8767594974574eDavid Brownell 943d0ffff8fddd5853e4b2b101790ac0c3690655af5Andres Salomon embd_phy = ((asix_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); 9444ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 94583e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); 94683e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) { 9472e55cc7210fef90f88201e860d8767594974574eDavid Brownell dbg("Select PHY #1 failed: %d", ret); 94851bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 9492e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 9502e55cc7210fef90f88201e860d8767594974574eDavid Brownell 95183e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); 95283e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 95351bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 9542e55cc7210fef90f88201e860d8767594974574eDavid Brownell 9552e55cc7210fef90f88201e860d8767594974574eDavid Brownell msleep(150); 95683e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler 95783e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); 95883e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 95951bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 9602e55cc7210fef90f88201e860d8767594974574eDavid Brownell 9612e55cc7210fef90f88201e860d8767594974574eDavid Brownell msleep(150); 9624ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 963d0ffff8fddd5853e4b2b101790ac0c3690655af5Andres Salomon if (embd_phy) { 96483e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_sw_reset(dev, AX_SWRESET_IPRL); 96583e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 96651bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 96783e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler } else { 96883e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_sw_reset(dev, AX_SWRESET_PRTE); 96983e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 97051bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 971d0ffff8fddd5853e4b2b101790ac0c3690655af5Andres Salomon } 9722e55cc7210fef90f88201e860d8767594974574eDavid Brownell 9732e55cc7210fef90f88201e860d8767594974574eDavid Brownell msleep(150); 974933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis rx_ctl = asix_read_rx_ctl(dev); 975933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dbg("RX_CTL is 0x%04x after software reset", rx_ctl); 97683e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_write_rx_ctl(dev, 0x0000); 97783e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 97851bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 9792e55cc7210fef90f88201e860d8767594974574eDavid Brownell 980933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis rx_ctl = asix_read_rx_ctl(dev); 981933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl); 982933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 98383e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_sw_reset(dev, AX_SWRESET_PRL); 98483e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 98551bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 9862e55cc7210fef90f88201e860d8767594974574eDavid Brownell 9872e55cc7210fef90f88201e860d8767594974574eDavid Brownell msleep(150); 98848b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis 98983e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL); 99083e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 99151bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 9922e55cc7210fef90f88201e860d8767594974574eDavid Brownell 99348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis msleep(150); 9942e55cc7210fef90f88201e860d8767594974574eDavid Brownell 995933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); 996933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, 9972e55cc7210fef90f88201e860d8767594974574eDavid Brownell ADVERTISE_ALL | ADVERTISE_CSMA); 9982e55cc7210fef90f88201e860d8767594974574eDavid Brownell mii_nway_restart(&dev->mii); 9992e55cc7210fef90f88201e860d8767594974574eDavid Brownell 100083e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT); 100183e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 100251bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 10032e55cc7210fef90f88201e860d8767594974574eDavid Brownell 100483e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0, 10052e55cc7210fef90f88201e860d8767594974574eDavid Brownell AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, 100683e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler AX88772_IPG2_DEFAULT, 0, NULL); 100783e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) { 10082e55cc7210fef90f88201e860d8767594974574eDavid Brownell dbg("Write IPG,IPG1,IPG2 failed: %d", ret); 100951bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 10102e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 10112e55cc7210fef90f88201e860d8767594974574eDavid Brownell 10128ef66bdc4bda6aac2dae73b84d79dc8c2db33637Jussi Kivilinna /* Rewrite MAC address */ 10138ef66bdc4bda6aac2dae73b84d79dc8c2db33637Jussi Kivilinna memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); 10148ef66bdc4bda6aac2dae73b84d79dc8c2db33637Jussi Kivilinna ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, 10158ef66bdc4bda6aac2dae73b84d79dc8c2db33637Jussi Kivilinna data->mac_addr); 10168ef66bdc4bda6aac2dae73b84d79dc8c2db33637Jussi Kivilinna if (ret < 0) 10178ef66bdc4bda6aac2dae73b84d79dc8c2db33637Jussi Kivilinna goto out; 10188ef66bdc4bda6aac2dae73b84d79dc8c2db33637Jussi Kivilinna 10192e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* Set RX_CTL to default values with 2k buffer, and enable cactus */ 102083e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); 102183e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 102251bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro goto out; 10232e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1024933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis rx_ctl = asix_read_rx_ctl(dev); 1025933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dbg("RX_CTL is 0x%04x after all initializations", rx_ctl); 1026933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1027933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis rx_ctl = asix_read_medium_status(dev); 1028933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dbg("Medium Status is 0x%04x after all initializations", rx_ctl); 1029933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 10304ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler return 0; 10314ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 10324ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundlerout: 10334ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler return ret; 10344ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 10354ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler} 10364ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 10374ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundlerstatic const struct net_device_ops ax88772_netdev_ops = { 10384ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler .ndo_open = usbnet_open, 10394ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler .ndo_stop = usbnet_stop, 10404ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler .ndo_start_xmit = usbnet_start_xmit, 10414ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler .ndo_tx_timeout = usbnet_tx_timeout, 10424ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler .ndo_change_mtu = usbnet_change_mtu, 10434ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler .ndo_set_mac_address = asix_set_mac_address, 10444ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler .ndo_validate_addr = eth_validate_addr, 10454ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler .ndo_do_ioctl = asix_ioctl, 10464ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler .ndo_set_rx_mode = asix_set_multicast, 10474ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler}; 10484ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 10494ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundlerstatic int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) 10504ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler{ 1051d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler int ret, embd_phy; 10524ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler struct asix_data *data = (struct asix_data *)&dev->data; 10534ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler u8 buf[ETH_ALEN]; 10544ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler u32 phyid; 10554ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 10564ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler data->eeprom_len = AX88772_EEPROM_LEN; 10574ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 10584ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler usbnet_get_endpoints(dev,intf); 10594ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 10604ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler /* Get the MAC address */ 106183e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); 106283e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) { 10634ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler dbg("Failed to read MAC address: %d", ret); 106483e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler return ret; 10654ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler } 10664ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler memcpy(dev->net->dev_addr, buf, ETH_ALEN); 10674ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 10684ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler /* Initialize MII structure */ 10694ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler dev->mii.dev = dev->net; 10704ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler dev->mii.mdio_read = asix_mdio_read; 10714ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler dev->mii.mdio_write = asix_mdio_write; 10724ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler dev->mii.phy_id_mask = 0x1f; 10734ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler dev->mii.reg_num_mask = 0x1f; 10744ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler dev->mii.phy_id = asix_get_phy_addr(dev); 10754ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 10764ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler dev->net->netdev_ops = &ax88772_netdev_ops; 10774ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler dev->net->ethtool_ops = &ax88772_ethtool_ops; 10784ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 1079d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); 1080d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler 1081d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler /* Reset the PHY to normal operation mode */ 1082d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); 1083d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler if (ret < 0) { 1084d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler dbg("Select PHY #1 failed: %d", ret); 1085d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler return ret; 1086d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler } 1087d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler 1088d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); 108983e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 109083e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler return ret; 10914ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler 1092d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler msleep(150); 1093d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler 1094d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); 1095d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler if (ret < 0) 1096d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler return ret; 1097d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler 1098d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler msleep(150); 1099d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler 1100d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_PRTE); 1101d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler 1102d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler /* Read PHYID register *AFTER* the PHY was reset properly */ 1103d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler phyid = asix_get_phyid(dev); 1104d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler dbg("PHYID=0x%08x", phyid); 1105d3665188a79254c0698aa161e2c36dcda4e9ef55Grant Grundler 11062e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ 11072e55cc7210fef90f88201e860d8767594974574eDavid Brownell if (dev->driver_info->flags & FLAG_FRAMING_AX) { 11082e55cc7210fef90f88201e860d8767594974574eDavid Brownell /* hard_mtu is still the default - the device does not support 11092e55cc7210fef90f88201e860d8767594974574eDavid Brownell jumbo eth frames */ 11102e55cc7210fef90f88201e860d8767594974574eDavid Brownell dev->rx_urb_size = 2048; 11112e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 111283e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler 11132e55cc7210fef90f88201e860d8767594974574eDavid Brownell return 0; 11142e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 11152e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1116bc689c9788f2cc9829d01d84083bc1714b969b15stephen hemmingerstatic const struct ethtool_ops ax88178_ethtool_ops = { 1117933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .get_drvinfo = asix_get_drvinfo, 1118933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .get_link = asix_get_link, 1119933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .get_msglevel = usbnet_get_msglevel, 1120933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .set_msglevel = usbnet_set_msglevel, 1121933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .get_wol = asix_get_wol, 1122933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .set_wol = asix_set_wol, 1123933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .get_eeprom_len = asix_get_eeprom_len, 1124933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .get_eeprom = asix_get_eeprom, 1125c41286fd42f3545513f8de9f61028120b6d38e89Arnd Bergmann .get_settings = usbnet_get_settings, 1126c41286fd42f3545513f8de9f61028120b6d38e89Arnd Bergmann .set_settings = usbnet_set_settings, 1127c41286fd42f3545513f8de9f61028120b6d38e89Arnd Bergmann .nway_reset = usbnet_nway_reset, 1128933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis}; 1129933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1130933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic int marvell_phy_init(struct usbnet *dev) 11312e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 1132933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct asix_data *data = (struct asix_data *)&dev->data; 1133933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u16 reg; 11342e55cc7210fef90f88201e860d8767594974574eDavid Brownell 113560b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "marvell_phy_init()\n"); 11362e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1137933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS); 113860b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "MII_MARVELL_STATUS = 0x%04x\n", reg); 11392e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1140933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL, 1141933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY); 11422e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1143933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (data->ledmode) { 1144933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis reg = asix_mdio_read(dev->net, dev->mii.phy_id, 1145933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis MII_MARVELL_LED_CTRL); 114660b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (1) = 0x%04x\n", reg); 11472e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1148933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis reg &= 0xf8ff; 1149933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis reg |= (1 + 0x0100); 1150933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_mdio_write(dev->net, dev->mii.phy_id, 1151933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis MII_MARVELL_LED_CTRL, reg); 11522e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1153933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis reg = asix_mdio_read(dev->net, dev->mii.phy_id, 1154933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis MII_MARVELL_LED_CTRL); 115560b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "MII_MARVELL_LED_CTRL (2) = 0x%04x\n", reg); 1156933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis reg &= 0xfc0f; 1157933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 11582e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1159933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 0; 1160933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 1161933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1162610d885d3176bd807b582401e8990898ae25bed2Grant Grundlerstatic int rtl8211cl_phy_init(struct usbnet *dev) 1163610d885d3176bd807b582401e8990898ae25bed2Grant Grundler{ 1164610d885d3176bd807b582401e8990898ae25bed2Grant Grundler struct asix_data *data = (struct asix_data *)&dev->data; 1165610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1166610d885d3176bd807b582401e8990898ae25bed2Grant Grundler netdev_dbg(dev->net, "rtl8211cl_phy_init()\n"); 1167610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1168610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0005); 1169610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_mdio_write (dev->net, dev->mii.phy_id, 0x0c, 0); 1170610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_mdio_write (dev->net, dev->mii.phy_id, 0x01, 1171610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_mdio_read (dev->net, dev->mii.phy_id, 0x01) | 0x0080); 1172610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); 1173610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1174610d885d3176bd807b582401e8990898ae25bed2Grant Grundler if (data->ledmode == 12) { 1175610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0x0002); 1176610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_mdio_write (dev->net, dev->mii.phy_id, 0x1a, 0x00cb); 1177610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_mdio_write (dev->net, dev->mii.phy_id, 0x1f, 0); 1178610d885d3176bd807b582401e8990898ae25bed2Grant Grundler } 1179610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1180610d885d3176bd807b582401e8990898ae25bed2Grant Grundler return 0; 1181610d885d3176bd807b582401e8990898ae25bed2Grant Grundler} 1182610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1183933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic int marvell_led_status(struct usbnet *dev, u16 speed) 1184933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 1185933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL); 1186933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 118760b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "marvell_led_status() read 0x%04x\n", reg); 1188933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1189933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis /* Clear out the center LED bits - 0x03F0 */ 1190933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis reg &= 0xfc0f; 1191933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1192933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis switch (speed) { 1193933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis case SPEED_1000: 1194933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis reg |= 0x03e0; 1195933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis break; 1196933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis case SPEED_100: 1197933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis reg |= 0x03b0; 1198933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis break; 1199933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis default: 1200933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis reg |= 0x02f0; 12012e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 12022e55cc7210fef90f88201e860d8767594974574eDavid Brownell 120360b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "marvell_led_status() writing 0x%04x\n", reg); 1204933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg); 1205933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1206933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 0; 1207933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 1208933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1209610d885d3176bd807b582401e8990898ae25bed2Grant Grundlerstatic int ax88178_reset(struct usbnet *dev) 1210610d885d3176bd807b582401e8990898ae25bed2Grant Grundler{ 1211610d885d3176bd807b582401e8990898ae25bed2Grant Grundler struct asix_data *data = (struct asix_data *)&dev->data; 1212610d885d3176bd807b582401e8990898ae25bed2Grant Grundler int ret; 1213610d885d3176bd807b582401e8990898ae25bed2Grant Grundler __le16 eeprom; 1214610d885d3176bd807b582401e8990898ae25bed2Grant Grundler u8 status; 1215610d885d3176bd807b582401e8990898ae25bed2Grant Grundler int gpio0 = 0; 1216b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler u32 phyid; 1217610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1218610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); 1219610d885d3176bd807b582401e8990898ae25bed2Grant Grundler dbg("GPIO Status: 0x%04x", status); 1220610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1221610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL); 1222610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom); 1223610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL); 1224610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1225610d885d3176bd807b582401e8990898ae25bed2Grant Grundler dbg("EEPROM index 0x17 is 0x%04x", eeprom); 1226610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1227610d885d3176bd807b582401e8990898ae25bed2Grant Grundler if (eeprom == cpu_to_le16(0xffff)) { 1228610d885d3176bd807b582401e8990898ae25bed2Grant Grundler data->phymode = PHY_MODE_MARVELL; 1229610d885d3176bd807b582401e8990898ae25bed2Grant Grundler data->ledmode = 0; 1230610d885d3176bd807b582401e8990898ae25bed2Grant Grundler gpio0 = 1; 1231610d885d3176bd807b582401e8990898ae25bed2Grant Grundler } else { 1232b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler data->phymode = le16_to_cpu(eeprom) & 0x7F; 1233610d885d3176bd807b582401e8990898ae25bed2Grant Grundler data->ledmode = le16_to_cpu(eeprom) >> 8; 1234610d885d3176bd807b582401e8990898ae25bed2Grant Grundler gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; 1235610d885d3176bd807b582401e8990898ae25bed2Grant Grundler } 1236610d885d3176bd807b582401e8990898ae25bed2Grant Grundler dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode); 1237610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1238b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler /* Power up external GigaPHY through AX88178 GPIO pin */ 1239610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); 1240610d885d3176bd807b582401e8990898ae25bed2Grant Grundler if ((le16_to_cpu(eeprom) >> 8) != 1) { 1241610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_write_gpio(dev, 0x003c, 30); 1242610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_write_gpio(dev, 0x001c, 300); 1243610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_write_gpio(dev, 0x003c, 30); 1244610d885d3176bd807b582401e8990898ae25bed2Grant Grundler } else { 1245610d885d3176bd807b582401e8990898ae25bed2Grant Grundler dbg("gpio phymode == 1 path"); 1246610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_write_gpio(dev, AX_GPIO_GPO1EN, 30); 1247610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); 1248610d885d3176bd807b582401e8990898ae25bed2Grant Grundler } 1249610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1250b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler /* Read PHYID register *AFTER* powering up PHY */ 1251b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler phyid = asix_get_phyid(dev); 1252b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler dbg("PHYID=0x%08x", phyid); 1253b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler 1254b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */ 1255b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); 1256b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler 1257610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_sw_reset(dev, 0); 1258610d885d3176bd807b582401e8990898ae25bed2Grant Grundler msleep(150); 1259610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1260610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); 1261610d885d3176bd807b582401e8990898ae25bed2Grant Grundler msleep(150); 1262610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1263610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_write_rx_ctl(dev, 0); 1264610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1265610d885d3176bd807b582401e8990898ae25bed2Grant Grundler if (data->phymode == PHY_MODE_MARVELL) { 1266610d885d3176bd807b582401e8990898ae25bed2Grant Grundler marvell_phy_init(dev); 1267610d885d3176bd807b582401e8990898ae25bed2Grant Grundler msleep(60); 1268610d885d3176bd807b582401e8990898ae25bed2Grant Grundler } else if (data->phymode == PHY_MODE_RTL8211CL) 1269610d885d3176bd807b582401e8990898ae25bed2Grant Grundler rtl8211cl_phy_init(dev); 1270610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1271610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, 1272610d885d3176bd807b582401e8990898ae25bed2Grant Grundler BMCR_RESET | BMCR_ANENABLE); 1273610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, 1274610d885d3176bd807b582401e8990898ae25bed2Grant Grundler ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); 1275610d885d3176bd807b582401e8990898ae25bed2Grant Grundler asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000, 1276610d885d3176bd807b582401e8990898ae25bed2Grant Grundler ADVERTISE_1000FULL); 1277610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1278610d885d3176bd807b582401e8990898ae25bed2Grant Grundler mii_nway_restart(&dev->mii); 1279610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 128083e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT); 128183e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 128283e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler return ret; 1283610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 128471bc5d94061516c4e70303570128797bcf768b10Jussi Kivilinna /* Rewrite MAC address */ 128571bc5d94061516c4e70303570128797bcf768b10Jussi Kivilinna memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); 128671bc5d94061516c4e70303570128797bcf768b10Jussi Kivilinna ret = asix_write_cmd(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, 128771bc5d94061516c4e70303570128797bcf768b10Jussi Kivilinna data->mac_addr); 128871bc5d94061516c4e70303570128797bcf768b10Jussi Kivilinna if (ret < 0) 128971bc5d94061516c4e70303570128797bcf768b10Jussi Kivilinna return ret; 129071bc5d94061516c4e70303570128797bcf768b10Jussi Kivilinna 129183e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL); 129283e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) 129383e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler return ret; 1294610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1295610d885d3176bd807b582401e8990898ae25bed2Grant Grundler return 0; 1296610d885d3176bd807b582401e8990898ae25bed2Grant Grundler} 1297610d885d3176bd807b582401e8990898ae25bed2Grant Grundler 1298933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic int ax88178_link_reset(struct usbnet *dev) 1299933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 1300933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u16 mode; 13018ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; 1302933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct asix_data *data = (struct asix_data *)&dev->data; 13038ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny u32 speed; 1304933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 130560b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "ax88178_link_reset()\n"); 1306933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1307933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mii_check_media(&dev->mii, 1, 1); 1308933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mii_ethtool_gset(&dev->mii, &ecmd); 1309933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mode = AX88178_MEDIUM_DEFAULT; 13108ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny speed = ethtool_cmd_speed(&ecmd); 1311933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 13128ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny if (speed == SPEED_1000) 1313a7f75c0c9cfb628512b30795bcba02c8a97e03a0Pantelis Koukousoulas mode |= AX_MEDIUM_GM; 13148ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny else if (speed == SPEED_100) 1315933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mode |= AX_MEDIUM_PS; 1316933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis else 1317933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM); 1318933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1319a7f75c0c9cfb628512b30795bcba02c8a97e03a0Pantelis Koukousoulas mode |= AX_MEDIUM_ENCK; 1320a7f75c0c9cfb628512b30795bcba02c8a97e03a0Pantelis Koukousoulas 1321933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (ecmd.duplex == DUPLEX_FULL) 1322933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mode |= AX_MEDIUM_FD; 1323933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis else 1324933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mode &= ~AX_MEDIUM_FD; 1325933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 13268ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n", 13278ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny speed, ecmd.duplex, mode); 1328933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1329933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_write_medium_mode(dev, mode); 1330933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1331933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (data->phymode == PHY_MODE_MARVELL && data->ledmode) 13328ae6daca85c8bbd6a32c382db5e2a2a989f8bed2David Decotigny marvell_led_status(dev, speed); 1333933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1334933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 0; 1335933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 1336933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1337933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic void ax88178_set_mfb(struct usbnet *dev) 1338933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 1339933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u16 mfb = AX_RX_CTL_MFB_16384; 1340933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u16 rxctl; 1341933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis u16 medium; 1342933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis int old_rx_urb_size = dev->rx_urb_size; 1343933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1344933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (dev->hard_mtu < 2048) { 1345933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->rx_urb_size = 2048; 1346933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mfb = AX_RX_CTL_MFB_2048; 1347933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } else if (dev->hard_mtu < 4096) { 1348933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->rx_urb_size = 4096; 1349933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mfb = AX_RX_CTL_MFB_4096; 1350933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } else if (dev->hard_mtu < 8192) { 1351933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->rx_urb_size = 8192; 1352933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mfb = AX_RX_CTL_MFB_8192; 1353933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } else if (dev->hard_mtu < 16384) { 1354933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->rx_urb_size = 16384; 1355933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis mfb = AX_RX_CTL_MFB_16384; 13562e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 1357933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1358933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis rxctl = asix_read_rx_ctl(dev); 1359933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb); 1360933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1361933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis medium = asix_read_medium_status(dev); 1362933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (dev->net->mtu > 1500) 1363933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis medium |= AX_MEDIUM_JFE; 1364933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis else 1365933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis medium &= ~AX_MEDIUM_JFE; 1366933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis asix_write_medium_mode(dev, medium); 1367933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1368933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (dev->rx_urb_size > old_rx_urb_size) 1369933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis usbnet_unlink_rx_urbs(dev); 13702e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 13712e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1372933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic int ax88178_change_mtu(struct net_device *net, int new_mtu) 13732e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 1374933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis struct usbnet *dev = netdev_priv(net); 1375933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis int ll_mtu = new_mtu + net->hard_header_len + 4; 13762e55cc7210fef90f88201e860d8767594974574eDavid Brownell 137760b86755929e1a7e9038c8d860a8491cfdf8d93aJoe Perches netdev_dbg(dev->net, "ax88178_change_mtu() new_mtu=%d\n", new_mtu); 13782e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1379933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (new_mtu <= 0 || ll_mtu > 16384) 1380933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return -EINVAL; 1381933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1382933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if ((ll_mtu % dev->maxpacket) == 0) 1383933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return -EDOM; 1384933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1385933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis net->mtu = new_mtu; 1386933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->hard_mtu = net->mtu + net->hard_header_len; 1387933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis ax88178_set_mfb(dev); 1388933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1389933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis return 0; 1390933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis} 1391933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 13921703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemmingerstatic const struct net_device_ops ax88178_netdev_ops = { 13931703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_open = usbnet_open, 13941703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_stop = usbnet_stop, 13951703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_start_xmit = usbnet_start_xmit, 13961703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_tx_timeout = usbnet_tx_timeout, 13977f29a3baa825725d29db399663790d15c78cddcfJussi Kivilinna .ndo_set_mac_address = asix_set_mac_address, 13981703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_validate_addr = eth_validate_addr, 1399afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = asix_set_multicast, 14001703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_do_ioctl = asix_ioctl, 14011703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger .ndo_change_mtu = ax88178_change_mtu, 14021703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger}; 14031703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger 1404933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) 1405933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis{ 1406933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis int ret; 140751bf2976b55d07f9daae9697a0a3ac9f58abcedcAl Viro u8 buf[ETH_ALEN]; 140879de9efdb93d8e693dccd0eb7d80cd6092f5875bGrant Grundler struct asix_data *data = (struct asix_data *)&dev->data; 140979de9efdb93d8e693dccd0eb7d80cd6092f5875bGrant Grundler 141079de9efdb93d8e693dccd0eb7d80cd6092f5875bGrant Grundler data->eeprom_len = AX88772_EEPROM_LEN; 1411933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1412933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis usbnet_get_endpoints(dev,intf); 1413933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1414933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis /* Get the MAC address */ 141583e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf); 141683e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler if (ret < 0) { 1417933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dbg("Failed to read MAC address: %d", ret); 141883e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler return ret; 14192e55cc7210fef90f88201e860d8767594974574eDavid Brownell } 1420933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis memcpy(dev->net->dev_addr, buf, ETH_ALEN); 14212e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1422933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis /* Initialize MII structure */ 1423933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->mii.dev = dev->net; 1424933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->mii.mdio_read = asix_mdio_read; 1425933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->mii.mdio_write = asix_mdio_write; 1426933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->mii.phy_id_mask = 0x1f; 1427933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->mii.reg_num_mask = 0xff; 1428933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->mii.supports_gmii = 1; 1429933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->mii.phy_id = asix_get_phy_addr(dev); 14301703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger 14311703338c79f39178535fe54b5aeaebf9c42300f6Stephen Hemminger dev->net->netdev_ops = &ax88178_netdev_ops; 1432933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->net->ethtool_ops = &ax88178_ethtool_ops; 14332e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1434b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler /* Blink LEDS so users know driver saw dongle */ 1435b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler asix_sw_reset(dev, 0); 1436b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler msleep(150); 14372e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1438b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); 1439b2d3ad291fab1783cc12eef3dd91c5fa98c2e5d5Grant Grundler msleep(150); 1440933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1441933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ 1442933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis if (dev->driver_info->flags & FLAG_FRAMING_AX) { 1443933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis /* hard_mtu is still the default - the device does not support 1444933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis jumbo eth frames */ 1445933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis dev->rx_urb_size = 2048; 1446933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis } 1447933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 144883e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler return 0; 14492e55cc7210fef90f88201e860d8767594974574eDavid Brownell} 14502e55cc7210fef90f88201e860d8767594974574eDavid Brownell 14512e55cc7210fef90f88201e860d8767594974574eDavid Brownellstatic const struct driver_info ax8817x_info = { 14522e55cc7210fef90f88201e860d8767594974574eDavid Brownell .description = "ASIX AX8817x USB 2.0 Ethernet", 145348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .bind = ax88172_bind, 145448b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .status = asix_status, 14552e55cc7210fef90f88201e860d8767594974574eDavid Brownell .link_reset = ax88172_link_reset, 14562e55cc7210fef90f88201e860d8767594974574eDavid Brownell .reset = ax88172_link_reset, 145737e8273cd30592d3a82bcb70cbb1bdc4eaeb6b71Ben Hutchings .flags = FLAG_ETHER | FLAG_LINK_INTR, 14582e55cc7210fef90f88201e860d8767594974574eDavid Brownell .data = 0x00130103, 14592e55cc7210fef90f88201e860d8767594974574eDavid Brownell}; 14602e55cc7210fef90f88201e860d8767594974574eDavid Brownell 14612e55cc7210fef90f88201e860d8767594974574eDavid Brownellstatic const struct driver_info dlink_dub_e100_info = { 14622e55cc7210fef90f88201e860d8767594974574eDavid Brownell .description = "DLink DUB-E100 USB Ethernet", 146348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .bind = ax88172_bind, 146448b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .status = asix_status, 14652e55cc7210fef90f88201e860d8767594974574eDavid Brownell .link_reset = ax88172_link_reset, 14662e55cc7210fef90f88201e860d8767594974574eDavid Brownell .reset = ax88172_link_reset, 146737e8273cd30592d3a82bcb70cbb1bdc4eaeb6b71Ben Hutchings .flags = FLAG_ETHER | FLAG_LINK_INTR, 14682e55cc7210fef90f88201e860d8767594974574eDavid Brownell .data = 0x009f9d9f, 14692e55cc7210fef90f88201e860d8767594974574eDavid Brownell}; 14702e55cc7210fef90f88201e860d8767594974574eDavid Brownell 14712e55cc7210fef90f88201e860d8767594974574eDavid Brownellstatic const struct driver_info netgear_fa120_info = { 14722e55cc7210fef90f88201e860d8767594974574eDavid Brownell .description = "Netgear FA-120 USB Ethernet", 147348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .bind = ax88172_bind, 147448b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .status = asix_status, 14752e55cc7210fef90f88201e860d8767594974574eDavid Brownell .link_reset = ax88172_link_reset, 14762e55cc7210fef90f88201e860d8767594974574eDavid Brownell .reset = ax88172_link_reset, 147737e8273cd30592d3a82bcb70cbb1bdc4eaeb6b71Ben Hutchings .flags = FLAG_ETHER | FLAG_LINK_INTR, 14782e55cc7210fef90f88201e860d8767594974574eDavid Brownell .data = 0x00130103, 14792e55cc7210fef90f88201e860d8767594974574eDavid Brownell}; 14802e55cc7210fef90f88201e860d8767594974574eDavid Brownell 14812e55cc7210fef90f88201e860d8767594974574eDavid Brownellstatic const struct driver_info hawking_uf200_info = { 14822e55cc7210fef90f88201e860d8767594974574eDavid Brownell .description = "Hawking UF200 USB Ethernet", 148348b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .bind = ax88172_bind, 148448b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .status = asix_status, 14852e55cc7210fef90f88201e860d8767594974574eDavid Brownell .link_reset = ax88172_link_reset, 14862e55cc7210fef90f88201e860d8767594974574eDavid Brownell .reset = ax88172_link_reset, 148737e8273cd30592d3a82bcb70cbb1bdc4eaeb6b71Ben Hutchings .flags = FLAG_ETHER | FLAG_LINK_INTR, 14882e55cc7210fef90f88201e860d8767594974574eDavid Brownell .data = 0x001f1d1f, 14892e55cc7210fef90f88201e860d8767594974574eDavid Brownell}; 14902e55cc7210fef90f88201e860d8767594974574eDavid Brownell 14912e55cc7210fef90f88201e860d8767594974574eDavid Brownellstatic const struct driver_info ax88772_info = { 14922e55cc7210fef90f88201e860d8767594974574eDavid Brownell .description = "ASIX AX88772 USB 2.0 Ethernet", 14932e55cc7210fef90f88201e860d8767594974574eDavid Brownell .bind = ax88772_bind, 149448b1be6ac080c3bb5ad3e529d8816953507790abDavid Hollis .status = asix_status, 14952e55cc7210fef90f88201e860d8767594974574eDavid Brownell .link_reset = ax88772_link_reset, 14964ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant Grundler .reset = ax88772_reset, 1497a9e0aca4b37885b5599e52211f098bd7f565e749Eric Dumazet .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET, 1498933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .rx_fixup = asix_rx_fixup, 1499933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .tx_fixup = asix_tx_fixup, 1500933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis}; 1501933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis 1502933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollisstatic const struct driver_info ax88178_info = { 1503933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .description = "ASIX AX88178 USB 2.0 Ethernet", 1504933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .bind = ax88178_bind, 1505933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .status = asix_status, 1506933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .link_reset = ax88178_link_reset, 1507610d885d3176bd807b582401e8990898ae25bed2Grant Grundler .reset = ax88178_reset, 150837e8273cd30592d3a82bcb70cbb1bdc4eaeb6b71Ben Hutchings .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, 1509933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .rx_fixup = asix_rx_fixup, 1510933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .tx_fixup = asix_tx_fixup, 15112e55cc7210fef90f88201e860d8767594974574eDavid Brownell}; 15122e55cc7210fef90f88201e860d8767594974574eDavid Brownell 15132e55cc7210fef90f88201e860d8767594974574eDavid Brownellstatic const struct usb_device_id products [] = { 15142e55cc7210fef90f88201e860d8767594974574eDavid Brownell{ 15152e55cc7210fef90f88201e860d8767594974574eDavid Brownell // Linksys USB200M 15162e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DEVICE (0x077b, 0x2226), 15172e55cc7210fef90f88201e860d8767594974574eDavid Brownell .driver_info = (unsigned long) &ax8817x_info, 15182e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 15192e55cc7210fef90f88201e860d8767594974574eDavid Brownell // Netgear FA120 15202e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DEVICE (0x0846, 0x1040), 15212e55cc7210fef90f88201e860d8767594974574eDavid Brownell .driver_info = (unsigned long) &netgear_fa120_info, 15222e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 15232e55cc7210fef90f88201e860d8767594974574eDavid Brownell // DLink DUB-E100 15242e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DEVICE (0x2001, 0x1a00), 15252e55cc7210fef90f88201e860d8767594974574eDavid Brownell .driver_info = (unsigned long) &dlink_dub_e100_info, 15262e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 15272e55cc7210fef90f88201e860d8767594974574eDavid Brownell // Intellinet, ST Lab USB Ethernet 15282e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DEVICE (0x0b95, 0x1720), 15292e55cc7210fef90f88201e860d8767594974574eDavid Brownell .driver_info = (unsigned long) &ax8817x_info, 15302e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 15312e55cc7210fef90f88201e860d8767594974574eDavid Brownell // Hawking UF200, TrendNet TU2-ET100 15322e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DEVICE (0x07b8, 0x420a), 15332e55cc7210fef90f88201e860d8767594974574eDavid Brownell .driver_info = (unsigned long) &hawking_uf200_info, 15342e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 153539c4b38cad00287cfd92cb66fec7c9a3edf50f2aDavid Hollis // Billionton Systems, USB2AR 153639c4b38cad00287cfd92cb66fec7c9a3edf50f2aDavid Hollis USB_DEVICE (0x08dd, 0x90ff), 153739c4b38cad00287cfd92cb66fec7c9a3edf50f2aDavid Hollis .driver_info = (unsigned long) &ax8817x_info, 15382e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 15392e55cc7210fef90f88201e860d8767594974574eDavid Brownell // ATEN UC210T 15402e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DEVICE (0x0557, 0x2009), 15412e55cc7210fef90f88201e860d8767594974574eDavid Brownell .driver_info = (unsigned long) &ax8817x_info, 15422e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 15432e55cc7210fef90f88201e860d8767594974574eDavid Brownell // Buffalo LUA-U2-KTX 15442e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DEVICE (0x0411, 0x003d), 15452e55cc7210fef90f88201e860d8767594974574eDavid Brownell .driver_info = (unsigned long) &ax8817x_info, 15462e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 1547ac7b77f13f2f33270276f88ad0f427e031552e04Mattia Dongili // Buffalo LUA-U2-GT 10/100/1000 1548ac7b77f13f2f33270276f88ad0f427e031552e04Mattia Dongili USB_DEVICE (0x0411, 0x006e), 1549ac7b77f13f2f33270276f88ad0f427e031552e04Mattia Dongili .driver_info = (unsigned long) &ax88178_info, 1550ac7b77f13f2f33270276f88ad0f427e031552e04Mattia Dongili}, { 15512e55cc7210fef90f88201e860d8767594974574eDavid Brownell // Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter" 15522e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DEVICE (0x6189, 0x182d), 15532e55cc7210fef90f88201e860d8767594974574eDavid Brownell .driver_info = (unsigned long) &ax8817x_info, 15542e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 15554e50391968849860dff1aacde358b4eb14aa5127Joerg Neikes // Sitecom LN-031 "USB 2.0 10/100/1000 Ethernet adapter" 15564e50391968849860dff1aacde358b4eb14aa5127Joerg Neikes USB_DEVICE (0x0df6, 0x0056), 15574e50391968849860dff1aacde358b4eb14aa5127Joerg Neikes .driver_info = (unsigned long) &ax88178_info, 15584e50391968849860dff1aacde358b4eb14aa5127Joerg Neikes}, { 15592e55cc7210fef90f88201e860d8767594974574eDavid Brownell // corega FEther USB2-TX 15602e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DEVICE (0x07aa, 0x0017), 15612e55cc7210fef90f88201e860d8767594974574eDavid Brownell .driver_info = (unsigned long) &ax8817x_info, 15622e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 15632e55cc7210fef90f88201e860d8767594974574eDavid Brownell // Surecom EP-1427X-2 15642e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DEVICE (0x1189, 0x0893), 15652e55cc7210fef90f88201e860d8767594974574eDavid Brownell .driver_info = (unsigned long) &ax8817x_info, 15662e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 15672e55cc7210fef90f88201e860d8767594974574eDavid Brownell // goodway corp usb gwusb2e 15682e55cc7210fef90f88201e860d8767594974574eDavid Brownell USB_DEVICE (0x1631, 0x6200), 15692e55cc7210fef90f88201e860d8767594974574eDavid Brownell .driver_info = (unsigned long) &ax8817x_info, 15702e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, { 157139c4b38cad00287cfd92cb66fec7c9a3edf50f2aDavid Hollis // JVC MP-PRX1 Port Replicator 157239c4b38cad00287cfd92cb66fec7c9a3edf50f2aDavid Hollis USB_DEVICE (0x04f1, 0x3008), 157339c4b38cad00287cfd92cb66fec7c9a3edf50f2aDavid Hollis .driver_info = (unsigned long) &ax8817x_info, 157439c4b38cad00287cfd92cb66fec7c9a3edf50f2aDavid Hollis}, { 1575308859097831831a979f2e82cbeef0a94f438080Marek Vasut // ASIX AX88772B 10/100 1576308859097831831a979f2e82cbeef0a94f438080Marek Vasut USB_DEVICE (0x0b95, 0x772b), 1577308859097831831a979f2e82cbeef0a94f438080Marek Vasut .driver_info = (unsigned long) &ax88772_info, 1578308859097831831a979f2e82cbeef0a94f438080Marek Vasut}, { 15792e55cc7210fef90f88201e860d8767594974574eDavid Brownell // ASIX AX88772 10/100 158039c4b38cad00287cfd92cb66fec7c9a3edf50f2aDavid Hollis USB_DEVICE (0x0b95, 0x7720), 158139c4b38cad00287cfd92cb66fec7c9a3edf50f2aDavid Hollis .driver_info = (unsigned long) &ax88772_info, 15825e0f76c6bbc0d26cd9625876f7beeb7b002f39bfDavid Hollis}, { 15837327413c745c2f8e8d4b92f76759821263b095c1Eduard Warkentin // ASIX AX88178 10/100/1000 15847327413c745c2f8e8d4b92f76759821263b095c1Eduard Warkentin USB_DEVICE (0x0b95, 0x1780), 1585933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .driver_info = (unsigned long) &ax88178_info, 15867327413c745c2f8e8d4b92f76759821263b095c1Eduard Warkentin}, { 1587f4680d3db71f13d2764340a9880745bf54f2469dArnaud Ebalard // Logitec LAN-GTJ/U2A 1588f4680d3db71f13d2764340a9880745bf54f2469dArnaud Ebalard USB_DEVICE (0x0789, 0x0160), 1589f4680d3db71f13d2764340a9880745bf54f2469dArnaud Ebalard .driver_info = (unsigned long) &ax88178_info, 1590f4680d3db71f13d2764340a9880745bf54f2469dArnaud Ebalard}, { 15915e0f76c6bbc0d26cd9625876f7beeb7b002f39bfDavid Hollis // Linksys USB200M Rev 2 15925e0f76c6bbc0d26cd9625876f7beeb7b002f39bfDavid Hollis USB_DEVICE (0x13b1, 0x0018), 15935e0f76c6bbc0d26cd9625876f7beeb7b002f39bfDavid Hollis .driver_info = (unsigned long) &ax88772_info, 15945732ce8424527ec271e8fa43709948852aa3fc0aDavid Hollis}, { 15955732ce8424527ec271e8fa43709948852aa3fc0aDavid Hollis // 0Q0 cable ethernet 15965732ce8424527ec271e8fa43709948852aa3fc0aDavid Hollis USB_DEVICE (0x1557, 0x7720), 15975732ce8424527ec271e8fa43709948852aa3fc0aDavid Hollis .driver_info = (unsigned long) &ax88772_info, 1598933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis}, { 1599933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis // DLink DUB-E100 H/W Ver B1 1600933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis USB_DEVICE (0x07d1, 0x3c05), 1601933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .driver_info = (unsigned long) &ax88772_info, 1602933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis}, { 1603b923e7fcc152199959b673e09c318a750a10928bDavid Hollis // DLink DUB-E100 H/W Ver B1 Alternate 1604b923e7fcc152199959b673e09c318a750a10928bDavid Hollis USB_DEVICE (0x2001, 0x3c05), 1605b923e7fcc152199959b673e09c318a750a10928bDavid Hollis .driver_info = (unsigned long) &ax88772_info, 1606b923e7fcc152199959b673e09c318a750a10928bDavid Hollis}, { 1607933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis // Linksys USB1000 1608933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis USB_DEVICE (0x1737, 0x0039), 1609933a27d39e0e57ba56cff2e4ebe92cf23f4cd815David Hollis .driver_info = (unsigned long) &ax88178_info, 1610b29cf31d7ee7da285265577b0df5e62c6b5a6119YOSHIFUJI Hideaki / 吉藤英明}, { 1611b29cf31d7ee7da285265577b0df5e62c6b5a6119YOSHIFUJI Hideaki / 吉藤英明 // IO-DATA ETG-US2 1612b29cf31d7ee7da285265577b0df5e62c6b5a6119YOSHIFUJI Hideaki / 吉藤英明 USB_DEVICE (0x04bb, 0x0930), 1613b29cf31d7ee7da285265577b0df5e62c6b5a6119YOSHIFUJI Hideaki / 吉藤英明 .driver_info = (unsigned long) &ax88178_info, 16142ed22bc294315d19aa1f0423b83d21a2d94c641bDavid Hollis}, { 16152ed22bc294315d19aa1f0423b83d21a2d94c641bDavid Hollis // Belkin F5D5055 16162ed22bc294315d19aa1f0423b83d21a2d94c641bDavid Hollis USB_DEVICE(0x050d, 0x5055), 16172ed22bc294315d19aa1f0423b83d21a2d94c641bDavid Hollis .driver_info = (unsigned long) &ax88178_info, 16183d60efb55f634e200fd99e0960a8e099fb38446aAurelien Nephtali}, { 16193d60efb55f634e200fd99e0960a8e099fb38446aAurelien Nephtali // Apple USB Ethernet Adapter 16203d60efb55f634e200fd99e0960a8e099fb38446aAurelien Nephtali USB_DEVICE(0x05ac, 0x1402), 16213d60efb55f634e200fd99e0960a8e099fb38446aAurelien Nephtali .driver_info = (unsigned long) &ax88772_info, 1622ccf95402d0ae6f433f29ce88cfd589cec8fc81adJason Cooper}, { 1623ccf95402d0ae6f433f29ce88cfd589cec8fc81adJason Cooper // Cables-to-Go USB Ethernet Adapter 1624ccf95402d0ae6f433f29ce88cfd589cec8fc81adJason Cooper USB_DEVICE(0x0b95, 0x772a), 1625ccf95402d0ae6f433f29ce88cfd589cec8fc81adJason Cooper .driver_info = (unsigned long) &ax88772_info, 1626fef7cc0893146550b286b13c0e6e914556142730Greg Kroah-Hartman}, { 1627fef7cc0893146550b286b13c0e6e914556142730Greg Kroah-Hartman // ABOCOM for pci 1628fef7cc0893146550b286b13c0e6e914556142730Greg Kroah-Hartman USB_DEVICE(0x14ea, 0xab11), 1629fef7cc0893146550b286b13c0e6e914556142730Greg Kroah-Hartman .driver_info = (unsigned long) &ax88178_info, 1630fef7cc0893146550b286b13c0e6e914556142730Greg Kroah-Hartman}, { 1631fef7cc0893146550b286b13c0e6e914556142730Greg Kroah-Hartman // ASIX 88772a 1632fef7cc0893146550b286b13c0e6e914556142730Greg Kroah-Hartman USB_DEVICE(0x0db0, 0xa877), 1633fef7cc0893146550b286b13c0e6e914556142730Greg Kroah-Hartman .driver_info = (unsigned long) &ax88772_info, 1634e8303a3b2196272c3eb994d0fd1a189a958a2bddAurelien Jacobs}, { 1635e8303a3b2196272c3eb994d0fd1a189a958a2bddAurelien Jacobs // Asus USB Ethernet Adapter 1636e8303a3b2196272c3eb994d0fd1a189a958a2bddAurelien Jacobs USB_DEVICE (0x0b95, 0x7e2b), 1637e8303a3b2196272c3eb994d0fd1a189a958a2bddAurelien Jacobs .driver_info = (unsigned long) &ax88772_info, 16382e55cc7210fef90f88201e860d8767594974574eDavid Brownell}, 16392e55cc7210fef90f88201e860d8767594974574eDavid Brownell { }, // END 16402e55cc7210fef90f88201e860d8767594974574eDavid Brownell}; 16412e55cc7210fef90f88201e860d8767594974574eDavid BrownellMODULE_DEVICE_TABLE(usb, products); 16422e55cc7210fef90f88201e860d8767594974574eDavid Brownell 16432e55cc7210fef90f88201e860d8767594974574eDavid Brownellstatic struct usb_driver asix_driver = { 164483e1b91845403f6322284a6e74581cc47d57de9fGrant Grundler .name = DRIVER_NAME, 16452e55cc7210fef90f88201e860d8767594974574eDavid Brownell .id_table = products, 16462e55cc7210fef90f88201e860d8767594974574eDavid Brownell .probe = usbnet_probe, 16472e55cc7210fef90f88201e860d8767594974574eDavid Brownell .suspend = usbnet_suspend, 16482e55cc7210fef90f88201e860d8767594974574eDavid Brownell .resume = usbnet_resume, 16492e55cc7210fef90f88201e860d8767594974574eDavid Brownell .disconnect = usbnet_disconnect, 1650a11a6544c0bf6c0871f2379ad0c5ad0210691e73Oliver Neukum .supports_autosuspend = 1, 16512e55cc7210fef90f88201e860d8767594974574eDavid Brownell}; 16522e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1653d632eb1bf22e11def74e4e53cc47d790fbdba105Greg Kroah-Hartmanmodule_usb_driver(asix_driver); 16542e55cc7210fef90f88201e860d8767594974574eDavid Brownell 16552e55cc7210fef90f88201e860d8767594974574eDavid BrownellMODULE_AUTHOR("David Hollis"); 16564ad1438f025ed8d1e4e95a796ca7f0ad5a22c378Grant GrundlerMODULE_VERSION(DRIVER_VERSION); 16572e55cc7210fef90f88201e860d8767594974574eDavid BrownellMODULE_DESCRIPTION("ASIX AX8817X based USB 2.0 Ethernet Devices"); 16582e55cc7210fef90f88201e860d8767594974574eDavid BrownellMODULE_LICENSE("GPL"); 16592e55cc7210fef90f88201e860d8767594974574eDavid Brownell 1660