if_rge.c revision 1.9.4.2 1 1.9.4.2 martin /* $NetBSD: if_rge.c,v 1.9.4.2 2020/04/08 14:08:09 martin Exp $ */
2 1.9.4.2 martin /* $OpenBSD: if_rge.c,v 1.2 2020/01/02 09:00:45 kevlo Exp $ */
3 1.9.4.2 martin
4 1.9.4.2 martin /*
5 1.9.4.2 martin * Copyright (c) 2019 Kevin Lo <kevlo (at) openbsd.org>
6 1.9.4.2 martin *
7 1.9.4.2 martin * Permission to use, copy, modify, and distribute this software for any
8 1.9.4.2 martin * purpose with or without fee is hereby granted, provided that the above
9 1.9.4.2 martin * copyright notice and this permission notice appear in all copies.
10 1.9.4.2 martin *
11 1.9.4.2 martin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 1.9.4.2 martin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 1.9.4.2 martin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 1.9.4.2 martin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 1.9.4.2 martin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 1.9.4.2 martin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 1.9.4.2 martin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 1.9.4.2 martin */
19 1.9.4.2 martin
20 1.9.4.2 martin #include <sys/cdefs.h>
21 1.9.4.2 martin __KERNEL_RCSID(0, "$NetBSD: if_rge.c,v 1.9.4.2 2020/04/08 14:08:09 martin Exp $");
22 1.9.4.2 martin
23 1.9.4.2 martin /* #include "vlan.h" Sevan */
24 1.9.4.2 martin
25 1.9.4.2 martin #include <sys/types.h>
26 1.9.4.2 martin
27 1.9.4.2 martin #include <sys/param.h>
28 1.9.4.2 martin #include <sys/systm.h>
29 1.9.4.2 martin #include <sys/sockio.h>
30 1.9.4.2 martin #include <sys/mbuf.h>
31 1.9.4.2 martin #include <sys/malloc.h>
32 1.9.4.2 martin #include <sys/kernel.h>
33 1.9.4.2 martin #include <sys/socket.h>
34 1.9.4.2 martin #include <sys/device.h>
35 1.9.4.2 martin #include <sys/endian.h>
36 1.9.4.2 martin #include <sys/callout.h>
37 1.9.4.2 martin #include <sys/workqueue.h>
38 1.9.4.2 martin
39 1.9.4.2 martin #include <net/if.h>
40 1.9.4.2 martin
41 1.9.4.2 martin #include <net/if_dl.h>
42 1.9.4.2 martin #include <net/if_ether.h>
43 1.9.4.2 martin
44 1.9.4.2 martin #include <net/if_media.h>
45 1.9.4.2 martin
46 1.9.4.2 martin #include <netinet/in.h>
47 1.9.4.2 martin #include <net/if_ether.h>
48 1.9.4.2 martin
49 1.9.4.2 martin #if NBPFILTER > 0
50 1.9.4.2 martin #include <net/bpf.h>
51 1.9.4.2 martin #endif
52 1.9.4.2 martin
53 1.9.4.2 martin #include <sys/bus.h>
54 1.9.4.2 martin #include <machine/intr.h>
55 1.9.4.2 martin
56 1.9.4.2 martin #include <dev/mii/mii.h>
57 1.9.4.2 martin
58 1.9.4.2 martin #include <dev/pci/pcivar.h>
59 1.9.4.2 martin #include <dev/pci/pcireg.h>
60 1.9.4.2 martin #include <dev/pci/pcidevs.h>
61 1.9.4.2 martin
62 1.9.4.2 martin #include <dev/pci/if_rgereg.h>
63 1.9.4.2 martin
64 1.9.4.2 martin #ifdef __NetBSD__
65 1.9.4.2 martin #define letoh32 htole32
66 1.9.4.2 martin #define nitems(x) __arraycount(x)
67 1.9.4.2 martin #define MBUF_LIST_INITIALIZER() { NULL, NULL, 0 }
68 1.9.4.2 martin struct mbuf_list {
69 1.9.4.2 martin struct mbuf *ml_head;
70 1.9.4.2 martin struct mbuf *ml_tail;
71 1.9.4.2 martin u_int ml_len;
72 1.9.4.2 martin };
73 1.9.4.2 martin
74 1.9.4.2 martin static struct mbuf *
75 1.9.4.2 martin MCLGETI(struct rge_softc *sc __unused, int how,
76 1.9.4.2 martin struct ifnet *ifp __unused, u_int size)
77 1.9.4.2 martin {
78 1.9.4.2 martin struct mbuf *m;
79 1.9.4.2 martin
80 1.9.4.2 martin MGETHDR(m, how, MT_DATA);
81 1.9.4.2 martin if (m == NULL)
82 1.9.4.2 martin return NULL;
83 1.9.4.2 martin
84 1.9.4.2 martin MEXTMALLOC(m, size, how);
85 1.9.4.2 martin if ((m->m_flags & M_EXT) == 0) {
86 1.9.4.2 martin m_freem(m);
87 1.9.4.2 martin return NULL;
88 1.9.4.2 martin }
89 1.9.4.2 martin return m;
90 1.9.4.2 martin }
91 1.9.4.2 martin
92 1.9.4.2 martin #ifdef NET_MPSAFE
93 1.9.4.2 martin #define RGE_MPSAFE 1
94 1.9.4.2 martin #define CALLOUT_FLAGS CALLOUT_MPSAFE
95 1.9.4.2 martin #else
96 1.9.4.2 martin #define CALLOUT_FLAGS 0
97 1.9.4.2 martin #endif
98 1.9.4.2 martin #endif
99 1.9.4.2 martin
100 1.9.4.2 martin static int rge_match(device_t, cfdata_t, void *);
101 1.9.4.2 martin static void rge_attach(device_t, device_t, void *);
102 1.9.4.2 martin int rge_intr(void *);
103 1.9.4.2 martin int rge_encap(struct rge_softc *, struct mbuf *, int);
104 1.9.4.2 martin int rge_ioctl(struct ifnet *, u_long, void *);
105 1.9.4.2 martin void rge_start(struct ifnet *);
106 1.9.4.2 martin void rge_watchdog(struct ifnet *);
107 1.9.4.2 martin int rge_init(struct ifnet *);
108 1.9.4.2 martin void rge_stop(struct ifnet *);
109 1.9.4.2 martin int rge_ifmedia_upd(struct ifnet *);
110 1.9.4.2 martin void rge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
111 1.9.4.2 martin int rge_allocmem(struct rge_softc *);
112 1.9.4.2 martin int rge_newbuf(struct rge_softc *, int);
113 1.9.4.2 martin void rge_discard_rxbuf(struct rge_softc *, int);
114 1.9.4.2 martin int rge_rx_list_init(struct rge_softc *);
115 1.9.4.2 martin void rge_tx_list_init(struct rge_softc *);
116 1.9.4.2 martin int rge_rxeof(struct rge_softc *);
117 1.9.4.2 martin int rge_txeof(struct rge_softc *);
118 1.9.4.2 martin void rge_reset(struct rge_softc *);
119 1.9.4.2 martin void rge_iff(struct rge_softc *);
120 1.9.4.2 martin void rge_set_phy_power(struct rge_softc *, int);
121 1.9.4.2 martin void rge_phy_config(struct rge_softc *);
122 1.9.4.2 martin void rge_set_macaddr(struct rge_softc *, const uint8_t *);
123 1.9.4.2 martin void rge_get_macaddr(struct rge_softc *, uint8_t *);
124 1.9.4.2 martin void rge_hw_init(struct rge_softc *);
125 1.9.4.2 martin void rge_disable_phy_ocp_pwrsave(struct rge_softc *);
126 1.9.4.2 martin void rge_patch_phy_mcu(struct rge_softc *, int);
127 1.9.4.2 martin void rge_add_media_types(struct rge_softc *);
128 1.9.4.2 martin void rge_config_imtype(struct rge_softc *, int);
129 1.9.4.2 martin void rge_disable_sim_im(struct rge_softc *);
130 1.9.4.2 martin void rge_setup_sim_im(struct rge_softc *);
131 1.9.4.2 martin void rge_setup_intr(struct rge_softc *, int);
132 1.9.4.2 martin void rge_exit_oob(struct rge_softc *);
133 1.9.4.2 martin void rge_write_csi(struct rge_softc *, uint32_t, uint32_t);
134 1.9.4.2 martin uint32_t rge_read_csi(struct rge_softc *, uint32_t);
135 1.9.4.2 martin void rge_write_mac_ocp(struct rge_softc *, uint16_t, uint16_t);
136 1.9.4.2 martin uint16_t rge_read_mac_ocp(struct rge_softc *, uint16_t);
137 1.9.4.2 martin void rge_write_ephy(struct rge_softc *, uint16_t, uint16_t);
138 1.9.4.2 martin void rge_write_phy(struct rge_softc *, uint16_t, uint16_t, uint16_t);
139 1.9.4.2 martin void rge_write_phy_ocp(struct rge_softc *, uint16_t, uint16_t);
140 1.9.4.2 martin uint16_t rge_read_phy_ocp(struct rge_softc *, uint16_t);
141 1.9.4.2 martin int rge_get_link_status(struct rge_softc *);
142 1.9.4.2 martin void rge_txstart(struct work *, void *);
143 1.9.4.2 martin void rge_tick(void *);
144 1.9.4.2 martin void rge_link_state(struct rge_softc *);
145 1.9.4.2 martin
146 1.9.4.2 martin static const struct {
147 1.9.4.2 martin uint16_t reg;
148 1.9.4.2 martin uint16_t val;
149 1.9.4.2 martin } rtl8125_def_bps[] = {
150 1.9.4.2 martin RTL8125_DEF_BPS
151 1.9.4.2 martin }, rtl8125_mac_cfg2_ephy[] = {
152 1.9.4.2 martin RTL8125_MAC_CFG2_EPHY
153 1.9.4.2 martin }, rtl8125_mac_cfg2_mcu[] = {
154 1.9.4.2 martin RTL8125_MAC_CFG2_MCU
155 1.9.4.2 martin }, rtl8125_mac_cfg3_ephy[] = {
156 1.9.4.2 martin RTL8125_MAC_CFG3_EPHY
157 1.9.4.2 martin }, rtl8125_mac_cfg3_mcu[] = {
158 1.9.4.2 martin RTL8125_MAC_CFG3_MCU
159 1.9.4.2 martin };
160 1.9.4.2 martin
161 1.9.4.2 martin CFATTACH_DECL_NEW(rge, sizeof(struct rge_softc), rge_match, rge_attach,
162 1.9.4.2 martin NULL, NULL); /* Sevan - detach function? */
163 1.9.4.2 martin
164 1.9.4.2 martin extern struct cfdriver rge_cd;
165 1.9.4.2 martin
166 1.9.4.2 martin static const struct {
167 1.9.4.2 martin pci_vendor_id_t vendor;
168 1.9.4.2 martin pci_product_id_t product;
169 1.9.4.2 martin }rge_devices[] = {
170 1.9.4.2 martin { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_E3000 },
171 1.9.4.2 martin { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8125 },
172 1.9.4.2 martin };
173 1.9.4.2 martin
174 1.9.4.2 martin static int
175 1.9.4.2 martin rge_match(device_t parent, cfdata_t match, void *aux)
176 1.9.4.2 martin {
177 1.9.4.2 martin struct pci_attach_args *pa =aux;
178 1.9.4.2 martin int n;
179 1.9.4.2 martin
180 1.9.4.2 martin for (n =0; n < __arraycount(rge_devices); n++) {
181 1.9.4.2 martin if (PCI_VENDOR(pa->pa_id) == rge_devices[n].vendor &&
182 1.9.4.2 martin PCI_PRODUCT(pa->pa_id) == rge_devices[n].product)
183 1.9.4.2 martin return 1;
184 1.9.4.2 martin }
185 1.9.4.2 martin
186 1.9.4.2 martin return 0;
187 1.9.4.2 martin }
188 1.9.4.2 martin
189 1.9.4.2 martin void
190 1.9.4.2 martin rge_attach(device_t parent, device_t self, void *aux)
191 1.9.4.2 martin {
192 1.9.4.2 martin struct rge_softc *sc = (struct rge_softc *)self;
193 1.9.4.2 martin struct pci_attach_args *pa = aux;
194 1.9.4.2 martin pci_chipset_tag_t pc = pa->pa_pc;
195 1.9.4.2 martin pci_intr_handle_t ih;
196 1.9.4.2 martin char intrbuf[PCI_INTRSTR_LEN];
197 1.9.4.2 martin const char *intrstr = NULL;
198 1.9.4.2 martin struct ifnet *ifp;
199 1.9.4.2 martin pcireg_t reg;
200 1.9.4.2 martin uint32_t hwrev;
201 1.9.4.2 martin uint8_t eaddr[ETHER_ADDR_LEN];
202 1.9.4.2 martin int offset;
203 1.9.4.2 martin
204 1.9.4.2 martin pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0);
205 1.9.4.2 martin
206 1.9.4.2 martin /*
207 1.9.4.2 martin * Map control/status registers.
208 1.9.4.2 martin */
209 1.9.4.2 martin if (pci_mapreg_map(pa, RGE_PCI_BAR2, PCI_MAPREG_TYPE_MEM |
210 1.9.4.2 martin PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->rge_btag, &sc->rge_bhandle,
211 1.9.4.2 martin NULL, &sc->rge_bsize)) {
212 1.9.4.2 martin if (pci_mapreg_map(pa, RGE_PCI_BAR1, PCI_MAPREG_TYPE_MEM |
213 1.9.4.2 martin PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->rge_btag,
214 1.9.4.2 martin &sc->rge_bhandle, NULL, &sc->rge_bsize)) {
215 1.9.4.2 martin if (pci_mapreg_map(pa, RGE_PCI_BAR0, PCI_MAPREG_TYPE_IO,
216 1.9.4.2 martin 0, &sc->rge_btag, &sc->rge_bhandle, NULL,
217 1.9.4.2 martin &sc->rge_bsize)) {
218 1.9.4.2 martin printf(": can't map mem or i/o space\n");
219 1.9.4.2 martin return;
220 1.9.4.2 martin }
221 1.9.4.2 martin }
222 1.9.4.2 martin }
223 1.9.4.2 martin
224 1.9.4.2 martin /*
225 1.9.4.2 martin * Allocate interrupt.
226 1.9.4.2 martin */
227 1.9.4.2 martin if (pci_intr_map(pa, &ih) == 0)
228 1.9.4.2 martin sc->rge_flags |= RGE_FLAG_MSI;
229 1.9.4.2 martin else if (pci_intr_map(pa, &ih) != 0) {
230 1.9.4.2 martin printf(": couldn't map interrupt\n");
231 1.9.4.2 martin return;
232 1.9.4.2 martin }
233 1.9.4.2 martin intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
234 1.9.4.2 martin sc->sc_ih = pci_intr_establish_xname(pc, ih, IPL_NET, rge_intr,
235 1.9.4.2 martin sc, sc->sc_dev.dv_xname);
236 1.9.4.2 martin if (sc->sc_ih == NULL) {
237 1.9.4.2 martin printf(": couldn't establish interrupt");
238 1.9.4.2 martin if (intrstr != NULL)
239 1.9.4.2 martin printf(" at %s", intrstr);
240 1.9.4.2 martin printf("\n");
241 1.9.4.2 martin return;
242 1.9.4.2 martin }
243 1.9.4.2 martin printf(": %s", intrstr);
244 1.9.4.2 martin
245 1.9.4.2 martin if (pci_dma64_available(pa))
246 1.9.4.2 martin sc->sc_dmat = pa->pa_dmat64;
247 1.9.4.2 martin else
248 1.9.4.2 martin sc->sc_dmat = pa->pa_dmat;
249 1.9.4.2 martin
250 1.9.4.2 martin sc->sc_pc = pa->pa_pc;
251 1.9.4.2 martin sc->sc_tag = pa->pa_tag;
252 1.9.4.2 martin
253 1.9.4.2 martin /* Determine hardware revision */
254 1.9.4.2 martin hwrev = RGE_READ_4(sc, RGE_TXCFG) & RGE_TXCFG_HWREV;
255 1.9.4.2 martin switch (hwrev) {
256 1.9.4.2 martin case 0x60800000:
257 1.9.4.2 martin sc->rge_type = MAC_CFG2;
258 1.9.4.2 martin break;
259 1.9.4.2 martin case 0x60900000:
260 1.9.4.2 martin sc->rge_type = MAC_CFG3;
261 1.9.4.2 martin break;
262 1.9.4.2 martin default:
263 1.9.4.2 martin printf(": unknown version 0x%08x\n", hwrev);
264 1.9.4.2 martin return;
265 1.9.4.2 martin }
266 1.9.4.2 martin
267 1.9.4.2 martin rge_config_imtype(sc, RGE_IMTYPE_SIM);
268 1.9.4.2 martin
269 1.9.4.2 martin /*
270 1.9.4.2 martin * PCI Express check.
271 1.9.4.2 martin */
272 1.9.4.2 martin if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_PCIEXPRESS,
273 1.9.4.2 martin &offset, NULL)) {
274 1.9.4.2 martin /* Disable PCIe ASPM. */
275 1.9.4.2 martin reg = pci_conf_read(pa->pa_pc, pa->pa_tag,
276 1.9.4.2 martin offset + PCIE_LCSR);
277 1.9.4.2 martin reg &= ~(PCIE_LCSR_ASPM_L0S | PCIE_LCSR_ASPM_L1 );
278 1.9.4.2 martin pci_conf_write(pa->pa_pc, pa->pa_tag, offset + PCIE_LCSR,
279 1.9.4.2 martin reg);
280 1.9.4.2 martin }
281 1.9.4.2 martin
282 1.9.4.2 martin rge_exit_oob(sc);
283 1.9.4.2 martin rge_hw_init(sc);
284 1.9.4.2 martin
285 1.9.4.2 martin rge_get_macaddr(sc, eaddr);
286 1.9.4.2 martin printf(", address %s\n", ether_sprintf(eaddr));
287 1.9.4.2 martin
288 1.9.4.2 martin memcpy(sc->sc_enaddr, eaddr, ETHER_ADDR_LEN);
289 1.9.4.2 martin
290 1.9.4.2 martin rge_set_phy_power(sc, 1);
291 1.9.4.2 martin rge_phy_config(sc);
292 1.9.4.2 martin
293 1.9.4.2 martin if (rge_allocmem(sc))
294 1.9.4.2 martin return;
295 1.9.4.2 martin
296 1.9.4.2 martin ifp = &sc->sc_ec.ec_if;
297 1.9.4.2 martin ifp->if_softc = sc;
298 1.9.4.2 martin strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
299 1.9.4.2 martin ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
300 1.9.4.2 martin #ifdef RGE_MPSAFE
301 1.9.4.2 martin ifp->if_xflags = IFEF_MPSAFE;
302 1.9.4.2 martin #endif
303 1.9.4.2 martin ifp->if_ioctl = rge_ioctl;
304 1.9.4.2 martin ifp->if_start = rge_start;
305 1.9.4.2 martin ifp->if_watchdog = rge_watchdog;
306 1.9.4.2 martin IFQ_SET_MAXLEN(&ifp->if_snd, RGE_TX_LIST_CNT);
307 1.9.4.2 martin ifp->if_mtu = RGE_JUMBO_MTU;
308 1.9.4.2 martin
309 1.9.4.2 martin ifp->if_capabilities = ETHERCAP_VLAN_MTU | IFCAP_CSUM_IPv4_Rx |
310 1.9.4.2 martin IFCAP_CSUM_IPv4_Tx |IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_TCPv4_Tx|
311 1.9.4.2 martin IFCAP_CSUM_UDPv4_Rx | IFCAP_CSUM_UDPv4_Tx;
312 1.9.4.2 martin
313 1.9.4.2 martin #if NVLAN > 0
314 1.9.4.2 martin ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
315 1.9.4.2 martin #endif
316 1.9.4.2 martin
317 1.9.4.2 martin callout_init(&sc->sc_timeout, CALLOUT_FLAGS);
318 1.9.4.2 martin callout_setfunc(&sc->sc_timeout, rge_tick, sc);
319 1.9.4.2 martin rge_txstart(&sc->sc_task, sc);
320 1.9.4.2 martin
321 1.9.4.2 martin /* Initialize ifmedia structures. */
322 1.9.4.2 martin ifmedia_init(&sc->sc_media, IFM_IMASK, rge_ifmedia_upd,
323 1.9.4.2 martin rge_ifmedia_sts);
324 1.9.4.2 martin rge_add_media_types(sc);
325 1.9.4.2 martin ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
326 1.9.4.2 martin ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
327 1.9.4.2 martin sc->sc_media.ifm_media = sc->sc_media.ifm_cur->ifm_media;
328 1.9.4.2 martin
329 1.9.4.2 martin if_attach(ifp);
330 1.9.4.2 martin ether_ifattach(ifp, eaddr);
331 1.9.4.2 martin }
332 1.9.4.2 martin
333 1.9.4.2 martin int
334 1.9.4.2 martin rge_intr(void *arg)
335 1.9.4.2 martin {
336 1.9.4.2 martin struct rge_softc *sc = arg;
337 1.9.4.2 martin struct ifnet *ifp = &sc->sc_ec.ec_if;
338 1.9.4.2 martin uint32_t status;
339 1.9.4.2 martin int claimed = 0, rx, tx;
340 1.9.4.2 martin
341 1.9.4.2 martin if (!(ifp->if_flags & IFF_RUNNING))
342 1.9.4.2 martin return (0);
343 1.9.4.2 martin
344 1.9.4.2 martin /* Disable interrupts. */
345 1.9.4.2 martin RGE_WRITE_4(sc, RGE_IMR, 0);
346 1.9.4.2 martin
347 1.9.4.2 martin status = RGE_READ_4(sc, RGE_ISR);
348 1.9.4.2 martin if (!(sc->rge_flags & RGE_FLAG_MSI)) {
349 1.9.4.2 martin if ((status & RGE_INTRS) == 0 || status == 0xffffffff)
350 1.9.4.2 martin return (0);
351 1.9.4.2 martin }
352 1.9.4.2 martin if (status)
353 1.9.4.2 martin RGE_WRITE_4(sc, RGE_ISR, status);
354 1.9.4.2 martin
355 1.9.4.2 martin if (status & RGE_ISR_PCS_TIMEOUT)
356 1.9.4.2 martin claimed = 1;
357 1.9.4.2 martin
358 1.9.4.2 martin rx = tx = 0;
359 1.9.4.2 martin if (status & RGE_INTRS) {
360 1.9.4.2 martin if (status &
361 1.9.4.2 martin (sc->rge_rx_ack | RGE_ISR_RX_ERR | RGE_ISR_RX_FIFO_OFLOW)) {
362 1.9.4.2 martin rx |= rge_rxeof(sc);
363 1.9.4.2 martin claimed = 1;
364 1.9.4.2 martin }
365 1.9.4.2 martin
366 1.9.4.2 martin if (status & (sc->rge_tx_ack | RGE_ISR_TX_ERR)) {
367 1.9.4.2 martin tx |= rge_txeof(sc);
368 1.9.4.2 martin claimed = 1;
369 1.9.4.2 martin }
370 1.9.4.2 martin
371 1.9.4.2 martin if (status & RGE_ISR_SYSTEM_ERR) {
372 1.9.4.2 martin KERNEL_LOCK(1, NULL);
373 1.9.4.2 martin rge_init(ifp);
374 1.9.4.2 martin KERNEL_UNLOCK_ONE(NULL);
375 1.9.4.2 martin claimed = 1;
376 1.9.4.2 martin }
377 1.9.4.2 martin }
378 1.9.4.2 martin
379 1.9.4.2 martin if (sc->rge_timerintr) {
380 1.9.4.2 martin if ((tx | rx) == 0) {
381 1.9.4.2 martin /*
382 1.9.4.2 martin * Nothing needs to be processed, fallback
383 1.9.4.2 martin * to use TX/RX interrupts.
384 1.9.4.2 martin */
385 1.9.4.2 martin rge_setup_intr(sc, RGE_IMTYPE_NONE);
386 1.9.4.2 martin
387 1.9.4.2 martin /*
388 1.9.4.2 martin * Recollect, mainly to avoid the possible
389 1.9.4.2 martin * race introduced by changing interrupt
390 1.9.4.2 martin * masks.
391 1.9.4.2 martin */
392 1.9.4.2 martin rge_rxeof(sc);
393 1.9.4.2 martin rge_txeof(sc);
394 1.9.4.2 martin } else
395 1.9.4.2 martin RGE_WRITE_4(sc, RGE_TIMERCNT, 1);
396 1.9.4.2 martin } else if (tx | rx) {
397 1.9.4.2 martin /*
398 1.9.4.2 martin * Assume that using simulated interrupt moderation
399 1.9.4.2 martin * (hardware timer based) could reduce the interrupt
400 1.9.4.2 martin * rate.
401 1.9.4.2 martin */
402 1.9.4.2 martin rge_setup_intr(sc, RGE_IMTYPE_SIM);
403 1.9.4.2 martin }
404 1.9.4.2 martin
405 1.9.4.2 martin RGE_WRITE_4(sc, RGE_IMR, sc->rge_intrs);
406 1.9.4.2 martin
407 1.9.4.2 martin return (claimed);
408 1.9.4.2 martin }
409 1.9.4.2 martin
410 1.9.4.2 martin int
411 1.9.4.2 martin rge_encap(struct rge_softc *sc, struct mbuf *m, int idx)
412 1.9.4.2 martin {
413 1.9.4.2 martin struct rge_tx_desc *d = NULL;
414 1.9.4.2 martin struct rge_txq *txq;
415 1.9.4.2 martin bus_dmamap_t txmap;
416 1.9.4.2 martin uint32_t cmdsts, cflags = 0;
417 1.9.4.2 martin int cur, error, i, last, nsegs;
418 1.9.4.2 martin
419 1.9.4.2 martin /*
420 1.9.4.2 martin * Set RGE_TDEXTSTS_IPCSUM if any checksum offloading is requested.
421 1.9.4.2 martin * Otherwise, RGE_TDEXTSTS_TCPCSUM / RGE_TDEXTSTS_UDPCSUM does not
422 1.9.4.2 martin * take affect.
423 1.9.4.2 martin */
424 1.9.4.2 martin if ((m->m_pkthdr.csum_flags &
425 1.9.4.2 martin (M_CSUM_IPv4 | M_CSUM_TCPv4 | M_CSUM_UDPv4)) != 0) {
426 1.9.4.2 martin cflags |= RGE_TDEXTSTS_IPCSUM;
427 1.9.4.2 martin if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT)
428 1.9.4.2 martin cflags |= RGE_TDEXTSTS_TCPCSUM;
429 1.9.4.2 martin if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT)
430 1.9.4.2 martin cflags |= RGE_TDEXTSTS_UDPCSUM;
431 1.9.4.2 martin }
432 1.9.4.2 martin
433 1.9.4.2 martin txq = &sc->rge_ldata.rge_txq[idx];
434 1.9.4.2 martin txmap = txq->txq_dmamap;
435 1.9.4.2 martin
436 1.9.4.2 martin error = bus_dmamap_load_mbuf(sc->sc_dmat, txmap, m, BUS_DMA_NOWAIT);
437 1.9.4.2 martin switch (error) {
438 1.9.4.2 martin case 0:
439 1.9.4.2 martin break;
440 1.9.4.2 martin case EFBIG: /* mbuf chain is too fragmented */
441 1.9.4.2 martin if (m_defrag(m, M_DONTWAIT) == 0 &&
442 1.9.4.2 martin bus_dmamap_load_mbuf(sc->sc_dmat, txmap, m,
443 1.9.4.2 martin BUS_DMA_NOWAIT) == 0)
444 1.9.4.2 martin break;
445 1.9.4.2 martin
446 1.9.4.2 martin /* FALLTHROUGH */
447 1.9.4.2 martin default:
448 1.9.4.2 martin return (0);
449 1.9.4.2 martin }
450 1.9.4.2 martin
451 1.9.4.2 martin bus_dmamap_sync(sc->sc_dmat, txmap, 0, txmap->dm_mapsize,
452 1.9.4.2 martin BUS_DMASYNC_PREWRITE);
453 1.9.4.2 martin
454 1.9.4.2 martin nsegs = txmap->dm_nsegs;
455 1.9.4.2 martin
456 1.9.4.2 martin /* Set up hardware VLAN tagging. */
457 1.9.4.2 martin #if NVLAN > 0
458 1.9.4.2 martin if (m->m_flags & M_VLANTAG)
459 1.9.4.2 martin cflags |= swap16(m->m_pkthdr.ether_vtag | RGE_TDEXTSTS_VTAG);
460 1.9.4.2 martin #endif
461 1.9.4.2 martin
462 1.9.4.2 martin cur = idx;
463 1.9.4.2 martin cmdsts = RGE_TDCMDSTS_SOF;
464 1.9.4.2 martin
465 1.9.4.2 martin for (i = 0; i < txmap->dm_nsegs; i++) {
466 1.9.4.2 martin d = &sc->rge_ldata.rge_tx_list[cur];
467 1.9.4.2 martin
468 1.9.4.2 martin d->rge_extsts = htole32(cflags);
469 1.9.4.2 martin d->rge_addrlo = htole32(RGE_ADDR_LO(txmap->dm_segs[i].ds_addr));
470 1.9.4.2 martin d->rge_addrhi = htole32(RGE_ADDR_HI(txmap->dm_segs[i].ds_addr));
471 1.9.4.2 martin
472 1.9.4.2 martin cmdsts |= txmap->dm_segs[i].ds_len;
473 1.9.4.2 martin
474 1.9.4.2 martin if (cur == RGE_TX_LIST_CNT - 1)
475 1.9.4.2 martin cmdsts |= RGE_TDCMDSTS_EOR;
476 1.9.4.2 martin
477 1.9.4.2 martin d->rge_cmdsts = htole32(cmdsts);
478 1.9.4.2 martin
479 1.9.4.2 martin last = cur;
480 1.9.4.2 martin cmdsts = RGE_TDCMDSTS_OWN;
481 1.9.4.2 martin cur = RGE_NEXT_TX_DESC(cur);
482 1.9.4.2 martin }
483 1.9.4.2 martin
484 1.9.4.2 martin /* Set EOF on the last descriptor. */
485 1.9.4.2 martin d->rge_cmdsts |= htole32(RGE_TDCMDSTS_EOF);
486 1.9.4.2 martin
487 1.9.4.2 martin /* Transfer ownership of packet to the chip. */
488 1.9.4.2 martin d = &sc->rge_ldata.rge_tx_list[idx];
489 1.9.4.2 martin
490 1.9.4.2 martin d->rge_cmdsts |= htole32(RGE_TDCMDSTS_OWN);
491 1.9.4.2 martin
492 1.9.4.2 martin bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map,
493 1.9.4.2 martin cur * sizeof(struct rge_tx_desc), sizeof(struct rge_tx_desc),
494 1.9.4.2 martin BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
495 1.9.4.2 martin
496 1.9.4.2 martin /* Update info of TX queue and descriptors. */
497 1.9.4.2 martin txq->txq_mbuf = m;
498 1.9.4.2 martin txq->txq_descidx = last;
499 1.9.4.2 martin
500 1.9.4.2 martin return (nsegs);
501 1.9.4.2 martin }
502 1.9.4.2 martin
503 1.9.4.2 martin int
504 1.9.4.2 martin rge_ioctl(struct ifnet *ifp, u_long cmd, void *data)
505 1.9.4.2 martin {
506 1.9.4.2 martin struct rge_softc *sc = ifp->if_softc;
507 1.9.4.2 martin struct ifreq *ifr = (struct ifreq *)data;
508 1.9.4.2 martin int s, error = 0;
509 1.9.4.2 martin
510 1.9.4.2 martin s = splnet();
511 1.9.4.2 martin
512 1.9.4.2 martin switch (cmd) {
513 1.9.4.2 martin case SIOCSIFADDR:
514 1.9.4.2 martin ifp->if_flags |= IFF_UP;
515 1.9.4.2 martin if (!(ifp->if_flags & IFF_RUNNING))
516 1.9.4.2 martin rge_init(ifp);
517 1.9.4.2 martin break;
518 1.9.4.2 martin case SIOCSIFFLAGS:
519 1.9.4.2 martin if (ifp->if_flags & IFF_UP) {
520 1.9.4.2 martin if (ifp->if_flags & IFF_RUNNING)
521 1.9.4.2 martin error = ENETRESET;
522 1.9.4.2 martin else
523 1.9.4.2 martin rge_init(ifp);
524 1.9.4.2 martin } else {
525 1.9.4.2 martin if (ifp->if_flags & IFF_RUNNING)
526 1.9.4.2 martin rge_stop(ifp);
527 1.9.4.2 martin }
528 1.9.4.2 martin break;
529 1.9.4.2 martin case SIOCGIFMEDIA:
530 1.9.4.2 martin case SIOCSIFMEDIA:
531 1.9.4.2 martin error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
532 1.9.4.2 martin break;
533 1.9.4.2 martin case SIOCSIFMTU:
534 1.9.4.2 martin if (ifr->ifr_mtu > ifp->if_mtu) {
535 1.9.4.2 martin error = EINVAL;
536 1.9.4.2 martin break;
537 1.9.4.2 martin }
538 1.9.4.2 martin ifp->if_mtu = ifr->ifr_mtu;
539 1.9.4.2 martin break;
540 1.9.4.2 martin default:
541 1.9.4.2 martin error = ether_ioctl(ifp, cmd, data);
542 1.9.4.2 martin }
543 1.9.4.2 martin
544 1.9.4.2 martin if (error == ENETRESET) {
545 1.9.4.2 martin if (ifp->if_flags & IFF_RUNNING)
546 1.9.4.2 martin rge_iff(sc);
547 1.9.4.2 martin error = 0;
548 1.9.4.2 martin }
549 1.9.4.2 martin
550 1.9.4.2 martin splx(s);
551 1.9.4.2 martin return (error);
552 1.9.4.2 martin }
553 1.9.4.2 martin
554 1.9.4.2 martin void
555 1.9.4.2 martin rge_start(struct ifnet *ifp)
556 1.9.4.2 martin {
557 1.9.4.2 martin struct rge_softc *sc = ifp->if_softc;
558 1.9.4.2 martin struct mbuf *m;
559 1.9.4.2 martin int free, idx, used;
560 1.9.4.2 martin int queued = 0;
561 1.9.4.2 martin
562 1.9.4.2 martin #define LINK_STATE_IS_UP(_s) \
563 1.9.4.2 martin ((_s) >= LINK_STATE_UP || (_s) == LINK_STATE_UNKNOWN)
564 1.9.4.2 martin
565 1.9.4.2 martin if (!LINK_STATE_IS_UP(ifp->if_link_state)) {
566 1.9.4.2 martin ifq_purge(ifq);
567 1.9.4.2 martin return;
568 1.9.4.2 martin }
569 1.9.4.2 martin
570 1.9.4.2 martin /* Calculate free space. */
571 1.9.4.2 martin idx = sc->rge_ldata.rge_txq_prodidx;
572 1.9.4.2 martin free = sc->rge_ldata.rge_txq_considx;
573 1.9.4.2 martin if (free <= idx)
574 1.9.4.2 martin free += RGE_TX_LIST_CNT;
575 1.9.4.2 martin free -= idx;
576 1.9.4.2 martin
577 1.9.4.2 martin for (;;) {
578 1.9.4.2 martin if (RGE_TX_NSEGS >= free + 2) {
579 1.9.4.2 martin SET(ifp->if_flags, IFF_OACTIVE);
580 1.9.4.2 martin break;
581 1.9.4.2 martin }
582 1.9.4.2 martin
583 1.9.4.2 martin IFQ_DEQUEUE(&ifp->if_snd, m);
584 1.9.4.2 martin if (m == NULL)
585 1.9.4.2 martin break;
586 1.9.4.2 martin
587 1.9.4.2 martin used = rge_encap(sc, m, idx);
588 1.9.4.2 martin if (used == 0) {
589 1.9.4.2 martin m_freem(m);
590 1.9.4.2 martin continue;
591 1.9.4.2 martin }
592 1.9.4.2 martin
593 1.9.4.2 martin KASSERT(used <= free);
594 1.9.4.2 martin free -= used;
595 1.9.4.2 martin
596 1.9.4.2 martin #if NBPFILTER > 0
597 1.9.4.2 martin if (ifp->if_bpf)
598 1.9.4.2 martin bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
599 1.9.4.2 martin #endif
600 1.9.4.2 martin
601 1.9.4.2 martin idx += used;
602 1.9.4.2 martin if (idx >= RGE_TX_LIST_CNT)
603 1.9.4.2 martin idx -= RGE_TX_LIST_CNT;
604 1.9.4.2 martin
605 1.9.4.2 martin queued++;
606 1.9.4.2 martin }
607 1.9.4.2 martin
608 1.9.4.2 martin if (queued == 0)
609 1.9.4.2 martin return;
610 1.9.4.2 martin
611 1.9.4.2 martin /* Set a timeout in case the chip goes out to lunch. */
612 1.9.4.2 martin ifp->if_timer = 5;
613 1.9.4.2 martin
614 1.9.4.2 martin sc->rge_ldata.rge_txq_prodidx = idx;
615 1.9.4.2 martin ifq_serialize(ifq, &sc->sc_task);
616 1.9.4.2 martin }
617 1.9.4.2 martin
618 1.9.4.2 martin void
619 1.9.4.2 martin rge_watchdog(struct ifnet *ifp)
620 1.9.4.2 martin {
621 1.9.4.2 martin struct rge_softc *sc = ifp->if_softc;
622 1.9.4.2 martin
623 1.9.4.2 martin printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
624 1.9.4.2 martin if_statinc(ifp, if_oerrors);
625 1.9.4.2 martin
626 1.9.4.2 martin rge_init(ifp);
627 1.9.4.2 martin }
628 1.9.4.2 martin
629 1.9.4.2 martin int
630 1.9.4.2 martin rge_init(struct ifnet *ifp)
631 1.9.4.2 martin {
632 1.9.4.2 martin struct rge_softc *sc = ifp->if_softc;
633 1.9.4.2 martin uint32_t val;
634 1.9.4.2 martin uint16_t max_frame_size;
635 1.9.4.2 martin int i;
636 1.9.4.2 martin
637 1.9.4.2 martin rge_stop(ifp);
638 1.9.4.2 martin
639 1.9.4.2 martin /* Set MAC address. */
640 1.9.4.2 martin rge_set_macaddr(sc, sc->sc_enaddr);
641 1.9.4.2 martin
642 1.9.4.2 martin /* Set Maximum frame size but don't let MTU be lass than ETHER_MTU. */
643 1.9.4.2 martin if (ifp->if_mtu < ETHERMTU)
644 1.9.4.2 martin max_frame_size = ETHERMTU;
645 1.9.4.2 martin else
646 1.9.4.2 martin max_frame_size = ifp->if_mtu;
647 1.9.4.2 martin
648 1.9.4.2 martin max_frame_size += ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN +
649 1.9.4.2 martin ETHER_CRC_LEN + 1;
650 1.9.4.2 martin
651 1.9.4.2 martin if (max_frame_size > RGE_JUMBO_FRAMELEN)
652 1.9.4.2 martin max_frame_size -= 1;
653 1.9.4.2 martin
654 1.9.4.2 martin RGE_WRITE_2(sc, RGE_RXMAXSIZE, max_frame_size);
655 1.9.4.2 martin
656 1.9.4.2 martin /* Initialize RX descriptors list. */
657 1.9.4.2 martin if (rge_rx_list_init(sc) == ENOBUFS) {
658 1.9.4.2 martin printf("%s: init failed: no memory for RX buffers\n",
659 1.9.4.2 martin sc->sc_dev.dv_xname);
660 1.9.4.2 martin rge_stop(ifp);
661 1.9.4.2 martin return (ENOBUFS);
662 1.9.4.2 martin }
663 1.9.4.2 martin
664 1.9.4.2 martin /* Initialize TX descriptors. */
665 1.9.4.2 martin rge_tx_list_init(sc);
666 1.9.4.2 martin
667 1.9.4.2 martin /* Load the addresses of the RX and TX lists into the chip. */
668 1.9.4.2 martin RGE_WRITE_4(sc, RGE_RXDESC_ADDR_LO,
669 1.9.4.2 martin RGE_ADDR_LO(sc->rge_ldata.rge_rx_list_map->dm_segs[0].ds_addr));
670 1.9.4.2 martin RGE_WRITE_4(sc, RGE_RXDESC_ADDR_HI,
671 1.9.4.2 martin RGE_ADDR_HI(sc->rge_ldata.rge_rx_list_map->dm_segs[0].ds_addr));
672 1.9.4.2 martin RGE_WRITE_4(sc, RGE_TXDESC_ADDR_LO,
673 1.9.4.2 martin RGE_ADDR_LO(sc->rge_ldata.rge_tx_list_map->dm_segs[0].ds_addr));
674 1.9.4.2 martin RGE_WRITE_4(sc, RGE_TXDESC_ADDR_HI,
675 1.9.4.2 martin RGE_ADDR_HI(sc->rge_ldata.rge_tx_list_map->dm_segs[0].ds_addr));
676 1.9.4.2 martin
677 1.9.4.2 martin RGE_SETBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
678 1.9.4.2 martin
679 1.9.4.2 martin RGE_CLRBIT_1(sc, 0xf1, 0x80);
680 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_CFG2, RGE_CFG2_CLKREQ_EN);
681 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_CFG5, RGE_CFG5_PME_STS);
682 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_CFG3, RGE_CFG3_RDY_TO_L23);
683 1.9.4.2 martin
684 1.9.4.2 martin /* Clear interrupt moderation timer. */
685 1.9.4.2 martin for (i = 0; i < 64; i++)
686 1.9.4.2 martin RGE_WRITE_4(sc, RGE_IM(i), 0);
687 1.9.4.2 martin
688 1.9.4.2 martin /* Set the initial RX and TX configurations. */
689 1.9.4.2 martin RGE_WRITE_4(sc, RGE_RXCFG, RGE_RXCFG_CONFIG);
690 1.9.4.2 martin RGE_WRITE_4(sc, RGE_TXCFG, RGE_TXCFG_CONFIG);
691 1.9.4.2 martin
692 1.9.4.2 martin val = rge_read_csi(sc, 0x70c) & ~0xff000000;
693 1.9.4.2 martin rge_write_csi(sc, 0x70c, val | 0x27000000);
694 1.9.4.2 martin
695 1.9.4.2 martin /* Enable hardware optimization function. */
696 1.9.4.2 martin val = pci_conf_read(sc->sc_pc, sc->sc_tag, 0x78) & ~0x00007000;
697 1.9.4.2 martin pci_conf_write(sc->sc_pc, sc->sc_tag, 0x78, val | 0x00005000);
698 1.9.4.2 martin
699 1.9.4.2 martin RGE_WRITE_2(sc, 0x0382, 0x221b);
700 1.9.4.2 martin RGE_WRITE_1(sc, 0x4500, 0);
701 1.9.4.2 martin RGE_WRITE_2(sc, 0x4800, 0);
702 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_CFG1, RGE_CFG1_SPEED_DOWN);
703 1.9.4.2 martin
704 1.9.4.2 martin rge_write_mac_ocp(sc, 0xc140, 0xffff);
705 1.9.4.2 martin rge_write_mac_ocp(sc, 0xc142, 0xffff);
706 1.9.4.2 martin
707 1.9.4.2 martin val = rge_read_mac_ocp(sc, 0xd3e2) & ~0x0fff;
708 1.9.4.2 martin rge_write_mac_ocp(sc, 0xd3e2, val | 0x03a9);
709 1.9.4.2 martin
710 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xd3e4, 0x00ff);
711 1.9.4.2 martin RGE_MAC_SETBIT(sc, 0xe860, 0x0080);
712 1.9.4.2 martin RGE_MAC_SETBIT(sc, 0xeb58, 0x0001);
713 1.9.4.2 martin
714 1.9.4.2 martin val = rge_read_mac_ocp(sc, 0xe614) & ~0x0700;
715 1.9.4.2 martin rge_write_mac_ocp(sc, 0xe614, val | 0x0400);
716 1.9.4.2 martin
717 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xe63e, 0x0c00);
718 1.9.4.2 martin
719 1.9.4.2 martin val = rge_read_mac_ocp(sc, 0xe63e) & ~0x0030;
720 1.9.4.2 martin rge_write_mac_ocp(sc, 0xe63e, val | 0x0020);
721 1.9.4.2 martin
722 1.9.4.2 martin RGE_MAC_SETBIT(sc, 0xc0b4, 0x000c);
723 1.9.4.2 martin
724 1.9.4.2 martin val = rge_read_mac_ocp(sc, 0xeb6a) & ~0x007f;
725 1.9.4.2 martin rge_write_mac_ocp(sc, 0xeb6a, val | 0x0033);
726 1.9.4.2 martin
727 1.9.4.2 martin val = rge_read_mac_ocp(sc, 0xeb50) & ~0x03e0;
728 1.9.4.2 martin rge_write_mac_ocp(sc, 0xeb50, val | 0x0040);
729 1.9.4.2 martin
730 1.9.4.2 martin val = rge_read_mac_ocp(sc, 0xe056) & ~0x00f0;
731 1.9.4.2 martin rge_write_mac_ocp(sc, 0xe056, val | 0x0030);
732 1.9.4.2 martin
733 1.9.4.2 martin RGE_WRITE_1(sc, RGE_TDFNR, 0x10);
734 1.9.4.2 martin
735 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xe040, 0x1000);
736 1.9.4.2 martin
737 1.9.4.2 martin val = rge_read_mac_ocp(sc, 0xe0c0) & ~0x4f0f;
738 1.9.4.2 martin rge_write_mac_ocp(sc, 0xe0c0, val | 0x4403);
739 1.9.4.2 martin
740 1.9.4.2 martin RGE_MAC_SETBIT(sc, 0xe052, 0x0068);
741 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xe052, 0x0080);
742 1.9.4.2 martin
743 1.9.4.2 martin val = rge_read_mac_ocp(sc, 0xc0ac) & ~0x0080;
744 1.9.4.2 martin rge_write_mac_ocp(sc, 0xc0ac, val | 0x1f00);
745 1.9.4.2 martin
746 1.9.4.2 martin val = rge_read_mac_ocp(sc, 0xd430) & ~0x0fff;
747 1.9.4.2 martin rge_write_mac_ocp(sc, 0xd430, val | 0x047f);
748 1.9.4.2 martin
749 1.9.4.2 martin RGE_MAC_SETBIT(sc, 0xe84c, 0x00c0);
750 1.9.4.2 martin
751 1.9.4.2 martin /* Disable EEE plus. */
752 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xe080, 0x0002);
753 1.9.4.2 martin
754 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xea1c, 0x0004);
755 1.9.4.2 martin
756 1.9.4.2 martin RGE_MAC_SETBIT(sc, 0xeb54, 0x0001);
757 1.9.4.2 martin DELAY(1);
758 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xeb54, 0x0001);
759 1.9.4.2 martin
760 1.9.4.2 martin RGE_CLRBIT_4(sc, 0x1880, 0x0030);
761 1.9.4.2 martin
762 1.9.4.2 martin rge_write_mac_ocp(sc, 0xe098, 0xc302);
763 1.9.4.2 martin
764 1.9.4.2 martin if (ifp->if_capabilities & ETHERCAP_VLAN_HWTAGGING)
765 1.9.4.2 martin RGE_SETBIT_4(sc, RGE_RXCFG, RGE_RXCFG_VLANSTRIP);
766 1.9.4.2 martin
767 1.9.4.2 martin RGE_SETBIT_2(sc, RGE_CPLUSCMD, RGE_CPLUSCMD_RXCSUM);
768 1.9.4.2 martin
769 1.9.4.2 martin for (i = 0; i < 10; i++) {
770 1.9.4.2 martin if (!(rge_read_mac_ocp(sc, 0xe00e) & 0x2000))
771 1.9.4.2 martin break;
772 1.9.4.2 martin DELAY(1000);
773 1.9.4.2 martin }
774 1.9.4.2 martin
775 1.9.4.2 martin /* Disable RXDV gate. */
776 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_PPSW, 0x08);
777 1.9.4.2 martin DELAY(2000);
778 1.9.4.2 martin
779 1.9.4.2 martin rge_ifmedia_upd(ifp);
780 1.9.4.2 martin
781 1.9.4.2 martin /* Enable transmit and receive. */
782 1.9.4.2 martin RGE_WRITE_1(sc, RGE_CMD, RGE_CMD_TXENB | RGE_CMD_RXENB);
783 1.9.4.2 martin
784 1.9.4.2 martin /* Program promiscuous mode and multicast filters. */
785 1.9.4.2 martin rge_iff(sc);
786 1.9.4.2 martin
787 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_CFG2, RGE_CFG2_CLKREQ_EN);
788 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_CFG5, RGE_CFG5_PME_STS);
789 1.9.4.2 martin
790 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
791 1.9.4.2 martin
792 1.9.4.2 martin /* Enable interrupts. */
793 1.9.4.2 martin rge_setup_intr(sc, RGE_IMTYPE_SIM);
794 1.9.4.2 martin
795 1.9.4.2 martin ifp->if_flags |= IFF_RUNNING;
796 1.9.4.2 martin CLR(ifp->if_flags, IFF_OACTIVE);
797 1.9.4.2 martin
798 1.9.4.2 martin callout_schedule(&sc->sc_timeout, 1);
799 1.9.4.2 martin
800 1.9.4.2 martin return (0);
801 1.9.4.2 martin }
802 1.9.4.2 martin
803 1.9.4.2 martin /*
804 1.9.4.2 martin * Stop the adapter and free any mbufs allocated to the RX and TX lists.
805 1.9.4.2 martin */
806 1.9.4.2 martin void
807 1.9.4.2 martin rge_stop(struct ifnet *ifp)
808 1.9.4.2 martin {
809 1.9.4.2 martin struct rge_softc *sc = ifp->if_softc;
810 1.9.4.2 martin int i;
811 1.9.4.2 martin
812 1.9.4.2 martin timeout_del(&sc->sc_timeout);
813 1.9.4.2 martin
814 1.9.4.2 martin ifp->if_timer = 0;
815 1.9.4.2 martin ifp->if_flags &= ~IFF_RUNNING;
816 1.9.4.2 martin sc->rge_timerintr = 0;
817 1.9.4.2 martin
818 1.9.4.2 martin RGE_CLRBIT_4(sc, RGE_RXCFG, RGE_RXCFG_ALLPHYS | RGE_RXCFG_INDIV |
819 1.9.4.2 martin RGE_RXCFG_MULTI | RGE_RXCFG_BROAD | RGE_RXCFG_RUNT |
820 1.9.4.2 martin RGE_RXCFG_ERRPKT);
821 1.9.4.2 martin
822 1.9.4.2 martin RGE_WRITE_4(sc, RGE_IMR, 0);
823 1.9.4.2 martin RGE_WRITE_4(sc, RGE_ISR, 0xffffffff);
824 1.9.4.2 martin
825 1.9.4.2 martin rge_reset(sc);
826 1.9.4.2 martin
827 1.9.4.2 martin intr_barrier(sc->sc_ih);
828 1.9.4.2 martin ifq_barrier(&ifp->if_snd);
829 1.9.4.2 martin /* ifq_clr_oactive(&ifp->if_snd); Sevan - OpenBSD queue API */
830 1.9.4.2 martin
831 1.9.4.2 martin if (sc->rge_head != NULL) {
832 1.9.4.2 martin m_freem(sc->rge_head);
833 1.9.4.2 martin sc->rge_head = sc->rge_tail = NULL;
834 1.9.4.2 martin }
835 1.9.4.2 martin
836 1.9.4.2 martin /* Free the TX list buffers. */
837 1.9.4.2 martin for (i = 0; i < RGE_TX_LIST_CNT; i++) {
838 1.9.4.2 martin if (sc->rge_ldata.rge_txq[i].txq_mbuf != NULL) {
839 1.9.4.2 martin bus_dmamap_unload(sc->sc_dmat,
840 1.9.4.2 martin sc->rge_ldata.rge_txq[i].txq_dmamap);
841 1.9.4.2 martin m_freem(sc->rge_ldata.rge_txq[i].txq_mbuf);
842 1.9.4.2 martin sc->rge_ldata.rge_txq[i].txq_mbuf = NULL;
843 1.9.4.2 martin }
844 1.9.4.2 martin }
845 1.9.4.2 martin
846 1.9.4.2 martin /* Free the RX list buffers. */
847 1.9.4.2 martin for (i = 0; i < RGE_RX_LIST_CNT; i++) {
848 1.9.4.2 martin if (sc->rge_ldata.rge_rxq[i].rxq_mbuf != NULL) {
849 1.9.4.2 martin bus_dmamap_unload(sc->sc_dmat,
850 1.9.4.2 martin sc->rge_ldata.rge_rxq[i].rxq_dmamap);
851 1.9.4.2 martin m_freem(sc->rge_ldata.rge_rxq[i].rxq_mbuf);
852 1.9.4.2 martin sc->rge_ldata.rge_rxq[i].rxq_mbuf = NULL;
853 1.9.4.2 martin }
854 1.9.4.2 martin }
855 1.9.4.2 martin }
856 1.9.4.2 martin
857 1.9.4.2 martin /*
858 1.9.4.2 martin * Set media options.
859 1.9.4.2 martin */
860 1.9.4.2 martin int
861 1.9.4.2 martin rge_ifmedia_upd(struct ifnet *ifp)
862 1.9.4.2 martin {
863 1.9.4.2 martin struct rge_softc *sc = ifp->if_softc;
864 1.9.4.2 martin struct ifmedia *ifm = &sc->sc_media;
865 1.9.4.2 martin int anar, gig, val;
866 1.9.4.2 martin
867 1.9.4.2 martin if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
868 1.9.4.2 martin return (EINVAL);
869 1.9.4.2 martin
870 1.9.4.2 martin /* Disable Gigabit Lite. */
871 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa428, 0x0200);
872 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa5ea, 0x0001);
873 1.9.4.2 martin
874 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa5d4);
875 1.9.4.2 martin val &= ~RGE_ADV_2500TFDX;
876 1.9.4.2 martin
877 1.9.4.2 martin anar = gig = 0;
878 1.9.4.2 martin switch (IFM_SUBTYPE(ifm->ifm_media)) {
879 1.9.4.2 martin case IFM_AUTO:
880 1.9.4.2 martin anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
881 1.9.4.2 martin gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
882 1.9.4.2 martin val |= RGE_ADV_2500TFDX;
883 1.9.4.2 martin break;
884 1.9.4.2 martin case IFM_2500_T:
885 1.9.4.2 martin anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
886 1.9.4.2 martin gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
887 1.9.4.2 martin val |= RGE_ADV_2500TFDX;
888 1.9.4.2 martin ifp->if_baudrate = IF_Mbps(2500);
889 1.9.4.2 martin break;
890 1.9.4.2 martin case IFM_1000_T:
891 1.9.4.2 martin anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
892 1.9.4.2 martin gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
893 1.9.4.2 martin ifp->if_baudrate = IF_Gbps(1);
894 1.9.4.2 martin break;
895 1.9.4.2 martin case IFM_100_TX:
896 1.9.4.2 martin anar |= ANAR_TX | ANAR_TX_FD;
897 1.9.4.2 martin ifp->if_baudrate = IF_Mbps(100);
898 1.9.4.2 martin break;
899 1.9.4.2 martin case IFM_10_T:
900 1.9.4.2 martin anar |= ANAR_10 | ANAR_10_FD;
901 1.9.4.2 martin ifp->if_baudrate = IF_Mbps(10);
902 1.9.4.2 martin break;
903 1.9.4.2 martin default:
904 1.9.4.2 martin printf("%s: unsupported media type\n", sc->sc_dev.dv_xname);
905 1.9.4.2 martin return (EINVAL);
906 1.9.4.2 martin }
907 1.9.4.2 martin
908 1.9.4.2 martin rge_write_phy(sc, 0, MII_ANAR, anar | ANAR_PAUSE_ASYM | ANAR_FC);
909 1.9.4.2 martin rge_write_phy(sc, 0, MII_100T2CR, gig);
910 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa5d4, val);
911 1.9.4.2 martin rge_write_phy(sc, 0, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
912 1.9.4.2 martin
913 1.9.4.2 martin return (0);
914 1.9.4.2 martin }
915 1.9.4.2 martin
916 1.9.4.2 martin /*
917 1.9.4.2 martin * Report current media status.
918 1.9.4.2 martin */
919 1.9.4.2 martin void
920 1.9.4.2 martin rge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
921 1.9.4.2 martin {
922 1.9.4.2 martin struct rge_softc *sc = ifp->if_softc;
923 1.9.4.2 martin uint16_t status = 0;
924 1.9.4.2 martin
925 1.9.4.2 martin ifmr->ifm_status = IFM_AVALID;
926 1.9.4.2 martin ifmr->ifm_active = IFM_ETHER;
927 1.9.4.2 martin
928 1.9.4.2 martin if (rge_get_link_status(sc)) {
929 1.9.4.2 martin ifmr->ifm_status |= IFM_ACTIVE;
930 1.9.4.2 martin
931 1.9.4.2 martin status = RGE_READ_2(sc, RGE_PHYSTAT);
932 1.9.4.2 martin if ((status & RGE_PHYSTAT_FDX) ||
933 1.9.4.2 martin (status & RGE_PHYSTAT_2500MBPS))
934 1.9.4.2 martin ifmr->ifm_active |= IFM_FDX;
935 1.9.4.2 martin else
936 1.9.4.2 martin ifmr->ifm_active |= IFM_HDX;
937 1.9.4.2 martin
938 1.9.4.2 martin if (status & RGE_PHYSTAT_10MBPS)
939 1.9.4.2 martin ifmr->ifm_active |= IFM_10_T;
940 1.9.4.2 martin else if (status & RGE_PHYSTAT_100MBPS)
941 1.9.4.2 martin ifmr->ifm_active |= IFM_100_TX;
942 1.9.4.2 martin else if (status & RGE_PHYSTAT_1000MBPS)
943 1.9.4.2 martin ifmr->ifm_active |= IFM_1000_T;
944 1.9.4.2 martin else if (status & RGE_PHYSTAT_2500MBPS)
945 1.9.4.2 martin ifmr->ifm_active |= IFM_2500_T;
946 1.9.4.2 martin }
947 1.9.4.2 martin }
948 1.9.4.2 martin
949 1.9.4.2 martin /*
950 1.9.4.2 martin * Allocate memory for RX/TX rings.
951 1.9.4.2 martin */
952 1.9.4.2 martin int
953 1.9.4.2 martin rge_allocmem(struct rge_softc *sc)
954 1.9.4.2 martin {
955 1.9.4.2 martin int error, i;
956 1.9.4.2 martin
957 1.9.4.2 martin /* Allocate DMA'able memory for the TX ring. */
958 1.9.4.2 martin error = bus_dmamap_create(sc->sc_dmat, RGE_TX_LIST_SZ, 1,
959 1.9.4.2 martin RGE_TX_LIST_SZ, 0, BUS_DMA_NOWAIT, &sc->rge_ldata.rge_tx_list_map);
960 1.9.4.2 martin if (error) {
961 1.9.4.2 martin printf("%s: can't create TX list map\n", sc->sc_dev.dv_xname);
962 1.9.4.2 martin return (error);
963 1.9.4.2 martin }
964 1.9.4.2 martin error = bus_dmamem_alloc(sc->sc_dmat, RGE_TX_LIST_SZ, RGE_ALIGN, 0,
965 1.9.4.2 martin &sc->rge_ldata.rge_tx_listseg, 1, &sc->rge_ldata.rge_tx_listnseg,
966 1.9.4.2 martin BUS_DMA_NOWAIT); /* XXX OpenBSD adds BUS_DMA_ZERO */
967 1.9.4.2 martin if (error) {
968 1.9.4.2 martin printf("%s: can't alloc TX list\n", sc->sc_dev.dv_xname);
969 1.9.4.2 martin return (error);
970 1.9.4.2 martin }
971 1.9.4.2 martin
972 1.9.4.2 martin /* Load the map for the TX ring. */
973 1.9.4.2 martin error = bus_dmamem_map(sc->sc_dmat, &sc->rge_ldata.rge_tx_listseg,
974 1.9.4.2 martin sc->rge_ldata.rge_tx_listnseg, RGE_TX_LIST_SZ,
975 1.9.4.2 martin (void **) &sc->rge_ldata.rge_tx_list,
976 1.9.4.2 martin BUS_DMA_NOWAIT); /* XXX OpenBSD adds BUS_DMA_COHERENT */
977 1.9.4.2 martin if (error) {
978 1.9.4.2 martin printf("%s: can't map TX dma buffers\n", sc->sc_dev.dv_xname);
979 1.9.4.2 martin bus_dmamem_free(sc->sc_dmat, &sc->rge_ldata.rge_tx_listseg,
980 1.9.4.2 martin sc->rge_ldata.rge_tx_listnseg);
981 1.9.4.2 martin return (error);
982 1.9.4.2 martin }
983 1.9.4.2 martin error = bus_dmamap_load(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map,
984 1.9.4.2 martin sc->rge_ldata.rge_tx_list, RGE_TX_LIST_SZ, NULL, BUS_DMA_NOWAIT);
985 1.9.4.2 martin if (error) {
986 1.9.4.2 martin printf("%s: can't load TX dma map\n", sc->sc_dev.dv_xname);
987 1.9.4.2 martin bus_dmamap_destroy(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map);
988 1.9.4.2 martin bus_dmamem_unmap(sc->sc_dmat,
989 1.9.4.2 martin sc->rge_ldata.rge_tx_list, RGE_TX_LIST_SZ);
990 1.9.4.2 martin bus_dmamem_free(sc->sc_dmat, &sc->rge_ldata.rge_tx_listseg,
991 1.9.4.2 martin sc->rge_ldata.rge_tx_listnseg);
992 1.9.4.2 martin return (error);
993 1.9.4.2 martin }
994 1.9.4.2 martin
995 1.9.4.2 martin /* Create DMA maps for TX buffers. */
996 1.9.4.2 martin for (i = 0; i < RGE_TX_LIST_CNT; i++) {
997 1.9.4.2 martin error = bus_dmamap_create(sc->sc_dmat, RGE_JUMBO_FRAMELEN,
998 1.9.4.2 martin RGE_TX_NSEGS, RGE_JUMBO_FRAMELEN, 0, 0,
999 1.9.4.2 martin &sc->rge_ldata.rge_txq[i].txq_dmamap);
1000 1.9.4.2 martin if (error) {
1001 1.9.4.2 martin printf("%s: can't create DMA map for TX\n",
1002 1.9.4.2 martin sc->sc_dev.dv_xname);
1003 1.9.4.2 martin return (error);
1004 1.9.4.2 martin }
1005 1.9.4.2 martin }
1006 1.9.4.2 martin
1007 1.9.4.2 martin /* Allocate DMA'able memory for the RX ring. */
1008 1.9.4.2 martin error = bus_dmamap_create(sc->sc_dmat, RGE_RX_LIST_SZ, 1,
1009 1.9.4.2 martin RGE_RX_LIST_SZ, 0, 0, &sc->rge_ldata.rge_rx_list_map);
1010 1.9.4.2 martin if (error) {
1011 1.9.4.2 martin printf("%s: can't create RX list map\n", sc->sc_dev.dv_xname);
1012 1.9.4.2 martin return (error);
1013 1.9.4.2 martin }
1014 1.9.4.2 martin error = bus_dmamem_alloc(sc->sc_dmat, RGE_RX_LIST_SZ, RGE_ALIGN, 0,
1015 1.9.4.2 martin &sc->rge_ldata.rge_rx_listseg, 1, &sc->rge_ldata.rge_rx_listnseg,
1016 1.9.4.2 martin BUS_DMA_NOWAIT); /* XXX OpenBSD adds BUS_DMA_ZERO */
1017 1.9.4.2 martin if (error) {
1018 1.9.4.2 martin printf("%s: can't alloc RX list\n", sc->sc_dev.dv_xname);
1019 1.9.4.2 martin return (error);
1020 1.9.4.2 martin }
1021 1.9.4.2 martin
1022 1.9.4.2 martin /* Load the map for the RX ring. */
1023 1.9.4.2 martin error = bus_dmamem_map(sc->sc_dmat, &sc->rge_ldata.rge_rx_listseg,
1024 1.9.4.2 martin sc->rge_ldata.rge_rx_listnseg, RGE_RX_LIST_SZ,
1025 1.9.4.2 martin (void **) &sc->rge_ldata.rge_rx_list,
1026 1.9.4.2 martin BUS_DMA_NOWAIT); /* XXX OpenBSD adds BUS_DMA_COHERENT */
1027 1.9.4.2 martin if (error) {
1028 1.9.4.2 martin printf("%s: can't map RX dma buffers\n", sc->sc_dev.dv_xname);
1029 1.9.4.2 martin bus_dmamem_free(sc->sc_dmat, &sc->rge_ldata.rge_rx_listseg,
1030 1.9.4.2 martin sc->rge_ldata.rge_rx_listnseg);
1031 1.9.4.2 martin return (error);
1032 1.9.4.2 martin }
1033 1.9.4.2 martin error = bus_dmamap_load(sc->sc_dmat, sc->rge_ldata.rge_rx_list_map,
1034 1.9.4.2 martin sc->rge_ldata.rge_rx_list, RGE_RX_LIST_SZ, NULL, BUS_DMA_NOWAIT);
1035 1.9.4.2 martin if (error) {
1036 1.9.4.2 martin printf("%s: can't load RX dma map\n", sc->sc_dev.dv_xname);
1037 1.9.4.2 martin bus_dmamap_destroy(sc->sc_dmat, sc->rge_ldata.rge_rx_list_map);
1038 1.9.4.2 martin bus_dmamem_unmap(sc->sc_dmat,
1039 1.9.4.2 martin sc->rge_ldata.rge_rx_list, RGE_RX_LIST_SZ);
1040 1.9.4.2 martin bus_dmamem_free(sc->sc_dmat, &sc->rge_ldata.rge_rx_listseg,
1041 1.9.4.2 martin sc->rge_ldata.rge_rx_listnseg);
1042 1.9.4.2 martin return (error);
1043 1.9.4.2 martin }
1044 1.9.4.2 martin
1045 1.9.4.2 martin /* Create DMA maps for RX buffers. */
1046 1.9.4.2 martin for (i = 0; i < RGE_RX_LIST_CNT; i++) {
1047 1.9.4.2 martin error = bus_dmamap_create(sc->sc_dmat, RGE_JUMBO_FRAMELEN, 1,
1048 1.9.4.2 martin RGE_JUMBO_FRAMELEN, 0, 0,
1049 1.9.4.2 martin &sc->rge_ldata.rge_rxq[i].rxq_dmamap);
1050 1.9.4.2 martin if (error) {
1051 1.9.4.2 martin printf("%s: can't create DMA map for RX\n",
1052 1.9.4.2 martin sc->sc_dev.dv_xname);
1053 1.9.4.2 martin return (error);
1054 1.9.4.2 martin }
1055 1.9.4.2 martin }
1056 1.9.4.2 martin
1057 1.9.4.2 martin return (error);
1058 1.9.4.2 martin }
1059 1.9.4.2 martin
1060 1.9.4.2 martin /*
1061 1.9.4.2 martin * Initialize the RX descriptor and attach an mbuf cluster.
1062 1.9.4.2 martin */
1063 1.9.4.2 martin int
1064 1.9.4.2 martin rge_newbuf(struct rge_softc *sc, int idx)
1065 1.9.4.2 martin {
1066 1.9.4.2 martin struct mbuf *m;
1067 1.9.4.2 martin struct rge_rx_desc *r;
1068 1.9.4.2 martin struct rge_rxq *rxq;
1069 1.9.4.2 martin bus_dmamap_t rxmap;
1070 1.9.4.2 martin
1071 1.9.4.2 martin m = MCLGETI(NULL, M_DONTWAIT, NULL, RGE_JUMBO_FRAMELEN);
1072 1.9.4.2 martin if (m == NULL)
1073 1.9.4.2 martin return (ENOBUFS);
1074 1.9.4.2 martin
1075 1.9.4.2 martin m->m_len = m->m_pkthdr.len = RGE_JUMBO_FRAMELEN;
1076 1.9.4.2 martin
1077 1.9.4.2 martin rxq = &sc->rge_ldata.rge_rxq[idx];
1078 1.9.4.2 martin rxmap = rxq->rxq_dmamap;
1079 1.9.4.2 martin
1080 1.9.4.2 martin if (bus_dmamap_load_mbuf(sc->sc_dmat, rxmap, m, BUS_DMA_NOWAIT))
1081 1.9.4.2 martin goto out;
1082 1.9.4.2 martin
1083 1.9.4.2 martin bus_dmamap_sync(sc->sc_dmat, rxmap, 0, rxmap->dm_mapsize,
1084 1.9.4.2 martin BUS_DMASYNC_PREREAD);
1085 1.9.4.2 martin
1086 1.9.4.2 martin /* Map the segments into RX descriptors. */
1087 1.9.4.2 martin r = &sc->rge_ldata.rge_rx_list[idx];
1088 1.9.4.2 martin
1089 1.9.4.2 martin if (RGE_OWN(r)) {
1090 1.9.4.2 martin printf("%s: tried to map busy RX descriptor\n",
1091 1.9.4.2 martin sc->sc_dev.dv_xname);
1092 1.9.4.2 martin goto out;
1093 1.9.4.2 martin }
1094 1.9.4.2 martin
1095 1.9.4.2 martin rxq->rxq_mbuf = m;
1096 1.9.4.2 martin
1097 1.9.4.2 martin r->rge_extsts = 0;
1098 1.9.4.2 martin r->rge_addrlo = htole32(RGE_ADDR_LO(rxmap->dm_segs[0].ds_addr));
1099 1.9.4.2 martin r->rge_addrhi = htole32(RGE_ADDR_HI(rxmap->dm_segs[0].ds_addr));
1100 1.9.4.2 martin
1101 1.9.4.2 martin r->rge_cmdsts = htole32(rxmap->dm_segs[0].ds_len);
1102 1.9.4.2 martin if (idx == RGE_RX_LIST_CNT - 1)
1103 1.9.4.2 martin r->rge_cmdsts |= htole32(RGE_RDCMDSTS_EOR);
1104 1.9.4.2 martin
1105 1.9.4.2 martin r->rge_cmdsts |= htole32(RGE_RDCMDSTS_OWN);
1106 1.9.4.2 martin
1107 1.9.4.2 martin bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_rx_list_map,
1108 1.9.4.2 martin idx * sizeof(struct rge_rx_desc), sizeof(struct rge_rx_desc),
1109 1.9.4.2 martin BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1110 1.9.4.2 martin
1111 1.9.4.2 martin return (0);
1112 1.9.4.2 martin out:
1113 1.9.4.2 martin if (m != NULL)
1114 1.9.4.2 martin m_freem(m);
1115 1.9.4.2 martin return (ENOMEM);
1116 1.9.4.2 martin }
1117 1.9.4.2 martin
1118 1.9.4.2 martin void
1119 1.9.4.2 martin rge_discard_rxbuf(struct rge_softc *sc, int idx)
1120 1.9.4.2 martin {
1121 1.9.4.2 martin struct rge_rx_desc *r;
1122 1.9.4.2 martin
1123 1.9.4.2 martin r = &sc->rge_ldata.rge_rx_list[idx];
1124 1.9.4.2 martin
1125 1.9.4.2 martin r->rge_cmdsts = htole32(RGE_JUMBO_FRAMELEN);
1126 1.9.4.2 martin r->rge_extsts = 0;
1127 1.9.4.2 martin if (idx == RGE_RX_LIST_CNT - 1)
1128 1.9.4.2 martin r->rge_cmdsts |= htole32(RGE_RDCMDSTS_EOR);
1129 1.9.4.2 martin r->rge_cmdsts |= htole32(RGE_RDCMDSTS_OWN);
1130 1.9.4.2 martin
1131 1.9.4.2 martin bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_rx_list_map,
1132 1.9.4.2 martin idx * sizeof(struct rge_rx_desc), sizeof(struct rge_rx_desc),
1133 1.9.4.2 martin BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1134 1.9.4.2 martin }
1135 1.9.4.2 martin
1136 1.9.4.2 martin int
1137 1.9.4.2 martin rge_rx_list_init(struct rge_softc *sc)
1138 1.9.4.2 martin {
1139 1.9.4.2 martin int i;
1140 1.9.4.2 martin
1141 1.9.4.2 martin memset(sc->rge_ldata.rge_rx_list, 0, RGE_RX_LIST_SZ);
1142 1.9.4.2 martin
1143 1.9.4.2 martin for (i = 0; i < RGE_RX_LIST_CNT; i++) {
1144 1.9.4.2 martin sc->rge_ldata.rge_rxq[i].rxq_mbuf = NULL;
1145 1.9.4.2 martin if (rge_newbuf(sc, i) == ENOBUFS)
1146 1.9.4.2 martin return (ENOBUFS);
1147 1.9.4.2 martin }
1148 1.9.4.2 martin
1149 1.9.4.2 martin sc->rge_ldata.rge_rxq_prodidx = 0;
1150 1.9.4.2 martin sc->rge_head = sc->rge_tail = NULL;
1151 1.9.4.2 martin
1152 1.9.4.2 martin return (0);
1153 1.9.4.2 martin }
1154 1.9.4.2 martin
1155 1.9.4.2 martin void
1156 1.9.4.2 martin rge_tx_list_init(struct rge_softc *sc)
1157 1.9.4.2 martin {
1158 1.9.4.2 martin int i;
1159 1.9.4.2 martin
1160 1.9.4.2 martin memset(sc->rge_ldata.rge_tx_list, 0, RGE_TX_LIST_SZ);
1161 1.9.4.2 martin
1162 1.9.4.2 martin for (i = 0; i < RGE_TX_LIST_CNT; i++)
1163 1.9.4.2 martin sc->rge_ldata.rge_txq[i].txq_mbuf = NULL;
1164 1.9.4.2 martin
1165 1.9.4.2 martin bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map, 0,
1166 1.9.4.2 martin sc->rge_ldata.rge_tx_list_map->dm_mapsize,
1167 1.9.4.2 martin BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1168 1.9.4.2 martin
1169 1.9.4.2 martin sc->rge_ldata.rge_txq_prodidx = sc->rge_ldata.rge_txq_considx = 0;
1170 1.9.4.2 martin }
1171 1.9.4.2 martin
1172 1.9.4.2 martin int
1173 1.9.4.2 martin rge_rxeof(struct rge_softc *sc)
1174 1.9.4.2 martin {
1175 1.9.4.2 martin struct mbuf_list ml = MBUF_LIST_INITIALIZER();
1176 1.9.4.2 martin struct mbuf *m;
1177 1.9.4.2 martin struct ifnet *ifp = &sc->sc_ec.ec_if;
1178 1.9.4.2 martin struct rge_rx_desc *cur_rx;
1179 1.9.4.2 martin struct rge_rxq *rxq;
1180 1.9.4.2 martin uint32_t rxstat, extsts;
1181 1.9.4.2 martin int i, total_len, rx = 0;
1182 1.9.4.2 martin
1183 1.9.4.2 martin for (i = sc->rge_ldata.rge_rxq_prodidx; ; i = RGE_NEXT_RX_DESC(i)) {
1184 1.9.4.2 martin /* Invalidate the descriptor memory. */
1185 1.9.4.2 martin bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_rx_list_map,
1186 1.9.4.2 martin i * sizeof(struct rge_rx_desc), sizeof(struct rge_rx_desc),
1187 1.9.4.2 martin BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1188 1.9.4.2 martin
1189 1.9.4.2 martin cur_rx = &sc->rge_ldata.rge_rx_list[i];
1190 1.9.4.2 martin
1191 1.9.4.2 martin if (RGE_OWN(cur_rx))
1192 1.9.4.2 martin break;
1193 1.9.4.2 martin
1194 1.9.4.2 martin rxstat = letoh32(cur_rx->rge_cmdsts);
1195 1.9.4.2 martin extsts = letoh32(cur_rx->rge_extsts);
1196 1.9.4.2 martin
1197 1.9.4.2 martin total_len = RGE_RXBYTES(cur_rx);
1198 1.9.4.2 martin rxq = &sc->rge_ldata.rge_rxq[i];
1199 1.9.4.2 martin m = rxq->rxq_mbuf;
1200 1.9.4.2 martin rx = 1;
1201 1.9.4.2 martin
1202 1.9.4.2 martin /* Invalidate the RX mbuf and unload its map. */
1203 1.9.4.2 martin bus_dmamap_sync(sc->sc_dmat, rxq->rxq_dmamap, 0,
1204 1.9.4.2 martin rxq->rxq_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
1205 1.9.4.2 martin bus_dmamap_unload(sc->sc_dmat, rxq->rxq_dmamap);
1206 1.9.4.2 martin
1207 1.9.4.2 martin if ((rxstat & (RGE_RDCMDSTS_SOF | RGE_RDCMDSTS_EOF)) !=
1208 1.9.4.2 martin (RGE_RDCMDSTS_SOF | RGE_RDCMDSTS_EOF)) {
1209 1.9.4.2 martin rge_discard_rxbuf(sc, i);
1210 1.9.4.2 martin continue;
1211 1.9.4.2 martin }
1212 1.9.4.2 martin
1213 1.9.4.2 martin if (rxstat & RGE_RDCMDSTS_RXERRSUM) {
1214 1.9.4.2 martin if_statinc(ifp, if_ierrors);
1215 1.9.4.2 martin /*
1216 1.9.4.2 martin * If this is part of a multi-fragment packet,
1217 1.9.4.2 martin * discard all the pieces.
1218 1.9.4.2 martin */
1219 1.9.4.2 martin if (sc->rge_head != NULL) {
1220 1.9.4.2 martin m_freem(sc->rge_head);
1221 1.9.4.2 martin sc->rge_head = sc->rge_tail = NULL;
1222 1.9.4.2 martin }
1223 1.9.4.2 martin rge_discard_rxbuf(sc, i);
1224 1.9.4.2 martin continue;
1225 1.9.4.2 martin }
1226 1.9.4.2 martin
1227 1.9.4.2 martin /*
1228 1.9.4.2 martin * If allocating a replacement mbuf fails,
1229 1.9.4.2 martin * reload the current one.
1230 1.9.4.2 martin */
1231 1.9.4.2 martin
1232 1.9.4.2 martin if (rge_newbuf(sc, i) == ENOBUFS) {
1233 1.9.4.2 martin if (sc->rge_head != NULL) {
1234 1.9.4.2 martin m_freem(sc->rge_head);
1235 1.9.4.2 martin sc->rge_head = sc->rge_tail = NULL;
1236 1.9.4.2 martin }
1237 1.9.4.2 martin rge_discard_rxbuf(sc, i);
1238 1.9.4.2 martin continue;
1239 1.9.4.2 martin }
1240 1.9.4.2 martin
1241 1.9.4.2 martin if (sc->rge_head != NULL) {
1242 1.9.4.2 martin m->m_len = total_len;
1243 1.9.4.2 martin /*
1244 1.9.4.2 martin * Special case: if there's 4 bytes or less
1245 1.9.4.2 martin * in this buffer, the mbuf can be discarded:
1246 1.9.4.2 martin * the last 4 bytes is the CRC, which we don't
1247 1.9.4.2 martin * care about anyway.
1248 1.9.4.2 martin */
1249 1.9.4.2 martin if (m->m_len <= ETHER_CRC_LEN) {
1250 1.9.4.2 martin sc->rge_tail->m_len -=
1251 1.9.4.2 martin (ETHER_CRC_LEN - m->m_len);
1252 1.9.4.2 martin m_freem(m);
1253 1.9.4.2 martin } else {
1254 1.9.4.2 martin m->m_len -= ETHER_CRC_LEN;
1255 1.9.4.2 martin m->m_flags &= ~M_PKTHDR;
1256 1.9.4.2 martin sc->rge_tail->m_next = m;
1257 1.9.4.2 martin }
1258 1.9.4.2 martin m = sc->rge_head;
1259 1.9.4.2 martin sc->rge_head = sc->rge_tail = NULL;
1260 1.9.4.2 martin m->m_pkthdr.len = total_len - ETHER_CRC_LEN;
1261 1.9.4.2 martin } else
1262 1.9.4.2 martin m->m_pkthdr.len = m->m_len =
1263 1.9.4.2 martin (total_len - ETHER_CRC_LEN);
1264 1.9.4.2 martin
1265 1.9.4.2 martin /* Check IP header checksum. */
1266 1.9.4.2 martin if (!(rxstat & RGE_RDCMDSTS_IPCSUMERR) &&
1267 1.9.4.2 martin (extsts & RGE_RDEXTSTS_IPV4))
1268 1.9.4.2 martin m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
1269 1.9.4.2 martin
1270 1.9.4.2 martin /* Check TCP/UDP checksum. */
1271 1.9.4.2 martin if ((extsts & (RGE_RDEXTSTS_IPV4 | RGE_RDEXTSTS_IPV6)) &&
1272 1.9.4.2 martin (((rxstat & RGE_RDCMDSTS_TCPPKT) &&
1273 1.9.4.2 martin !(rxstat & RGE_RDCMDSTS_TCPCSUMERR)) ||
1274 1.9.4.2 martin ((rxstat & RGE_RDCMDSTS_UDPPKT) &&
1275 1.9.4.2 martin !(rxstat & RGE_RDCMDSTS_UDPCSUMERR))))
1276 1.9.4.2 martin m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK |
1277 1.9.4.2 martin M_UDP_CSUM_IN_OK;
1278 1.9.4.2 martin
1279 1.9.4.2 martin #if NVLAN > 0
1280 1.9.4.2 martin if (extsts & RGE_RDEXTSTS_VTAG) {
1281 1.9.4.2 martin m->m_pkthdr.ether_vtag =
1282 1.9.4.2 martin ntohs(extsts & RGE_RDEXTSTS_VLAN_MASK);
1283 1.9.4.2 martin m->m_flags |= M_VLANTAG;
1284 1.9.4.2 martin }
1285 1.9.4.2 martin #endif
1286 1.9.4.2 martin
1287 1.9.4.2 martin ml_enqueue(&ml, m);
1288 1.9.4.2 martin }
1289 1.9.4.2 martin
1290 1.9.4.2 martin sc->rge_ldata.rge_rxq_prodidx = i;
1291 1.9.4.2 martin
1292 1.9.4.2 martin if_input(ifp, &ml);
1293 1.9.4.2 martin
1294 1.9.4.2 martin return (rx);
1295 1.9.4.2 martin }
1296 1.9.4.2 martin
1297 1.9.4.2 martin int
1298 1.9.4.2 martin rge_txeof(struct rge_softc *sc)
1299 1.9.4.2 martin {
1300 1.9.4.2 martin struct ifnet *ifp = &sc->sc_ec.ec_if;
1301 1.9.4.2 martin struct rge_txq *txq;
1302 1.9.4.2 martin uint32_t txstat;
1303 1.9.4.2 martin int cons, idx, prod;
1304 1.9.4.2 martin int free = 0;
1305 1.9.4.2 martin
1306 1.9.4.2 martin prod = sc->rge_ldata.rge_txq_prodidx;
1307 1.9.4.2 martin cons = sc->rge_ldata.rge_txq_considx;
1308 1.9.4.2 martin
1309 1.9.4.2 martin while (prod != cons) {
1310 1.9.4.2 martin txq = &sc->rge_ldata.rge_txq[cons];
1311 1.9.4.2 martin idx = txq->txq_descidx;
1312 1.9.4.2 martin
1313 1.9.4.2 martin bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map,
1314 1.9.4.2 martin idx * sizeof(struct rge_tx_desc),
1315 1.9.4.2 martin sizeof(struct rge_tx_desc),
1316 1.9.4.2 martin BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1317 1.9.4.2 martin
1318 1.9.4.2 martin txstat = letoh32(sc->rge_ldata.rge_tx_list[idx].rge_cmdsts);
1319 1.9.4.2 martin
1320 1.9.4.2 martin if (txstat & RGE_TDCMDSTS_OWN) {
1321 1.9.4.2 martin free = 2;
1322 1.9.4.2 martin break;
1323 1.9.4.2 martin }
1324 1.9.4.2 martin
1325 1.9.4.2 martin bus_dmamap_sync(sc->sc_dmat, txq->txq_dmamap, 0,
1326 1.9.4.2 martin txq->txq_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1327 1.9.4.2 martin bus_dmamap_unload(sc->sc_dmat, txq->txq_dmamap);
1328 1.9.4.2 martin m_freem(txq->txq_mbuf);
1329 1.9.4.2 martin txq->txq_mbuf = NULL;
1330 1.9.4.2 martin
1331 1.9.4.2 martin if (txstat & (RGE_TDCMDSTS_EXCESSCOLL | RGE_TDCMDSTS_COLL))
1332 1.9.4.2 martin if_statinc(ifp, if_collisions);
1333 1.9.4.2 martin if (txstat & RGE_TDCMDSTS_TXERR)
1334 1.9.4.2 martin if_statinc(ifp, if_oerrors);
1335 1.9.4.2 martin
1336 1.9.4.2 martin bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map,
1337 1.9.4.2 martin idx * sizeof(struct rge_tx_desc),
1338 1.9.4.2 martin sizeof(struct rge_tx_desc),
1339 1.9.4.2 martin BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1340 1.9.4.2 martin
1341 1.9.4.2 martin cons = RGE_NEXT_TX_DESC(idx);
1342 1.9.4.2 martin free = 1;
1343 1.9.4.2 martin }
1344 1.9.4.2 martin
1345 1.9.4.2 martin if (free == 0)
1346 1.9.4.2 martin return (0);
1347 1.9.4.2 martin
1348 1.9.4.2 martin sc->rge_ldata.rge_txq_considx = cons;
1349 1.9.4.2 martin
1350 1.9.4.2 martin if (ifq_is_oactive(&ifp->if_snd))
1351 1.9.4.2 martin ifq_restart(&ifp->if_snd);
1352 1.9.4.2 martin else if (free == 2)
1353 1.9.4.2 martin ifq_serialize(&ifp->if_snd, &sc->sc_task);
1354 1.9.4.2 martin else
1355 1.9.4.2 martin ifp->if_timer = 0;
1356 1.9.4.2 martin
1357 1.9.4.2 martin return (1);
1358 1.9.4.2 martin }
1359 1.9.4.2 martin
1360 1.9.4.2 martin void
1361 1.9.4.2 martin rge_reset(struct rge_softc *sc)
1362 1.9.4.2 martin {
1363 1.9.4.2 martin int i;
1364 1.9.4.2 martin
1365 1.9.4.2 martin /* Enable RXDV gate. */
1366 1.9.4.2 martin RGE_SETBIT_1(sc, RGE_PPSW, 0x08);
1367 1.9.4.2 martin DELAY(2000);
1368 1.9.4.2 martin
1369 1.9.4.2 martin for (i = 0; i < 10; i++) {
1370 1.9.4.2 martin DELAY(100);
1371 1.9.4.2 martin if ((RGE_READ_1(sc, RGE_MCUCMD) & (RGE_MCUCMD_RXFIFO_EMPTY |
1372 1.9.4.2 martin RGE_MCUCMD_TXFIFO_EMPTY)) == (RGE_MCUCMD_RXFIFO_EMPTY |
1373 1.9.4.2 martin RGE_MCUCMD_TXFIFO_EMPTY))
1374 1.9.4.2 martin break;
1375 1.9.4.2 martin }
1376 1.9.4.2 martin
1377 1.9.4.2 martin /* Soft reset. */
1378 1.9.4.2 martin RGE_WRITE_1(sc, RGE_CMD, RGE_CMD_RESET);
1379 1.9.4.2 martin
1380 1.9.4.2 martin for (i = 0; i < RGE_TIMEOUT; i++) {
1381 1.9.4.2 martin DELAY(100);
1382 1.9.4.2 martin if (!(RGE_READ_1(sc, RGE_CMD) & RGE_CMD_RESET))
1383 1.9.4.2 martin break;
1384 1.9.4.2 martin }
1385 1.9.4.2 martin if (i == RGE_TIMEOUT)
1386 1.9.4.2 martin printf("%s: reset never completed!\n", sc->sc_dev.dv_xname);
1387 1.9.4.2 martin }
1388 1.9.4.2 martin
1389 1.9.4.2 martin void
1390 1.9.4.2 martin rge_iff(struct rge_softc *sc)
1391 1.9.4.2 martin {
1392 1.9.4.2 martin struct ifnet *ifp = &sc->sc_ec.ec_if;
1393 1.9.4.2 martin struct ethercom *ac = &sc->sc_ec;
1394 1.9.4.2 martin struct ether_multi *enm;
1395 1.9.4.2 martin struct ether_multistep step;
1396 1.9.4.2 martin uint32_t hashes[2];
1397 1.9.4.2 martin uint32_t rxfilt;
1398 1.9.4.2 martin int h = 0;
1399 1.9.4.2 martin
1400 1.9.4.2 martin rxfilt = RGE_READ_4(sc, RGE_RXCFG);
1401 1.9.4.2 martin rxfilt &= ~(RGE_RXCFG_ALLPHYS | RGE_RXCFG_MULTI);
1402 1.9.4.2 martin ifp->if_flags &= ~IFF_ALLMULTI;
1403 1.9.4.2 martin
1404 1.9.4.2 martin /*
1405 1.9.4.2 martin * Always accept frames destined to our station address.
1406 1.9.4.2 martin * Always accept broadcast frames.
1407 1.9.4.2 martin */
1408 1.9.4.2 martin rxfilt |= RGE_RXCFG_INDIV | RGE_RXCFG_BROAD;
1409 1.9.4.2 martin
1410 1.9.4.2 martin if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
1411 1.9.4.2 martin ifp->if_flags |= IFF_ALLMULTI;
1412 1.9.4.2 martin rxfilt |= RGE_RXCFG_MULTI;
1413 1.9.4.2 martin if (ifp->if_flags & IFF_PROMISC)
1414 1.9.4.2 martin rxfilt |= RGE_RXCFG_ALLPHYS;
1415 1.9.4.2 martin hashes[0] = hashes[1] = 0xffffffff;
1416 1.9.4.2 martin } else {
1417 1.9.4.2 martin rxfilt |= RGE_RXCFG_MULTI;
1418 1.9.4.2 martin /* Program new filter. */
1419 1.9.4.2 martin memset(hashes, 0, sizeof(hashes));
1420 1.9.4.2 martin
1421 1.9.4.2 martin ETHER_FIRST_MULTI(step, ac, enm);
1422 1.9.4.2 martin while (enm != NULL) {
1423 1.9.4.2 martin h = ether_crc32_be(enm->enm_addrlo,
1424 1.9.4.2 martin ETHER_ADDR_LEN) >> 26;
1425 1.9.4.2 martin
1426 1.9.4.2 martin if (h < 32)
1427 1.9.4.2 martin hashes[0] |= (1 << h);
1428 1.9.4.2 martin else
1429 1.9.4.2 martin hashes[1] |= (1 << (h - 32));
1430 1.9.4.2 martin
1431 1.9.4.2 martin ETHER_NEXT_MULTI(step, enm);
1432 1.9.4.2 martin }
1433 1.9.4.2 martin }
1434 1.9.4.2 martin
1435 1.9.4.2 martin RGE_WRITE_4(sc, RGE_RXCFG, rxfilt);
1436 1.9.4.2 martin RGE_WRITE_4(sc, RGE_MAR0, bswap32(hashes[1]));
1437 1.9.4.2 martin RGE_WRITE_4(sc, RGE_MAR4, bswap32(hashes[0]));
1438 1.9.4.2 martin }
1439 1.9.4.2 martin
1440 1.9.4.2 martin void
1441 1.9.4.2 martin rge_set_phy_power(struct rge_softc *sc, int on)
1442 1.9.4.2 martin {
1443 1.9.4.2 martin int i;
1444 1.9.4.2 martin
1445 1.9.4.2 martin if (on) {
1446 1.9.4.2 martin RGE_SETBIT_1(sc, RGE_PMCH, 0xc0);
1447 1.9.4.2 martin
1448 1.9.4.2 martin rge_write_phy(sc, 0, MII_BMCR, BMCR_AUTOEN);
1449 1.9.4.2 martin
1450 1.9.4.2 martin for (i = 0; i < RGE_TIMEOUT; i++) {
1451 1.9.4.2 martin if ((rge_read_phy_ocp(sc, 0xa420) & 0x0080) == 3)
1452 1.9.4.2 martin break;
1453 1.9.4.2 martin DELAY(1000);
1454 1.9.4.2 martin }
1455 1.9.4.2 martin } else
1456 1.9.4.2 martin rge_write_phy(sc, 0, MII_BMCR, BMCR_AUTOEN | BMCR_PDOWN);
1457 1.9.4.2 martin }
1458 1.9.4.2 martin
1459 1.9.4.2 martin void
1460 1.9.4.2 martin rge_phy_config(struct rge_softc *sc)
1461 1.9.4.2 martin {
1462 1.9.4.2 martin uint16_t mcode_ver, val;
1463 1.9.4.2 martin int i;
1464 1.9.4.2 martin static const uint16_t mac_cfg3_a438_value[] =
1465 1.9.4.2 martin { 0x0043, 0x00a7, 0x00d6, 0x00ec, 0x00f6, 0x00fb, 0x00fd, 0x00ff,
1466 1.9.4.2 martin 0x00bb, 0x0058, 0x0029, 0x0013, 0x0009, 0x0004, 0x0002 };
1467 1.9.4.2 martin
1468 1.9.4.2 martin static const uint16_t mac_cfg3_b88e_value[] =
1469 1.9.4.2 martin { 0xc091, 0x6e12, 0xc092, 0x1214, 0xc094, 0x1516, 0xc096, 0x171b,
1470 1.9.4.2 martin 0xc098, 0x1b1c, 0xc09a, 0x1f1f, 0xc09c, 0x2021, 0xc09e, 0x2224,
1471 1.9.4.2 martin 0xc0a0, 0x2424, 0xc0a2, 0x2424, 0xc0a4, 0x2424, 0xc018, 0x0af2,
1472 1.9.4.2 martin 0xc01a, 0x0d4a, 0xc01c, 0x0f26, 0xc01e, 0x118d, 0xc020, 0x14f3,
1473 1.9.4.2 martin 0xc022, 0x175a, 0xc024, 0x19c0, 0xc026, 0x1c26, 0xc089, 0x6050,
1474 1.9.4.2 martin 0xc08a, 0x5f6e, 0xc08c, 0x6e6e, 0xc08e, 0x6e6e, 0xc090, 0x6e12 };
1475 1.9.4.2 martin
1476 1.9.4.2 martin /* Read microcode version. */
1477 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x801e);
1478 1.9.4.2 martin mcode_ver = rge_read_phy_ocp(sc, 0xa438);
1479 1.9.4.2 martin
1480 1.9.4.2 martin if (sc->rge_type == MAC_CFG2) {
1481 1.9.4.2 martin for (i = 0; i < nitems(rtl8125_mac_cfg2_ephy); i++) {
1482 1.9.4.2 martin rge_write_ephy(sc, rtl8125_mac_cfg2_ephy[i].reg,
1483 1.9.4.2 martin rtl8125_mac_cfg2_ephy[i].val);
1484 1.9.4.2 martin }
1485 1.9.4.2 martin
1486 1.9.4.2 martin if (mcode_ver != RGE_MAC_CFG2_MCODE_VER) {
1487 1.9.4.2 martin /* Disable PHY config. */
1488 1.9.4.2 martin RGE_CLRBIT_1(sc, 0xf2, 0x20);
1489 1.9.4.2 martin DELAY(1000);
1490 1.9.4.2 martin
1491 1.9.4.2 martin rge_patch_phy_mcu(sc, 1);
1492 1.9.4.2 martin
1493 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x8024);
1494 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0x8600);
1495 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0xb82e);
1496 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0x0001);
1497 1.9.4.2 martin
1498 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xb820, 0x0080);
1499 1.9.4.2 martin for (i = 0; i < nitems(rtl8125_mac_cfg2_mcu); i++) {
1500 1.9.4.2 martin rge_write_phy_ocp(sc,
1501 1.9.4.2 martin rtl8125_mac_cfg2_mcu[i].reg,
1502 1.9.4.2 martin rtl8125_mac_cfg2_mcu[i].val);
1503 1.9.4.2 martin }
1504 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xb820, 0x0080);
1505 1.9.4.2 martin
1506 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0);
1507 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0);
1508 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xb82e, 0x0001);
1509 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x8024);
1510 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0);
1511 1.9.4.2 martin
1512 1.9.4.2 martin rge_patch_phy_mcu(sc, 0);
1513 1.9.4.2 martin
1514 1.9.4.2 martin /* Enable PHY config. */
1515 1.9.4.2 martin RGE_SETBIT_1(sc, 0xf2, 0x20);
1516 1.9.4.2 martin
1517 1.9.4.2 martin /* Write microcode version. */
1518 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x801e);
1519 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, RGE_MAC_CFG2_MCODE_VER);
1520 1.9.4.2 martin }
1521 1.9.4.2 martin
1522 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xad40) & ~0x03ff;
1523 1.9.4.2 martin rge_write_phy_ocp(sc, 0xad40, val | 0x0084);
1524 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xad4e, 0x0010);
1525 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xad16) & ~0x03ff;
1526 1.9.4.2 martin rge_write_phy_ocp(sc, 0xad16, val | 0x0006);
1527 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xad32) & ~0x03ff;
1528 1.9.4.2 martin rge_write_phy_ocp(sc, 0xad32, val | 0x0006);
1529 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xac08, 0x1100);
1530 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xac8a) & ~0xf000;
1531 1.9.4.2 martin rge_write_phy_ocp(sc, 0xac8a, val | 0x7000);
1532 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xad18, 0x0400);
1533 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xad1a, 0x03ff);
1534 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xad1c, 0x03ff);
1535 1.9.4.2 martin
1536 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x80ea);
1537 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1538 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, val | 0xc400);
1539 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x80eb);
1540 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa438) & ~0x0700;
1541 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, val | 0x0300);
1542 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x80f8);
1543 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1544 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, val | 0x1c00);
1545 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x80f1);
1546 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1547 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, val | 0x3000);
1548 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x80fe);
1549 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1550 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, val | 0xa500);
1551 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x8102);
1552 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1553 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, val | 0x5000);
1554 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x8105);
1555 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1556 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, val | 0x3300);
1557 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x8100);
1558 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1559 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, val | 0x7000);
1560 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x8104);
1561 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1562 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, val | 0xf000);
1563 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x8106);
1564 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1565 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, val | 0x6500);
1566 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x80dc);
1567 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1568 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, val | 0xed00);
1569 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x80df);
1570 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xa438, 0x0100);
1571 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x80e1);
1572 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa438, 0x0100);
1573 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xbf06) & ~0x003f;
1574 1.9.4.2 martin rge_write_phy_ocp(sc, 0xbf06, val | 0x0038);
1575 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x819f);
1576 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0xd0b6);
1577 1.9.4.2 martin rge_write_phy_ocp(sc, 0xbc34, 0x5555);
1578 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xbf0a) & ~0x0e00;
1579 1.9.4.2 martin rge_write_phy_ocp(sc, 0xbf0a, val | 0x0a00);
1580 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa5c0, 0x0400);
1581 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xa442, 0x0800);
1582 1.9.4.2 martin } else {
1583 1.9.4.2 martin for (i = 0; i < nitems(rtl8125_mac_cfg3_ephy); i++)
1584 1.9.4.2 martin rge_write_ephy(sc, rtl8125_mac_cfg3_ephy[i].reg,
1585 1.9.4.2 martin rtl8125_mac_cfg3_ephy[i].val);
1586 1.9.4.2 martin
1587 1.9.4.2 martin if (mcode_ver != RGE_MAC_CFG3_MCODE_VER) {
1588 1.9.4.2 martin /* Disable PHY config. */
1589 1.9.4.2 martin RGE_CLRBIT_1(sc, 0xf2, 0x20);
1590 1.9.4.2 martin DELAY(1000);
1591 1.9.4.2 martin
1592 1.9.4.2 martin rge_patch_phy_mcu(sc, 1);
1593 1.9.4.2 martin
1594 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x8024);
1595 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0x8601);
1596 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0xb82e);
1597 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0x0001);
1598 1.9.4.2 martin
1599 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xb820, 0x0080);
1600 1.9.4.2 martin for (i = 0; i < nitems(rtl8125_mac_cfg3_mcu); i++) {
1601 1.9.4.2 martin rge_write_phy_ocp(sc,
1602 1.9.4.2 martin rtl8125_mac_cfg3_mcu[i].reg,
1603 1.9.4.2 martin rtl8125_mac_cfg3_mcu[i].val);
1604 1.9.4.2 martin }
1605 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xb820, 0x0080);
1606 1.9.4.2 martin
1607 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0);
1608 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0);
1609 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xb82e, 0x0001);
1610 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x8024);
1611 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0);
1612 1.9.4.2 martin
1613 1.9.4.2 martin rge_patch_phy_mcu(sc, 0);
1614 1.9.4.2 martin
1615 1.9.4.2 martin /* Enable PHY config. */
1616 1.9.4.2 martin RGE_SETBIT_1(sc, 0xf2, 0x20);
1617 1.9.4.2 martin
1618 1.9.4.2 martin /* Write microcode version. */
1619 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x801e);
1620 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, RGE_MAC_CFG3_MCODE_VER);
1621 1.9.4.2 martin }
1622 1.9.4.2 martin
1623 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xad4e, 0x0010);
1624 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xad16) & ~0x03ff;
1625 1.9.4.2 martin rge_write_phy_ocp(sc, 0xad16, val | 0x03ff);
1626 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xad32) & ~0x003f;
1627 1.9.4.2 martin rge_write_phy_ocp(sc, 0xad32, val | 0x0006);
1628 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xac08, 0x1000);
1629 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xac08, 0x0100);
1630 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xacc0) & ~0x0003;
1631 1.9.4.2 martin rge_write_phy_ocp(sc, 0xacc0, val | 0x0002);
1632 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xad40) & ~0x00e0;
1633 1.9.4.2 martin rge_write_phy_ocp(sc, 0xad40, val | 0x0040);
1634 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xad40) & ~0x0007;
1635 1.9.4.2 martin rge_write_phy_ocp(sc, 0xad40, val | 0x0004);
1636 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xac14, 0x0080);
1637 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xac80, 0x0300);
1638 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xac5e) & ~0x0007;
1639 1.9.4.2 martin rge_write_phy_ocp(sc, 0xac5e, val | 0x0002);
1640 1.9.4.2 martin rge_write_phy_ocp(sc, 0xad4c, 0x00a8);
1641 1.9.4.2 martin rge_write_phy_ocp(sc, 0xac5c, 0x01ff);
1642 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xac8a) & ~0x00f0;
1643 1.9.4.2 martin rge_write_phy_ocp(sc, 0xac8a, val | 0x0030);
1644 1.9.4.2 martin rge_write_phy_ocp(sc, 0xb87c, 0x80a2);
1645 1.9.4.2 martin rge_write_phy_ocp(sc, 0xb87e, 0x0153);
1646 1.9.4.2 martin rge_write_phy_ocp(sc, 0xb87c, 0x809c);
1647 1.9.4.2 martin rge_write_phy_ocp(sc, 0xb87e, 0x0153);
1648 1.9.4.2 martin
1649 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x81b3);
1650 1.9.4.2 martin for (i = 0; i < nitems(mac_cfg3_a438_value); i++)
1651 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, mac_cfg3_a438_value[i]);
1652 1.9.4.2 martin for (i = 0; i < 26; i++)
1653 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0);
1654 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x8257);
1655 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0x020f);
1656 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x80ea);
1657 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa438, 0x7843);
1658 1.9.4.2 martin
1659 1.9.4.2 martin rge_patch_phy_mcu(sc, 1);
1660 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xb896, 0x0001);
1661 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xb892, 0xff00);
1662 1.9.4.2 martin for (i = 0; i < nitems(mac_cfg3_b88e_value); i += 2) {
1663 1.9.4.2 martin rge_write_phy_ocp(sc, 0xb88e, mac_cfg3_b88e_value[i]);
1664 1.9.4.2 martin rge_write_phy_ocp(sc, 0xb890,
1665 1.9.4.2 martin mac_cfg3_b88e_value[i + 1]);
1666 1.9.4.2 martin }
1667 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xb896, 0x0001);
1668 1.9.4.2 martin rge_patch_phy_mcu(sc, 0);
1669 1.9.4.2 martin
1670 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xd068, 0x2000);
1671 1.9.4.2 martin rge_write_phy_ocp(sc, 0xa436, 0x81a2);
1672 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xa438, 0x0100);
1673 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xb54c) & ~0xff00;
1674 1.9.4.2 martin rge_write_phy_ocp(sc, 0xb54c, val | 0xdb00);
1675 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa454, 0x0001);
1676 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xa5d4, 0x0020);
1677 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xad4e, 0x0010);
1678 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa86a, 0x0001);
1679 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xa442, 0x0800);
1680 1.9.4.2 martin }
1681 1.9.4.2 martin
1682 1.9.4.2 martin /* Disable EEE. */
1683 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xe040, 0x0003);
1684 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xeb62, 0x0006);
1685 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa432, 0x0010);
1686 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa5d0, 0x0006);
1687 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa6d4, 0x0001);
1688 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa6d8, 0x0010);
1689 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa428, 0x0080);
1690 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa4a2, 0x0200);
1691 1.9.4.2 martin
1692 1.9.4.2 martin rge_patch_phy_mcu(sc, 1);
1693 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xe052, 0x0001);
1694 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa442, 0x3000);
1695 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa430, 0x8000);
1696 1.9.4.2 martin rge_patch_phy_mcu(sc, 0);
1697 1.9.4.2 martin }
1698 1.9.4.2 martin
1699 1.9.4.2 martin void
1700 1.9.4.2 martin rge_set_macaddr(struct rge_softc *sc, const uint8_t *addr)
1701 1.9.4.2 martin {
1702 1.9.4.2 martin RGE_SETBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
1703 1.9.4.2 martin RGE_WRITE_4(sc, RGE_MAC0,
1704 1.9.4.2 martin addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]);
1705 1.9.4.2 martin RGE_WRITE_4(sc, RGE_MAC4,
1706 1.9.4.2 martin addr[5] << 8 | addr[4]);
1707 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
1708 1.9.4.2 martin }
1709 1.9.4.2 martin
1710 1.9.4.2 martin void
1711 1.9.4.2 martin rge_get_macaddr(struct rge_softc *sc, uint8_t *addr)
1712 1.9.4.2 martin {
1713 1.9.4.2 martin *(uint32_t *)&addr[0] = RGE_READ_4(sc, RGE_ADDR0);
1714 1.9.4.2 martin *(uint16_t *)&addr[4] = RGE_READ_2(sc, RGE_ADDR1);
1715 1.9.4.2 martin }
1716 1.9.4.2 martin
1717 1.9.4.2 martin void
1718 1.9.4.2 martin rge_hw_init(struct rge_softc *sc)
1719 1.9.4.2 martin {
1720 1.9.4.2 martin int i;
1721 1.9.4.2 martin
1722 1.9.4.2 martin RGE_SETBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
1723 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_CFG5, RGE_CFG5_PME_STS);
1724 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_CFG2, RGE_CFG2_CLKREQ_EN);
1725 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
1726 1.9.4.2 martin RGE_CLRBIT_1(sc, 0xf1, 0x80);
1727 1.9.4.2 martin
1728 1.9.4.2 martin /* Disable UPS. */
1729 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xd40a, 0x0010);
1730 1.9.4.2 martin
1731 1.9.4.2 martin /* Configure MAC MCU. */
1732 1.9.4.2 martin rge_write_mac_ocp(sc, 0xfc38, 0);
1733 1.9.4.2 martin
1734 1.9.4.2 martin for (i = 0xfc28; i < 0xfc38; i += 2)
1735 1.9.4.2 martin rge_write_mac_ocp(sc, i, 0);
1736 1.9.4.2 martin
1737 1.9.4.2 martin DELAY(3000);
1738 1.9.4.2 martin rge_write_mac_ocp(sc, 0xfc26, 0);
1739 1.9.4.2 martin
1740 1.9.4.2 martin if (sc->rge_type == MAC_CFG3) {
1741 1.9.4.2 martin for (i = 0; i < nitems(rtl8125_def_bps); i++)
1742 1.9.4.2 martin rge_write_mac_ocp(sc, rtl8125_def_bps[i].reg,
1743 1.9.4.2 martin rtl8125_def_bps[i].val);
1744 1.9.4.2 martin }
1745 1.9.4.2 martin
1746 1.9.4.2 martin /* Disable PHY power saving. */
1747 1.9.4.2 martin rge_disable_phy_ocp_pwrsave(sc);
1748 1.9.4.2 martin
1749 1.9.4.2 martin /* Set PCIe uncorrectable error status. */
1750 1.9.4.2 martin rge_write_csi(sc, 0x108,
1751 1.9.4.2 martin rge_read_csi(sc, 0x108) | 0x00100000);
1752 1.9.4.2 martin }
1753 1.9.4.2 martin
1754 1.9.4.2 martin void
1755 1.9.4.2 martin rge_disable_phy_ocp_pwrsave(struct rge_softc *sc)
1756 1.9.4.2 martin {
1757 1.9.4.2 martin if (rge_read_phy_ocp(sc, 0xc416) != 0x0500) {
1758 1.9.4.2 martin rge_patch_phy_mcu(sc, 1);
1759 1.9.4.2 martin rge_write_phy_ocp(sc, 0xc416, 0);
1760 1.9.4.2 martin rge_write_phy_ocp(sc, 0xc416, 0x0500);
1761 1.9.4.2 martin rge_patch_phy_mcu(sc, 0);
1762 1.9.4.2 martin }
1763 1.9.4.2 martin }
1764 1.9.4.2 martin
1765 1.9.4.2 martin void
1766 1.9.4.2 martin rge_patch_phy_mcu(struct rge_softc *sc, int set)
1767 1.9.4.2 martin {
1768 1.9.4.2 martin uint16_t val;
1769 1.9.4.2 martin int i;
1770 1.9.4.2 martin
1771 1.9.4.2 martin if (set)
1772 1.9.4.2 martin RGE_PHY_SETBIT(sc, 0xb820, 0x0010);
1773 1.9.4.2 martin else
1774 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xb820, 0x0010);
1775 1.9.4.2 martin
1776 1.9.4.2 martin for (i = 0; i < 1000; i++) {
1777 1.9.4.2 martin val = rge_read_phy_ocp(sc, 0xb800) & 0x0040;
1778 1.9.4.2 martin DELAY(100);
1779 1.9.4.2 martin if (val == 0x0040)
1780 1.9.4.2 martin break;
1781 1.9.4.2 martin }
1782 1.9.4.2 martin if (i == 1000)
1783 1.9.4.2 martin printf("%s: timeout waiting to patch phy mcu\n",
1784 1.9.4.2 martin sc->sc_dev.dv_xname);
1785 1.9.4.2 martin }
1786 1.9.4.2 martin
1787 1.9.4.2 martin void
1788 1.9.4.2 martin rge_add_media_types(struct rge_softc *sc)
1789 1.9.4.2 martin {
1790 1.9.4.2 martin ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T, 0, NULL);
1791 1.9.4.2 martin ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
1792 1.9.4.2 martin ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX, 0, NULL);
1793 1.9.4.2 martin ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
1794 1.9.4.2 martin ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_T, 0, NULL);
1795 1.9.4.2 martin ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
1796 1.9.4.2 martin ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_2500_T, 0, NULL);
1797 1.9.4.2 martin ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_2500_T | IFM_FDX, 0, NULL);
1798 1.9.4.2 martin }
1799 1.9.4.2 martin
1800 1.9.4.2 martin void
1801 1.9.4.2 martin rge_config_imtype(struct rge_softc *sc, int imtype)
1802 1.9.4.2 martin {
1803 1.9.4.2 martin switch (imtype) {
1804 1.9.4.2 martin case RGE_IMTYPE_NONE:
1805 1.9.4.2 martin sc->rge_intrs = RGE_INTRS;
1806 1.9.4.2 martin sc->rge_rx_ack = RGE_ISR_RX_OK | RGE_ISR_RX_DESC_UNAVAIL |
1807 1.9.4.2 martin RGE_ISR_RX_FIFO_OFLOW;
1808 1.9.4.2 martin sc->rge_tx_ack = RGE_ISR_TX_OK;
1809 1.9.4.2 martin break;
1810 1.9.4.2 martin case RGE_IMTYPE_SIM:
1811 1.9.4.2 martin sc->rge_intrs = RGE_INTRS_TIMER;
1812 1.9.4.2 martin sc->rge_rx_ack = RGE_ISR_PCS_TIMEOUT;
1813 1.9.4.2 martin sc->rge_tx_ack = RGE_ISR_PCS_TIMEOUT;
1814 1.9.4.2 martin break;
1815 1.9.4.2 martin default:
1816 1.9.4.2 martin panic("%s: unknown imtype %d", sc->sc_dev.dv_xname, imtype);
1817 1.9.4.2 martin }
1818 1.9.4.2 martin }
1819 1.9.4.2 martin
1820 1.9.4.2 martin void
1821 1.9.4.2 martin rge_disable_sim_im(struct rge_softc *sc)
1822 1.9.4.2 martin {
1823 1.9.4.2 martin RGE_WRITE_4(sc, RGE_TIMERINT, 0);
1824 1.9.4.2 martin sc->rge_timerintr = 0;
1825 1.9.4.2 martin }
1826 1.9.4.2 martin
1827 1.9.4.2 martin void
1828 1.9.4.2 martin rge_setup_sim_im(struct rge_softc *sc)
1829 1.9.4.2 martin {
1830 1.9.4.2 martin RGE_WRITE_4(sc, RGE_TIMERINT, 0x2600);
1831 1.9.4.2 martin RGE_WRITE_4(sc, RGE_TIMERCNT, 1);
1832 1.9.4.2 martin sc->rge_timerintr = 1;
1833 1.9.4.2 martin }
1834 1.9.4.2 martin
1835 1.9.4.2 martin void
1836 1.9.4.2 martin rge_setup_intr(struct rge_softc *sc, int imtype)
1837 1.9.4.2 martin {
1838 1.9.4.2 martin rge_config_imtype(sc, imtype);
1839 1.9.4.2 martin
1840 1.9.4.2 martin /* Enable interrupts. */
1841 1.9.4.2 martin RGE_WRITE_4(sc, RGE_IMR, sc->rge_intrs);
1842 1.9.4.2 martin
1843 1.9.4.2 martin switch (imtype) {
1844 1.9.4.2 martin case RGE_IMTYPE_NONE:
1845 1.9.4.2 martin rge_disable_sim_im(sc);
1846 1.9.4.2 martin break;
1847 1.9.4.2 martin case RGE_IMTYPE_SIM:
1848 1.9.4.2 martin rge_setup_sim_im(sc);
1849 1.9.4.2 martin break;
1850 1.9.4.2 martin default:
1851 1.9.4.2 martin panic("%s: unknown imtype %d", sc->sc_dev.dv_xname, imtype);
1852 1.9.4.2 martin }
1853 1.9.4.2 martin }
1854 1.9.4.2 martin
1855 1.9.4.2 martin void
1856 1.9.4.2 martin rge_exit_oob(struct rge_softc *sc)
1857 1.9.4.2 martin {
1858 1.9.4.2 martin int i;
1859 1.9.4.2 martin
1860 1.9.4.2 martin RGE_CLRBIT_4(sc, RGE_RXCFG, RGE_RXCFG_ALLPHYS | RGE_RXCFG_INDIV |
1861 1.9.4.2 martin RGE_RXCFG_MULTI | RGE_RXCFG_BROAD | RGE_RXCFG_RUNT |
1862 1.9.4.2 martin RGE_RXCFG_ERRPKT);
1863 1.9.4.2 martin
1864 1.9.4.2 martin /* Disable RealWoW. */
1865 1.9.4.2 martin rge_write_mac_ocp(sc, 0xc0bc, 0x00ff);
1866 1.9.4.2 martin
1867 1.9.4.2 martin rge_reset(sc);
1868 1.9.4.2 martin
1869 1.9.4.2 martin /* Disable OOB. */
1870 1.9.4.2 martin RGE_CLRBIT_1(sc, RGE_MCUCMD, RGE_MCUCMD_IS_OOB);
1871 1.9.4.2 martin
1872 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xe8de, 0x4000);
1873 1.9.4.2 martin
1874 1.9.4.2 martin for (i = 0; i < 10; i++) {
1875 1.9.4.2 martin DELAY(100);
1876 1.9.4.2 martin if (RGE_READ_2(sc, RGE_TWICMD) & 0x0200)
1877 1.9.4.2 martin break;
1878 1.9.4.2 martin }
1879 1.9.4.2 martin
1880 1.9.4.2 martin rge_write_mac_ocp(sc, 0xc0aa, 0x07d0);
1881 1.9.4.2 martin rge_write_mac_ocp(sc, 0xc0a6, 0x0150);
1882 1.9.4.2 martin rge_write_mac_ocp(sc, 0xc01e, 0x5555);
1883 1.9.4.2 martin
1884 1.9.4.2 martin for (i = 0; i < 10; i++) {
1885 1.9.4.2 martin DELAY(100);
1886 1.9.4.2 martin if (RGE_READ_2(sc, RGE_TWICMD) & 0x0200)
1887 1.9.4.2 martin break;
1888 1.9.4.2 martin }
1889 1.9.4.2 martin
1890 1.9.4.2 martin if (rge_read_mac_ocp(sc, 0xd42c) & 0x0100) {
1891 1.9.4.2 martin for (i = 0; i < RGE_TIMEOUT; i++) {
1892 1.9.4.2 martin if ((rge_read_phy_ocp(sc, 0xa420) & 0x0080) == 2)
1893 1.9.4.2 martin break;
1894 1.9.4.2 martin DELAY(1000);
1895 1.9.4.2 martin }
1896 1.9.4.2 martin RGE_MAC_CLRBIT(sc, 0xd408, 0x0100);
1897 1.9.4.2 martin RGE_PHY_CLRBIT(sc, 0xa468, 0x000a);
1898 1.9.4.2 martin }
1899 1.9.4.2 martin }
1900 1.9.4.2 martin
1901 1.9.4.2 martin void
1902 1.9.4.2 martin rge_write_csi(struct rge_softc *sc, uint32_t reg, uint32_t val)
1903 1.9.4.2 martin {
1904 1.9.4.2 martin int i;
1905 1.9.4.2 martin
1906 1.9.4.2 martin RGE_WRITE_4(sc, RGE_CSIDR, val);
1907 1.9.4.2 martin RGE_WRITE_4(sc, RGE_CSIAR, (1 << 16) | (reg & RGE_CSIAR_ADDR_MASK) |
1908 1.9.4.2 martin (RGE_CSIAR_BYTE_EN << RGE_CSIAR_BYTE_EN_SHIFT) | RGE_CSIAR_BUSY);
1909 1.9.4.2 martin
1910 1.9.4.2 martin for (i = 0; i < 10; i++) {
1911 1.9.4.2 martin DELAY(100);
1912 1.9.4.2 martin if (!(RGE_READ_4(sc, RGE_CSIAR) & RGE_CSIAR_BUSY))
1913 1.9.4.2 martin break;
1914 1.9.4.2 martin }
1915 1.9.4.2 martin
1916 1.9.4.2 martin DELAY(20);
1917 1.9.4.2 martin }
1918 1.9.4.2 martin
1919 1.9.4.2 martin uint32_t
1920 1.9.4.2 martin rge_read_csi(struct rge_softc *sc, uint32_t reg)
1921 1.9.4.2 martin {
1922 1.9.4.2 martin int i;
1923 1.9.4.2 martin
1924 1.9.4.2 martin RGE_WRITE_4(sc, RGE_CSIAR, (1 << 16) | (reg & RGE_CSIAR_ADDR_MASK) |
1925 1.9.4.2 martin (RGE_CSIAR_BYTE_EN << RGE_CSIAR_BYTE_EN_SHIFT));
1926 1.9.4.2 martin
1927 1.9.4.2 martin for (i = 0; i < 10; i++) {
1928 1.9.4.2 martin DELAY(100);
1929 1.9.4.2 martin if (RGE_READ_4(sc, RGE_CSIAR) & RGE_CSIAR_BUSY)
1930 1.9.4.2 martin break;
1931 1.9.4.2 martin }
1932 1.9.4.2 martin
1933 1.9.4.2 martin DELAY(20);
1934 1.9.4.2 martin
1935 1.9.4.2 martin return (RGE_READ_4(sc, RGE_CSIDR));
1936 1.9.4.2 martin }
1937 1.9.4.2 martin
1938 1.9.4.2 martin void
1939 1.9.4.2 martin rge_write_mac_ocp(struct rge_softc *sc, uint16_t reg, uint16_t val)
1940 1.9.4.2 martin {
1941 1.9.4.2 martin uint32_t tmp;
1942 1.9.4.2 martin
1943 1.9.4.2 martin tmp = (reg >> 1) << RGE_MACOCP_ADDR_SHIFT;
1944 1.9.4.2 martin tmp += val;
1945 1.9.4.2 martin tmp |= RGE_MACOCP_BUSY;
1946 1.9.4.2 martin RGE_WRITE_4(sc, RGE_MACOCP, tmp);
1947 1.9.4.2 martin }
1948 1.9.4.2 martin
1949 1.9.4.2 martin uint16_t
1950 1.9.4.2 martin rge_read_mac_ocp(struct rge_softc *sc, uint16_t reg)
1951 1.9.4.2 martin {
1952 1.9.4.2 martin uint32_t val;
1953 1.9.4.2 martin
1954 1.9.4.2 martin val = (reg >> 1) << RGE_MACOCP_ADDR_SHIFT;
1955 1.9.4.2 martin RGE_WRITE_4(sc, RGE_MACOCP, val);
1956 1.9.4.2 martin
1957 1.9.4.2 martin return (RGE_READ_4(sc, RGE_MACOCP) & RGE_MACOCP_DATA_MASK);
1958 1.9.4.2 martin }
1959 1.9.4.2 martin
1960 1.9.4.2 martin void
1961 1.9.4.2 martin rge_write_ephy(struct rge_softc *sc, uint16_t reg, uint16_t val)
1962 1.9.4.2 martin {
1963 1.9.4.2 martin uint32_t tmp;
1964 1.9.4.2 martin int i;
1965 1.9.4.2 martin
1966 1.9.4.2 martin tmp = (reg & RGE_EPHYAR_ADDR_MASK) << RGE_EPHYAR_ADDR_SHIFT;
1967 1.9.4.2 martin tmp |= RGE_EPHYAR_BUSY | (val & RGE_EPHYAR_DATA_MASK);
1968 1.9.4.2 martin RGE_WRITE_4(sc, RGE_EPHYAR, tmp);
1969 1.9.4.2 martin
1970 1.9.4.2 martin for (i = 0; i < 10; i++) {
1971 1.9.4.2 martin DELAY(100);
1972 1.9.4.2 martin if (!(RGE_READ_4(sc, RGE_EPHYAR) & RGE_EPHYAR_BUSY))
1973 1.9.4.2 martin break;
1974 1.9.4.2 martin }
1975 1.9.4.2 martin
1976 1.9.4.2 martin DELAY(20);
1977 1.9.4.2 martin }
1978 1.9.4.2 martin
1979 1.9.4.2 martin void
1980 1.9.4.2 martin rge_write_phy(struct rge_softc *sc, uint16_t addr, uint16_t reg, uint16_t val)
1981 1.9.4.2 martin {
1982 1.9.4.2 martin uint16_t off, phyaddr;
1983 1.9.4.2 martin
1984 1.9.4.2 martin phyaddr = addr ? addr : RGE_PHYBASE + (reg / 8);
1985 1.9.4.2 martin phyaddr <<= 4;
1986 1.9.4.2 martin
1987 1.9.4.2 martin off = addr ? reg : 0x10 + (reg % 8);
1988 1.9.4.2 martin
1989 1.9.4.2 martin phyaddr += (off - 16) << 1;
1990 1.9.4.2 martin
1991 1.9.4.2 martin rge_write_phy_ocp(sc, phyaddr, val);
1992 1.9.4.2 martin }
1993 1.9.4.2 martin
1994 1.9.4.2 martin void
1995 1.9.4.2 martin rge_write_phy_ocp(struct rge_softc *sc, uint16_t reg, uint16_t val)
1996 1.9.4.2 martin {
1997 1.9.4.2 martin uint32_t tmp;
1998 1.9.4.2 martin int i;
1999 1.9.4.2 martin
2000 1.9.4.2 martin tmp = (reg >> 1) << RGE_PHYOCP_ADDR_SHIFT;
2001 1.9.4.2 martin tmp |= RGE_PHYOCP_BUSY | val;
2002 1.9.4.2 martin RGE_WRITE_4(sc, RGE_PHYOCP, tmp);
2003 1.9.4.2 martin
2004 1.9.4.2 martin for (i = 0; i < RGE_TIMEOUT; i++) {
2005 1.9.4.2 martin DELAY(1);
2006 1.9.4.2 martin if (!(RGE_READ_4(sc, RGE_PHYOCP) & RGE_PHYOCP_BUSY))
2007 1.9.4.2 martin break;
2008 1.9.4.2 martin }
2009 1.9.4.2 martin }
2010 1.9.4.2 martin
2011 1.9.4.2 martin uint16_t
2012 1.9.4.2 martin rge_read_phy_ocp(struct rge_softc *sc, uint16_t reg)
2013 1.9.4.2 martin {
2014 1.9.4.2 martin uint32_t val;
2015 1.9.4.2 martin int i;
2016 1.9.4.2 martin
2017 1.9.4.2 martin val = (reg >> 1) << RGE_PHYOCP_ADDR_SHIFT;
2018 1.9.4.2 martin RGE_WRITE_4(sc, RGE_PHYOCP, val);
2019 1.9.4.2 martin
2020 1.9.4.2 martin for (i = 0; i < RGE_TIMEOUT; i++) {
2021 1.9.4.2 martin DELAY(1);
2022 1.9.4.2 martin val = RGE_READ_4(sc, RGE_PHYOCP);
2023 1.9.4.2 martin if (val & RGE_PHYOCP_BUSY)
2024 1.9.4.2 martin break;
2025 1.9.4.2 martin }
2026 1.9.4.2 martin
2027 1.9.4.2 martin return (val & RGE_PHYOCP_DATA_MASK);
2028 1.9.4.2 martin }
2029 1.9.4.2 martin
2030 1.9.4.2 martin int
2031 1.9.4.2 martin rge_get_link_status(struct rge_softc *sc)
2032 1.9.4.2 martin {
2033 1.9.4.2 martin return ((RGE_READ_2(sc, RGE_PHYSTAT) & RGE_PHYSTAT_LINK) ? 1 : 0);
2034 1.9.4.2 martin }
2035 1.9.4.2 martin
2036 1.9.4.2 martin void
2037 1.9.4.2 martin rge_txstart(struct work *wk, void *arg)
2038 1.9.4.2 martin {
2039 1.9.4.2 martin struct rge_softc *sc = arg;
2040 1.9.4.2 martin
2041 1.9.4.2 martin RGE_WRITE_2(sc, RGE_TXSTART, RGE_TXSTART_START);
2042 1.9.4.2 martin }
2043 1.9.4.2 martin
2044 1.9.4.2 martin void
2045 1.9.4.2 martin rge_tick(void *arg)
2046 1.9.4.2 martin {
2047 1.9.4.2 martin struct rge_softc *sc = arg;
2048 1.9.4.2 martin int s;
2049 1.9.4.2 martin
2050 1.9.4.2 martin s = splnet();
2051 1.9.4.2 martin rge_link_state(sc);
2052 1.9.4.2 martin splx(s);
2053 1.9.4.2 martin
2054 1.9.4.2 martin timeout_add_sec(&sc->sc_timeout, 1);
2055 1.9.4.2 martin }
2056 1.9.4.2 martin
2057 1.9.4.2 martin void
2058 1.9.4.2 martin rge_link_state(struct rge_softc *sc)
2059 1.9.4.2 martin {
2060 1.9.4.2 martin struct ifnet *ifp = &sc->sc_ec.ec_if;
2061 1.9.4.2 martin int link = LINK_STATE_DOWN;
2062 1.9.4.2 martin
2063 1.9.4.2 martin if (rge_get_link_status(sc))
2064 1.9.4.2 martin link = LINK_STATE_UP;
2065 1.9.4.2 martin
2066 1.9.4.2 martin if (ifp->if_link_state != link) {
2067 1.9.4.2 martin ifp->if_link_state = link;
2068 1.9.4.2 martin if_link_state_change(ifp, LINK_STATE_DOWN);
2069 1.9.4.2 martin }
2070 1.9.4.2 martin }
2071