1f85e0762SSepherosa Ziehau /*-
2f85e0762SSepherosa Ziehau * Copyright (c) 2008 Stanislav Sedov <stas@FreeBSD.org>.
3f85e0762SSepherosa Ziehau * All rights reserved.
4f85e0762SSepherosa Ziehau *
5f85e0762SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without
6f85e0762SSepherosa Ziehau * modification, are permitted provided that the following conditions
7f85e0762SSepherosa Ziehau * are met:
8f85e0762SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright
9f85e0762SSepherosa Ziehau * notice, this list of conditions and the following disclaimer.
10f85e0762SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright
11f85e0762SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the
12f85e0762SSepherosa Ziehau * documentation and/or other materials provided with the distribution.
13f85e0762SSepherosa Ziehau *
14f85e0762SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15f85e0762SSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16f85e0762SSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17f85e0762SSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18f85e0762SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19f85e0762SSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20f85e0762SSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21f85e0762SSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22f85e0762SSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23f85e0762SSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24f85e0762SSepherosa Ziehau *
25f85e0762SSepherosa Ziehau * Driver for Attansic Technology Corp. L2 FastEthernet adapter.
26f85e0762SSepherosa Ziehau *
27f85e0762SSepherosa Ziehau * This driver is heavily based on age(4) Attansic L1 driver by Pyun YongHyeon.
28f85e0762SSepherosa Ziehau *
29f85e0762SSepherosa Ziehau * $FreeBSD: src/sys/dev/ae/if_ae.c,v 1.1.2.3.2.1 2009/04/15 03:14:26 kensmith Exp $
30f85e0762SSepherosa Ziehau */
31f85e0762SSepherosa Ziehau
32f85e0762SSepherosa Ziehau #include <sys/param.h>
33f85e0762SSepherosa Ziehau #include <sys/endian.h>
34f85e0762SSepherosa Ziehau #include <sys/kernel.h>
35f85e0762SSepherosa Ziehau #include <sys/bus.h>
36f85e0762SSepherosa Ziehau #include <sys/interrupt.h>
37f85e0762SSepherosa Ziehau #include <sys/malloc.h>
38f85e0762SSepherosa Ziehau #include <sys/proc.h>
39f85e0762SSepherosa Ziehau #include <sys/rman.h>
40f85e0762SSepherosa Ziehau #include <sys/serialize.h>
41f85e0762SSepherosa Ziehau #include <sys/socket.h>
42f85e0762SSepherosa Ziehau #include <sys/sockio.h>
43f85e0762SSepherosa Ziehau #include <sys/sysctl.h>
44f85e0762SSepherosa Ziehau
45f85e0762SSepherosa Ziehau #include <net/ethernet.h>
46f85e0762SSepherosa Ziehau #include <net/if.h>
47f85e0762SSepherosa Ziehau #include <net/bpf.h>
48f85e0762SSepherosa Ziehau #include <net/if_arp.h>
49f85e0762SSepherosa Ziehau #include <net/if_dl.h>
50f85e0762SSepherosa Ziehau #include <net/if_media.h>
51f85e0762SSepherosa Ziehau #include <net/ifq_var.h>
52f85e0762SSepherosa Ziehau #include <net/vlan/if_vlan_var.h>
53f85e0762SSepherosa Ziehau #include <net/vlan/if_vlan_ether.h>
54f85e0762SSepherosa Ziehau
55f85e0762SSepherosa Ziehau #include <bus/pci/pcireg.h>
56f85e0762SSepherosa Ziehau #include <bus/pci/pcivar.h>
57dcb4b80dSSascha Wildner #include "pcidevs.h"
58f85e0762SSepherosa Ziehau
59f85e0762SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h>
60f85e0762SSepherosa Ziehau
61f85e0762SSepherosa Ziehau #include <dev/netif/ae/if_aereg.h>
62f85e0762SSepherosa Ziehau #include <dev/netif/ae/if_aevar.h>
63f85e0762SSepherosa Ziehau
64f85e0762SSepherosa Ziehau /* "device miibus" required. See GENERIC if you get errors here. */
65f85e0762SSepherosa Ziehau #include "miibus_if.h"
66f85e0762SSepherosa Ziehau
67f85e0762SSepherosa Ziehau /*
68f85e0762SSepherosa Ziehau * Devices supported by this driver.
69f85e0762SSepherosa Ziehau */
70f85e0762SSepherosa Ziehau static const struct ae_dev {
71f85e0762SSepherosa Ziehau uint16_t ae_vendorid;
72f85e0762SSepherosa Ziehau uint16_t ae_deviceid;
73f85e0762SSepherosa Ziehau const char *ae_name;
74f85e0762SSepherosa Ziehau } ae_devs[] = {
75f85e0762SSepherosa Ziehau { VENDORID_ATTANSIC, DEVICEID_ATTANSIC_L2,
76f85e0762SSepherosa Ziehau "Attansic Technology Corp, L2 Fast Ethernet" },
77f85e0762SSepherosa Ziehau /* Required last entry */
78f85e0762SSepherosa Ziehau { 0, 0, NULL }
79f85e0762SSepherosa Ziehau };
80f85e0762SSepherosa Ziehau
81f85e0762SSepherosa Ziehau
82f85e0762SSepherosa Ziehau static int ae_probe(device_t);
83f85e0762SSepherosa Ziehau static int ae_attach(device_t);
84f85e0762SSepherosa Ziehau static int ae_detach(device_t);
85f85e0762SSepherosa Ziehau static int ae_shutdown(device_t);
86f85e0762SSepherosa Ziehau static int ae_suspend(device_t);
87f85e0762SSepherosa Ziehau static int ae_resume(device_t);
88f85e0762SSepherosa Ziehau static int ae_miibus_readreg(device_t, int, int);
89f85e0762SSepherosa Ziehau static int ae_miibus_writereg(device_t, int, int, int);
90f85e0762SSepherosa Ziehau static void ae_miibus_statchg(device_t);
91f85e0762SSepherosa Ziehau
92f85e0762SSepherosa Ziehau static int ae_mediachange(struct ifnet *);
93f85e0762SSepherosa Ziehau static void ae_mediastatus(struct ifnet *, struct ifmediareq *);
94f85e0762SSepherosa Ziehau static void ae_init(void *);
95f0a26983SSepherosa Ziehau static void ae_start(struct ifnet *, struct ifaltq_subque *);
96f85e0762SSepherosa Ziehau static int ae_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
97f85e0762SSepherosa Ziehau static void ae_watchdog(struct ifnet *);
98f85e0762SSepherosa Ziehau static void ae_stop(struct ae_softc *);
99f85e0762SSepherosa Ziehau static void ae_tick(void *);
100f85e0762SSepherosa Ziehau
101f85e0762SSepherosa Ziehau static void ae_intr(void *);
102f85e0762SSepherosa Ziehau static void ae_tx_intr(struct ae_softc *);
103f85e0762SSepherosa Ziehau static void ae_rx_intr(struct ae_softc *);
104f85e0762SSepherosa Ziehau static int ae_rxeof(struct ae_softc *, struct ae_rxd *);
105f85e0762SSepherosa Ziehau
106f85e0762SSepherosa Ziehau static int ae_encap(struct ae_softc *, struct mbuf **);
107f85e0762SSepherosa Ziehau static void ae_sysctl_node(struct ae_softc *);
108f85e0762SSepherosa Ziehau static void ae_phy_reset(struct ae_softc *);
109f85e0762SSepherosa Ziehau static int ae_reset(struct ae_softc *);
110f85e0762SSepherosa Ziehau static void ae_pcie_init(struct ae_softc *);
111f85e0762SSepherosa Ziehau static void ae_get_eaddr(struct ae_softc *);
112f85e0762SSepherosa Ziehau static void ae_dma_free(struct ae_softc *);
113f85e0762SSepherosa Ziehau static int ae_dma_alloc(struct ae_softc *);
114f85e0762SSepherosa Ziehau static void ae_mac_config(struct ae_softc *);
115f85e0762SSepherosa Ziehau static void ae_stop_rxmac(struct ae_softc *);
116f85e0762SSepherosa Ziehau static void ae_stop_txmac(struct ae_softc *);
117f85e0762SSepherosa Ziehau static void ae_rxfilter(struct ae_softc *);
118f85e0762SSepherosa Ziehau static void ae_rxvlan(struct ae_softc *);
119f85e0762SSepherosa Ziehau static void ae_update_stats_rx(uint16_t, struct ae_stats *);
120f85e0762SSepherosa Ziehau static void ae_update_stats_tx(uint16_t, struct ae_stats *);
121f85e0762SSepherosa Ziehau static void ae_powersave_disable(struct ae_softc *);
122f85e0762SSepherosa Ziehau static void ae_powersave_enable(struct ae_softc *);
123f85e0762SSepherosa Ziehau
124f85e0762SSepherosa Ziehau static device_method_t ae_methods[] = {
125f85e0762SSepherosa Ziehau /* Device interface. */
126f85e0762SSepherosa Ziehau DEVMETHOD(device_probe, ae_probe),
127f85e0762SSepherosa Ziehau DEVMETHOD(device_attach, ae_attach),
128f85e0762SSepherosa Ziehau DEVMETHOD(device_detach, ae_detach),
129f85e0762SSepherosa Ziehau DEVMETHOD(device_shutdown, ae_shutdown),
130f85e0762SSepherosa Ziehau DEVMETHOD(device_suspend, ae_suspend),
131f85e0762SSepherosa Ziehau DEVMETHOD(device_resume, ae_resume),
132f85e0762SSepherosa Ziehau
133f85e0762SSepherosa Ziehau /* Bus interface. */
134f85e0762SSepherosa Ziehau DEVMETHOD(bus_print_child, bus_generic_print_child),
135f85e0762SSepherosa Ziehau DEVMETHOD(bus_driver_added, bus_generic_driver_added),
136f85e0762SSepherosa Ziehau
137f85e0762SSepherosa Ziehau /* MII interface. */
138f85e0762SSepherosa Ziehau DEVMETHOD(miibus_readreg, ae_miibus_readreg),
139f85e0762SSepherosa Ziehau DEVMETHOD(miibus_writereg, ae_miibus_writereg),
140f85e0762SSepherosa Ziehau DEVMETHOD(miibus_statchg, ae_miibus_statchg),
141f85e0762SSepherosa Ziehau { NULL, NULL }
142f85e0762SSepherosa Ziehau };
143f85e0762SSepherosa Ziehau
144f85e0762SSepherosa Ziehau static driver_t ae_driver = {
145f85e0762SSepherosa Ziehau "ae",
146f85e0762SSepherosa Ziehau ae_methods,
147f85e0762SSepherosa Ziehau sizeof(struct ae_softc)
148f85e0762SSepherosa Ziehau };
149f85e0762SSepherosa Ziehau
150f85e0762SSepherosa Ziehau static devclass_t ae_devclass;
151f85e0762SSepherosa Ziehau DECLARE_DUMMY_MODULE(if_ae);
152f85e0762SSepherosa Ziehau MODULE_DEPEND(if_ae, miibus, 1, 1, 1);
153aa2b9d05SSascha Wildner DRIVER_MODULE(if_ae, pci, ae_driver, ae_devclass, NULL, NULL);
154aa2b9d05SSascha Wildner DRIVER_MODULE(miibus, ae, miibus_driver, miibus_devclass, NULL, NULL);
155f85e0762SSepherosa Ziehau
156f85e0762SSepherosa Ziehau /* Register access macros. */
157f85e0762SSepherosa Ziehau #define AE_WRITE_4(_sc, reg, val) \
158f85e0762SSepherosa Ziehau bus_space_write_4((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg), (val))
159f85e0762SSepherosa Ziehau #define AE_WRITE_2(_sc, reg, val) \
160f85e0762SSepherosa Ziehau bus_space_write_2((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg), (val))
161f85e0762SSepherosa Ziehau #define AE_WRITE_1(_sc, reg, val) \
162f85e0762SSepherosa Ziehau bus_space_write_1((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg), (val))
163f85e0762SSepherosa Ziehau #define AE_READ_4(_sc, reg) \
164f85e0762SSepherosa Ziehau bus_space_read_4((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg))
165f85e0762SSepherosa Ziehau #define AE_READ_2(_sc, reg) \
166f85e0762SSepherosa Ziehau bus_space_read_2((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg))
167f85e0762SSepherosa Ziehau #define AE_READ_1(_sc, reg) \
168f85e0762SSepherosa Ziehau bus_space_read_1((_sc)->ae_mem_bt, (_sc)->ae_mem_bh, (reg))
169f85e0762SSepherosa Ziehau
170f85e0762SSepherosa Ziehau #define AE_PHY_READ(sc, reg) \
171f85e0762SSepherosa Ziehau ae_miibus_readreg(sc->ae_dev, 0, reg)
172f85e0762SSepherosa Ziehau #define AE_PHY_WRITE(sc, reg, val) \
173f85e0762SSepherosa Ziehau ae_miibus_writereg(sc->ae_dev, 0, reg, val)
174f85e0762SSepherosa Ziehau #define AE_CHECK_EADDR_VALID(eaddr) \
175f85e0762SSepherosa Ziehau ((eaddr[0] == 0 && eaddr[1] == 0) || \
176f85e0762SSepherosa Ziehau (eaddr[0] == 0xffffffff && eaddr[1] == 0xffff))
177f85e0762SSepherosa Ziehau #define AE_RXD_VLAN(vtag) \
178f85e0762SSepherosa Ziehau (((vtag) >> 4) | (((vtag) & 0x07) << 13) | (((vtag) & 0x08) << 9))
179f85e0762SSepherosa Ziehau #define AE_TXD_VLAN(vtag) \
180f85e0762SSepherosa Ziehau (((vtag) << 4) | (((vtag) >> 13) & 0x07) | (((vtag) >> 9) & 0x08))
181f85e0762SSepherosa Ziehau
182f85e0762SSepherosa Ziehau /*
183f85e0762SSepherosa Ziehau * ae statistics.
184f85e0762SSepherosa Ziehau */
185f85e0762SSepherosa Ziehau #define STATS_ENTRY(node, desc, field) \
186f85e0762SSepherosa Ziehau { node, desc, offsetof(struct ae_stats, field) }
187f85e0762SSepherosa Ziehau struct {
188f85e0762SSepherosa Ziehau const char *node;
189f85e0762SSepherosa Ziehau const char *desc;
190f85e0762SSepherosa Ziehau intptr_t offset;
191f85e0762SSepherosa Ziehau } ae_stats_tx[] = {
192f85e0762SSepherosa Ziehau STATS_ENTRY("bcast", "broadcast frames", tx_bcast),
193f85e0762SSepherosa Ziehau STATS_ENTRY("mcast", "multicast frames", tx_mcast),
194f85e0762SSepherosa Ziehau STATS_ENTRY("pause", "PAUSE frames", tx_pause),
195f85e0762SSepherosa Ziehau STATS_ENTRY("control", "control frames", tx_ctrl),
196f85e0762SSepherosa Ziehau STATS_ENTRY("defers", "deferrals occuried", tx_defer),
197f85e0762SSepherosa Ziehau STATS_ENTRY("exc_defers", "excessive deferrals occuried", tx_excdefer),
198f85e0762SSepherosa Ziehau STATS_ENTRY("singlecols", "single collisions occuried", tx_singlecol),
199f85e0762SSepherosa Ziehau STATS_ENTRY("multicols", "multiple collisions occuried", tx_multicol),
200f85e0762SSepherosa Ziehau STATS_ENTRY("latecols", "late collisions occuried", tx_latecol),
201f85e0762SSepherosa Ziehau STATS_ENTRY("aborts", "transmit aborts due collisions", tx_abortcol),
202f85e0762SSepherosa Ziehau STATS_ENTRY("underruns", "Tx FIFO underruns", tx_underrun)
203f85e0762SSepherosa Ziehau }, ae_stats_rx[] = {
204f85e0762SSepherosa Ziehau STATS_ENTRY("bcast", "broadcast frames", rx_bcast),
205f85e0762SSepherosa Ziehau STATS_ENTRY("mcast", "multicast frames", rx_mcast),
206f85e0762SSepherosa Ziehau STATS_ENTRY("pause", "PAUSE frames", rx_pause),
207f85e0762SSepherosa Ziehau STATS_ENTRY("control", "control frames", rx_ctrl),
208f85e0762SSepherosa Ziehau STATS_ENTRY("crc_errors", "frames with CRC errors", rx_crcerr),
209f85e0762SSepherosa Ziehau STATS_ENTRY("code_errors", "frames with invalid opcode", rx_codeerr),
210f85e0762SSepherosa Ziehau STATS_ENTRY("runt", "runt frames", rx_runt),
211f85e0762SSepherosa Ziehau STATS_ENTRY("frag", "fragmented frames", rx_frag),
212f85e0762SSepherosa Ziehau STATS_ENTRY("align_errors", "frames with alignment errors", rx_align),
213f85e0762SSepherosa Ziehau STATS_ENTRY("truncated", "frames truncated due to Rx FIFO inderrun",
214f85e0762SSepherosa Ziehau rx_trunc)
215f85e0762SSepherosa Ziehau };
216b370aff7SSascha Wildner #define AE_STATS_RX_LEN NELEM(ae_stats_rx)
217b370aff7SSascha Wildner #define AE_STATS_TX_LEN NELEM(ae_stats_tx)
218f85e0762SSepherosa Ziehau
219f85e0762SSepherosa Ziehau static void
ae_stop(struct ae_softc * sc)220f85e0762SSepherosa Ziehau ae_stop(struct ae_softc *sc)
221f85e0762SSepherosa Ziehau {
222f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
223f85e0762SSepherosa Ziehau int i;
224f85e0762SSepherosa Ziehau
225f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer);
226f85e0762SSepherosa Ziehau
2279ed293e0SSepherosa Ziehau ifp->if_flags &= ~IFF_RUNNING;
2289ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd);
229f85e0762SSepherosa Ziehau ifp->if_timer = 0;
230f85e0762SSepherosa Ziehau
231f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_LINK;
232f85e0762SSepherosa Ziehau callout_stop(&sc->ae_tick_ch);
233f85e0762SSepherosa Ziehau
234f85e0762SSepherosa Ziehau /*
235f85e0762SSepherosa Ziehau * Clear and disable interrupts.
236f85e0762SSepherosa Ziehau */
237f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_IMR_REG, 0);
238f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0xffffffff);
239f85e0762SSepherosa Ziehau
240f85e0762SSepherosa Ziehau /*
241f85e0762SSepherosa Ziehau * Stop Rx/Tx MACs.
242f85e0762SSepherosa Ziehau */
243f85e0762SSepherosa Ziehau ae_stop_txmac(sc);
244f85e0762SSepherosa Ziehau ae_stop_rxmac(sc);
245f85e0762SSepherosa Ziehau
246f85e0762SSepherosa Ziehau /*
247f85e0762SSepherosa Ziehau * Stop DMA engines.
248f85e0762SSepherosa Ziehau */
249f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAREAD_REG, ~AE_DMAREAD_EN);
250f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAWRITE_REG, ~AE_DMAWRITE_EN);
251f85e0762SSepherosa Ziehau
252f85e0762SSepherosa Ziehau /*
253f85e0762SSepherosa Ziehau * Wait for everything to enter idle state.
254f85e0762SSepherosa Ziehau */
255f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i++) {
256f85e0762SSepherosa Ziehau if (AE_READ_4(sc, AE_IDLE_REG) == 0)
257f85e0762SSepherosa Ziehau break;
258f85e0762SSepherosa Ziehau DELAY(100);
259f85e0762SSepherosa Ziehau }
260f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT)
261f85e0762SSepherosa Ziehau if_printf(ifp, "could not enter idle state in stop.\n");
262f85e0762SSepherosa Ziehau }
263f85e0762SSepherosa Ziehau
264f85e0762SSepherosa Ziehau static void
ae_stop_rxmac(struct ae_softc * sc)265f85e0762SSepherosa Ziehau ae_stop_rxmac(struct ae_softc *sc)
266f85e0762SSepherosa Ziehau {
267f85e0762SSepherosa Ziehau uint32_t val;
268f85e0762SSepherosa Ziehau int i;
269f85e0762SSepherosa Ziehau
270f85e0762SSepherosa Ziehau /*
271f85e0762SSepherosa Ziehau * Stop Rx MAC engine.
272f85e0762SSepherosa Ziehau */
273f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG);
274f85e0762SSepherosa Ziehau if ((val & AE_MAC_RX_EN) != 0) {
275f85e0762SSepherosa Ziehau val &= ~AE_MAC_RX_EN;
276f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val);
277f85e0762SSepherosa Ziehau }
278f85e0762SSepherosa Ziehau
279f85e0762SSepherosa Ziehau /*
280f85e0762SSepherosa Ziehau * Stop Rx DMA engine.
281f85e0762SSepherosa Ziehau */
282f85e0762SSepherosa Ziehau if (AE_READ_1(sc, AE_DMAWRITE_REG) == AE_DMAWRITE_EN)
283f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAWRITE_REG, 0);
284f85e0762SSepherosa Ziehau
285f85e0762SSepherosa Ziehau /*
286f85e0762SSepherosa Ziehau * Wait for IDLE state.
287f85e0762SSepherosa Ziehau */
288f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i--) {
289f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_IDLE_REG);
290f85e0762SSepherosa Ziehau if ((val & (AE_IDLE_RXMAC | AE_IDLE_DMAWRITE)) == 0)
291f85e0762SSepherosa Ziehau break;
292f85e0762SSepherosa Ziehau DELAY(100);
293f85e0762SSepherosa Ziehau }
294f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT) {
295f85e0762SSepherosa Ziehau if_printf(&sc->arpcom.ac_if,
296f85e0762SSepherosa Ziehau "timed out while stopping Rx MAC.\n");
297f85e0762SSepherosa Ziehau }
298f85e0762SSepherosa Ziehau }
299f85e0762SSepherosa Ziehau
300f85e0762SSepherosa Ziehau static void
ae_stop_txmac(struct ae_softc * sc)301f85e0762SSepherosa Ziehau ae_stop_txmac(struct ae_softc *sc)
302f85e0762SSepherosa Ziehau {
303f85e0762SSepherosa Ziehau uint32_t val;
304f85e0762SSepherosa Ziehau int i;
305f85e0762SSepherosa Ziehau
306f85e0762SSepherosa Ziehau /*
307f85e0762SSepherosa Ziehau * Stop Tx MAC engine.
308f85e0762SSepherosa Ziehau */
309f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG);
310f85e0762SSepherosa Ziehau if ((val & AE_MAC_TX_EN) != 0) {
311f85e0762SSepherosa Ziehau val &= ~AE_MAC_TX_EN;
312f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val);
313f85e0762SSepherosa Ziehau }
314f85e0762SSepherosa Ziehau
315f85e0762SSepherosa Ziehau /*
316f85e0762SSepherosa Ziehau * Stop Tx DMA engine.
317f85e0762SSepherosa Ziehau */
318f85e0762SSepherosa Ziehau if (AE_READ_1(sc, AE_DMAREAD_REG) == AE_DMAREAD_EN)
319f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAREAD_REG, 0);
320f85e0762SSepherosa Ziehau
321f85e0762SSepherosa Ziehau /*
322f85e0762SSepherosa Ziehau * Wait for IDLE state.
323f85e0762SSepherosa Ziehau */
324f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i--) {
325f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_IDLE_REG);
326f85e0762SSepherosa Ziehau if ((val & (AE_IDLE_TXMAC | AE_IDLE_DMAREAD)) == 0)
327f85e0762SSepherosa Ziehau break;
328f85e0762SSepherosa Ziehau DELAY(100);
329f85e0762SSepherosa Ziehau }
330f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT) {
331f85e0762SSepherosa Ziehau if_printf(&sc->arpcom.ac_if,
332f85e0762SSepherosa Ziehau "timed out while stopping Tx MAC.\n");
333f85e0762SSepherosa Ziehau }
334f85e0762SSepherosa Ziehau }
335f85e0762SSepherosa Ziehau
336f85e0762SSepherosa Ziehau /*
337f85e0762SSepherosa Ziehau * Callback from MII layer when media changes.
338f85e0762SSepherosa Ziehau */
339f85e0762SSepherosa Ziehau static void
ae_miibus_statchg(device_t dev)340f85e0762SSepherosa Ziehau ae_miibus_statchg(device_t dev)
341f85e0762SSepherosa Ziehau {
342f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev);
343f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
344f85e0762SSepherosa Ziehau struct mii_data *mii;
345f85e0762SSepherosa Ziehau uint32_t val;
346f85e0762SSepherosa Ziehau
347f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer);
348f85e0762SSepherosa Ziehau
349f85e0762SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0)
350f85e0762SSepherosa Ziehau return;
351f85e0762SSepherosa Ziehau
352f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus);
353f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_LINK;
354f85e0762SSepherosa Ziehau if ((mii->mii_media_status & IFM_AVALID) != 0) {
355f85e0762SSepherosa Ziehau switch (IFM_SUBTYPE(mii->mii_media_active)) {
356f85e0762SSepherosa Ziehau case IFM_10_T:
357f85e0762SSepherosa Ziehau case IFM_100_TX:
358f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_LINK;
359f85e0762SSepherosa Ziehau break;
360f85e0762SSepherosa Ziehau default:
361f85e0762SSepherosa Ziehau break;
362f85e0762SSepherosa Ziehau }
363f85e0762SSepherosa Ziehau }
364f85e0762SSepherosa Ziehau
365f85e0762SSepherosa Ziehau /* Stop Rx/Tx MACs. */
366f85e0762SSepherosa Ziehau ae_stop_rxmac(sc);
367f85e0762SSepherosa Ziehau ae_stop_txmac(sc);
368f85e0762SSepherosa Ziehau
369f85e0762SSepherosa Ziehau /* Program MACs with resolved speed/duplex/flow-control. */
370f85e0762SSepherosa Ziehau if ((sc->ae_flags & AE_FLAG_LINK) != 0) {
371f85e0762SSepherosa Ziehau ae_mac_config(sc);
372f85e0762SSepherosa Ziehau
373f85e0762SSepherosa Ziehau /*
374f85e0762SSepherosa Ziehau * Restart DMA engines.
375f85e0762SSepherosa Ziehau */
376f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAREAD_REG, AE_DMAREAD_EN);
377f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAWRITE_REG, AE_DMAWRITE_EN);
378f85e0762SSepherosa Ziehau
379f85e0762SSepherosa Ziehau /*
380f85e0762SSepherosa Ziehau * Enable Rx and Tx MACs.
381f85e0762SSepherosa Ziehau */
382f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG);
383f85e0762SSepherosa Ziehau val |= AE_MAC_TX_EN | AE_MAC_RX_EN;
384f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val);
385f85e0762SSepherosa Ziehau }
386f85e0762SSepherosa Ziehau }
387f85e0762SSepherosa Ziehau
388f85e0762SSepherosa Ziehau static void
ae_sysctl_node(struct ae_softc * sc)389f85e0762SSepherosa Ziehau ae_sysctl_node(struct ae_softc *sc)
390f85e0762SSepherosa Ziehau {
391f85e0762SSepherosa Ziehau struct sysctl_ctx_list *ctx;
392f85e0762SSepherosa Ziehau struct sysctl_oid *root, *stats, *stats_rx, *stats_tx;
393f85e0762SSepherosa Ziehau struct ae_stats *ae_stats;
394f85e0762SSepherosa Ziehau unsigned int i;
395f85e0762SSepherosa Ziehau
396f85e0762SSepherosa Ziehau ae_stats = &sc->stats;
397f85e0762SSepherosa Ziehau
39826595b18SSascha Wildner ctx = device_get_sysctl_ctx(sc->ae_dev);
39926595b18SSascha Wildner root = device_get_sysctl_tree(sc->ae_dev);
400f85e0762SSepherosa Ziehau stats = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(root), OID_AUTO, "stats",
401f85e0762SSepherosa Ziehau CTLFLAG_RD, NULL, "ae statistics");
402f85e0762SSepherosa Ziehau if (stats == NULL) {
403f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "can't add stats sysctl node\n");
404f85e0762SSepherosa Ziehau return;
405f85e0762SSepherosa Ziehau }
406f85e0762SSepherosa Ziehau
407f85e0762SSepherosa Ziehau /*
408f85e0762SSepherosa Ziehau * Receiver statistcics.
409f85e0762SSepherosa Ziehau */
410f85e0762SSepherosa Ziehau stats_rx = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, "rx",
411f85e0762SSepherosa Ziehau CTLFLAG_RD, NULL, "Rx MAC statistics");
412f85e0762SSepherosa Ziehau if (stats_rx != NULL) {
413f85e0762SSepherosa Ziehau for (i = 0; i < AE_STATS_RX_LEN; i++) {
414f85e0762SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(stats_rx),
415f85e0762SSepherosa Ziehau OID_AUTO, ae_stats_rx[i].node, CTLFLAG_RD,
416f85e0762SSepherosa Ziehau (char *)ae_stats + ae_stats_rx[i].offset, 0,
417f85e0762SSepherosa Ziehau ae_stats_rx[i].desc);
418f85e0762SSepherosa Ziehau }
419f85e0762SSepherosa Ziehau }
420f85e0762SSepherosa Ziehau
421f85e0762SSepherosa Ziehau /*
422f85e0762SSepherosa Ziehau * Transmitter statistcics.
423f85e0762SSepherosa Ziehau */
424f85e0762SSepherosa Ziehau stats_tx = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(stats), OID_AUTO, "tx",
425f85e0762SSepherosa Ziehau CTLFLAG_RD, NULL, "Tx MAC statistics");
426f85e0762SSepherosa Ziehau if (stats_tx != NULL) {
427f85e0762SSepherosa Ziehau for (i = 0; i < AE_STATS_TX_LEN; i++) {
428f85e0762SSepherosa Ziehau SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(stats_tx),
429f85e0762SSepherosa Ziehau OID_AUTO, ae_stats_tx[i].node, CTLFLAG_RD,
430f85e0762SSepherosa Ziehau (char *)ae_stats + ae_stats_tx[i].offset, 0,
431f85e0762SSepherosa Ziehau ae_stats_tx[i].desc);
432f85e0762SSepherosa Ziehau }
433f85e0762SSepherosa Ziehau }
434f85e0762SSepherosa Ziehau }
435f85e0762SSepherosa Ziehau
436f85e0762SSepherosa Ziehau static int
ae_miibus_readreg(device_t dev,int phy,int reg)437f85e0762SSepherosa Ziehau ae_miibus_readreg(device_t dev, int phy, int reg)
438f85e0762SSepherosa Ziehau {
439f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev);
440f85e0762SSepherosa Ziehau uint32_t val;
441f85e0762SSepherosa Ziehau int i;
442f85e0762SSepherosa Ziehau
443f85e0762SSepherosa Ziehau /*
444f85e0762SSepherosa Ziehau * Locking is done in upper layers.
445f85e0762SSepherosa Ziehau */
446f85e0762SSepherosa Ziehau if (phy != sc->ae_phyaddr)
447f85e0762SSepherosa Ziehau return (0);
448f85e0762SSepherosa Ziehau val = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) |
449f85e0762SSepherosa Ziehau AE_MDIO_START | AE_MDIO_READ | AE_MDIO_SUP_PREAMBLE |
450f85e0762SSepherosa Ziehau ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK);
451f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MDIO_REG, val);
452f85e0762SSepherosa Ziehau
453f85e0762SSepherosa Ziehau /*
454f85e0762SSepherosa Ziehau * Wait for operation to complete.
455f85e0762SSepherosa Ziehau */
456f85e0762SSepherosa Ziehau for (i = 0; i < AE_MDIO_TIMEOUT; i++) {
457f85e0762SSepherosa Ziehau DELAY(2);
458f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MDIO_REG);
459f85e0762SSepherosa Ziehau if ((val & (AE_MDIO_START | AE_MDIO_BUSY)) == 0)
460f85e0762SSepherosa Ziehau break;
461f85e0762SSepherosa Ziehau }
462f85e0762SSepherosa Ziehau if (i == AE_MDIO_TIMEOUT) {
463f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "phy read timeout: %d.\n", reg);
464f85e0762SSepherosa Ziehau return (0);
465f85e0762SSepherosa Ziehau }
466f85e0762SSepherosa Ziehau return ((val << AE_MDIO_DATA_SHIFT) & AE_MDIO_DATA_MASK);
467f85e0762SSepherosa Ziehau }
468f85e0762SSepherosa Ziehau
469f85e0762SSepherosa Ziehau static int
ae_miibus_writereg(device_t dev,int phy,int reg,int val)470f85e0762SSepherosa Ziehau ae_miibus_writereg(device_t dev, int phy, int reg, int val)
471f85e0762SSepherosa Ziehau {
472f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev);
473f85e0762SSepherosa Ziehau uint32_t aereg;
474f85e0762SSepherosa Ziehau int i;
475f85e0762SSepherosa Ziehau
476f85e0762SSepherosa Ziehau /*
477f85e0762SSepherosa Ziehau * Locking is done in upper layers.
478f85e0762SSepherosa Ziehau */
479f85e0762SSepherosa Ziehau if (phy != sc->ae_phyaddr)
480f85e0762SSepherosa Ziehau return (0);
481f85e0762SSepherosa Ziehau aereg = ((reg << AE_MDIO_REGADDR_SHIFT) & AE_MDIO_REGADDR_MASK) |
482f85e0762SSepherosa Ziehau AE_MDIO_START | AE_MDIO_SUP_PREAMBLE |
483f85e0762SSepherosa Ziehau ((AE_MDIO_CLK_25_4 << AE_MDIO_CLK_SHIFT) & AE_MDIO_CLK_MASK) |
484f85e0762SSepherosa Ziehau ((val << AE_MDIO_DATA_SHIFT) & AE_MDIO_DATA_MASK);
485f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MDIO_REG, aereg);
486f85e0762SSepherosa Ziehau
487f85e0762SSepherosa Ziehau /*
488f85e0762SSepherosa Ziehau * Wait for operation to complete.
489f85e0762SSepherosa Ziehau */
490f85e0762SSepherosa Ziehau for (i = 0; i < AE_MDIO_TIMEOUT; i++) {
491f85e0762SSepherosa Ziehau DELAY(2);
492f85e0762SSepherosa Ziehau aereg = AE_READ_4(sc, AE_MDIO_REG);
493f85e0762SSepherosa Ziehau if ((aereg & (AE_MDIO_START | AE_MDIO_BUSY)) == 0)
494f85e0762SSepherosa Ziehau break;
495f85e0762SSepherosa Ziehau }
496f85e0762SSepherosa Ziehau if (i == AE_MDIO_TIMEOUT)
497f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "phy write timeout: %d.\n", reg);
498f85e0762SSepherosa Ziehau return (0);
499f85e0762SSepherosa Ziehau }
500f85e0762SSepherosa Ziehau
501f85e0762SSepherosa Ziehau static int
ae_probe(device_t dev)502f85e0762SSepherosa Ziehau ae_probe(device_t dev)
503f85e0762SSepherosa Ziehau {
504f85e0762SSepherosa Ziehau uint16_t vendor, devid;
505f85e0762SSepherosa Ziehau const struct ae_dev *sp;
506f85e0762SSepherosa Ziehau
507f85e0762SSepherosa Ziehau vendor = pci_get_vendor(dev);
508f85e0762SSepherosa Ziehau devid = pci_get_device(dev);
509f85e0762SSepherosa Ziehau for (sp = ae_devs; sp->ae_name != NULL; sp++) {
510f85e0762SSepherosa Ziehau if (vendor == sp->ae_vendorid &&
511f85e0762SSepherosa Ziehau devid == sp->ae_deviceid) {
512f85e0762SSepherosa Ziehau device_set_desc(dev, sp->ae_name);
513f85e0762SSepherosa Ziehau return (0);
514f85e0762SSepherosa Ziehau }
515f85e0762SSepherosa Ziehau }
516f85e0762SSepherosa Ziehau return (ENXIO);
517f85e0762SSepherosa Ziehau }
518f85e0762SSepherosa Ziehau
519f85e0762SSepherosa Ziehau static int
ae_dma_alloc(struct ae_softc * sc)520f85e0762SSepherosa Ziehau ae_dma_alloc(struct ae_softc *sc)
521f85e0762SSepherosa Ziehau {
522f85e0762SSepherosa Ziehau bus_addr_t busaddr;
523f85e0762SSepherosa Ziehau int error;
524f85e0762SSepherosa Ziehau
525f85e0762SSepherosa Ziehau /*
526f85e0762SSepherosa Ziehau * Create parent DMA tag.
527f85e0762SSepherosa Ziehau */
528f85e0762SSepherosa Ziehau error = bus_dma_tag_create(NULL, 1, 0,
529f85e0762SSepherosa Ziehau BUS_SPACE_MAXADDR_32BIT,
530f85e0762SSepherosa Ziehau BUS_SPACE_MAXADDR,
531f85e0762SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,
532f85e0762SSepherosa Ziehau 0,
533f85e0762SSepherosa Ziehau BUS_SPACE_MAXSIZE_32BIT,
534f85e0762SSepherosa Ziehau 0, &sc->dma_parent_tag);
535f85e0762SSepherosa Ziehau if (error) {
536f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare parent DMA tag.\n");
537f85e0762SSepherosa Ziehau return (error);
538f85e0762SSepherosa Ziehau }
539f85e0762SSepherosa Ziehau
540f85e0762SSepherosa Ziehau /*
541f85e0762SSepherosa Ziehau * Create DMA stuffs for TxD.
542f85e0762SSepherosa Ziehau */
543f85e0762SSepherosa Ziehau sc->txd_base = bus_dmamem_coherent_any(sc->dma_parent_tag, 4,
544f85e0762SSepherosa Ziehau AE_TXD_BUFSIZE_DEFAULT, BUS_DMA_WAITOK | BUS_DMA_ZERO,
545f85e0762SSepherosa Ziehau &sc->dma_txd_tag, &sc->dma_txd_map,
546f85e0762SSepherosa Ziehau &sc->dma_txd_busaddr);
547f85e0762SSepherosa Ziehau if (sc->txd_base == NULL) {
548f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare TxD DMA stuffs.\n");
549f85e0762SSepherosa Ziehau return ENOMEM;
550f85e0762SSepherosa Ziehau }
551f85e0762SSepherosa Ziehau
552f85e0762SSepherosa Ziehau /*
553f85e0762SSepherosa Ziehau * Create DMA stuffs for TxS.
554f85e0762SSepherosa Ziehau */
555f85e0762SSepherosa Ziehau sc->txs_base = bus_dmamem_coherent_any(sc->dma_parent_tag, 4,
556f85e0762SSepherosa Ziehau AE_TXS_COUNT_DEFAULT * 4, BUS_DMA_WAITOK | BUS_DMA_ZERO,
557f85e0762SSepherosa Ziehau &sc->dma_txs_tag, &sc->dma_txs_map,
558f85e0762SSepherosa Ziehau &sc->dma_txs_busaddr);
559f85e0762SSepherosa Ziehau if (sc->txs_base == NULL) {
560f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare TxS DMA stuffs.\n");
561f85e0762SSepherosa Ziehau return ENOMEM;
562f85e0762SSepherosa Ziehau }
563f85e0762SSepherosa Ziehau
564f85e0762SSepherosa Ziehau /*
565f85e0762SSepherosa Ziehau * Create DMA stuffs for RxD.
566f85e0762SSepherosa Ziehau */
567f85e0762SSepherosa Ziehau sc->rxd_base_dma = bus_dmamem_coherent_any(sc->dma_parent_tag, 128,
568f85e0762SSepherosa Ziehau AE_RXD_COUNT_DEFAULT * 1536 + 120,
569f85e0762SSepherosa Ziehau BUS_DMA_WAITOK | BUS_DMA_ZERO,
570f85e0762SSepherosa Ziehau &sc->dma_rxd_tag, &sc->dma_rxd_map,
571f85e0762SSepherosa Ziehau &busaddr);
572f85e0762SSepherosa Ziehau if (sc->rxd_base_dma == NULL) {
573f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not creare RxD DMA stuffs.\n");
574f85e0762SSepherosa Ziehau return ENOMEM;
575f85e0762SSepherosa Ziehau }
576f85e0762SSepherosa Ziehau sc->dma_rxd_busaddr = busaddr + 120;
577f85e0762SSepherosa Ziehau sc->rxd_base = (struct ae_rxd *)(sc->rxd_base_dma + 120);
578f85e0762SSepherosa Ziehau
579f85e0762SSepherosa Ziehau return (0);
580f85e0762SSepherosa Ziehau }
581f85e0762SSepherosa Ziehau
582f85e0762SSepherosa Ziehau static void
ae_mac_config(struct ae_softc * sc)583f85e0762SSepherosa Ziehau ae_mac_config(struct ae_softc *sc)
584f85e0762SSepherosa Ziehau {
585f85e0762SSepherosa Ziehau struct mii_data *mii;
586f85e0762SSepherosa Ziehau uint32_t val;
587f85e0762SSepherosa Ziehau
588f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus);
589f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG);
590f85e0762SSepherosa Ziehau val &= ~AE_MAC_FULL_DUPLEX;
591f85e0762SSepherosa Ziehau /* XXX disable AE_MAC_TX_FLOW_EN? */
592f85e0762SSepherosa Ziehau if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
593f85e0762SSepherosa Ziehau val |= AE_MAC_FULL_DUPLEX;
594f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val);
595f85e0762SSepherosa Ziehau }
596f85e0762SSepherosa Ziehau
597f85e0762SSepherosa Ziehau static int
ae_rxeof(struct ae_softc * sc,struct ae_rxd * rxd)598f85e0762SSepherosa Ziehau ae_rxeof(struct ae_softc *sc, struct ae_rxd *rxd)
599f85e0762SSepherosa Ziehau {
600f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
601f85e0762SSepherosa Ziehau struct mbuf *m;
602f85e0762SSepherosa Ziehau unsigned int size;
603f85e0762SSepherosa Ziehau uint16_t flags;
604f85e0762SSepherosa Ziehau
605f85e0762SSepherosa Ziehau flags = le16toh(rxd->flags);
606f85e0762SSepherosa Ziehau #ifdef AE_DEBUG
607f85e0762SSepherosa Ziehau if_printf(ifp, "Rx interrupt occuried.\n");
608f85e0762SSepherosa Ziehau #endif
609f85e0762SSepherosa Ziehau size = le16toh(rxd->len) - ETHER_CRC_LEN;
610f85e0762SSepherosa Ziehau if (size < (ETHER_MIN_LEN - ETHER_CRC_LEN -
611f85e0762SSepherosa Ziehau sizeof(struct ether_vlan_header))) {
612f85e0762SSepherosa Ziehau if_printf(ifp, "Runt frame received.");
613f85e0762SSepherosa Ziehau return (EIO);
614f85e0762SSepherosa Ziehau }
615f85e0762SSepherosa Ziehau
616*4e4d812dSAaron LI m = m_devget(&rxd->data[0], size, 0, ifp);
617f85e0762SSepherosa Ziehau if (m == NULL)
618f85e0762SSepherosa Ziehau return (ENOBUFS);
619f85e0762SSepherosa Ziehau
620f85e0762SSepherosa Ziehau if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) &&
621f85e0762SSepherosa Ziehau (flags & AE_RXD_HAS_VLAN)) {
622f85e0762SSepherosa Ziehau m->m_pkthdr.ether_vlantag = AE_RXD_VLAN(le16toh(rxd->vlan));
623f85e0762SSepherosa Ziehau m->m_flags |= M_VLANTAG;
624f85e0762SSepherosa Ziehau }
62573029d08SFranco Fichtner ifp->if_input(ifp, m, NULL, -1);
626f85e0762SSepherosa Ziehau
627f85e0762SSepherosa Ziehau return (0);
628f85e0762SSepherosa Ziehau }
629f85e0762SSepherosa Ziehau
630f85e0762SSepherosa Ziehau static void
ae_rx_intr(struct ae_softc * sc)631f85e0762SSepherosa Ziehau ae_rx_intr(struct ae_softc *sc)
632f85e0762SSepherosa Ziehau {
633f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
634f85e0762SSepherosa Ziehau struct ae_rxd *rxd;
635f85e0762SSepherosa Ziehau uint16_t flags;
636f85e0762SSepherosa Ziehau int error;
637f85e0762SSepherosa Ziehau
638f85e0762SSepherosa Ziehau /*
639f85e0762SSepherosa Ziehau * Syncronize DMA buffers.
640f85e0762SSepherosa Ziehau */
641f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_rxd_tag, sc->dma_rxd_map,
642f85e0762SSepherosa Ziehau BUS_DMASYNC_POSTREAD);
643f85e0762SSepherosa Ziehau for (;;) {
644f85e0762SSepherosa Ziehau rxd = (struct ae_rxd *)(sc->rxd_base + sc->rxd_cur);
645f85e0762SSepherosa Ziehau
646f85e0762SSepherosa Ziehau flags = le16toh(rxd->flags);
647f85e0762SSepherosa Ziehau if ((flags & AE_RXD_UPDATE) == 0)
648f85e0762SSepherosa Ziehau break;
649f85e0762SSepherosa Ziehau rxd->flags = htole16(flags & ~AE_RXD_UPDATE);
650f85e0762SSepherosa Ziehau
651f85e0762SSepherosa Ziehau /* Update stats. */
652f85e0762SSepherosa Ziehau ae_update_stats_rx(flags, &sc->stats);
653f85e0762SSepherosa Ziehau
654f85e0762SSepherosa Ziehau /*
655f85e0762SSepherosa Ziehau * Update position index.
656f85e0762SSepherosa Ziehau */
657f85e0762SSepherosa Ziehau sc->rxd_cur = (sc->rxd_cur + 1) % AE_RXD_COUNT_DEFAULT;
658f85e0762SSepherosa Ziehau if ((flags & AE_RXD_SUCCESS) == 0) {
659d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1);
660f85e0762SSepherosa Ziehau continue;
661f85e0762SSepherosa Ziehau }
662f85e0762SSepherosa Ziehau
663f85e0762SSepherosa Ziehau error = ae_rxeof(sc, rxd);
664f85e0762SSepherosa Ziehau if (error)
665d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ierrors, 1);
666f85e0762SSepherosa Ziehau else
667d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, ipackets, 1);
668f85e0762SSepherosa Ziehau }
669f85e0762SSepherosa Ziehau
670f85e0762SSepherosa Ziehau /* Update Rx index. */
671f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MB_RXD_IDX_REG, sc->rxd_cur);
672f85e0762SSepherosa Ziehau }
673f85e0762SSepherosa Ziehau
674f85e0762SSepherosa Ziehau static void
ae_tx_intr(struct ae_softc * sc)675f85e0762SSepherosa Ziehau ae_tx_intr(struct ae_softc *sc)
676f85e0762SSepherosa Ziehau {
677f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
678f85e0762SSepherosa Ziehau struct ae_txd *txd;
679f85e0762SSepherosa Ziehau struct ae_txs *txs;
680f85e0762SSepherosa Ziehau uint16_t flags;
681f85e0762SSepherosa Ziehau
682f85e0762SSepherosa Ziehau /*
683f85e0762SSepherosa Ziehau * Syncronize DMA buffers.
684f85e0762SSepherosa Ziehau */
685f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txd_tag, sc->dma_txd_map, BUS_DMASYNC_POSTREAD);
686f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txs_tag, sc->dma_txs_map, BUS_DMASYNC_POSTREAD);
687f85e0762SSepherosa Ziehau
688f85e0762SSepherosa Ziehau for (;;) {
689f85e0762SSepherosa Ziehau txs = sc->txs_base + sc->txs_ack;
690f85e0762SSepherosa Ziehau
691f85e0762SSepherosa Ziehau flags = le16toh(txs->flags);
692f85e0762SSepherosa Ziehau if ((flags & AE_TXS_UPDATE) == 0)
693f85e0762SSepherosa Ziehau break;
694f85e0762SSepherosa Ziehau txs->flags = htole16(flags & ~AE_TXS_UPDATE);
695f85e0762SSepherosa Ziehau
696f85e0762SSepherosa Ziehau /* Update stats. */
697f85e0762SSepherosa Ziehau ae_update_stats_tx(flags, &sc->stats);
698f85e0762SSepherosa Ziehau
699f85e0762SSepherosa Ziehau /*
700f85e0762SSepherosa Ziehau * Update TxS position.
701f85e0762SSepherosa Ziehau */
702f85e0762SSepherosa Ziehau sc->txs_ack = (sc->txs_ack + 1) % AE_TXS_COUNT_DEFAULT;
703f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_TXAVAIL;
704f85e0762SSepherosa Ziehau txd = (struct ae_txd *)(sc->txd_base + sc->txd_ack);
705f85e0762SSepherosa Ziehau if (txs->len != txd->len) {
706f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "Size mismatch: "
707f85e0762SSepherosa Ziehau "TxS:%d TxD:%d\n",
708f85e0762SSepherosa Ziehau le16toh(txs->len), le16toh(txd->len));
709f85e0762SSepherosa Ziehau }
710f85e0762SSepherosa Ziehau
711f85e0762SSepherosa Ziehau /*
712f85e0762SSepherosa Ziehau * Move txd ack and align on 4-byte boundary.
713f85e0762SSepherosa Ziehau */
714f85e0762SSepherosa Ziehau sc->txd_ack = ((sc->txd_ack + le16toh(txd->len) + 4 + 3) & ~3) %
715f85e0762SSepherosa Ziehau AE_TXD_BUFSIZE_DEFAULT;
716f85e0762SSepherosa Ziehau if ((flags & AE_TXS_SUCCESS) != 0)
717d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1);
718f85e0762SSepherosa Ziehau else
719d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1);
720f85e0762SSepherosa Ziehau sc->tx_inproc--;
721f85e0762SSepherosa Ziehau }
722f85e0762SSepherosa Ziehau
723f85e0762SSepherosa Ziehau if (sc->tx_inproc < 0) {
724f85e0762SSepherosa Ziehau /* XXX assert? */
725f85e0762SSepherosa Ziehau if_printf(ifp, "Received stray Tx interrupt(s).\n");
726f85e0762SSepherosa Ziehau sc->tx_inproc = 0;
727f85e0762SSepherosa Ziehau }
728f85e0762SSepherosa Ziehau if (sc->tx_inproc == 0)
729f85e0762SSepherosa Ziehau ifp->if_timer = 0; /* Unarm watchdog. */
730f85e0762SSepherosa Ziehau if (sc->ae_flags & AE_FLAG_TXAVAIL) {
7319ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd);
732f85e0762SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd))
733f85e0762SSepherosa Ziehau #ifdef foo
734f85e0762SSepherosa Ziehau ae_intr(sc);
735f85e0762SSepherosa Ziehau #else
736f85e0762SSepherosa Ziehau if_devstart(ifp);
737f85e0762SSepherosa Ziehau #endif
738f85e0762SSepherosa Ziehau }
739f85e0762SSepherosa Ziehau
740f85e0762SSepherosa Ziehau /*
741f85e0762SSepherosa Ziehau * Syncronize DMA buffers.
742f85e0762SSepherosa Ziehau */
743f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txd_tag, sc->dma_txd_map, BUS_DMASYNC_PREWRITE);
744f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txs_tag, sc->dma_txs_map, BUS_DMASYNC_PREWRITE);
745f85e0762SSepherosa Ziehau }
746f85e0762SSepherosa Ziehau
747f85e0762SSepherosa Ziehau static void
ae_intr(void * xsc)748f85e0762SSepherosa Ziehau ae_intr(void *xsc)
749f85e0762SSepherosa Ziehau {
750f85e0762SSepherosa Ziehau struct ae_softc *sc = xsc;
751f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
752f85e0762SSepherosa Ziehau uint32_t val;
753f85e0762SSepherosa Ziehau
754f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer);
755f85e0762SSepherosa Ziehau
756f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_ISR_REG);
757f85e0762SSepherosa Ziehau if (val == 0 || (val & AE_IMR_DEFAULT) == 0)
758f85e0762SSepherosa Ziehau return;
759f85e0762SSepherosa Ziehau
760f85e0762SSepherosa Ziehau #ifdef foo
761f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, AE_ISR_DISABLE);
762f85e0762SSepherosa Ziehau #endif
763f85e0762SSepherosa Ziehau
764f85e0762SSepherosa Ziehau /* Read interrupt status. */
765f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_ISR_REG);
766f85e0762SSepherosa Ziehau
767f85e0762SSepherosa Ziehau /* Clear interrupts and disable them. */
768f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, val | AE_ISR_DISABLE);
769f85e0762SSepherosa Ziehau
770f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) {
771f85e0762SSepherosa Ziehau if (val & (AE_ISR_DMAR_TIMEOUT |
772f85e0762SSepherosa Ziehau AE_ISR_DMAW_TIMEOUT |
773f85e0762SSepherosa Ziehau AE_ISR_PHY_LINKDOWN)) {
774f85e0762SSepherosa Ziehau ae_init(sc);
775f85e0762SSepherosa Ziehau }
776f85e0762SSepherosa Ziehau if (val & AE_ISR_TX_EVENT)
777f85e0762SSepherosa Ziehau ae_tx_intr(sc);
778f85e0762SSepherosa Ziehau if (val & AE_ISR_RX_EVENT)
779f85e0762SSepherosa Ziehau ae_rx_intr(sc);
780f85e0762SSepherosa Ziehau }
781f85e0762SSepherosa Ziehau
782f85e0762SSepherosa Ziehau /* Re-enable interrupts. */
783f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0);
784f85e0762SSepherosa Ziehau }
785f85e0762SSepherosa Ziehau
786f85e0762SSepherosa Ziehau static void
ae_init(void * xsc)787f85e0762SSepherosa Ziehau ae_init(void *xsc)
788f85e0762SSepherosa Ziehau {
789f85e0762SSepherosa Ziehau struct ae_softc *sc = xsc;
790f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
791f85e0762SSepherosa Ziehau struct mii_data *mii;
792f85e0762SSepherosa Ziehau uint8_t eaddr[ETHER_ADDR_LEN];
793f85e0762SSepherosa Ziehau uint32_t val;
794f85e0762SSepherosa Ziehau bus_addr_t addr;
795f85e0762SSepherosa Ziehau
796f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer);
797f85e0762SSepherosa Ziehau
798f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus);
799f85e0762SSepherosa Ziehau ae_stop(sc);
800f85e0762SSepherosa Ziehau ae_reset(sc);
801f85e0762SSepherosa Ziehau ae_pcie_init(sc);
802f85e0762SSepherosa Ziehau ae_powersave_disable(sc);
803f85e0762SSepherosa Ziehau
804f85e0762SSepherosa Ziehau /*
805f85e0762SSepherosa Ziehau * Clear and disable interrupts.
806f85e0762SSepherosa Ziehau */
807f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0xffffffff);
808f85e0762SSepherosa Ziehau
809f85e0762SSepherosa Ziehau /*
810f85e0762SSepherosa Ziehau * Set the MAC address.
811f85e0762SSepherosa Ziehau */
812f85e0762SSepherosa Ziehau bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN);
813f85e0762SSepherosa Ziehau val = eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5];
814f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_EADDR0_REG, val);
815f85e0762SSepherosa Ziehau val = eaddr[0] << 8 | eaddr[1];
816f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_EADDR1_REG, val);
817f85e0762SSepherosa Ziehau
818f85e0762SSepherosa Ziehau /*
819f85e0762SSepherosa Ziehau * Set ring buffers base addresses.
820f85e0762SSepherosa Ziehau */
821f85e0762SSepherosa Ziehau addr = sc->dma_rxd_busaddr;
822f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_DESC_ADDR_HI_REG, BUS_ADDR_HI(addr));
823f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_RXD_ADDR_LO_REG, BUS_ADDR_LO(addr));
824f85e0762SSepherosa Ziehau addr = sc->dma_txd_busaddr;
825f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_TXD_ADDR_LO_REG, BUS_ADDR_LO(addr));
826f85e0762SSepherosa Ziehau addr = sc->dma_txs_busaddr;
827f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_TXS_ADDR_LO_REG, BUS_ADDR_LO(addr));
828f85e0762SSepherosa Ziehau
829f85e0762SSepherosa Ziehau /*
830f85e0762SSepherosa Ziehau * Configure ring buffers sizes.
831f85e0762SSepherosa Ziehau */
832f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_RXD_COUNT_REG, AE_RXD_COUNT_DEFAULT);
833f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_TXD_BUFSIZE_REG, AE_TXD_BUFSIZE_DEFAULT / 4);
834f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_TXS_COUNT_REG, AE_TXS_COUNT_DEFAULT);
835f85e0762SSepherosa Ziehau
836f85e0762SSepherosa Ziehau /*
837f85e0762SSepherosa Ziehau * Configure interframe gap parameters.
838f85e0762SSepherosa Ziehau */
839f85e0762SSepherosa Ziehau val = ((AE_IFG_TXIPG_DEFAULT << AE_IFG_TXIPG_SHIFT) &
840f85e0762SSepherosa Ziehau AE_IFG_TXIPG_MASK) |
841f85e0762SSepherosa Ziehau ((AE_IFG_RXIPG_DEFAULT << AE_IFG_RXIPG_SHIFT) &
842f85e0762SSepherosa Ziehau AE_IFG_RXIPG_MASK) |
843f85e0762SSepherosa Ziehau ((AE_IFG_IPGR1_DEFAULT << AE_IFG_IPGR1_SHIFT) &
844f85e0762SSepherosa Ziehau AE_IFG_IPGR1_MASK) |
845f85e0762SSepherosa Ziehau ((AE_IFG_IPGR2_DEFAULT << AE_IFG_IPGR2_SHIFT) &
846f85e0762SSepherosa Ziehau AE_IFG_IPGR2_MASK);
847f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_IFG_REG, val);
848f85e0762SSepherosa Ziehau
849f85e0762SSepherosa Ziehau /*
850f85e0762SSepherosa Ziehau * Configure half-duplex operation.
851f85e0762SSepherosa Ziehau */
852f85e0762SSepherosa Ziehau val = ((AE_HDPX_LCOL_DEFAULT << AE_HDPX_LCOL_SHIFT) &
853f85e0762SSepherosa Ziehau AE_HDPX_LCOL_MASK) |
854f85e0762SSepherosa Ziehau ((AE_HDPX_RETRY_DEFAULT << AE_HDPX_RETRY_SHIFT) &
855f85e0762SSepherosa Ziehau AE_HDPX_RETRY_MASK) |
856f85e0762SSepherosa Ziehau ((AE_HDPX_ABEBT_DEFAULT << AE_HDPX_ABEBT_SHIFT) &
857f85e0762SSepherosa Ziehau AE_HDPX_ABEBT_MASK) |
858f85e0762SSepherosa Ziehau ((AE_HDPX_JAMIPG_DEFAULT << AE_HDPX_JAMIPG_SHIFT) &
859f85e0762SSepherosa Ziehau AE_HDPX_JAMIPG_MASK) | AE_HDPX_EXC_EN;
860f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_HDPX_REG, val);
861f85e0762SSepherosa Ziehau
862f85e0762SSepherosa Ziehau /*
863f85e0762SSepherosa Ziehau * Configure interrupt moderate timer.
864f85e0762SSepherosa Ziehau */
865f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_IMT_REG, AE_IMT_DEFAULT);
866f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MASTER_REG);
867f85e0762SSepherosa Ziehau val |= AE_MASTER_IMT_EN;
868f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MASTER_REG, val);
869f85e0762SSepherosa Ziehau
870f85e0762SSepherosa Ziehau /*
871f85e0762SSepherosa Ziehau * Configure interrupt clearing timer.
872f85e0762SSepherosa Ziehau */
873f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_ICT_REG, AE_ICT_DEFAULT);
874f85e0762SSepherosa Ziehau
875f85e0762SSepherosa Ziehau /*
876f85e0762SSepherosa Ziehau * Configure MTU.
877f85e0762SSepherosa Ziehau */
878f85e0762SSepherosa Ziehau val = ifp->if_mtu + ETHER_HDR_LEN + sizeof(struct ether_vlan_header) +
879f85e0762SSepherosa Ziehau ETHER_CRC_LEN;
880f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MTU_REG, val);
881f85e0762SSepherosa Ziehau
882f85e0762SSepherosa Ziehau /*
883f85e0762SSepherosa Ziehau * Configure cut-through threshold.
884f85e0762SSepherosa Ziehau */
885f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_CUT_THRESH_REG, AE_CUT_THRESH_DEFAULT);
886f85e0762SSepherosa Ziehau
887f85e0762SSepherosa Ziehau /*
888f85e0762SSepherosa Ziehau * Configure flow control.
889f85e0762SSepherosa Ziehau */
890f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_FLOW_THRESH_HI_REG, (AE_RXD_COUNT_DEFAULT / 8) * 7);
891f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_FLOW_THRESH_LO_REG, (AE_RXD_COUNT_MIN / 8) >
892f85e0762SSepherosa Ziehau (AE_RXD_COUNT_DEFAULT / 12) ? (AE_RXD_COUNT_MIN / 8) :
893f85e0762SSepherosa Ziehau (AE_RXD_COUNT_DEFAULT / 12));
894f85e0762SSepherosa Ziehau
895f85e0762SSepherosa Ziehau /*
896f85e0762SSepherosa Ziehau * Init mailboxes.
897f85e0762SSepherosa Ziehau */
898f85e0762SSepherosa Ziehau sc->txd_cur = sc->rxd_cur = 0;
899f85e0762SSepherosa Ziehau sc->txs_ack = sc->txd_ack = 0;
900f85e0762SSepherosa Ziehau sc->rxd_cur = 0;
901f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MB_TXD_IDX_REG, sc->txd_cur);
902f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MB_RXD_IDX_REG, sc->rxd_cur);
903f85e0762SSepherosa Ziehau sc->tx_inproc = 0;
904f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_TXAVAIL; /* Free Tx's available. */
905f85e0762SSepherosa Ziehau
906f85e0762SSepherosa Ziehau /*
907f85e0762SSepherosa Ziehau * Enable DMA.
908f85e0762SSepherosa Ziehau */
909f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAREAD_REG, AE_DMAREAD_EN);
910f85e0762SSepherosa Ziehau AE_WRITE_1(sc, AE_DMAWRITE_REG, AE_DMAWRITE_EN);
911f85e0762SSepherosa Ziehau
912f85e0762SSepherosa Ziehau /*
913f85e0762SSepherosa Ziehau * Check if everything is OK.
914f85e0762SSepherosa Ziehau */
915f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_ISR_REG);
916f85e0762SSepherosa Ziehau if ((val & AE_ISR_PHY_LINKDOWN) != 0) {
917f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "Initialization failed.\n");
918f85e0762SSepherosa Ziehau return;
919f85e0762SSepherosa Ziehau }
920f85e0762SSepherosa Ziehau
921f85e0762SSepherosa Ziehau /*
922f85e0762SSepherosa Ziehau * Clear interrupt status.
923f85e0762SSepherosa Ziehau */
924f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0x3fffffff);
925f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_ISR_REG, 0x0);
926f85e0762SSepherosa Ziehau
927f85e0762SSepherosa Ziehau /*
928f85e0762SSepherosa Ziehau * Enable interrupts.
929f85e0762SSepherosa Ziehau */
930f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MASTER_REG);
931f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MASTER_REG, val | AE_MASTER_MANUAL_INT);
932f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_IMR_REG, AE_IMR_DEFAULT);
933f85e0762SSepherosa Ziehau
934f85e0762SSepherosa Ziehau /*
935f85e0762SSepherosa Ziehau * Disable WOL.
936f85e0762SSepherosa Ziehau */
937f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_WOL_REG, 0);
938f85e0762SSepherosa Ziehau
939f85e0762SSepherosa Ziehau /*
940f85e0762SSepherosa Ziehau * Configure MAC.
941f85e0762SSepherosa Ziehau */
942f85e0762SSepherosa Ziehau val = AE_MAC_TX_CRC_EN | AE_MAC_TX_AUTOPAD |
943f85e0762SSepherosa Ziehau AE_MAC_FULL_DUPLEX | AE_MAC_CLK_PHY |
944f85e0762SSepherosa Ziehau AE_MAC_TX_FLOW_EN | AE_MAC_RX_FLOW_EN |
945f85e0762SSepherosa Ziehau ((AE_HALFBUF_DEFAULT << AE_HALFBUF_SHIFT) & AE_HALFBUF_MASK) |
946f85e0762SSepherosa Ziehau ((AE_MAC_PREAMBLE_DEFAULT << AE_MAC_PREAMBLE_SHIFT) &
947f85e0762SSepherosa Ziehau AE_MAC_PREAMBLE_MASK);
948f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val);
949f85e0762SSepherosa Ziehau
950f85e0762SSepherosa Ziehau /*
951f85e0762SSepherosa Ziehau * Configure Rx MAC.
952f85e0762SSepherosa Ziehau */
953f85e0762SSepherosa Ziehau ae_rxfilter(sc);
954f85e0762SSepherosa Ziehau ae_rxvlan(sc);
955f85e0762SSepherosa Ziehau
956f85e0762SSepherosa Ziehau /*
957f85e0762SSepherosa Ziehau * Enable Tx/Rx.
958f85e0762SSepherosa Ziehau */
959f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG);
960f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val | AE_MAC_TX_EN | AE_MAC_RX_EN);
961f85e0762SSepherosa Ziehau
962f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_LINK;
963f85e0762SSepherosa Ziehau mii_mediachg(mii); /* Switch to the current media. */
964f85e0762SSepherosa Ziehau
965f85e0762SSepherosa Ziehau callout_reset(&sc->ae_tick_ch, hz, ae_tick, sc);
966f85e0762SSepherosa Ziehau ifp->if_flags |= IFF_RUNNING;
9679ed293e0SSepherosa Ziehau ifq_clr_oactive(&ifp->if_snd);
968f85e0762SSepherosa Ziehau }
969f85e0762SSepherosa Ziehau
970f85e0762SSepherosa Ziehau static void
ae_watchdog(struct ifnet * ifp)971f85e0762SSepherosa Ziehau ae_watchdog(struct ifnet *ifp)
972f85e0762SSepherosa Ziehau {
973f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc;
974f85e0762SSepherosa Ziehau
975f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer);
976f85e0762SSepherosa Ziehau
977f85e0762SSepherosa Ziehau if ((sc->ae_flags & AE_FLAG_LINK) == 0)
978f85e0762SSepherosa Ziehau if_printf(ifp, "watchdog timeout (missed link).\n");
979f85e0762SSepherosa Ziehau else
980f85e0762SSepherosa Ziehau if_printf(ifp, "watchdog timeout - resetting.\n");
981d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1);
982f85e0762SSepherosa Ziehau
983f85e0762SSepherosa Ziehau ae_init(sc);
984f85e0762SSepherosa Ziehau if (!ifq_is_empty(&ifp->if_snd))
985f85e0762SSepherosa Ziehau if_devstart(ifp);
986f85e0762SSepherosa Ziehau }
987f85e0762SSepherosa Ziehau
988f85e0762SSepherosa Ziehau static void
ae_tick(void * xsc)989f85e0762SSepherosa Ziehau ae_tick(void *xsc)
990f85e0762SSepherosa Ziehau {
991f85e0762SSepherosa Ziehau struct ae_softc *sc = xsc;
992f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
993f85e0762SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->ae_miibus);
994f85e0762SSepherosa Ziehau
995f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer);
996f85e0762SSepherosa Ziehau mii_tick(mii);
997f85e0762SSepherosa Ziehau callout_reset(&sc->ae_tick_ch, hz, ae_tick, sc);
998f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer);
999f85e0762SSepherosa Ziehau }
1000f85e0762SSepherosa Ziehau
1001f85e0762SSepherosa Ziehau static void
ae_rxvlan(struct ae_softc * sc)1002f85e0762SSepherosa Ziehau ae_rxvlan(struct ae_softc *sc)
1003f85e0762SSepherosa Ziehau {
1004f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
1005f85e0762SSepherosa Ziehau uint32_t val;
1006f85e0762SSepherosa Ziehau
1007f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_MAC_REG);
1008f85e0762SSepherosa Ziehau val &= ~AE_MAC_RMVLAN_EN;
1009f85e0762SSepherosa Ziehau if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING)
1010f85e0762SSepherosa Ziehau val |= AE_MAC_RMVLAN_EN;
1011f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, val);
1012f85e0762SSepherosa Ziehau }
1013f85e0762SSepherosa Ziehau
1014f85e0762SSepherosa Ziehau static void
ae_rxfilter(struct ae_softc * sc)1015f85e0762SSepherosa Ziehau ae_rxfilter(struct ae_softc *sc)
1016f85e0762SSepherosa Ziehau {
1017f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
1018f85e0762SSepherosa Ziehau struct ifmultiaddr *ifma;
1019f85e0762SSepherosa Ziehau uint32_t crc;
1020f85e0762SSepherosa Ziehau uint32_t mchash[2];
1021f85e0762SSepherosa Ziehau uint32_t rxcfg;
1022f85e0762SSepherosa Ziehau
1023f85e0762SSepherosa Ziehau rxcfg = AE_READ_4(sc, AE_MAC_REG);
1024f85e0762SSepherosa Ziehau rxcfg &= ~(AE_MAC_MCAST_EN | AE_MAC_BCAST_EN | AE_MAC_PROMISC_EN);
1025f85e0762SSepherosa Ziehau rxcfg |= AE_MAC_BCAST_EN;
1026f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_PROMISC)
1027f85e0762SSepherosa Ziehau rxcfg |= AE_MAC_PROMISC_EN;
1028f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_ALLMULTI)
1029f85e0762SSepherosa Ziehau rxcfg |= AE_MAC_MCAST_EN;
1030f85e0762SSepherosa Ziehau
1031f85e0762SSepherosa Ziehau /*
1032f85e0762SSepherosa Ziehau * Wipe old settings.
1033f85e0762SSepherosa Ziehau */
1034f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT0, 0);
1035f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT1, 0);
1036f85e0762SSepherosa Ziehau if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) {
1037f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT0, 0xffffffff);
1038f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT1, 0xffffffff);
1039f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, rxcfg);
1040f85e0762SSepherosa Ziehau return;
1041f85e0762SSepherosa Ziehau }
1042f85e0762SSepherosa Ziehau
1043f85e0762SSepherosa Ziehau /*
1044f85e0762SSepherosa Ziehau * Load multicast tables.
1045f85e0762SSepherosa Ziehau */
1046f85e0762SSepherosa Ziehau bzero(mchash, sizeof(mchash));
1047441d34b2SSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1048f85e0762SSepherosa Ziehau if (ifma->ifma_addr->sa_family != AF_LINK)
1049f85e0762SSepherosa Ziehau continue;
1050f85e0762SSepherosa Ziehau crc = ether_crc32_le(LLADDR((struct sockaddr_dl *)
1051f85e0762SSepherosa Ziehau ifma->ifma_addr), ETHER_ADDR_LEN);
1052f85e0762SSepherosa Ziehau mchash[crc >> 31] |= 1 << ((crc >> 26) & 0x1f);
1053f85e0762SSepherosa Ziehau }
1054f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT0, mchash[0]);
1055f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_REG_MHT1, mchash[1]);
1056f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MAC_REG, rxcfg);
1057f85e0762SSepherosa Ziehau }
1058f85e0762SSepherosa Ziehau
1059f85e0762SSepherosa Ziehau static unsigned int
ae_tx_avail_size(struct ae_softc * sc)1060f85e0762SSepherosa Ziehau ae_tx_avail_size(struct ae_softc *sc)
1061f85e0762SSepherosa Ziehau {
1062f85e0762SSepherosa Ziehau unsigned int avail;
1063f85e0762SSepherosa Ziehau
1064f85e0762SSepherosa Ziehau if (sc->txd_cur >= sc->txd_ack)
1065f85e0762SSepherosa Ziehau avail = AE_TXD_BUFSIZE_DEFAULT - (sc->txd_cur - sc->txd_ack);
1066f85e0762SSepherosa Ziehau else
1067f85e0762SSepherosa Ziehau avail = sc->txd_ack - sc->txd_cur;
1068f85e0762SSepherosa Ziehau return (avail - 4); /* 4-byte header. */
1069f85e0762SSepherosa Ziehau }
1070f85e0762SSepherosa Ziehau
1071f85e0762SSepherosa Ziehau static int
ae_encap(struct ae_softc * sc,struct mbuf ** m_head)1072f85e0762SSepherosa Ziehau ae_encap(struct ae_softc *sc, struct mbuf **m_head)
1073f85e0762SSepherosa Ziehau {
1074f85e0762SSepherosa Ziehau struct mbuf *m0;
1075f85e0762SSepherosa Ziehau struct ae_txd *hdr;
1076f85e0762SSepherosa Ziehau unsigned int to_end;
1077f85e0762SSepherosa Ziehau uint16_t len;
1078f85e0762SSepherosa Ziehau
1079f85e0762SSepherosa Ziehau M_ASSERTPKTHDR((*m_head));
1080f85e0762SSepherosa Ziehau m0 = *m_head;
1081f85e0762SSepherosa Ziehau len = m0->m_pkthdr.len;
1082f85e0762SSepherosa Ziehau if ((sc->ae_flags & AE_FLAG_TXAVAIL) == 0 ||
1083f85e0762SSepherosa Ziehau ae_tx_avail_size(sc) < len) {
1084f85e0762SSepherosa Ziehau #ifdef AE_DEBUG
1085f85e0762SSepherosa Ziehau if_printf(sc->ifp, "No free Tx available.\n");
1086f85e0762SSepherosa Ziehau #endif
1087f85e0762SSepherosa Ziehau return ENOBUFS;
1088f85e0762SSepherosa Ziehau }
1089f85e0762SSepherosa Ziehau
1090f85e0762SSepherosa Ziehau hdr = (struct ae_txd *)(sc->txd_base + sc->txd_cur);
1091f85e0762SSepherosa Ziehau bzero(hdr, sizeof(*hdr));
1092f85e0762SSepherosa Ziehau
1093f85e0762SSepherosa Ziehau /* Header size. */
1094f85e0762SSepherosa Ziehau sc->txd_cur = (sc->txd_cur + 4) % AE_TXD_BUFSIZE_DEFAULT;
1095f85e0762SSepherosa Ziehau
1096f85e0762SSepherosa Ziehau /* Space available to the end of the ring */
1097f85e0762SSepherosa Ziehau to_end = AE_TXD_BUFSIZE_DEFAULT - sc->txd_cur;
1098f85e0762SSepherosa Ziehau
1099f85e0762SSepherosa Ziehau if (to_end >= len) {
110005d02a38SAaron LI m_copydata(m0, 0, len, sc->txd_base + sc->txd_cur);
1101f85e0762SSepherosa Ziehau } else {
110205d02a38SAaron LI m_copydata(m0, 0, to_end, sc->txd_base + sc->txd_cur);
110305d02a38SAaron LI m_copydata(m0, to_end, len - to_end, sc->txd_base);
1104f85e0762SSepherosa Ziehau }
1105f85e0762SSepherosa Ziehau
1106f85e0762SSepherosa Ziehau /*
1107f85e0762SSepherosa Ziehau * Set TxD flags and parameters.
1108f85e0762SSepherosa Ziehau */
1109f85e0762SSepherosa Ziehau if ((m0->m_flags & M_VLANTAG) != 0) {
1110f85e0762SSepherosa Ziehau hdr->vlan = htole16(AE_TXD_VLAN(m0->m_pkthdr.ether_vlantag));
1111f85e0762SSepherosa Ziehau hdr->len = htole16(len | AE_TXD_INSERT_VTAG);
1112f85e0762SSepherosa Ziehau } else {
1113f85e0762SSepherosa Ziehau hdr->len = htole16(len);
1114f85e0762SSepherosa Ziehau }
1115f85e0762SSepherosa Ziehau
1116f85e0762SSepherosa Ziehau /*
1117f85e0762SSepherosa Ziehau * Set current TxD position and round up to a 4-byte boundary.
1118f85e0762SSepherosa Ziehau */
1119f85e0762SSepherosa Ziehau sc->txd_cur = ((sc->txd_cur + len + 3) & ~3) % AE_TXD_BUFSIZE_DEFAULT;
1120f85e0762SSepherosa Ziehau if (sc->txd_cur == sc->txd_ack)
1121f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_TXAVAIL;
1122f85e0762SSepherosa Ziehau #ifdef AE_DEBUG
1123f85e0762SSepherosa Ziehau if_printf(sc->ifp, "New txd_cur = %d.\n", sc->txd_cur);
1124f85e0762SSepherosa Ziehau #endif
1125f85e0762SSepherosa Ziehau
1126f85e0762SSepherosa Ziehau /*
1127f85e0762SSepherosa Ziehau * Update TxS position and check if there are empty TxS available.
1128f85e0762SSepherosa Ziehau */
1129f85e0762SSepherosa Ziehau sc->txs_base[sc->txs_cur].flags &= ~htole16(AE_TXS_UPDATE);
1130f85e0762SSepherosa Ziehau sc->txs_cur = (sc->txs_cur + 1) % AE_TXS_COUNT_DEFAULT;
1131f85e0762SSepherosa Ziehau if (sc->txs_cur == sc->txs_ack)
1132f85e0762SSepherosa Ziehau sc->ae_flags &= ~AE_FLAG_TXAVAIL;
1133f85e0762SSepherosa Ziehau
1134f85e0762SSepherosa Ziehau /*
1135f85e0762SSepherosa Ziehau * Synchronize DMA memory.
1136f85e0762SSepherosa Ziehau */
1137f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txd_tag, sc->dma_txd_map, BUS_DMASYNC_PREWRITE);
1138f85e0762SSepherosa Ziehau bus_dmamap_sync(sc->dma_txs_tag, sc->dma_txs_map, BUS_DMASYNC_PREWRITE);
1139f85e0762SSepherosa Ziehau
1140f85e0762SSepherosa Ziehau return (0);
1141f85e0762SSepherosa Ziehau }
1142f85e0762SSepherosa Ziehau
1143f85e0762SSepherosa Ziehau static void
ae_start(struct ifnet * ifp,struct ifaltq_subque * ifsq)1144f0a26983SSepherosa Ziehau ae_start(struct ifnet *ifp, struct ifaltq_subque *ifsq)
1145f85e0762SSepherosa Ziehau {
1146f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc;
1147f85e0762SSepherosa Ziehau int error, trans;
1148f85e0762SSepherosa Ziehau
1149f0a26983SSepherosa Ziehau ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq);
1150f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer);
1151f85e0762SSepherosa Ziehau
1152f85e0762SSepherosa Ziehau #ifdef AE_DEBUG
1153f85e0762SSepherosa Ziehau if_printf(ifp, "Start called.\n");
1154f85e0762SSepherosa Ziehau #endif
1155f85e0762SSepherosa Ziehau if ((sc->ae_flags & AE_FLAG_LINK) == 0) {
1156f85e0762SSepherosa Ziehau ifq_purge(&ifp->if_snd);
1157f85e0762SSepherosa Ziehau return;
1158f85e0762SSepherosa Ziehau }
11599ed293e0SSepherosa Ziehau if ((ifp->if_flags & IFF_RUNNING) == 0 || ifq_is_oactive(&ifp->if_snd))
1160f85e0762SSepherosa Ziehau return;
1161f85e0762SSepherosa Ziehau
1162f85e0762SSepherosa Ziehau trans = 0;
1163f85e0762SSepherosa Ziehau while (!ifq_is_empty(&ifp->if_snd)) {
1164f85e0762SSepherosa Ziehau struct mbuf *m0;
1165f85e0762SSepherosa Ziehau
1166ac9843a1SSepherosa Ziehau m0 = ifq_dequeue(&ifp->if_snd);
1167f85e0762SSepherosa Ziehau if (m0 == NULL)
1168f85e0762SSepherosa Ziehau break; /* Nothing to do. */
1169f85e0762SSepherosa Ziehau
1170f85e0762SSepherosa Ziehau error = ae_encap(sc, &m0);
1171f85e0762SSepherosa Ziehau if (error != 0) {
1172f85e0762SSepherosa Ziehau if (m0 != NULL) {
1173f85e0762SSepherosa Ziehau ifq_prepend(&ifp->if_snd, m0);
11749ed293e0SSepherosa Ziehau ifq_set_oactive(&ifp->if_snd);
1175f85e0762SSepherosa Ziehau #ifdef AE_DEBUG
1176f85e0762SSepherosa Ziehau if_printf(ifp, "Setting OACTIVE.\n");
1177f85e0762SSepherosa Ziehau #endif
1178f85e0762SSepherosa Ziehau }
1179f85e0762SSepherosa Ziehau break;
1180f85e0762SSepherosa Ziehau }
1181f85e0762SSepherosa Ziehau trans = 1;
1182f85e0762SSepherosa Ziehau sc->tx_inproc++;
1183f85e0762SSepherosa Ziehau
1184f85e0762SSepherosa Ziehau /* Bounce a copy of the frame to BPF. */
1185f85e0762SSepherosa Ziehau ETHER_BPF_MTAP(ifp, m0);
1186f85e0762SSepherosa Ziehau m_freem(m0);
1187f85e0762SSepherosa Ziehau }
1188f85e0762SSepherosa Ziehau if (trans) { /* Something was dequeued. */
1189f85e0762SSepherosa Ziehau AE_WRITE_2(sc, AE_MB_TXD_IDX_REG, sc->txd_cur / 4);
1190f85e0762SSepherosa Ziehau ifp->if_timer = AE_TX_TIMEOUT; /* Load watchdog. */
1191f85e0762SSepherosa Ziehau #ifdef AE_DEBUG
1192f85e0762SSepherosa Ziehau if_printf(ifp, "%d packets dequeued.\n", count);
1193f85e0762SSepherosa Ziehau if_printf(ifp, "Tx pos now is %d.\n", sc->txd_cur);
1194f85e0762SSepherosa Ziehau #endif
1195f85e0762SSepherosa Ziehau }
1196f85e0762SSepherosa Ziehau }
1197f85e0762SSepherosa Ziehau
1198f85e0762SSepherosa Ziehau static int
ae_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data,struct ucred * cr)1199f85e0762SSepherosa Ziehau ae_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr)
1200f85e0762SSepherosa Ziehau {
1201f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc;
1202f85e0762SSepherosa Ziehau struct ifreq *ifr;
1203f85e0762SSepherosa Ziehau struct mii_data *mii;
1204f85e0762SSepherosa Ziehau int error = 0, mask;
1205f85e0762SSepherosa Ziehau
1206f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer);
1207f85e0762SSepherosa Ziehau
1208f85e0762SSepherosa Ziehau ifr = (struct ifreq *)data;
1209f85e0762SSepherosa Ziehau switch (cmd) {
1210f85e0762SSepherosa Ziehau case SIOCSIFFLAGS:
1211f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_UP) {
1212f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING) {
1213f85e0762SSepherosa Ziehau if (((ifp->if_flags ^ sc->ae_if_flags)
1214f85e0762SSepherosa Ziehau & (IFF_PROMISC | IFF_ALLMULTI)) != 0)
1215f85e0762SSepherosa Ziehau ae_rxfilter(sc);
1216f85e0762SSepherosa Ziehau } else {
1217f85e0762SSepherosa Ziehau ae_init(sc);
1218f85e0762SSepherosa Ziehau }
1219f85e0762SSepherosa Ziehau } else {
1220f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING)
1221f85e0762SSepherosa Ziehau ae_stop(sc);
1222f85e0762SSepherosa Ziehau }
1223f85e0762SSepherosa Ziehau sc->ae_if_flags = ifp->if_flags;
1224f85e0762SSepherosa Ziehau break;
1225f85e0762SSepherosa Ziehau
1226f85e0762SSepherosa Ziehau case SIOCADDMULTI:
1227f85e0762SSepherosa Ziehau case SIOCDELMULTI:
1228f85e0762SSepherosa Ziehau if (ifp->if_flags & IFF_RUNNING)
1229f85e0762SSepherosa Ziehau ae_rxfilter(sc);
1230f85e0762SSepherosa Ziehau break;
1231f85e0762SSepherosa Ziehau
1232f85e0762SSepherosa Ziehau case SIOCSIFMEDIA:
1233f85e0762SSepherosa Ziehau case SIOCGIFMEDIA:
1234f85e0762SSepherosa Ziehau mii = device_get_softc(sc->ae_miibus);
1235f85e0762SSepherosa Ziehau error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
1236f85e0762SSepherosa Ziehau break;
1237f85e0762SSepherosa Ziehau
1238f85e0762SSepherosa Ziehau case SIOCSIFCAP:
1239f85e0762SSepherosa Ziehau mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1240f85e0762SSepherosa Ziehau if (mask & IFCAP_VLAN_HWTAGGING) {
1241f85e0762SSepherosa Ziehau ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1242f85e0762SSepherosa Ziehau ae_rxvlan(sc);
1243f85e0762SSepherosa Ziehau }
1244f85e0762SSepherosa Ziehau break;
1245f85e0762SSepherosa Ziehau
1246f85e0762SSepherosa Ziehau default:
1247f85e0762SSepherosa Ziehau error = ether_ioctl(ifp, cmd, data);
1248f85e0762SSepherosa Ziehau break;
1249f85e0762SSepherosa Ziehau }
1250f85e0762SSepherosa Ziehau return (error);
1251f85e0762SSepherosa Ziehau }
1252f85e0762SSepherosa Ziehau
1253f85e0762SSepherosa Ziehau static int
ae_attach(device_t dev)1254f85e0762SSepherosa Ziehau ae_attach(device_t dev)
1255f85e0762SSepherosa Ziehau {
1256f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev);
1257f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
1258f85e0762SSepherosa Ziehau int error = 0;
1259f85e0762SSepherosa Ziehau
1260f85e0762SSepherosa Ziehau sc->ae_dev = dev;
1261f85e0762SSepherosa Ziehau if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1262f85e0762SSepherosa Ziehau callout_init(&sc->ae_tick_ch);
1263f85e0762SSepherosa Ziehau
1264f85e0762SSepherosa Ziehau /* Enable bus mastering */
1265f85e0762SSepherosa Ziehau pci_enable_busmaster(dev);
1266f85e0762SSepherosa Ziehau
1267f85e0762SSepherosa Ziehau /*
1268f85e0762SSepherosa Ziehau * Allocate memory mapped IO
1269f85e0762SSepherosa Ziehau */
1270f85e0762SSepherosa Ziehau sc->ae_mem_rid = PCIR_BAR(0);
1271f85e0762SSepherosa Ziehau sc->ae_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
1272f85e0762SSepherosa Ziehau &sc->ae_mem_rid, RF_ACTIVE);
1273f85e0762SSepherosa Ziehau if (sc->ae_mem_res == NULL) {
1274f85e0762SSepherosa Ziehau device_printf(dev, "can't allocate IO memory\n");
1275f85e0762SSepherosa Ziehau return ENXIO;
1276f85e0762SSepherosa Ziehau }
1277f85e0762SSepherosa Ziehau sc->ae_mem_bt = rman_get_bustag(sc->ae_mem_res);
1278f85e0762SSepherosa Ziehau sc->ae_mem_bh = rman_get_bushandle(sc->ae_mem_res);
1279f85e0762SSepherosa Ziehau
1280f85e0762SSepherosa Ziehau /*
1281f85e0762SSepherosa Ziehau * Allocate IRQ
1282f85e0762SSepherosa Ziehau */
1283f85e0762SSepherosa Ziehau sc->ae_irq_rid = 0;
1284f85e0762SSepherosa Ziehau sc->ae_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
1285f85e0762SSepherosa Ziehau &sc->ae_irq_rid,
1286f85e0762SSepherosa Ziehau RF_SHAREABLE | RF_ACTIVE);
1287f85e0762SSepherosa Ziehau if (sc->ae_irq_res == NULL) {
1288f85e0762SSepherosa Ziehau device_printf(dev, "can't allocate irq\n");
1289f85e0762SSepherosa Ziehau error = ENXIO;
1290f85e0762SSepherosa Ziehau goto fail;
1291f85e0762SSepherosa Ziehau }
1292f85e0762SSepherosa Ziehau
1293f85e0762SSepherosa Ziehau /* Set PHY address. */
1294f85e0762SSepherosa Ziehau sc->ae_phyaddr = AE_PHYADDR_DEFAULT;
1295f85e0762SSepherosa Ziehau
1296f85e0762SSepherosa Ziehau /* Create sysctl tree */
1297f85e0762SSepherosa Ziehau ae_sysctl_node(sc);
1298f85e0762SSepherosa Ziehau
1299f85e0762SSepherosa Ziehau /* Reset PHY. */
1300f85e0762SSepherosa Ziehau ae_phy_reset(sc);
1301f85e0762SSepherosa Ziehau
1302f85e0762SSepherosa Ziehau /*
1303f85e0762SSepherosa Ziehau * Reset the ethernet controller.
1304f85e0762SSepherosa Ziehau */
1305f85e0762SSepherosa Ziehau ae_reset(sc);
1306f85e0762SSepherosa Ziehau ae_pcie_init(sc);
1307f85e0762SSepherosa Ziehau
1308f85e0762SSepherosa Ziehau /*
1309f85e0762SSepherosa Ziehau * Get PCI and chip id/revision.
1310f85e0762SSepherosa Ziehau */
1311f85e0762SSepherosa Ziehau sc->ae_rev = pci_get_revid(dev);
1312f85e0762SSepherosa Ziehau sc->ae_chip_rev =
1313f85e0762SSepherosa Ziehau (AE_READ_4(sc, AE_MASTER_REG) >> AE_MASTER_REVNUM_SHIFT) &
1314f85e0762SSepherosa Ziehau AE_MASTER_REVNUM_MASK;
1315f85e0762SSepherosa Ziehau if (bootverbose) {
1316f85e0762SSepherosa Ziehau device_printf(dev, "PCI device revision : 0x%04x\n", sc->ae_rev);
1317f85e0762SSepherosa Ziehau device_printf(dev, "Chip id/revision : 0x%04x\n",
1318f85e0762SSepherosa Ziehau sc->ae_chip_rev);
1319f85e0762SSepherosa Ziehau }
1320f85e0762SSepherosa Ziehau
1321f85e0762SSepherosa Ziehau /*
1322f85e0762SSepherosa Ziehau * XXX
1323f85e0762SSepherosa Ziehau * Unintialized hardware returns an invalid chip id/revision
1324f85e0762SSepherosa Ziehau * as well as 0xFFFFFFFF for Tx/Rx fifo length. It seems that
1325f85e0762SSepherosa Ziehau * unplugged cable results in putting hardware into automatic
1326f85e0762SSepherosa Ziehau * power down mode which in turn returns invalld chip revision.
1327f85e0762SSepherosa Ziehau */
1328f85e0762SSepherosa Ziehau if (sc->ae_chip_rev == 0xFFFF) {
1329f85e0762SSepherosa Ziehau device_printf(dev,"invalid chip revision : 0x%04x -- "
1330f85e0762SSepherosa Ziehau "not initialized?\n", sc->ae_chip_rev);
1331f85e0762SSepherosa Ziehau error = ENXIO;
1332f85e0762SSepherosa Ziehau goto fail;
1333f85e0762SSepherosa Ziehau }
1334f85e0762SSepherosa Ziehau #if 0
1335f85e0762SSepherosa Ziehau /* Get DMA parameters from PCIe device control register. */
1336f85e0762SSepherosa Ziehau pcie_ptr = pci_get_pciecap_ptr(dev);
1337f85e0762SSepherosa Ziehau if (pcie_ptr) {
1338f85e0762SSepherosa Ziehau uint16_t devctl;
1339f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_PCIE;
1340f85e0762SSepherosa Ziehau devctl = pci_read_config(dev, pcie_ptr + PCIER_DEVCTRL, 2);
1341f85e0762SSepherosa Ziehau /* Max read request size. */
1342f85e0762SSepherosa Ziehau sc->ae_dma_rd_burst = ((devctl >> 12) & 0x07) <<
1343f85e0762SSepherosa Ziehau DMA_CFG_RD_BURST_SHIFT;
1344f85e0762SSepherosa Ziehau /* Max payload size. */
1345f85e0762SSepherosa Ziehau sc->ae_dma_wr_burst = ((devctl >> 5) & 0x07) <<
1346f85e0762SSepherosa Ziehau DMA_CFG_WR_BURST_SHIFT;
1347f85e0762SSepherosa Ziehau if (bootverbose) {
1348f85e0762SSepherosa Ziehau device_printf(dev, "Read request size : %d bytes.\n",
1349f85e0762SSepherosa Ziehau 128 << ((devctl >> 12) & 0x07));
1350f85e0762SSepherosa Ziehau device_printf(dev, "TLP payload size : %d bytes.\n",
1351f85e0762SSepherosa Ziehau 128 << ((devctl >> 5) & 0x07));
1352f85e0762SSepherosa Ziehau }
1353f85e0762SSepherosa Ziehau } else {
1354f85e0762SSepherosa Ziehau sc->ae_dma_rd_burst = DMA_CFG_RD_BURST_128;
1355f85e0762SSepherosa Ziehau sc->ae_dma_wr_burst = DMA_CFG_WR_BURST_128;
1356f85e0762SSepherosa Ziehau }
1357f85e0762SSepherosa Ziehau #endif
1358f85e0762SSepherosa Ziehau
1359f85e0762SSepherosa Ziehau /* Create DMA stuffs */
1360f85e0762SSepherosa Ziehau error = ae_dma_alloc(sc);
1361f85e0762SSepherosa Ziehau if (error)
1362f85e0762SSepherosa Ziehau goto fail;
1363f85e0762SSepherosa Ziehau
1364f85e0762SSepherosa Ziehau /* Load station address. */
1365f85e0762SSepherosa Ziehau ae_get_eaddr(sc);
1366f85e0762SSepherosa Ziehau
1367f85e0762SSepherosa Ziehau ifp->if_softc = sc;
1368f85e0762SSepherosa Ziehau ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1369f85e0762SSepherosa Ziehau ifp->if_ioctl = ae_ioctl;
1370f85e0762SSepherosa Ziehau ifp->if_start = ae_start;
1371f85e0762SSepherosa Ziehau ifp->if_init = ae_init;
1372f85e0762SSepherosa Ziehau ifp->if_watchdog = ae_watchdog;
1373f85e0762SSepherosa Ziehau ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN - 1);
1374f85e0762SSepherosa Ziehau ifq_set_ready(&ifp->if_snd);
1375f85e0762SSepherosa Ziehau ifp->if_capabilities = IFCAP_VLAN_MTU |
1376f85e0762SSepherosa Ziehau IFCAP_VLAN_HWTAGGING;
1377f85e0762SSepherosa Ziehau ifp->if_hwassist = 0;
1378f85e0762SSepherosa Ziehau ifp->if_capenable = ifp->if_capabilities;
1379f85e0762SSepherosa Ziehau
1380f85e0762SSepherosa Ziehau /* Set up MII bus. */
1381f85e0762SSepherosa Ziehau error = mii_phy_probe(dev, &sc->ae_miibus,
1382f85e0762SSepherosa Ziehau ae_mediachange, ae_mediastatus);
1383f85e0762SSepherosa Ziehau if (error) {
1384f85e0762SSepherosa Ziehau device_printf(dev, "no PHY found!\n");
1385f85e0762SSepherosa Ziehau goto fail;
1386f85e0762SSepherosa Ziehau }
1387f85e0762SSepherosa Ziehau ether_ifattach(ifp, sc->ae_eaddr, NULL);
1388f85e0762SSepherosa Ziehau
1389f85e0762SSepherosa Ziehau /* Tell the upper layer(s) we support long frames. */
1390f85e0762SSepherosa Ziehau ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
1391f85e0762SSepherosa Ziehau
13924c77af2dSSepherosa Ziehau ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->ae_irq_res));
13934c77af2dSSepherosa Ziehau
1394f85e0762SSepherosa Ziehau error = bus_setup_intr(dev, sc->ae_irq_res, INTR_MPSAFE, ae_intr, sc,
1395f85e0762SSepherosa Ziehau &sc->ae_irq_handle, ifp->if_serializer);
1396f85e0762SSepherosa Ziehau if (error) {
1397f85e0762SSepherosa Ziehau device_printf(dev, "could not set up interrupt handler.\n");
1398f85e0762SSepherosa Ziehau ether_ifdetach(ifp);
1399f85e0762SSepherosa Ziehau goto fail;
1400f85e0762SSepherosa Ziehau }
1401f85e0762SSepherosa Ziehau return 0;
1402f85e0762SSepherosa Ziehau fail:
1403f85e0762SSepherosa Ziehau ae_detach(dev);
1404f85e0762SSepherosa Ziehau return (error);
1405f85e0762SSepherosa Ziehau }
1406f85e0762SSepherosa Ziehau
1407f85e0762SSepherosa Ziehau static int
ae_detach(device_t dev)1408f85e0762SSepherosa Ziehau ae_detach(device_t dev)
1409f85e0762SSepherosa Ziehau {
1410f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev);
1411f85e0762SSepherosa Ziehau
1412f85e0762SSepherosa Ziehau if (device_is_attached(dev)) {
1413f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
1414f85e0762SSepherosa Ziehau
1415f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer);
1416f85e0762SSepherosa Ziehau sc->ae_flags |= AE_FLAG_DETACH;
1417f85e0762SSepherosa Ziehau ae_stop(sc);
1418f85e0762SSepherosa Ziehau bus_teardown_intr(dev, sc->ae_irq_res, sc->ae_irq_handle);
1419f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer);
1420f85e0762SSepherosa Ziehau
1421f85e0762SSepherosa Ziehau ether_ifdetach(ifp);
1422f85e0762SSepherosa Ziehau }
1423f85e0762SSepherosa Ziehau
1424f85e0762SSepherosa Ziehau if (sc->ae_miibus != NULL)
1425f85e0762SSepherosa Ziehau device_delete_child(dev, sc->ae_miibus);
1426f85e0762SSepherosa Ziehau bus_generic_detach(dev);
1427f85e0762SSepherosa Ziehau
1428f85e0762SSepherosa Ziehau if (sc->ae_irq_res != NULL) {
1429f85e0762SSepherosa Ziehau bus_release_resource(dev, SYS_RES_IRQ, sc->ae_irq_rid,
1430f85e0762SSepherosa Ziehau sc->ae_irq_res);
1431f85e0762SSepherosa Ziehau }
1432f85e0762SSepherosa Ziehau if (sc->ae_mem_res != NULL) {
1433f85e0762SSepherosa Ziehau bus_release_resource(dev, SYS_RES_MEMORY, sc->ae_mem_rid,
1434f85e0762SSepherosa Ziehau sc->ae_mem_res);
1435f85e0762SSepherosa Ziehau }
1436f85e0762SSepherosa Ziehau ae_dma_free(sc);
1437f85e0762SSepherosa Ziehau
1438f85e0762SSepherosa Ziehau return (0);
1439f85e0762SSepherosa Ziehau }
1440f85e0762SSepherosa Ziehau
1441f85e0762SSepherosa Ziehau static void
ae_dma_free(struct ae_softc * sc)1442f85e0762SSepherosa Ziehau ae_dma_free(struct ae_softc *sc)
1443f85e0762SSepherosa Ziehau {
1444f85e0762SSepherosa Ziehau if (sc->dma_txd_tag != NULL) {
1445f85e0762SSepherosa Ziehau bus_dmamap_unload(sc->dma_txd_tag, sc->dma_txd_map);
1446f85e0762SSepherosa Ziehau bus_dmamem_free(sc->dma_txd_tag, sc->txd_base,
1447f85e0762SSepherosa Ziehau sc->dma_txd_map);
1448f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_txd_tag);
1449f85e0762SSepherosa Ziehau }
1450f85e0762SSepherosa Ziehau if (sc->dma_txs_tag != NULL) {
1451f85e0762SSepherosa Ziehau bus_dmamap_unload(sc->dma_txs_tag, sc->dma_txs_map);
1452f85e0762SSepherosa Ziehau bus_dmamem_free(sc->dma_txs_tag, sc->txs_base,
1453f85e0762SSepherosa Ziehau sc->dma_txs_map);
1454f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_txs_tag);
1455f85e0762SSepherosa Ziehau }
1456f85e0762SSepherosa Ziehau if (sc->dma_rxd_tag != NULL) {
1457f85e0762SSepherosa Ziehau bus_dmamap_unload(sc->dma_rxd_tag, sc->dma_rxd_map);
1458f85e0762SSepherosa Ziehau bus_dmamem_free(sc->dma_rxd_tag,
1459f85e0762SSepherosa Ziehau sc->rxd_base_dma, sc->dma_rxd_map);
1460f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_rxd_tag);
1461f85e0762SSepherosa Ziehau }
1462f85e0762SSepherosa Ziehau if (sc->dma_parent_tag != NULL)
1463f85e0762SSepherosa Ziehau bus_dma_tag_destroy(sc->dma_parent_tag);
1464f85e0762SSepherosa Ziehau }
1465f85e0762SSepherosa Ziehau
1466f85e0762SSepherosa Ziehau static void
ae_pcie_init(struct ae_softc * sc)1467f85e0762SSepherosa Ziehau ae_pcie_init(struct ae_softc *sc)
1468f85e0762SSepherosa Ziehau {
1469f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_PCIE_LTSSM_TESTMODE_REG,
1470f85e0762SSepherosa Ziehau AE_PCIE_LTSSM_TESTMODE_DEFAULT);
1471f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_PCIE_DLL_TX_CTRL_REG,
1472f85e0762SSepherosa Ziehau AE_PCIE_DLL_TX_CTRL_DEFAULT);
1473f85e0762SSepherosa Ziehau }
1474f85e0762SSepherosa Ziehau
1475f85e0762SSepherosa Ziehau static void
ae_phy_reset(struct ae_softc * sc)1476f85e0762SSepherosa Ziehau ae_phy_reset(struct ae_softc *sc)
1477f85e0762SSepherosa Ziehau {
1478f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_PHY_ENABLE_REG, AE_PHY_ENABLE);
1479f85e0762SSepherosa Ziehau DELAY(1000); /* XXX: pause(9) ? */
1480f85e0762SSepherosa Ziehau }
1481f85e0762SSepherosa Ziehau
1482f85e0762SSepherosa Ziehau static int
ae_reset(struct ae_softc * sc)1483f85e0762SSepherosa Ziehau ae_reset(struct ae_softc *sc)
1484f85e0762SSepherosa Ziehau {
1485f85e0762SSepherosa Ziehau int i;
1486f85e0762SSepherosa Ziehau
1487f85e0762SSepherosa Ziehau /*
1488f85e0762SSepherosa Ziehau * Issue a soft reset.
1489f85e0762SSepherosa Ziehau */
1490f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_MASTER_REG, AE_MASTER_SOFT_RESET);
1491f85e0762SSepherosa Ziehau bus_space_barrier(sc->ae_mem_bt, sc->ae_mem_bh, AE_MASTER_REG, 4,
1492f85e0762SSepherosa Ziehau BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
1493f85e0762SSepherosa Ziehau
1494f85e0762SSepherosa Ziehau /*
1495f85e0762SSepherosa Ziehau * Wait for reset to complete.
1496f85e0762SSepherosa Ziehau */
1497f85e0762SSepherosa Ziehau for (i = 0; i < AE_RESET_TIMEOUT; i++) {
1498f85e0762SSepherosa Ziehau if ((AE_READ_4(sc, AE_MASTER_REG) & AE_MASTER_SOFT_RESET) == 0)
1499f85e0762SSepherosa Ziehau break;
1500f85e0762SSepherosa Ziehau DELAY(10);
1501f85e0762SSepherosa Ziehau }
1502f85e0762SSepherosa Ziehau if (i == AE_RESET_TIMEOUT) {
1503f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "reset timeout.\n");
1504f85e0762SSepherosa Ziehau return (ENXIO);
1505f85e0762SSepherosa Ziehau }
1506f85e0762SSepherosa Ziehau
1507f85e0762SSepherosa Ziehau /*
1508f85e0762SSepherosa Ziehau * Wait for everything to enter idle state.
1509f85e0762SSepherosa Ziehau */
1510f85e0762SSepherosa Ziehau for (i = 0; i < AE_IDLE_TIMEOUT; i++) {
1511f85e0762SSepherosa Ziehau if (AE_READ_4(sc, AE_IDLE_REG) == 0)
1512f85e0762SSepherosa Ziehau break;
1513f85e0762SSepherosa Ziehau DELAY(100);
1514f85e0762SSepherosa Ziehau }
1515f85e0762SSepherosa Ziehau if (i == AE_IDLE_TIMEOUT) {
1516f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "could not enter idle state.\n");
1517f85e0762SSepherosa Ziehau return (ENXIO);
1518f85e0762SSepherosa Ziehau }
1519f85e0762SSepherosa Ziehau return (0);
1520f85e0762SSepherosa Ziehau }
1521f85e0762SSepherosa Ziehau
1522f85e0762SSepherosa Ziehau static int
ae_check_eeprom_present(struct ae_softc * sc,int * vpdc)1523f85e0762SSepherosa Ziehau ae_check_eeprom_present(struct ae_softc *sc, int *vpdc)
1524f85e0762SSepherosa Ziehau {
1525f85e0762SSepherosa Ziehau int error;
1526f85e0762SSepherosa Ziehau uint32_t val;
1527f85e0762SSepherosa Ziehau
1528f85e0762SSepherosa Ziehau /*
1529f85e0762SSepherosa Ziehau * Not sure why, but Linux does this.
1530f85e0762SSepherosa Ziehau */
1531f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_SPICTL_REG);
1532f85e0762SSepherosa Ziehau if ((val & AE_SPICTL_VPD_EN) != 0) {
1533f85e0762SSepherosa Ziehau val &= ~AE_SPICTL_VPD_EN;
1534f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_SPICTL_REG, val);
1535f85e0762SSepherosa Ziehau }
1536f85e0762SSepherosa Ziehau error = pci_find_extcap(sc->ae_dev, PCIY_VPD, vpdc);
1537f85e0762SSepherosa Ziehau return (error);
1538f85e0762SSepherosa Ziehau }
1539f85e0762SSepherosa Ziehau
1540f85e0762SSepherosa Ziehau static int
ae_vpd_read_word(struct ae_softc * sc,int reg,uint32_t * word)1541f85e0762SSepherosa Ziehau ae_vpd_read_word(struct ae_softc *sc, int reg, uint32_t *word)
1542f85e0762SSepherosa Ziehau {
1543f85e0762SSepherosa Ziehau uint32_t val;
1544f85e0762SSepherosa Ziehau int i;
1545f85e0762SSepherosa Ziehau
1546f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_VPD_DATA_REG, 0); /* Clear register value. */
1547f85e0762SSepherosa Ziehau
1548f85e0762SSepherosa Ziehau /*
1549f85e0762SSepherosa Ziehau * VPD registers start at offset 0x100. Read them.
1550f85e0762SSepherosa Ziehau */
1551f85e0762SSepherosa Ziehau val = 0x100 + reg * 4;
1552f85e0762SSepherosa Ziehau AE_WRITE_4(sc, AE_VPD_CAP_REG, (val << AE_VPD_CAP_ADDR_SHIFT) &
1553f85e0762SSepherosa Ziehau AE_VPD_CAP_ADDR_MASK);
1554f85e0762SSepherosa Ziehau for (i = 0; i < AE_VPD_TIMEOUT; i++) {
1555f85e0762SSepherosa Ziehau DELAY(2000);
1556f85e0762SSepherosa Ziehau val = AE_READ_4(sc, AE_VPD_CAP_REG);
1557f85e0762SSepherosa Ziehau if ((val & AE_VPD_CAP_DONE) != 0)
1558f85e0762SSepherosa Ziehau break;
1559f85e0762SSepherosa Ziehau }
1560f85e0762SSepherosa Ziehau if (i == AE_VPD_TIMEOUT) {
1561f85e0762SSepherosa Ziehau device_printf(sc->ae_dev, "timeout reading VPD register %d.\n",
1562f85e0762SSepherosa Ziehau reg);
1563f85e0762SSepherosa Ziehau return (ETIMEDOUT);
1564f85e0762SSepherosa Ziehau }
1565f85e0762SSepherosa Ziehau *word = AE_READ_4(sc, AE_VPD_DATA_REG);
1566f85e0762SSepherosa Ziehau return (0);
1567f85e0762SSepherosa Ziehau }
1568f85e0762SSepherosa Ziehau
1569f85e0762SSepherosa Ziehau static int
ae_get_vpd_eaddr(struct ae_softc * sc,uint32_t * eaddr)1570f85e0762SSepherosa Ziehau ae_get_vpd_eaddr(struct ae_softc *sc, uint32_t *eaddr)
1571f85e0762SSepherosa Ziehau {
1572f85e0762SSepherosa Ziehau uint32_t word, reg, val;
1573f85e0762SSepherosa Ziehau int error;
1574f85e0762SSepherosa Ziehau int found;
1575f85e0762SSepherosa Ziehau int vpdc;
1576f85e0762SSepherosa Ziehau int i;
1577f85e0762SSepherosa Ziehau
1578f85e0762SSepherosa Ziehau /*
1579f85e0762SSepherosa Ziehau * Check for EEPROM.
1580f85e0762SSepherosa Ziehau */
1581f85e0762SSepherosa Ziehau error = ae_check_eeprom_present(sc, &vpdc);
1582f85e0762SSepherosa Ziehau if (error != 0)
1583f85e0762SSepherosa Ziehau return (error);
1584f85e0762SSepherosa Ziehau
1585f85e0762SSepherosa Ziehau /*
1586f85e0762SSepherosa Ziehau * Read the VPD configuration space.
1587f85e0762SSepherosa Ziehau * Each register is prefixed with signature,
1588f85e0762SSepherosa Ziehau * so we can check if it is valid.
1589f85e0762SSepherosa Ziehau */
1590f85e0762SSepherosa Ziehau for (i = 0, found = 0; i < AE_VPD_NREGS; i++) {
1591f85e0762SSepherosa Ziehau error = ae_vpd_read_word(sc, i, &word);
1592f85e0762SSepherosa Ziehau if (error != 0)
1593f85e0762SSepherosa Ziehau break;
1594f85e0762SSepherosa Ziehau
1595f85e0762SSepherosa Ziehau /*
1596f85e0762SSepherosa Ziehau * Check signature.
1597f85e0762SSepherosa Ziehau */
1598f85e0762SSepherosa Ziehau if ((word & AE_VPD_SIG_MASK) != AE_VPD_SIG)
1599f85e0762SSepherosa Ziehau break;
1600f85e0762SSepherosa Ziehau reg = word >> AE_VPD_REG_SHIFT;
1601f85e0762SSepherosa Ziehau i++; /* Move to the next word. */
1602f85e0762SSepherosa Ziehau if (reg != AE_EADDR0_REG && reg != AE_EADDR1_REG)
1603f85e0762SSepherosa Ziehau continue;
1604f85e0762SSepherosa Ziehau
1605f85e0762SSepherosa Ziehau error = ae_vpd_read_word(sc, i, &val);
1606f85e0762SSepherosa Ziehau if (error != 0)
1607f85e0762SSepherosa Ziehau break;
1608f85e0762SSepherosa Ziehau if (reg == AE_EADDR0_REG)
1609f85e0762SSepherosa Ziehau eaddr[0] = val;
1610f85e0762SSepherosa Ziehau else
1611f85e0762SSepherosa Ziehau eaddr[1] = val;
1612f85e0762SSepherosa Ziehau found++;
1613f85e0762SSepherosa Ziehau }
1614f85e0762SSepherosa Ziehau if (found < 2)
1615f85e0762SSepherosa Ziehau return (ENOENT);
1616f85e0762SSepherosa Ziehau
1617f85e0762SSepherosa Ziehau eaddr[1] &= 0xffff; /* Only last 2 bytes are used. */
1618f85e0762SSepherosa Ziehau if (AE_CHECK_EADDR_VALID(eaddr) != 0) {
1619f85e0762SSepherosa Ziehau if (bootverbose)
1620f85e0762SSepherosa Ziehau device_printf(sc->ae_dev,
1621f85e0762SSepherosa Ziehau "VPD ethernet address registers are invalid.\n");
1622f85e0762SSepherosa Ziehau return (EINVAL);
1623f85e0762SSepherosa Ziehau }
1624f85e0762SSepherosa Ziehau return (0);
1625f85e0762SSepherosa Ziehau }
1626f85e0762SSepherosa Ziehau
1627f85e0762SSepherosa Ziehau static int
ae_get_reg_eaddr(struct ae_softc * sc,uint32_t * eaddr)1628f85e0762SSepherosa Ziehau ae_get_reg_eaddr(struct ae_softc *sc, uint32_t *eaddr)
1629f85e0762SSepherosa Ziehau {
1630f85e0762SSepherosa Ziehau /*
1631f85e0762SSepherosa Ziehau * BIOS is supposed to set this.
1632f85e0762SSepherosa Ziehau */
1633f85e0762SSepherosa Ziehau eaddr[0] = AE_READ_4(sc, AE_EADDR0_REG);
1634f85e0762SSepherosa Ziehau eaddr[1] = AE_READ_4(sc, AE_EADDR1_REG);
1635f85e0762SSepherosa Ziehau eaddr[1] &= 0xffff; /* Only last 2 bytes are used. */
1636f85e0762SSepherosa Ziehau if (AE_CHECK_EADDR_VALID(eaddr) != 0) {
1637f85e0762SSepherosa Ziehau if (bootverbose)
1638f85e0762SSepherosa Ziehau device_printf(sc->ae_dev,
1639f85e0762SSepherosa Ziehau "Ethetnet address registers are invalid.\n");
1640f85e0762SSepherosa Ziehau return (EINVAL);
1641f85e0762SSepherosa Ziehau }
1642f85e0762SSepherosa Ziehau return (0);
1643f85e0762SSepherosa Ziehau }
1644f85e0762SSepherosa Ziehau
1645f85e0762SSepherosa Ziehau static void
ae_get_eaddr(struct ae_softc * sc)1646f85e0762SSepherosa Ziehau ae_get_eaddr(struct ae_softc *sc)
1647f85e0762SSepherosa Ziehau {
1648f85e0762SSepherosa Ziehau uint32_t eaddr[2] = {0, 0};
1649f85e0762SSepherosa Ziehau int error;
1650f85e0762SSepherosa Ziehau
1651f85e0762SSepherosa Ziehau /*
1652f85e0762SSepherosa Ziehau *Check for EEPROM.
1653f85e0762SSepherosa Ziehau */
1654f85e0762SSepherosa Ziehau error = ae_get_vpd_eaddr(sc, eaddr);
1655f85e0762SSepherosa Ziehau if (error)
1656f85e0762SSepherosa Ziehau error = ae_get_reg_eaddr(sc, eaddr);
1657f85e0762SSepherosa Ziehau if (error) {
1658f85e0762SSepherosa Ziehau if (bootverbose)
1659f85e0762SSepherosa Ziehau device_printf(sc->ae_dev,
1660f85e0762SSepherosa Ziehau "Generating random ethernet address.\n");
1661f85e0762SSepherosa Ziehau eaddr[0] = karc4random();
1662f85e0762SSepherosa Ziehau /*
1663f85e0762SSepherosa Ziehau * Set OUI to ASUSTek COMPUTER INC.
1664f85e0762SSepherosa Ziehau */
1665f85e0762SSepherosa Ziehau sc->ae_eaddr[0] = 0x02; /* U/L bit set. */
1666f85e0762SSepherosa Ziehau sc->ae_eaddr[1] = 0x1f;
1667f85e0762SSepherosa Ziehau sc->ae_eaddr[2] = 0xc6;
1668f85e0762SSepherosa Ziehau sc->ae_eaddr[3] = (eaddr[0] >> 16) & 0xff;
1669f85e0762SSepherosa Ziehau sc->ae_eaddr[4] = (eaddr[0] >> 8) & 0xff;
1670f85e0762SSepherosa Ziehau sc->ae_eaddr[5] = (eaddr[0] >> 0) & 0xff;
1671f85e0762SSepherosa Ziehau } else {
1672f85e0762SSepherosa Ziehau sc->ae_eaddr[0] = (eaddr[1] >> 8) & 0xff;
1673f85e0762SSepherosa Ziehau sc->ae_eaddr[1] = (eaddr[1] >> 0) & 0xff;
1674f85e0762SSepherosa Ziehau sc->ae_eaddr[2] = (eaddr[0] >> 24) & 0xff;
1675f85e0762SSepherosa Ziehau sc->ae_eaddr[3] = (eaddr[0] >> 16) & 0xff;
1676f85e0762SSepherosa Ziehau sc->ae_eaddr[4] = (eaddr[0] >> 8) & 0xff;
1677f85e0762SSepherosa Ziehau sc->ae_eaddr[5] = (eaddr[0] >> 0) & 0xff;
1678f85e0762SSepherosa Ziehau }
1679f85e0762SSepherosa Ziehau }
1680f85e0762SSepherosa Ziehau
1681f85e0762SSepherosa Ziehau static int
ae_mediachange(struct ifnet * ifp)1682f85e0762SSepherosa Ziehau ae_mediachange(struct ifnet *ifp)
1683f85e0762SSepherosa Ziehau {
1684f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc;
1685f85e0762SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->ae_miibus);
1686f85e0762SSepherosa Ziehau int error;
1687f85e0762SSepherosa Ziehau
1688f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer);
1689f85e0762SSepherosa Ziehau if (mii->mii_instance != 0) {
1690f85e0762SSepherosa Ziehau struct mii_softc *miisc;
1691f85e0762SSepherosa Ziehau LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1692f85e0762SSepherosa Ziehau mii_phy_reset(miisc);
1693f85e0762SSepherosa Ziehau }
1694f85e0762SSepherosa Ziehau error = mii_mediachg(mii);
1695f85e0762SSepherosa Ziehau return (error);
1696f85e0762SSepherosa Ziehau }
1697f85e0762SSepherosa Ziehau
1698f85e0762SSepherosa Ziehau static void
ae_mediastatus(struct ifnet * ifp,struct ifmediareq * ifmr)1699f85e0762SSepherosa Ziehau ae_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1700f85e0762SSepherosa Ziehau {
1701f85e0762SSepherosa Ziehau struct ae_softc *sc = ifp->if_softc;
1702f85e0762SSepherosa Ziehau struct mii_data *mii = device_get_softc(sc->ae_miibus);
1703f85e0762SSepherosa Ziehau
1704f85e0762SSepherosa Ziehau ASSERT_SERIALIZED(ifp->if_serializer);
1705f85e0762SSepherosa Ziehau mii_pollstat(mii);
1706f85e0762SSepherosa Ziehau ifmr->ifm_status = mii->mii_media_status;
1707f85e0762SSepherosa Ziehau ifmr->ifm_active = mii->mii_media_active;
1708f85e0762SSepherosa Ziehau }
1709f85e0762SSepherosa Ziehau
1710f85e0762SSepherosa Ziehau static void
ae_update_stats_tx(uint16_t flags,struct ae_stats * stats)1711f85e0762SSepherosa Ziehau ae_update_stats_tx(uint16_t flags, struct ae_stats *stats)
1712f85e0762SSepherosa Ziehau {
1713f85e0762SSepherosa Ziehau if ((flags & AE_TXS_BCAST) != 0)
1714f85e0762SSepherosa Ziehau stats->tx_bcast++;
1715f85e0762SSepherosa Ziehau if ((flags & AE_TXS_MCAST) != 0)
1716f85e0762SSepherosa Ziehau stats->tx_mcast++;
1717f85e0762SSepherosa Ziehau if ((flags & AE_TXS_PAUSE) != 0)
1718f85e0762SSepherosa Ziehau stats->tx_pause++;
1719f85e0762SSepherosa Ziehau if ((flags & AE_TXS_CTRL) != 0)
1720f85e0762SSepherosa Ziehau stats->tx_ctrl++;
1721f85e0762SSepherosa Ziehau if ((flags & AE_TXS_DEFER) != 0)
1722f85e0762SSepherosa Ziehau stats->tx_defer++;
1723f85e0762SSepherosa Ziehau if ((flags & AE_TXS_EXCDEFER) != 0)
1724f85e0762SSepherosa Ziehau stats->tx_excdefer++;
1725f85e0762SSepherosa Ziehau if ((flags & AE_TXS_SINGLECOL) != 0)
1726f85e0762SSepherosa Ziehau stats->tx_singlecol++;
1727f85e0762SSepherosa Ziehau if ((flags & AE_TXS_MULTICOL) != 0)
1728f85e0762SSepherosa Ziehau stats->tx_multicol++;
1729f85e0762SSepherosa Ziehau if ((flags & AE_TXS_LATECOL) != 0)
1730f85e0762SSepherosa Ziehau stats->tx_latecol++;
1731f85e0762SSepherosa Ziehau if ((flags & AE_TXS_ABORTCOL) != 0)
1732f85e0762SSepherosa Ziehau stats->tx_abortcol++;
1733f85e0762SSepherosa Ziehau if ((flags & AE_TXS_UNDERRUN) != 0)
1734f85e0762SSepherosa Ziehau stats->tx_underrun++;
1735f85e0762SSepherosa Ziehau }
1736f85e0762SSepherosa Ziehau
1737f85e0762SSepherosa Ziehau static void
ae_update_stats_rx(uint16_t flags,struct ae_stats * stats)1738f85e0762SSepherosa Ziehau ae_update_stats_rx(uint16_t flags, struct ae_stats *stats)
1739f85e0762SSepherosa Ziehau {
1740f85e0762SSepherosa Ziehau if ((flags & AE_RXD_BCAST) != 0)
1741f85e0762SSepherosa Ziehau stats->rx_bcast++;
1742f85e0762SSepherosa Ziehau if ((flags & AE_RXD_MCAST) != 0)
1743f85e0762SSepherosa Ziehau stats->rx_mcast++;
1744f85e0762SSepherosa Ziehau if ((flags & AE_RXD_PAUSE) != 0)
1745f85e0762SSepherosa Ziehau stats->rx_pause++;
1746f85e0762SSepherosa Ziehau if ((flags & AE_RXD_CTRL) != 0)
1747f85e0762SSepherosa Ziehau stats->rx_ctrl++;
1748f85e0762SSepherosa Ziehau if ((flags & AE_RXD_CRCERR) != 0)
1749f85e0762SSepherosa Ziehau stats->rx_crcerr++;
1750f85e0762SSepherosa Ziehau if ((flags & AE_RXD_CODEERR) != 0)
1751f85e0762SSepherosa Ziehau stats->rx_codeerr++;
1752f85e0762SSepherosa Ziehau if ((flags & AE_RXD_RUNT) != 0)
1753f85e0762SSepherosa Ziehau stats->rx_runt++;
1754f85e0762SSepherosa Ziehau if ((flags & AE_RXD_FRAG) != 0)
1755f85e0762SSepherosa Ziehau stats->rx_frag++;
1756f85e0762SSepherosa Ziehau if ((flags & AE_RXD_TRUNC) != 0)
1757f85e0762SSepherosa Ziehau stats->rx_trunc++;
1758f85e0762SSepherosa Ziehau if ((flags & AE_RXD_ALIGN) != 0)
1759f85e0762SSepherosa Ziehau stats->rx_align++;
1760f85e0762SSepherosa Ziehau }
1761f85e0762SSepherosa Ziehau
1762f85e0762SSepherosa Ziehau static int
ae_resume(device_t dev)1763f85e0762SSepherosa Ziehau ae_resume(device_t dev)
1764f85e0762SSepherosa Ziehau {
1765f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev);
1766f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
1767f85e0762SSepherosa Ziehau
1768f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer);
1769f85e0762SSepherosa Ziehau #if 0
1770f85e0762SSepherosa Ziehau AE_READ_4(sc, AE_WOL_REG); /* Clear WOL status. */
1771f85e0762SSepherosa Ziehau #endif
177297c1b3a4SSepherosa Ziehau ae_phy_reset(sc);
1773f85e0762SSepherosa Ziehau if ((ifp->if_flags & IFF_UP) != 0)
1774f85e0762SSepherosa Ziehau ae_init(sc);
1775f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer);
1776f85e0762SSepherosa Ziehau return (0);
1777f85e0762SSepherosa Ziehau }
1778f85e0762SSepherosa Ziehau
1779f85e0762SSepherosa Ziehau static int
ae_suspend(device_t dev)1780f85e0762SSepherosa Ziehau ae_suspend(device_t dev)
1781f85e0762SSepherosa Ziehau {
1782f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev);
1783f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
1784f85e0762SSepherosa Ziehau
1785f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer);
1786f85e0762SSepherosa Ziehau ae_stop(sc);
1787f85e0762SSepherosa Ziehau #if 0
1788f85e0762SSepherosa Ziehau /* we don't use ae_pm_init because we don't want WOL */
1789f85e0762SSepherosa Ziehau ae_pm_init(sc);
1790f85e0762SSepherosa Ziehau #endif
1791f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer);
1792f85e0762SSepherosa Ziehau return (0);
1793f85e0762SSepherosa Ziehau }
1794f85e0762SSepherosa Ziehau
1795f85e0762SSepherosa Ziehau static int
ae_shutdown(device_t dev)1796f85e0762SSepherosa Ziehau ae_shutdown(device_t dev)
1797f85e0762SSepherosa Ziehau {
1798f85e0762SSepherosa Ziehau struct ae_softc *sc = device_get_softc(dev);
1799f85e0762SSepherosa Ziehau struct ifnet *ifp = &sc->arpcom.ac_if;
1800f85e0762SSepherosa Ziehau
1801f85e0762SSepherosa Ziehau ae_suspend(dev);
1802f85e0762SSepherosa Ziehau
1803f85e0762SSepherosa Ziehau lwkt_serialize_enter(ifp->if_serializer);
1804f85e0762SSepherosa Ziehau ae_powersave_enable(sc);
1805f85e0762SSepherosa Ziehau lwkt_serialize_exit(ifp->if_serializer);
1806f85e0762SSepherosa Ziehau
1807f85e0762SSepherosa Ziehau return (0);
1808f85e0762SSepherosa Ziehau }
1809f85e0762SSepherosa Ziehau
1810f85e0762SSepherosa Ziehau static void
ae_powersave_disable(struct ae_softc * sc)1811f85e0762SSepherosa Ziehau ae_powersave_disable(struct ae_softc *sc)
1812f85e0762SSepherosa Ziehau {
1813f85e0762SSepherosa Ziehau uint32_t val;
1814f85e0762SSepherosa Ziehau
1815f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 0);
1816f85e0762SSepherosa Ziehau val = AE_PHY_READ(sc, AE_PHY_DBG_DATA);
1817f85e0762SSepherosa Ziehau if (val & AE_PHY_DBG_POWERSAVE) {
1818f85e0762SSepherosa Ziehau val &= ~AE_PHY_DBG_POWERSAVE;
1819f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, val);
1820f85e0762SSepherosa Ziehau DELAY(1000);
1821f85e0762SSepherosa Ziehau }
1822f85e0762SSepherosa Ziehau }
1823f85e0762SSepherosa Ziehau
1824f85e0762SSepherosa Ziehau static void
ae_powersave_enable(struct ae_softc * sc)1825f85e0762SSepherosa Ziehau ae_powersave_enable(struct ae_softc *sc)
1826f85e0762SSepherosa Ziehau {
1827f85e0762SSepherosa Ziehau uint32_t val;
1828f85e0762SSepherosa Ziehau
1829f85e0762SSepherosa Ziehau /*
1830f85e0762SSepherosa Ziehau * XXX magic numbers.
1831f85e0762SSepherosa Ziehau */
1832f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 0);
1833f85e0762SSepherosa Ziehau val = AE_PHY_READ(sc, AE_PHY_DBG_DATA);
1834f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, val | 0x1000);
1835f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 2);
1836f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, 0x3000);
1837f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_ADDR, 3);
1838f85e0762SSepherosa Ziehau AE_PHY_WRITE(sc, AE_PHY_DBG_DATA, 0);
1839f85e0762SSepherosa Ziehau }
1840