Deleted Added
sdiff udiff text old ( 226479 ) new ( 226743 )
full compact
1/*-
2 * Copyright (c) 1997, 1998, 1999, 2000-2003
3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 17 unchanged lines hidden (view full) ---

26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_axe.c 226479 2011-10-17 19:51:38Z yongari $");
35
36/*
37 * ASIX Electronics AX88172/AX88178/AX88778 USB 2.0 ethernet driver.
38 * Used in the LinkSys USB200M and various other adapters.
39 *
40 * Manuals available from:
41 * http://www.asix.com.tw/datasheet/mac/Ax88172.PDF
42 * Note: you need the manual for the AX88170 chip (USB 1.x ethernet

--- 28 unchanged lines hidden (view full) ---

71 * Ax88178 and Ax88772 support backported from the OpenBSD driver.
72 * 2007/02/12, J.R. Oldroyd, fbsd@opal.com
73 *
74 * Manual here:
75 * http://www.asix.com.tw/FrootAttach/datasheet/AX88178_datasheet_Rev10.pdf
76 * http://www.asix.com.tw/FrootAttach/datasheet/AX88772_datasheet_Rev10.pdf
77 */
78
79#include <sys/stdint.h>
80#include <sys/stddef.h>
81#include <sys/param.h>
82#include <sys/queue.h>
83#include <sys/types.h>
84#include <sys/systm.h>
85#include <sys/kernel.h>
86#include <sys/bus.h>
87#include <sys/module.h>
88#include <sys/lock.h>
89#include <sys/mutex.h>
90#include <sys/condvar.h>
91#include <sys/sysctl.h>
92#include <sys/sx.h>
93#include <sys/unistd.h>
94#include <sys/callout.h>
95#include <sys/malloc.h>
96#include <sys/priv.h>
97
98#include <dev/usb/usb.h>
99#include <dev/usb/usbdi.h>
100#include <dev/usb/usbdi_util.h>
101#include "usbdevs.h"
102
103#define USB_DEBUG_VAR axe_debug
104#include <dev/usb/usb_debug.h>
105#include <dev/usb/usb_process.h>

--- 11 unchanged lines hidden (view full) ---

117 * use the largest your system can handle without USB stalling.
118 *
119 * NB: 88772 parts appear to generate lots of input errors with
120 * a 2K rx buffer and 8K is only slightly faster than 4K on an
121 * EHCI port on a T42 so change at your own risk.
122 */
123#define AXE_178_MAX_FRAME_BURST 1
124
125#ifdef USB_DEBUG
126static int axe_debug = 0;
127
128SYSCTL_NODE(_hw_usb, OID_AUTO, axe, CTLFLAG_RW, 0, "USB axe");
129SYSCTL_INT(_hw_usb_axe, OID_AUTO, debug, CTLFLAG_RW, &axe_debug, 0,
130 "Debug level");
131#endif
132

--- 48 unchanged lines hidden (view full) ---

