summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/net/if_axe.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/net/if_axe.c')
-rw-r--r--sys/dev/usb/net/if_axe.c121
1 files changed, 96 insertions, 25 deletions
diff --git a/sys/dev/usb/net/if_axe.c b/sys/dev/usb/net/if_axe.c
index 5c94e91..a440294 100644
--- a/sys/dev/usb/net/if_axe.c
+++ b/sys/dev/usb/net/if_axe.c
@@ -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),
@@ -225,7 +239,6 @@ static device_method_t axe_methods[] = {
/* bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
- DEVMETHOD(bus_driver_added, bus_generic_driver_added),
/* MII interface */
DEVMETHOD(miibus_readreg, axe_miibus_readreg),
@@ -669,16 +682,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 +712,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 +789,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 +814,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 +1163,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
- /*
- * Default Rx buffer size is too small to get
- * maximum performance.
- */
- rxmode |= AXE_178_RXCMD_MFB_16384;
-#endif
+ 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;
+ }
} else {
rxmode |= AXE_172_RXCMD_UNICAST;
}
OpenPOWER on IntegriCloud