xref: /illumos-gate/usr/src/uts/common/io/axf/axf_usbgem.c (revision 2d6eb4a5)
16716431bSRobert Mustacchi /*
26716431bSRobert Mustacchi  * axf_usbgem.c : ASIX AX88172/772 USB to Fast Ethernet Driver for Solaris
36716431bSRobert Mustacchi  *
46716431bSRobert Mustacchi  * Copyright (c) 2004-2012 Masayuki Murayama.  All rights reserved.
56716431bSRobert Mustacchi  *
66716431bSRobert Mustacchi  * Redistribution and use in source and binary forms, with or without
76716431bSRobert Mustacchi  * modification, are permitted provided that the following conditions are met:
86716431bSRobert Mustacchi  *
96716431bSRobert Mustacchi  * 1. Redistributions of source code must retain the above copyright notice,
106716431bSRobert Mustacchi  *    this list of conditions and the following disclaimer.
116716431bSRobert Mustacchi  *
126716431bSRobert Mustacchi  * 2. Redistributions in binary form must reproduce the above copyright notice,
136716431bSRobert Mustacchi  *    this list of conditions and the following disclaimer in the documentation
146716431bSRobert Mustacchi  *    and/or other materials provided with the distribution.
156716431bSRobert Mustacchi  *
166716431bSRobert Mustacchi  * 3. Neither the name of the author nor the names of its contributors may be
176716431bSRobert Mustacchi  *    used to endorse or promote products derived from this software without
186716431bSRobert Mustacchi  *    specific prior written permission.
196716431bSRobert Mustacchi  *
206716431bSRobert Mustacchi  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
216716431bSRobert Mustacchi  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
226716431bSRobert Mustacchi  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
236716431bSRobert Mustacchi  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
246716431bSRobert Mustacchi  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
256716431bSRobert Mustacchi  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
266716431bSRobert Mustacchi  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
276716431bSRobert Mustacchi  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
286716431bSRobert Mustacchi  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
296716431bSRobert Mustacchi  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
306716431bSRobert Mustacchi  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
316716431bSRobert Mustacchi  * DAMAGE.
326716431bSRobert Mustacchi  */
336716431bSRobert Mustacchi 
346716431bSRobert Mustacchi /*
356716431bSRobert Mustacchi  *  Changelog:
366716431bSRobert Mustacchi  */
376716431bSRobert Mustacchi 
386716431bSRobert Mustacchi /*
396716431bSRobert Mustacchi  * TODO
406716431bSRobert Mustacchi  * handle RXMODE_ENABLE in set_rx_filter()
416716431bSRobert Mustacchi  */
426716431bSRobert Mustacchi /* ======================================================= */
436716431bSRobert Mustacchi 
446716431bSRobert Mustacchi /*
456716431bSRobert Mustacchi  * Solaris system header files and macros
466716431bSRobert Mustacchi  */
476716431bSRobert Mustacchi 
486716431bSRobert Mustacchi /* minimum kernel headers for drivers */
496716431bSRobert Mustacchi #include <sys/types.h>
506716431bSRobert Mustacchi #include <sys/conf.h>
516716431bSRobert Mustacchi #include <sys/debug.h>
526716431bSRobert Mustacchi #include <sys/kmem.h>
536716431bSRobert Mustacchi #include <sys/modctl.h>
546716431bSRobert Mustacchi #include <sys/errno.h>
556716431bSRobert Mustacchi #include <sys/ddi.h>
566716431bSRobert Mustacchi #include <sys/sunddi.h>
576716431bSRobert Mustacchi #include <sys/byteorder.h>
586716431bSRobert Mustacchi 
596716431bSRobert Mustacchi /* ethernet stuff */
606716431bSRobert Mustacchi #include <sys/ethernet.h>
616716431bSRobert Mustacchi 
626716431bSRobert Mustacchi /* interface card depend stuff */
636716431bSRobert Mustacchi #include <sys/stropts.h>
646716431bSRobert Mustacchi #include <sys/stream.h>
656716431bSRobert Mustacchi #include <sys/strlog.h>
666716431bSRobert Mustacchi #include <sys/usb/usba.h>
676716431bSRobert Mustacchi #include "usbgem.h"
686716431bSRobert Mustacchi 
696716431bSRobert Mustacchi /* hardware stuff */
706716431bSRobert Mustacchi #include "usbgem_mii.h"
716716431bSRobert Mustacchi #include "ax88172reg.h"
726716431bSRobert Mustacchi 
736716431bSRobert Mustacchi char	ident[] = "ax88x72 usbnic driver v" VERSION;
746716431bSRobert Mustacchi 
756716431bSRobert Mustacchi /*
766716431bSRobert Mustacchi  * Useful macros
776716431bSRobert Mustacchi  */
786716431bSRobert Mustacchi #define	CHECK_AND_JUMP(err, label)	if (err != USB_SUCCESS) goto label
796716431bSRobert Mustacchi #define	LE16P(p)	((((uint8_t *)(p))[1] << 8) | ((uint8_t *)(p))[0])
806716431bSRobert Mustacchi 
816716431bSRobert Mustacchi #define	AX88172(dp)	\
826716431bSRobert Mustacchi 	(((struct axf_dev *)(dp)->private)->chip->type == CHIP_TYPE_AX88172)
836716431bSRobert Mustacchi 
846716431bSRobert Mustacchi #define	AX88772(dp)	\
856716431bSRobert Mustacchi 	(((struct axf_dev *)(dp)->private)->chip->type == CHIP_TYPE_AX88772)
866716431bSRobert Mustacchi 
876716431bSRobert Mustacchi /*
886716431bSRobert Mustacchi  * Debugging
896716431bSRobert Mustacchi  */
906716431bSRobert Mustacchi #ifdef DEBUG_LEVEL
916716431bSRobert Mustacchi static int axf_debug = DEBUG_LEVEL;
926716431bSRobert Mustacchi #define	DPRINTF(n, args)	if (axf_debug > (n)) cmn_err args
936716431bSRobert Mustacchi #else
946716431bSRobert Mustacchi #define	DPRINTF(n, args)
956716431bSRobert Mustacchi #endif
966716431bSRobert Mustacchi 
976716431bSRobert Mustacchi /*
986716431bSRobert Mustacchi  * Our configration for ax88172
996716431bSRobert Mustacchi  */
1006716431bSRobert Mustacchi /* timeouts */
1016716431bSRobert Mustacchi #define	ONESEC		(drv_usectohz(1*1000000))
1026716431bSRobert Mustacchi 
1036716431bSRobert Mustacchi /*
1046716431bSRobert Mustacchi  * RX/TX buffer size
1056716431bSRobert Mustacchi  */
1066716431bSRobert Mustacchi 
1076716431bSRobert Mustacchi /*
1086716431bSRobert Mustacchi  * Local device definitions
1096716431bSRobert Mustacchi  */
1106716431bSRobert Mustacchi struct chip_info {
1116716431bSRobert Mustacchi 	uint16_t	vid;	/* usb vendor id */
1126716431bSRobert Mustacchi 	uint16_t	pid;	/* usb product id */
1136716431bSRobert Mustacchi 	int		type;
1146716431bSRobert Mustacchi 	uint8_t		gpio_reset[2];
1156716431bSRobert Mustacchi 	uint8_t		gpio_speed[2];
1166716431bSRobert Mustacchi 	uint8_t		gpio_duplex[2];
1176716431bSRobert Mustacchi 	char		*name;
1186716431bSRobert Mustacchi #define	CHIP_TYPE_AX88172	0
1196716431bSRobert Mustacchi #define	CHIP_TYPE_AX88772	1
1206716431bSRobert Mustacchi #define	CHIP_TYPE_AX88178	2
1216716431bSRobert Mustacchi };
1226716431bSRobert Mustacchi 
1236716431bSRobert Mustacchi #define	GPIO_DEFAULT	{0x00, 0x15}, {0, 0}, {0, 0}
1246716431bSRobert Mustacchi struct chip_info chiptbl_88x7x[] = {
1256716431bSRobert Mustacchi /* AX88172 */
1266716431bSRobert Mustacchi {
1276716431bSRobert Mustacchi 	/* Planex UE2-100TX, Hawking UF200, TrendNet TU2-ET100 */
1286716431bSRobert Mustacchi 	0x07b8, 0x420a, CHIP_TYPE_AX88172,
1296716431bSRobert Mustacchi 
1306716431bSRobert Mustacchi 	/*
1316716431bSRobert Mustacchi 	 * the default setting covers below:
1326716431bSRobert Mustacchi 	 * gpio bit2 has to be 0 and gpio bit0 has to be 1
1336716431bSRobert Mustacchi 	 */
1346716431bSRobert Mustacchi 	{0, 0},
1356716431bSRobert Mustacchi 	{GPIO_EN1, GPIO_DATA1 | GPIO_EN1},
1366716431bSRobert Mustacchi 	{0, 0},
1376716431bSRobert Mustacchi 	"Planex UE2-100TX",	/* tested */
1386716431bSRobert Mustacchi },
1396716431bSRobert Mustacchi {
1406716431bSRobert Mustacchi 	0x2001, 0x1a00, CHIP_TYPE_AX88172,
1416716431bSRobert Mustacchi 	{0x9f, 0x9e}, {0, 0}, {0, 0},
1426716431bSRobert Mustacchi 	"D-Link dube100",	/* XXX */
1436716431bSRobert Mustacchi },
1446716431bSRobert Mustacchi {
1456716431bSRobert Mustacchi 	0x077b, 0x2226, CHIP_TYPE_AX88172,
1466716431bSRobert Mustacchi 	GPIO_DEFAULT,
1476716431bSRobert Mustacchi 	"Linksys USB200M",
1486716431bSRobert Mustacchi },
1496716431bSRobert Mustacchi {
1506716431bSRobert Mustacchi 	0x0846, 0x1040, CHIP_TYPE_AX88172,
1516716431bSRobert Mustacchi 	GPIO_DEFAULT,
1526716431bSRobert Mustacchi 	"Netgear FA120",
1536716431bSRobert Mustacchi },
1546716431bSRobert Mustacchi {
1556716431bSRobert Mustacchi 	0x0b95, 0x1720, CHIP_TYPE_AX88172,
1566716431bSRobert Mustacchi 	GPIO_DEFAULT,
1576716431bSRobert Mustacchi 	"Intellinet, ST Lab USB Ethernet",
1586716431bSRobert Mustacchi },
1596716431bSRobert Mustacchi {
1606716431bSRobert Mustacchi 	0x08dd, 0x90ff, CHIP_TYPE_AX88172,
1616716431bSRobert Mustacchi 	GPIO_DEFAULT,
1626716431bSRobert Mustacchi 	"Billionton Systems, USB2AR",
1636716431bSRobert Mustacchi },
1646716431bSRobert Mustacchi {
1656716431bSRobert Mustacchi 	0x0557, 0x2009, CHIP_TYPE_AX88172,
1666716431bSRobert Mustacchi 	GPIO_DEFAULT,
1676716431bSRobert Mustacchi 	"ATEN UC210T",
1686716431bSRobert Mustacchi },
1696716431bSRobert Mustacchi {
1706716431bSRobert Mustacchi 	0x0411, 0x003d, CHIP_TYPE_AX88172,
1716716431bSRobert Mustacchi 	GPIO_DEFAULT,
1726716431bSRobert Mustacchi 	"Buffalo LUA-U2-KTX",
1736716431bSRobert Mustacchi },
1746716431bSRobert Mustacchi {
1756716431bSRobert Mustacchi 	0x6189, 0x182d, CHIP_TYPE_AX88172,
1766716431bSRobert Mustacchi 	GPIO_DEFAULT,
1776716431bSRobert Mustacchi 	"Sitecom LN-029 USB 2.0 10/100 Ethernet adapter",
1786716431bSRobert Mustacchi },
1796716431bSRobert Mustacchi {
1806716431bSRobert Mustacchi 	0x07aa, 0x0017, CHIP_TYPE_AX88172,
1816716431bSRobert Mustacchi 	GPIO_DEFAULT,
1826716431bSRobert Mustacchi 	"corega FEther USB2-TX",
1836716431bSRobert Mustacchi },
1846716431bSRobert Mustacchi {
1856716431bSRobert Mustacchi 	0x1189, 0x0893, CHIP_TYPE_AX88172,
1866716431bSRobert Mustacchi 	GPIO_DEFAULT,
1876716431bSRobert Mustacchi 	"Surecom EP-1427X-2",
1886716431bSRobert Mustacchi },
1896716431bSRobert Mustacchi {
1906716431bSRobert Mustacchi 	0x1631, 0x6200, CHIP_TYPE_AX88172,
1916716431bSRobert Mustacchi 	GPIO_DEFAULT,
1926716431bSRobert Mustacchi 	"goodway corp usb gwusb2e",
1936716431bSRobert Mustacchi },
1946716431bSRobert Mustacchi /* AX88772 and AX88178 */
1956716431bSRobert Mustacchi {
1966716431bSRobert Mustacchi 	0x13b1, 0x0018, CHIP_TYPE_AX88772,
1976716431bSRobert Mustacchi 	{0, 0}, {0, 0}, {0, 0},
1986716431bSRobert Mustacchi 	"Linksys USB200M rev.2",
1996716431bSRobert Mustacchi },
2006716431bSRobert Mustacchi {
2016716431bSRobert Mustacchi 	0x1557, 0x7720, CHIP_TYPE_AX88772,
2026716431bSRobert Mustacchi 	{0, 0}, {0, 0}, {0, 0},
2036716431bSRobert Mustacchi 	"0Q0 cable ethernet",
2046716431bSRobert Mustacchi },
2056716431bSRobert Mustacchi {
2066716431bSRobert Mustacchi 	0x07d1, 0x3c05, CHIP_TYPE_AX88772,
2076716431bSRobert Mustacchi 	{0, 0}, {0, 0}, {0, 0},
2086716431bSRobert Mustacchi 	"DLink DUB E100 ver B1",
2096716431bSRobert Mustacchi },
2106716431bSRobert Mustacchi {
2116716431bSRobert Mustacchi 	0x2001, 0x3c05, CHIP_TYPE_AX88772,
2126716431bSRobert Mustacchi 	{0, 0}, {0, 0}, {0, 0},
2136716431bSRobert Mustacchi 	"DLink DUB E100 ver B1(2)",
2146716431bSRobert Mustacchi },
2156716431bSRobert Mustacchi {
2166716431bSRobert Mustacchi 	0x05ac, 0x1402, CHIP_TYPE_AX88772,
2176716431bSRobert Mustacchi 	{0, 0}, {0, 0}, {0, 0},
2186716431bSRobert Mustacchi 	"Apple Ethernet USB Adapter",
2196716431bSRobert Mustacchi },
2206716431bSRobert Mustacchi {
2216716431bSRobert Mustacchi 	0x1737, 0x0039, CHIP_TYPE_AX88178,
2226716431bSRobert Mustacchi 	{0, 0}, {0, 0}, {0, 0},
2236716431bSRobert Mustacchi 	"Linksys USB1000",
2246716431bSRobert Mustacchi },
2256716431bSRobert Mustacchi {
2266716431bSRobert Mustacchi 	0x0411, 0x006e, CHIP_TYPE_AX88178,
2276716431bSRobert Mustacchi 	{0, 0}, {0, 0}, {0, 0},
2286716431bSRobert Mustacchi 	"Buffalo LUA-U2-KGT/LUA-U2-GT",
2296716431bSRobert Mustacchi },
2306716431bSRobert Mustacchi {
2316716431bSRobert Mustacchi 	0x04bb, 0x0930, CHIP_TYPE_AX88178,
2326716431bSRobert Mustacchi 	{0, 0}, {0, 0}, {0, 0},
2336716431bSRobert Mustacchi 	"I/O DATA ETG-US2",
2346716431bSRobert Mustacchi },
2356716431bSRobert Mustacchi {
2366716431bSRobert Mustacchi 	0x050d, 0x5055, CHIP_TYPE_AX88178,
2376716431bSRobert Mustacchi 	{0, 0}, {0, 0}, {0, 0},
2386716431bSRobert Mustacchi 	"Belkin F5D5055",
2396716431bSRobert Mustacchi },
2406716431bSRobert Mustacchi {
2416716431bSRobert Mustacchi 	/* generic ax88772 must be the last entry */
2426716431bSRobert Mustacchi 	/* planex UE-200TX-G */
2436716431bSRobert Mustacchi 	0x0b95, 0x7720, CHIP_TYPE_AX88772,
2446716431bSRobert Mustacchi 	{0, 0}, {0, 0}, {0, 0},
2456716431bSRobert Mustacchi 	"ASIX AX88772/AX88178",	/* tested */
2466716431bSRobert Mustacchi },
2476716431bSRobert Mustacchi };
2486716431bSRobert Mustacchi 
2496716431bSRobert Mustacchi #define	CHIPTABLESIZE	(sizeof (chiptbl_88x7x) / sizeof (struct chip_info))
2506716431bSRobert Mustacchi 
2516716431bSRobert Mustacchi struct axf_dev {
2526716431bSRobert Mustacchi 	/*
2536716431bSRobert Mustacchi 	 * Misc HW information
2546716431bSRobert Mustacchi 	 */
2556716431bSRobert Mustacchi 	struct chip_info	*chip;
2566716431bSRobert Mustacchi 	uint8_t			ipg[3];
2576716431bSRobert Mustacchi 	uint8_t			gpio;
2586716431bSRobert Mustacchi 	uint16_t		rcr;
2596716431bSRobert Mustacchi 	uint16_t		msr;
2606716431bSRobert Mustacchi 	uint8_t			last_link_state;
2616716431bSRobert Mustacchi 	boolean_t		phy_has_reset;
2626716431bSRobert Mustacchi };
2636716431bSRobert Mustacchi 
2646716431bSRobert Mustacchi /*
2656716431bSRobert Mustacchi  * private functions
2666716431bSRobert Mustacchi  */
2676716431bSRobert Mustacchi 
2686716431bSRobert Mustacchi /* mii operations */
2696716431bSRobert Mustacchi static uint16_t axf_mii_read(struct usbgem_dev *, uint_t, int *errp);
2706716431bSRobert Mustacchi static void axf_mii_write(struct usbgem_dev *, uint_t, uint16_t, int *errp);
2716716431bSRobert Mustacchi 
2726716431bSRobert Mustacchi /* nic operations */
2736716431bSRobert Mustacchi static int axf_reset_chip(struct usbgem_dev *);
2746716431bSRobert Mustacchi static int axf_init_chip(struct usbgem_dev *);
2756716431bSRobert Mustacchi static int axf_start_chip(struct usbgem_dev *);
2766716431bSRobert Mustacchi static int axf_stop_chip(struct usbgem_dev *);
2776716431bSRobert Mustacchi static int axf_set_media(struct usbgem_dev *);
2786716431bSRobert Mustacchi static int axf_set_rx_filter(struct usbgem_dev *);
2796716431bSRobert Mustacchi static int axf_get_stats(struct usbgem_dev *);
2806716431bSRobert Mustacchi static void  axf_interrupt(struct usbgem_dev *, mblk_t *);
2816716431bSRobert Mustacchi 
2826716431bSRobert Mustacchi /* packet operations */
2836716431bSRobert Mustacchi static mblk_t *axf_tx_make_packet(struct usbgem_dev *, mblk_t *);
2846716431bSRobert Mustacchi static mblk_t *axf_rx_make_packet(struct usbgem_dev *, mblk_t *);
2856716431bSRobert Mustacchi 
2866716431bSRobert Mustacchi /* =============================================================== */
2876716431bSRobert Mustacchi /*
2886716431bSRobert Mustacchi  * I/O functions
2896716431bSRobert Mustacchi  */
2906716431bSRobert Mustacchi /* =============================================================== */
2916716431bSRobert Mustacchi /* BEGIN CSTYLED */
2926716431bSRobert Mustacchi #define	OUT(dp, req, val, ix, len, buf, errp, label)	\
293ceb6b962SRobert Mustacchi 	if ((*(errp) = usbgem_ctrl_out((dp),	\
2946716431bSRobert Mustacchi 	/* bmRequestType */ USB_DEV_REQ_HOST_TO_DEV	\
2956716431bSRobert Mustacchi 		    | USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_RCPT_DEV,	\
2966716431bSRobert Mustacchi 	/* bRequest */ (req),	\
2976716431bSRobert Mustacchi 	/* wValue */   (val),	\
2986716431bSRobert Mustacchi 	/* wIndex */   (ix),	\
2996716431bSRobert Mustacchi 	/* wLength */  (len),	\
3006716431bSRobert Mustacchi 	/* value */    (buf),	\
3016716431bSRobert Mustacchi 	/* size */     (len))) != USB_SUCCESS) goto label
3026716431bSRobert Mustacchi 
3036716431bSRobert Mustacchi #define	IN(dp, req, val, ix, len, buf, errp, label)	\
304ceb6b962SRobert Mustacchi 	if ((*(errp) = usbgem_ctrl_in((dp),	\
3056716431bSRobert Mustacchi 	/* bmRequestType */ USB_DEV_REQ_DEV_TO_HOST	\
3066716431bSRobert Mustacchi 		    | USB_DEV_REQ_TYPE_VENDOR | USB_DEV_REQ_RCPT_DEV,	\
3076716431bSRobert Mustacchi 	/* bRequest */ (req),	\
3086716431bSRobert Mustacchi 	/* wValue */   (val),	\
3096716431bSRobert Mustacchi 	/* wIndex */   (ix),	\
3106716431bSRobert Mustacchi 	/* wLength */  (len),	\
3116716431bSRobert Mustacchi 	/* valuep */   (buf),	\
3126716431bSRobert Mustacchi 	/* size */     (len))) != USB_SUCCESS) goto label
3136716431bSRobert Mustacchi /* END CSTYLED */
3146716431bSRobert Mustacchi 
3156716431bSRobert Mustacchi /* =============================================================== */
3166716431bSRobert Mustacchi /*
3176716431bSRobert Mustacchi  * Hardware manupilation
3186716431bSRobert Mustacchi  */
3196716431bSRobert Mustacchi /* =============================================================== */
3206716431bSRobert Mustacchi static int
axf_reset_phy(struct usbgem_dev * dp)3216716431bSRobert Mustacchi axf_reset_phy(struct usbgem_dev *dp)
3226716431bSRobert Mustacchi {
3236716431bSRobert Mustacchi 	uint8_t	phys[2];
3246716431bSRobert Mustacchi 	uint8_t	val8;
3256716431bSRobert Mustacchi 	int	err;
3266716431bSRobert Mustacchi 	struct axf_dev	*lp = dp->private;
3276716431bSRobert Mustacchi 
3286716431bSRobert Mustacchi 	DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__));
3296716431bSRobert Mustacchi 
3306716431bSRobert Mustacchi 	if (AX88172(dp)) {
3316716431bSRobert Mustacchi 		delay(drv_usectohz(5000));
3326716431bSRobert Mustacchi 		IN(dp, VCMD_READ_GPIO, 0, 0, 1, &val8, &err, usberr);
3336716431bSRobert Mustacchi 
3346716431bSRobert Mustacchi 		DPRINTF(0, (CE_CONT, "!%s: %s: gpio 0x%b",
3356716431bSRobert Mustacchi 		    dp->name, __func__, val8, GPIO_BITS));
3366716431bSRobert Mustacchi 
3376716431bSRobert Mustacchi 		/* reset MII PHY */
3386716431bSRobert Mustacchi 		val8 = lp->chip->gpio_reset[1]
3396716431bSRobert Mustacchi 		    | lp->chip->gpio_speed[dp->speed]
3406716431bSRobert Mustacchi 		    | lp->chip->gpio_duplex[dp->full_duplex];
3416716431bSRobert Mustacchi 
3426716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_GPIO,
3436716431bSRobert Mustacchi 		    val8, 0, 0, NULL, &err, usberr);
3446716431bSRobert Mustacchi 		delay(drv_usectohz(5000));
3456716431bSRobert Mustacchi 
3466716431bSRobert Mustacchi 		val8 = lp->chip->gpio_reset[0]
3476716431bSRobert Mustacchi 		    | lp->chip->gpio_speed[dp->speed]
3486716431bSRobert Mustacchi 		    | lp->chip->gpio_duplex[dp->full_duplex];
3496716431bSRobert Mustacchi 
3506716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_GPIO,
3516716431bSRobert Mustacchi 		    val8, 0, 0, NULL, &err, usberr);
3526716431bSRobert Mustacchi 		delay(drv_usectohz(5000));
3536716431bSRobert Mustacchi 	} else {
3546716431bSRobert Mustacchi 		lp->gpio = GPIO_RSE | GPIO_DATA2 | GPIO_EN2;
3556716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_GPIO, lp->gpio, 0,
3566716431bSRobert Mustacchi 		    0, NULL, &err, usberr);
3576716431bSRobert Mustacchi 		drv_usecwait(1000);
3586716431bSRobert Mustacchi 
3596716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_PHY_SELECT_88772,
3606716431bSRobert Mustacchi 		    dp->mii_phy_addr == 16 ? 1 : 0, 0, 0, NULL, &err, usberr);
3616716431bSRobert Mustacchi 
3626716431bSRobert Mustacchi 		OUT(dp, VCMD_SOFTWARE_RESET_88772,
3636716431bSRobert Mustacchi 		    SWRST_IPPD | SWRST_PRL, 0, 0, NULL, &err, usberr);
3646716431bSRobert Mustacchi 		delay(drv_usectohz(150*1000));
3656716431bSRobert Mustacchi 		OUT(dp, VCMD_SOFTWARE_RESET_88772,
3666716431bSRobert Mustacchi 		    0, 0, 0, NULL, &err, usberr);
3676716431bSRobert Mustacchi 
3686716431bSRobert Mustacchi 		OUT(dp, VCMD_SOFTWARE_RESET_88772,
3696716431bSRobert Mustacchi 		    dp->mii_phy_addr == 16 ? SWRST_IPRL : SWRST_PRTE,
3706716431bSRobert Mustacchi 		    0, 0, NULL, &err, usberr);
3716716431bSRobert Mustacchi 		delay(drv_usectohz(150*1000));
3726716431bSRobert Mustacchi 	}
3736716431bSRobert Mustacchi 
3746716431bSRobert Mustacchi 
3756716431bSRobert Mustacchi 	return (USB_SUCCESS);
3766716431bSRobert Mustacchi 
3776716431bSRobert Mustacchi usberr:
3786716431bSRobert Mustacchi 	return (USB_FAILURE);
3796716431bSRobert Mustacchi }
3806716431bSRobert Mustacchi 
3816716431bSRobert Mustacchi static int
axf_reset_chip(struct usbgem_dev * dp)3826716431bSRobert Mustacchi axf_reset_chip(struct usbgem_dev *dp)
3836716431bSRobert Mustacchi {
3846716431bSRobert Mustacchi 	int	err = USB_SUCCESS;
3856716431bSRobert Mustacchi 
3866716431bSRobert Mustacchi 	if (AX88172(dp)) {
3876716431bSRobert Mustacchi 		/* there are no ways to reset nic */
3886716431bSRobert Mustacchi 		return (USB_SUCCESS);
3896716431bSRobert Mustacchi 	}
3906716431bSRobert Mustacchi #ifdef NEVER
3916716431bSRobert Mustacchi 	OUT(dp, VCMD_SOFTWARE_RESET_88772,
3926716431bSRobert Mustacchi 	    SWRST_RR | SWRST_RT, 0, 0, NULL, &err, usberr);
3936716431bSRobert Mustacchi 	OUT(dp, VCMD_SOFTWARE_RESET_88772,
3946716431bSRobert Mustacchi 	    0, 0, 0, NULL, &err, usberr);
3956716431bSRobert Mustacchi usberr:
3966716431bSRobert Mustacchi #endif
3976716431bSRobert Mustacchi 	return (err);
3986716431bSRobert Mustacchi }
3996716431bSRobert Mustacchi 
4006716431bSRobert Mustacchi /*
4016716431bSRobert Mustacchi  * Setup ax88172
4026716431bSRobert Mustacchi  */
4036716431bSRobert Mustacchi static int
axf_init_chip(struct usbgem_dev * dp)4046716431bSRobert Mustacchi axf_init_chip(struct usbgem_dev *dp)
4056716431bSRobert Mustacchi {
4066716431bSRobert Mustacchi 	int		i;
4076716431bSRobert Mustacchi 	uint32_t	val;
4086716431bSRobert Mustacchi 	int		err = USB_SUCCESS;
4096716431bSRobert Mustacchi 	uint16_t	reg;
4106716431bSRobert Mustacchi 	uint8_t		buf[2];
4116716431bSRobert Mustacchi 	uint16_t	tmp16;
4126716431bSRobert Mustacchi 	struct axf_dev	*lp = dp->private;
4136716431bSRobert Mustacchi 
4146716431bSRobert Mustacchi 	DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__));
4156716431bSRobert Mustacchi 
4166716431bSRobert Mustacchi 	/* rx conrol register: read default value */
4176716431bSRobert Mustacchi 	if (!AX88172(dp)) {
4186716431bSRobert Mustacchi 		/* clear rx control */
4196716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_RXCTRL, 0, 0, 0, NULL, &err, usberr);
4206716431bSRobert Mustacchi 	}
4216716431bSRobert Mustacchi 
4226716431bSRobert Mustacchi 	IN(dp, VCMD_READ_RXCTRL, 0, 0, 2, buf, &err, usberr);
4236716431bSRobert Mustacchi 	lp->rcr = LE16P(buf);
4246716431bSRobert Mustacchi 	DPRINTF(0, (CE_CONT, "!%s: %s: rcr(default):%b",
4256716431bSRobert Mustacchi 	    dp->name, __func__, lp->rcr, RCR_BITS));
4266716431bSRobert Mustacchi 
4276716431bSRobert Mustacchi 	lp->rcr &= ~RCR_SO;
4286716431bSRobert Mustacchi 
4296716431bSRobert Mustacchi 	/* Media status register */
4306716431bSRobert Mustacchi 	if (AX88172(dp)) {
4316716431bSRobert Mustacchi #ifdef notdef
4326716431bSRobert Mustacchi 		lp->msr = MSR_TXABT;
4336716431bSRobert Mustacchi #else
4346716431bSRobert Mustacchi 		lp->msr = 0;
4356716431bSRobert Mustacchi #endif
4366716431bSRobert Mustacchi 	} else {
4376716431bSRobert Mustacchi 		lp->msr = MSR_RE | MSR_TXABT;
4386716431bSRobert Mustacchi 	}
4396716431bSRobert Mustacchi 	DPRINTF(0, (CE_CONT, "!%s: %s: msr:%b",
4406716431bSRobert Mustacchi 	    dp->name, __func__, lp->msr, MSR_BITS));
4416716431bSRobert Mustacchi 	err = axf_set_media(dp);
4426716431bSRobert Mustacchi 	CHECK_AND_JUMP(err, usberr);
4436716431bSRobert Mustacchi 
4446716431bSRobert Mustacchi 	/* write IPG0-2 registers */
4456716431bSRobert Mustacchi 	if (AX88172(dp)) {
4466716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_IPG, lp->ipg[0], 0, 0, NULL, &err, usberr);
4476716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_IPG1, lp->ipg[1], 0, 0, NULL, &err, usberr);
4486716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_IPG2, lp->ipg[2], 0, 0, NULL, &err, usberr);
4496716431bSRobert Mustacchi 	} else {
4506716431bSRobert Mustacchi 		/* EMPTY */
4516716431bSRobert Mustacchi 	}
4526716431bSRobert Mustacchi #ifdef ENABLE_RX_IN_INIT_CHIP
4536716431bSRobert Mustacchi 	/* enable Rx */
4546716431bSRobert Mustacchi 	lp->rcr |= RCR_SO;
4556716431bSRobert Mustacchi 	OUT(dp, VCMD_WRITE_RXCTRL, lp->rcr, 0, 0, NULL, &err, usberr);
4566716431bSRobert Mustacchi #endif
4576716431bSRobert Mustacchi usberr:
4586716431bSRobert Mustacchi 	DPRINTF(2, (CE_CONT, "!%s: %s: end (%s)",
4596716431bSRobert Mustacchi 	    dp->name, __func__,
4606716431bSRobert Mustacchi 	    err, err == USB_SUCCESS ? "success" : "error"));
4616716431bSRobert Mustacchi 	return (err);
4626716431bSRobert Mustacchi }
4636716431bSRobert Mustacchi 
4646716431bSRobert Mustacchi static int
axf_start_chip(struct usbgem_dev * dp)4656716431bSRobert Mustacchi axf_start_chip(struct usbgem_dev *dp)
4666716431bSRobert Mustacchi {
4676716431bSRobert Mustacchi 	int	err = USB_SUCCESS;
4686716431bSRobert Mustacchi 	struct axf_dev	*lp = dp->private;
4696716431bSRobert Mustacchi #ifndef ENABLE_RX_IN_INIT_CHIP
4706716431bSRobert Mustacchi 	/* enable Rx */
4716716431bSRobert Mustacchi 	lp->rcr |= RCR_SO;
4726716431bSRobert Mustacchi 	OUT(dp, VCMD_WRITE_RXCTRL, lp->rcr, 0, 0, NULL, &err, usberr);
4736716431bSRobert Mustacchi 
4746716431bSRobert Mustacchi usberr:
4756716431bSRobert Mustacchi 	DPRINTF(2, (CE_CONT, "!%s: %s: end (%s)",
4766716431bSRobert Mustacchi 	    dp->name, __func__,
4776716431bSRobert Mustacchi 	    err, err == USB_SUCCESS ? "success" : "error"));
4786716431bSRobert Mustacchi #endif
4796716431bSRobert Mustacchi 	return (err);
4806716431bSRobert Mustacchi }
4816716431bSRobert Mustacchi 
4826716431bSRobert Mustacchi static int
axf_stop_chip(struct usbgem_dev * dp)4836716431bSRobert Mustacchi axf_stop_chip(struct usbgem_dev *dp)
4846716431bSRobert Mustacchi {
4856716431bSRobert Mustacchi 	int	err = USB_SUCCESS;
4866716431bSRobert Mustacchi 	struct axf_dev	*lp = dp->private;
4876716431bSRobert Mustacchi 
4886716431bSRobert Mustacchi 	/* Disable Rx */
4896716431bSRobert Mustacchi 	lp->rcr &= ~RCR_SO;
4906716431bSRobert Mustacchi 	OUT(dp, VCMD_WRITE_RXCTRL, lp->rcr, 0, 0, NULL, &err, usberr);
4916716431bSRobert Mustacchi 
4926716431bSRobert Mustacchi 	/*
4936716431bSRobert Mustacchi 	 * Restore factory mac address
4946716431bSRobert Mustacchi 	 * if we have changed current mac address
4956716431bSRobert Mustacchi 	 */
4966716431bSRobert Mustacchi 	if (!AX88172(dp) &&
4976716431bSRobert Mustacchi 	    bcmp(dp->dev_addr.ether_addr_octet,
4986716431bSRobert Mustacchi 	    dp->cur_addr.ether_addr_octet,
4996716431bSRobert Mustacchi 	    ETHERADDRL) != 0) {
5006716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_NODE_ID_88772, 0, 0,
5016716431bSRobert Mustacchi 		    ETHERADDRL, dp->cur_addr.ether_addr_octet, &err, usberr);
5026716431bSRobert Mustacchi 	}
5036716431bSRobert Mustacchi usberr:
5046716431bSRobert Mustacchi 	return (axf_reset_chip(dp));
5056716431bSRobert Mustacchi }
5066716431bSRobert Mustacchi 
5076716431bSRobert Mustacchi static int
axf_get_stats(struct usbgem_dev * dp)5086716431bSRobert Mustacchi axf_get_stats(struct usbgem_dev *dp)
5096716431bSRobert Mustacchi {
5106716431bSRobert Mustacchi 	/* empty */
5116716431bSRobert Mustacchi 	return (USB_SUCCESS);
5126716431bSRobert Mustacchi }
5136716431bSRobert Mustacchi 
5146716431bSRobert Mustacchi static uint_t
axf_mcast_hash(struct usbgem_dev * dp,const uint8_t * addr)5156716431bSRobert Mustacchi axf_mcast_hash(struct usbgem_dev *dp, const uint8_t *addr)
5166716431bSRobert Mustacchi {
5176716431bSRobert Mustacchi 	return (usbgem_ether_crc_be(addr) >> (32 - 6));
5186716431bSRobert Mustacchi }
5196716431bSRobert Mustacchi 
5206716431bSRobert Mustacchi static int
axf_set_rx_filter(struct usbgem_dev * dp)5216716431bSRobert Mustacchi axf_set_rx_filter(struct usbgem_dev *dp)
5226716431bSRobert Mustacchi {
5236716431bSRobert Mustacchi 	int		i;
5246716431bSRobert Mustacchi 	uint8_t		mode;
5256716431bSRobert Mustacchi 	uint8_t		mhash[8];
5266716431bSRobert Mustacchi 	uint8_t		buf[2];
5276716431bSRobert Mustacchi 	uint_t		h;
5286716431bSRobert Mustacchi 	int		err = USB_SUCCESS;
5296716431bSRobert Mustacchi 	struct axf_dev	*lp = dp->private;
5306716431bSRobert Mustacchi 
5316716431bSRobert Mustacchi 	DPRINTF(2, (CE_CONT, "!%s: %s: called, rxmode:%x",
5326716431bSRobert Mustacchi 	    dp->name, __func__, dp->rxmode));
5336716431bSRobert Mustacchi 
5346716431bSRobert Mustacchi 	if (lp->rcr & RCR_SO) {
5356716431bSRobert Mustacchi 		/* set promiscuous mode  before changing it. */
5366716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_RXCTRL,
5376716431bSRobert Mustacchi 		    lp->rcr | RCR_PRO, 0, 0, NULL, &err, usberr);
5386716431bSRobert Mustacchi 	}
5396716431bSRobert Mustacchi 
5406716431bSRobert Mustacchi 	lp->rcr &= ~(RCR_AP_88772 | RCR_AM | RCR_SEP | RCR_AMALL | RCR_PRO);
5416716431bSRobert Mustacchi 	mode = RCR_AB;	/* accept broadcast packets */
5426716431bSRobert Mustacchi 
5436716431bSRobert Mustacchi 	bzero(mhash, sizeof (mhash));
5446716431bSRobert Mustacchi 
5456716431bSRobert Mustacchi 	if (dp->rxmode & RXMODE_PROMISC) {
5466716431bSRobert Mustacchi 		/* promiscious mode implies all multicast and all physical */
5476716431bSRobert Mustacchi 		mode |= RCR_PRO;
5486716431bSRobert Mustacchi 	} else if ((dp->rxmode & RXMODE_ALLMULTI) || dp->mc_count > 32) {
5496716431bSRobert Mustacchi 		/* accept all multicast packets */
5506716431bSRobert Mustacchi 		mode |= RCR_AMALL;
5516716431bSRobert Mustacchi 	} else if (dp->mc_count > 0) {
5526716431bSRobert Mustacchi 		/*
5536716431bSRobert Mustacchi 		 * make hash table to select interresting
5546716431bSRobert Mustacchi 		 * multicast address only.
5556716431bSRobert Mustacchi 		 */
5566716431bSRobert Mustacchi 		mode |= RCR_AM;
5576716431bSRobert Mustacchi 		for (i = 0; i < dp->mc_count; i++) {
5586716431bSRobert Mustacchi 			h = dp->mc_list[i].hash;
5596716431bSRobert Mustacchi 			mhash[h / 8] |= 1 << (h % 8);
5606716431bSRobert Mustacchi 		}
5616716431bSRobert Mustacchi 	}
5626716431bSRobert Mustacchi 	if (AX88172(dp)) {
5636716431bSRobert Mustacchi 		if (bcmp(dp->dev_addr.ether_addr_octet,
5646716431bSRobert Mustacchi 		    dp->cur_addr.ether_addr_octet, ETHERADDRL) != 0) {
5656716431bSRobert Mustacchi 			/*
5666716431bSRobert Mustacchi 			 * we use promiscious mode instead of changing the
5676716431bSRobert Mustacchi 			 * mac address in ax88172
5686716431bSRobert Mustacchi 			 */
5696716431bSRobert Mustacchi 			mode |= RCR_PRO;
5706716431bSRobert Mustacchi 		}
5716716431bSRobert Mustacchi 	} else {
5726716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_NODE_ID_88772, 0, 0,
5736716431bSRobert Mustacchi 		    ETHERADDRL, dp->cur_addr.ether_addr_octet, &err, usberr);
5746716431bSRobert Mustacchi 	}
5756716431bSRobert Mustacchi 	lp->rcr |= mode;
5766716431bSRobert Mustacchi 
5776716431bSRobert Mustacchi 	/* set multicast hash table */
5786716431bSRobert Mustacchi 	if (mode & RCR_AM) {
5796716431bSRobert Mustacchi 		/* need to set up multicast hash table */
5806716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_MCAST_FILTER, 0, 0,
5816716431bSRobert Mustacchi 		    sizeof (mhash), mhash, &err, usberr);
5826716431bSRobert Mustacchi 	}
5836716431bSRobert Mustacchi 
5846716431bSRobert Mustacchi 	/* update rcr */
5856716431bSRobert Mustacchi 	OUT(dp, VCMD_WRITE_RXCTRL, lp->rcr, 0,
5866716431bSRobert Mustacchi 	    0, NULL, &err, usberr);
5876716431bSRobert Mustacchi 
5886716431bSRobert Mustacchi #if DEBUG_LEVEL > 1
5896716431bSRobert Mustacchi 	/* verify rxctrl reg */
5906716431bSRobert Mustacchi 	IN(dp, VCMD_READ_RXCTRL, 0, 0, 2, buf, &err, usberr);
5916716431bSRobert Mustacchi 	cmn_err(CE_CONT, "!%s: %s: rcr:%b returned",
5926716431bSRobert Mustacchi 	    dp->name, __func__, LE16P(buf), RCR_BITS);
5936716431bSRobert Mustacchi #endif
5946716431bSRobert Mustacchi usberr:
5956716431bSRobert Mustacchi 	DPRINTF(2, (CE_CONT, "!%s: %s: end (%s)",
5966716431bSRobert Mustacchi 	    dp->name, __func__,
5976716431bSRobert Mustacchi 	    err, err == USB_SUCCESS ? "success" : "error"));
5986716431bSRobert Mustacchi 	return (err);
5996716431bSRobert Mustacchi }
6006716431bSRobert Mustacchi 
6016716431bSRobert Mustacchi static int
axf_set_media(struct usbgem_dev * dp)6026716431bSRobert Mustacchi axf_set_media(struct usbgem_dev *dp)
6036716431bSRobert Mustacchi {
6046716431bSRobert Mustacchi 	uint8_t	val8;
6056716431bSRobert Mustacchi 	uint8_t	gpio;
6066716431bSRobert Mustacchi 	uint8_t	gpio_old;
6076716431bSRobert Mustacchi 	int	err = USB_SUCCESS;
6086716431bSRobert Mustacchi 	uint16_t	msr;
6096716431bSRobert Mustacchi 	struct axf_dev	*lp = dp->private;
6106716431bSRobert Mustacchi 
6116716431bSRobert Mustacchi 	IN(dp, VCMD_READ_GPIO, 0, 0, 1, &gpio, &err, usberr);
6126716431bSRobert Mustacchi 
6136716431bSRobert Mustacchi 	DPRINTF(0, (CE_CONT, "!%s: %s: called, gpio:%b",
6146716431bSRobert Mustacchi 	    dp->name, __func__, gpio, GPIO_BITS));
6156716431bSRobert Mustacchi 
6166716431bSRobert Mustacchi 	msr = lp->msr;
6176716431bSRobert Mustacchi 	gpio_old = gpio;
6186716431bSRobert Mustacchi 	gpio = lp->chip->gpio_reset[0];
6196716431bSRobert Mustacchi 
6206716431bSRobert Mustacchi 	/* setup speed */
6216716431bSRobert Mustacchi 	if (AX88172(dp)) {
6226716431bSRobert Mustacchi 		/* EMPTY */
6236716431bSRobert Mustacchi 	} else {
6246716431bSRobert Mustacchi 		msr &= ~(MSR_PS | MSR_GM | MSR_ENCK);
6256716431bSRobert Mustacchi 
6266716431bSRobert Mustacchi 		switch (dp->speed) {
6276716431bSRobert Mustacchi 		case USBGEM_SPD_1000:
6286716431bSRobert Mustacchi 			msr |= MSR_GM | MSR_ENCK;
6296716431bSRobert Mustacchi 			break;
6306716431bSRobert Mustacchi 
6316716431bSRobert Mustacchi 		case USBGEM_SPD_100:
6326716431bSRobert Mustacchi 			msr |= MSR_PS;
6336716431bSRobert Mustacchi 			break;
6346716431bSRobert Mustacchi 
6356716431bSRobert Mustacchi 		case USBGEM_SPD_10:
6366716431bSRobert Mustacchi 			break;
6376716431bSRobert Mustacchi 		}
6386716431bSRobert Mustacchi 	}
6396716431bSRobert Mustacchi 	gpio |= lp->chip->gpio_speed[dp->speed == USBGEM_SPD_100 ? 1 : 0];
6406716431bSRobert Mustacchi 
6416716431bSRobert Mustacchi 	/* select duplex */
6426716431bSRobert Mustacchi 	msr &= ~MSR_FDPX;
6436716431bSRobert Mustacchi 	if (dp->full_duplex) {
6446716431bSRobert Mustacchi 		msr |= MSR_FDPX;
6456716431bSRobert Mustacchi 
6466716431bSRobert Mustacchi 		/* select flow control */
6476716431bSRobert Mustacchi 		if (AX88172(dp)) {
6486716431bSRobert Mustacchi 			msr &= ~MSR_FCEN;
6496716431bSRobert Mustacchi 			switch (dp->flow_control) {
6506716431bSRobert Mustacchi 			case FLOW_CONTROL_TX_PAUSE:
6516716431bSRobert Mustacchi 			case FLOW_CONTROL_SYMMETRIC:
6526716431bSRobert Mustacchi 			case FLOW_CONTROL_RX_PAUSE:
6536716431bSRobert Mustacchi 				msr |= MSR_FCEN;
6546716431bSRobert Mustacchi 				break;
6556716431bSRobert Mustacchi 			}
6566716431bSRobert Mustacchi 		} else {
6576716431bSRobert Mustacchi 			msr &= ~(MSR_RFC | MSR_TFC);
6586716431bSRobert Mustacchi 			switch (dp->flow_control) {
6596716431bSRobert Mustacchi 			case FLOW_CONTROL_TX_PAUSE:
6606716431bSRobert Mustacchi 				msr |= MSR_TFC;
6616716431bSRobert Mustacchi 				break;
6626716431bSRobert Mustacchi 
6636716431bSRobert Mustacchi 			case FLOW_CONTROL_SYMMETRIC:
6646716431bSRobert Mustacchi 				msr |= MSR_TFC | MSR_RFC;
6656716431bSRobert Mustacchi 				break;
6666716431bSRobert Mustacchi 
6676716431bSRobert Mustacchi 			case FLOW_CONTROL_RX_PAUSE:
6686716431bSRobert Mustacchi 				msr |= MSR_RFC;
6696716431bSRobert Mustacchi 				break;
6706716431bSRobert Mustacchi 			}
6716716431bSRobert Mustacchi 		}
6726716431bSRobert Mustacchi 	}
6736716431bSRobert Mustacchi 	gpio |= lp->chip->gpio_duplex[dp->full_duplex ? 1 : 0];
6746716431bSRobert Mustacchi 
6756716431bSRobert Mustacchi 	/* update medium status register */
6766716431bSRobert Mustacchi 	lp->msr = msr;
6776716431bSRobert Mustacchi 	OUT(dp, VCMD_WRITE_MEDIUM_STATUS, lp->msr, 0,
6786716431bSRobert Mustacchi 	    0, NULL, &err, usberr);
6796716431bSRobert Mustacchi 
6806716431bSRobert Mustacchi 	if (gpio != gpio_old) {
6816716431bSRobert Mustacchi 		/* LED control required for some products */
6826716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_GPIO,
6836716431bSRobert Mustacchi 		    gpio, 0, 0, NULL, &err, usberr);
6846716431bSRobert Mustacchi 	}
6856716431bSRobert Mustacchi 
6866716431bSRobert Mustacchi usberr:
6876716431bSRobert Mustacchi 	DPRINTF(2, (CE_CONT, "!%s: %s: end (%s)",
6886716431bSRobert Mustacchi 	    dp->name, __func__,
6896716431bSRobert Mustacchi 	    err, err == USB_SUCCESS ? "success" : "error"));
6906716431bSRobert Mustacchi 	return (err);
6916716431bSRobert Mustacchi }
6926716431bSRobert Mustacchi 
6936716431bSRobert Mustacchi #define	FILL_PKT_HEADER(bp, len)	{	\
6946716431bSRobert Mustacchi 	(bp)[0] = (uint8_t)(len);	\
6956716431bSRobert Mustacchi 	(bp)[1] = (uint8_t)((len) >> 8);	\
6966716431bSRobert Mustacchi 	(bp)[2] = (uint8_t)(~(len));	\
6976716431bSRobert Mustacchi 	(bp)[3] = (uint8_t)((~(len)) >> 8);	\
6986716431bSRobert Mustacchi }
6996716431bSRobert Mustacchi 
7006716431bSRobert Mustacchi #define	PKT_HEADER_SIZE	4
7016716431bSRobert Mustacchi 
7026716431bSRobert Mustacchi /*
7036716431bSRobert Mustacchi  * send/receive packet check
7046716431bSRobert Mustacchi  */
7056716431bSRobert Mustacchi static mblk_t *
axf_tx_make_packet(struct usbgem_dev * dp,mblk_t * mp)7066716431bSRobert Mustacchi axf_tx_make_packet(struct usbgem_dev *dp, mblk_t *mp)
7076716431bSRobert Mustacchi {
7086716431bSRobert Mustacchi 	int		n;
7096716431bSRobert Mustacchi 	size_t		len;
7106716431bSRobert Mustacchi 	size_t		pkt_size;
7116716431bSRobert Mustacchi 	mblk_t		*new;
7126716431bSRobert Mustacchi 	mblk_t		*tp;
7136716431bSRobert Mustacchi 	uint8_t		*bp;
7146716431bSRobert Mustacchi 	uint8_t		*last_pos;
7156716431bSRobert Mustacchi 	uint_t		align_mask;
7166716431bSRobert Mustacchi 	size_t		header_size;
7176716431bSRobert Mustacchi 	int		pad_size;
7186716431bSRobert Mustacchi 
7196716431bSRobert Mustacchi 	len = msgdsize(mp);
7206716431bSRobert Mustacchi 
7216716431bSRobert Mustacchi 	if (AX88172(dp)) {
7226716431bSRobert Mustacchi #ifdef notdef
7236716431bSRobert Mustacchi 		align_mask = 63;
7246716431bSRobert Mustacchi #else
7256716431bSRobert Mustacchi 		align_mask = 511;
7266716431bSRobert Mustacchi #endif
7276716431bSRobert Mustacchi 		header_size = 0;
7286716431bSRobert Mustacchi 
7296716431bSRobert Mustacchi 		if (len >= ETHERMIN && mp->b_cont == NULL &&
7306716431bSRobert Mustacchi 		    (len & align_mask) != 0) {
7316716431bSRobert Mustacchi 			/* use the mp "as is" */
7326716431bSRobert Mustacchi 			return (mp);
7336716431bSRobert Mustacchi 		}
7346716431bSRobert Mustacchi 	} else {
7356716431bSRobert Mustacchi 		align_mask = 511;
7366716431bSRobert Mustacchi 		header_size = PKT_HEADER_SIZE;
7376716431bSRobert Mustacchi 	}
7386716431bSRobert Mustacchi 
7396716431bSRobert Mustacchi 	/*
7406716431bSRobert Mustacchi 	 * re-allocate the mp
7416716431bSRobert Mustacchi 	 */
7426716431bSRobert Mustacchi 	/* minimum ethernet packet size of ETHERMIN */
7436716431bSRobert Mustacchi 	pkt_size = max(len, ETHERMIN);
7446716431bSRobert Mustacchi 
7456716431bSRobert Mustacchi 	if (((pkt_size + header_size) & align_mask) == 0) {
7466716431bSRobert Mustacchi 		/* padding is required in usb communication */
7476716431bSRobert Mustacchi 		pad_size = PKT_HEADER_SIZE;
7486716431bSRobert Mustacchi 	} else {
7496716431bSRobert Mustacchi 		pad_size = 0;
7506716431bSRobert Mustacchi 	}
7516716431bSRobert Mustacchi 
7526716431bSRobert Mustacchi 	if ((new = allocb(header_size + pkt_size + pad_size, 0)) == NULL) {
7536716431bSRobert Mustacchi 		return (NULL);
7546716431bSRobert Mustacchi 	}
7556716431bSRobert Mustacchi 
7566716431bSRobert Mustacchi 	bp = new->b_rptr;
7576716431bSRobert Mustacchi 	if (header_size) {
7586716431bSRobert Mustacchi 		uint16_t	tmp;
7596716431bSRobert Mustacchi 
7606716431bSRobert Mustacchi 		/* add a header */
7616716431bSRobert Mustacchi 		tmp = (uint16_t)pkt_size;
7626716431bSRobert Mustacchi 		FILL_PKT_HEADER(bp, tmp);
7636716431bSRobert Mustacchi 		bp += header_size;
7646716431bSRobert Mustacchi 	}
7656716431bSRobert Mustacchi 
7666716431bSRobert Mustacchi 	/* copy contents of the buffer */
7676716431bSRobert Mustacchi 	for (tp = mp; tp; tp = tp->b_cont) {
7686716431bSRobert Mustacchi 		n = (uintptr_t)tp->b_wptr - (uintptr_t)tp->b_rptr;
7696716431bSRobert Mustacchi 		bcopy(tp->b_rptr, bp, n);
7706716431bSRobert Mustacchi 		bp += n;
7716716431bSRobert Mustacchi 	}
7726716431bSRobert Mustacchi 
7736716431bSRobert Mustacchi 	/* add pads for ethernet packets */
7746716431bSRobert Mustacchi 	last_pos = new->b_rptr + header_size + pkt_size;
7756716431bSRobert Mustacchi 	while (bp < last_pos) {
7766716431bSRobert Mustacchi 		*bp++ = 0;
7776716431bSRobert Mustacchi 	}
7786716431bSRobert Mustacchi 
7796716431bSRobert Mustacchi 	/* add a zero-length pad segment for usb communications */
7806716431bSRobert Mustacchi 	if (pad_size) {
7816716431bSRobert Mustacchi 		/* add a dummy header for zero-length packet */
7826716431bSRobert Mustacchi 		FILL_PKT_HEADER(bp, 0);
7836716431bSRobert Mustacchi 		bp += pad_size;
7846716431bSRobert Mustacchi 	}
7856716431bSRobert Mustacchi 
7866716431bSRobert Mustacchi 	/* close the payload of the packet */
7876716431bSRobert Mustacchi 	new->b_wptr = bp;
7886716431bSRobert Mustacchi 
7896716431bSRobert Mustacchi 	return (new);
7906716431bSRobert Mustacchi }
7916716431bSRobert Mustacchi 
792*ae5a8bedSAndy Fiddaman #if DEBUG_LEVEL > 10
7936716431bSRobert Mustacchi static void
axf_dump_packet(struct usbgem_dev * dp,uint8_t * bp,int n)7946716431bSRobert Mustacchi axf_dump_packet(struct usbgem_dev *dp, uint8_t *bp, int n)
7956716431bSRobert Mustacchi {
7966716431bSRobert Mustacchi 	int	i;
7976716431bSRobert Mustacchi 
7986716431bSRobert Mustacchi 	for (i = 0; i < n; i += 8, bp += 8) {
7996716431bSRobert Mustacchi 		cmn_err(CE_CONT, "%02x %02x %02x %02x %02x %02x %02x %02x",
8006716431bSRobert Mustacchi 		    bp[0], bp[1], bp[2], bp[3], bp[4], bp[5], bp[6], bp[7]);
8016716431bSRobert Mustacchi 	}
8026716431bSRobert Mustacchi }
803*ae5a8bedSAndy Fiddaman #endif
8046716431bSRobert Mustacchi 
8056716431bSRobert Mustacchi static mblk_t *
axf_rx_make_packet(struct usbgem_dev * dp,mblk_t * mp)8066716431bSRobert Mustacchi axf_rx_make_packet(struct usbgem_dev *dp, mblk_t *mp)
8076716431bSRobert Mustacchi {
8086716431bSRobert Mustacchi 	mblk_t	*tp;
8096716431bSRobert Mustacchi 	uintptr_t rest;
8106716431bSRobert Mustacchi 
8116716431bSRobert Mustacchi 	if (AX88172(dp)) {
8126716431bSRobert Mustacchi 		return (mp);
8136716431bSRobert Mustacchi 	}
8146716431bSRobert Mustacchi 
8156716431bSRobert Mustacchi 	tp = mp;
8166716431bSRobert Mustacchi 	rest = (uintptr_t)tp->b_wptr - (uintptr_t)tp->b_rptr;
8176716431bSRobert Mustacchi 
8186716431bSRobert Mustacchi 	if (rest <= PKT_HEADER_SIZE) {
8196716431bSRobert Mustacchi 		/*
8206716431bSRobert Mustacchi 		 * the usb bulk-in frame doesn't include any valid
8216716431bSRobert Mustacchi 		 * ethernet packets.
8226716431bSRobert Mustacchi 		 */
8236716431bSRobert Mustacchi 		return (NULL);
8246716431bSRobert Mustacchi 	}
8256716431bSRobert Mustacchi 
8266716431bSRobert Mustacchi 	for (; ; ) {
8276716431bSRobert Mustacchi 		uint16_t	len;
8286716431bSRobert Mustacchi 		uint16_t	cksum;
8296716431bSRobert Mustacchi 
8306716431bSRobert Mustacchi 		/* analyse the header of the received usb frame */
8316716431bSRobert Mustacchi 		len = LE16P(tp->b_rptr + 0);
8326716431bSRobert Mustacchi 		cksum = LE16P(tp->b_rptr + 2);
8336716431bSRobert Mustacchi 
8346716431bSRobert Mustacchi 		/* test if the header is valid */
8356716431bSRobert Mustacchi 		if (len + cksum != 0xffff) {
8366716431bSRobert Mustacchi 			/* discard whole the packet */
8376716431bSRobert Mustacchi 			cmn_err(CE_WARN,
8386716431bSRobert Mustacchi 			    "!%s: %s: corrupted header:%04x %04x",
8396716431bSRobert Mustacchi 			    dp->name, __func__, len, cksum);
8406716431bSRobert Mustacchi 			return (NULL);
8416716431bSRobert Mustacchi 		}
8426716431bSRobert Mustacchi #if DEBUG_LEVEL > 0
8436716431bSRobert Mustacchi 		if (len < ETHERMIN || len > ETHERMAX) {
8446716431bSRobert Mustacchi 			cmn_err(CE_NOTE,
8456716431bSRobert Mustacchi 			    "!%s: %s: incorrect pktsize:%d",
8466716431bSRobert Mustacchi 			    dp->name, __func__, len);
8476716431bSRobert Mustacchi 		}
8486716431bSRobert Mustacchi #endif
8496716431bSRobert Mustacchi 		/* extract a ethernet packet from the bulk-in frame */
8506716431bSRobert Mustacchi 		tp->b_rptr += PKT_HEADER_SIZE;
8516716431bSRobert Mustacchi 		tp->b_wptr = tp->b_rptr + len;
8526716431bSRobert Mustacchi 
8536716431bSRobert Mustacchi 		if (len & 1) {
8546716431bSRobert Mustacchi 			/*
8556716431bSRobert Mustacchi 			 * skip a tailing pad byte if the packet
8566716431bSRobert Mustacchi 			 * length is odd
8576716431bSRobert Mustacchi 			 */
8586716431bSRobert Mustacchi 			len++;
8596716431bSRobert Mustacchi 		}
8606716431bSRobert Mustacchi 		rest -= len + PKT_HEADER_SIZE;
8616716431bSRobert Mustacchi 
8626716431bSRobert Mustacchi 		if (rest <= PKT_HEADER_SIZE) {
8636716431bSRobert Mustacchi 			/* no more vaild ethernet packets */
8646716431bSRobert Mustacchi 			break;
8656716431bSRobert Mustacchi 		}
8666716431bSRobert Mustacchi 
8676716431bSRobert Mustacchi #if DEBUG_LEVEL > 10
8686716431bSRobert Mustacchi 		axf_dump_packet(dp, tp->b_wptr, 18);
8696716431bSRobert Mustacchi #endif
8706716431bSRobert Mustacchi 		/* allocate a mblk_t header for the next ethernet packet */
8716716431bSRobert Mustacchi 		tp->b_next = dupb(mp);
8726716431bSRobert Mustacchi 		tp->b_next->b_rptr = tp->b_rptr + len;
8736716431bSRobert Mustacchi 		tp = tp->b_next;
8746716431bSRobert Mustacchi 	}
8756716431bSRobert Mustacchi 
8766716431bSRobert Mustacchi 	return (mp);
8776716431bSRobert Mustacchi }
8786716431bSRobert Mustacchi 
8796716431bSRobert Mustacchi /*
8806716431bSRobert Mustacchi  * MII Interfaces
8816716431bSRobert Mustacchi  */
8826716431bSRobert Mustacchi static uint16_t
axf_mii_read(struct usbgem_dev * dp,uint_t index,int * errp)8836716431bSRobert Mustacchi axf_mii_read(struct usbgem_dev *dp, uint_t index, int *errp)
8846716431bSRobert Mustacchi {
8856716431bSRobert Mustacchi 	uint8_t		buf[2];
8866716431bSRobert Mustacchi 	uint16_t	val;
8876716431bSRobert Mustacchi 
8886716431bSRobert Mustacchi 	DPRINTF(4, (CE_CONT, "!%s: %s: called, ix:%d",
8896716431bSRobert Mustacchi 	    dp->name, __func__, index));
8906716431bSRobert Mustacchi 
8916716431bSRobert Mustacchi 	/* switch to software MII operation mode */
8926716431bSRobert Mustacchi 	OUT(dp, VCMD_SOFTWARE_MII_OP, 0, 0, 0, NULL, errp, usberr);
8936716431bSRobert Mustacchi 
8946716431bSRobert Mustacchi 	/* Read MII register */
8956716431bSRobert Mustacchi 	IN(dp, VCMD_READ_MII_REG, dp->mii_phy_addr, index,
8966716431bSRobert Mustacchi 	    2, buf, errp, usberr);
8976716431bSRobert Mustacchi 
8986716431bSRobert Mustacchi 	/* switch to hardware MII operation mode */
8996716431bSRobert Mustacchi 	OUT(dp, VCMD_HARDWARE_MII_OP, 0, 0, 0, NULL, errp, usberr);
9006716431bSRobert Mustacchi 
9016716431bSRobert Mustacchi 	return (LE16P(buf));
9026716431bSRobert Mustacchi 
9036716431bSRobert Mustacchi usberr:
9046716431bSRobert Mustacchi 	cmn_err(CE_CONT,
9056716431bSRobert Mustacchi 	    "!%s: %s: usberr(%d) detected", dp->name, __func__, *errp);
9066716431bSRobert Mustacchi 	return (0);
9076716431bSRobert Mustacchi }
9086716431bSRobert Mustacchi 
9096716431bSRobert Mustacchi static void
axf_mii_write(struct usbgem_dev * dp,uint_t index,uint16_t val,int * errp)9106716431bSRobert Mustacchi axf_mii_write(struct usbgem_dev *dp, uint_t index, uint16_t val, int *errp)
9116716431bSRobert Mustacchi {
9126716431bSRobert Mustacchi 	uint8_t		buf[2];
9136716431bSRobert Mustacchi 
9146716431bSRobert Mustacchi 	DPRINTF(4, (CE_CONT, "!%s: %s called, reg:%x val:%x",
9156716431bSRobert Mustacchi 	    dp->name, __func__, index, val));
9166716431bSRobert Mustacchi 
9176716431bSRobert Mustacchi 	/* switch software MII operation mode */
9186716431bSRobert Mustacchi 	OUT(dp, VCMD_SOFTWARE_MII_OP, 0, 0, 0, NULL, errp, usberr);
9196716431bSRobert Mustacchi 
9206716431bSRobert Mustacchi 	/* Write to the specified MII register */
9216716431bSRobert Mustacchi 	buf[0] = (uint8_t)val;
9226716431bSRobert Mustacchi 	buf[1] = (uint8_t)(val >> 8);
9236716431bSRobert Mustacchi 	OUT(dp, VCMD_WRITE_MII_REG, dp->mii_phy_addr, index,
9246716431bSRobert Mustacchi 	    2, buf, errp, usberr);
9256716431bSRobert Mustacchi 
9266716431bSRobert Mustacchi 	/* switch to hardware MII operation mode */
9276716431bSRobert Mustacchi 	OUT(dp, VCMD_HARDWARE_MII_OP, 0, 0, 0, NULL, errp, usberr);
9286716431bSRobert Mustacchi 
9296716431bSRobert Mustacchi usberr:
9306716431bSRobert Mustacchi 	;
9316716431bSRobert Mustacchi }
9326716431bSRobert Mustacchi 
9336716431bSRobert Mustacchi static void
axf_interrupt(struct usbgem_dev * dp,mblk_t * mp)9346716431bSRobert Mustacchi axf_interrupt(struct usbgem_dev *dp, mblk_t *mp)
9356716431bSRobert Mustacchi {
9366716431bSRobert Mustacchi 	uint8_t	*bp;
9376716431bSRobert Mustacchi 	struct axf_dev	*lp = dp->private;
9386716431bSRobert Mustacchi 
9396716431bSRobert Mustacchi 	bp = mp->b_rptr;
9406716431bSRobert Mustacchi 
9416716431bSRobert Mustacchi 	DPRINTF(2, (CE_CONT,
9426716431bSRobert Mustacchi 	    "!%s: %s: size:%d, %02x %02x %02x %02x %02x %02x %02x %02x",
9436716431bSRobert Mustacchi 	    dp->name, __func__, mp->b_wptr - mp->b_rptr,
9446716431bSRobert Mustacchi 	    bp[0], bp[1], bp[2], bp[3], bp[4], bp[5], bp[6], bp[7]));
9456716431bSRobert Mustacchi 
9466716431bSRobert Mustacchi 	if (lp->last_link_state ^ bp[2]) {
9476716431bSRobert Mustacchi 		usbgem_mii_update_link(dp);
9486716431bSRobert Mustacchi 	}
9496716431bSRobert Mustacchi 
9506716431bSRobert Mustacchi 	lp->last_link_state = bp[2];
9516716431bSRobert Mustacchi }
9526716431bSRobert Mustacchi 
9536716431bSRobert Mustacchi /* ======================================================== */
9546716431bSRobert Mustacchi /*
9556716431bSRobert Mustacchi  * OS depend (device driver DKI) routine
9566716431bSRobert Mustacchi  */
9576716431bSRobert Mustacchi /* ======================================================== */
9586716431bSRobert Mustacchi #ifdef DEBUG_LEVEL
9596716431bSRobert Mustacchi static void
axf_eeprom_dump(struct usbgem_dev * dp,int size)9606716431bSRobert Mustacchi axf_eeprom_dump(struct usbgem_dev *dp, int size)
9616716431bSRobert Mustacchi {
9626716431bSRobert Mustacchi 	int	i;
9636716431bSRobert Mustacchi 	int	err;
9646716431bSRobert Mustacchi 	uint8_t	w0[2], w1[2], w2[2], w3[2];
9656716431bSRobert Mustacchi 
9666716431bSRobert Mustacchi 	cmn_err(CE_CONT, "!%s: eeprom dump:", dp->name);
9676716431bSRobert Mustacchi 
9686716431bSRobert Mustacchi 	err = USB_SUCCESS;
9696716431bSRobert Mustacchi 
9706716431bSRobert Mustacchi 	for (i = 0; i < size; i += 4) {
9716716431bSRobert Mustacchi 		IN(dp, VCMD_READ_SROM, i + 0, 0, 2, w0, &err, usberr);
9726716431bSRobert Mustacchi 		IN(dp, VCMD_READ_SROM, i + 1, 0, 2, w1, &err, usberr);
9736716431bSRobert Mustacchi 		IN(dp, VCMD_READ_SROM, i + 2, 0, 2, w2, &err, usberr);
9746716431bSRobert Mustacchi 		IN(dp, VCMD_READ_SROM, i + 3, 0, 2, w3, &err, usberr);
9756716431bSRobert Mustacchi 		cmn_err(CE_CONT, "!0x%02x: 0x%04x 0x%04x 0x%04x 0x%04x",
9766716431bSRobert Mustacchi 		    i,
9776716431bSRobert Mustacchi 		    (w0[1] << 8) | w0[0],
9786716431bSRobert Mustacchi 		    (w1[1] << 8) | w1[0],
9796716431bSRobert Mustacchi 		    (w2[1] << 8) | w2[0],
9806716431bSRobert Mustacchi 		    (w3[1] << 8) | w3[0]);
9816716431bSRobert Mustacchi 	}
9826716431bSRobert Mustacchi usberr:
9836716431bSRobert Mustacchi 	;
9846716431bSRobert Mustacchi }
9856716431bSRobert Mustacchi #endif
9866716431bSRobert Mustacchi 
9876716431bSRobert Mustacchi static int
axf_attach_chip(struct usbgem_dev * dp)9886716431bSRobert Mustacchi axf_attach_chip(struct usbgem_dev *dp)
9896716431bSRobert Mustacchi {
9906716431bSRobert Mustacchi 	uint8_t	phys[2];
9916716431bSRobert Mustacchi 	int	err;
9926716431bSRobert Mustacchi 	uint_t	vcmd;
9936716431bSRobert Mustacchi 	int	ret;
9946716431bSRobert Mustacchi #ifdef CONFIG_FULLSIZE_VLAN
9956716431bSRobert Mustacchi 	uint8_t	maxpktsize[2];
9966716431bSRobert Mustacchi 	uint16_t	vlan_pktsize;
9976716431bSRobert Mustacchi #endif
9986716431bSRobert Mustacchi #ifdef DEBUG_LEVEL
9996716431bSRobert Mustacchi 	uint8_t	val8;
10006716431bSRobert Mustacchi #endif
10016716431bSRobert Mustacchi 	struct axf_dev	*lp = dp->private;
10026716431bSRobert Mustacchi 
10036716431bSRobert Mustacchi 	DPRINTF(0, (CE_CONT, "!%s: %s enter", dp->name, __func__));
10046716431bSRobert Mustacchi 
10056716431bSRobert Mustacchi 	ret = USB_SUCCESS;
10066716431bSRobert Mustacchi 	/*
10076716431bSRobert Mustacchi 	 * mac address in EEPROM has loaded to ID registers.
10086716431bSRobert Mustacchi 	 */
10096716431bSRobert Mustacchi 	vcmd = AX88172(dp) ? VCMD_READ_NODE_ID : VCMD_READ_NODE_ID_88772;
10106716431bSRobert Mustacchi 	IN(dp, vcmd, 0, 0,
10116716431bSRobert Mustacchi 	    ETHERADDRL, dp->dev_addr.ether_addr_octet, &err, usberr);
10126716431bSRobert Mustacchi 
10136716431bSRobert Mustacchi 	/*
10146716431bSRobert Mustacchi 	 * setup IPG values
10156716431bSRobert Mustacchi 	 */
10166716431bSRobert Mustacchi 	lp->ipg[0] = 0x15;
10176716431bSRobert Mustacchi 	lp->ipg[1] = 0x0c;
10186716431bSRobert Mustacchi 	lp->ipg[2] = 0x12;
10196716431bSRobert Mustacchi 
10206716431bSRobert Mustacchi 	/*
10216716431bSRobert Mustacchi 	 * We cannot scan phy because the nic returns undefined
10226716431bSRobert Mustacchi 	 * value, i.e. remained garbage, when MII phy is not at the
10236716431bSRobert Mustacchi 	 * specified index.
10246716431bSRobert Mustacchi 	 */
10256716431bSRobert Mustacchi #ifdef DEBUG_LEVELx
10266716431bSRobert Mustacchi 	if (lp->chip->vid == 0x07b8 && lp->chip->pid == 0x420a) {
10276716431bSRobert Mustacchi 		/*
10286716431bSRobert Mustacchi 		 * restore the original phy address of brain
10296716431bSRobert Mustacchi 		 * damaged Planex UE2-100TX
10306716431bSRobert Mustacchi 		 */
10316716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_SROM_ENABLE, 0, 0, 0, NULL, &err, usberr);
10326716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_SROM, 0x11, 0xe004, 0, NULL, &err, usberr);
10336716431bSRobert Mustacchi 		OUT(dp, VCMD_WRITE_SROM_DISABLE, 0, 0, 0, NULL, &err, usberr);
10346716431bSRobert Mustacchi 	}
10356716431bSRobert Mustacchi #endif
10366716431bSRobert Mustacchi 	if (AX88172(dp)) {
10376716431bSRobert Mustacchi 		IN(dp, VCMD_READ_PHY_IDS, 0, 0, 2, &phys, &err, usberr);
10386716431bSRobert Mustacchi 		dp->mii_phy_addr = phys[1];
10396716431bSRobert Mustacchi 		DPRINTF(0, (CE_CONT, "!%s: %s: phys_addr:%d %d",
10406716431bSRobert Mustacchi 		    dp->name, __func__, phys[0], phys[1]));
10416716431bSRobert Mustacchi 	} else {
10426716431bSRobert Mustacchi 		/* use built-in phy */
10436716431bSRobert Mustacchi 		dp->mii_phy_addr = 0x10;
10446716431bSRobert Mustacchi 	}
10456716431bSRobert Mustacchi 
10466716431bSRobert Mustacchi 	dp->misc_flag |= USBGEM_VLAN;
10476716431bSRobert Mustacchi #ifdef CONFIG_FULLSIZE_VLAN
10486716431bSRobert Mustacchi 	if (AX88172(dp) || AX88772(dp)) {
10496716431bSRobert Mustacchi 		/* check max packet size in srom */
10506716431bSRobert Mustacchi 		IN(dp, VCMD_READ_SROM, 0x10, 0, 2, maxpktsize, &err, usberr);
10516716431bSRobert Mustacchi 		vlan_pktsize = ETHERMAX + ETHERFCSL + 4 /* VTAG_SIZE */;
10526716431bSRobert Mustacchi 
10536716431bSRobert Mustacchi 		if (LE16P(maxpktsize) < vlan_pktsize) {
10546716431bSRobert Mustacchi 			cmn_err(CE_CONT,
10556716431bSRobert Mustacchi 			    "!%s: %s: max packet size in srom is too small, "
10566716431bSRobert Mustacchi 			    "changing %d -> %d, do power cycle for the device",
10576716431bSRobert Mustacchi 			    dp->name, __func__,
10586716431bSRobert Mustacchi 			    LE16P(maxpktsize), vlan_pktsize);
10596716431bSRobert Mustacchi 			OUT(dp, VCMD_WRITE_SROM_ENABLE,
10606716431bSRobert Mustacchi 			    0, 0, 0, NULL, &err, usberr);
10616716431bSRobert Mustacchi 			OUT(dp, VCMD_WRITE_SROM, 0x10,
10626716431bSRobert Mustacchi 			    vlan_pktsize, 0, NULL, &err, usberr);
10636716431bSRobert Mustacchi 			OUT(dp, VCMD_WRITE_SROM_DISABLE,
10646716431bSRobert Mustacchi 			    0, 0, 0, NULL, &err, usberr);
10656716431bSRobert Mustacchi 
10666716431bSRobert Mustacchi 			/* need to power off the device */
10676716431bSRobert Mustacchi 			ret = USB_FAILURE;
10686716431bSRobert Mustacchi 		}
10696716431bSRobert Mustacchi 	}
10706716431bSRobert Mustacchi #endif
10716716431bSRobert Mustacchi #ifdef DEBUG_LEVEL
10726716431bSRobert Mustacchi 	IN(dp, VCMD_READ_GPIO, 0, 0, 1, &val8, &err, usberr);
10736716431bSRobert Mustacchi 	cmn_err(CE_CONT,
10746716431bSRobert Mustacchi 	    "!%s: %s: ipg 0x%02x 0x%02x 0x%02x, gpio 0x%b",
10756716431bSRobert Mustacchi 	    dp->name, __func__, lp->ipg[0], lp->ipg[1], lp->ipg[2],
10766716431bSRobert Mustacchi 	    val8, GPIO_BITS);
10776716431bSRobert Mustacchi #endif
10786716431bSRobert Mustacchi 	/* fix rx buffer size */
10796716431bSRobert Mustacchi 	if (!AX88172(dp)) {
10806716431bSRobert Mustacchi 		dp->rx_buf_len = 2048;
10816716431bSRobert Mustacchi 	}
10826716431bSRobert Mustacchi 
10836716431bSRobert Mustacchi #if DEBUG_LEVEL > 0
10846716431bSRobert Mustacchi 	axf_eeprom_dump(dp, 0x20);
10856716431bSRobert Mustacchi #endif
10866716431bSRobert Mustacchi 	return (ret);
10876716431bSRobert Mustacchi 
10886716431bSRobert Mustacchi usberr:
10896716431bSRobert Mustacchi 	cmn_err(CE_WARN, "%s: %s: usb error detected (%d)",
10906716431bSRobert Mustacchi 	    dp->name, __func__, err);
10916716431bSRobert Mustacchi 	return (USB_FAILURE);
10926716431bSRobert Mustacchi }
10936716431bSRobert Mustacchi 
10946716431bSRobert Mustacchi static boolean_t
axf_scan_phy(struct usbgem_dev * dp)10956716431bSRobert Mustacchi axf_scan_phy(struct usbgem_dev *dp)
10966716431bSRobert Mustacchi {
10976716431bSRobert Mustacchi 	int	i;
10986716431bSRobert Mustacchi 	int	err;
10996716431bSRobert Mustacchi 	uint16_t	val;
11006716431bSRobert Mustacchi 	int	phy_addr_saved;
11016716431bSRobert Mustacchi 	struct axf_dev	*lp = dp->private;
11026716431bSRobert Mustacchi 
11036716431bSRobert Mustacchi 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
11046716431bSRobert Mustacchi 
11056716431bSRobert Mustacchi 	phy_addr_saved = dp->mii_phy_addr;
11066716431bSRobert Mustacchi 
11076716431bSRobert Mustacchi 	/* special probe routine for unreliable MII addr */
11086716431bSRobert Mustacchi #define	PROBE_PAT	\
11096716431bSRobert Mustacchi 	(MII_ABILITY_100BASE_TX_FD |	\
11106716431bSRobert Mustacchi 	MII_ABILITY_100BASE_TX |	\
11116716431bSRobert Mustacchi 	MII_ABILITY_10BASE_T_FD |	\
11126716431bSRobert Mustacchi 	MII_ABILITY_10BASE_T)
11136716431bSRobert Mustacchi 
11146716431bSRobert Mustacchi 	for (i = 0; i < 32; i++) {
11156716431bSRobert Mustacchi 		dp->mii_phy_addr = i;
11166716431bSRobert Mustacchi 		axf_mii_write(dp, MII_AN_ADVERT, 0, &err);
11176716431bSRobert Mustacchi 		if (err != USBGEM_SUCCESS) {
11186716431bSRobert Mustacchi 			break;
11196716431bSRobert Mustacchi 		}
11206716431bSRobert Mustacchi 		val = axf_mii_read(dp, MII_AN_ADVERT, &err);
11216716431bSRobert Mustacchi 		if (err != USBGEM_SUCCESS) {
11226716431bSRobert Mustacchi 			break;
11236716431bSRobert Mustacchi 		}
11246716431bSRobert Mustacchi 		if (val != 0) {
11256716431bSRobert Mustacchi 			DPRINTF(0, (CE_CONT, "!%s: %s: index:%d,  val %b != 0",
11266716431bSRobert Mustacchi 			    dp->name, __func__, i, val, MII_ABILITY_BITS));
11276716431bSRobert Mustacchi 			continue;
11286716431bSRobert Mustacchi 		}
11296716431bSRobert Mustacchi 
11306716431bSRobert Mustacchi 		axf_mii_write(dp, MII_AN_ADVERT, PROBE_PAT, &err);
11316716431bSRobert Mustacchi 		if (err != USBGEM_SUCCESS) {
11326716431bSRobert Mustacchi 			break;
11336716431bSRobert Mustacchi 		}
11346716431bSRobert Mustacchi 		val = axf_mii_read(dp, MII_AN_ADVERT, &err);
11356716431bSRobert Mustacchi 		if (err != USBGEM_SUCCESS) {
11366716431bSRobert Mustacchi 			break;
11376716431bSRobert Mustacchi 		}
11386716431bSRobert Mustacchi 		if ((val & MII_ABILITY_TECH) != PROBE_PAT) {
11396716431bSRobert Mustacchi 			DPRINTF(0, (CE_CONT, "!%s: %s: "
11406716431bSRobert Mustacchi 			    "index:%d,  pat:%x != val:%b",
11416716431bSRobert Mustacchi 			    dp->name, __func__, i,
11426716431bSRobert Mustacchi 			    PROBE_PAT, val, MII_ABILITY_BITS));
11436716431bSRobert Mustacchi 			continue;
11446716431bSRobert Mustacchi 		}
11456716431bSRobert Mustacchi 
11466716431bSRobert Mustacchi 		/* found */
11476716431bSRobert Mustacchi 		dp->mii_phy_addr = phy_addr_saved;
11486716431bSRobert Mustacchi 		return (i);
11496716431bSRobert Mustacchi 	}
11506716431bSRobert Mustacchi #undef PROBE_PAT
11516716431bSRobert Mustacchi 	if (i == 32) {
11526716431bSRobert Mustacchi 		cmn_err(CE_CONT, "!%s: %s: no mii phy found",
11536716431bSRobert Mustacchi 		    dp->name, __func__);
11546716431bSRobert Mustacchi 	} else {
11556716431bSRobert Mustacchi 		cmn_err(CE_CONT, "!%s: %s: i/o error while scanning phy",
11566716431bSRobert Mustacchi 		    dp->name, __func__);
11576716431bSRobert Mustacchi 	}
11586716431bSRobert Mustacchi 	dp->mii_phy_addr = phy_addr_saved;
11596716431bSRobert Mustacchi 	return (-1);
11606716431bSRobert Mustacchi }
11616716431bSRobert Mustacchi 
11626716431bSRobert Mustacchi static int
axf_mii_probe(struct usbgem_dev * dp)11636716431bSRobert Mustacchi axf_mii_probe(struct usbgem_dev *dp)
11646716431bSRobert Mustacchi {
11656716431bSRobert Mustacchi 	int	my_guess;
11666716431bSRobert Mustacchi 	int	err;
11676716431bSRobert Mustacchi 	uint8_t	old_11th[2];
11686716431bSRobert Mustacchi 	uint8_t	new_11th[2];
11696716431bSRobert Mustacchi 	struct axf_dev	*lp = dp->private;
11706716431bSRobert Mustacchi 
11716716431bSRobert Mustacchi 	DPRINTF(0, (CE_CONT, "!%s: %s: called", dp->name, __func__));
11726716431bSRobert Mustacchi 	(void) axf_reset_phy(dp);
11736716431bSRobert Mustacchi 	lp->phy_has_reset = B_TRUE;
11746716431bSRobert Mustacchi 
11756716431bSRobert Mustacchi 	if (AX88172(dp)) {
11766716431bSRobert Mustacchi 		my_guess = axf_scan_phy(dp);
11776716431bSRobert Mustacchi 		if (my_guess >= 0 && my_guess < 32 &&
11786716431bSRobert Mustacchi 		    my_guess != dp->mii_phy_addr) {
11796716431bSRobert Mustacchi 			/*
11806716431bSRobert Mustacchi 			 * phy addr in srom is wrong, need to fix it
11816716431bSRobert Mustacchi 			 */
11826716431bSRobert Mustacchi 			IN(dp, VCMD_READ_SROM,
11836716431bSRobert Mustacchi 			    0x11, 0, 2, old_11th, &err, usberr);
11846716431bSRobert Mustacchi 
11856716431bSRobert Mustacchi 			new_11th[0] = my_guess;
11866716431bSRobert Mustacchi 			new_11th[1] = old_11th[1];
11876716431bSRobert Mustacchi 
11886716431bSRobert Mustacchi 			OUT(dp, VCMD_WRITE_SROM_ENABLE,
11896716431bSRobert Mustacchi 			    0, 0, 0, NULL, &err, usberr);
11906716431bSRobert Mustacchi 			OUT(dp, VCMD_WRITE_SROM,
11916716431bSRobert Mustacchi 			    0x11, LE16P(new_11th), 0, NULL, &err, usberr);
11926716431bSRobert Mustacchi 			OUT(dp, VCMD_WRITE_SROM_DISABLE,
11936716431bSRobert Mustacchi 			    0, 0, 0, NULL, &err, usberr);
11946716431bSRobert Mustacchi #if 1
11956716431bSRobert Mustacchi 			/* XXX - read back, but it doesn't work, why? */
11966716431bSRobert Mustacchi 			delay(drv_usectohz(1000*1000));
11976716431bSRobert Mustacchi 			IN(dp, VCMD_READ_SROM,
11986716431bSRobert Mustacchi 			    0x11, 0, 2, new_11th, &err, usberr);
11996716431bSRobert Mustacchi #endif
12006716431bSRobert Mustacchi 			cmn_err(CE_NOTE, "!%s: %s: phy addr in srom fixed: "
12016716431bSRobert Mustacchi 			    "%04x -> %04x",
12026716431bSRobert Mustacchi 			    dp->name, __func__,
12036716431bSRobert Mustacchi 			    LE16P(old_11th), LE16P(new_11th));
12046716431bSRobert Mustacchi 			return (USBGEM_FAILURE);
12056716431bSRobert Mustacchi usberr:
12066716431bSRobert Mustacchi 			cmn_err(CE_NOTE,
12076716431bSRobert Mustacchi 			    "!%s: %s:  failed to patch phy addr, "
12086716431bSRobert Mustacchi 			    "current: %04x",
12096716431bSRobert Mustacchi 			    dp->name, __func__, LE16P(old_11th));
12106716431bSRobert Mustacchi 			return (USBGEM_FAILURE);
12116716431bSRobert Mustacchi 		}
12126716431bSRobert Mustacchi 	}
12136716431bSRobert Mustacchi 	return (usbgem_mii_probe_default(dp));
12146716431bSRobert Mustacchi }
12156716431bSRobert Mustacchi 
12166716431bSRobert Mustacchi static int
axf_mii_init(struct usbgem_dev * dp)12176716431bSRobert Mustacchi axf_mii_init(struct usbgem_dev *dp)
12186716431bSRobert Mustacchi {
12196716431bSRobert Mustacchi 	struct axf_dev	*lp = dp->private;
12206716431bSRobert Mustacchi 
12216716431bSRobert Mustacchi 	DPRINTF(2, (CE_CONT, "!%s: %s: called", dp->name, __func__));
12226716431bSRobert Mustacchi 
12236716431bSRobert Mustacchi 	if (!lp->phy_has_reset) {
12246716431bSRobert Mustacchi 		(void) axf_reset_phy(dp);
12256716431bSRobert Mustacchi 	}
12266716431bSRobert Mustacchi 
12276716431bSRobert Mustacchi 	/* prepare to reset phy on the next reconnect or resume */
12286716431bSRobert Mustacchi 	lp->phy_has_reset = B_FALSE;
12296716431bSRobert Mustacchi 
12306716431bSRobert Mustacchi 	return (USB_SUCCESS);
12316716431bSRobert Mustacchi }
12326716431bSRobert Mustacchi 
12336716431bSRobert Mustacchi static int
axfattach(dev_info_t * dip,ddi_attach_cmd_t cmd)12346716431bSRobert Mustacchi axfattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
12356716431bSRobert Mustacchi {
12366716431bSRobert Mustacchi 	int			i;
12376716431bSRobert Mustacchi 	ddi_iblock_cookie_t	c;
12386716431bSRobert Mustacchi 	int			ret;
12396716431bSRobert Mustacchi 	int			revid;
12406716431bSRobert Mustacchi 	int			unit;
12416716431bSRobert Mustacchi 	int			vid;
12426716431bSRobert Mustacchi 	int			pid;
12436716431bSRobert Mustacchi 	struct chip_info	*p;
12446716431bSRobert Mustacchi 	int			len;
12456716431bSRobert Mustacchi 	const char		*drv_name;
12466716431bSRobert Mustacchi 	struct usbgem_dev	*dp;
12476716431bSRobert Mustacchi 	void			*base;
12486716431bSRobert Mustacchi 	struct usbgem_conf	*ugcp;
12496716431bSRobert Mustacchi 	struct axf_dev		*lp;
12506716431bSRobert Mustacchi 
12516716431bSRobert Mustacchi 	unit = ddi_get_instance(dip);
12526716431bSRobert Mustacchi 	drv_name = ddi_driver_name(dip);
12536716431bSRobert Mustacchi 
12546716431bSRobert Mustacchi 	DPRINTF(3, (CE_CONT, "!%s%d: %s: called, cmd:%d",
12556716431bSRobert Mustacchi 	    drv_name, unit, __func__, cmd));
12566716431bSRobert Mustacchi 
12576716431bSRobert Mustacchi 	if (cmd == DDI_ATTACH) {
12586716431bSRobert Mustacchi 		/*
12596716431bSRobert Mustacchi 		 * Check if the chip is supported.
12606716431bSRobert Mustacchi 		 */
12616716431bSRobert Mustacchi 		vid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
12626716431bSRobert Mustacchi 		    "usb-vendor-id", -1);
12636716431bSRobert Mustacchi 		pid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
12646716431bSRobert Mustacchi 		    "usb-product-id", -1);
12656716431bSRobert Mustacchi 		revid = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
12666716431bSRobert Mustacchi 		    "usb-revision-id", -1);
12676716431bSRobert Mustacchi 
12686716431bSRobert Mustacchi 		for (i = 0, p = chiptbl_88x7x; i < CHIPTABLESIZE; i++, p++) {
12696716431bSRobert Mustacchi 			if (p->vid == vid && p->pid == pid) {
12706716431bSRobert Mustacchi 				/* found */
12716716431bSRobert Mustacchi 				cmn_err(CE_CONT, "!%s%d: %s "
12726716431bSRobert Mustacchi 				    "(vid: 0x%04x, did: 0x%04x, revid: 0x%02x)",
12736716431bSRobert Mustacchi 				    drv_name, unit, p->name, vid, pid, revid);
12746716431bSRobert Mustacchi 				goto chip_found;
12756716431bSRobert Mustacchi 			}
12766716431bSRobert Mustacchi 		}
12776716431bSRobert Mustacchi 
12786716431bSRobert Mustacchi 		/* Not found */
12796716431bSRobert Mustacchi 		cmn_err(CE_WARN, "!%s: %s: wrong usb venid/prodid (0x%x, 0x%x)",
12806716431bSRobert Mustacchi 		    drv_name, __func__, vid, pid);
12816716431bSRobert Mustacchi 
12826716431bSRobert Mustacchi 		/* assume 88772 */
12836716431bSRobert Mustacchi 		p = &chiptbl_88x7x[CHIPTABLESIZE - 1];
12846716431bSRobert Mustacchi chip_found:
12856716431bSRobert Mustacchi 		/*
12866716431bSRobert Mustacchi 		 * construct usbgem configration
12876716431bSRobert Mustacchi 		 */
12886716431bSRobert Mustacchi 		ugcp = kmem_zalloc(sizeof (*ugcp), KM_SLEEP);
12896716431bSRobert Mustacchi 
12906716431bSRobert Mustacchi 		/* name */
12916716431bSRobert Mustacchi 		/*
12926716431bSRobert Mustacchi 		 * softmac requires that ppa is the instance number
12936716431bSRobert Mustacchi 		 * of the device, otherwise it hangs in seaching the device.
12946716431bSRobert Mustacchi 		 */
12956716431bSRobert Mustacchi 		(void) sprintf(ugcp->usbgc_name, "%s%d", drv_name, unit);
12966716431bSRobert Mustacchi 		ugcp->usbgc_ppa = unit;
12976716431bSRobert Mustacchi 
12986716431bSRobert Mustacchi 		ugcp->usbgc_ifnum = 0;
12996716431bSRobert Mustacchi 		ugcp->usbgc_alt = 0;
13006716431bSRobert Mustacchi 
13016716431bSRobert Mustacchi 		ugcp->usbgc_tx_list_max = 64;
13026716431bSRobert Mustacchi 
13036716431bSRobert Mustacchi 		ugcp->usbgc_rx_header_len = 0;
13046716431bSRobert Mustacchi 		ugcp->usbgc_rx_list_max = 64;
13056716431bSRobert Mustacchi 
13066716431bSRobert Mustacchi 		/* time out parameters */
13076716431bSRobert Mustacchi 		ugcp->usbgc_tx_timeout = USBGEM_TX_TIMEOUT;
13086716431bSRobert Mustacchi 		ugcp->usbgc_tx_timeout_interval = USBGEM_TX_TIMEOUT_INTERVAL;
13096716431bSRobert Mustacchi 
13106716431bSRobert Mustacchi 		/* flow control */
13116716431bSRobert Mustacchi 		/*
13126716431bSRobert Mustacchi 		 * XXX - flow control caused link down frequently under
13136716431bSRobert Mustacchi 		 * heavy traffic
13146716431bSRobert Mustacchi 		 */
13156716431bSRobert Mustacchi 		ugcp->usbgc_flow_control = FLOW_CONTROL_RX_PAUSE;
13166716431bSRobert Mustacchi 
13176716431bSRobert Mustacchi 		/* MII timeout parameters */
13186716431bSRobert Mustacchi 		ugcp->usbgc_mii_link_watch_interval = ONESEC;
13196716431bSRobert Mustacchi 		ugcp->usbgc_mii_an_watch_interval = ONESEC/5;
13206716431bSRobert Mustacchi 		ugcp->usbgc_mii_reset_timeout = MII_RESET_TIMEOUT; /* 1 sec */
13216716431bSRobert Mustacchi 		ugcp->usbgc_mii_an_timeout = MII_AN_TIMEOUT;	/* 5 sec */
13226716431bSRobert Mustacchi 		ugcp->usbgc_mii_an_wait = 0;
13236716431bSRobert Mustacchi 		ugcp->usbgc_mii_linkdown_timeout = MII_LINKDOWN_TIMEOUT;
13246716431bSRobert Mustacchi 
13256716431bSRobert Mustacchi 		ugcp->usbgc_mii_an_delay = ONESEC/10;
13266716431bSRobert Mustacchi 		ugcp->usbgc_mii_linkdown_action = MII_ACTION_RSA;
13276716431bSRobert Mustacchi 		ugcp->usbgc_mii_linkdown_timeout_action = MII_ACTION_RESET;
13286716431bSRobert Mustacchi 		ugcp->usbgc_mii_dont_reset = B_FALSE;
13296716431bSRobert Mustacchi 		ugcp->usbgc_mii_hw_link_detection = B_TRUE;
13306716431bSRobert Mustacchi 		ugcp->usbgc_mii_stop_mac_on_linkdown = B_FALSE;
13316716431bSRobert Mustacchi 
13326716431bSRobert Mustacchi 		/* I/O methods */
13336716431bSRobert Mustacchi 
13346716431bSRobert Mustacchi 		/* mac operation */
13356716431bSRobert Mustacchi 		ugcp->usbgc_attach_chip = &axf_attach_chip;
13366716431bSRobert Mustacchi 		ugcp->usbgc_reset_chip = &axf_reset_chip;
13376716431bSRobert Mustacchi 		ugcp->usbgc_init_chip = &axf_init_chip;
13386716431bSRobert Mustacchi 		ugcp->usbgc_start_chip = &axf_start_chip;
13396716431bSRobert Mustacchi 		ugcp->usbgc_stop_chip = &axf_stop_chip;
13406716431bSRobert Mustacchi 		ugcp->usbgc_multicast_hash = &axf_mcast_hash;
13416716431bSRobert Mustacchi 
13426716431bSRobert Mustacchi 		ugcp->usbgc_set_rx_filter = &axf_set_rx_filter;
13436716431bSRobert Mustacchi 		ugcp->usbgc_set_media = &axf_set_media;
13446716431bSRobert Mustacchi 		ugcp->usbgc_get_stats = &axf_get_stats;
13456716431bSRobert Mustacchi 		ugcp->usbgc_interrupt = &axf_interrupt;
13466716431bSRobert Mustacchi 
13476716431bSRobert Mustacchi 		/* packet operation */
13486716431bSRobert Mustacchi 		ugcp->usbgc_tx_make_packet = &axf_tx_make_packet;
13496716431bSRobert Mustacchi 		ugcp->usbgc_rx_make_packet = &axf_rx_make_packet;
13506716431bSRobert Mustacchi 
13516716431bSRobert Mustacchi 		/* mii operations */
13526716431bSRobert Mustacchi 		ugcp->usbgc_mii_probe = &axf_mii_probe;
13536716431bSRobert Mustacchi 		ugcp->usbgc_mii_init = &axf_mii_init;
13546716431bSRobert Mustacchi 		ugcp->usbgc_mii_config = &usbgem_mii_config_default;
13556716431bSRobert Mustacchi 		ugcp->usbgc_mii_read = &axf_mii_read;
13566716431bSRobert Mustacchi 		ugcp->usbgc_mii_write = &axf_mii_write;
13576716431bSRobert Mustacchi 
13586716431bSRobert Mustacchi 		/* mtu */
13596716431bSRobert Mustacchi 		ugcp->usbgc_min_mtu = ETHERMTU;
13606716431bSRobert Mustacchi 		ugcp->usbgc_max_mtu = ETHERMTU;
13616716431bSRobert Mustacchi 		ugcp->usbgc_default_mtu = ETHERMTU;
13626716431bSRobert Mustacchi 
13636716431bSRobert Mustacchi 		lp = kmem_zalloc(sizeof (struct axf_dev), KM_SLEEP);
13646716431bSRobert Mustacchi 		lp->chip = p;
13656716431bSRobert Mustacchi 		lp->last_link_state = 0;
13666716431bSRobert Mustacchi 		lp->phy_has_reset = B_FALSE;
13676716431bSRobert Mustacchi 
13686716431bSRobert Mustacchi 		dp = usbgem_do_attach(dip, ugcp, lp, sizeof (struct axf_dev));
13696716431bSRobert Mustacchi 
13706716431bSRobert Mustacchi 		kmem_free(ugcp, sizeof (*ugcp));
13716716431bSRobert Mustacchi 
13726716431bSRobert Mustacchi 		if (dp != NULL) {
13736716431bSRobert Mustacchi 			return (DDI_SUCCESS);
13746716431bSRobert Mustacchi 		}
13756716431bSRobert Mustacchi 
13766716431bSRobert Mustacchi err_free_mem:
13776716431bSRobert Mustacchi 		kmem_free(lp, sizeof (struct axf_dev));
13786716431bSRobert Mustacchi err_close_pipe:
13796716431bSRobert Mustacchi err:
13806716431bSRobert Mustacchi 		return (DDI_FAILURE);
13816716431bSRobert Mustacchi 	}
13826716431bSRobert Mustacchi 
13836716431bSRobert Mustacchi 	if (cmd == DDI_RESUME) {
13846716431bSRobert Mustacchi 		return (usbgem_resume(dip));
13856716431bSRobert Mustacchi 	}
13866716431bSRobert Mustacchi 
13876716431bSRobert Mustacchi 	return (DDI_FAILURE);
13886716431bSRobert Mustacchi }
13896716431bSRobert Mustacchi 
13906716431bSRobert Mustacchi static int
axfdetach(dev_info_t * dip,ddi_detach_cmd_t cmd)13916716431bSRobert Mustacchi axfdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
13926716431bSRobert Mustacchi {
13936716431bSRobert Mustacchi 	int	ret;
13946716431bSRobert Mustacchi 
13956716431bSRobert Mustacchi 	if (cmd == DDI_DETACH) {
13966716431bSRobert Mustacchi 		ret = usbgem_do_detach(dip);
13976716431bSRobert Mustacchi 		if (ret != DDI_SUCCESS) {
13986716431bSRobert Mustacchi 			return (DDI_FAILURE);
13996716431bSRobert Mustacchi 		}
14006716431bSRobert Mustacchi 		return (DDI_SUCCESS);
14016716431bSRobert Mustacchi 	}
14026716431bSRobert Mustacchi 	if (cmd == DDI_SUSPEND) {
14036716431bSRobert Mustacchi 		return (usbgem_suspend(dip));
14046716431bSRobert Mustacchi 	}
14056716431bSRobert Mustacchi 	return (DDI_FAILURE);
14066716431bSRobert Mustacchi }
14076716431bSRobert Mustacchi 
14086716431bSRobert Mustacchi /* ======================================================== */
14096716431bSRobert Mustacchi /*
14106716431bSRobert Mustacchi  * OS depend (loadable streams driver) routine
14116716431bSRobert Mustacchi  */
14126716431bSRobert Mustacchi /* ======================================================== */
14136716431bSRobert Mustacchi USBGEM_STREAM_OPS(axf_ops, axfattach, axfdetach);
14146716431bSRobert Mustacchi 
14156716431bSRobert Mustacchi static struct modldrv modldrv = {
14166716431bSRobert Mustacchi 	&mod_driverops,	/* Type of module.  This one is a driver */
14176716431bSRobert Mustacchi 	ident,
14186716431bSRobert Mustacchi 	&axf_ops,	/* driver ops */
14196716431bSRobert Mustacchi };
14206716431bSRobert Mustacchi 
14216716431bSRobert Mustacchi static struct modlinkage modlinkage = {
14226716431bSRobert Mustacchi 	MODREV_1, &modldrv, NULL
14236716431bSRobert Mustacchi };
14246716431bSRobert Mustacchi 
14256716431bSRobert Mustacchi /* ======================================================== */
14266716431bSRobert Mustacchi /*
14276716431bSRobert Mustacchi  * _init : done
14286716431bSRobert Mustacchi  */
14296716431bSRobert Mustacchi /* ======================================================== */
14306716431bSRobert Mustacchi int
_init(void)14316716431bSRobert Mustacchi _init(void)
14326716431bSRobert Mustacchi {
1433ceb6b962SRobert Mustacchi 	int	status;
14346716431bSRobert Mustacchi 
14356716431bSRobert Mustacchi 	DPRINTF(2, (CE_CONT, "!axf: _init: called"));
14366716431bSRobert Mustacchi 
14376716431bSRobert Mustacchi 	status = usbgem_mod_init(&axf_ops, "axf");
14386716431bSRobert Mustacchi 	if (status != DDI_SUCCESS) {
14396716431bSRobert Mustacchi 		return (status);
14406716431bSRobert Mustacchi 	}
14416716431bSRobert Mustacchi 	status = mod_install(&modlinkage);
14426716431bSRobert Mustacchi 	if (status != DDI_SUCCESS) {
14436716431bSRobert Mustacchi 		usbgem_mod_fini(&axf_ops);
14446716431bSRobert Mustacchi 	}
14456716431bSRobert Mustacchi 	return (status);
14466716431bSRobert Mustacchi }
14476716431bSRobert Mustacchi 
14486716431bSRobert Mustacchi /*
14496716431bSRobert Mustacchi  * _fini : done
14506716431bSRobert Mustacchi  */
14516716431bSRobert Mustacchi int
_fini(void)14526716431bSRobert Mustacchi _fini(void)
14536716431bSRobert Mustacchi {
14546716431bSRobert Mustacchi 	int	status;
14556716431bSRobert Mustacchi 
14566716431bSRobert Mustacchi 	DPRINTF(2, (CE_CONT, "!axf: _fini: called"));
14576716431bSRobert Mustacchi 	status = mod_remove(&modlinkage);
14586716431bSRobert Mustacchi 	if (status == DDI_SUCCESS) {
14596716431bSRobert Mustacchi 		usbgem_mod_fini(&axf_ops);
14606716431bSRobert Mustacchi 	}
14616716431bSRobert Mustacchi 	return (status);
14626716431bSRobert Mustacchi }
14636716431bSRobert Mustacchi 
14646716431bSRobert Mustacchi int
_info(struct modinfo * modinfop)14656716431bSRobert Mustacchi _info(struct modinfo *modinfop)
14666716431bSRobert Mustacchi {
14676716431bSRobert Mustacchi 	return (mod_info(&modlinkage, modinfop));
14686716431bSRobert Mustacchi }
1469