xref: /netbsd-src/sys/dev/pci/if_rge.c (revision 965ff70d6cc168e208e3ec6b725c8ce156e95fd0)
1*965ff70dSmlelstv /*	$NetBSD: if_rge.c,v 1.33 2024/11/10 11:45:48 mlelstv Exp $	*/
2e13c9dceSjakllsch /*	$OpenBSD: if_rge.c,v 1.9 2020/12/12 11:48:53 jan Exp $	*/
3156bc3dcSsevan 
4156bc3dcSsevan /*
5e13c9dceSjakllsch  * Copyright (c) 2019, 2020 Kevin Lo <kevlo@openbsd.org>
6156bc3dcSsevan  *
7156bc3dcSsevan  * Permission to use, copy, modify, and distribute this software for any
8156bc3dcSsevan  * purpose with or without fee is hereby granted, provided that the above
9156bc3dcSsevan  * copyright notice and this permission notice appear in all copies.
10156bc3dcSsevan  *
11156bc3dcSsevan  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12156bc3dcSsevan  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13156bc3dcSsevan  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14156bc3dcSsevan  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15156bc3dcSsevan  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16156bc3dcSsevan  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17156bc3dcSsevan  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18156bc3dcSsevan  */
19156bc3dcSsevan 
207ff7ee85Ssevan #include <sys/cdefs.h>
21*965ff70dSmlelstv __KERNEL_RCSID(0, "$NetBSD: if_rge.c,v 1.33 2024/11/10 11:45:48 mlelstv Exp $");
22ccc8e576Sskrll 
23ccc8e576Sskrll #if defined(_KERNEL_OPT)
24ccc8e576Sskrll #include "opt_net_mpsafe.h"
25ccc8e576Sskrll #endif
267ff7ee85Ssevan 
277ff7ee85Ssevan #include <sys/types.h>
28156bc3dcSsevan 
29156bc3dcSsevan #include <sys/param.h>
30156bc3dcSsevan #include <sys/systm.h>
31156bc3dcSsevan #include <sys/sockio.h>
32156bc3dcSsevan #include <sys/mbuf.h>
33156bc3dcSsevan #include <sys/kernel.h>
34156bc3dcSsevan #include <sys/socket.h>
35156bc3dcSsevan #include <sys/device.h>
36156bc3dcSsevan #include <sys/endian.h>
37d57dd85eSsevan #include <sys/callout.h>
38d57dd85eSsevan #include <sys/workqueue.h>
39156bc3dcSsevan 
40156bc3dcSsevan #include <net/if.h>
417ff7ee85Ssevan 
427ff7ee85Ssevan #include <net/if_dl.h>
437ff7ee85Ssevan #include <net/if_ether.h>
447ff7ee85Ssevan 
45156bc3dcSsevan #include <net/if_media.h>
46156bc3dcSsevan 
47156bc3dcSsevan #include <netinet/in.h>
487ff7ee85Ssevan #include <net/if_ether.h>
49156bc3dcSsevan 
50156bc3dcSsevan #include <net/bpf.h>
51156bc3dcSsevan 
527ff7ee85Ssevan #include <sys/bus.h>
53156bc3dcSsevan #include <machine/intr.h>
54156bc3dcSsevan 
55156bc3dcSsevan #include <dev/mii/mii.h>
56156bc3dcSsevan 
57156bc3dcSsevan #include <dev/pci/pcivar.h>
58156bc3dcSsevan #include <dev/pci/pcireg.h>
59156bc3dcSsevan #include <dev/pci/pcidevs.h>
60156bc3dcSsevan 
61156bc3dcSsevan #include <dev/pci/if_rgereg.h>
62156bc3dcSsevan 
637ff7ee85Ssevan #ifdef __NetBSD__
647ff7ee85Ssevan #define letoh32 	htole32
657ff7ee85Ssevan #define nitems(x) 	__arraycount(x)
66657257e0Ssevan 
67657257e0Ssevan static struct mbuf *
68e13c9dceSjakllsch MCLGETL(struct rge_softc *sc __unused, int how,
69e13c9dceSjakllsch     u_int size)
70657257e0Ssevan {
71657257e0Ssevan 	struct mbuf *m;
72657257e0Ssevan 
73657257e0Ssevan 	MGETHDR(m, how, MT_DATA);
74657257e0Ssevan 	if (m == NULL)
75657257e0Ssevan 		return NULL;
76657257e0Ssevan 
77657257e0Ssevan 	MEXTMALLOC(m, size, how);
78657257e0Ssevan 	if ((m->m_flags & M_EXT) == 0) {
79657257e0Ssevan 		m_freem(m);
80657257e0Ssevan 		return NULL;
81657257e0Ssevan 	}
82657257e0Ssevan 	return m;
83657257e0Ssevan }
84657257e0Ssevan 
85d57dd85eSsevan #ifdef NET_MPSAFE
86d57dd85eSsevan #define 	RGE_MPSAFE	1
87d57dd85eSsevan #define 	CALLOUT_FLAGS	CALLOUT_MPSAFE
88d57dd85eSsevan #else
89d57dd85eSsevan #define 	CALLOUT_FLAGS	0
90d57dd85eSsevan #endif
917ff7ee85Ssevan #endif
927ff7ee85Ssevan 
93e13c9dceSjakllsch #ifdef RGE_DEBUG
94e13c9dceSjakllsch #define DPRINTF(x)	do { if (rge_debug > 0) printf x; } while (0)
95e13c9dceSjakllsch int rge_debug = 0;
96e13c9dceSjakllsch #else
97e13c9dceSjakllsch #define DPRINTF(x)
98e13c9dceSjakllsch #endif
99e13c9dceSjakllsch 
1007ff7ee85Ssevan static int		rge_match(device_t, cfdata_t, void *);
1017ff7ee85Ssevan static void		rge_attach(device_t, device_t, void *);
102156bc3dcSsevan int		rge_intr(void *);
103156bc3dcSsevan int		rge_encap(struct rge_softc *, struct mbuf *, int);
1047ff7ee85Ssevan int		rge_ioctl(struct ifnet *, u_long, void *);
1057ff7ee85Ssevan void		rge_start(struct ifnet *);
106156bc3dcSsevan void		rge_watchdog(struct ifnet *);
107156bc3dcSsevan int		rge_init(struct ifnet *);
108e13c9dceSjakllsch void		rge_stop(struct ifnet *, int);
109156bc3dcSsevan int		rge_ifmedia_upd(struct ifnet *);
110156bc3dcSsevan void		rge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
111156bc3dcSsevan int		rge_allocmem(struct rge_softc *);
112156bc3dcSsevan int		rge_newbuf(struct rge_softc *, int);
11321a1f964Smrg static int	rge_rx_list_init(struct rge_softc *);
11421a1f964Smrg static void	rge_rx_list_fini(struct rge_softc *);
11521a1f964Smrg static void	rge_tx_list_init(struct rge_softc *);
11621a1f964Smrg static void	rge_tx_list_fini(struct rge_softc *);
117156bc3dcSsevan int		rge_rxeof(struct rge_softc *);
118156bc3dcSsevan int		rge_txeof(struct rge_softc *);
119156bc3dcSsevan void		rge_reset(struct rge_softc *);
120156bc3dcSsevan void		rge_iff(struct rge_softc *);
121156bc3dcSsevan void		rge_set_phy_power(struct rge_softc *, int);
122156bc3dcSsevan void		rge_phy_config(struct rge_softc *);
123e13c9dceSjakllsch void		rge_phy_config_mac_cfg2(struct rge_softc *);
124e13c9dceSjakllsch void		rge_phy_config_mac_cfg3(struct rge_softc *);
125e13c9dceSjakllsch void		rge_phy_config_mac_cfg4(struct rge_softc *);
126e13c9dceSjakllsch void		rge_phy_config_mac_cfg5(struct rge_softc *);
127e13c9dceSjakllsch void		rge_phy_config_mcu(struct rge_softc *, uint16_t);
128156bc3dcSsevan void		rge_set_macaddr(struct rge_softc *, const uint8_t *);
129156bc3dcSsevan void		rge_get_macaddr(struct rge_softc *, uint8_t *);
130156bc3dcSsevan void		rge_hw_init(struct rge_softc *);
131156bc3dcSsevan void		rge_disable_phy_ocp_pwrsave(struct rge_softc *);
132156bc3dcSsevan void		rge_patch_phy_mcu(struct rge_softc *, int);
133156bc3dcSsevan void		rge_add_media_types(struct rge_softc *);
134156bc3dcSsevan void		rge_config_imtype(struct rge_softc *, int);
135e13c9dceSjakllsch void		rge_disable_hw_im(struct rge_softc *);
136156bc3dcSsevan void		rge_disable_sim_im(struct rge_softc *);
137156bc3dcSsevan void		rge_setup_sim_im(struct rge_softc *);
138156bc3dcSsevan void		rge_setup_intr(struct rge_softc *, int);
139156bc3dcSsevan void		rge_exit_oob(struct rge_softc *);
140156bc3dcSsevan void		rge_write_csi(struct rge_softc *, uint32_t, uint32_t);
141156bc3dcSsevan uint32_t	rge_read_csi(struct rge_softc *, uint32_t);
142156bc3dcSsevan void		rge_write_mac_ocp(struct rge_softc *, uint16_t, uint16_t);
143156bc3dcSsevan uint16_t	rge_read_mac_ocp(struct rge_softc *, uint16_t);
144156bc3dcSsevan void		rge_write_ephy(struct rge_softc *, uint16_t, uint16_t);
145e13c9dceSjakllsch uint16_t	rge_read_ephy(struct rge_softc *, uint16_t);
146156bc3dcSsevan void		rge_write_phy(struct rge_softc *, uint16_t, uint16_t, uint16_t);
147e13c9dceSjakllsch uint16_t	rge_read_phy(struct rge_softc *, uint16_t, uint16_t);
148156bc3dcSsevan void		rge_write_phy_ocp(struct rge_softc *, uint16_t, uint16_t);
149156bc3dcSsevan uint16_t	rge_read_phy_ocp(struct rge_softc *, uint16_t);
150156bc3dcSsevan int		rge_get_link_status(struct rge_softc *);
151ccc8e576Sskrll void		rge_txstart(void *);
152156bc3dcSsevan void		rge_tick(void *);
153156bc3dcSsevan void		rge_link_state(struct rge_softc *);
154156bc3dcSsevan 
155156bc3dcSsevan static const struct {
156156bc3dcSsevan 	uint16_t reg;
157156bc3dcSsevan 	uint16_t val;
158e13c9dceSjakllsch }  rtl8125_mac_cfg2_mcu[] = {
159156bc3dcSsevan 	RTL8125_MAC_CFG2_MCU
160156bc3dcSsevan }, rtl8125_mac_cfg3_mcu[] = {
161156bc3dcSsevan 	RTL8125_MAC_CFG3_MCU
162e13c9dceSjakllsch }, rtl8125_mac_cfg4_mcu[] = {
163e13c9dceSjakllsch 	RTL8125_MAC_CFG4_MCU
164e13c9dceSjakllsch }, rtl8125_mac_cfg5_mcu[] = {
165e13c9dceSjakllsch 	RTL8125_MAC_CFG5_MCU
166156bc3dcSsevan };
167156bc3dcSsevan 
1687ff7ee85Ssevan CFATTACH_DECL_NEW(rge, sizeof(struct rge_softc), rge_match, rge_attach,
1697ff7ee85Ssevan 		NULL, NULL); /* Sevan - detach function? */
170156bc3dcSsevan 
171c06247ceSthorpej static const struct device_compatible_entry compat_data[] = {
172c06247ceSthorpej 	{ .id = PCI_ID_CODE(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_E3000) },
173c06247ceSthorpej 	{ .id = PCI_ID_CODE(PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8125) },
174c06247ceSthorpej 
175c06247ceSthorpej 	PCI_COMPAT_EOL
176156bc3dcSsevan };
177156bc3dcSsevan 
1787ff7ee85Ssevan static int
1797ff7ee85Ssevan rge_match(device_t parent, cfdata_t match, void *aux)
180156bc3dcSsevan {
1817ff7ee85Ssevan 	struct pci_attach_args *pa =aux;
1827ff7ee85Ssevan 
183c06247ceSthorpej 	return pci_compatible_match(pa, compat_data);
184156bc3dcSsevan }
185156bc3dcSsevan 
186156bc3dcSsevan void
1877ff7ee85Ssevan rge_attach(device_t parent, device_t self, void *aux)
188156bc3dcSsevan {
18926d841cbSsevan 	struct rge_softc *sc = device_private(self);
190156bc3dcSsevan 	struct pci_attach_args *pa = aux;
191156bc3dcSsevan 	pci_chipset_tag_t pc = pa->pa_pc;
192e13c9dceSjakllsch 	pci_intr_handle_t *ihp;
1937ff7ee85Ssevan 	char intrbuf[PCI_INTRSTR_LEN];
194156bc3dcSsevan 	const char *intrstr = NULL;
195156bc3dcSsevan 	struct ifnet *ifp;
196156bc3dcSsevan 	pcireg_t reg;
197156bc3dcSsevan 	uint32_t hwrev;
198156bc3dcSsevan 	uint8_t eaddr[ETHER_ADDR_LEN];
199156bc3dcSsevan 	int offset;
200e13c9dceSjakllsch 	pcireg_t command;
201164a08daSmsaitoh 	const char *revstr;
202156bc3dcSsevan 
203156bc3dcSsevan 	pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0);
204156bc3dcSsevan 
205112b980bSsevan 	sc->sc_dev = self;
206112b980bSsevan 
207e13c9dceSjakllsch 	pci_aprint_devinfo(pa, "Ethernet controller");
208e13c9dceSjakllsch 
209156bc3dcSsevan 	/*
210156bc3dcSsevan 	 * Map control/status registers.
211156bc3dcSsevan 	 */
212156bc3dcSsevan 	if (pci_mapreg_map(pa, RGE_PCI_BAR2, PCI_MAPREG_TYPE_MEM |
213156bc3dcSsevan 	    PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->rge_btag, &sc->rge_bhandle,
2147ff7ee85Ssevan 	    NULL, &sc->rge_bsize)) {
215156bc3dcSsevan 		if (pci_mapreg_map(pa, RGE_PCI_BAR1, PCI_MAPREG_TYPE_MEM |
216156bc3dcSsevan 		    PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->rge_btag,
2177ff7ee85Ssevan 		    &sc->rge_bhandle, NULL, &sc->rge_bsize)) {
218156bc3dcSsevan 			if (pci_mapreg_map(pa, RGE_PCI_BAR0, PCI_MAPREG_TYPE_IO,
219156bc3dcSsevan 			    0, &sc->rge_btag, &sc->rge_bhandle, NULL,
2207ff7ee85Ssevan 			    &sc->rge_bsize)) {
221a164c08fSsevan 				aprint_error(": can't map mem or i/o space\n");
222156bc3dcSsevan 				return;
223156bc3dcSsevan 			}
224156bc3dcSsevan 		}
225156bc3dcSsevan 	}
226156bc3dcSsevan 
227e13c9dceSjakllsch 	int counts[PCI_INTR_TYPE_SIZE] = {
228e13c9dceSjakllsch  		[PCI_INTR_TYPE_INTX] = 1,
229e13c9dceSjakllsch  		[PCI_INTR_TYPE_MSI] = 1,
230e13c9dceSjakllsch  		[PCI_INTR_TYPE_MSIX] = 1,
231e13c9dceSjakllsch  	};
232e13c9dceSjakllsch 	int max_type = PCI_INTR_TYPE_MSIX;
233156bc3dcSsevan 	/*
234156bc3dcSsevan 	 * Allocate interrupt.
235156bc3dcSsevan 	 */
236e13c9dceSjakllsch 	if (pci_intr_alloc(pa, &ihp, counts, max_type) != 0) {
237a164c08fSsevan 		aprint_error(": couldn't map interrupt\n");
238156bc3dcSsevan 		return;
239156bc3dcSsevan 	}
240e13c9dceSjakllsch 	switch (pci_intr_type(pc, ihp[0])) {
241e13c9dceSjakllsch 	case PCI_INTR_TYPE_MSIX:
242e13c9dceSjakllsch 	case PCI_INTR_TYPE_MSI:
243e13c9dceSjakllsch 		sc->rge_flags |= RGE_FLAG_MSI;
244e13c9dceSjakllsch 		break;
245e13c9dceSjakllsch 	default:
246e13c9dceSjakllsch 		break;
247e13c9dceSjakllsch 	}
248e13c9dceSjakllsch 	intrstr = pci_intr_string(pc, ihp[0], intrbuf, sizeof(intrbuf));
249e13c9dceSjakllsch 	sc->sc_ih = pci_intr_establish_xname(pc, ihp[0], IPL_NET, rge_intr,
250b7feb0b5Ssevan 	    sc, device_xname(sc->sc_dev));
251156bc3dcSsevan 	if (sc->sc_ih == NULL) {
252a164c08fSsevan 		aprint_error_dev(sc->sc_dev, ": couldn't establish interrupt");
253156bc3dcSsevan 		if (intrstr != NULL)
254a164c08fSsevan 			aprint_error(" at %s\n", intrstr);
255a164c08fSsevan 		aprint_error("\n");
256156bc3dcSsevan 		return;
257156bc3dcSsevan 	}
258a164c08fSsevan 	aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
259156bc3dcSsevan 
260ecffff35Sthorpej 	if (pci_dma64_available(pa))
261ecffff35Sthorpej 		sc->sc_dmat = pa->pa_dmat64;
262ecffff35Sthorpej 	else
263156bc3dcSsevan 		sc->sc_dmat = pa->pa_dmat;
264ecffff35Sthorpej 
265156bc3dcSsevan 	sc->sc_pc = pa->pa_pc;
266156bc3dcSsevan 	sc->sc_tag = pa->pa_tag;
267156bc3dcSsevan 
268156bc3dcSsevan 	/* Determine hardware revision */
269156bc3dcSsevan 	hwrev = RGE_READ_4(sc, RGE_TXCFG) & RGE_TXCFG_HWREV;
270156bc3dcSsevan 	switch (hwrev) {
271156bc3dcSsevan 	case 0x60800000:
272156bc3dcSsevan 		sc->rge_type = MAC_CFG2;
273164a08daSmsaitoh 		revstr = "Z1";
274156bc3dcSsevan 		break;
275156bc3dcSsevan 	case 0x60900000:
276156bc3dcSsevan 		sc->rge_type = MAC_CFG3;
277164a08daSmsaitoh 		revstr = "Z2";
278156bc3dcSsevan 		break;
279e13c9dceSjakllsch 	case 0x64000000:
280e13c9dceSjakllsch 		sc->rge_type = MAC_CFG4;
281164a08daSmsaitoh 		revstr = "A";
282e13c9dceSjakllsch 		break;
283e13c9dceSjakllsch 	case 0x64100000:
284e13c9dceSjakllsch 		sc->rge_type = MAC_CFG5;
285164a08daSmsaitoh 		revstr = "B";
286e13c9dceSjakllsch 		break;
287156bc3dcSsevan 	default:
288a164c08fSsevan 		aprint_error(": unknown version 0x%08x\n", hwrev);
289156bc3dcSsevan 		return;
290156bc3dcSsevan 	}
291156bc3dcSsevan 
292164a08daSmsaitoh 	aprint_normal_dev(sc->sc_dev, "HW rev. %s\n", revstr);
293156bc3dcSsevan 	rge_config_imtype(sc, RGE_IMTYPE_SIM);
294156bc3dcSsevan 
295156bc3dcSsevan 	/*
296156bc3dcSsevan 	 * PCI Express check.
297156bc3dcSsevan 	 */
298156bc3dcSsevan 	if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_PCIEXPRESS,
299156bc3dcSsevan 	    &offset, NULL)) {
300e13c9dceSjakllsch 		/* Disable PCIe ASPM and ECPM. */
301156bc3dcSsevan 		reg = pci_conf_read(pa->pa_pc, pa->pa_tag,
3027ff7ee85Ssevan 		    offset + PCIE_LCSR);
303e13c9dceSjakllsch 		reg &= ~(PCIE_LCSR_ASPM_L0S | PCIE_LCSR_ASPM_L1 |
304e13c9dceSjakllsch 		    PCIE_LCSR_ENCLKPM);
3057ff7ee85Ssevan 		pci_conf_write(pa->pa_pc, pa->pa_tag, offset + PCIE_LCSR,
306156bc3dcSsevan 		    reg);
307156bc3dcSsevan 	}
308156bc3dcSsevan 
309156bc3dcSsevan 	rge_exit_oob(sc);
310156bc3dcSsevan 	rge_hw_init(sc);
311156bc3dcSsevan 
312156bc3dcSsevan 	rge_get_macaddr(sc, eaddr);
313a164c08fSsevan 	aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n",
314a164c08fSsevan 	    ether_sprintf(eaddr));
315156bc3dcSsevan 
3167ff7ee85Ssevan 	memcpy(sc->sc_enaddr, eaddr, ETHER_ADDR_LEN);
317156bc3dcSsevan 
318156bc3dcSsevan 	rge_set_phy_power(sc, 1);
319156bc3dcSsevan 	rge_phy_config(sc);
320156bc3dcSsevan 
321156bc3dcSsevan 	if (rge_allocmem(sc))
322156bc3dcSsevan 		return;
323156bc3dcSsevan 
3247ff7ee85Ssevan 	ifp = &sc->sc_ec.ec_if;
325156bc3dcSsevan 	ifp->if_softc = sc;
326b7feb0b5Ssevan 	strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
327156bc3dcSsevan 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
3287ff7ee85Ssevan #ifdef RGE_MPSAFE
32945f95ba0Sknakahara 	ifp->if_extflags = IFEF_MPSAFE;
3307ff7ee85Ssevan #endif
331156bc3dcSsevan 	ifp->if_ioctl = rge_ioctl;
332e13c9dceSjakllsch 	ifp->if_stop = rge_stop;
3337ff7ee85Ssevan 	ifp->if_start = rge_start;
334e13c9dceSjakllsch 	ifp->if_init = rge_init;
335156bc3dcSsevan 	ifp->if_watchdog = rge_watchdog;
336e13c9dceSjakllsch 	IFQ_SET_MAXLEN(&ifp->if_snd, RGE_TX_LIST_CNT - 1);
337156bc3dcSsevan 
338e13c9dceSjakllsch #if notyet
339e13c9dceSjakllsch 	ifp->if_capabilities = IFCAP_CSUM_IPv4_Rx |
3407ff7ee85Ssevan 	    IFCAP_CSUM_IPv4_Tx |IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_TCPv4_Tx|
3417ff7ee85Ssevan 	    IFCAP_CSUM_UDPv4_Rx | IFCAP_CSUM_UDPv4_Tx;
342156bc3dcSsevan #endif
343156bc3dcSsevan 
344e13c9dceSjakllsch 	sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
345e13c9dceSjakllsch 	sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_HWTAGGING;
346e13c9dceSjakllsch 
347d57dd85eSsevan 	callout_init(&sc->sc_timeout, CALLOUT_FLAGS);
348d57dd85eSsevan 	callout_setfunc(&sc->sc_timeout, rge_tick, sc);
349e13c9dceSjakllsch 
350e13c9dceSjakllsch 	command = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
351e13c9dceSjakllsch 	command |= PCI_COMMAND_MASTER_ENABLE;
352e13c9dceSjakllsch 	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command);
353156bc3dcSsevan 
354156bc3dcSsevan 	/* Initialize ifmedia structures. */
355e13c9dceSjakllsch 	sc->sc_ec.ec_ifmedia = &sc->sc_media;
356156bc3dcSsevan 	ifmedia_init(&sc->sc_media, IFM_IMASK, rge_ifmedia_upd,
357156bc3dcSsevan 	    rge_ifmedia_sts);
358156bc3dcSsevan 	rge_add_media_types(sc);
359156bc3dcSsevan 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
360156bc3dcSsevan 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
361156bc3dcSsevan 	sc->sc_media.ifm_media = sc->sc_media.ifm_cur->ifm_media;
362156bc3dcSsevan 
363156bc3dcSsevan 	if_attach(ifp);
3649a4c4a4cSmlelstv 	if_deferred_start_init(ifp, NULL);
3657ff7ee85Ssevan 	ether_ifattach(ifp, eaddr);
366409fa0f6Smsaitoh 
367409fa0f6Smsaitoh 	if (pmf_device_register(self, NULL, NULL))
368409fa0f6Smsaitoh 		pmf_class_network_register(self, ifp);
369409fa0f6Smsaitoh 	else
370409fa0f6Smsaitoh 		aprint_error_dev(self, "couldn't establish power handler\n");
371156bc3dcSsevan }
372156bc3dcSsevan 
373156bc3dcSsevan int
374156bc3dcSsevan rge_intr(void *arg)
375156bc3dcSsevan {
376156bc3dcSsevan 	struct rge_softc *sc = arg;
3777ff7ee85Ssevan 	struct ifnet *ifp = &sc->sc_ec.ec_if;
378156bc3dcSsevan 	uint32_t status;
379156bc3dcSsevan 	int claimed = 0, rx, tx;
380156bc3dcSsevan 
381156bc3dcSsevan 	if (!(ifp->if_flags & IFF_RUNNING))
382156bc3dcSsevan 		return (0);
383156bc3dcSsevan 
384156bc3dcSsevan 	/* Disable interrupts. */
385156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_IMR, 0);
386156bc3dcSsevan 
387156bc3dcSsevan 	if (!(sc->rge_flags & RGE_FLAG_MSI)) {
388e13c9dceSjakllsch 		if ((RGE_READ_4(sc, RGE_ISR) & sc->rge_intrs) == 0)
389156bc3dcSsevan 			return (0);
390156bc3dcSsevan 	}
391e13c9dceSjakllsch 
392e13c9dceSjakllsch 	status = RGE_READ_4(sc, RGE_ISR);
393156bc3dcSsevan 	if (status)
394156bc3dcSsevan 		RGE_WRITE_4(sc, RGE_ISR, status);
395156bc3dcSsevan 
396156bc3dcSsevan 	if (status & RGE_ISR_PCS_TIMEOUT)
397156bc3dcSsevan 		claimed = 1;
398156bc3dcSsevan 
399156bc3dcSsevan 	rx = tx = 0;
400e13c9dceSjakllsch 	if (status & sc->rge_intrs) {
401156bc3dcSsevan 		if (status &
402156bc3dcSsevan 		    (sc->rge_rx_ack | RGE_ISR_RX_ERR | RGE_ISR_RX_FIFO_OFLOW)) {
403156bc3dcSsevan 			rx |= rge_rxeof(sc);
404156bc3dcSsevan 			claimed = 1;
405156bc3dcSsevan 		}
406156bc3dcSsevan 
407156bc3dcSsevan 		if (status & (sc->rge_tx_ack | RGE_ISR_TX_ERR)) {
408156bc3dcSsevan 			tx |= rge_txeof(sc);
409156bc3dcSsevan 			claimed = 1;
410156bc3dcSsevan 		}
411156bc3dcSsevan 
412156bc3dcSsevan 		if (status & RGE_ISR_SYSTEM_ERR) {
4137ff7ee85Ssevan 			KERNEL_LOCK(1, NULL);
414156bc3dcSsevan 			rge_init(ifp);
4157ff7ee85Ssevan 			KERNEL_UNLOCK_ONE(NULL);
416156bc3dcSsevan 			claimed = 1;
417156bc3dcSsevan 		}
418156bc3dcSsevan 	}
419156bc3dcSsevan 
420156bc3dcSsevan 	if (sc->rge_timerintr) {
421156bc3dcSsevan 		if ((tx | rx) == 0) {
422156bc3dcSsevan 			/*
423156bc3dcSsevan 			 * Nothing needs to be processed, fallback
424156bc3dcSsevan 			 * to use TX/RX interrupts.
425156bc3dcSsevan 			 */
426156bc3dcSsevan 			rge_setup_intr(sc, RGE_IMTYPE_NONE);
427156bc3dcSsevan 
428156bc3dcSsevan 			/*
429156bc3dcSsevan 			 * Recollect, mainly to avoid the possible
430156bc3dcSsevan 			 * race introduced by changing interrupt
431156bc3dcSsevan 			 * masks.
432156bc3dcSsevan 			 */
433156bc3dcSsevan 			rge_rxeof(sc);
434156bc3dcSsevan 			rge_txeof(sc);
435156bc3dcSsevan 		} else
436156bc3dcSsevan 			RGE_WRITE_4(sc, RGE_TIMERCNT, 1);
437156bc3dcSsevan 	} else if (tx | rx) {
438156bc3dcSsevan 		/*
439156bc3dcSsevan 		 * Assume that using simulated interrupt moderation
440156bc3dcSsevan 		 * (hardware timer based) could reduce the interrupt
441156bc3dcSsevan 		 * rate.
442156bc3dcSsevan 		 */
443156bc3dcSsevan 		rge_setup_intr(sc, RGE_IMTYPE_SIM);
444156bc3dcSsevan 	}
445156bc3dcSsevan 
446156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_IMR, sc->rge_intrs);
447156bc3dcSsevan 
448156bc3dcSsevan 	return (claimed);
449156bc3dcSsevan }
450156bc3dcSsevan 
451156bc3dcSsevan int
452156bc3dcSsevan rge_encap(struct rge_softc *sc, struct mbuf *m, int idx)
453156bc3dcSsevan {
454156bc3dcSsevan 	struct rge_tx_desc *d = NULL;
455156bc3dcSsevan 	struct rge_txq *txq;
456156bc3dcSsevan 	bus_dmamap_t txmap;
457156bc3dcSsevan 	uint32_t cmdsts, cflags = 0;
458156bc3dcSsevan 	int cur, error, i, last, nsegs;
459156bc3dcSsevan 
460e13c9dceSjakllsch #if notyet
461156bc3dcSsevan 	/*
462156bc3dcSsevan 	 * Set RGE_TDEXTSTS_IPCSUM if any checksum offloading is requested.
463156bc3dcSsevan 	 * Otherwise, RGE_TDEXTSTS_TCPCSUM / RGE_TDEXTSTS_UDPCSUM does not
464156bc3dcSsevan 	 * take affect.
465156bc3dcSsevan 	 */
466156bc3dcSsevan 	if ((m->m_pkthdr.csum_flags &
4677ff7ee85Ssevan 	    (M_CSUM_IPv4 | M_CSUM_TCPv4 | M_CSUM_UDPv4)) != 0) {
468156bc3dcSsevan 		cflags |= RGE_TDEXTSTS_IPCSUM;
469156bc3dcSsevan 		if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT)
470156bc3dcSsevan 			cflags |= RGE_TDEXTSTS_TCPCSUM;
471156bc3dcSsevan 		if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT)
472156bc3dcSsevan 			cflags |= RGE_TDEXTSTS_UDPCSUM;
473156bc3dcSsevan 	}
474e13c9dceSjakllsch #endif
475156bc3dcSsevan 
476156bc3dcSsevan 	txq = &sc->rge_ldata.rge_txq[idx];
477156bc3dcSsevan 	txmap = txq->txq_dmamap;
478156bc3dcSsevan 
479156bc3dcSsevan 	error = bus_dmamap_load_mbuf(sc->sc_dmat, txmap, m, BUS_DMA_NOWAIT);
480156bc3dcSsevan 	switch (error) {
481156bc3dcSsevan 	case 0:
482156bc3dcSsevan 		break;
483156bc3dcSsevan 	case EFBIG: /* mbuf chain is too fragmented */
484156bc3dcSsevan 		if (m_defrag(m, M_DONTWAIT) == 0 &&
485156bc3dcSsevan 		    bus_dmamap_load_mbuf(sc->sc_dmat, txmap, m,
486156bc3dcSsevan 		    BUS_DMA_NOWAIT) == 0)
487156bc3dcSsevan 			break;
488156bc3dcSsevan 
489156bc3dcSsevan 		/* FALLTHROUGH */
490156bc3dcSsevan 	default:
491156bc3dcSsevan 		return (0);
492156bc3dcSsevan 	}
493156bc3dcSsevan 
494156bc3dcSsevan 	bus_dmamap_sync(sc->sc_dmat, txmap, 0, txmap->dm_mapsize,
495156bc3dcSsevan 	    BUS_DMASYNC_PREWRITE);
496156bc3dcSsevan 
497156bc3dcSsevan 	nsegs = txmap->dm_nsegs;
498156bc3dcSsevan 
499156bc3dcSsevan 	/* Set up hardware VLAN tagging. */
500e13c9dceSjakllsch 	if (vlan_has_tag(m))
501e13c9dceSjakllsch 		cflags |= bswap16(vlan_get_tag(m)) | RGE_TDEXTSTS_VTAG;
502156bc3dcSsevan 
503e13c9dceSjakllsch 	last = cur = idx;
504156bc3dcSsevan 	cmdsts = RGE_TDCMDSTS_SOF;
505156bc3dcSsevan 
506156bc3dcSsevan 	for (i = 0; i < txmap->dm_nsegs; i++) {
507156bc3dcSsevan 		d = &sc->rge_ldata.rge_tx_list[cur];
508156bc3dcSsevan 
509156bc3dcSsevan 		d->rge_extsts = htole32(cflags);
510156bc3dcSsevan 		d->rge_addrlo = htole32(RGE_ADDR_LO(txmap->dm_segs[i].ds_addr));
511156bc3dcSsevan 		d->rge_addrhi = htole32(RGE_ADDR_HI(txmap->dm_segs[i].ds_addr));
512156bc3dcSsevan 
513156bc3dcSsevan 		cmdsts |= txmap->dm_segs[i].ds_len;
514156bc3dcSsevan 
515156bc3dcSsevan 		if (cur == RGE_TX_LIST_CNT - 1)
516156bc3dcSsevan 			cmdsts |= RGE_TDCMDSTS_EOR;
517156bc3dcSsevan 
518156bc3dcSsevan 		d->rge_cmdsts = htole32(cmdsts);
519156bc3dcSsevan 
520156bc3dcSsevan 		last = cur;
521156bc3dcSsevan 		cmdsts = RGE_TDCMDSTS_OWN;
522156bc3dcSsevan 		cur = RGE_NEXT_TX_DESC(cur);
523156bc3dcSsevan 	}
524156bc3dcSsevan 
525156bc3dcSsevan 	/* Set EOF on the last descriptor. */
526156bc3dcSsevan 	d->rge_cmdsts |= htole32(RGE_TDCMDSTS_EOF);
527156bc3dcSsevan 
528156bc3dcSsevan 	/* Transfer ownership of packet to the chip. */
529156bc3dcSsevan 	d = &sc->rge_ldata.rge_tx_list[idx];
530156bc3dcSsevan 
531156bc3dcSsevan 	d->rge_cmdsts |= htole32(RGE_TDCMDSTS_OWN);
532156bc3dcSsevan 
533156bc3dcSsevan 	bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map,
534156bc3dcSsevan 	    cur * sizeof(struct rge_tx_desc), sizeof(struct rge_tx_desc),
535156bc3dcSsevan 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
536156bc3dcSsevan 
537156bc3dcSsevan 	/* Update info of TX queue and descriptors. */
538156bc3dcSsevan 	txq->txq_mbuf = m;
539156bc3dcSsevan 	txq->txq_descidx = last;
540156bc3dcSsevan 
541156bc3dcSsevan 	return (nsegs);
542156bc3dcSsevan }
543156bc3dcSsevan 
544156bc3dcSsevan int
5457ff7ee85Ssevan rge_ioctl(struct ifnet *ifp, u_long cmd, void *data)
546156bc3dcSsevan {
547156bc3dcSsevan 	struct rge_softc *sc = ifp->if_softc;
548e13c9dceSjakllsch 	//struct ifreq *ifr = (struct ifreq *)data;
549156bc3dcSsevan 	int s, error = 0;
550156bc3dcSsevan 
551156bc3dcSsevan 	s = splnet();
552156bc3dcSsevan 
553156bc3dcSsevan 	switch (cmd) {
554156bc3dcSsevan 	case SIOCSIFFLAGS:
555e13c9dceSjakllsch 		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
556e13c9dceSjakllsch 			break;
557e13c9dceSjakllsch 		/* XXX set an ifflags callback and let ether_ioctl
558e13c9dceSjakllsch 		 * handle all of this.
559e13c9dceSjakllsch 		 */
560156bc3dcSsevan 		if (ifp->if_flags & IFF_UP) {
561156bc3dcSsevan 			if (ifp->if_flags & IFF_RUNNING)
562156bc3dcSsevan 				error = ENETRESET;
563156bc3dcSsevan 			else
564156bc3dcSsevan 				rge_init(ifp);
565156bc3dcSsevan 		} else {
566156bc3dcSsevan 			if (ifp->if_flags & IFF_RUNNING)
567e13c9dceSjakllsch 				rge_stop(ifp, 1);
568156bc3dcSsevan 		}
569156bc3dcSsevan 		break;
570156bc3dcSsevan 	default:
5717ff7ee85Ssevan 		error = ether_ioctl(ifp, cmd, data);
572156bc3dcSsevan 	}
573156bc3dcSsevan 
574156bc3dcSsevan 	if (error == ENETRESET) {
575156bc3dcSsevan 		if (ifp->if_flags & IFF_RUNNING)
576156bc3dcSsevan 			rge_iff(sc);
577156bc3dcSsevan 		error = 0;
578156bc3dcSsevan 	}
579156bc3dcSsevan 
580156bc3dcSsevan 	splx(s);
581156bc3dcSsevan 	return (error);
582156bc3dcSsevan }
583156bc3dcSsevan 
584156bc3dcSsevan void
585d57dd85eSsevan rge_start(struct ifnet *ifp)
586156bc3dcSsevan {
587156bc3dcSsevan 	struct rge_softc *sc = ifp->if_softc;
588156bc3dcSsevan 	struct mbuf *m;
589156bc3dcSsevan 	int free, idx, used;
590156bc3dcSsevan 	int queued = 0;
591156bc3dcSsevan 
5927ff7ee85Ssevan #define LINK_STATE_IS_UP(_s)    \
5937ff7ee85Ssevan 	((_s) >= LINK_STATE_UP || (_s) == LINK_STATE_UNKNOWN)
5947ff7ee85Ssevan 
595156bc3dcSsevan 	if (!LINK_STATE_IS_UP(ifp->if_link_state)) {
596e13c9dceSjakllsch 		IFQ_PURGE(&ifp->if_snd);
597156bc3dcSsevan 		return;
598156bc3dcSsevan 	}
599156bc3dcSsevan 
600156bc3dcSsevan 	/* Calculate free space. */
601156bc3dcSsevan 	idx = sc->rge_ldata.rge_txq_prodidx;
602156bc3dcSsevan 	free = sc->rge_ldata.rge_txq_considx;
603156bc3dcSsevan 	if (free <= idx)
604156bc3dcSsevan 		free += RGE_TX_LIST_CNT;
605156bc3dcSsevan 	free -= idx;
606156bc3dcSsevan 
607156bc3dcSsevan 	for (;;) {
608156bc3dcSsevan 		if (RGE_TX_NSEGS >= free + 2) {
609d57dd85eSsevan 			SET(ifp->if_flags, IFF_OACTIVE);
610156bc3dcSsevan 			break;
611156bc3dcSsevan 		}
612156bc3dcSsevan 
613d57dd85eSsevan 		IFQ_DEQUEUE(&ifp->if_snd, m);
614156bc3dcSsevan 		if (m == NULL)
615156bc3dcSsevan 			break;
616156bc3dcSsevan 
617156bc3dcSsevan 		used = rge_encap(sc, m, idx);
618156bc3dcSsevan 		if (used == 0) {
619156bc3dcSsevan 			m_freem(m);
620156bc3dcSsevan 			continue;
621156bc3dcSsevan 		}
622156bc3dcSsevan 
623156bc3dcSsevan 		KASSERT(used <= free);
624156bc3dcSsevan 		free -= used;
625156bc3dcSsevan 
626e13c9dceSjakllsch 		bpf_mtap(ifp, m, BPF_D_OUT);
627156bc3dcSsevan 
628156bc3dcSsevan 		idx += used;
629156bc3dcSsevan 		if (idx >= RGE_TX_LIST_CNT)
630156bc3dcSsevan 			idx -= RGE_TX_LIST_CNT;
631156bc3dcSsevan 
632156bc3dcSsevan 		queued++;
633156bc3dcSsevan 	}
634156bc3dcSsevan 
635156bc3dcSsevan 	if (queued == 0)
636156bc3dcSsevan 		return;
637156bc3dcSsevan 
638156bc3dcSsevan 	/* Set a timeout in case the chip goes out to lunch. */
639156bc3dcSsevan 	ifp->if_timer = 5;
640156bc3dcSsevan 
641156bc3dcSsevan 	sc->rge_ldata.rge_txq_prodidx = idx;
642ccc8e576Sskrll 	rge_txstart(sc);
643156bc3dcSsevan }
644156bc3dcSsevan 
645156bc3dcSsevan void
646156bc3dcSsevan rge_watchdog(struct ifnet *ifp)
647156bc3dcSsevan {
648156bc3dcSsevan 	struct rge_softc *sc = ifp->if_softc;
649156bc3dcSsevan 
65019599902Sjakllsch 	device_printf(sc->sc_dev, "watchdog timeout\n");
65111704b98Sskrll 	if_statinc(ifp, if_oerrors);
652156bc3dcSsevan 
653156bc3dcSsevan 	rge_init(ifp);
654156bc3dcSsevan }
655156bc3dcSsevan 
656156bc3dcSsevan int
657156bc3dcSsevan rge_init(struct ifnet *ifp)
658156bc3dcSsevan {
659156bc3dcSsevan 	struct rge_softc *sc = ifp->if_softc;
660156bc3dcSsevan 	uint32_t val;
66121a1f964Smrg 	unsigned i;
662156bc3dcSsevan 
663e13c9dceSjakllsch 	rge_stop(ifp, 0);
664156bc3dcSsevan 
665156bc3dcSsevan 	/* Set MAC address. */
666e13c9dceSjakllsch 	rge_set_macaddr(sc, CLLADDR(ifp->if_sadl));
667156bc3dcSsevan 
668e13c9dceSjakllsch 	/* Set Maximum frame size. */
669e13c9dceSjakllsch 	RGE_WRITE_2(sc, RGE_RXMAXSIZE, RGE_JUMBO_FRAMELEN);
670156bc3dcSsevan 
671156bc3dcSsevan 	/* Initialize RX descriptors list. */
67221a1f964Smrg 	int error = rge_rx_list_init(sc);
67321a1f964Smrg 	if (error != 0) {
67419599902Sjakllsch 		device_printf(sc->sc_dev,
675a164c08fSsevan 		    "init failed: no memory for RX buffers\n");
676e13c9dceSjakllsch 		rge_stop(ifp, 1);
67721a1f964Smrg 		return error;
678156bc3dcSsevan 	}
679156bc3dcSsevan 
680156bc3dcSsevan 	/* Initialize TX descriptors. */
681156bc3dcSsevan 	rge_tx_list_init(sc);
682156bc3dcSsevan 
683156bc3dcSsevan 	/* Load the addresses of the RX and TX lists into the chip. */
684156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_RXDESC_ADDR_LO,
685156bc3dcSsevan 	    RGE_ADDR_LO(sc->rge_ldata.rge_rx_list_map->dm_segs[0].ds_addr));
686156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_RXDESC_ADDR_HI,
687156bc3dcSsevan 	    RGE_ADDR_HI(sc->rge_ldata.rge_rx_list_map->dm_segs[0].ds_addr));
688156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_TXDESC_ADDR_LO,
689156bc3dcSsevan 	    RGE_ADDR_LO(sc->rge_ldata.rge_tx_list_map->dm_segs[0].ds_addr));
690156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_TXDESC_ADDR_HI,
691156bc3dcSsevan 	    RGE_ADDR_HI(sc->rge_ldata.rge_tx_list_map->dm_segs[0].ds_addr));
692156bc3dcSsevan 
693156bc3dcSsevan 	RGE_SETBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
694156bc3dcSsevan 
695156bc3dcSsevan 	RGE_CLRBIT_1(sc, 0xf1, 0x80);
696156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_CFG2, RGE_CFG2_CLKREQ_EN);
697156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_CFG5, RGE_CFG5_PME_STS);
698156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_CFG3, RGE_CFG3_RDY_TO_L23);
699156bc3dcSsevan 
700156bc3dcSsevan 	/* Clear interrupt moderation timer. */
701156bc3dcSsevan 	for (i = 0; i < 64; i++)
702e13c9dceSjakllsch 		RGE_WRITE_4(sc, RGE_INTMITI(i), 0);
703156bc3dcSsevan 
704156bc3dcSsevan 	/* Set the initial RX and TX configurations. */
705156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_RXCFG, RGE_RXCFG_CONFIG);
706156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_TXCFG, RGE_TXCFG_CONFIG);
707156bc3dcSsevan 
708156bc3dcSsevan 	val = rge_read_csi(sc, 0x70c) & ~0xff000000;
709156bc3dcSsevan 	rge_write_csi(sc, 0x70c, val | 0x27000000);
710156bc3dcSsevan 
711156bc3dcSsevan 	/* Enable hardware optimization function. */
712156bc3dcSsevan 	val = pci_conf_read(sc->sc_pc, sc->sc_tag, 0x78) & ~0x00007000;
713156bc3dcSsevan 	pci_conf_write(sc->sc_pc, sc->sc_tag, 0x78, val | 0x00005000);
714156bc3dcSsevan 
715156bc3dcSsevan 	RGE_WRITE_2(sc, 0x0382, 0x221b);
716156bc3dcSsevan 	RGE_WRITE_1(sc, 0x4500, 0);
717156bc3dcSsevan 	RGE_WRITE_2(sc, 0x4800, 0);
718156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_CFG1, RGE_CFG1_SPEED_DOWN);
719156bc3dcSsevan 
720156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xc140, 0xffff);
721156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xc142, 0xffff);
722156bc3dcSsevan 
723156bc3dcSsevan 	val = rge_read_mac_ocp(sc, 0xd3e2) & ~0x0fff;
724156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xd3e2, val | 0x03a9);
725156bc3dcSsevan 
726156bc3dcSsevan 	RGE_MAC_CLRBIT(sc, 0xd3e4, 0x00ff);
727156bc3dcSsevan 	RGE_MAC_SETBIT(sc, 0xe860, 0x0080);
728156bc3dcSsevan 	RGE_MAC_SETBIT(sc, 0xeb58, 0x0001);
729156bc3dcSsevan 
730156bc3dcSsevan 	val = rge_read_mac_ocp(sc, 0xe614) & ~0x0700;
731e13c9dceSjakllsch 	if (sc->rge_type == MAC_CFG2 || sc->rge_type == MAC_CFG3)
732156bc3dcSsevan 		rge_write_mac_ocp(sc, 0xe614, val | 0x0400);
733e13c9dceSjakllsch 	else
734e13c9dceSjakllsch 		rge_write_mac_ocp(sc, 0xe614, val | 0x0200);
735156bc3dcSsevan 
736156bc3dcSsevan 	RGE_MAC_CLRBIT(sc, 0xe63e, 0x0c00);
737156bc3dcSsevan 
738e13c9dceSjakllsch 	if (sc->rge_type == MAC_CFG2 || sc->rge_type == MAC_CFG3) {
739156bc3dcSsevan 		val = rge_read_mac_ocp(sc, 0xe63e) & ~0x0030;
740156bc3dcSsevan 		rge_write_mac_ocp(sc, 0xe63e, val | 0x0020);
741e13c9dceSjakllsch 	} else
742e13c9dceSjakllsch 		RGE_MAC_CLRBIT(sc, 0xe63e, 0x0030);
743156bc3dcSsevan 
744156bc3dcSsevan 	RGE_MAC_SETBIT(sc, 0xc0b4, 0x000c);
745156bc3dcSsevan 
746e13c9dceSjakllsch 	val = rge_read_mac_ocp(sc, 0xeb6a) & ~0x00ff;
747156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xeb6a, val | 0x0033);
748156bc3dcSsevan 
749156bc3dcSsevan 	val = rge_read_mac_ocp(sc, 0xeb50) & ~0x03e0;
750156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xeb50, val | 0x0040);
751156bc3dcSsevan 
752156bc3dcSsevan 	val = rge_read_mac_ocp(sc, 0xe056) & ~0x00f0;
753156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xe056, val | 0x0030);
754156bc3dcSsevan 
755156bc3dcSsevan 	RGE_WRITE_1(sc, RGE_TDFNR, 0x10);
756156bc3dcSsevan 
757e13c9dceSjakllsch 	RGE_SETBIT_1(sc, RGE_DLLPR, RGE_DLLPR_TX_10M_PS_EN);
758e13c9dceSjakllsch 
759156bc3dcSsevan 	RGE_MAC_CLRBIT(sc, 0xe040, 0x1000);
760156bc3dcSsevan 
761e13c9dceSjakllsch 	val = rge_read_mac_ocp(sc, 0xea1c) & ~0x0003;
762e13c9dceSjakllsch 	rge_write_mac_ocp(sc, 0xea1c, val | 0x0001);
763e13c9dceSjakllsch 
764156bc3dcSsevan 	val = rge_read_mac_ocp(sc, 0xe0c0) & ~0x4f0f;
765156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xe0c0, val | 0x4403);
766156bc3dcSsevan 
767156bc3dcSsevan 	RGE_MAC_SETBIT(sc, 0xe052, 0x0068);
768156bc3dcSsevan 	RGE_MAC_CLRBIT(sc, 0xe052, 0x0080);
769156bc3dcSsevan 
770156bc3dcSsevan 	val = rge_read_mac_ocp(sc, 0xc0ac) & ~0x0080;
771156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xc0ac, val | 0x1f00);
772156bc3dcSsevan 
773156bc3dcSsevan 	val = rge_read_mac_ocp(sc, 0xd430) & ~0x0fff;
774156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xd430, val | 0x047f);
775156bc3dcSsevan 
776e13c9dceSjakllsch 	val = rge_read_mac_ocp(sc, 0xe84c) & ~0x0040;
777e13c9dceSjakllsch 	if (sc->rge_type == MAC_CFG2 || sc->rge_type == MAC_CFG3)
778e13c9dceSjakllsch 		rge_write_mac_ocp(sc, 0xe84c, 0x00c0);
779e13c9dceSjakllsch 	else
780e13c9dceSjakllsch 		rge_write_mac_ocp(sc, 0xe84c, 0x0080);
781e13c9dceSjakllsch 
782e13c9dceSjakllsch 	RGE_SETBIT_1(sc, RGE_DLLPR, RGE_DLLPR_PFM_EN);
783e13c9dceSjakllsch 
784e13c9dceSjakllsch 	if (sc->rge_type == MAC_CFG2 || sc->rge_type == MAC_CFG3)
785e13c9dceSjakllsch 		RGE_SETBIT_1(sc, RGE_MCUCMD, 0x01);
786156bc3dcSsevan 
787156bc3dcSsevan 	/* Disable EEE plus. */
788156bc3dcSsevan 	RGE_MAC_CLRBIT(sc, 0xe080, 0x0002);
789156bc3dcSsevan 
790156bc3dcSsevan 	RGE_MAC_CLRBIT(sc, 0xea1c, 0x0004);
791156bc3dcSsevan 
792156bc3dcSsevan 	RGE_MAC_SETBIT(sc, 0xeb54, 0x0001);
793156bc3dcSsevan 	DELAY(1);
794156bc3dcSsevan 	RGE_MAC_CLRBIT(sc, 0xeb54, 0x0001);
795156bc3dcSsevan 
796156bc3dcSsevan 	RGE_CLRBIT_4(sc, 0x1880, 0x0030);
797156bc3dcSsevan 
798156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xe098, 0xc302);
799156bc3dcSsevan 
800e13c9dceSjakllsch 	if ((sc->sc_ec.ec_capenable & ETHERCAP_VLAN_HWTAGGING) != 0)
801156bc3dcSsevan 		RGE_SETBIT_4(sc, RGE_RXCFG, RGE_RXCFG_VLANSTRIP);
802e13c9dceSjakllsch 	else
803e13c9dceSjakllsch 		RGE_CLRBIT_4(sc, RGE_RXCFG, RGE_RXCFG_VLANSTRIP);
804156bc3dcSsevan 
805156bc3dcSsevan 	RGE_SETBIT_2(sc, RGE_CPLUSCMD, RGE_CPLUSCMD_RXCSUM);
806156bc3dcSsevan 
807156bc3dcSsevan 	for (i = 0; i < 10; i++) {
808156bc3dcSsevan 		if (!(rge_read_mac_ocp(sc, 0xe00e) & 0x2000))
809156bc3dcSsevan 			break;
810156bc3dcSsevan 		DELAY(1000);
811156bc3dcSsevan 	}
812156bc3dcSsevan 
813156bc3dcSsevan 	/* Disable RXDV gate. */
814156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_PPSW, 0x08);
815156bc3dcSsevan 	DELAY(2000);
816156bc3dcSsevan 
817156bc3dcSsevan 	rge_ifmedia_upd(ifp);
818156bc3dcSsevan 
819156bc3dcSsevan 	/* Enable transmit and receive. */
820156bc3dcSsevan 	RGE_WRITE_1(sc, RGE_CMD, RGE_CMD_TXENB | RGE_CMD_RXENB);
821156bc3dcSsevan 
822156bc3dcSsevan 	/* Program promiscuous mode and multicast filters. */
823156bc3dcSsevan 	rge_iff(sc);
824156bc3dcSsevan 
825156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_CFG2, RGE_CFG2_CLKREQ_EN);
826156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_CFG5, RGE_CFG5_PME_STS);
827156bc3dcSsevan 
828156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
829156bc3dcSsevan 
830156bc3dcSsevan 	/* Enable interrupts. */
831156bc3dcSsevan 	rge_setup_intr(sc, RGE_IMTYPE_SIM);
832156bc3dcSsevan 
833156bc3dcSsevan 	ifp->if_flags |= IFF_RUNNING;
834d57dd85eSsevan 	CLR(ifp->if_flags, IFF_OACTIVE);
835156bc3dcSsevan 
836d57dd85eSsevan 	callout_schedule(&sc->sc_timeout, 1);
837156bc3dcSsevan 
838156bc3dcSsevan 	return (0);
839156bc3dcSsevan }
840156bc3dcSsevan 
841156bc3dcSsevan /*
842156bc3dcSsevan  * Stop the adapter and free any mbufs allocated to the RX and TX lists.
843156bc3dcSsevan  */
844156bc3dcSsevan void
845e13c9dceSjakllsch rge_stop(struct ifnet *ifp, int disable)
846156bc3dcSsevan {
847156bc3dcSsevan 	struct rge_softc *sc = ifp->if_softc;
848156bc3dcSsevan 
849e13c9dceSjakllsch 	callout_halt(&sc->sc_timeout, NULL);
850156bc3dcSsevan 
851156bc3dcSsevan 	ifp->if_timer = 0;
852156bc3dcSsevan 	ifp->if_flags &= ~IFF_RUNNING;
853156bc3dcSsevan 	sc->rge_timerintr = 0;
854156bc3dcSsevan 
855156bc3dcSsevan 	RGE_CLRBIT_4(sc, RGE_RXCFG, RGE_RXCFG_ALLPHYS | RGE_RXCFG_INDIV |
856156bc3dcSsevan 	    RGE_RXCFG_MULTI | RGE_RXCFG_BROAD | RGE_RXCFG_RUNT |
857156bc3dcSsevan 	    RGE_RXCFG_ERRPKT);
858156bc3dcSsevan 
859156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_IMR, 0);
860e13c9dceSjakllsch 
861e13c9dceSjakllsch 	/* Clear timer interrupts. */
862e13c9dceSjakllsch 	RGE_WRITE_4(sc, RGE_TIMERINT0, 0);
863e13c9dceSjakllsch 	RGE_WRITE_4(sc, RGE_TIMERINT1, 0);
864e13c9dceSjakllsch 	RGE_WRITE_4(sc, RGE_TIMERINT2, 0);
865e13c9dceSjakllsch 	RGE_WRITE_4(sc, RGE_TIMERINT3, 0);
866156bc3dcSsevan 
867156bc3dcSsevan 	rge_reset(sc);
868156bc3dcSsevan 
869e13c9dceSjakllsch //	intr_barrier(sc->sc_ih);
870e13c9dceSjakllsch //	ifq_barrier(&ifp->if_snd);
8717ff7ee85Ssevan /*	ifq_clr_oactive(&ifp->if_snd); Sevan - OpenBSD queue API */
872156bc3dcSsevan 
873156bc3dcSsevan 	if (sc->rge_head != NULL) {
874156bc3dcSsevan 		m_freem(sc->rge_head);
875156bc3dcSsevan 		sc->rge_head = sc->rge_tail = NULL;
876156bc3dcSsevan 	}
877156bc3dcSsevan 
87821a1f964Smrg 	rge_tx_list_fini(sc);
87921a1f964Smrg 	rge_rx_list_fini(sc);
880156bc3dcSsevan }
881156bc3dcSsevan 
882156bc3dcSsevan /*
883156bc3dcSsevan  * Set media options.
884156bc3dcSsevan  */
885156bc3dcSsevan int
886156bc3dcSsevan rge_ifmedia_upd(struct ifnet *ifp)
887156bc3dcSsevan {
888156bc3dcSsevan 	struct rge_softc *sc = ifp->if_softc;
889156bc3dcSsevan 	struct ifmedia *ifm = &sc->sc_media;
890156bc3dcSsevan 	int anar, gig, val;
891156bc3dcSsevan 
892156bc3dcSsevan 	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
893156bc3dcSsevan 		return (EINVAL);
894156bc3dcSsevan 
895156bc3dcSsevan 	/* Disable Gigabit Lite. */
896156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xa428, 0x0200);
897156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xa5ea, 0x0001);
898156bc3dcSsevan 
899156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa5d4);
900156bc3dcSsevan 	val &= ~RGE_ADV_2500TFDX;
901156bc3dcSsevan 
902156bc3dcSsevan 	anar = gig = 0;
903156bc3dcSsevan 	switch (IFM_SUBTYPE(ifm->ifm_media)) {
904156bc3dcSsevan 	case IFM_AUTO:
905e13c9dceSjakllsch 		anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
906e13c9dceSjakllsch 		gig = GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
907156bc3dcSsevan 		val |= RGE_ADV_2500TFDX;
908156bc3dcSsevan 		break;
909156bc3dcSsevan 	case IFM_2500_T:
910e13c9dceSjakllsch 		anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
911e13c9dceSjakllsch 		gig = GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
912156bc3dcSsevan 		val |= RGE_ADV_2500TFDX;
913156bc3dcSsevan 		ifp->if_baudrate = IF_Mbps(2500);
914156bc3dcSsevan 		break;
915156bc3dcSsevan 	case IFM_1000_T:
916e13c9dceSjakllsch 		anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
917e13c9dceSjakllsch 		gig = GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
918156bc3dcSsevan 		ifp->if_baudrate = IF_Gbps(1);
919156bc3dcSsevan 		break;
920156bc3dcSsevan 	case IFM_100_TX:
921e13c9dceSjakllsch 		gig = rge_read_phy(sc, 0, MII_100T2CR) &
922e13c9dceSjakllsch 		    ~(GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX);
923e13c9dceSjakllsch 		anar = ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) ?
924e13c9dceSjakllsch 		    ANAR_TX | ANAR_TX_FD | ANAR_10_FD | ANAR_10 :
925e13c9dceSjakllsch 		    ANAR_TX | ANAR_10_FD | ANAR_10;
926156bc3dcSsevan 		ifp->if_baudrate = IF_Mbps(100);
927156bc3dcSsevan 		break;
928156bc3dcSsevan 	case IFM_10_T:
929e13c9dceSjakllsch 		gig = rge_read_phy(sc, 0, MII_100T2CR) &
930e13c9dceSjakllsch 		    ~(GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX);
931e13c9dceSjakllsch 		anar = ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) ?
932e13c9dceSjakllsch 		    ANAR_10_FD | ANAR_10 : ANAR_10;
933156bc3dcSsevan 		ifp->if_baudrate = IF_Mbps(10);
934156bc3dcSsevan 		break;
935156bc3dcSsevan 	default:
93619599902Sjakllsch 		device_printf(sc->sc_dev,
937a164c08fSsevan 		    "unsupported media type\n");
938156bc3dcSsevan 		return (EINVAL);
939156bc3dcSsevan 	}
940156bc3dcSsevan 
941156bc3dcSsevan 	rge_write_phy(sc, 0, MII_ANAR, anar | ANAR_PAUSE_ASYM | ANAR_FC);
942156bc3dcSsevan 	rge_write_phy(sc, 0, MII_100T2CR, gig);
943156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa5d4, val);
944e13c9dceSjakllsch 	rge_write_phy(sc, 0, MII_BMCR, BMCR_RESET | BMCR_AUTOEN |
945e13c9dceSjakllsch 	    BMCR_STARTNEG);
946156bc3dcSsevan 
947156bc3dcSsevan 	return (0);
948156bc3dcSsevan }
949156bc3dcSsevan 
950156bc3dcSsevan /*
951156bc3dcSsevan  * Report current media status.
952156bc3dcSsevan  */
953156bc3dcSsevan void
954156bc3dcSsevan rge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
955156bc3dcSsevan {
956156bc3dcSsevan 	struct rge_softc *sc = ifp->if_softc;
957156bc3dcSsevan 	uint16_t status = 0;
958156bc3dcSsevan 
959156bc3dcSsevan 	ifmr->ifm_status = IFM_AVALID;
960156bc3dcSsevan 	ifmr->ifm_active = IFM_ETHER;
961156bc3dcSsevan 
962156bc3dcSsevan 	if (rge_get_link_status(sc)) {
963156bc3dcSsevan 		ifmr->ifm_status |= IFM_ACTIVE;
964156bc3dcSsevan 
965156bc3dcSsevan 		status = RGE_READ_2(sc, RGE_PHYSTAT);
966156bc3dcSsevan 		if ((status & RGE_PHYSTAT_FDX) ||
967156bc3dcSsevan 		    (status & RGE_PHYSTAT_2500MBPS))
968156bc3dcSsevan 			ifmr->ifm_active |= IFM_FDX;
969156bc3dcSsevan 		else
970156bc3dcSsevan 			ifmr->ifm_active |= IFM_HDX;
971156bc3dcSsevan 
972156bc3dcSsevan 		if (status & RGE_PHYSTAT_10MBPS)
973156bc3dcSsevan 			ifmr->ifm_active |= IFM_10_T;
974156bc3dcSsevan 		else if (status & RGE_PHYSTAT_100MBPS)
975156bc3dcSsevan 			ifmr->ifm_active |= IFM_100_TX;
976156bc3dcSsevan 		else if (status & RGE_PHYSTAT_1000MBPS)
977156bc3dcSsevan 			ifmr->ifm_active |= IFM_1000_T;
978156bc3dcSsevan 		else if (status & RGE_PHYSTAT_2500MBPS)
979156bc3dcSsevan 			ifmr->ifm_active |= IFM_2500_T;
980156bc3dcSsevan 	}
981156bc3dcSsevan }
982156bc3dcSsevan 
983156bc3dcSsevan /*
984156bc3dcSsevan  * Allocate memory for RX/TX rings.
985022d5228Smrg  *
986022d5228Smrg  * XXX There is no tear-down for this if it any part fails, so everything
987022d5228Smrg  * remains allocated.
988156bc3dcSsevan  */
989156bc3dcSsevan int
990156bc3dcSsevan rge_allocmem(struct rge_softc *sc)
991156bc3dcSsevan {
992156bc3dcSsevan 	int error, i;
993156bc3dcSsevan 
994156bc3dcSsevan 	/* Allocate DMA'able memory for the TX ring. */
995156bc3dcSsevan 	error = bus_dmamap_create(sc->sc_dmat, RGE_TX_LIST_SZ, 1,
996156bc3dcSsevan 	    RGE_TX_LIST_SZ, 0, BUS_DMA_NOWAIT, &sc->rge_ldata.rge_tx_list_map);
997156bc3dcSsevan 	if (error) {
998a164c08fSsevan 		aprint_error_dev(sc->sc_dev, "can't create TX list map\n");
999156bc3dcSsevan 		return (error);
1000156bc3dcSsevan 	}
1001156bc3dcSsevan 	error = bus_dmamem_alloc(sc->sc_dmat, RGE_TX_LIST_SZ, RGE_ALIGN, 0,
1002156bc3dcSsevan 	    &sc->rge_ldata.rge_tx_listseg, 1, &sc->rge_ldata.rge_tx_listnseg,
1003e13c9dceSjakllsch 	    BUS_DMA_NOWAIT);
1004156bc3dcSsevan 	if (error) {
1005a164c08fSsevan 		aprint_error_dev(sc->sc_dev, "can't alloc TX list\n");
1006156bc3dcSsevan 		return (error);
1007156bc3dcSsevan 	}
1008156bc3dcSsevan 
1009156bc3dcSsevan 	/* Load the map for the TX ring. */
1010156bc3dcSsevan 	error = bus_dmamem_map(sc->sc_dmat, &sc->rge_ldata.rge_tx_listseg,
1011156bc3dcSsevan 	    sc->rge_ldata.rge_tx_listnseg, RGE_TX_LIST_SZ,
1012322778c4Ssevan 	    (void **) &sc->rge_ldata.rge_tx_list,
1013e13c9dceSjakllsch 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
1014156bc3dcSsevan 	if (error) {
1015a164c08fSsevan 		aprint_error_dev(sc->sc_dev, "can't map TX dma buffers\n");
1016156bc3dcSsevan 		bus_dmamem_free(sc->sc_dmat, &sc->rge_ldata.rge_tx_listseg,
1017156bc3dcSsevan 		    sc->rge_ldata.rge_tx_listnseg);
1018156bc3dcSsevan 		return (error);
1019156bc3dcSsevan 	}
1020e13c9dceSjakllsch 	memset(sc->rge_ldata.rge_tx_list, 0, RGE_TX_LIST_SZ);
1021156bc3dcSsevan 	error = bus_dmamap_load(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map,
1022156bc3dcSsevan 	    sc->rge_ldata.rge_tx_list, RGE_TX_LIST_SZ, NULL, BUS_DMA_NOWAIT);
1023156bc3dcSsevan 	if (error) {
1024a164c08fSsevan 		aprint_error_dev(sc->sc_dev, "can't load TX dma map\n");
1025156bc3dcSsevan 		bus_dmamap_destroy(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map);
1026156bc3dcSsevan 		bus_dmamem_unmap(sc->sc_dmat,
10277ff7ee85Ssevan 		    sc->rge_ldata.rge_tx_list, RGE_TX_LIST_SZ);
1028156bc3dcSsevan 		bus_dmamem_free(sc->sc_dmat, &sc->rge_ldata.rge_tx_listseg,
1029156bc3dcSsevan 		    sc->rge_ldata.rge_tx_listnseg);
1030156bc3dcSsevan 		return (error);
1031156bc3dcSsevan 	}
1032156bc3dcSsevan 
1033156bc3dcSsevan 	/* Create DMA maps for TX buffers. */
1034156bc3dcSsevan 	for (i = 0; i < RGE_TX_LIST_CNT; i++) {
1035156bc3dcSsevan 		error = bus_dmamap_create(sc->sc_dmat, RGE_JUMBO_FRAMELEN,
1036156bc3dcSsevan 		    RGE_TX_NSEGS, RGE_JUMBO_FRAMELEN, 0, 0,
1037156bc3dcSsevan 		    &sc->rge_ldata.rge_txq[i].txq_dmamap);
1038156bc3dcSsevan 		if (error) {
1039a164c08fSsevan 			aprint_error_dev(sc->sc_dev, "can't create DMA map for TX\n");
1040156bc3dcSsevan 			return (error);
1041156bc3dcSsevan 		}
1042156bc3dcSsevan 	}
1043156bc3dcSsevan 
1044156bc3dcSsevan 	/* Allocate DMA'able memory for the RX ring. */
1045156bc3dcSsevan 	error = bus_dmamap_create(sc->sc_dmat, RGE_RX_LIST_SZ, 1,
1046156bc3dcSsevan 	    RGE_RX_LIST_SZ, 0, 0, &sc->rge_ldata.rge_rx_list_map);
1047156bc3dcSsevan 	if (error) {
1048a164c08fSsevan 		aprint_error_dev(sc->sc_dev, "can't create RX list map\n");
1049156bc3dcSsevan 		return (error);
1050156bc3dcSsevan 	}
1051156bc3dcSsevan 	error = bus_dmamem_alloc(sc->sc_dmat, RGE_RX_LIST_SZ, RGE_ALIGN, 0,
1052156bc3dcSsevan 	    &sc->rge_ldata.rge_rx_listseg, 1, &sc->rge_ldata.rge_rx_listnseg,
1053e13c9dceSjakllsch 	    BUS_DMA_NOWAIT);
1054156bc3dcSsevan 	if (error) {
1055a164c08fSsevan 		aprint_error_dev(sc->sc_dev, "can't alloc RX list\n");
1056156bc3dcSsevan 		return (error);
1057156bc3dcSsevan 	}
1058156bc3dcSsevan 
1059156bc3dcSsevan 	/* Load the map for the RX ring. */
1060156bc3dcSsevan 	error = bus_dmamem_map(sc->sc_dmat, &sc->rge_ldata.rge_rx_listseg,
1061156bc3dcSsevan 	    sc->rge_ldata.rge_rx_listnseg, RGE_RX_LIST_SZ,
1062322778c4Ssevan 	    (void **) &sc->rge_ldata.rge_rx_list,
1063e13c9dceSjakllsch 	    BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
1064156bc3dcSsevan 	if (error) {
1065a164c08fSsevan 		aprint_error_dev(sc->sc_dev, "can't map RX dma buffers\n");
1066156bc3dcSsevan 		bus_dmamem_free(sc->sc_dmat, &sc->rge_ldata.rge_rx_listseg,
1067156bc3dcSsevan 		    sc->rge_ldata.rge_rx_listnseg);
1068156bc3dcSsevan 		return (error);
1069156bc3dcSsevan 	}
1070e13c9dceSjakllsch 	memset(sc->rge_ldata.rge_rx_list, 0, RGE_RX_LIST_SZ);
1071156bc3dcSsevan 	error = bus_dmamap_load(sc->sc_dmat, sc->rge_ldata.rge_rx_list_map,
1072156bc3dcSsevan 	    sc->rge_ldata.rge_rx_list, RGE_RX_LIST_SZ, NULL, BUS_DMA_NOWAIT);
1073156bc3dcSsevan 	if (error) {
1074a164c08fSsevan 		aprint_error_dev(sc->sc_dev, "can't load RX dma map\n");
1075156bc3dcSsevan 		bus_dmamap_destroy(sc->sc_dmat, sc->rge_ldata.rge_rx_list_map);
1076156bc3dcSsevan 		bus_dmamem_unmap(sc->sc_dmat,
10777ff7ee85Ssevan 		    sc->rge_ldata.rge_rx_list, RGE_RX_LIST_SZ);
1078156bc3dcSsevan 		bus_dmamem_free(sc->sc_dmat, &sc->rge_ldata.rge_rx_listseg,
1079156bc3dcSsevan 		    sc->rge_ldata.rge_rx_listnseg);
1080156bc3dcSsevan 		return (error);
1081156bc3dcSsevan 	}
1082156bc3dcSsevan 
1083022d5228Smrg 	/*
1084022d5228Smrg 	 * Create DMA maps for RX buffers.  Use BUS_DMA_ALLOCNOW to avoid any
1085022d5228Smrg 	 * potential failure in bus_dmamap_load_mbuf() in the RX path.
1086022d5228Smrg 	 */
1087156bc3dcSsevan 	for (i = 0; i < RGE_RX_LIST_CNT; i++) {
1088156bc3dcSsevan 		error = bus_dmamap_create(sc->sc_dmat, RGE_JUMBO_FRAMELEN, 1,
1089022d5228Smrg 		    RGE_JUMBO_FRAMELEN, 0, BUS_DMA_ALLOCNOW,
1090156bc3dcSsevan 		    &sc->rge_ldata.rge_rxq[i].rxq_dmamap);
1091156bc3dcSsevan 		if (error) {
1092a164c08fSsevan 			aprint_error_dev(sc->sc_dev, "can't create DMA map for RX\n");
1093156bc3dcSsevan 			return (error);
1094156bc3dcSsevan 		}
1095156bc3dcSsevan 	}
1096156bc3dcSsevan 
1097156bc3dcSsevan 	return (error);
1098156bc3dcSsevan }
1099156bc3dcSsevan 
1100156bc3dcSsevan /*
1101022d5228Smrg  * Set an RX descriptor and sync it.
1102022d5228Smrg  */
1103022d5228Smrg static void
1104022d5228Smrg rge_load_rxbuf(struct rge_softc *sc, int idx)
1105022d5228Smrg {
1106022d5228Smrg 	struct rge_rx_desc *r = &sc->rge_ldata.rge_rx_list[idx];
1107022d5228Smrg 	struct rge_rxq *rxq = &sc->rge_ldata.rge_rxq[idx];
1108022d5228Smrg 	bus_dmamap_t rxmap = rxq->rxq_dmamap;
1109022d5228Smrg 	uint32_t cmdsts;
1110022d5228Smrg 
1111022d5228Smrg 	cmdsts = rxmap->dm_segs[0].ds_len | RGE_RDCMDSTS_OWN;
1112022d5228Smrg 	if (idx == RGE_RX_LIST_CNT - 1)
1113022d5228Smrg 		cmdsts |= RGE_RDCMDSTS_EOR;
1114022d5228Smrg 
1115022d5228Smrg 	r->hi_qword0.rge_addr = htole64(rxmap->dm_segs[0].ds_addr);
1116022d5228Smrg 	r->hi_qword1.rx_qword4.rge_extsts = 0;
1117022d5228Smrg 	r->hi_qword1.rx_qword4.rge_cmdsts = htole32(cmdsts);
1118022d5228Smrg 
1119022d5228Smrg 	bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_rx_list_map,
1120022d5228Smrg 	    idx * sizeof(struct rge_rx_desc), sizeof(struct rge_rx_desc),
1121022d5228Smrg 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1122022d5228Smrg }
1123022d5228Smrg 
1124022d5228Smrg /*
1125156bc3dcSsevan  * Initialize the RX descriptor and attach an mbuf cluster.
1126156bc3dcSsevan  */
1127156bc3dcSsevan int
1128156bc3dcSsevan rge_newbuf(struct rge_softc *sc, int idx)
1129156bc3dcSsevan {
1130156bc3dcSsevan 	struct mbuf *m;
1131156bc3dcSsevan 	struct rge_rxq *rxq;
1132156bc3dcSsevan 	bus_dmamap_t rxmap;
1133022d5228Smrg 	int error __diagused;
1134156bc3dcSsevan 
1135e13c9dceSjakllsch 	m = MCLGETL(NULL, M_DONTWAIT, RGE_JUMBO_FRAMELEN);
1136156bc3dcSsevan 	if (m == NULL)
1137156bc3dcSsevan 		return (ENOBUFS);
1138*965ff70dSmlelstv 	MCLAIM(m, &sc->sc_ec.ec_rx_mowner);
1139156bc3dcSsevan 
1140156bc3dcSsevan 	m->m_len = m->m_pkthdr.len = RGE_JUMBO_FRAMELEN;
1141156bc3dcSsevan 
1142156bc3dcSsevan 	rxq = &sc->rge_ldata.rge_rxq[idx];
1143156bc3dcSsevan 	rxmap = rxq->rxq_dmamap;
1144156bc3dcSsevan 
1145022d5228Smrg 	if (rxq->rxq_mbuf != NULL)
1146022d5228Smrg 		bus_dmamap_unload(sc->sc_dmat, rxq->rxq_dmamap);
1147022d5228Smrg 
1148022d5228Smrg 	/* This map was created with BUS_DMA_ALLOCNOW so should never fail. */
1149022d5228Smrg 	error = bus_dmamap_load_mbuf(sc->sc_dmat, rxmap, m, BUS_DMA_NOWAIT);
1150022d5228Smrg 	KASSERTMSG(error == 0, "error=%d", error);
1151156bc3dcSsevan 
1152156bc3dcSsevan 	bus_dmamap_sync(sc->sc_dmat, rxmap, 0, rxmap->dm_mapsize,
1153156bc3dcSsevan 	    BUS_DMASYNC_PREREAD);
1154156bc3dcSsevan 
1155156bc3dcSsevan 	/* Map the segments into RX descriptors. */
1156156bc3dcSsevan 
1157156bc3dcSsevan 	rxq->rxq_mbuf = m;
1158022d5228Smrg 	rge_load_rxbuf(sc, idx);
1159156bc3dcSsevan 
1160022d5228Smrg 	return 0;
1161156bc3dcSsevan }
1162156bc3dcSsevan 
116321a1f964Smrg static int
1164156bc3dcSsevan rge_rx_list_init(struct rge_softc *sc)
1165156bc3dcSsevan {
116621a1f964Smrg 	unsigned i;
1167156bc3dcSsevan 
1168156bc3dcSsevan 	memset(sc->rge_ldata.rge_rx_list, 0, RGE_RX_LIST_SZ);
1169156bc3dcSsevan 
1170156bc3dcSsevan 	for (i = 0; i < RGE_RX_LIST_CNT; i++) {
1171156bc3dcSsevan 		sc->rge_ldata.rge_rxq[i].rxq_mbuf = NULL;
117221a1f964Smrg 		if (rge_newbuf(sc, i) != 0) {
117321a1f964Smrg 			rge_rx_list_fini(sc);
1174156bc3dcSsevan 			return (ENOBUFS);
1175156bc3dcSsevan 		}
117621a1f964Smrg 	}
1177156bc3dcSsevan 
1178e13c9dceSjakllsch 	sc->rge_ldata.rge_rxq_prodidx = sc->rge_ldata.rge_rxq_considx = 0;
1179156bc3dcSsevan 	sc->rge_head = sc->rge_tail = NULL;
1180156bc3dcSsevan 
1181156bc3dcSsevan 	return (0);
1182156bc3dcSsevan }
1183156bc3dcSsevan 
118421a1f964Smrg static void
118521a1f964Smrg rge_rx_list_fini(struct rge_softc *sc)
118621a1f964Smrg {
118721a1f964Smrg 	unsigned i;
118821a1f964Smrg 
118921a1f964Smrg 	/* Free the RX list buffers. */
119021a1f964Smrg 	for (i = 0; i < RGE_RX_LIST_CNT; i++) {
119121a1f964Smrg 		if (sc->rge_ldata.rge_rxq[i].rxq_mbuf != NULL) {
119221a1f964Smrg 			bus_dmamap_unload(sc->sc_dmat,
119321a1f964Smrg 			    sc->rge_ldata.rge_rxq[i].rxq_dmamap);
119421a1f964Smrg 			m_freem(sc->rge_ldata.rge_rxq[i].rxq_mbuf);
119521a1f964Smrg 			sc->rge_ldata.rge_rxq[i].rxq_mbuf = NULL;
119621a1f964Smrg 		}
119721a1f964Smrg 	}
119821a1f964Smrg }
119921a1f964Smrg 
120021a1f964Smrg static void
1201156bc3dcSsevan rge_tx_list_init(struct rge_softc *sc)
1202156bc3dcSsevan {
120321a1f964Smrg 	unsigned i;
1204156bc3dcSsevan 
1205156bc3dcSsevan 	memset(sc->rge_ldata.rge_tx_list, 0, RGE_TX_LIST_SZ);
1206156bc3dcSsevan 
1207156bc3dcSsevan 	for (i = 0; i < RGE_TX_LIST_CNT; i++)
1208156bc3dcSsevan 		sc->rge_ldata.rge_txq[i].txq_mbuf = NULL;
1209156bc3dcSsevan 
1210156bc3dcSsevan 	bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map, 0,
1211156bc3dcSsevan 	    sc->rge_ldata.rge_tx_list_map->dm_mapsize,
1212156bc3dcSsevan 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1213156bc3dcSsevan 
1214156bc3dcSsevan 	sc->rge_ldata.rge_txq_prodidx = sc->rge_ldata.rge_txq_considx = 0;
1215156bc3dcSsevan }
1216156bc3dcSsevan 
121721a1f964Smrg static void
121821a1f964Smrg rge_tx_list_fini(struct rge_softc *sc)
121921a1f964Smrg {
122021a1f964Smrg 	unsigned i;
122121a1f964Smrg 
122221a1f964Smrg 	/* Free the TX list buffers. */
122321a1f964Smrg 	for (i = 0; i < RGE_TX_LIST_CNT; i++) {
122421a1f964Smrg 		if (sc->rge_ldata.rge_txq[i].txq_mbuf != NULL) {
122521a1f964Smrg 			bus_dmamap_unload(sc->sc_dmat,
122621a1f964Smrg 			    sc->rge_ldata.rge_txq[i].txq_dmamap);
122721a1f964Smrg 			m_freem(sc->rge_ldata.rge_txq[i].txq_mbuf);
122821a1f964Smrg 			sc->rge_ldata.rge_txq[i].txq_mbuf = NULL;
122921a1f964Smrg 		}
123021a1f964Smrg 	}
123121a1f964Smrg }
123221a1f964Smrg 
1233156bc3dcSsevan int
1234156bc3dcSsevan rge_rxeof(struct rge_softc *sc)
1235156bc3dcSsevan {
1236156bc3dcSsevan 	struct mbuf *m;
12377ff7ee85Ssevan 	struct ifnet *ifp = &sc->sc_ec.ec_if;
1238156bc3dcSsevan 	struct rge_rx_desc *cur_rx;
1239156bc3dcSsevan 	struct rge_rxq *rxq;
1240156bc3dcSsevan 	uint32_t rxstat, extsts;
1241156bc3dcSsevan 	int i, total_len, rx = 0;
1242156bc3dcSsevan 
1243e13c9dceSjakllsch 	for (i = sc->rge_ldata.rge_rxq_considx; ; i = RGE_NEXT_RX_DESC(i)) {
1244156bc3dcSsevan 		/* Invalidate the descriptor memory. */
1245156bc3dcSsevan 		bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_rx_list_map,
1246156bc3dcSsevan 		    i * sizeof(struct rge_rx_desc), sizeof(struct rge_rx_desc),
1247156bc3dcSsevan 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1248156bc3dcSsevan 
1249156bc3dcSsevan 		cur_rx = &sc->rge_ldata.rge_rx_list[i];
1250156bc3dcSsevan 
1251156bc3dcSsevan 		if (RGE_OWN(cur_rx))
1252156bc3dcSsevan 			break;
1253156bc3dcSsevan 
125437d52952Snonaka 		rxstat = letoh32(cur_rx->hi_qword1.rx_qword4.rge_cmdsts);
125537d52952Snonaka 		extsts = letoh32(cur_rx->hi_qword1.rx_qword4.rge_extsts);
1256156bc3dcSsevan 
1257156bc3dcSsevan 		total_len = RGE_RXBYTES(cur_rx);
1258156bc3dcSsevan 		rxq = &sc->rge_ldata.rge_rxq[i];
1259156bc3dcSsevan 		m = rxq->rxq_mbuf;
1260156bc3dcSsevan 		rx = 1;
1261156bc3dcSsevan 
1262022d5228Smrg 		/* Invalidate the RX mbuf. */
1263156bc3dcSsevan 		bus_dmamap_sync(sc->sc_dmat, rxq->rxq_dmamap, 0,
1264156bc3dcSsevan 		    rxq->rxq_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
1265156bc3dcSsevan 
1266156bc3dcSsevan 		if ((rxstat & (RGE_RDCMDSTS_SOF | RGE_RDCMDSTS_EOF)) !=
1267156bc3dcSsevan 		    (RGE_RDCMDSTS_SOF | RGE_RDCMDSTS_EOF)) {
1268022d5228Smrg 			if_statinc(ifp, if_ierrors);
1269022d5228Smrg 			rge_load_rxbuf(sc, i);
1270156bc3dcSsevan 			continue;
1271156bc3dcSsevan 		}
1272156bc3dcSsevan 
1273156bc3dcSsevan 		if (rxstat & RGE_RDCMDSTS_RXERRSUM) {
127411704b98Sskrll 			if_statinc(ifp, if_ierrors);
1275156bc3dcSsevan 			/*
1276156bc3dcSsevan 			 * If this is part of a multi-fragment packet,
1277156bc3dcSsevan 			 * discard all the pieces.
1278156bc3dcSsevan 			 */
1279156bc3dcSsevan 			if (sc->rge_head != NULL) {
1280156bc3dcSsevan 				m_freem(sc->rge_head);
1281156bc3dcSsevan 				sc->rge_head = sc->rge_tail = NULL;
1282156bc3dcSsevan 			}
1283022d5228Smrg 			rge_load_rxbuf(sc, i);
1284156bc3dcSsevan 			continue;
1285156bc3dcSsevan 		}
1286156bc3dcSsevan 
1287156bc3dcSsevan 		/*
1288156bc3dcSsevan 		 * If allocating a replacement mbuf fails,
1289156bc3dcSsevan 		 * reload the current one.
1290156bc3dcSsevan 		 */
129121a1f964Smrg 		if (rge_newbuf(sc, i) != 0) {
1292022d5228Smrg 			if_statinc(ifp, if_iqdrops);
1293156bc3dcSsevan 			if (sc->rge_head != NULL) {
1294156bc3dcSsevan 				m_freem(sc->rge_head);
1295156bc3dcSsevan 				sc->rge_head = sc->rge_tail = NULL;
1296156bc3dcSsevan 			}
1297022d5228Smrg 			rge_load_rxbuf(sc, i);
1298156bc3dcSsevan 			continue;
1299156bc3dcSsevan 		}
1300156bc3dcSsevan 
1301e13c9dceSjakllsch 		m_set_rcvif(m, ifp);
1302156bc3dcSsevan 		if (sc->rge_head != NULL) {
1303156bc3dcSsevan 			m->m_len = total_len;
1304156bc3dcSsevan 			/*
1305156bc3dcSsevan 			 * Special case: if there's 4 bytes or less
1306156bc3dcSsevan 			 * in this buffer, the mbuf can be discarded:
1307156bc3dcSsevan 			 * the last 4 bytes is the CRC, which we don't
1308156bc3dcSsevan 			 * care about anyway.
1309156bc3dcSsevan 			 */
1310156bc3dcSsevan 			if (m->m_len <= ETHER_CRC_LEN) {
1311156bc3dcSsevan 				sc->rge_tail->m_len -=
1312156bc3dcSsevan 				    (ETHER_CRC_LEN - m->m_len);
1313156bc3dcSsevan 				m_freem(m);
1314156bc3dcSsevan 			} else {
1315156bc3dcSsevan 				m->m_len -= ETHER_CRC_LEN;
1316156bc3dcSsevan 				m->m_flags &= ~M_PKTHDR;
1317156bc3dcSsevan 				sc->rge_tail->m_next = m;
1318156bc3dcSsevan 			}
1319156bc3dcSsevan 			m = sc->rge_head;
1320156bc3dcSsevan 			sc->rge_head = sc->rge_tail = NULL;
1321156bc3dcSsevan 			m->m_pkthdr.len = total_len - ETHER_CRC_LEN;
1322156bc3dcSsevan 		} else
1323e13c9dceSjakllsch 	#if 0
1324156bc3dcSsevan 			m->m_pkthdr.len = m->m_len =
1325156bc3dcSsevan 			    (total_len - ETHER_CRC_LEN);
1326e13c9dceSjakllsch 	#else
1327e13c9dceSjakllsch 		{
1328e13c9dceSjakllsch 			m->m_pkthdr.len = m->m_len = total_len;
1329e13c9dceSjakllsch 			m->m_flags |= M_HASFCS;
1330e13c9dceSjakllsch 		}
1331e13c9dceSjakllsch 	#endif
1332156bc3dcSsevan 
1333e13c9dceSjakllsch #if notyet
1334156bc3dcSsevan 		/* Check IP header checksum. */
133537d52952Snonaka 		if (!(extsts & RGE_RDEXTSTS_IPCSUMERR) &&
1336156bc3dcSsevan 		    (extsts & RGE_RDEXTSTS_IPV4))
1337156bc3dcSsevan 			m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
1338156bc3dcSsevan 
1339156bc3dcSsevan 		/* Check TCP/UDP checksum. */
1340156bc3dcSsevan 		if ((extsts & (RGE_RDEXTSTS_IPV4 | RGE_RDEXTSTS_IPV6)) &&
134137d52952Snonaka 		    (((extsts & RGE_RDEXTSTS_TCPPKT) &&
134237d52952Snonaka 		    !(extsts & RGE_RDEXTSTS_TCPCSUMERR)) ||
134337d52952Snonaka 		    ((extsts & RGE_RDEXTSTS_UDPPKT) &&
134437d52952Snonaka 		    !(extsts & RGE_RDEXTSTS_UDPCSUMERR))))
1345156bc3dcSsevan 			m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK |
1346156bc3dcSsevan 			    M_UDP_CSUM_IN_OK;
1347156bc3dcSsevan #endif
1348156bc3dcSsevan 
1349e13c9dceSjakllsch 		if (extsts & RGE_RDEXTSTS_VTAG) {
1350e13c9dceSjakllsch 			vlan_set_tag(m,
1351e13c9dceSjakllsch 			    bswap16(extsts & RGE_RDEXTSTS_VLAN_MASK));
1352156bc3dcSsevan 		}
1353156bc3dcSsevan 
1354e13c9dceSjakllsch 		if_percpuq_enqueue(ifp->if_percpuq, m);
1355e13c9dceSjakllsch 	}
1356156bc3dcSsevan 
1357e13c9dceSjakllsch 	sc->rge_ldata.rge_rxq_considx = i;
1358156bc3dcSsevan 
1359156bc3dcSsevan 	return (rx);
1360156bc3dcSsevan }
1361156bc3dcSsevan 
1362156bc3dcSsevan int
1363156bc3dcSsevan rge_txeof(struct rge_softc *sc)
1364156bc3dcSsevan {
13657ff7ee85Ssevan 	struct ifnet *ifp = &sc->sc_ec.ec_if;
1366156bc3dcSsevan 	struct rge_txq *txq;
1367156bc3dcSsevan 	uint32_t txstat;
1368156bc3dcSsevan 	int cons, idx, prod;
1369156bc3dcSsevan 	int free = 0;
1370156bc3dcSsevan 
1371156bc3dcSsevan 	prod = sc->rge_ldata.rge_txq_prodidx;
1372156bc3dcSsevan 	cons = sc->rge_ldata.rge_txq_considx;
1373156bc3dcSsevan 
1374156bc3dcSsevan 	while (prod != cons) {
1375156bc3dcSsevan 		txq = &sc->rge_ldata.rge_txq[cons];
1376156bc3dcSsevan 		idx = txq->txq_descidx;
1377156bc3dcSsevan 
1378156bc3dcSsevan 		bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map,
1379156bc3dcSsevan 		    idx * sizeof(struct rge_tx_desc),
1380156bc3dcSsevan 		    sizeof(struct rge_tx_desc),
1381156bc3dcSsevan 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1382156bc3dcSsevan 
1383156bc3dcSsevan 		txstat = letoh32(sc->rge_ldata.rge_tx_list[idx].rge_cmdsts);
1384156bc3dcSsevan 
1385156bc3dcSsevan 		if (txstat & RGE_TDCMDSTS_OWN) {
1386156bc3dcSsevan 			free = 2;
1387156bc3dcSsevan 			break;
1388156bc3dcSsevan 		}
1389156bc3dcSsevan 
1390156bc3dcSsevan 		bus_dmamap_sync(sc->sc_dmat, txq->txq_dmamap, 0,
1391156bc3dcSsevan 		    txq->txq_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1392156bc3dcSsevan 		bus_dmamap_unload(sc->sc_dmat, txq->txq_dmamap);
1393156bc3dcSsevan 		m_freem(txq->txq_mbuf);
1394156bc3dcSsevan 		txq->txq_mbuf = NULL;
1395156bc3dcSsevan 
13969a4c4a4cSmlelstv 		net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
1397156bc3dcSsevan 		if (txstat & (RGE_TDCMDSTS_EXCESSCOLL | RGE_TDCMDSTS_COLL))
1398be6f2fceSriastradh 			if_statinc_ref(ifp, nsr, if_collisions);
1399156bc3dcSsevan 		if (txstat & RGE_TDCMDSTS_TXERR)
1400be6f2fceSriastradh 			if_statinc_ref(ifp, nsr, if_oerrors);
14019a4c4a4cSmlelstv 		else
1402be6f2fceSriastradh 			if_statinc_ref(ifp, nsr, if_opackets);
14039a4c4a4cSmlelstv 		IF_STAT_PUTREF(ifp);
1404156bc3dcSsevan 
1405156bc3dcSsevan 		bus_dmamap_sync(sc->sc_dmat, sc->rge_ldata.rge_tx_list_map,
1406156bc3dcSsevan 		    idx * sizeof(struct rge_tx_desc),
1407156bc3dcSsevan 		    sizeof(struct rge_tx_desc),
1408156bc3dcSsevan 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1409156bc3dcSsevan 
1410156bc3dcSsevan 		cons = RGE_NEXT_TX_DESC(idx);
1411156bc3dcSsevan 		free = 1;
1412156bc3dcSsevan 	}
1413156bc3dcSsevan 
1414156bc3dcSsevan 	if (free == 0)
1415156bc3dcSsevan 		return (0);
1416156bc3dcSsevan 
1417156bc3dcSsevan 	sc->rge_ldata.rge_txq_considx = cons;
1418156bc3dcSsevan 
1419e13c9dceSjakllsch 	if (free == 2)
1420ccc8e576Sskrll 		rge_txstart(sc);
14219a4c4a4cSmlelstv 
14229a4c4a4cSmlelstv 	CLR(ifp->if_flags, IFF_OACTIVE);
1423e13c9dceSjakllsch 	ifp->if_timer = 0;
14249a4c4a4cSmlelstv 	if_schedule_deferred_start(ifp);
1425156bc3dcSsevan 
1426156bc3dcSsevan 	return (1);
1427156bc3dcSsevan }
1428156bc3dcSsevan 
1429156bc3dcSsevan void
1430156bc3dcSsevan rge_reset(struct rge_softc *sc)
1431156bc3dcSsevan {
1432156bc3dcSsevan 	int i;
1433156bc3dcSsevan 
1434156bc3dcSsevan 	/* Enable RXDV gate. */
1435156bc3dcSsevan 	RGE_SETBIT_1(sc, RGE_PPSW, 0x08);
1436156bc3dcSsevan 	DELAY(2000);
1437156bc3dcSsevan 
1438e13c9dceSjakllsch 	for (i = 0; i < 3000; i++) {
1439e13c9dceSjakllsch 		DELAY(50);
1440156bc3dcSsevan 		if ((RGE_READ_1(sc, RGE_MCUCMD) & (RGE_MCUCMD_RXFIFO_EMPTY |
1441156bc3dcSsevan 		    RGE_MCUCMD_TXFIFO_EMPTY)) == (RGE_MCUCMD_RXFIFO_EMPTY |
1442156bc3dcSsevan 		    RGE_MCUCMD_TXFIFO_EMPTY))
1443156bc3dcSsevan 			break;
1444156bc3dcSsevan 	}
1445e13c9dceSjakllsch 	if (sc->rge_type == MAC_CFG4 || sc->rge_type == MAC_CFG5) {
1446e13c9dceSjakllsch 		for (i = 0; i < 3000; i++) {
1447e13c9dceSjakllsch 			DELAY(50);
1448e13c9dceSjakllsch 			if ((RGE_READ_2(sc, RGE_IM) & 0x0103) == 0x0103)
1449e13c9dceSjakllsch 				break;
1450e13c9dceSjakllsch 		}
1451e13c9dceSjakllsch 	}
1452e13c9dceSjakllsch 
1453e13c9dceSjakllsch 	DELAY(2000);
1454156bc3dcSsevan 
1455156bc3dcSsevan 	/* Soft reset. */
1456156bc3dcSsevan 	RGE_WRITE_1(sc, RGE_CMD, RGE_CMD_RESET);
1457156bc3dcSsevan 
1458156bc3dcSsevan 	for (i = 0; i < RGE_TIMEOUT; i++) {
1459156bc3dcSsevan 		DELAY(100);
1460156bc3dcSsevan 		if (!(RGE_READ_1(sc, RGE_CMD) & RGE_CMD_RESET))
1461156bc3dcSsevan 			break;
1462156bc3dcSsevan 	}
1463156bc3dcSsevan 	if (i == RGE_TIMEOUT)
146419599902Sjakllsch 		device_printf(sc->sc_dev, "reset never completed!\n");
1465156bc3dcSsevan }
1466156bc3dcSsevan 
1467156bc3dcSsevan void
1468156bc3dcSsevan rge_iff(struct rge_softc *sc)
1469156bc3dcSsevan {
14707ff7ee85Ssevan 	struct ifnet *ifp = &sc->sc_ec.ec_if;
1471e13c9dceSjakllsch 	struct ethercom *ec = &sc->sc_ec;
1472156bc3dcSsevan 	struct ether_multi *enm;
1473156bc3dcSsevan 	struct ether_multistep step;
1474156bc3dcSsevan 	uint32_t hashes[2];
1475156bc3dcSsevan 	uint32_t rxfilt;
1476156bc3dcSsevan 	int h = 0;
1477156bc3dcSsevan 
1478156bc3dcSsevan 	rxfilt = RGE_READ_4(sc, RGE_RXCFG);
1479156bc3dcSsevan 	rxfilt &= ~(RGE_RXCFG_ALLPHYS | RGE_RXCFG_MULTI);
1480156bc3dcSsevan 	ifp->if_flags &= ~IFF_ALLMULTI;
1481156bc3dcSsevan 
1482156bc3dcSsevan 	/*
1483156bc3dcSsevan 	 * Always accept frames destined to our station address.
1484156bc3dcSsevan 	 * Always accept broadcast frames.
1485156bc3dcSsevan 	 */
1486156bc3dcSsevan 	rxfilt |= RGE_RXCFG_INDIV | RGE_RXCFG_BROAD;
1487156bc3dcSsevan 
1488e13c9dceSjakllsch 	if (ifp->if_flags & IFF_PROMISC) {
1489e13c9dceSjakllsch  allmulti:
1490156bc3dcSsevan 		ifp->if_flags |= IFF_ALLMULTI;
1491156bc3dcSsevan 		rxfilt |= RGE_RXCFG_MULTI;
1492156bc3dcSsevan 		if (ifp->if_flags & IFF_PROMISC)
1493156bc3dcSsevan 			rxfilt |= RGE_RXCFG_ALLPHYS;
1494156bc3dcSsevan 		hashes[0] = hashes[1] = 0xffffffff;
1495156bc3dcSsevan 	} else {
1496156bc3dcSsevan 		rxfilt |= RGE_RXCFG_MULTI;
1497156bc3dcSsevan 		/* Program new filter. */
1498156bc3dcSsevan 		memset(hashes, 0, sizeof(hashes));
1499156bc3dcSsevan 
1500e13c9dceSjakllsch 		ETHER_LOCK(ec);
1501e13c9dceSjakllsch 		ETHER_FIRST_MULTI(step, ec, enm);
1502156bc3dcSsevan 		while (enm != NULL) {
1503e13c9dceSjakllsch 			if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
1504e13c9dceSjakllsch 			    ETHER_ADDR_LEN) != 0) {
1505e13c9dceSjakllsch 			    	ETHER_UNLOCK(ec);
1506e13c9dceSjakllsch 				goto allmulti;
1507e13c9dceSjakllsch 			}
1508156bc3dcSsevan 			h = ether_crc32_be(enm->enm_addrlo,
1509156bc3dcSsevan 			    ETHER_ADDR_LEN) >> 26;
1510156bc3dcSsevan 
1511156bc3dcSsevan 			if (h < 32)
15121c3b521aSmsaitoh 				hashes[0] |= (1U << h);
1513156bc3dcSsevan 			else
15141c3b521aSmsaitoh 				hashes[1] |= (1U << (h - 32));
1515156bc3dcSsevan 
1516156bc3dcSsevan 			ETHER_NEXT_MULTI(step, enm);
1517156bc3dcSsevan 		}
1518e13c9dceSjakllsch 		ETHER_UNLOCK(ec);
1519156bc3dcSsevan 	}
1520156bc3dcSsevan 
1521156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_RXCFG, rxfilt);
15227ff7ee85Ssevan 	RGE_WRITE_4(sc, RGE_MAR0, bswap32(hashes[1]));
15237ff7ee85Ssevan 	RGE_WRITE_4(sc, RGE_MAR4, bswap32(hashes[0]));
1524156bc3dcSsevan }
1525156bc3dcSsevan 
1526156bc3dcSsevan void
1527156bc3dcSsevan rge_set_phy_power(struct rge_softc *sc, int on)
1528156bc3dcSsevan {
1529156bc3dcSsevan 	int i;
1530156bc3dcSsevan 
1531156bc3dcSsevan 	if (on) {
1532156bc3dcSsevan 		RGE_SETBIT_1(sc, RGE_PMCH, 0xc0);
1533156bc3dcSsevan 
1534156bc3dcSsevan 		rge_write_phy(sc, 0, MII_BMCR, BMCR_AUTOEN);
1535156bc3dcSsevan 
1536156bc3dcSsevan 		for (i = 0; i < RGE_TIMEOUT; i++) {
15374a23f239Ssevan 			if ((rge_read_phy_ocp(sc, 0xa420) & 0x0007) == 3)
1538156bc3dcSsevan 				break;
1539156bc3dcSsevan 			DELAY(1000);
1540156bc3dcSsevan 		}
1541e13c9dceSjakllsch 	} else {
1542156bc3dcSsevan 		rge_write_phy(sc, 0, MII_BMCR, BMCR_AUTOEN | BMCR_PDOWN);
1543e13c9dceSjakllsch 		RGE_CLRBIT_1(sc, RGE_PMCH, 0x80);
1544e13c9dceSjakllsch 		RGE_CLRBIT_1(sc, RGE_PPSW, 0x40);
1545e13c9dceSjakllsch 	}
1546156bc3dcSsevan }
1547156bc3dcSsevan 
1548156bc3dcSsevan void
1549156bc3dcSsevan rge_phy_config(struct rge_softc *sc)
1550156bc3dcSsevan {
1551156bc3dcSsevan 	/* Read microcode version. */
1552156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x801e);
1553e13c9dceSjakllsch 	sc->rge_mcodever = rge_read_phy_ocp(sc, 0xa438);
1554156bc3dcSsevan 
1555e13c9dceSjakllsch 	switch (sc->rge_type) {
1556e13c9dceSjakllsch 	case MAC_CFG2:
1557e13c9dceSjakllsch 		rge_phy_config_mac_cfg2(sc);
1558e13c9dceSjakllsch 		break;
1559e13c9dceSjakllsch 	case MAC_CFG3:
1560e13c9dceSjakllsch 		rge_phy_config_mac_cfg3(sc);
1561e13c9dceSjakllsch 		break;
1562e13c9dceSjakllsch 	case MAC_CFG4:
1563e13c9dceSjakllsch 		rge_phy_config_mac_cfg4(sc);
1564e13c9dceSjakllsch 		break;
1565e13c9dceSjakllsch 	case MAC_CFG5:
1566e13c9dceSjakllsch 		rge_phy_config_mac_cfg5(sc);
1567e13c9dceSjakllsch 		break;
1568e13c9dceSjakllsch 	default:
1569e13c9dceSjakllsch 		break;	/* Can't happen. */
1570156bc3dcSsevan 	}
1571156bc3dcSsevan 
1572e13c9dceSjakllsch 	rge_write_phy(sc, 0x0a5b, 0x12,
1573e13c9dceSjakllsch 	    rge_read_phy(sc, 0x0a5b, 0x12) & ~0x8000);
1574e13c9dceSjakllsch 
1575e13c9dceSjakllsch 	/* Disable EEE. */
1576e13c9dceSjakllsch 	RGE_MAC_CLRBIT(sc, 0xe040, 0x0003);
1577e13c9dceSjakllsch 	if (sc->rge_type == MAC_CFG2 || sc->rge_type == MAC_CFG3) {
1578e13c9dceSjakllsch 		RGE_MAC_CLRBIT(sc, 0xeb62, 0x0006);
1579e13c9dceSjakllsch 		RGE_PHY_CLRBIT(sc, 0xa432, 0x0010);
1580e13c9dceSjakllsch 	}
1581e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xa5d0, 0x0006);
1582e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xa6d4, 0x0001);
1583e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xa6d8, 0x0010);
1584e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xa428, 0x0080);
1585e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xa4a2, 0x0200);
1586156bc3dcSsevan 
1587156bc3dcSsevan 	rge_patch_phy_mcu(sc, 1);
1588e13c9dceSjakllsch 	RGE_MAC_CLRBIT(sc, 0xe052, 0x0001);
1589e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xa442, 0x3000);
1590e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xa430, 0x8000);
1591156bc3dcSsevan 	rge_patch_phy_mcu(sc, 0);
1592156bc3dcSsevan }
1593156bc3dcSsevan 
1594e13c9dceSjakllsch void
1595e13c9dceSjakllsch rge_phy_config_mac_cfg2(struct rge_softc *sc)
1596e13c9dceSjakllsch {
1597e13c9dceSjakllsch 	uint16_t val;
1598e13c9dceSjakllsch 	int i;
1599e13c9dceSjakllsch 
1600e13c9dceSjakllsch 	for (i = 0; i < nitems(rtl8125_mac_cfg2_ephy); i++)
1601e13c9dceSjakllsch 		rge_write_ephy(sc, rtl8125_mac_cfg2_ephy[i].reg,
1602e13c9dceSjakllsch 		    rtl8125_mac_cfg2_ephy[i].val);
1603e13c9dceSjakllsch 
1604e13c9dceSjakllsch 	rge_phy_config_mcu(sc, RGE_MAC_CFG2_MCODE_VER);
1605e13c9dceSjakllsch 
1606156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xad40) & ~0x03ff;
1607156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xad40, val | 0x0084);
1608156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xad4e, 0x0010);
1609156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xad16) & ~0x03ff;
1610156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xad16, val | 0x0006);
1611156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xad32) & ~0x03ff;
1612156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xad32, val | 0x0006);
1613156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xac08, 0x1100);
1614156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xac8a) & ~0xf000;
1615156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xac8a, val | 0x7000);
1616156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xad18, 0x0400);
1617156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xad1a, 0x03ff);
1618156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xad1c, 0x03ff);
1619156bc3dcSsevan 
1620156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x80ea);
1621156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1622156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, val | 0xc400);
1623156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x80eb);
1624156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa438) & ~0x0700;
1625156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, val | 0x0300);
1626156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x80f8);
1627156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1628156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, val | 0x1c00);
1629156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x80f1);
1630156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1631156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, val | 0x3000);
1632156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x80fe);
1633156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1634156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, val | 0xa500);
1635156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x8102);
1636156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1637156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, val | 0x5000);
1638156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x8105);
1639156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1640156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, val | 0x3300);
1641156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x8100);
1642156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1643156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, val | 0x7000);
1644156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x8104);
1645156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1646156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, val | 0xf000);
1647156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x8106);
1648156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1649156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, val | 0x6500);
1650156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x80dc);
1651156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1652156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, val | 0xed00);
1653156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x80df);
1654156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xa438, 0x0100);
1655156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x80e1);
1656156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xa438, 0x0100);
1657156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xbf06) & ~0x003f;
1658156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xbf06, val | 0x0038);
1659156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x819f);
1660156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, 0xd0b6);
1661156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xbc34, 0x5555);
1662156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xbf0a) & ~0x0e00;
1663156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xbf0a, val | 0x0a00);
1664156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xa5c0, 0x0400);
1665156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xa442, 0x0800);
1666e13c9dceSjakllsch }
1667e13c9dceSjakllsch 
1668e13c9dceSjakllsch void
1669e13c9dceSjakllsch rge_phy_config_mac_cfg3(struct rge_softc *sc)
1670e13c9dceSjakllsch {
1671e13c9dceSjakllsch 	struct ifnet *ifp = &sc->sc_ec.ec_if;
1672e13c9dceSjakllsch 	uint16_t val;
1673e13c9dceSjakllsch 	int i;
1674e13c9dceSjakllsch 	static const uint16_t mac_cfg3_a438_value[] =
1675e13c9dceSjakllsch 	    { 0x0043, 0x00a7, 0x00d6, 0x00ec, 0x00f6, 0x00fb, 0x00fd, 0x00ff,
1676e13c9dceSjakllsch 	      0x00bb, 0x0058, 0x0029, 0x0013, 0x0009, 0x0004, 0x0002 };
1677e13c9dceSjakllsch 
1678e13c9dceSjakllsch 	static const uint16_t mac_cfg3_b88e_value[] =
1679e13c9dceSjakllsch 	    { 0xc091, 0x6e12, 0xc092, 0x1214, 0xc094, 0x1516, 0xc096, 0x171b,
1680e13c9dceSjakllsch 	      0xc098, 0x1b1c, 0xc09a, 0x1f1f, 0xc09c, 0x2021, 0xc09e, 0x2224,
1681e13c9dceSjakllsch 	      0xc0a0, 0x2424, 0xc0a2, 0x2424, 0xc0a4, 0x2424, 0xc018, 0x0af2,
1682e13c9dceSjakllsch 	      0xc01a, 0x0d4a, 0xc01c, 0x0f26, 0xc01e, 0x118d, 0xc020, 0x14f3,
1683e13c9dceSjakllsch 	      0xc022, 0x175a, 0xc024, 0x19c0, 0xc026, 0x1c26, 0xc089, 0x6050,
1684e13c9dceSjakllsch 	      0xc08a, 0x5f6e, 0xc08c, 0x6e6e, 0xc08e, 0x6e6e, 0xc090, 0x6e12 };
1685e13c9dceSjakllsch 
1686156bc3dcSsevan 	for (i = 0; i < nitems(rtl8125_mac_cfg3_ephy); i++)
1687156bc3dcSsevan 		rge_write_ephy(sc, rtl8125_mac_cfg3_ephy[i].reg,
1688156bc3dcSsevan 		    rtl8125_mac_cfg3_ephy[i].val);
1689156bc3dcSsevan 
1690e13c9dceSjakllsch 	val = rge_read_ephy(sc, 0x002a) & ~0x7000;
1691e13c9dceSjakllsch 	rge_write_ephy(sc, 0x002a, val | 0x3000);
1692e13c9dceSjakllsch 	RGE_EPHY_CLRBIT(sc, 0x0019, 0x0040);
1693e13c9dceSjakllsch 	RGE_EPHY_SETBIT(sc, 0x001b, 0x0e00);
1694e13c9dceSjakllsch 	RGE_EPHY_CLRBIT(sc, 0x001b, 0x7000);
1695e13c9dceSjakllsch 	rge_write_ephy(sc, 0x0002, 0x6042);
1696e13c9dceSjakllsch 	rge_write_ephy(sc, 0x0006, 0x0014);
1697e13c9dceSjakllsch 	val = rge_read_ephy(sc, 0x006a) & ~0x7000;
1698e13c9dceSjakllsch 	rge_write_ephy(sc, 0x006a, val | 0x3000);
1699e13c9dceSjakllsch 	RGE_EPHY_CLRBIT(sc, 0x0059, 0x0040);
1700e13c9dceSjakllsch 	RGE_EPHY_SETBIT(sc, 0x005b, 0x0e00);
1701e13c9dceSjakllsch 	RGE_EPHY_CLRBIT(sc, 0x005b, 0x7000);
1702e13c9dceSjakllsch 	rge_write_ephy(sc, 0x0042, 0x6042);
1703e13c9dceSjakllsch 	rge_write_ephy(sc, 0x0046, 0x0014);
1704156bc3dcSsevan 
1705e13c9dceSjakllsch 	rge_phy_config_mcu(sc, RGE_MAC_CFG3_MCODE_VER);
1706156bc3dcSsevan 
1707156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xad4e, 0x0010);
1708156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xad16) & ~0x03ff;
1709156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xad16, val | 0x03ff);
1710156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xad32) & ~0x003f;
1711156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xad32, val | 0x0006);
1712156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xac08, 0x1000);
1713156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xac08, 0x0100);
1714156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xacc0) & ~0x0003;
1715156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xacc0, val | 0x0002);
1716156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xad40) & ~0x00e0;
1717156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xad40, val | 0x0040);
1718156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xad40) & ~0x0007;
1719156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xad40, val | 0x0004);
1720156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xac14, 0x0080);
1721156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xac80, 0x0300);
1722156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xac5e) & ~0x0007;
1723156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xac5e, val | 0x0002);
1724156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xad4c, 0x00a8);
1725156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xac5c, 0x01ff);
1726156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xac8a) & ~0x00f0;
1727156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xac8a, val | 0x0030);
1728e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x8157);
1729e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00;
1730e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, val | 0x0500);
1731e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x8159);
1732e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00;
1733e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, val | 0x0700);
1734e13c9dceSjakllsch 	RGE_WRITE_2(sc, RGE_EEE_TXIDLE_TIMER, ifp->if_mtu + ETHER_HDR_LEN +
1735e13c9dceSjakllsch 	    32);
1736156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xb87c, 0x80a2);
1737156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xb87e, 0x0153);
1738156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xb87c, 0x809c);
1739156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xb87e, 0x0153);
1740156bc3dcSsevan 
1741156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x81b3);
1742156bc3dcSsevan 	for (i = 0; i < nitems(mac_cfg3_a438_value); i++)
1743156bc3dcSsevan 		rge_write_phy_ocp(sc, 0xa438, mac_cfg3_a438_value[i]);
1744156bc3dcSsevan 	for (i = 0; i < 26; i++)
1745156bc3dcSsevan 		rge_write_phy_ocp(sc, 0xa438, 0);
1746156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x8257);
1747156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, 0x020f);
1748156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x80ea);
1749156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa438, 0x7843);
1750156bc3dcSsevan 
1751156bc3dcSsevan 	rge_patch_phy_mcu(sc, 1);
1752156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xb896, 0x0001);
1753156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xb892, 0xff00);
1754156bc3dcSsevan 	for (i = 0; i < nitems(mac_cfg3_b88e_value); i += 2) {
1755156bc3dcSsevan 		rge_write_phy_ocp(sc, 0xb88e, mac_cfg3_b88e_value[i]);
1756e13c9dceSjakllsch 		rge_write_phy_ocp(sc, 0xb890, mac_cfg3_b88e_value[i + 1]);
1757156bc3dcSsevan 	}
1758156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xb896, 0x0001);
1759156bc3dcSsevan 	rge_patch_phy_mcu(sc, 0);
1760156bc3dcSsevan 
1761156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xd068, 0x2000);
1762156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xa436, 0x81a2);
1763156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xa438, 0x0100);
1764156bc3dcSsevan 	val = rge_read_phy_ocp(sc, 0xb54c) & ~0xff00;
1765156bc3dcSsevan 	rge_write_phy_ocp(sc, 0xb54c, val | 0xdb00);
1766156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xa454, 0x0001);
1767156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xa5d4, 0x0020);
1768156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xad4e, 0x0010);
1769156bc3dcSsevan 	RGE_PHY_CLRBIT(sc, 0xa86a, 0x0001);
1770156bc3dcSsevan 	RGE_PHY_SETBIT(sc, 0xa442, 0x0800);
1771156bc3dcSsevan }
1772156bc3dcSsevan 
1773e13c9dceSjakllsch void
1774e13c9dceSjakllsch rge_phy_config_mac_cfg4(struct rge_softc *sc)
1775e13c9dceSjakllsch {
1776e13c9dceSjakllsch 	struct ifnet *ifp = &sc->sc_ec.ec_if;
1777e13c9dceSjakllsch 	uint16_t val;
1778e13c9dceSjakllsch 	int i;
1779e13c9dceSjakllsch 	static const uint16_t mac_cfg4_b87c_value[] =
1780e13c9dceSjakllsch 	    { 0x8013, 0x0700, 0x8fb9, 0x2801, 0x8fba, 0x0100, 0x8fbc, 0x1900,
1781e13c9dceSjakllsch 	      0x8fbe, 0xe100, 0x8fc0, 0x0800, 0x8fc2, 0xe500, 0x8fc4, 0x0f00,
1782e13c9dceSjakllsch 	      0x8fc6, 0xf100, 0x8fc8, 0x0400, 0x8fca, 0xf300, 0x8fcc, 0xfd00,
1783e13c9dceSjakllsch 	      0x8fce, 0xff00, 0x8fd0, 0xfb00, 0x8fd2, 0x0100, 0x8fd4, 0xf400,
1784e13c9dceSjakllsch 	      0x8fd6, 0xff00, 0x8fd8, 0xf600, 0x813d, 0x390e, 0x814f, 0x790e,
1785e13c9dceSjakllsch 	      0x80b0, 0x0f31 };
1786e13c9dceSjakllsch 
1787e13c9dceSjakllsch 	for (i = 0; i < nitems(rtl8125_mac_cfg4_ephy); i++)
1788e13c9dceSjakllsch 		rge_write_ephy(sc, rtl8125_mac_cfg4_ephy[i].reg,
1789e13c9dceSjakllsch 		    rtl8125_mac_cfg4_ephy[i].val);
1790e13c9dceSjakllsch 
1791e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbf86, 0x9000);
1792e13c9dceSjakllsch 	RGE_PHY_SETBIT(sc, 0xc402, 0x0400);
1793e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xc402, 0x0400);
1794e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbd86, 0x1010);
1795e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbd88, 0x1010);
1796e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xbd4e) & ~0x0c00;
1797e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbd4e, val | 0x0800);
1798e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xbf46) & ~0x0f00;
1799e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbf46, val | 0x0700);
1800e13c9dceSjakllsch 
1801e13c9dceSjakllsch 	rge_phy_config_mcu(sc, RGE_MAC_CFG4_MCODE_VER);
1802e13c9dceSjakllsch 
1803e13c9dceSjakllsch 	RGE_PHY_SETBIT(sc, 0xa442, 0x0800);
1804e13c9dceSjakllsch 	RGE_PHY_SETBIT(sc, 0xbc08, 0x000c);
1805e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x8fff);
1806e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1807e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, val | 0x0400);
1808e13c9dceSjakllsch 	for (i = 0; i < 6; i++) {
1809e13c9dceSjakllsch 		rge_write_phy_ocp(sc, 0xb87c, 0x8560 + i * 2);
1810e13c9dceSjakllsch 		if (i < 3)
1811e13c9dceSjakllsch 			rge_write_phy_ocp(sc, 0xb87e, 0x19cc);
1812e13c9dceSjakllsch 		else
1813e13c9dceSjakllsch 			rge_write_phy_ocp(sc, 0xb87e, 0x147d);
1814e13c9dceSjakllsch 	}
1815e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x8ffe);
1816e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x0907);
1817e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xacda) & ~0xff00;
1818e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xacda, val | 0xff00);
1819e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xacde) & ~0xf000;
1820e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xacde, val | 0xf000);
1821e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x80d6);
1822e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x2801);
1823e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x80F2);
1824e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x2801);
1825e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x80f4);
1826e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x6077);
1827e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb506, 0x01e7);
1828e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xac8c, 0x0ffc);
1829e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xac46, 0xb7b4);
1830e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xac50, 0x0fbc);
1831e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xac3c, 0x9240);
1832e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xac4E, 0x0db4);
1833e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xacc6, 0x0707);
1834e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xacc8, 0xa0d3);
1835e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xad08, 0x0007);
1836e13c9dceSjakllsch 	for (i = 0; i < nitems(mac_cfg4_b87c_value); i += 2) {
1837e13c9dceSjakllsch 		rge_write_phy_ocp(sc, 0xb87c, mac_cfg4_b87c_value[i]);
1838e13c9dceSjakllsch 		rge_write_phy_ocp(sc, 0xb87e, mac_cfg4_b87c_value[i + 1]);
1839e13c9dceSjakllsch 	}
1840e13c9dceSjakllsch 	RGE_PHY_SETBIT(sc, 0xbf4c, 0x0002);
1841e13c9dceSjakllsch 	RGE_PHY_SETBIT(sc, 0xbcca, 0x0300);
1842e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x8141);
1843e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x320e);
1844e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x8153);
1845e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x720e);
1846e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xa432, 0x0040);
1847e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x8529);
1848e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x050e);
1849e13c9dceSjakllsch 	RGE_WRITE_2(sc, RGE_EEE_TXIDLE_TIMER, ifp->if_mtu + ETHER_HDR_LEN +
1850e13c9dceSjakllsch 	    32);
1851e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x816c);
1852e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0xc4a0);
1853e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x8170);
1854e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0xc4a0);
1855e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x8174);
1856e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x04a0);
1857e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x8178);
1858e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x04a0);
1859e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x817c);
1860e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x0719);
1861e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x8ff4);
1862e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x0400);
1863e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x8ff1);
1864e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x0404);
1865e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbf4a, 0x001b);
1866e13c9dceSjakllsch 	for (i = 0; i < 6; i++) {
1867e13c9dceSjakllsch 		rge_write_phy_ocp(sc, 0xb87c, 0x8033 + i * 4);
1868e13c9dceSjakllsch 		if (i == 2)
1869e13c9dceSjakllsch 			rge_write_phy_ocp(sc, 0xb87e, 0xfc32);
1870e13c9dceSjakllsch 		else
1871e13c9dceSjakllsch 			rge_write_phy_ocp(sc, 0xb87e, 0x7c13);
1872e13c9dceSjakllsch 	}
1873e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x8145);
1874e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x370e);
1875e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x8157);
1876e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x770e);
1877e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x8169);
1878e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x0d0a);
1879e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x817b);
1880e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x1d0a);
1881e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x8217);
1882e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1883e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, val | 0x5000);
1884e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x821a);
1885e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1886e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, val | 0x5000);
1887e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80da);
1888e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x0403);
1889e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80dc);
1890e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1891e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, val | 0x1000);
1892e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80b3);
1893e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x0384);
1894e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80b7);
1895e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x2007);
1896e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80ba);
1897e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1898e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, val | 0x6c00);
1899e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80b5);
1900e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0xf009);
1901e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80bd);
1902e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1903e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, val | 0x9f00);
1904e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80c7);
1905e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0xf083);
1906e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80dd);
1907e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x03f0);
1908e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80df);
1909e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1910e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, val | 0x1000);
1911e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80cb);
1912e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x2007);
1913e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80ce);
1914e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1915e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, val | 0x6c00);
1916e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80c9);
1917e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x8009);
1918e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80d1);
1919e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1920e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, val | 0x8000);
1921e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80a3);
1922e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x200a);
1923e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80a5);
1924e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0xf0ad);
1925e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x809f);
1926e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x6073);
1927e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80a1);
1928e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, 0x000b);
1929e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x80a9);
1930e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00;
1931e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa438, val | 0xc000);
1932e13c9dceSjakllsch 	rge_patch_phy_mcu(sc, 1);
1933e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xb896, 0x0001);
1934e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xb892, 0xff00);
1935e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb88e, 0xc23e);
1936e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb890, 0x0000);
1937e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb88e, 0xc240);
1938e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb890, 0x0103);
1939e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb88e, 0xc242);
1940e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb890, 0x0507);
1941e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb88e, 0xc244);
1942e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb890, 0x090b);
1943e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb88e, 0xc246);
1944e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb890, 0x0c0e);
1945e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb88e, 0xc248);
1946e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb890, 0x1012);
1947e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb88e, 0xc24a);
1948e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb890, 0x1416);
1949e13c9dceSjakllsch 	RGE_PHY_SETBIT(sc, 0xb896, 0x0001);
1950e13c9dceSjakllsch 	rge_patch_phy_mcu(sc, 0);
1951e13c9dceSjakllsch 	RGE_PHY_SETBIT(sc, 0xa86a, 0x0001);
1952e13c9dceSjakllsch 	RGE_PHY_SETBIT(sc, 0xa6f0, 0x0001);
1953e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbfa0, 0xd70d);
1954e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbfa2, 0x4100);
1955e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbfa4, 0xe868);
1956e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbfa6, 0xdc59);
1957e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb54c, 0x3c18);
1958e13c9dceSjakllsch 	RGE_PHY_CLRBIT(sc, 0xbfa4, 0x0020);
1959e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xa436, 0x817d);
1960e13c9dceSjakllsch 	RGE_PHY_SETBIT(sc, 0xa438, 0x1000);
1961e13c9dceSjakllsch }
1962e13c9dceSjakllsch 
1963e13c9dceSjakllsch void
1964e13c9dceSjakllsch rge_phy_config_mac_cfg5(struct rge_softc *sc)
1965e13c9dceSjakllsch {
1966e13c9dceSjakllsch 	struct ifnet *ifp = &sc->sc_ec.ec_if;
1967e13c9dceSjakllsch 	uint16_t val;
1968e13c9dceSjakllsch 	int i;
1969e13c9dceSjakllsch 
1970e13c9dceSjakllsch 	for (i = 0; i < nitems(rtl8125_mac_cfg5_ephy); i++)
1971e13c9dceSjakllsch 		rge_write_ephy(sc, rtl8125_mac_cfg5_ephy[i].reg,
1972e13c9dceSjakllsch 		    rtl8125_mac_cfg5_ephy[i].val);
1973e13c9dceSjakllsch 
1974e13c9dceSjakllsch 	val = rge_read_ephy(sc, 0x0022) & ~0x0030;
1975e13c9dceSjakllsch 	rge_write_ephy(sc, 0x0022, val | 0x0020);
1976e13c9dceSjakllsch 	val = rge_read_ephy(sc, 0x0062) & ~0x0030;
1977e13c9dceSjakllsch 	rge_write_ephy(sc, 0x0062, val | 0x0020);
1978e13c9dceSjakllsch 
1979e13c9dceSjakllsch 	rge_phy_config_mcu(sc, RGE_MAC_CFG5_MCODE_VER);
1980e13c9dceSjakllsch 
1981e13c9dceSjakllsch 	RGE_PHY_SETBIT(sc, 0xa442, 0x0800);
1982e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xac46) & ~0x00f0;
1983e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xac46, val | 0x0090);
1984e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xad30) & ~0x0003;
1985e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xad30, val | 0x0001);
1986e13c9dceSjakllsch 	RGE_WRITE_2(sc, RGE_EEE_TXIDLE_TIMER, ifp->if_mtu + ETHER_HDR_LEN +
1987e13c9dceSjakllsch 	    32);
1988e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x80f5);
1989e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x760e);
1990e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x8107);
1991e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, 0x360e);
1992e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87c, 0x8551);
1993e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00;
1994e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xb87e, val | 0x0800);
1995e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xbf00) & ~0xe000;
1996e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbf00, val | 0xa000);
1997e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xbf46) & ~0x0f00;
1998e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbf46, val | 0x0300);
1999e13c9dceSjakllsch 	for (i = 0; i < 10; i++) {
2000e13c9dceSjakllsch 		rge_write_phy_ocp(sc, 0xa436, 0x8044 + i * 6);
2001e13c9dceSjakllsch 		rge_write_phy_ocp(sc, 0xa438, 0x2417);
2002e13c9dceSjakllsch 	}
2003e13c9dceSjakllsch 	RGE_PHY_SETBIT(sc, 0xa4ca, 0x0040);
2004e13c9dceSjakllsch 	val = rge_read_phy_ocp(sc, 0xbf84) & ~0xe000;
2005e13c9dceSjakllsch 	rge_write_phy_ocp(sc, 0xbf84, val | 0xa000);
2006e13c9dceSjakllsch }
2007e13c9dceSjakllsch 
2008e13c9dceSjakllsch void
2009e13c9dceSjakllsch rge_phy_config_mcu(struct rge_softc *sc, uint16_t mcode_version)
2010e13c9dceSjakllsch {
2011e13c9dceSjakllsch 	if (sc->rge_mcodever != mcode_version) {
2012e13c9dceSjakllsch 		int i;
2013156bc3dcSsevan 
2014156bc3dcSsevan 		rge_patch_phy_mcu(sc, 1);
2015e13c9dceSjakllsch 
2016e13c9dceSjakllsch 		if (sc->rge_type == MAC_CFG2 || sc->rge_type == MAC_CFG3) {
2017e13c9dceSjakllsch 			rge_write_phy_ocp(sc, 0xa436, 0x8024);
2018e13c9dceSjakllsch 			if (sc->rge_type == MAC_CFG2)
2019e13c9dceSjakllsch 				rge_write_phy_ocp(sc, 0xa438, 0x8600);
2020e13c9dceSjakllsch 			else
2021e13c9dceSjakllsch 				rge_write_phy_ocp(sc, 0xa438, 0x8601);
2022e13c9dceSjakllsch 			rge_write_phy_ocp(sc, 0xa436, 0xb82e);
2023e13c9dceSjakllsch 			rge_write_phy_ocp(sc, 0xa438, 0x0001);
2024e13c9dceSjakllsch 
2025e13c9dceSjakllsch 			RGE_PHY_SETBIT(sc, 0xb820, 0x0080);
2026e13c9dceSjakllsch 		}
2027e13c9dceSjakllsch 
2028e13c9dceSjakllsch 		if (sc->rge_type == MAC_CFG2) {
2029e13c9dceSjakllsch 			for (i = 0; i < nitems(rtl8125_mac_cfg2_mcu); i++) {
2030e13c9dceSjakllsch 				rge_write_phy_ocp(sc,
2031e13c9dceSjakllsch 				    rtl8125_mac_cfg2_mcu[i].reg,
2032e13c9dceSjakllsch 				    rtl8125_mac_cfg2_mcu[i].val);
2033e13c9dceSjakllsch 			}
2034e13c9dceSjakllsch 		} else if (sc->rge_type == MAC_CFG3) {
2035e13c9dceSjakllsch 			for (i = 0; i < nitems(rtl8125_mac_cfg3_mcu); i++) {
2036e13c9dceSjakllsch 				rge_write_phy_ocp(sc,
2037e13c9dceSjakllsch 				    rtl8125_mac_cfg3_mcu[i].reg,
2038e13c9dceSjakllsch 				    rtl8125_mac_cfg3_mcu[i].val);
2039e13c9dceSjakllsch 			}
2040e13c9dceSjakllsch 		} else if (sc->rge_type == MAC_CFG4) {
2041e13c9dceSjakllsch 			for (i = 0; i < nitems(rtl8125_mac_cfg4_mcu); i++) {
2042e13c9dceSjakllsch 				rge_write_phy_ocp(sc,
2043e13c9dceSjakllsch 				    rtl8125_mac_cfg4_mcu[i].reg,
2044e13c9dceSjakllsch 				    rtl8125_mac_cfg4_mcu[i].val);
2045e13c9dceSjakllsch 			}
2046e13c9dceSjakllsch 		} else if (sc->rge_type == MAC_CFG5) {
2047e13c9dceSjakllsch 			for (i = 0; i < nitems(rtl8125_mac_cfg5_mcu); i++) {
2048e13c9dceSjakllsch 				rge_write_phy_ocp(sc,
2049e13c9dceSjakllsch 				    rtl8125_mac_cfg5_mcu[i].reg,
2050e13c9dceSjakllsch 				    rtl8125_mac_cfg5_mcu[i].val);
2051e13c9dceSjakllsch 			}
2052e13c9dceSjakllsch 		}
2053e13c9dceSjakllsch 
2054e13c9dceSjakllsch 		if (sc->rge_type == MAC_CFG2 || sc->rge_type == MAC_CFG3) {
2055e13c9dceSjakllsch 			RGE_PHY_CLRBIT(sc, 0xb820, 0x0080);
2056e13c9dceSjakllsch 
2057e13c9dceSjakllsch 			rge_write_phy_ocp(sc, 0xa436, 0);
2058e13c9dceSjakllsch 			rge_write_phy_ocp(sc, 0xa438, 0);
2059e13c9dceSjakllsch 			RGE_PHY_CLRBIT(sc, 0xb82e, 0x0001);
2060e13c9dceSjakllsch 			rge_write_phy_ocp(sc, 0xa436, 0x8024);
2061e13c9dceSjakllsch 			rge_write_phy_ocp(sc, 0xa438, 0);
2062e13c9dceSjakllsch 		}
2063e13c9dceSjakllsch 
2064156bc3dcSsevan 		rge_patch_phy_mcu(sc, 0);
2065e13c9dceSjakllsch 
2066e13c9dceSjakllsch 		/* Write microcode version. */
2067e13c9dceSjakllsch 		rge_write_phy_ocp(sc, 0xa436, 0x801e);
2068e13c9dceSjakllsch 		rge_write_phy_ocp(sc, 0xa438, mcode_version);
2069e13c9dceSjakllsch 	}
2070156bc3dcSsevan }
2071156bc3dcSsevan 
2072156bc3dcSsevan void
2073156bc3dcSsevan rge_set_macaddr(struct rge_softc *sc, const uint8_t *addr)
2074156bc3dcSsevan {
2075156bc3dcSsevan 	RGE_SETBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
2076156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_MAC0,
20771c3b521aSmsaitoh 	    (uint32_t)addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]);
2078156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_MAC4,
2079156bc3dcSsevan 	    addr[5] <<  8 | addr[4]);
2080156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
2081156bc3dcSsevan }
2082156bc3dcSsevan 
2083156bc3dcSsevan void
2084156bc3dcSsevan rge_get_macaddr(struct rge_softc *sc, uint8_t *addr)
2085156bc3dcSsevan {
208683c2dfd4Smsaitoh 	int i;
208783c2dfd4Smsaitoh 
208883c2dfd4Smsaitoh 	for (i = 0; i < ETHER_ADDR_LEN; i++)
208983c2dfd4Smsaitoh 		addr[i] = RGE_READ_1(sc, RGE_ADDR0 + i);
2090156bc3dcSsevan }
2091156bc3dcSsevan 
2092156bc3dcSsevan void
2093156bc3dcSsevan rge_hw_init(struct rge_softc *sc)
2094156bc3dcSsevan {
2095156bc3dcSsevan 	int i;
2096156bc3dcSsevan 
2097156bc3dcSsevan 	RGE_SETBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
2098156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_CFG5, RGE_CFG5_PME_STS);
2099156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_CFG2, RGE_CFG2_CLKREQ_EN);
2100156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG);
2101156bc3dcSsevan 	RGE_CLRBIT_1(sc, 0xf1, 0x80);
2102156bc3dcSsevan 
2103156bc3dcSsevan 	/* Disable UPS. */
2104156bc3dcSsevan 	RGE_MAC_CLRBIT(sc, 0xd40a, 0x0010);
2105156bc3dcSsevan 
2106156bc3dcSsevan 	/* Configure MAC MCU. */
2107156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xfc38, 0);
2108156bc3dcSsevan 
2109156bc3dcSsevan 	for (i = 0xfc28; i < 0xfc38; i += 2)
2110156bc3dcSsevan 		rge_write_mac_ocp(sc, i, 0);
2111156bc3dcSsevan 
2112156bc3dcSsevan 	DELAY(3000);
2113156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xfc26, 0);
2114156bc3dcSsevan 
2115156bc3dcSsevan 	if (sc->rge_type == MAC_CFG3) {
2116e13c9dceSjakllsch 		for (i = 0; i < nitems(rtl8125_mac_bps); i++) {
2117e13c9dceSjakllsch 			rge_write_mac_ocp(sc, rtl8125_mac_bps[i].reg,
2118e13c9dceSjakllsch 			    rtl8125_mac_bps[i].val);
2119e13c9dceSjakllsch 		}
2120e13c9dceSjakllsch 	} else if (sc->rge_type == MAC_CFG5) {
2121e13c9dceSjakllsch 		for (i = 0; i < nitems(rtl8125b_mac_bps); i++) {
2122e13c9dceSjakllsch 			rge_write_mac_ocp(sc, rtl8125b_mac_bps[i].reg,
2123e13c9dceSjakllsch 			    rtl8125b_mac_bps[i].val);
2124e13c9dceSjakllsch 		}
2125156bc3dcSsevan 	}
2126156bc3dcSsevan 
2127156bc3dcSsevan 	/* Disable PHY power saving. */
2128156bc3dcSsevan 	rge_disable_phy_ocp_pwrsave(sc);
2129156bc3dcSsevan 
2130156bc3dcSsevan 	/* Set PCIe uncorrectable error status. */
2131156bc3dcSsevan 	rge_write_csi(sc, 0x108,
2132156bc3dcSsevan 	    rge_read_csi(sc, 0x108) | 0x00100000);
2133156bc3dcSsevan }
2134156bc3dcSsevan 
2135156bc3dcSsevan void
2136156bc3dcSsevan rge_disable_phy_ocp_pwrsave(struct rge_softc *sc)
2137156bc3dcSsevan {
2138156bc3dcSsevan 	if (rge_read_phy_ocp(sc, 0xc416) != 0x0500) {
2139156bc3dcSsevan 		rge_patch_phy_mcu(sc, 1);
2140156bc3dcSsevan 		rge_write_phy_ocp(sc, 0xc416, 0);
2141156bc3dcSsevan 		rge_write_phy_ocp(sc, 0xc416, 0x0500);
2142156bc3dcSsevan 		rge_patch_phy_mcu(sc, 0);
2143156bc3dcSsevan 	}
2144156bc3dcSsevan }
2145156bc3dcSsevan 
2146156bc3dcSsevan void
2147156bc3dcSsevan rge_patch_phy_mcu(struct rge_softc *sc, int set)
2148156bc3dcSsevan {
2149156bc3dcSsevan 	int i;
2150156bc3dcSsevan 
2151156bc3dcSsevan 	if (set)
2152156bc3dcSsevan 		RGE_PHY_SETBIT(sc, 0xb820, 0x0010);
2153156bc3dcSsevan 	else
2154156bc3dcSsevan 		RGE_PHY_CLRBIT(sc, 0xb820, 0x0010);
2155156bc3dcSsevan 
2156156bc3dcSsevan 	for (i = 0; i < 1000; i++) {
2157e13c9dceSjakllsch 		if ((rge_read_phy_ocp(sc, 0xb800) & 0x0040) == 0x0040)
2158156bc3dcSsevan 			break;
2159e13c9dceSjakllsch 		DELAY(100);
2160156bc3dcSsevan 	}
2161e13c9dceSjakllsch 	if (i == 1000) {
2162e13c9dceSjakllsch 		DPRINTF(("timeout waiting to patch phy mcu\n"));
2163e13c9dceSjakllsch 		return;
2164e13c9dceSjakllsch 	}
2165156bc3dcSsevan }
2166156bc3dcSsevan 
2167156bc3dcSsevan void
2168156bc3dcSsevan rge_add_media_types(struct rge_softc *sc)
2169156bc3dcSsevan {
2170156bc3dcSsevan 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T, 0, NULL);
2171156bc3dcSsevan 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
2172156bc3dcSsevan 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX, 0, NULL);
2173156bc3dcSsevan 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
2174156bc3dcSsevan 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_T, 0, NULL);
2175156bc3dcSsevan 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
2176156bc3dcSsevan 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_2500_T, 0, NULL);
2177156bc3dcSsevan 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_2500_T | IFM_FDX, 0, NULL);
2178156bc3dcSsevan }
2179156bc3dcSsevan 
2180156bc3dcSsevan void
2181156bc3dcSsevan rge_config_imtype(struct rge_softc *sc, int imtype)
2182156bc3dcSsevan {
2183156bc3dcSsevan 	switch (imtype) {
2184156bc3dcSsevan 	case RGE_IMTYPE_NONE:
2185156bc3dcSsevan 		sc->rge_intrs = RGE_INTRS;
2186156bc3dcSsevan 		sc->rge_rx_ack = RGE_ISR_RX_OK | RGE_ISR_RX_DESC_UNAVAIL |
2187156bc3dcSsevan 		    RGE_ISR_RX_FIFO_OFLOW;
2188156bc3dcSsevan 		sc->rge_tx_ack = RGE_ISR_TX_OK;
2189156bc3dcSsevan 		break;
2190156bc3dcSsevan 	case RGE_IMTYPE_SIM:
2191156bc3dcSsevan 		sc->rge_intrs = RGE_INTRS_TIMER;
2192156bc3dcSsevan 		sc->rge_rx_ack = RGE_ISR_PCS_TIMEOUT;
2193156bc3dcSsevan 		sc->rge_tx_ack = RGE_ISR_PCS_TIMEOUT;
2194156bc3dcSsevan 		break;
2195156bc3dcSsevan 	default:
2196b7feb0b5Ssevan 		panic("%s: unknown imtype %d", device_xname(sc->sc_dev), imtype);
2197156bc3dcSsevan 	}
2198156bc3dcSsevan }
2199156bc3dcSsevan 
2200156bc3dcSsevan void
2201e13c9dceSjakllsch rge_disable_hw_im(struct rge_softc *sc)
2202e13c9dceSjakllsch {
2203e13c9dceSjakllsch 	RGE_WRITE_2(sc, RGE_IM, 0);
2204e13c9dceSjakllsch }
2205e13c9dceSjakllsch 
2206e13c9dceSjakllsch void
2207156bc3dcSsevan rge_disable_sim_im(struct rge_softc *sc)
2208156bc3dcSsevan {
2209e13c9dceSjakllsch 	RGE_WRITE_4(sc, RGE_TIMERINT0, 0);
2210156bc3dcSsevan 	sc->rge_timerintr = 0;
2211156bc3dcSsevan }
2212156bc3dcSsevan 
2213156bc3dcSsevan void
2214156bc3dcSsevan rge_setup_sim_im(struct rge_softc *sc)
2215156bc3dcSsevan {
2216e13c9dceSjakllsch 	RGE_WRITE_4(sc, RGE_TIMERINT0, 0x2600);
2217156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_TIMERCNT, 1);
2218156bc3dcSsevan 	sc->rge_timerintr = 1;
2219156bc3dcSsevan }
2220156bc3dcSsevan 
2221156bc3dcSsevan void
2222156bc3dcSsevan rge_setup_intr(struct rge_softc *sc, int imtype)
2223156bc3dcSsevan {
2224156bc3dcSsevan 	rge_config_imtype(sc, imtype);
2225156bc3dcSsevan 
2226156bc3dcSsevan 	/* Enable interrupts. */
2227156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_IMR, sc->rge_intrs);
2228156bc3dcSsevan 
2229156bc3dcSsevan 	switch (imtype) {
2230156bc3dcSsevan 	case RGE_IMTYPE_NONE:
2231156bc3dcSsevan 		rge_disable_sim_im(sc);
2232e13c9dceSjakllsch 		rge_disable_hw_im(sc);
2233156bc3dcSsevan 		break;
2234156bc3dcSsevan 	case RGE_IMTYPE_SIM:
2235e13c9dceSjakllsch 		rge_disable_hw_im(sc);
2236156bc3dcSsevan 		rge_setup_sim_im(sc);
2237156bc3dcSsevan 		break;
2238156bc3dcSsevan 	default:
2239b7feb0b5Ssevan 		panic("%s: unknown imtype %d", device_xname(sc->sc_dev), imtype);
2240156bc3dcSsevan 	}
2241156bc3dcSsevan }
2242156bc3dcSsevan 
2243156bc3dcSsevan void
2244156bc3dcSsevan rge_exit_oob(struct rge_softc *sc)
2245156bc3dcSsevan {
2246156bc3dcSsevan 	int i;
2247156bc3dcSsevan 
2248156bc3dcSsevan 	RGE_CLRBIT_4(sc, RGE_RXCFG, RGE_RXCFG_ALLPHYS | RGE_RXCFG_INDIV |
2249156bc3dcSsevan 	    RGE_RXCFG_MULTI | RGE_RXCFG_BROAD | RGE_RXCFG_RUNT |
2250156bc3dcSsevan 	    RGE_RXCFG_ERRPKT);
2251156bc3dcSsevan 
2252156bc3dcSsevan 	/* Disable RealWoW. */
2253156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xc0bc, 0x00ff);
2254156bc3dcSsevan 
2255156bc3dcSsevan 	rge_reset(sc);
2256156bc3dcSsevan 
2257156bc3dcSsevan 	/* Disable OOB. */
2258156bc3dcSsevan 	RGE_CLRBIT_1(sc, RGE_MCUCMD, RGE_MCUCMD_IS_OOB);
2259156bc3dcSsevan 
2260156bc3dcSsevan 	RGE_MAC_CLRBIT(sc, 0xe8de, 0x4000);
2261156bc3dcSsevan 
2262156bc3dcSsevan 	for (i = 0; i < 10; i++) {
2263156bc3dcSsevan 		DELAY(100);
2264156bc3dcSsevan 		if (RGE_READ_2(sc, RGE_TWICMD) & 0x0200)
2265156bc3dcSsevan 			break;
2266156bc3dcSsevan 	}
2267156bc3dcSsevan 
2268156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xc0aa, 0x07d0);
2269e13c9dceSjakllsch 	rge_write_mac_ocp(sc, 0xc0a6, 0x01b5);
2270156bc3dcSsevan 	rge_write_mac_ocp(sc, 0xc01e, 0x5555);
2271156bc3dcSsevan 
2272156bc3dcSsevan 	for (i = 0; i < 10; i++) {
2273156bc3dcSsevan 		DELAY(100);
2274156bc3dcSsevan 		if (RGE_READ_2(sc, RGE_TWICMD) & 0x0200)
2275156bc3dcSsevan 			break;
2276156bc3dcSsevan 	}
2277156bc3dcSsevan 
2278156bc3dcSsevan 	if (rge_read_mac_ocp(sc, 0xd42c) & 0x0100) {
2279e13c9dceSjakllsch 		printf("%s: rge_exit_oob(): rtl8125_is_ups_resume!!\n",
2280e13c9dceSjakllsch 		    device_xname(sc->sc_dev));
2281156bc3dcSsevan 		for (i = 0; i < RGE_TIMEOUT; i++) {
22824a23f239Ssevan 			if ((rge_read_phy_ocp(sc, 0xa420) & 0x0007) == 2)
2283156bc3dcSsevan 				break;
2284156bc3dcSsevan 			DELAY(1000);
2285156bc3dcSsevan 		}
2286156bc3dcSsevan 		RGE_MAC_CLRBIT(sc, 0xd408, 0x0100);
2287e13c9dceSjakllsch 		if (sc->rge_type == MAC_CFG4 || sc->rge_type == MAC_CFG5)
2288e13c9dceSjakllsch 			RGE_PHY_CLRBIT(sc, 0xa466, 0x0001);
2289156bc3dcSsevan 		RGE_PHY_CLRBIT(sc, 0xa468, 0x000a);
2290156bc3dcSsevan 	}
2291156bc3dcSsevan }
2292156bc3dcSsevan 
2293156bc3dcSsevan void
2294156bc3dcSsevan rge_write_csi(struct rge_softc *sc, uint32_t reg, uint32_t val)
2295156bc3dcSsevan {
2296156bc3dcSsevan 	int i;
2297156bc3dcSsevan 
2298156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_CSIDR, val);
2299e13c9dceSjakllsch 	RGE_WRITE_4(sc, RGE_CSIAR, (reg & RGE_CSIAR_ADDR_MASK) |
2300156bc3dcSsevan 	    (RGE_CSIAR_BYTE_EN << RGE_CSIAR_BYTE_EN_SHIFT) | RGE_CSIAR_BUSY);
2301156bc3dcSsevan 
2302156bc3dcSsevan 	for (i = 0; i < 10; i++) {
2303156bc3dcSsevan 		 DELAY(100);
2304156bc3dcSsevan 		 if (!(RGE_READ_4(sc, RGE_CSIAR) & RGE_CSIAR_BUSY))
2305156bc3dcSsevan 			break;
2306156bc3dcSsevan 	}
2307156bc3dcSsevan 
2308156bc3dcSsevan 	DELAY(20);
2309156bc3dcSsevan }
2310156bc3dcSsevan 
2311156bc3dcSsevan uint32_t
2312156bc3dcSsevan rge_read_csi(struct rge_softc *sc, uint32_t reg)
2313156bc3dcSsevan {
2314156bc3dcSsevan 	int i;
2315156bc3dcSsevan 
2316e13c9dceSjakllsch 	RGE_WRITE_4(sc, RGE_CSIAR, (reg & RGE_CSIAR_ADDR_MASK) |
2317156bc3dcSsevan 	    (RGE_CSIAR_BYTE_EN << RGE_CSIAR_BYTE_EN_SHIFT));
2318156bc3dcSsevan 
2319156bc3dcSsevan 	for (i = 0; i < 10; i++) {
2320156bc3dcSsevan 		 DELAY(100);
2321156bc3dcSsevan 		 if (RGE_READ_4(sc, RGE_CSIAR) & RGE_CSIAR_BUSY)
2322156bc3dcSsevan 			break;
2323156bc3dcSsevan 	}
2324156bc3dcSsevan 
2325156bc3dcSsevan 	DELAY(20);
2326156bc3dcSsevan 
2327156bc3dcSsevan 	return (RGE_READ_4(sc, RGE_CSIDR));
2328156bc3dcSsevan }
2329156bc3dcSsevan 
2330156bc3dcSsevan void
2331156bc3dcSsevan rge_write_mac_ocp(struct rge_softc *sc, uint16_t reg, uint16_t val)
2332156bc3dcSsevan {
2333156bc3dcSsevan 	uint32_t tmp;
2334156bc3dcSsevan 
2335156bc3dcSsevan 	tmp = (reg >> 1) << RGE_MACOCP_ADDR_SHIFT;
2336156bc3dcSsevan 	tmp += val;
2337156bc3dcSsevan 	tmp |= RGE_MACOCP_BUSY;
2338156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_MACOCP, tmp);
2339156bc3dcSsevan }
2340156bc3dcSsevan 
2341156bc3dcSsevan uint16_t
2342156bc3dcSsevan rge_read_mac_ocp(struct rge_softc *sc, uint16_t reg)
2343156bc3dcSsevan {
2344156bc3dcSsevan 	uint32_t val;
2345156bc3dcSsevan 
2346156bc3dcSsevan 	val = (reg >> 1) << RGE_MACOCP_ADDR_SHIFT;
2347156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_MACOCP, val);
2348156bc3dcSsevan 
2349156bc3dcSsevan 	return (RGE_READ_4(sc, RGE_MACOCP) & RGE_MACOCP_DATA_MASK);
2350156bc3dcSsevan }
2351156bc3dcSsevan 
2352156bc3dcSsevan void
2353156bc3dcSsevan rge_write_ephy(struct rge_softc *sc, uint16_t reg, uint16_t val)
2354156bc3dcSsevan {
2355156bc3dcSsevan 	uint32_t tmp;
2356156bc3dcSsevan 	int i;
2357156bc3dcSsevan 
2358156bc3dcSsevan 	tmp = (reg & RGE_EPHYAR_ADDR_MASK) << RGE_EPHYAR_ADDR_SHIFT;
2359156bc3dcSsevan 	tmp |= RGE_EPHYAR_BUSY | (val & RGE_EPHYAR_DATA_MASK);
2360156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_EPHYAR, tmp);
2361156bc3dcSsevan 
2362156bc3dcSsevan 	for (i = 0; i < 10; i++) {
2363156bc3dcSsevan 		DELAY(100);
2364156bc3dcSsevan 		if (!(RGE_READ_4(sc, RGE_EPHYAR) & RGE_EPHYAR_BUSY))
2365156bc3dcSsevan 			break;
2366156bc3dcSsevan 	}
2367156bc3dcSsevan 
2368156bc3dcSsevan 	DELAY(20);
2369156bc3dcSsevan }
2370156bc3dcSsevan 
2371e13c9dceSjakllsch uint16_t
2372e13c9dceSjakllsch rge_read_ephy(struct rge_softc *sc, uint16_t reg)
2373e13c9dceSjakllsch {
2374e13c9dceSjakllsch 	uint32_t val;
2375e13c9dceSjakllsch 	int i;
2376e13c9dceSjakllsch 
2377e13c9dceSjakllsch 	val = (reg & RGE_EPHYAR_ADDR_MASK) << RGE_EPHYAR_ADDR_SHIFT;
2378e13c9dceSjakllsch 	RGE_WRITE_4(sc, RGE_EPHYAR, val);
2379e13c9dceSjakllsch 
2380e13c9dceSjakllsch 	for (i = 0; i < 10; i++) {
2381e13c9dceSjakllsch 		DELAY(100);
2382e13c9dceSjakllsch 		val = RGE_READ_4(sc, RGE_EPHYAR);
2383e13c9dceSjakllsch 		if (val & RGE_EPHYAR_BUSY)
2384e13c9dceSjakllsch 			break;
2385e13c9dceSjakllsch 	}
2386e13c9dceSjakllsch 
2387e13c9dceSjakllsch 	DELAY(20);
2388e13c9dceSjakllsch 
2389e13c9dceSjakllsch 	return (val & RGE_EPHYAR_DATA_MASK);
2390e13c9dceSjakllsch }
2391e13c9dceSjakllsch 
2392156bc3dcSsevan void
2393156bc3dcSsevan rge_write_phy(struct rge_softc *sc, uint16_t addr, uint16_t reg, uint16_t val)
2394156bc3dcSsevan {
2395156bc3dcSsevan 	uint16_t off, phyaddr;
2396156bc3dcSsevan 
2397156bc3dcSsevan 	phyaddr = addr ? addr : RGE_PHYBASE + (reg / 8);
2398156bc3dcSsevan 	phyaddr <<= 4;
2399156bc3dcSsevan 
2400156bc3dcSsevan 	off = addr ? reg : 0x10 + (reg % 8);
2401156bc3dcSsevan 
2402156bc3dcSsevan 	phyaddr += (off - 16) << 1;
2403156bc3dcSsevan 
2404156bc3dcSsevan 	rge_write_phy_ocp(sc, phyaddr, val);
2405156bc3dcSsevan }
2406156bc3dcSsevan 
2407e13c9dceSjakllsch uint16_t
2408e13c9dceSjakllsch rge_read_phy(struct rge_softc *sc, uint16_t addr, uint16_t reg)
2409e13c9dceSjakllsch {
2410e13c9dceSjakllsch 	uint16_t off, phyaddr;
2411e13c9dceSjakllsch 
2412e13c9dceSjakllsch 	phyaddr = addr ? addr : RGE_PHYBASE + (reg / 8);
2413e13c9dceSjakllsch 	phyaddr <<= 4;
2414e13c9dceSjakllsch 
2415e13c9dceSjakllsch 	off = addr ? reg : 0x10 + (reg % 8);
2416e13c9dceSjakllsch 
2417e13c9dceSjakllsch 	phyaddr += (off - 16) << 1;
2418e13c9dceSjakllsch 
2419e13c9dceSjakllsch 	return (rge_read_phy_ocp(sc, phyaddr));
2420e13c9dceSjakllsch }
2421e13c9dceSjakllsch 
2422156bc3dcSsevan void
2423156bc3dcSsevan rge_write_phy_ocp(struct rge_softc *sc, uint16_t reg, uint16_t val)
2424156bc3dcSsevan {
2425156bc3dcSsevan 	uint32_t tmp;
2426156bc3dcSsevan 	int i;
2427156bc3dcSsevan 
2428156bc3dcSsevan 	tmp = (reg >> 1) << RGE_PHYOCP_ADDR_SHIFT;
2429156bc3dcSsevan 	tmp |= RGE_PHYOCP_BUSY | val;
2430156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_PHYOCP, tmp);
2431156bc3dcSsevan 
2432156bc3dcSsevan 	for (i = 0; i < RGE_TIMEOUT; i++) {
2433156bc3dcSsevan 		DELAY(1);
2434156bc3dcSsevan 		if (!(RGE_READ_4(sc, RGE_PHYOCP) & RGE_PHYOCP_BUSY))
2435156bc3dcSsevan 			break;
2436156bc3dcSsevan 	}
2437156bc3dcSsevan }
2438156bc3dcSsevan 
2439156bc3dcSsevan uint16_t
2440156bc3dcSsevan rge_read_phy_ocp(struct rge_softc *sc, uint16_t reg)
2441156bc3dcSsevan {
2442156bc3dcSsevan 	uint32_t val;
2443156bc3dcSsevan 	int i;
2444156bc3dcSsevan 
2445156bc3dcSsevan 	val = (reg >> 1) << RGE_PHYOCP_ADDR_SHIFT;
2446156bc3dcSsevan 	RGE_WRITE_4(sc, RGE_PHYOCP, val);
2447156bc3dcSsevan 
2448156bc3dcSsevan 	for (i = 0; i < RGE_TIMEOUT; i++) {
2449156bc3dcSsevan 		DELAY(1);
2450156bc3dcSsevan 		val = RGE_READ_4(sc, RGE_PHYOCP);
2451156bc3dcSsevan 		if (val & RGE_PHYOCP_BUSY)
2452156bc3dcSsevan 			break;
2453156bc3dcSsevan 	}
2454156bc3dcSsevan 
2455156bc3dcSsevan 	return (val & RGE_PHYOCP_DATA_MASK);
2456156bc3dcSsevan }
2457156bc3dcSsevan 
2458156bc3dcSsevan int
2459156bc3dcSsevan rge_get_link_status(struct rge_softc *sc)
2460156bc3dcSsevan {
2461156bc3dcSsevan 	return ((RGE_READ_2(sc, RGE_PHYSTAT) & RGE_PHYSTAT_LINK) ? 1 : 0);
2462156bc3dcSsevan }
2463156bc3dcSsevan 
2464156bc3dcSsevan void
2465ccc8e576Sskrll rge_txstart(void *arg)
2466156bc3dcSsevan {
2467156bc3dcSsevan 	struct rge_softc *sc = arg;
2468156bc3dcSsevan 
2469156bc3dcSsevan 	RGE_WRITE_2(sc, RGE_TXSTART, RGE_TXSTART_START);
2470156bc3dcSsevan }
2471156bc3dcSsevan 
2472156bc3dcSsevan void
2473156bc3dcSsevan rge_tick(void *arg)
2474156bc3dcSsevan {
2475156bc3dcSsevan 	struct rge_softc *sc = arg;
2476156bc3dcSsevan 	int s;
2477156bc3dcSsevan 
2478156bc3dcSsevan 	s = splnet();
2479156bc3dcSsevan 	rge_link_state(sc);
2480156bc3dcSsevan 	splx(s);
2481156bc3dcSsevan 
2482e13c9dceSjakllsch 	callout_schedule(&sc->sc_timeout, hz);
2483156bc3dcSsevan }
2484156bc3dcSsevan 
2485156bc3dcSsevan void
2486156bc3dcSsevan rge_link_state(struct rge_softc *sc)
2487156bc3dcSsevan {
24887ff7ee85Ssevan 	struct ifnet *ifp = &sc->sc_ec.ec_if;
2489156bc3dcSsevan 	int link = LINK_STATE_DOWN;
2490156bc3dcSsevan 
2491156bc3dcSsevan 	if (rge_get_link_status(sc))
2492156bc3dcSsevan 		link = LINK_STATE_UP;
2493156bc3dcSsevan 
2494e13c9dceSjakllsch 	if (ifp->if_link_state != link) { /* XXX not safe to access */
2495e13c9dceSjakllsch 		if_link_state_change(ifp, link);
2496156bc3dcSsevan 	}
2497156bc3dcSsevan }
2498