Add initial support for AX88772B USB Fast Ethernet. AX88772B
supports IPv4/IPv6 checksum offloading and VLAN tag insertion/ stripping as well as WOL. Because uether does not provide a way to announce driver specific offload capabilities to upper stack, checksum offloading support needs more work and will be done in future. Special thanks to ASIX for donating sample hardware. H/W donated by: ASIX Electronics Reviewed by: hselasky
This commit is contained in:
parent
297becf967
commit
14ae1fa4cf
@ -142,6 +142,7 @@ static const STRUCT_USB_HOST_ID axe_devs[] = {
|
||||
AXE_DEV(ASIX, AX88178, AXE_FLAG_178),
|
||||
AXE_DEV(ASIX, AX88772, AXE_FLAG_772),
|
||||
AXE_DEV(ASIX, AX88772A, AXE_FLAG_772A),
|
||||
AXE_DEV(ASIX, AX88772B, AXE_FLAG_772B),
|
||||
AXE_DEV(ATEN, UC210T, 0),
|
||||
AXE_DEV(BELKIN, F5D5055, AXE_FLAG_178),
|
||||
AXE_DEV(BILLIONTON, USB2AR, 0),
|
||||
@ -190,7 +191,9 @@ static void axe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
|
||||
static int axe_cmd(struct axe_softc *, int, int, int, void *);
|
||||
static void axe_ax88178_init(struct axe_softc *);
|
||||
static void axe_ax88772_init(struct axe_softc *);
|
||||
static void axe_ax88772_phywake(struct axe_softc *);
|
||||
static void axe_ax88772a_init(struct axe_softc *);
|
||||
static void axe_ax88772b_init(struct axe_softc *);
|
||||
static int axe_get_phyno(struct axe_softc *, int);
|
||||
|
||||
static const struct usb_config axe_config[AXE_N_TRANSFER] = {
|
||||
@ -217,6 +220,17 @@ static const struct usb_config axe_config[AXE_N_TRANSFER] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ax88772b_mfb ax88772b_mfb_table[] = {
|
||||
{ 0x8000, 0x8001, 2048 },
|
||||
{ 0x8100, 0x8147, 4096},
|
||||
{ 0x8200, 0x81EB, 6144},
|
||||
{ 0x8300, 0x83D7, 8192},
|
||||
{ 0x8400, 0x851E, 16384},
|
||||
{ 0x8500, 0x8666, 20480},
|
||||
{ 0x8600, 0x87AE, 24576},
|
||||
{ 0x8700, 0x8A3D, 32768}
|
||||
};
|
||||
|
||||
static device_method_t axe_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, axe_probe),
|
||||
@ -669,16 +683,11 @@ axe_ax88772_init(struct axe_softc *sc)
|
||||
}
|
||||
|
||||
static void
|
||||
axe_ax88772a_init(struct axe_softc *sc)
|
||||
axe_ax88772_phywake(struct axe_softc *sc)
|
||||
{
|
||||
struct usb_ether *ue;
|
||||
uint16_t eeprom;
|
||||
|
||||
ue = &sc->sc_ue;
|
||||
axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom);
|
||||
eeprom = le16toh(eeprom);
|
||||
/* Reload EEPROM. */
|
||||
AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32);
|
||||
if (sc->sc_phyno == AXE_772_PHY_NO_EPHY) {
|
||||
/* Manually select internal(embedded) PHY - MAC mode. */
|
||||
axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_SS_ENB |
|
||||
@ -704,6 +713,55 @@ axe_ax88772a_init(struct axe_softc *sc)
|
||||
uether_pause(&sc->sc_ue, hz / 32);
|
||||
axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL);
|
||||
uether_pause(&sc->sc_ue, hz / 32);
|
||||
}
|
||||
|
||||
static void
|
||||
axe_ax88772a_init(struct axe_softc *sc)
|
||||
{
|
||||
struct usb_ether *ue;
|
||||
|
||||
ue = &sc->sc_ue;
|
||||
/* Reload EEPROM. */
|
||||
AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32);
|
||||
axe_ax88772_phywake(sc);
|
||||
/* Stop MAC. */
|
||||
axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
axe_ax88772b_init(struct axe_softc *sc)
|
||||
{
|
||||
struct usb_ether *ue;
|
||||
uint16_t eeprom;
|
||||
uint8_t *eaddr;
|
||||
int i;
|
||||
|
||||
ue = &sc->sc_ue;
|
||||
/* Reload EEPROM. */
|
||||
AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32);
|
||||
/*
|
||||
* Save PHY power saving configuration(high byte) and
|
||||
* clear EEPROM checksum value(low byte).
|
||||
*/
|
||||
axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_PHY_PWRCFG, &eeprom);
|
||||
sc->sc_pwrcfg = le16toh(eeprom) & 0xFF00;
|
||||
|
||||
/*
|
||||
* Auto-loaded default station address from internal ROM is
|
||||
* 00:00:00:00:00:00 such that an explicit access to EEPROM
|
||||
* is required to get real station address.
|
||||
*/
|
||||
eaddr = ue->ue_eaddr;
|
||||
for (i = 0; i < ETHER_ADDR_LEN / 2; i++) {
|
||||
axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_NODE_ID + i,
|
||||
&eeprom);
|
||||
eeprom = le16toh(eeprom);
|
||||
*eaddr++ = (uint8_t)(eeprom & 0xFF);
|
||||
*eaddr++ = (uint8_t)((eeprom >> 8) & 0xFF);
|
||||
}
|
||||
/* Wakeup PHY. */
|
||||
axe_ax88772_phywake(sc);
|
||||
/* Stop MAC. */
|
||||
axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
|
||||
}
|
||||
|
||||
@ -732,6 +790,8 @@ axe_reset(struct axe_softc *sc)
|
||||
axe_ax88772_init(sc);
|
||||
else if (sc->sc_flags & AXE_FLAG_772A)
|
||||
axe_ax88772a_init(sc);
|
||||
else if (sc->sc_flags & AXE_FLAG_772B)
|
||||
axe_ax88772b_init(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -755,29 +815,29 @@ axe_attach_post(struct usb_ether *ue)
|
||||
sc->sc_phyno = 0;
|
||||
}
|
||||
|
||||
/* Initialize controller and get station address. */
|
||||
if (sc->sc_flags & AXE_FLAG_178) {
|
||||
axe_ax88178_init(sc);
|
||||
sc->sc_tx_bufsz = 16 * 1024;
|
||||
axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
|
||||
} else if (sc->sc_flags & AXE_FLAG_772) {
|
||||
axe_ax88772_init(sc);
|
||||
sc->sc_tx_bufsz = 8 * 1024;
|
||||
axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
|
||||
} else if (sc->sc_flags & AXE_FLAG_772A) {
|
||||
axe_ax88772a_init(sc);
|
||||
sc->sc_tx_bufsz = 8 * 1024;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get station address.
|
||||
*/
|
||||
if (AXE_IS_178_FAMILY(sc))
|
||||
axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
|
||||
else
|
||||
} else if (sc->sc_flags & AXE_FLAG_772B) {
|
||||
axe_ax88772b_init(sc);
|
||||
sc->sc_tx_bufsz = 8 * 1024;
|
||||
} else
|
||||
axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
|
||||
|
||||
/*
|
||||
* Fetch IPG values.
|
||||
*/
|
||||
if (sc->sc_flags & AXE_FLAG_772A) {
|
||||
if (sc->sc_flags & (AXE_FLAG_772A | AXE_FLAG_772B)) {
|
||||
/* Set IPG values. */
|
||||
sc->sc_ipgs[0] = 0x15;
|
||||
sc->sc_ipgs[1] = 0x16;
|
||||
@ -1104,18 +1164,30 @@ axe_init(struct usb_ether *ue)
|
||||
axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->sc_ipgs[2], NULL);
|
||||
}
|
||||
|
||||
/* Enable receiver, set RX mode */
|
||||
/* AX88772B uses different maximum frame burst configuration. */
|
||||
if (sc->sc_flags & AXE_FLAG_772B)
|
||||
axe_cmd(sc, AXE_772B_CMD_RXCTL_WRITE_CFG,
|
||||
ax88772b_mfb_table[AX88772B_MFB_16K].threshold,
|
||||
ax88772b_mfb_table[AX88772B_MFB_16K].byte_cnt, NULL);
|
||||
|
||||
/* Enable receiver, set RX mode. */
|
||||
rxmode = (AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE);
|
||||
if (AXE_IS_178_FAMILY(sc)) {
|
||||
#if 0
|
||||
rxmode |= AXE_178_RXCMD_MFB_2048; /* chip default */
|
||||
#else
|
||||
if (sc->sc_flags & AXE_FLAG_772B) {
|
||||
/*
|
||||
* Select RX header format type 1. Aligning IP
|
||||
* header on 4 byte boundary is not needed
|
||||
* because we always copy the received frame in
|
||||
* RX handler.
|
||||
*/
|
||||
rxmode |= AXE_772B_RXCMD_HDR_TYPE_1;
|
||||
} else {
|
||||
/*
|
||||
* Default Rx buffer size is too small to get
|
||||
* maximum performance.
|
||||
*/
|
||||
rxmode |= AXE_178_RXCMD_MFB_16384;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
rxmode |= AXE_172_RXCMD_UNICAST;
|
||||
}
|
||||
|
@ -96,6 +96,8 @@
|
||||
#define AXE_CMD_READ_VLAN_CTRL 0x4027
|
||||
#define AXE_CMD_WRITE_VLAN_CTRL 0x4028
|
||||
|
||||
#define AXE_772B_CMD_RXCTL_WRITE_CFG 0x012A
|
||||
|
||||
#define AXE_SW_RESET_CLEAR 0x00
|
||||
#define AXE_SW_RESET_RR 0x01
|
||||
#define AXE_SW_RESET_RT 0x02
|
||||
@ -132,12 +134,18 @@
|
||||
#define AXE_178_RXCMD_KEEP_INVALID_CRC 0x0004
|
||||
#define AXE_RXCMD_BROADCAST 0x0008
|
||||
#define AXE_RXCMD_MULTICAST 0x0010
|
||||
#define AXE_RXCMD_ACCEPT_RUNT 0x0040 /* AX88772B */
|
||||
#define AXE_RXCMD_ENABLE 0x0080
|
||||
#define AXE_178_RXCMD_MFB_MASK 0x0300
|
||||
#define AXE_178_RXCMD_MFB_2048 0x0000
|
||||
#define AXE_178_RXCMD_MFB_4096 0x0100
|
||||
#define AXE_178_RXCMD_MFB_8192 0x0200
|
||||
#define AXE_178_RXCMD_MFB_16384 0x0300
|
||||
#define AXE_772B_RXCMD_HDR_TYPE_0 0x0000
|
||||
#define AXE_772B_RXCMD_HDR_TYPE_1 0x0100
|
||||
#define AXE_772B_RXCMD_IPHDR_ALIGN 0x0200
|
||||
#define AXE_772B_RXCMD_ADD_CHKSUM 0x0400
|
||||
#define AXE_RXCMD_LOOPBACK 0x1000 /* AX88772A/AX88772B */
|
||||
|
||||
#define AXE_PHY_SEL_PRI 1
|
||||
#define AXE_PHY_SEL_SEC 0
|
||||
@ -176,7 +184,7 @@
|
||||
#define AXE_PHY_MODE_REALTEK_8251CL 0x0E
|
||||
#define AXE_PHY_MODE_ATTANSIC 0x40
|
||||
|
||||
/* AX88772A only. */
|
||||
/* AX88772A/AX88772B only. */
|
||||
#define AXE_SW_PHY_SELECT_EXT 0x0000
|
||||
#define AXE_SW_PHY_SELECT_EMBEDDED 0x0001
|
||||
#define AXE_SW_PHY_SELECT_AUTO 0x0002
|
||||
@ -199,6 +207,24 @@
|
||||
#define AXE_CONFIG_IDX 0 /* config number 1 */
|
||||
#define AXE_IFACE_IDX 0
|
||||
|
||||
/* EEPROM Map. */
|
||||
#define AXE_EEPROM_772B_NODE_ID 0x04
|
||||
#define AXE_EEPROM_772B_PHY_PWRCFG 0x18
|
||||
|
||||
struct ax88772b_mfb {
|
||||
int byte_cnt;
|
||||
int threshold;
|
||||
int size;
|
||||
};
|
||||
#define AX88772B_MFB_2K 0
|
||||
#define AX88772B_MFB_4K 1
|
||||
#define AX88772B_MFB_6K 2
|
||||
#define AX88772B_MFB_8K 3
|
||||
#define AX88772B_MFB_16K 4
|
||||
#define AX88772B_MFB_20K 5
|
||||
#define AX88772B_MFB_24K 6
|
||||
#define AX88772B_MFB_32K 7
|
||||
|
||||
struct axe_sframe_hdr {
|
||||
uint16_t len;
|
||||
uint16_t ilen;
|
||||
@ -228,6 +254,7 @@ struct axe_softc {
|
||||
|
||||
uint8_t sc_ipgs[3];
|
||||
uint8_t sc_phyaddrs[2];
|
||||
uint16_t sc_pwrcfg;
|
||||
int sc_tx_bufsz;
|
||||
};
|
||||
|
||||
|
@ -1045,6 +1045,7 @@ product ASIX AX88172 0x1720 10/100 Ethernet
|
||||
product ASIX AX88178 0x1780 AX88178
|
||||
product ASIX AX88772 0x7720 AX88772
|
||||
product ASIX AX88772A 0x772a AX88772A USB 2.0 10/100 Ethernet
|
||||
product ASIX AX88772B 0x772b AX88772B USB 2.0 10/100 Ethernet
|
||||
|
||||
/* ASUS products */
|
||||
product ASUS2 USBN11 0x0b05 USB-N11
|
||||
|
Loading…
Reference in New Issue
Block a user