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