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