181static uether_fn_t axe_attach_post;
182static uether_fn_t axe_init;
183static uether_fn_t axe_stop;
184static uether_fn_t axe_start;
185static uether_fn_t axe_tick;
186static uether_fn_t axe_setmulti;
187static uether_fn_t axe_setpromisc;
188
189static int axe_ifmedia_upd(struct ifnet *);
190static void axe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
191static int axe_cmd(struct axe_softc *, int, int, int, void *);
192static void axe_ax88178_init(struct axe_softc *);
193static void axe_ax88772_init(struct axe_softc *);
194static void axe_ax88772_phywake(struct axe_softc *);
195static void axe_ax88772a_init(struct axe_softc *);
196static void axe_ax88772b_init(struct axe_softc *);
197static int axe_get_phyno(struct axe_softc *, int);
198
199static const struct usb_config axe_config[AXE_N_TRANSFER] = {
200
201 [AXE_BULK_DT_WR] = {
202 .type = UE_BULK,
203 .endpoint = UE_ADDR_ANY,
204 .direction = UE_DIR_OUT,
205 .frames = 16,

--- 55 unchanged lines hidden (view full) ---

261MODULE_DEPEND(axe, uether, 1, 1, 1);
262MODULE_DEPEND(axe, usb, 1, 1, 1);
263MODULE_DEPEND(axe, ether, 1, 1, 1);
264MODULE_DEPEND(axe, miibus, 1, 1, 1);
265MODULE_VERSION(axe, 1);
266
267static const struct usb_ether_methods axe_ue_methods = {
268 .ue_attach_post = axe_attach_post,
269 .ue_start = axe_start,
270 .ue_init = axe_init,
271 .ue_stop = axe_stop,
272 .ue_tick = axe_tick,
273 .ue_setmulti = axe_setmulti,
274 .ue_setpromisc = axe_setpromisc,
275 .ue_mii_upd = axe_ifmedia_upd,
276 .ue_mii_sts = axe_ifmedia_sts,

--- 22 unchanged lines hidden (view full) ---

299
300static int
301axe_miibus_readreg(device_t dev, int phy, int reg)
302{
303 struct axe_softc *sc = device_get_softc(dev);
304 uint16_t val;
305 int locked;
306
307 if (sc->sc_phyno != phy)
308 return (0);
309
310 locked = mtx_owned(&sc->sc_mtx);
311 if (!locked)
312 AXE_LOCK(sc);
313
314 axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
315 axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, &val);
316 axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
317

--- 15 unchanged lines hidden (view full) ---

333
334static int
335axe_miibus_writereg(device_t dev, int phy, int reg, int val)
336{
337 struct axe_softc *sc = device_get_softc(dev);
338 int locked;
339
340 val = htole32(val);
341
342 if (sc->sc_phyno != phy)
343 return (0);
344
345 locked = mtx_owned(&sc->sc_mtx);
346 if (!locked)
347 AXE_LOCK(sc);
348
349 axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
350 axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, &val);
351 axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
352

--- 14 unchanged lines hidden (view full) ---

367 locked = mtx_owned(&sc->sc_mtx);
368 if (!locked)
369 AXE_LOCK(sc);
370
371 ifp = uether_getifp(&sc->sc_ue);
372 if (mii == NULL || ifp == NULL ||
373 (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
374 goto done;
375
376 sc->sc_flags &= ~AXE_FLAG_LINK;
377 if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
378 (IFM_ACTIVE | IFM_AVALID)) {
379 switch (IFM_SUBTYPE(mii->mii_media_active)) {
380 case IFM_10_T:
381 case IFM_100_TX:
382 sc->sc_flags |= AXE_FLAG_LINK;
383 break;
384 case IFM_1000_T:
385 if ((sc->sc_flags & AXE_FLAG_178) == 0)
386 break;
387 sc->sc_flags |= AXE_FLAG_LINK;
388 break;
389 default:
390 break;
391 }
392 }
393
394 /* Lost link, do nothing. */
395 if ((sc->sc_flags & AXE_FLAG_LINK) == 0)
396 goto done;
397
398 val = 0;
399 if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
400 val |= AXE_MEDIA_FULL_DUPLEX;
401 if (AXE_IS_178_FAMILY(sc)) {
402 val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC;
403 if ((sc->sc_flags & AXE_FLAG_178) != 0)
404 val |= AXE_178_MEDIA_ENCK;
405 switch (IFM_SUBTYPE(mii->mii_media_active)) {
406 case IFM_1000_T:
407 val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK;
408 break;

--- 431 unchanged lines hidden (view full) ---

840 /* Set IPG values. */
841 sc->sc_ipgs[0] = 0x15;
842 sc->sc_ipgs[1] = 0x16;
843 sc->sc_ipgs[2] = 0x1A;
844 } else
845 axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->sc_ipgs);
846}
847
848/*
849 * Probe for a AX88172 chip.
850 */
851static int
852axe_probe(device_t dev)
853{
854 struct usb_attach_arg *uaa = device_get_ivars(dev);
855

--- 69 unchanged lines hidden (view full) ---

925#error "Please update axe_bulk_read_callback()!"
926#endif
927
928static void
929axe_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
930{
931 struct axe_softc *sc = usbd_xfer_softc(xfer);
932 struct usb_ether *ue = &sc->sc_ue;
933 struct ifnet *ifp = uether_getifp(ue);
934 struct axe_sframe_hdr hdr;
935 struct usb_page_cache *pc;
936 int err, pos, len;
937 int actlen;
938
939 usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
940
941 switch (USB_GET_STATE(xfer)) {
942 case USB_ST_TRANSFERRED:
943 pos = 0;
944 len = 0;
945 err = 0;
946
947 pc = usbd_xfer_get_frame(xfer, 0);
948 if (AXE_IS_178_FAMILY(sc)) {
949 while (pos < actlen) {
950 if ((pos + sizeof(hdr)) > actlen) {
951 /* too little data */
952 err = EINVAL;
953 break;
954 }
955 usbd_copy_out(pc, pos, &hdr, sizeof(hdr));
956
957 if ((hdr.len ^ hdr.ilen) != 0xFFFF) {
958 /* we lost sync */
959 err = EINVAL;
960 break;
961 }
962 pos += sizeof(hdr);
963
964 len = le16toh(hdr.len);
965 if ((pos + len) > actlen) {
966 /* invalid length */
967 err = EINVAL;
968 break;
969 }
970 uether_rxbuf(ue, pc, pos, len);
971
972 pos += len + (len % 2);
973 }
974 } else
975 uether_rxbuf(ue, pc, 0, actlen);
976
977 if (err != 0)
978 ifp->if_ierrors++;
979
980 /* FALLTHROUGH */
981 case USB_ST_SETUP:
982tr_setup:
983 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
984 usbd_transfer_submit(xfer);
985 uether_rxflush(ue);
986 return;
987

--- 5 unchanged lines hidden (view full) ---

993 usbd_xfer_set_stall(xfer);
994 goto tr_setup;
995 }
996 return;
997
998 }
999}
1000
1001#if ((AXE_BULK_BUF_SIZE >= 0x10000) || (AXE_BULK_BUF_SIZE < (MCLBYTES+4)))
1002#error "Please update axe_bulk_write_callback()!"
1003#endif
1004
1005static void
1006axe_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
1007{
1008 struct axe_softc *sc = usbd_xfer_softc(xfer);

--- 26 unchanged lines hidden (view full) ---

1035 break;
1036 usbd_xfer_set_frame_offset(xfer, nframes * MCLBYTES,
1037 nframes);
1038 pos = 0;
1039 pc = usbd_xfer_get_frame(xfer, nframes);
1040 if (AXE_IS_178_FAMILY(sc)) {
1041 hdr.len = htole16(m->m_pkthdr.len);
1042 hdr.ilen = ~hdr.len;
1043 usbd_copy_in(pc, pos, &hdr, sizeof(hdr));
1044 pos += sizeof(hdr);
1045 usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len);
1046 pos += m->m_pkthdr.len;
1047 if ((pos % 512) == 0) {
1048 hdr.len = 0;
1049 hdr.ilen = 0xffff;
1050 usbd_copy_in(pc, pos, &hdr,

--- 75 unchanged lines hidden (view full) ---

1126 /*
1127 * start the USB transfers, if not already started:
1128 */
1129 usbd_transfer_start(sc->sc_xfer[AXE_BULK_DT_RD]);
1130 usbd_transfer_start(sc->sc_xfer[AXE_BULK_DT_WR]);
1131}
1132
1133static void
1134axe_init(struct usb_ether *ue)
1135{
1136 struct axe_softc *sc = uether_getsc(ue);
1137 struct ifnet *ifp = uether_getifp(ue);
1138 uint16_t rxmode;
1139
1140 AXE_LOCK_ASSERT(sc, MA_OWNED);
1141
1142 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1143 return;
1144
1145 /* Cancel pending I/O */
1146 axe_stop(ue);
1147
1148 axe_reset(sc);
1149
1150 /* Set MAC address. */
1151 if (AXE_IS_178_FAMILY(sc))
1152 axe_cmd(sc, AXE_178_CMD_WRITE_NODEID, 0, 0, IF_LLADDR(ifp));
1153 else
1154 axe_cmd(sc, AXE_172_CMD_WRITE_NODEID, 0, 0, IF_LLADDR(ifp));
1155
1156 /* Set transmitter IPG values */
1157 if (AXE_IS_178_FAMILY(sc))
1158 axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->sc_ipgs[2],
1159 (sc->sc_ipgs[1] << 8) | (sc->sc_ipgs[0]), NULL);
1160 else {
1161 axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->sc_ipgs[0], NULL);
1162 axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->sc_ipgs[1], NULL);
1163 axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->sc_ipgs[2], NULL);
1164 }
1165
1166 /* AX88772B uses different maximum frame burst configuration. */
1167 if (sc->sc_flags & AXE_FLAG_772B)
1168 axe_cmd(sc, AXE_772B_CMD_RXCTL_WRITE_CFG,
1169 ax88772b_mfb_table[AX88772B_MFB_16K].threshold,
1170 ax88772b_mfb_table[AX88772B_MFB_16K].byte_cnt, NULL);
1171
1172 /* Enable receiver, set RX mode. */
1173 rxmode = (AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE);
1174 if (AXE_IS_178_FAMILY(sc)) {
1175 if (sc->sc_flags & AXE_FLAG_772B) {
1176 /*
1177 * Select RX header format type 1. Aligning IP
1178 * header on 4 byte boundary is not needed
1179 * because we always copy the received frame in
1180 * RX handler.
1181 */
1182 rxmode |= AXE_772B_RXCMD_HDR_TYPE_1;
1183 } else {
1184 /*
1185 * Default Rx buffer size is too small to get
1186 * maximum performance.
1187 */
1188 rxmode |= AXE_178_RXCMD_MFB_16384;
1189 }
1190 } else {

--- 12 unchanged lines hidden (view full) ---

1203 /* Load the multicast filter. */
1204 axe_setmulti(ue);
1205
1206 usbd_xfer_set_stall(sc->sc_xfer[AXE_BULK_DT_WR]);
1207
1208 ifp->if_drv_flags |= IFF_DRV_RUNNING;
1209 /* Switch to selected media. */
1210 axe_ifmedia_upd(ifp);
1211 axe_start(ue);
1212}
1213
1214static void
1215axe_setpromisc(struct usb_ether *ue)
1216{
1217 struct axe_softc *sc = uether_getsc(ue);
1218 struct ifnet *ifp = uether_getifp(ue);
1219 uint16_t rxmode;

--- 25 unchanged lines hidden (view full) ---

1245 sc->sc_flags &= ~AXE_FLAG_LINK;
1246
1247 /*
1248 * stop all the transfers, if not already stopped:
1249 */
1250 usbd_transfer_stop(sc->sc_xfer[AXE_BULK_DT_WR]);
1251 usbd_transfer_stop(sc->sc_xfer[AXE_BULK_DT_RD]);
1252}