sun4i_emac.c revision 1.2.2.2 1 1.2.2.2 jdolecek /* $NetBSD: sun4i_emac.c,v 1.2.2.2 2017/12/03 11:35:56 jdolecek Exp $ */
2 1.2.2.2 jdolecek
3 1.2.2.2 jdolecek /*-
4 1.2.2.2 jdolecek * Copyright (c) 2013-2017 The NetBSD Foundation, Inc.
5 1.2.2.2 jdolecek * All rights reserved.
6 1.2.2.2 jdolecek *
7 1.2.2.2 jdolecek * This code is derived from software contributed to The NetBSD Foundation
8 1.2.2.2 jdolecek * by Matt Thomas of 3am Software Foundry and Jared McNeill.
9 1.2.2.2 jdolecek *
10 1.2.2.2 jdolecek * Redistribution and use in source and binary forms, with or without
11 1.2.2.2 jdolecek * modification, are permitted provided that the following conditions
12 1.2.2.2 jdolecek * are met:
13 1.2.2.2 jdolecek * 1. Redistributions of source code must retain the above copyright
14 1.2.2.2 jdolecek * notice, this list of conditions and the following disclaimer.
15 1.2.2.2 jdolecek * 2. Redistributions in binary form must reproduce the above copyright
16 1.2.2.2 jdolecek * notice, this list of conditions and the following disclaimer in the
17 1.2.2.2 jdolecek * documentation and/or other materials provided with the distribution.
18 1.2.2.2 jdolecek *
19 1.2.2.2 jdolecek * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.2.2.2 jdolecek * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.2.2.2 jdolecek * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.2.2.2 jdolecek * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.2.2.2 jdolecek * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.2.2.2 jdolecek * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.2.2.2 jdolecek * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.2.2.2 jdolecek * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.2.2.2 jdolecek * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.2.2.2 jdolecek * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.2.2.2 jdolecek * POSSIBILITY OF SUCH DAMAGE.
30 1.2.2.2 jdolecek */
31 1.2.2.2 jdolecek
32 1.2.2.2 jdolecek #include <sys/cdefs.h>
33 1.2.2.2 jdolecek
34 1.2.2.2 jdolecek __KERNEL_RCSID(1, "$NetBSD: sun4i_emac.c,v 1.2.2.2 2017/12/03 11:35:56 jdolecek Exp $");
35 1.2.2.2 jdolecek
36 1.2.2.2 jdolecek #include <sys/param.h>
37 1.2.2.2 jdolecek #include <sys/bus.h>
38 1.2.2.2 jdolecek #include <sys/device.h>
39 1.2.2.2 jdolecek #include <sys/intr.h>
40 1.2.2.2 jdolecek #include <sys/ioctl.h>
41 1.2.2.2 jdolecek #include <sys/mutex.h>
42 1.2.2.2 jdolecek #include <sys/rndsource.h>
43 1.2.2.2 jdolecek #include <sys/kernel.h>
44 1.2.2.2 jdolecek #include <sys/systm.h>
45 1.2.2.2 jdolecek
46 1.2.2.2 jdolecek #include <net/bpf.h>
47 1.2.2.2 jdolecek #include <net/if.h>
48 1.2.2.2 jdolecek #include <net/if_dl.h>
49 1.2.2.2 jdolecek #include <net/if_ether.h>
50 1.2.2.2 jdolecek #include <net/if_media.h>
51 1.2.2.2 jdolecek
52 1.2.2.2 jdolecek #include <dev/mii/miivar.h>
53 1.2.2.2 jdolecek
54 1.2.2.2 jdolecek #include <dev/fdt/fdtvar.h>
55 1.2.2.2 jdolecek
56 1.2.2.2 jdolecek #include <arm/sunxi/sunxi_sramc.h>
57 1.2.2.2 jdolecek
58 1.2.2.2 jdolecek #define EMAC_IFNAME "emac%d"
59 1.2.2.2 jdolecek
60 1.2.2.2 jdolecek #define EMAC_CTL_REG 0x00
61 1.2.2.2 jdolecek #define EMAC_CTL_RX_EN __BIT(2)
62 1.2.2.2 jdolecek #define EMAC_CTL_TX_EN __BIT(1)
63 1.2.2.2 jdolecek #define EMAC_CTL_RST __BIT(0)
64 1.2.2.2 jdolecek #define EMAC_TX_MODE_REG 0x04
65 1.2.2.2 jdolecek #define EMAC_TX_MODE_DMA __BIT(1)
66 1.2.2.2 jdolecek #define EMAC_TX_MODE_ABF_ENA __BIT(0)
67 1.2.2.2 jdolecek #define EMAC_TX_FLOW_REG 0x08
68 1.2.2.2 jdolecek #define EMAC_TX_CTL0_REG 0x0c
69 1.2.2.2 jdolecek #define EMAC_TX_CTL1_REG 0x10
70 1.2.2.2 jdolecek #define EMAC_TX_CTL_REG(n) (EMAC_TX_CTL0_REG+4*(n))
71 1.2.2.2 jdolecek #define EMAC_TX_CTL_START __BIT(0)
72 1.2.2.2 jdolecek #define EMAC_TX_INS_REG 0x14
73 1.2.2.2 jdolecek #define EMAC_TX_PL0_REG 0x18
74 1.2.2.2 jdolecek #define EMAC_TX_PL1_REG 0x1c
75 1.2.2.2 jdolecek #define EMAC_TX_PL_REG(n) (EMAC_TX_PL0_REG+4*(n))
76 1.2.2.2 jdolecek #define EMAC_TX_STA_REG 0x20
77 1.2.2.2 jdolecek #define EMAC_TX_IO_DATA0_REG 0x24
78 1.2.2.2 jdolecek #define EMAC_TX_IO_DATA1_REG 0x28
79 1.2.2.2 jdolecek #define EMAC_TX_IO_DATA_REG(n) (EMAC_TX_IO_DATA0_REG+4*(n))
80 1.2.2.2 jdolecek #define EMAC_TX_TSVL0_REG 0x2c
81 1.2.2.2 jdolecek #define EMAC_TX_TSVH0_REG 0x30
82 1.2.2.2 jdolecek #define EMAC_TX_TSVL1_REG 0x34
83 1.2.2.2 jdolecek #define EMAC_TX_TSVH1_REG 0x38
84 1.2.2.2 jdolecek #define EMAC_RX_CTL_REG 0x3c
85 1.2.2.2 jdolecek #define EMAC_RX_CTL_SA_IF __BIT(25)
86 1.2.2.2 jdolecek #define EMAC_RX_CTL_SA __BIT(24)
87 1.2.2.2 jdolecek #define EMAC_RX_CTL_BC0 __BIT(22)
88 1.2.2.2 jdolecek #define EMAC_RX_CTL_MHF __BIT(21)
89 1.2.2.2 jdolecek #define EMAC_RX_CTL_MC0 __BIT(20)
90 1.2.2.2 jdolecek #define EMAC_RX_CTL_DAF __BIT(17)
91 1.2.2.2 jdolecek #define EMAC_RX_CTL_UCAD __BIT(16)
92 1.2.2.2 jdolecek #define EMAC_RX_CTL_POR __BIT(8)
93 1.2.2.2 jdolecek #define EMAC_RX_CTL_PLE __BIT(7)
94 1.2.2.2 jdolecek #define EMAC_RX_CTL_PCRCE __BIT(6)
95 1.2.2.2 jdolecek #define EMAC_RX_CTL_PCF __BIT(5)
96 1.2.2.2 jdolecek #define EMAC_RX_CTL_PROMISC __BIT(4)
97 1.2.2.2 jdolecek #define EMAC_RX_CTL_FIFO_RESET __BIT(3)
98 1.2.2.2 jdolecek #define EMAC_RX_CTL_DMA __BIT(2)
99 1.2.2.2 jdolecek #define EMAC_RX_CTL_DRQ_MODE __BIT(1)
100 1.2.2.2 jdolecek #define EMAC_RX_CTL_START __BIT(0)
101 1.2.2.2 jdolecek #define EMAC_RX_HASH0_REG 0x40
102 1.2.2.2 jdolecek #define EMAC_RX_HASH1_REG 0x44
103 1.2.2.2 jdolecek #define EMAC_RX_STA_REG 0x48
104 1.2.2.2 jdolecek #define EMAC_RX_STA_PKTOK __BIT(7)
105 1.2.2.2 jdolecek #define EMAC_RX_STA_ALNERR __BIT(6)
106 1.2.2.2 jdolecek #define EMAC_RX_STA_LENERR __BIT(5)
107 1.2.2.2 jdolecek #define EMAC_RX_STA_CRCERR __BIT(4)
108 1.2.2.2 jdolecek #define EMAC_RX_IO_DATA_REG 0x4c
109 1.2.2.2 jdolecek #define EMAC_RX_FBC_REG 0x50
110 1.2.2.2 jdolecek #define EMAC_INT_CTL_REG 0x54
111 1.2.2.2 jdolecek #define EMAC_INT_STA_REG 0x58
112 1.2.2.2 jdolecek #define EMAC_INT_RX __BIT(8)
113 1.2.2.2 jdolecek #define EMAC_INT_TX1 __BIT(1)
114 1.2.2.2 jdolecek #define EMAC_INT_TX0 __BIT(0)
115 1.2.2.2 jdolecek #define EMAC_INT_ENABLE \
116 1.2.2.2 jdolecek (EMAC_INT_RX|EMAC_INT_TX1|EMAC_INT_TX0)
117 1.2.2.2 jdolecek #define EMAC_MAC_CTL0_REG 0x5c
118 1.2.2.2 jdolecek #define EMAC_MAC_CTL0_SOFT_RESET __BIT(15)
119 1.2.2.2 jdolecek #define EMAC_MAC_CTL0_TFC __BIT(3)
120 1.2.2.2 jdolecek #define EMAC_MAC_CTL0_RFC __BIT(2)
121 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_REG 0x60
122 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_ED __BIT(15)
123 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_NB __BIT(13)
124 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_BNB __BIT(12)
125 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_LPE __BIT(9)
126 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_PRE __BIT(8)
127 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_ADP __BIT(7)
128 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_VC __BIT(6)
129 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_PC __BIT(5)
130 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_CRC __BIT(4)
131 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_DCRC __BIT(3)
132 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_HF __BIT(2)
133 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_FLC __BIT(1)
134 1.2.2.2 jdolecek #define EMAC_MAC_CTL1_FD __BIT(0)
135 1.2.2.2 jdolecek #define EMAC_MAC_IPGT_REG 0x64
136 1.2.2.2 jdolecek #define EMAC_MAC_IPGT_FD 0x15
137 1.2.2.2 jdolecek #define EMAC_MAC_IPGR_REG 0x68
138 1.2.2.2 jdolecek #define EMAC_MAC_IPGR_IPG1 __BITS(15,8)
139 1.2.2.2 jdolecek #define EMAC_MAC_IPGR_IPG2 __BITS(7,0)
140 1.2.2.2 jdolecek #define EMAC_MAC_CLRT_REG 0x6c
141 1.2.2.2 jdolecek #define EMAC_MAC_CLRT_CW __BITS(15,8)
142 1.2.2.2 jdolecek #define EMAC_MAC_CLRT_RM __BITS(7,0)
143 1.2.2.2 jdolecek #define EMAC_MAC_MAXF_REG 0x70
144 1.2.2.2 jdolecek #define EMAC_MAC_SUPP_REG 0x74
145 1.2.2.2 jdolecek #define EMAC_MAC_SUPP_100M __BIT(8)
146 1.2.2.2 jdolecek #define EMAC_MAC_TEST_REG 0x78
147 1.2.2.2 jdolecek #define EMAC_MAC_MCFG_REG 0x7c
148 1.2.2.2 jdolecek #define EMAC_MAC_MCFG_CLK __BITS(5,2)
149 1.2.2.2 jdolecek #define EMAC_MAC_MCMD_REG 0x80
150 1.2.2.2 jdolecek #define EMAC_MAC_MADR_REG 0x84
151 1.2.2.2 jdolecek #define EMAC_MAC_MWTD_REG 0x88
152 1.2.2.2 jdolecek #define EMAC_MAC_MRDD_REG 0x8c
153 1.2.2.2 jdolecek #define EMAC_MAC_MIND_REG 0x90
154 1.2.2.2 jdolecek #define EMAC_MAC_SSRR_REG 0x94
155 1.2.2.2 jdolecek #define EMAC_MAC_A0_REG 0x98
156 1.2.2.2 jdolecek #define EMAC_MAC_A1_REG 0x9c
157 1.2.2.2 jdolecek #define EMAC_MAC_A2_REG 0xa0
158 1.2.2.2 jdolecek
159 1.2.2.2 jdolecek #define EMAC_RXHDR_STS __BITS(31,16)
160 1.2.2.2 jdolecek #define EMAC_RXHDR_LEN __BITS(15,0)
161 1.2.2.2 jdolecek
162 1.2.2.2 jdolecek #define EMAC_RX_MAGIC 0x0143414d /* M A C \001 */
163 1.2.2.2 jdolecek
164 1.2.2.2 jdolecek #define EMAC_TXBUF_SIZE 4096
165 1.2.2.2 jdolecek
166 1.2.2.2 jdolecek static int sun4i_emac_match(device_t, cfdata_t, void *);
167 1.2.2.2 jdolecek static void sun4i_emac_attach(device_t, device_t, void *);
168 1.2.2.2 jdolecek
169 1.2.2.2 jdolecek static int sun4i_emac_intr(void *);
170 1.2.2.2 jdolecek static void sun4i_emac_tick(void *);
171 1.2.2.2 jdolecek
172 1.2.2.2 jdolecek static int sun4i_emac_miibus_read_reg(device_t, int, int);
173 1.2.2.2 jdolecek static void sun4i_emac_miibus_write_reg(device_t, int, int, int);
174 1.2.2.2 jdolecek static void sun4i_emac_miibus_statchg(struct ifnet *);
175 1.2.2.2 jdolecek
176 1.2.2.2 jdolecek static void sun4i_emac_ifstart(struct ifnet *);
177 1.2.2.2 jdolecek static int sun4i_emac_ifioctl(struct ifnet *, u_long, void *);
178 1.2.2.2 jdolecek static int sun4i_emac_ifinit(struct ifnet *);
179 1.2.2.2 jdolecek static void sun4i_emac_ifstop(struct ifnet *, int);
180 1.2.2.2 jdolecek static void sun4i_emac_ifwatchdog(struct ifnet *);
181 1.2.2.2 jdolecek
182 1.2.2.2 jdolecek struct sun4i_emac_softc;
183 1.2.2.2 jdolecek static void sun4i_emac_rx_hash(struct sun4i_emac_softc *);
184 1.2.2.2 jdolecek
185 1.2.2.2 jdolecek struct sun4i_emac_softc {
186 1.2.2.2 jdolecek device_t sc_dev;
187 1.2.2.2 jdolecek int sc_phandle;
188 1.2.2.2 jdolecek bus_space_tag_t sc_bst;
189 1.2.2.2 jdolecek bus_space_handle_t sc_bsh;
190 1.2.2.2 jdolecek bus_dma_tag_t sc_dmat;
191 1.2.2.2 jdolecek struct ethercom sc_ec;
192 1.2.2.2 jdolecek struct mii_data sc_mii;
193 1.2.2.2 jdolecek krndsource_t sc_rnd_source; /* random source */
194 1.2.2.2 jdolecek kmutex_t sc_intr_lock;
195 1.2.2.2 jdolecek uint8_t sc_tx_active;
196 1.2.2.2 jdolecek callout_t sc_stat_ch;
197 1.2.2.2 jdolecek void *sc_ih;
198 1.2.2.2 jdolecek uint32_t sc_txbuf[EMAC_TXBUF_SIZE/4];
199 1.2.2.2 jdolecek };
200 1.2.2.2 jdolecek
201 1.2.2.2 jdolecek static const char * compatible[] = {
202 1.2.2.2 jdolecek "allwinner,sun4i-a10-emac",
203 1.2.2.2 jdolecek NULL
204 1.2.2.2 jdolecek };
205 1.2.2.2 jdolecek
206 1.2.2.2 jdolecek CFATTACH_DECL_NEW(sun4i_emac, sizeof(struct sun4i_emac_softc),
207 1.2.2.2 jdolecek sun4i_emac_match, sun4i_emac_attach, NULL, NULL);
208 1.2.2.2 jdolecek
209 1.2.2.2 jdolecek static inline uint32_t
210 1.2.2.2 jdolecek sun4i_emac_read(struct sun4i_emac_softc *sc, bus_size_t o)
211 1.2.2.2 jdolecek {
212 1.2.2.2 jdolecek return bus_space_read_4(sc->sc_bst, sc->sc_bsh, o);
213 1.2.2.2 jdolecek }
214 1.2.2.2 jdolecek
215 1.2.2.2 jdolecek static inline void
216 1.2.2.2 jdolecek sun4i_emac_write(struct sun4i_emac_softc *sc, bus_size_t o, uint32_t v)
217 1.2.2.2 jdolecek {
218 1.2.2.2 jdolecek return bus_space_write_4(sc->sc_bst, sc->sc_bsh, o, v);
219 1.2.2.2 jdolecek }
220 1.2.2.2 jdolecek
221 1.2.2.2 jdolecek static inline void
222 1.2.2.2 jdolecek sun4i_emac_clear_set(struct sun4i_emac_softc *sc, bus_size_t o, uint32_t c,
223 1.2.2.2 jdolecek uint32_t s)
224 1.2.2.2 jdolecek {
225 1.2.2.2 jdolecek uint32_t v = bus_space_read_4(sc->sc_bst, sc->sc_bsh, o);
226 1.2.2.2 jdolecek return bus_space_write_4(sc->sc_bst, sc->sc_bsh, o, (v & ~c) | s);
227 1.2.2.2 jdolecek }
228 1.2.2.2 jdolecek
229 1.2.2.2 jdolecek static int
230 1.2.2.2 jdolecek sun4i_emac_match(device_t parent, cfdata_t cf, void *aux)
231 1.2.2.2 jdolecek {
232 1.2.2.2 jdolecek struct fdt_attach_args * const faa = aux;
233 1.2.2.2 jdolecek
234 1.2.2.2 jdolecek return of_match_compatible(faa->faa_phandle, compatible);
235 1.2.2.2 jdolecek }
236 1.2.2.2 jdolecek
237 1.2.2.2 jdolecek static void
238 1.2.2.2 jdolecek sun4i_emac_attach(device_t parent, device_t self, void *aux)
239 1.2.2.2 jdolecek {
240 1.2.2.2 jdolecek struct sun4i_emac_softc * const sc = device_private(self);
241 1.2.2.2 jdolecek struct fdt_attach_args * const faa = aux;
242 1.2.2.2 jdolecek struct ifnet * const ifp = &sc->sc_ec.ec_if;
243 1.2.2.2 jdolecek struct mii_data * const mii = &sc->sc_mii;
244 1.2.2.2 jdolecek const int phandle = faa->faa_phandle;
245 1.2.2.2 jdolecek char enaddr[ETHER_ADDR_LEN];
246 1.2.2.2 jdolecek const uint8_t *local_addr;
247 1.2.2.2 jdolecek char intrstr[128];
248 1.2.2.2 jdolecek struct clk *clk;
249 1.2.2.2 jdolecek bus_addr_t addr;
250 1.2.2.2 jdolecek bus_size_t size;
251 1.2.2.2 jdolecek int len;
252 1.2.2.2 jdolecek
253 1.2.2.2 jdolecek if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
254 1.2.2.2 jdolecek aprint_error(": cannot get registers\n");
255 1.2.2.2 jdolecek return;
256 1.2.2.2 jdolecek }
257 1.2.2.2 jdolecek
258 1.2.2.2 jdolecek if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
259 1.2.2.2 jdolecek aprint_error(": cannot decode interrupt\n");
260 1.2.2.2 jdolecek return;
261 1.2.2.2 jdolecek }
262 1.2.2.2 jdolecek
263 1.2.2.2 jdolecek clk = fdtbus_clock_get_index(phandle, 0);
264 1.2.2.2 jdolecek if (clk == NULL) {
265 1.2.2.2 jdolecek aprint_error(": cannot acquire clock\n");
266 1.2.2.2 jdolecek return;
267 1.2.2.2 jdolecek }
268 1.2.2.2 jdolecek if (clk_enable(clk) != 0) {
269 1.2.2.2 jdolecek aprint_error(": cannot enable clock\n");
270 1.2.2.2 jdolecek return;
271 1.2.2.2 jdolecek }
272 1.2.2.2 jdolecek
273 1.2.2.2 jdolecek if (sunxi_sramc_claim(phandle) != 0) {
274 1.2.2.2 jdolecek aprint_error(": cannot map SRAM to EMAC\n");
275 1.2.2.2 jdolecek return;
276 1.2.2.2 jdolecek }
277 1.2.2.2 jdolecek
278 1.2.2.2 jdolecek sc->sc_dev = self;
279 1.2.2.2 jdolecek sc->sc_phandle = phandle;
280 1.2.2.2 jdolecek sc->sc_ec.ec_mii = mii;
281 1.2.2.2 jdolecek sc->sc_bst = faa->faa_bst;
282 1.2.2.2 jdolecek if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
283 1.2.2.2 jdolecek aprint_error(": cannot map registers\n");
284 1.2.2.2 jdolecek return;
285 1.2.2.2 jdolecek }
286 1.2.2.2 jdolecek sc->sc_dmat = faa->faa_dmat;
287 1.2.2.2 jdolecek
288 1.2.2.2 jdolecek mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_NET);
289 1.2.2.2 jdolecek callout_init(&sc->sc_stat_ch, 0);
290 1.2.2.2 jdolecek callout_setfunc(&sc->sc_stat_ch, sun4i_emac_tick, sc);
291 1.2.2.2 jdolecek
292 1.2.2.2 jdolecek aprint_naive("\n");
293 1.2.2.2 jdolecek aprint_normal(": 10/100 Ethernet Controller\n");
294 1.2.2.2 jdolecek
295 1.2.2.2 jdolecek /*
296 1.2.2.2 jdolecek * Disable and then clear all interrupts
297 1.2.2.2 jdolecek */
298 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_INT_CTL_REG, 0);
299 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_INT_STA_REG,
300 1.2.2.2 jdolecek sun4i_emac_read(sc, EMAC_INT_STA_REG));
301 1.2.2.2 jdolecek
302 1.2.2.2 jdolecek sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_NET, 0,
303 1.2.2.2 jdolecek sun4i_emac_intr, sc);
304 1.2.2.2 jdolecek if (sc->sc_ih == NULL) {
305 1.2.2.2 jdolecek aprint_error_dev(self, "failed to establish interrupt on %s\n",
306 1.2.2.2 jdolecek intrstr);
307 1.2.2.2 jdolecek return;
308 1.2.2.2 jdolecek }
309 1.2.2.2 jdolecek aprint_normal_dev(self, "interrupting on %s\n", intrstr);
310 1.2.2.2 jdolecek
311 1.2.2.2 jdolecek local_addr = fdtbus_get_prop(phandle, "local-mac-address", &len);
312 1.2.2.2 jdolecek if (local_addr && len == ETHER_ADDR_LEN) {
313 1.2.2.2 jdolecek memcpy(enaddr, local_addr, ETHER_ADDR_LEN);
314 1.2.2.2 jdolecek
315 1.2.2.2 jdolecek uint32_t a1 = ((uint32_t)enaddr[0] << 16) |
316 1.2.2.2 jdolecek ((uint32_t)enaddr[1] << 8) |
317 1.2.2.2 jdolecek (uint32_t)enaddr[2];
318 1.2.2.2 jdolecek uint32_t a0 = ((uint32_t)enaddr[3] << 16) |
319 1.2.2.2 jdolecek ((uint32_t)enaddr[4] << 8) |
320 1.2.2.2 jdolecek (uint32_t)enaddr[5];
321 1.2.2.2 jdolecek
322 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_A1_REG, a1);
323 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_A0_REG, a0);
324 1.2.2.2 jdolecek }
325 1.2.2.2 jdolecek
326 1.2.2.2 jdolecek uint32_t a1 = sun4i_emac_read(sc, EMAC_MAC_A1_REG);
327 1.2.2.2 jdolecek uint32_t a0 = sun4i_emac_read(sc, EMAC_MAC_A0_REG);
328 1.2.2.2 jdolecek if (a0 != 0 || a1 != 0) {
329 1.2.2.2 jdolecek enaddr[0] = a1 >> 16;
330 1.2.2.2 jdolecek enaddr[1] = a1 >> 8;
331 1.2.2.2 jdolecek enaddr[2] = a1 >> 0;
332 1.2.2.2 jdolecek enaddr[3] = a0 >> 16;
333 1.2.2.2 jdolecek enaddr[4] = a0 >> 8;
334 1.2.2.2 jdolecek enaddr[5] = a0 >> 0;
335 1.2.2.2 jdolecek }
336 1.2.2.2 jdolecek aprint_normal_dev(self, "Ethernet address: %s\n", ether_sprintf(enaddr));
337 1.2.2.2 jdolecek
338 1.2.2.2 jdolecek snprintf(ifp->if_xname, IFNAMSIZ, EMAC_IFNAME, device_unit(self));
339 1.2.2.2 jdolecek ifp->if_softc = sc;
340 1.2.2.2 jdolecek ifp->if_capabilities = 0;
341 1.2.2.2 jdolecek ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
342 1.2.2.2 jdolecek ifp->if_start = sun4i_emac_ifstart;
343 1.2.2.2 jdolecek ifp->if_ioctl = sun4i_emac_ifioctl;
344 1.2.2.2 jdolecek ifp->if_init = sun4i_emac_ifinit;
345 1.2.2.2 jdolecek ifp->if_stop = sun4i_emac_ifstop;
346 1.2.2.2 jdolecek ifp->if_watchdog = sun4i_emac_ifwatchdog;
347 1.2.2.2 jdolecek IFQ_SET_READY(&ifp->if_snd);
348 1.2.2.2 jdolecek
349 1.2.2.2 jdolecek /* 802.1Q VLAN-sized frames are supported */
350 1.2.2.2 jdolecek sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
351 1.2.2.2 jdolecek
352 1.2.2.2 jdolecek ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
353 1.2.2.2 jdolecek
354 1.2.2.2 jdolecek mii->mii_ifp = ifp;
355 1.2.2.2 jdolecek mii->mii_readreg = sun4i_emac_miibus_read_reg;
356 1.2.2.2 jdolecek mii->mii_writereg = sun4i_emac_miibus_write_reg;
357 1.2.2.2 jdolecek mii->mii_statchg = sun4i_emac_miibus_statchg;
358 1.2.2.2 jdolecek
359 1.2.2.2 jdolecek mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
360 1.2.2.2 jdolecek
361 1.2.2.2 jdolecek if (LIST_EMPTY(&mii->mii_phys)) {
362 1.2.2.2 jdolecek aprint_error_dev(self, "no PHY found!\n");
363 1.2.2.2 jdolecek ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
364 1.2.2.2 jdolecek ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_MANUAL);
365 1.2.2.2 jdolecek } else {
366 1.2.2.2 jdolecek ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO);
367 1.2.2.2 jdolecek }
368 1.2.2.2 jdolecek
369 1.2.2.2 jdolecek /*
370 1.2.2.2 jdolecek * Attach the interface.
371 1.2.2.2 jdolecek */
372 1.2.2.2 jdolecek if_attach(ifp);
373 1.2.2.2 jdolecek if_deferred_start_init(ifp, NULL);
374 1.2.2.2 jdolecek ether_ifattach(ifp, enaddr);
375 1.2.2.2 jdolecek rnd_attach_source(&sc->sc_rnd_source, device_xname(self),
376 1.2.2.2 jdolecek RND_TYPE_NET, RND_FLAG_DEFAULT);
377 1.2.2.2 jdolecek }
378 1.2.2.2 jdolecek
379 1.2.2.2 jdolecek static inline void
380 1.2.2.2 jdolecek sun4i_emac_int_enable(struct sun4i_emac_softc *sc)
381 1.2.2.2 jdolecek {
382 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_INT_CTL_REG, 0,
383 1.2.2.2 jdolecek EMAC_INT_ENABLE);
384 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_INT_STA_REG,
385 1.2.2.2 jdolecek sun4i_emac_read(sc, EMAC_INT_STA_REG));
386 1.2.2.2 jdolecek }
387 1.2.2.2 jdolecek
388 1.2.2.2 jdolecek int
389 1.2.2.2 jdolecek sun4i_emac_miibus_read_reg(device_t self, int phy, int reg)
390 1.2.2.2 jdolecek {
391 1.2.2.2 jdolecek struct sun4i_emac_softc * const sc = device_private(self);
392 1.2.2.2 jdolecek int retry = 100;
393 1.2.2.2 jdolecek
394 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_MADR_REG, (phy << 8) | reg);
395 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_MCMD_REG, 1);
396 1.2.2.2 jdolecek
397 1.2.2.2 jdolecek while (--retry > 0 && (sun4i_emac_read(sc, EMAC_MAC_MIND_REG) & 1) != 0)
398 1.2.2.2 jdolecek delay(1000);
399 1.2.2.2 jdolecek if (retry == 0)
400 1.2.2.2 jdolecek device_printf(self, "PHY read timeout\n");
401 1.2.2.2 jdolecek
402 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_MCMD_REG, 0);
403 1.2.2.2 jdolecek const uint32_t rv = sun4i_emac_read(sc, EMAC_MAC_MRDD_REG);
404 1.2.2.2 jdolecek
405 1.2.2.2 jdolecek return rv;
406 1.2.2.2 jdolecek }
407 1.2.2.2 jdolecek
408 1.2.2.2 jdolecek void
409 1.2.2.2 jdolecek sun4i_emac_miibus_write_reg(device_t self, int phy, int reg, int val)
410 1.2.2.2 jdolecek {
411 1.2.2.2 jdolecek struct sun4i_emac_softc * const sc = device_private(self);
412 1.2.2.2 jdolecek int retry = 100;
413 1.2.2.2 jdolecek
414 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_MADR_REG, (phy << 8) | reg);
415 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_MCMD_REG, 1);
416 1.2.2.2 jdolecek
417 1.2.2.2 jdolecek while (--retry > 0 && (sun4i_emac_read(sc, EMAC_MAC_MIND_REG) & 1) != 0)
418 1.2.2.2 jdolecek delay(1000);
419 1.2.2.2 jdolecek if (retry == 0)
420 1.2.2.2 jdolecek device_printf(self, "PHY write timeout\n");
421 1.2.2.2 jdolecek
422 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_MCMD_REG, 0);
423 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_MWTD_REG, val);
424 1.2.2.2 jdolecek }
425 1.2.2.2 jdolecek
426 1.2.2.2 jdolecek void
427 1.2.2.2 jdolecek sun4i_emac_miibus_statchg(struct ifnet *ifp)
428 1.2.2.2 jdolecek {
429 1.2.2.2 jdolecek struct sun4i_emac_softc * const sc = ifp->if_softc;
430 1.2.2.2 jdolecek struct mii_data * const mii = &sc->sc_mii;
431 1.2.2.2 jdolecek const u_int media = mii->mii_media_active;
432 1.2.2.2 jdolecek
433 1.2.2.2 jdolecek /*
434 1.2.2.2 jdolecek * Set MII interface based on the speed
435 1.2.2.2 jdolecek * negotiated by the PHY.
436 1.2.2.2 jdolecek */
437 1.2.2.2 jdolecek switch (IFM_SUBTYPE(media)) {
438 1.2.2.2 jdolecek case IFM_10_T:
439 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_MAC_SUPP_REG,
440 1.2.2.2 jdolecek EMAC_MAC_SUPP_100M, 0);
441 1.2.2.2 jdolecek break;
442 1.2.2.2 jdolecek case IFM_100_TX:
443 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_MAC_SUPP_REG,
444 1.2.2.2 jdolecek 0, EMAC_MAC_SUPP_100M);
445 1.2.2.2 jdolecek break;
446 1.2.2.2 jdolecek }
447 1.2.2.2 jdolecek
448 1.2.2.2 jdolecek const bool link = (IFM_SUBTYPE(media) & (IFM_10_T|IFM_100_TX)) != 0;
449 1.2.2.2 jdolecek if (link) {
450 1.2.2.2 jdolecek if (media & IFM_FDX) {
451 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_MAC_CTL1_REG,
452 1.2.2.2 jdolecek 0, EMAC_MAC_CTL1_FD);
453 1.2.2.2 jdolecek } else {
454 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_MAC_CTL1_REG,
455 1.2.2.2 jdolecek EMAC_MAC_CTL1_FD, 0);
456 1.2.2.2 jdolecek }
457 1.2.2.2 jdolecek }
458 1.2.2.2 jdolecek }
459 1.2.2.2 jdolecek
460 1.2.2.2 jdolecek static void
461 1.2.2.2 jdolecek sun4i_emac_tick(void *softc)
462 1.2.2.2 jdolecek {
463 1.2.2.2 jdolecek struct sun4i_emac_softc * const sc = softc;
464 1.2.2.2 jdolecek struct mii_data * const mii = &sc->sc_mii;
465 1.2.2.2 jdolecek int s;
466 1.2.2.2 jdolecek
467 1.2.2.2 jdolecek s = splnet();
468 1.2.2.2 jdolecek mii_tick(mii);
469 1.2.2.2 jdolecek callout_schedule(&sc->sc_stat_ch, hz);
470 1.2.2.2 jdolecek splx(s);
471 1.2.2.2 jdolecek }
472 1.2.2.2 jdolecek
473 1.2.2.2 jdolecek static inline void
474 1.2.2.2 jdolecek sun4i_emac_rxfifo_flush(struct sun4i_emac_softc *sc)
475 1.2.2.2 jdolecek {
476 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_CTL_REG, EMAC_CTL_RX_EN, 0);
477 1.2.2.2 jdolecek
478 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_RX_CTL_REG, 0, EMAC_RX_CTL_FIFO_RESET);
479 1.2.2.2 jdolecek
480 1.2.2.2 jdolecek for (;;) {
481 1.2.2.2 jdolecek uint32_t v0 = sun4i_emac_read(sc, EMAC_RX_CTL_REG);
482 1.2.2.2 jdolecek if ((v0 & EMAC_RX_CTL_FIFO_RESET) == 0)
483 1.2.2.2 jdolecek break;
484 1.2.2.2 jdolecek }
485 1.2.2.2 jdolecek
486 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_CTL_REG, 0, EMAC_CTL_RX_EN);
487 1.2.2.2 jdolecek }
488 1.2.2.2 jdolecek
489 1.2.2.2 jdolecek static void
490 1.2.2.2 jdolecek sun4i_emac_rxfifo_consume(struct sun4i_emac_softc *sc, size_t len)
491 1.2.2.2 jdolecek {
492 1.2.2.2 jdolecek for (len = (len + 3) >> 2; len > 0; len--) {
493 1.2.2.2 jdolecek (void) sun4i_emac_read(sc, EMAC_RX_IO_DATA_REG);
494 1.2.2.2 jdolecek }
495 1.2.2.2 jdolecek }
496 1.2.2.2 jdolecek
497 1.2.2.2 jdolecek static void
498 1.2.2.2 jdolecek sun4i_emac_rxfifo_transfer(struct sun4i_emac_softc *sc, struct mbuf *m)
499 1.2.2.2 jdolecek {
500 1.2.2.2 jdolecek uint32_t *dp32 = mtod(m, uint32_t *);
501 1.2.2.2 jdolecek const int len = roundup2(m->m_len, 4);
502 1.2.2.2 jdolecek
503 1.2.2.2 jdolecek bus_space_read_multi_4(sc->sc_bst, sc->sc_bsh,
504 1.2.2.2 jdolecek EMAC_RX_IO_DATA_REG, dp32, len / 4);
505 1.2.2.2 jdolecek }
506 1.2.2.2 jdolecek
507 1.2.2.2 jdolecek static struct mbuf *
508 1.2.2.2 jdolecek sun4i_emac_mgethdr(struct sun4i_emac_softc *sc, size_t rxlen)
509 1.2.2.2 jdolecek {
510 1.2.2.2 jdolecek struct mbuf *m = m_gethdr(M_DONTWAIT, MT_DATA);
511 1.2.2.2 jdolecek
512 1.2.2.2 jdolecek if (rxlen + 2 > MHLEN) {
513 1.2.2.2 jdolecek MCLGET(m, M_DONTWAIT);
514 1.2.2.2 jdolecek if ((m->m_flags & M_EXT) == 0) {
515 1.2.2.2 jdolecek m_free(m);
516 1.2.2.2 jdolecek return NULL;
517 1.2.2.2 jdolecek }
518 1.2.2.2 jdolecek }
519 1.2.2.2 jdolecek
520 1.2.2.2 jdolecek m_adj(m, 2);
521 1.2.2.2 jdolecek m->m_len = rxlen;
522 1.2.2.2 jdolecek m->m_pkthdr.len = rxlen;
523 1.2.2.2 jdolecek m_set_rcvif(m, &sc->sc_ec.ec_if);
524 1.2.2.2 jdolecek m->m_flags |= M_HASFCS;
525 1.2.2.2 jdolecek
526 1.2.2.2 jdolecek return m;
527 1.2.2.2 jdolecek }
528 1.2.2.2 jdolecek
529 1.2.2.2 jdolecek static void
530 1.2.2.2 jdolecek sun4i_emac_if_input(struct sun4i_emac_softc *sc, struct mbuf *m)
531 1.2.2.2 jdolecek {
532 1.2.2.2 jdolecek struct ifnet * const ifp = &sc->sc_ec.ec_if;
533 1.2.2.2 jdolecek
534 1.2.2.2 jdolecek if_percpuq_enqueue(ifp->if_percpuq, m);
535 1.2.2.2 jdolecek }
536 1.2.2.2 jdolecek
537 1.2.2.2 jdolecek static void
538 1.2.2.2 jdolecek sun4i_emac_rx_intr(struct sun4i_emac_softc *sc)
539 1.2.2.2 jdolecek {
540 1.2.2.2 jdolecek for (;;) {
541 1.2.2.2 jdolecek uint32_t rx_count = sun4i_emac_read(sc, EMAC_RX_FBC_REG);
542 1.2.2.2 jdolecek struct mbuf *m;
543 1.2.2.2 jdolecek
544 1.2.2.2 jdolecek if (rx_count == 0) {
545 1.2.2.2 jdolecek rx_count = sun4i_emac_read(sc, EMAC_RX_FBC_REG);
546 1.2.2.2 jdolecek if (rx_count == 0)
547 1.2.2.2 jdolecek return;
548 1.2.2.2 jdolecek }
549 1.2.2.2 jdolecek
550 1.2.2.2 jdolecek uint32_t v = sun4i_emac_read(sc, EMAC_RX_IO_DATA_REG);
551 1.2.2.2 jdolecek if (v != EMAC_RX_MAGIC) {
552 1.2.2.2 jdolecek sun4i_emac_rxfifo_flush(sc);
553 1.2.2.2 jdolecek return;
554 1.2.2.2 jdolecek }
555 1.2.2.2 jdolecek
556 1.2.2.2 jdolecek uint32_t rxhdr = sun4i_emac_read(sc, EMAC_RX_IO_DATA_REG);
557 1.2.2.2 jdolecek uint32_t rxlen = __SHIFTOUT(rxhdr, EMAC_RXHDR_LEN);
558 1.2.2.2 jdolecek uint32_t rxsts = __SHIFTOUT(rxhdr, EMAC_RXHDR_STS);
559 1.2.2.2 jdolecek
560 1.2.2.2 jdolecek if (rxlen < ETHER_MIN_LEN || (rxsts & EMAC_RX_STA_PKTOK) == 0) {
561 1.2.2.2 jdolecek sc->sc_ec.ec_if.if_ierrors++;
562 1.2.2.2 jdolecek continue;
563 1.2.2.2 jdolecek }
564 1.2.2.2 jdolecek
565 1.2.2.2 jdolecek m = sun4i_emac_mgethdr(sc, rxlen);
566 1.2.2.2 jdolecek if (m == NULL) {
567 1.2.2.2 jdolecek sc->sc_ec.ec_if.if_ierrors++;
568 1.2.2.2 jdolecek sun4i_emac_rxfifo_consume(sc, rxlen);
569 1.2.2.2 jdolecek return;
570 1.2.2.2 jdolecek }
571 1.2.2.2 jdolecek
572 1.2.2.2 jdolecek sun4i_emac_rxfifo_transfer(sc, m);
573 1.2.2.2 jdolecek sun4i_emac_if_input(sc, m);
574 1.2.2.2 jdolecek }
575 1.2.2.2 jdolecek }
576 1.2.2.2 jdolecek
577 1.2.2.2 jdolecek static int
578 1.2.2.2 jdolecek sun4i_emac_txfifo_transfer(struct sun4i_emac_softc *sc, struct mbuf *m, u_int slot)
579 1.2.2.2 jdolecek {
580 1.2.2.2 jdolecek bus_size_t const io_data_reg = EMAC_TX_IO_DATA_REG(0);
581 1.2.2.2 jdolecek const int len = m->m_pkthdr.len;
582 1.2.2.2 jdolecek uint32_t *pktdata;
583 1.2.2.2 jdolecek
584 1.2.2.2 jdolecek KASSERT(len > 0 && len <= sizeof(sc->sc_txbuf));
585 1.2.2.2 jdolecek
586 1.2.2.2 jdolecek if (m->m_next != NULL) {
587 1.2.2.2 jdolecek m_copydata(m, 0, len, sc->sc_txbuf);
588 1.2.2.2 jdolecek pktdata = sc->sc_txbuf;
589 1.2.2.2 jdolecek } else {
590 1.2.2.2 jdolecek pktdata = mtod(m, uint32_t *);
591 1.2.2.2 jdolecek }
592 1.2.2.2 jdolecek
593 1.2.2.2 jdolecek bus_space_write_multi_4(sc->sc_bst, sc->sc_bsh, io_data_reg,
594 1.2.2.2 jdolecek pktdata, roundup2(len, 4) / 4);
595 1.2.2.2 jdolecek
596 1.2.2.2 jdolecek return len;
597 1.2.2.2 jdolecek }
598 1.2.2.2 jdolecek
599 1.2.2.2 jdolecek static void
600 1.2.2.2 jdolecek sun4i_emac_tx_enqueue(struct sun4i_emac_softc *sc, struct mbuf *m, u_int slot)
601 1.2.2.2 jdolecek {
602 1.2.2.2 jdolecek struct ifnet * const ifp = &sc->sc_ec.ec_if;
603 1.2.2.2 jdolecek
604 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_TX_INS_REG, slot);
605 1.2.2.2 jdolecek
606 1.2.2.2 jdolecek const int len = sun4i_emac_txfifo_transfer(sc, m, slot);
607 1.2.2.2 jdolecek
608 1.2.2.2 jdolecek bus_size_t const pl_reg = EMAC_TX_PL_REG(slot);
609 1.2.2.2 jdolecek bus_size_t const ctl_reg = EMAC_TX_CTL_REG(slot);
610 1.2.2.2 jdolecek
611 1.2.2.2 jdolecek sun4i_emac_write(sc, pl_reg, len);
612 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, ctl_reg, 0, EMAC_TX_CTL_START);
613 1.2.2.2 jdolecek
614 1.2.2.2 jdolecek bpf_mtap(ifp, m);
615 1.2.2.2 jdolecek
616 1.2.2.2 jdolecek m_freem(m);
617 1.2.2.2 jdolecek }
618 1.2.2.2 jdolecek
619 1.2.2.2 jdolecek static void
620 1.2.2.2 jdolecek sun4i_emac_tx_intr(struct sun4i_emac_softc *sc, u_int slot)
621 1.2.2.2 jdolecek {
622 1.2.2.2 jdolecek struct ifnet * const ifp = &sc->sc_ec.ec_if;
623 1.2.2.2 jdolecek
624 1.2.2.2 jdolecek sc->sc_tx_active &= ~__BIT(slot);
625 1.2.2.2 jdolecek ifp->if_flags &= ~IFF_OACTIVE;
626 1.2.2.2 jdolecek }
627 1.2.2.2 jdolecek
628 1.2.2.2 jdolecek int
629 1.2.2.2 jdolecek sun4i_emac_intr(void *arg)
630 1.2.2.2 jdolecek {
631 1.2.2.2 jdolecek struct sun4i_emac_softc * const sc = arg;
632 1.2.2.2 jdolecek struct ifnet * const ifp = &sc->sc_ec.ec_if;
633 1.2.2.2 jdolecek
634 1.2.2.2 jdolecek mutex_enter(&sc->sc_intr_lock);
635 1.2.2.2 jdolecek
636 1.2.2.2 jdolecek uint32_t sts = sun4i_emac_read(sc, EMAC_INT_STA_REG);
637 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_INT_STA_REG, sts);
638 1.2.2.2 jdolecek rnd_add_uint32(&sc->sc_rnd_source, sts);
639 1.2.2.2 jdolecek
640 1.2.2.2 jdolecek if (sts & EMAC_INT_RX) {
641 1.2.2.2 jdolecek sun4i_emac_rx_intr(sc);
642 1.2.2.2 jdolecek }
643 1.2.2.2 jdolecek if (sts & EMAC_INT_TX0) {
644 1.2.2.2 jdolecek sun4i_emac_tx_intr(sc, 0);
645 1.2.2.2 jdolecek }
646 1.2.2.2 jdolecek if (sts & EMAC_INT_TX1) {
647 1.2.2.2 jdolecek sun4i_emac_tx_intr(sc, 1);
648 1.2.2.2 jdolecek }
649 1.2.2.2 jdolecek if (sts & (EMAC_INT_TX0|EMAC_INT_TX1)) {
650 1.2.2.2 jdolecek if (sc->sc_tx_active == 0)
651 1.2.2.2 jdolecek ifp->if_timer = 0;
652 1.2.2.2 jdolecek if_schedule_deferred_start(ifp);
653 1.2.2.2 jdolecek }
654 1.2.2.2 jdolecek
655 1.2.2.2 jdolecek mutex_exit(&sc->sc_intr_lock);
656 1.2.2.2 jdolecek
657 1.2.2.2 jdolecek return 1;
658 1.2.2.2 jdolecek }
659 1.2.2.2 jdolecek
660 1.2.2.2 jdolecek void
661 1.2.2.2 jdolecek sun4i_emac_ifstart(struct ifnet *ifp)
662 1.2.2.2 jdolecek {
663 1.2.2.2 jdolecek struct sun4i_emac_softc * const sc = ifp->if_softc;
664 1.2.2.2 jdolecek
665 1.2.2.2 jdolecek mutex_enter(&sc->sc_intr_lock);
666 1.2.2.2 jdolecek
667 1.2.2.2 jdolecek if ((sc->sc_tx_active & 1) == 0) {
668 1.2.2.2 jdolecek struct mbuf *m;
669 1.2.2.2 jdolecek IFQ_DEQUEUE(&ifp->if_snd, m);
670 1.2.2.2 jdolecek if (m == NULL) {
671 1.2.2.2 jdolecek mutex_exit(&sc->sc_intr_lock);
672 1.2.2.2 jdolecek return;
673 1.2.2.2 jdolecek }
674 1.2.2.2 jdolecek sun4i_emac_tx_enqueue(sc, m, 0);
675 1.2.2.2 jdolecek sc->sc_tx_active |= 1;
676 1.2.2.2 jdolecek }
677 1.2.2.2 jdolecek
678 1.2.2.2 jdolecek if ((sc->sc_tx_active & 2) == 0) {
679 1.2.2.2 jdolecek struct mbuf *m;
680 1.2.2.2 jdolecek IFQ_DEQUEUE(&ifp->if_snd, m);
681 1.2.2.2 jdolecek if (m == NULL) {
682 1.2.2.2 jdolecek mutex_exit(&sc->sc_intr_lock);
683 1.2.2.2 jdolecek return;
684 1.2.2.2 jdolecek }
685 1.2.2.2 jdolecek sun4i_emac_tx_enqueue(sc, m, 1);
686 1.2.2.2 jdolecek sc->sc_tx_active |= 2;
687 1.2.2.2 jdolecek }
688 1.2.2.2 jdolecek
689 1.2.2.2 jdolecek if (sc->sc_tx_active == 3)
690 1.2.2.2 jdolecek ifp->if_flags |= IFF_OACTIVE;
691 1.2.2.2 jdolecek
692 1.2.2.2 jdolecek ifp->if_timer = 5;
693 1.2.2.2 jdolecek
694 1.2.2.2 jdolecek mutex_exit(&sc->sc_intr_lock);
695 1.2.2.2 jdolecek }
696 1.2.2.2 jdolecek
697 1.2.2.2 jdolecek
698 1.2.2.2 jdolecek static int
699 1.2.2.2 jdolecek sun4i_emac_ifioctl(struct ifnet *ifp, u_long cmd, void *data)
700 1.2.2.2 jdolecek {
701 1.2.2.2 jdolecek struct sun4i_emac_softc * const sc = ifp->if_softc;
702 1.2.2.2 jdolecek struct ifreq *ifr = (struct ifreq *)data;
703 1.2.2.2 jdolecek int error;
704 1.2.2.2 jdolecek
705 1.2.2.2 jdolecek switch (cmd) {
706 1.2.2.2 jdolecek case SIOCGIFMEDIA:
707 1.2.2.2 jdolecek case SIOCSIFMEDIA:
708 1.2.2.2 jdolecek error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
709 1.2.2.2 jdolecek break;
710 1.2.2.2 jdolecek default:
711 1.2.2.2 jdolecek if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET)
712 1.2.2.2 jdolecek break;
713 1.2.2.2 jdolecek error = 0;
714 1.2.2.2 jdolecek if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
715 1.2.2.2 jdolecek break;
716 1.2.2.2 jdolecek if (ifp->if_flags & IFF_RUNNING) {
717 1.2.2.2 jdolecek /*
718 1.2.2.2 jdolecek * Multicast list has changed; set the hardware filter
719 1.2.2.2 jdolecek * accordingly.
720 1.2.2.2 jdolecek */
721 1.2.2.2 jdolecek mutex_enter(&sc->sc_intr_lock);
722 1.2.2.2 jdolecek sun4i_emac_ifstop(ifp, 0);
723 1.2.2.2 jdolecek error = sun4i_emac_ifinit(ifp);
724 1.2.2.2 jdolecek mutex_exit(&sc->sc_intr_lock);
725 1.2.2.2 jdolecek }
726 1.2.2.2 jdolecek break;
727 1.2.2.2 jdolecek }
728 1.2.2.2 jdolecek
729 1.2.2.2 jdolecek return error;
730 1.2.2.2 jdolecek }
731 1.2.2.2 jdolecek
732 1.2.2.2 jdolecek static void
733 1.2.2.2 jdolecek sun4i_emac_ifstop(struct ifnet *ifp, int discard)
734 1.2.2.2 jdolecek {
735 1.2.2.2 jdolecek struct sun4i_emac_softc * const sc = ifp->if_softc;
736 1.2.2.2 jdolecek struct mii_data * const mii = &sc->sc_mii;
737 1.2.2.2 jdolecek
738 1.2.2.2 jdolecek KASSERT(mutex_owned(&sc->sc_intr_lock));
739 1.2.2.2 jdolecek
740 1.2.2.2 jdolecek callout_stop(&sc->sc_stat_ch);
741 1.2.2.2 jdolecek mii_down(mii);
742 1.2.2.2 jdolecek
743 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_INT_CTL_REG, 0);
744 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_INT_STA_REG,
745 1.2.2.2 jdolecek sun4i_emac_read(sc, EMAC_INT_STA_REG));
746 1.2.2.2 jdolecek
747 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_CTL_REG,
748 1.2.2.2 jdolecek EMAC_CTL_RST | EMAC_CTL_TX_EN | EMAC_CTL_RX_EN, 0);
749 1.2.2.2 jdolecek
750 1.2.2.2 jdolecek ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
751 1.2.2.2 jdolecek ifp->if_timer = 0;
752 1.2.2.2 jdolecek }
753 1.2.2.2 jdolecek
754 1.2.2.2 jdolecek int
755 1.2.2.2 jdolecek sun4i_emac_ifinit(struct ifnet *ifp)
756 1.2.2.2 jdolecek {
757 1.2.2.2 jdolecek struct sun4i_emac_softc * const sc = ifp->if_softc;
758 1.2.2.2 jdolecek struct mii_data * const mii = &sc->sc_mii;
759 1.2.2.2 jdolecek
760 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_RX_CTL_REG,
761 1.2.2.2 jdolecek 0, EMAC_RX_CTL_FIFO_RESET);
762 1.2.2.2 jdolecek
763 1.2.2.2 jdolecek delay(1);
764 1.2.2.2 jdolecek
765 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_MAC_CTL0_REG,
766 1.2.2.2 jdolecek EMAC_MAC_CTL0_SOFT_RESET, 0);
767 1.2.2.2 jdolecek
768 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_MAC_MCFG_REG,
769 1.2.2.2 jdolecek EMAC_MAC_MCFG_CLK, __SHIFTIN(0xd, EMAC_MAC_MCFG_CLK));
770 1.2.2.2 jdolecek
771 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_RX_FBC_REG, 0);
772 1.2.2.2 jdolecek
773 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_INT_CTL_REG, 0);
774 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_INT_STA_REG,
775 1.2.2.2 jdolecek sun4i_emac_read(sc, EMAC_INT_STA_REG));
776 1.2.2.2 jdolecek
777 1.2.2.2 jdolecek delay(1);
778 1.2.2.2 jdolecek
779 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_TX_MODE_REG,
780 1.2.2.2 jdolecek EMAC_TX_MODE_DMA, EMAC_TX_MODE_ABF_ENA);
781 1.2.2.2 jdolecek
782 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_MAC_CTL0_REG,
783 1.2.2.2 jdolecek 0, EMAC_MAC_CTL0_TFC | EMAC_MAC_CTL0_RFC);
784 1.2.2.2 jdolecek
785 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_RX_CTL_REG,
786 1.2.2.2 jdolecek EMAC_RX_CTL_DMA, 0);
787 1.2.2.2 jdolecek
788 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_MAC_CTL1_REG,
789 1.2.2.2 jdolecek 0,
790 1.2.2.2 jdolecek EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC |
791 1.2.2.2 jdolecek EMAC_MAC_CTL1_PC);
792 1.2.2.2 jdolecek
793 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_IPGT_REG, EMAC_MAC_IPGT_FD);
794 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_IPGR_REG,
795 1.2.2.2 jdolecek __SHIFTIN(0x0c, EMAC_MAC_IPGR_IPG1) |
796 1.2.2.2 jdolecek __SHIFTIN(0x12, EMAC_MAC_IPGR_IPG2));
797 1.2.2.2 jdolecek
798 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_CLRT_REG,
799 1.2.2.2 jdolecek __SHIFTIN(0x0f, EMAC_MAC_CLRT_RM) |
800 1.2.2.2 jdolecek __SHIFTIN(0x37, EMAC_MAC_CLRT_CW));
801 1.2.2.2 jdolecek
802 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_MAC_MAXF_REG, 0x600);
803 1.2.2.2 jdolecek
804 1.2.2.2 jdolecek sun4i_emac_rx_hash(sc);
805 1.2.2.2 jdolecek
806 1.2.2.2 jdolecek sun4i_emac_int_enable(sc);
807 1.2.2.2 jdolecek
808 1.2.2.2 jdolecek ifp->if_flags |= IFF_RUNNING;
809 1.2.2.2 jdolecek ifp->if_flags &= ~IFF_OACTIVE;
810 1.2.2.2 jdolecek
811 1.2.2.2 jdolecek /* Enable RX/TX */
812 1.2.2.2 jdolecek sun4i_emac_clear_set(sc, EMAC_CTL_REG,
813 1.2.2.2 jdolecek 0, EMAC_CTL_RST | EMAC_CTL_TX_EN | EMAC_CTL_RX_EN);
814 1.2.2.2 jdolecek
815 1.2.2.2 jdolecek mii_mediachg(mii);
816 1.2.2.2 jdolecek callout_schedule(&sc->sc_stat_ch, hz);
817 1.2.2.2 jdolecek
818 1.2.2.2 jdolecek return 0;
819 1.2.2.2 jdolecek }
820 1.2.2.2 jdolecek
821 1.2.2.2 jdolecek static void
822 1.2.2.2 jdolecek sun4i_emac_ifwatchdog(struct ifnet *ifp)
823 1.2.2.2 jdolecek {
824 1.2.2.2 jdolecek struct sun4i_emac_softc * const sc = ifp->if_softc;
825 1.2.2.2 jdolecek
826 1.2.2.2 jdolecek device_printf(sc->sc_dev, "device timeout\n");
827 1.2.2.2 jdolecek
828 1.2.2.2 jdolecek ifp->if_oerrors++;
829 1.2.2.2 jdolecek sun4i_emac_ifinit(ifp);
830 1.2.2.2 jdolecek sun4i_emac_ifstart(ifp);
831 1.2.2.2 jdolecek }
832 1.2.2.2 jdolecek
833 1.2.2.2 jdolecek static void
834 1.2.2.2 jdolecek sun4i_emac_rx_hash(struct sun4i_emac_softc *sc)
835 1.2.2.2 jdolecek {
836 1.2.2.2 jdolecek struct ifnet * const ifp = &sc->sc_ec.ec_if;
837 1.2.2.2 jdolecek struct ether_multistep step;
838 1.2.2.2 jdolecek struct ether_multi *enm;
839 1.2.2.2 jdolecek uint32_t hash[2];
840 1.2.2.2 jdolecek uint32_t rxctl;
841 1.2.2.2 jdolecek
842 1.2.2.2 jdolecek rxctl = sun4i_emac_read(sc, EMAC_RX_CTL_REG);
843 1.2.2.2 jdolecek rxctl &= ~EMAC_RX_CTL_MHF;
844 1.2.2.2 jdolecek rxctl |= EMAC_RX_CTL_UCAD;
845 1.2.2.2 jdolecek rxctl |= EMAC_RX_CTL_DAF;
846 1.2.2.2 jdolecek rxctl |= EMAC_RX_CTL_MC0;
847 1.2.2.2 jdolecek rxctl |= EMAC_RX_CTL_BC0;
848 1.2.2.2 jdolecek rxctl |= EMAC_RX_CTL_POR;
849 1.2.2.2 jdolecek
850 1.2.2.2 jdolecek hash[0] = hash[1] = ~0;
851 1.2.2.2 jdolecek if (ifp->if_flags & IFF_PROMISC) {
852 1.2.2.2 jdolecek ifp->if_flags |= IFF_ALLMULTI;
853 1.2.2.2 jdolecek rxctl |= EMAC_RX_CTL_PROMISC;
854 1.2.2.2 jdolecek } else {
855 1.2.2.2 jdolecek rxctl &= ~EMAC_RX_CTL_PROMISC;
856 1.2.2.2 jdolecek }
857 1.2.2.2 jdolecek
858 1.2.2.2 jdolecek if ((ifp->if_flags & IFF_PROMISC) == 0) {
859 1.2.2.2 jdolecek hash[0] = hash[1] = 0;
860 1.2.2.2 jdolecek
861 1.2.2.2 jdolecek ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
862 1.2.2.2 jdolecek while (enm != NULL) {
863 1.2.2.2 jdolecek if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
864 1.2.2.2 jdolecek /*
865 1.2.2.2 jdolecek * We must listen to a range of multicast addresses.
866 1.2.2.2 jdolecek * For now, just accept all multicasts, rather than
867 1.2.2.2 jdolecek * trying to set only those filter bits needed to match
868 1.2.2.2 jdolecek * the range. (At this time, the only use of address
869 1.2.2.2 jdolecek * ranges is for IP multicast routing, for which the
870 1.2.2.2 jdolecek * range is big enough to require all bits set.)
871 1.2.2.2 jdolecek */
872 1.2.2.2 jdolecek hash[0] = hash[1] = ~0;
873 1.2.2.2 jdolecek ifp->if_flags |= IFF_ALLMULTI;
874 1.2.2.2 jdolecek goto done;
875 1.2.2.2 jdolecek }
876 1.2.2.2 jdolecek
877 1.2.2.2 jdolecek u_int crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN);
878 1.2.2.2 jdolecek
879 1.2.2.2 jdolecek /* Just want the 6 most significant bits. */
880 1.2.2.2 jdolecek crc >>= 26;
881 1.2.2.2 jdolecek
882 1.2.2.2 jdolecek /* Set the corresponding bit in the filter. */
883 1.2.2.2 jdolecek hash[crc >> 5] |= __BIT(crc & 31);
884 1.2.2.2 jdolecek ETHER_NEXT_MULTI(step, enm);
885 1.2.2.2 jdolecek }
886 1.2.2.2 jdolecek ifp->if_flags &= ~IFF_ALLMULTI;
887 1.2.2.2 jdolecek rxctl |= EMAC_RX_CTL_MHF;
888 1.2.2.2 jdolecek }
889 1.2.2.2 jdolecek
890 1.2.2.2 jdolecek done:
891 1.2.2.2 jdolecek
892 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_RX_HASH0_REG, hash[0]);
893 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_RX_HASH1_REG, hash[1]);
894 1.2.2.2 jdolecek
895 1.2.2.2 jdolecek sun4i_emac_write(sc, EMAC_RX_CTL_REG, rxctl);
896 1.2.2.2 jdolecek }
897