1*8bb071cdSderaadt /* $OpenBSD: if_rge.c,v 1.35 2024/08/31 16:23:09 deraadt Exp $ */ 2be4e4fa3Skevlo 3be4e4fa3Skevlo /* 474263a62Skevlo * Copyright (c) 2019, 2020, 2023, 2024 574263a62Skevlo * Kevin Lo <kevlo@openbsd.org> 6be4e4fa3Skevlo * 7be4e4fa3Skevlo * Permission to use, copy, modify, and distribute this software for any 8be4e4fa3Skevlo * purpose with or without fee is hereby granted, provided that the above 9be4e4fa3Skevlo * copyright notice and this permission notice appear in all copies. 10be4e4fa3Skevlo * 11be4e4fa3Skevlo * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12be4e4fa3Skevlo * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13be4e4fa3Skevlo * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14be4e4fa3Skevlo * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15be4e4fa3Skevlo * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16be4e4fa3Skevlo * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17be4e4fa3Skevlo * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18be4e4fa3Skevlo */ 19be4e4fa3Skevlo 20be4e4fa3Skevlo #include "bpfilter.h" 21be4e4fa3Skevlo #include "vlan.h" 221b7ab755Sdlg #include "kstat.h" 23be4e4fa3Skevlo 24be4e4fa3Skevlo #include <sys/param.h> 25be4e4fa3Skevlo #include <sys/systm.h> 26be4e4fa3Skevlo #include <sys/sockio.h> 27be4e4fa3Skevlo #include <sys/mbuf.h> 28be4e4fa3Skevlo #include <sys/malloc.h> 29be4e4fa3Skevlo #include <sys/device.h> 30be4e4fa3Skevlo #include <sys/endian.h> 31be4e4fa3Skevlo 32be4e4fa3Skevlo #include <net/if.h> 33be4e4fa3Skevlo #include <net/if_media.h> 34be4e4fa3Skevlo 35be4e4fa3Skevlo #include <netinet/in.h> 36be4e4fa3Skevlo #include <netinet/if_ether.h> 37be4e4fa3Skevlo 38be4e4fa3Skevlo #if NBPFILTER > 0 39be4e4fa3Skevlo #include <net/bpf.h> 40be4e4fa3Skevlo #endif 41be4e4fa3Skevlo 421b7ab755Sdlg #if NKSTAT > 0 431b7ab755Sdlg #include <sys/kstat.h> 441b7ab755Sdlg #endif 451b7ab755Sdlg 46be4e4fa3Skevlo #include <machine/bus.h> 47be4e4fa3Skevlo #include <machine/intr.h> 48be4e4fa3Skevlo 49be4e4fa3Skevlo #include <dev/mii/mii.h> 50be4e4fa3Skevlo 51be4e4fa3Skevlo #include <dev/pci/pcivar.h> 52be4e4fa3Skevlo #include <dev/pci/pcireg.h> 53be4e4fa3Skevlo #include <dev/pci/pcidevs.h> 54be4e4fa3Skevlo 55be4e4fa3Skevlo #include <dev/pci/if_rgereg.h> 56be4e4fa3Skevlo 5781a23f33Skevlo #ifdef RGE_DEBUG 5881a23f33Skevlo #define DPRINTF(x) do { if (rge_debug > 0) printf x; } while (0) 5981a23f33Skevlo int rge_debug = 0; 6081a23f33Skevlo #else 6181a23f33Skevlo #define DPRINTF(x) 6281a23f33Skevlo #endif 6381a23f33Skevlo 64be4e4fa3Skevlo int rge_match(struct device *, void *, void *); 65be4e4fa3Skevlo void rge_attach(struct device *, struct device *, void *); 667bcadffeSkevlo int rge_activate(struct device *, int); 67be4e4fa3Skevlo int rge_intr(void *); 68be4e4fa3Skevlo int rge_ioctl(struct ifnet *, u_long, caddr_t); 69be4e4fa3Skevlo void rge_start(struct ifqueue *); 70be4e4fa3Skevlo void rge_watchdog(struct ifnet *); 718cbc3b0aSkevlo void rge_init(struct ifnet *); 72be4e4fa3Skevlo void rge_stop(struct ifnet *); 73be4e4fa3Skevlo int rge_ifmedia_upd(struct ifnet *); 74be4e4fa3Skevlo void rge_ifmedia_sts(struct ifnet *, struct ifmediareq *); 75be4e4fa3Skevlo int rge_allocmem(struct rge_softc *); 76804ff404Skevlo int rge_newbuf(struct rge_queues *); 77804ff404Skevlo void rge_rx_list_init(struct rge_queues *); 78804ff404Skevlo void rge_tx_list_init(struct rge_queues *); 79804ff404Skevlo void rge_fill_rx_ring(struct rge_queues *); 80804ff404Skevlo int rge_rxeof(struct rge_queues *); 81804ff404Skevlo int rge_txeof(struct rge_queues *); 82be4e4fa3Skevlo void rge_reset(struct rge_softc *); 83be4e4fa3Skevlo void rge_iff(struct rge_softc *); 848cbc3b0aSkevlo void rge_chipinit(struct rge_softc *); 85be4e4fa3Skevlo void rge_set_phy_power(struct rge_softc *, int); 868cbc3b0aSkevlo void rge_ephy_config(struct rge_softc *); 878cbc3b0aSkevlo void rge_ephy_config_mac_cfg3(struct rge_softc *); 888cbc3b0aSkevlo void rge_ephy_config_mac_cfg5(struct rge_softc *); 898cbc3b0aSkevlo int rge_phy_config(struct rge_softc *); 9074263a62Skevlo void rge_phy_config_mac_cfg2_8126(struct rge_softc *); 9181a23f33Skevlo void rge_phy_config_mac_cfg3(struct rge_softc *); 9281a23f33Skevlo void rge_phy_config_mac_cfg5(struct rge_softc *); 9381a23f33Skevlo void rge_phy_config_mcu(struct rge_softc *, uint16_t); 94be4e4fa3Skevlo void rge_set_macaddr(struct rge_softc *, const uint8_t *); 95be4e4fa3Skevlo void rge_get_macaddr(struct rge_softc *, uint8_t *); 96be4e4fa3Skevlo void rge_hw_init(struct rge_softc *); 978cbc3b0aSkevlo void rge_hw_reset(struct rge_softc *); 98be4e4fa3Skevlo void rge_disable_phy_ocp_pwrsave(struct rge_softc *); 99be4e4fa3Skevlo void rge_patch_phy_mcu(struct rge_softc *, int); 100be4e4fa3Skevlo void rge_add_media_types(struct rge_softc *); 101be4e4fa3Skevlo void rge_config_imtype(struct rge_softc *, int); 1028cbc3b0aSkevlo void rge_disable_aspm_clkreq(struct rge_softc *); 10381a23f33Skevlo void rge_disable_hw_im(struct rge_softc *); 104be4e4fa3Skevlo void rge_disable_sim_im(struct rge_softc *); 105be4e4fa3Skevlo void rge_setup_sim_im(struct rge_softc *); 106be4e4fa3Skevlo void rge_setup_intr(struct rge_softc *, int); 1078cbc3b0aSkevlo void rge_switch_mcu_ram_page(struct rge_softc *, int); 108be4e4fa3Skevlo void rge_exit_oob(struct rge_softc *); 109be4e4fa3Skevlo void rge_write_csi(struct rge_softc *, uint32_t, uint32_t); 110be4e4fa3Skevlo uint32_t rge_read_csi(struct rge_softc *, uint32_t); 111be4e4fa3Skevlo void rge_write_mac_ocp(struct rge_softc *, uint16_t, uint16_t); 112be4e4fa3Skevlo uint16_t rge_read_mac_ocp(struct rge_softc *, uint16_t); 113be4e4fa3Skevlo void rge_write_ephy(struct rge_softc *, uint16_t, uint16_t); 11481a23f33Skevlo uint16_t rge_read_ephy(struct rge_softc *, uint16_t); 115be4e4fa3Skevlo void rge_write_phy(struct rge_softc *, uint16_t, uint16_t, uint16_t); 116dfa3bc0bSkevlo uint16_t rge_read_phy(struct rge_softc *, uint16_t, uint16_t); 117be4e4fa3Skevlo void rge_write_phy_ocp(struct rge_softc *, uint16_t, uint16_t); 118be4e4fa3Skevlo uint16_t rge_read_phy_ocp(struct rge_softc *, uint16_t); 119be4e4fa3Skevlo int rge_get_link_status(struct rge_softc *); 120be4e4fa3Skevlo void rge_txstart(void *); 121be4e4fa3Skevlo void rge_tick(void *); 122be4e4fa3Skevlo void rge_link_state(struct rge_softc *); 1237bcadffeSkevlo #ifndef SMALL_KERNEL 1247bcadffeSkevlo int rge_wol(struct ifnet *, int); 1257bcadffeSkevlo void rge_wol_power(struct rge_softc *); 1267bcadffeSkevlo #endif 127be4e4fa3Skevlo 1281b7ab755Sdlg #if NKSTAT > 0 1291b7ab755Sdlg void rge_kstat_attach(struct rge_softc *); 1301b7ab755Sdlg #endif 1311b7ab755Sdlg 132be4e4fa3Skevlo static const struct { 133be4e4fa3Skevlo uint16_t reg; 134be4e4fa3Skevlo uint16_t val; 1358cbc3b0aSkevlo } rtl8125_mac_cfg3_mcu[] = { 136be4e4fa3Skevlo RTL8125_MAC_CFG3_MCU 13781a23f33Skevlo }, rtl8125_mac_cfg5_mcu[] = { 13881a23f33Skevlo RTL8125_MAC_CFG5_MCU 13974263a62Skevlo }, rtl8126_mac_cfg2_mcu[] = { 14074263a62Skevlo RTL8126_MAC_CFG2_MCU 141be4e4fa3Skevlo }; 142be4e4fa3Skevlo 143d895c343Sjmatthew const struct cfattach rge_ca = { 1447bcadffeSkevlo sizeof(struct rge_softc), rge_match, rge_attach, NULL, rge_activate 145be4e4fa3Skevlo }; 146be4e4fa3Skevlo 147d895c343Sjmatthew struct cfdriver rge_cd = { 148be4e4fa3Skevlo NULL, "rge", DV_IFNET 149be4e4fa3Skevlo }; 150be4e4fa3Skevlo 151be4e4fa3Skevlo const struct pci_matchid rge_devices[] = { 152be4e4fa3Skevlo { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_E3000 }, 15374263a62Skevlo { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTL8125 }, 15474263a62Skevlo { PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RTL8126 } 155be4e4fa3Skevlo }; 156be4e4fa3Skevlo 157be4e4fa3Skevlo int 158be4e4fa3Skevlo rge_match(struct device *parent, void *match, void *aux) 159be4e4fa3Skevlo { 160be4e4fa3Skevlo return (pci_matchbyid((struct pci_attach_args *)aux, rge_devices, 161be4e4fa3Skevlo nitems(rge_devices))); 162be4e4fa3Skevlo } 163be4e4fa3Skevlo 164be4e4fa3Skevlo void 165be4e4fa3Skevlo rge_attach(struct device *parent, struct device *self, void *aux) 166be4e4fa3Skevlo { 167be4e4fa3Skevlo struct rge_softc *sc = (struct rge_softc *)self; 168be4e4fa3Skevlo struct pci_attach_args *pa = aux; 169be4e4fa3Skevlo pci_chipset_tag_t pc = pa->pa_pc; 170be4e4fa3Skevlo pci_intr_handle_t ih; 171be4e4fa3Skevlo const char *intrstr = NULL; 172be4e4fa3Skevlo struct ifnet *ifp; 173804ff404Skevlo struct rge_queues *q; 174be4e4fa3Skevlo pcireg_t reg; 175be4e4fa3Skevlo uint32_t hwrev; 176be4e4fa3Skevlo uint8_t eaddr[ETHER_ADDR_LEN]; 177be4e4fa3Skevlo int offset; 178be4e4fa3Skevlo 179be4e4fa3Skevlo pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0); 180be4e4fa3Skevlo 181be4e4fa3Skevlo /* 182be4e4fa3Skevlo * Map control/status registers. 183be4e4fa3Skevlo */ 184be4e4fa3Skevlo if (pci_mapreg_map(pa, RGE_PCI_BAR2, PCI_MAPREG_TYPE_MEM | 185be4e4fa3Skevlo PCI_MAPREG_MEM_TYPE_64BIT, 0, &sc->rge_btag, &sc->rge_bhandle, 186be4e4fa3Skevlo NULL, &sc->rge_bsize, 0)) { 187be4e4fa3Skevlo if (pci_mapreg_map(pa, RGE_PCI_BAR1, PCI_MAPREG_TYPE_MEM | 188be4e4fa3Skevlo PCI_MAPREG_MEM_TYPE_32BIT, 0, &sc->rge_btag, 189be4e4fa3Skevlo &sc->rge_bhandle, NULL, &sc->rge_bsize, 0)) { 190be4e4fa3Skevlo if (pci_mapreg_map(pa, RGE_PCI_BAR0, PCI_MAPREG_TYPE_IO, 191be4e4fa3Skevlo 0, &sc->rge_btag, &sc->rge_bhandle, NULL, 192be4e4fa3Skevlo &sc->rge_bsize, 0)) { 193be4e4fa3Skevlo printf(": can't map mem or i/o space\n"); 194be4e4fa3Skevlo return; 195be4e4fa3Skevlo } 196be4e4fa3Skevlo } 197be4e4fa3Skevlo } 198be4e4fa3Skevlo 199804ff404Skevlo q = malloc(sizeof(struct rge_queues), M_DEVBUF, M_NOWAIT | M_ZERO); 200804ff404Skevlo if (q == NULL) { 201804ff404Skevlo printf(": unable to allocate queue memory\n"); 202804ff404Skevlo return; 203804ff404Skevlo } 204804ff404Skevlo q->q_sc = sc; 205804ff404Skevlo q->q_index = 0; 206804ff404Skevlo 207804ff404Skevlo sc->sc_queues = q; 208804ff404Skevlo sc->sc_nqueues = 1; 209804ff404Skevlo 210be4e4fa3Skevlo /* 211be4e4fa3Skevlo * Allocate interrupt. 212be4e4fa3Skevlo */ 213d67d920dSkevlo if (pci_intr_map_msix(pa, 0, &ih) == 0 || 214d67d920dSkevlo pci_intr_map_msi(pa, &ih) == 0) 215be4e4fa3Skevlo sc->rge_flags |= RGE_FLAG_MSI; 216be4e4fa3Skevlo else if (pci_intr_map(pa, &ih) != 0) { 217be4e4fa3Skevlo printf(": couldn't map interrupt\n"); 218be4e4fa3Skevlo return; 219be4e4fa3Skevlo } 220be4e4fa3Skevlo intrstr = pci_intr_string(pc, ih); 221be4e4fa3Skevlo sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET | IPL_MPSAFE, rge_intr, 222be4e4fa3Skevlo sc, sc->sc_dev.dv_xname); 223be4e4fa3Skevlo if (sc->sc_ih == NULL) { 224be4e4fa3Skevlo printf(": couldn't establish interrupt"); 225be4e4fa3Skevlo if (intrstr != NULL) 226be4e4fa3Skevlo printf(" at %s", intrstr); 227be4e4fa3Skevlo printf("\n"); 228be4e4fa3Skevlo return; 229be4e4fa3Skevlo } 230be4e4fa3Skevlo printf(": %s", intrstr); 231be4e4fa3Skevlo 232be4e4fa3Skevlo sc->sc_dmat = pa->pa_dmat; 233be4e4fa3Skevlo sc->sc_pc = pa->pa_pc; 234be4e4fa3Skevlo sc->sc_tag = pa->pa_tag; 235be4e4fa3Skevlo 236be4e4fa3Skevlo /* Determine hardware revision */ 237be4e4fa3Skevlo hwrev = RGE_READ_4(sc, RGE_TXCFG) & RGE_TXCFG_HWREV; 238be4e4fa3Skevlo switch (hwrev) { 239be4e4fa3Skevlo case 0x60900000: 240be4e4fa3Skevlo sc->rge_type = MAC_CFG3; 241be4e4fa3Skevlo break; 24281a23f33Skevlo case 0x64100000: 24381a23f33Skevlo sc->rge_type = MAC_CFG5; 24481a23f33Skevlo break; 24574263a62Skevlo case 0x64900000: 24674263a62Skevlo sc->rge_type = MAC_CFG2_8126; 24774263a62Skevlo break; 248be4e4fa3Skevlo default: 249be4e4fa3Skevlo printf(": unknown version 0x%08x\n", hwrev); 250be4e4fa3Skevlo return; 251be4e4fa3Skevlo } 252be4e4fa3Skevlo 253be4e4fa3Skevlo rge_config_imtype(sc, RGE_IMTYPE_SIM); 254be4e4fa3Skevlo 255be4e4fa3Skevlo /* 256be4e4fa3Skevlo * PCI Express check. 257be4e4fa3Skevlo */ 258be4e4fa3Skevlo if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_PCIEXPRESS, 259be4e4fa3Skevlo &offset, NULL)) { 260be4e4fa3Skevlo /* Disable PCIe ASPM and ECPM. */ 261be4e4fa3Skevlo reg = pci_conf_read(pa->pa_pc, pa->pa_tag, 262be4e4fa3Skevlo offset + PCI_PCIE_LCSR); 263be4e4fa3Skevlo reg &= ~(PCI_PCIE_LCSR_ASPM_L0S | PCI_PCIE_LCSR_ASPM_L1 | 264be4e4fa3Skevlo PCI_PCIE_LCSR_ECPM); 265be4e4fa3Skevlo pci_conf_write(pa->pa_pc, pa->pa_tag, offset + PCI_PCIE_LCSR, 266be4e4fa3Skevlo reg); 267be4e4fa3Skevlo } 268be4e4fa3Skevlo 2698cbc3b0aSkevlo rge_chipinit(sc); 270be4e4fa3Skevlo 271be4e4fa3Skevlo rge_get_macaddr(sc, eaddr); 272be4e4fa3Skevlo printf(", address %s\n", ether_sprintf(eaddr)); 273be4e4fa3Skevlo 274be4e4fa3Skevlo memcpy(sc->sc_arpcom.ac_enaddr, eaddr, ETHER_ADDR_LEN); 275be4e4fa3Skevlo 276be4e4fa3Skevlo if (rge_allocmem(sc)) 277be4e4fa3Skevlo return; 278be4e4fa3Skevlo 279be4e4fa3Skevlo ifp = &sc->sc_arpcom.ac_if; 280be4e4fa3Skevlo ifp->if_softc = sc; 281be4e4fa3Skevlo strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 282be4e4fa3Skevlo ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 283be4e4fa3Skevlo ifp->if_xflags = IFXF_MPSAFE; 284be4e4fa3Skevlo ifp->if_ioctl = rge_ioctl; 285be4e4fa3Skevlo ifp->if_qstart = rge_start; 286be4e4fa3Skevlo ifp->if_watchdog = rge_watchdog; 287cf96265bSbluhm ifq_init_maxlen(&ifp->if_snd, RGE_TX_LIST_CNT - 1); 288be4e4fa3Skevlo ifp->if_hardmtu = RGE_JUMBO_MTU; 289be4e4fa3Skevlo 290be4e4fa3Skevlo ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_CSUM_IPv4 | 291be4e4fa3Skevlo IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4; 292be4e4fa3Skevlo 293be4e4fa3Skevlo #if NVLAN > 0 294be4e4fa3Skevlo ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 295be4e4fa3Skevlo #endif 296be4e4fa3Skevlo 2977bcadffeSkevlo #ifndef SMALL_KERNEL 2987bcadffeSkevlo ifp->if_capabilities |= IFCAP_WOL; 2997bcadffeSkevlo ifp->if_wol = rge_wol; 3007bcadffeSkevlo rge_wol(ifp, 0); 3017bcadffeSkevlo #endif 302be4e4fa3Skevlo timeout_set(&sc->sc_timeout, rge_tick, sc); 303be4e4fa3Skevlo task_set(&sc->sc_task, rge_txstart, sc); 304be4e4fa3Skevlo 305be4e4fa3Skevlo /* Initialize ifmedia structures. */ 306be4e4fa3Skevlo ifmedia_init(&sc->sc_media, IFM_IMASK, rge_ifmedia_upd, 307be4e4fa3Skevlo rge_ifmedia_sts); 308be4e4fa3Skevlo rge_add_media_types(sc); 309be4e4fa3Skevlo ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL); 310be4e4fa3Skevlo ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO); 311be4e4fa3Skevlo sc->sc_media.ifm_media = sc->sc_media.ifm_cur->ifm_media; 312be4e4fa3Skevlo 313be4e4fa3Skevlo if_attach(ifp); 314be4e4fa3Skevlo ether_ifattach(ifp); 3151b7ab755Sdlg 3161b7ab755Sdlg #if NKSTAT > 0 3171b7ab755Sdlg rge_kstat_attach(sc); 3181b7ab755Sdlg #endif 319be4e4fa3Skevlo } 320be4e4fa3Skevlo 321be4e4fa3Skevlo int 3227bcadffeSkevlo rge_activate(struct device *self, int act) 3237bcadffeSkevlo { 3249a04daecSderaadt #ifndef SMALL_KERNEL 3257bcadffeSkevlo struct rge_softc *sc = (struct rge_softc *)self; 3269a04daecSderaadt #endif 3277bcadffeSkevlo 3287bcadffeSkevlo switch (act) { 3297bcadffeSkevlo case DVACT_POWERDOWN: 3307bcadffeSkevlo #ifndef SMALL_KERNEL 3317bcadffeSkevlo rge_wol_power(sc); 3327bcadffeSkevlo #endif 333df6c2a29Sstsp break; 3347bcadffeSkevlo } 335*8bb071cdSderaadt return (0); 3367bcadffeSkevlo } 3377bcadffeSkevlo 3387bcadffeSkevlo int 339be4e4fa3Skevlo rge_intr(void *arg) 340be4e4fa3Skevlo { 341be4e4fa3Skevlo struct rge_softc *sc = arg; 342804ff404Skevlo struct rge_queues *q = sc->sc_queues; 343be4e4fa3Skevlo struct ifnet *ifp = &sc->sc_arpcom.ac_if; 344be4e4fa3Skevlo uint32_t status; 345804ff404Skevlo int claimed = 0, rv; 346be4e4fa3Skevlo 347be4e4fa3Skevlo if (!(ifp->if_flags & IFF_RUNNING)) 348be4e4fa3Skevlo return (0); 349be4e4fa3Skevlo 350be4e4fa3Skevlo /* Disable interrupts. */ 351be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_IMR, 0); 352be4e4fa3Skevlo 353be4e4fa3Skevlo if (!(sc->rge_flags & RGE_FLAG_MSI)) { 35481a23f33Skevlo if ((RGE_READ_4(sc, RGE_ISR) & sc->rge_intrs) == 0) 355be4e4fa3Skevlo return (0); 356be4e4fa3Skevlo } 35781a23f33Skevlo 35881a23f33Skevlo status = RGE_READ_4(sc, RGE_ISR); 359be4e4fa3Skevlo if (status) 360be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_ISR, status); 361be4e4fa3Skevlo 362be4e4fa3Skevlo if (status & RGE_ISR_PCS_TIMEOUT) 363be4e4fa3Skevlo claimed = 1; 364be4e4fa3Skevlo 365804ff404Skevlo rv = 0; 36681a23f33Skevlo if (status & sc->rge_intrs) { 367804ff404Skevlo rv |= rge_rxeof(q); 368804ff404Skevlo rv |= rge_txeof(q); 369be4e4fa3Skevlo 370be4e4fa3Skevlo if (status & RGE_ISR_SYSTEM_ERR) { 371be4e4fa3Skevlo KERNEL_LOCK(); 372be4e4fa3Skevlo rge_init(ifp); 373be4e4fa3Skevlo KERNEL_UNLOCK(); 374be4e4fa3Skevlo } 375804ff404Skevlo claimed = 1; 376be4e4fa3Skevlo } 377be4e4fa3Skevlo 378be4e4fa3Skevlo if (sc->rge_timerintr) { 379804ff404Skevlo if (!rv) { 380be4e4fa3Skevlo /* 381be4e4fa3Skevlo * Nothing needs to be processed, fallback 382be4e4fa3Skevlo * to use TX/RX interrupts. 383be4e4fa3Skevlo */ 384be4e4fa3Skevlo rge_setup_intr(sc, RGE_IMTYPE_NONE); 385be4e4fa3Skevlo 386be4e4fa3Skevlo /* 387be4e4fa3Skevlo * Recollect, mainly to avoid the possible 388be4e4fa3Skevlo * race introduced by changing interrupt 389be4e4fa3Skevlo * masks. 390be4e4fa3Skevlo */ 391804ff404Skevlo rge_rxeof(q); 392804ff404Skevlo rge_txeof(q); 393be4e4fa3Skevlo } else 394be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_TIMERCNT, 1); 395804ff404Skevlo } else if (rv) { 396be4e4fa3Skevlo /* 397be4e4fa3Skevlo * Assume that using simulated interrupt moderation 398be4e4fa3Skevlo * (hardware timer based) could reduce the interrupt 399be4e4fa3Skevlo * rate. 400be4e4fa3Skevlo */ 401be4e4fa3Skevlo rge_setup_intr(sc, RGE_IMTYPE_SIM); 402be4e4fa3Skevlo } 403be4e4fa3Skevlo 404be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_IMR, sc->rge_intrs); 405be4e4fa3Skevlo 406be4e4fa3Skevlo return (claimed); 407be4e4fa3Skevlo } 408be4e4fa3Skevlo 409c6c75c18Sdlg static inline void 410c6c75c18Sdlg rge_tx_list_sync(struct rge_softc *sc, struct rge_queues *q, 411c6c75c18Sdlg unsigned int idx, unsigned int len, int ops) 412c6c75c18Sdlg { 413c6c75c18Sdlg bus_dmamap_sync(sc->sc_dmat, q->q_tx.rge_tx_list_map, 414c6c75c18Sdlg idx * sizeof(struct rge_tx_desc), len * sizeof(struct rge_tx_desc), 415c6c75c18Sdlg ops); 416c6c75c18Sdlg } 417c6c75c18Sdlg 418c6c75c18Sdlg static int 419c6c75c18Sdlg rge_encap(struct ifnet *ifp, struct rge_queues *q, struct mbuf *m, int idx) 420be4e4fa3Skevlo { 421804ff404Skevlo struct rge_softc *sc = q->q_sc; 422be4e4fa3Skevlo struct rge_tx_desc *d = NULL; 423be4e4fa3Skevlo struct rge_txq *txq; 424be4e4fa3Skevlo bus_dmamap_t txmap; 425be4e4fa3Skevlo uint32_t cmdsts, cflags = 0; 426c6c75c18Sdlg int cur, error, i; 427c6c75c18Sdlg #if NBPFILTER > 0 428c6c75c18Sdlg caddr_t if_bpf; 429c6c75c18Sdlg #endif 430be4e4fa3Skevlo 431804ff404Skevlo txq = &q->q_tx.rge_txq[idx]; 432be4e4fa3Skevlo txmap = txq->txq_dmamap; 433be4e4fa3Skevlo 434be4e4fa3Skevlo error = bus_dmamap_load_mbuf(sc->sc_dmat, txmap, m, BUS_DMA_NOWAIT); 435be4e4fa3Skevlo switch (error) { 436be4e4fa3Skevlo case 0: 437be4e4fa3Skevlo break; 438be4e4fa3Skevlo case EFBIG: /* mbuf chain is too fragmented */ 439be4e4fa3Skevlo if (m_defrag(m, M_DONTWAIT) == 0 && 440be4e4fa3Skevlo bus_dmamap_load_mbuf(sc->sc_dmat, txmap, m, 441be4e4fa3Skevlo BUS_DMA_NOWAIT) == 0) 442be4e4fa3Skevlo break; 443be4e4fa3Skevlo 444be4e4fa3Skevlo /* FALLTHROUGH */ 445be4e4fa3Skevlo default: 446be4e4fa3Skevlo return (0); 447be4e4fa3Skevlo } 448be4e4fa3Skevlo 449c6c75c18Sdlg #if NBPFILTER > 0 450c6c75c18Sdlg if_bpf = READ_ONCE(ifp->if_bpf); 451c6c75c18Sdlg if (if_bpf) 452c6c75c18Sdlg bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT); 453c6c75c18Sdlg #endif 454c6c75c18Sdlg 455be4e4fa3Skevlo bus_dmamap_sync(sc->sc_dmat, txmap, 0, txmap->dm_mapsize, 456be4e4fa3Skevlo BUS_DMASYNC_PREWRITE); 457be4e4fa3Skevlo 458c6c75c18Sdlg /* 459c6c75c18Sdlg * Set RGE_TDEXTSTS_IPCSUM if any checksum offloading is requested. 460c6c75c18Sdlg * Otherwise, RGE_TDEXTSTS_TCPCSUM / RGE_TDEXTSTS_UDPCSUM does not 461c6c75c18Sdlg * take affect. 462c6c75c18Sdlg */ 463c6c75c18Sdlg if ((m->m_pkthdr.csum_flags & 464c6c75c18Sdlg (M_IPV4_CSUM_OUT | M_TCP_CSUM_OUT | M_UDP_CSUM_OUT)) != 0) { 465c6c75c18Sdlg cflags |= RGE_TDEXTSTS_IPCSUM; 466c6c75c18Sdlg if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) 467c6c75c18Sdlg cflags |= RGE_TDEXTSTS_TCPCSUM; 468c6c75c18Sdlg if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT) 469c6c75c18Sdlg cflags |= RGE_TDEXTSTS_UDPCSUM; 470c6c75c18Sdlg } 471be4e4fa3Skevlo 472be4e4fa3Skevlo /* Set up hardware VLAN tagging. */ 473be4e4fa3Skevlo #if NVLAN > 0 474be4e4fa3Skevlo if (m->m_flags & M_VLANTAG) 475cd7fda7fSkevlo cflags |= swap16(m->m_pkthdr.ether_vtag) | RGE_TDEXTSTS_VTAG; 476be4e4fa3Skevlo #endif 477be4e4fa3Skevlo 478be4e4fa3Skevlo cur = idx; 479c6c75c18Sdlg for (i = 1; i < txmap->dm_nsegs; i++) { 480c6c75c18Sdlg cur = RGE_NEXT_TX_DESC(cur); 481be4e4fa3Skevlo 482c6c75c18Sdlg cmdsts = RGE_TDCMDSTS_OWN; 483be4e4fa3Skevlo cmdsts |= txmap->dm_segs[i].ds_len; 484be4e4fa3Skevlo 485be4e4fa3Skevlo if (cur == RGE_TX_LIST_CNT - 1) 486be4e4fa3Skevlo cmdsts |= RGE_TDCMDSTS_EOR; 487c6c75c18Sdlg if (i == txmap->dm_nsegs - 1) 488a772c87cSpatrick cmdsts |= RGE_TDCMDSTS_EOF; 489be4e4fa3Skevlo 490c6c75c18Sdlg d = &q->q_tx.rge_tx_list[cur]; 491be4e4fa3Skevlo d->rge_cmdsts = htole32(cmdsts); 492c6c75c18Sdlg d->rge_extsts = htole32(cflags); 493c6c75c18Sdlg d->rge_addr = htole64(txmap->dm_segs[i].ds_addr); 494be4e4fa3Skevlo } 495be4e4fa3Skevlo 496be4e4fa3Skevlo /* Update info of TX queue and descriptors. */ 497be4e4fa3Skevlo txq->txq_mbuf = m; 498c6c75c18Sdlg txq->txq_descidx = cur; 499be4e4fa3Skevlo 500c6c75c18Sdlg cmdsts = RGE_TDCMDSTS_SOF; 501c6c75c18Sdlg cmdsts |= txmap->dm_segs[0].ds_len; 502c6c75c18Sdlg 503c6c75c18Sdlg if (idx == RGE_TX_LIST_CNT - 1) 504c6c75c18Sdlg cmdsts |= RGE_TDCMDSTS_EOR; 505c6c75c18Sdlg if (txmap->dm_nsegs == 1) 506c6c75c18Sdlg cmdsts |= RGE_TDCMDSTS_EOF; 507c6c75c18Sdlg 508c6c75c18Sdlg d = &q->q_tx.rge_tx_list[idx]; 509c6c75c18Sdlg d->rge_cmdsts = htole32(cmdsts); 510c6c75c18Sdlg d->rge_extsts = htole32(cflags); 511c6c75c18Sdlg d->rge_addr = htole64(txmap->dm_segs[0].ds_addr); 512c6c75c18Sdlg 513c6c75c18Sdlg if (cur >= idx) { 514c6c75c18Sdlg rge_tx_list_sync(sc, q, idx, txmap->dm_nsegs, 515c6c75c18Sdlg BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 516c6c75c18Sdlg } else { 517c6c75c18Sdlg rge_tx_list_sync(sc, q, idx, RGE_TX_LIST_CNT - idx, 518c6c75c18Sdlg BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 519c6c75c18Sdlg rge_tx_list_sync(sc, q, 0, cur + 1, 520c6c75c18Sdlg BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 521c6c75c18Sdlg } 522c6c75c18Sdlg 523c6c75c18Sdlg /* Transfer ownership of packet to the chip. */ 524c6c75c18Sdlg cmdsts |= RGE_TDCMDSTS_OWN; 525c6c75c18Sdlg rge_tx_list_sync(sc, q, idx, 1, BUS_DMASYNC_POSTWRITE); 526c6c75c18Sdlg d->rge_cmdsts = htole32(cmdsts); 527c6c75c18Sdlg rge_tx_list_sync(sc, q, idx, 1, BUS_DMASYNC_PREWRITE); 528c6c75c18Sdlg 529c6c75c18Sdlg return (txmap->dm_nsegs); 530be4e4fa3Skevlo } 531be4e4fa3Skevlo 532be4e4fa3Skevlo int 533be4e4fa3Skevlo rge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 534be4e4fa3Skevlo { 535be4e4fa3Skevlo struct rge_softc *sc = ifp->if_softc; 536be4e4fa3Skevlo struct ifreq *ifr = (struct ifreq *)data; 537be4e4fa3Skevlo int s, error = 0; 538be4e4fa3Skevlo 539be4e4fa3Skevlo s = splnet(); 540be4e4fa3Skevlo 541be4e4fa3Skevlo switch (cmd) { 542be4e4fa3Skevlo case SIOCSIFADDR: 543be4e4fa3Skevlo ifp->if_flags |= IFF_UP; 544be4e4fa3Skevlo if (!(ifp->if_flags & IFF_RUNNING)) 545be4e4fa3Skevlo rge_init(ifp); 546be4e4fa3Skevlo break; 547be4e4fa3Skevlo case SIOCSIFFLAGS: 548be4e4fa3Skevlo if (ifp->if_flags & IFF_UP) { 549be4e4fa3Skevlo if (ifp->if_flags & IFF_RUNNING) 550be4e4fa3Skevlo error = ENETRESET; 551be4e4fa3Skevlo else 552be4e4fa3Skevlo rge_init(ifp); 553be4e4fa3Skevlo } else { 554be4e4fa3Skevlo if (ifp->if_flags & IFF_RUNNING) 555be4e4fa3Skevlo rge_stop(ifp); 556be4e4fa3Skevlo } 557be4e4fa3Skevlo break; 558be4e4fa3Skevlo case SIOCGIFMEDIA: 559be4e4fa3Skevlo case SIOCSIFMEDIA: 560be4e4fa3Skevlo error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 561be4e4fa3Skevlo break; 56281a23f33Skevlo case SIOCGIFRXR: 56381a23f33Skevlo error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data, 564da1cde29Sdlg NULL, MCLBYTES, &sc->sc_queues->q_rx.rge_rx_ring); 56581a23f33Skevlo break; 566be4e4fa3Skevlo default: 567be4e4fa3Skevlo error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data); 568be4e4fa3Skevlo } 569be4e4fa3Skevlo 570be4e4fa3Skevlo if (error == ENETRESET) { 571be4e4fa3Skevlo if (ifp->if_flags & IFF_RUNNING) 572be4e4fa3Skevlo rge_iff(sc); 573be4e4fa3Skevlo error = 0; 574be4e4fa3Skevlo } 575be4e4fa3Skevlo 576be4e4fa3Skevlo splx(s); 577be4e4fa3Skevlo return (error); 578be4e4fa3Skevlo } 579be4e4fa3Skevlo 580be4e4fa3Skevlo void 581be4e4fa3Skevlo rge_start(struct ifqueue *ifq) 582be4e4fa3Skevlo { 583be4e4fa3Skevlo struct ifnet *ifp = ifq->ifq_if; 584be4e4fa3Skevlo struct rge_softc *sc = ifp->if_softc; 585804ff404Skevlo struct rge_queues *q = sc->sc_queues; 586be4e4fa3Skevlo struct mbuf *m; 587be4e4fa3Skevlo int free, idx, used; 588be4e4fa3Skevlo int queued = 0; 589be4e4fa3Skevlo 590be4e4fa3Skevlo if (!LINK_STATE_IS_UP(ifp->if_link_state)) { 591be4e4fa3Skevlo ifq_purge(ifq); 592be4e4fa3Skevlo return; 593be4e4fa3Skevlo } 594be4e4fa3Skevlo 595be4e4fa3Skevlo /* Calculate free space. */ 596804ff404Skevlo idx = q->q_tx.rge_txq_prodidx; 597804ff404Skevlo free = q->q_tx.rge_txq_considx; 598be4e4fa3Skevlo if (free <= idx) 599be4e4fa3Skevlo free += RGE_TX_LIST_CNT; 600be4e4fa3Skevlo free -= idx; 601be4e4fa3Skevlo 602be4e4fa3Skevlo for (;;) { 6034ba1d670Sdlg if (free < RGE_TX_NSEGS + 2) { 604be4e4fa3Skevlo ifq_set_oactive(&ifp->if_snd); 605be4e4fa3Skevlo break; 606be4e4fa3Skevlo } 607be4e4fa3Skevlo 608be4e4fa3Skevlo m = ifq_dequeue(ifq); 609be4e4fa3Skevlo if (m == NULL) 610be4e4fa3Skevlo break; 611be4e4fa3Skevlo 612c6c75c18Sdlg used = rge_encap(ifp, q, m, idx); 613be4e4fa3Skevlo if (used == 0) { 614be4e4fa3Skevlo m_freem(m); 615be4e4fa3Skevlo continue; 616be4e4fa3Skevlo } 617be4e4fa3Skevlo 618c6c75c18Sdlg KASSERT(used < free); 619be4e4fa3Skevlo free -= used; 620be4e4fa3Skevlo 621be4e4fa3Skevlo idx += used; 622be4e4fa3Skevlo if (idx >= RGE_TX_LIST_CNT) 623be4e4fa3Skevlo idx -= RGE_TX_LIST_CNT; 624be4e4fa3Skevlo 625be4e4fa3Skevlo queued++; 626be4e4fa3Skevlo } 627be4e4fa3Skevlo 628be4e4fa3Skevlo if (queued == 0) 629be4e4fa3Skevlo return; 630be4e4fa3Skevlo 631be4e4fa3Skevlo /* Set a timeout in case the chip goes out to lunch. */ 632be4e4fa3Skevlo ifp->if_timer = 5; 633be4e4fa3Skevlo 634804ff404Skevlo q->q_tx.rge_txq_prodidx = idx; 635be4e4fa3Skevlo ifq_serialize(ifq, &sc->sc_task); 636be4e4fa3Skevlo } 637be4e4fa3Skevlo 638be4e4fa3Skevlo void 639be4e4fa3Skevlo rge_watchdog(struct ifnet *ifp) 640be4e4fa3Skevlo { 641be4e4fa3Skevlo struct rge_softc *sc = ifp->if_softc; 642be4e4fa3Skevlo 643be4e4fa3Skevlo printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname); 644be4e4fa3Skevlo ifp->if_oerrors++; 645be4e4fa3Skevlo 646be4e4fa3Skevlo rge_init(ifp); 647be4e4fa3Skevlo } 648be4e4fa3Skevlo 6498cbc3b0aSkevlo void 650be4e4fa3Skevlo rge_init(struct ifnet *ifp) 651be4e4fa3Skevlo { 652be4e4fa3Skevlo struct rge_softc *sc = ifp->if_softc; 653804ff404Skevlo struct rge_queues *q = sc->sc_queues; 65474263a62Skevlo uint32_t rxconf, val; 6558cbc3b0aSkevlo int i, num_miti; 656be4e4fa3Skevlo 657be4e4fa3Skevlo rge_stop(ifp); 658be4e4fa3Skevlo 659be4e4fa3Skevlo /* Set MAC address. */ 660be4e4fa3Skevlo rge_set_macaddr(sc, sc->sc_arpcom.ac_enaddr); 661be4e4fa3Skevlo 66281a23f33Skevlo /* Initialize RX and TX descriptors lists. */ 663804ff404Skevlo rge_rx_list_init(q); 664804ff404Skevlo rge_tx_list_init(q); 665be4e4fa3Skevlo 6668cbc3b0aSkevlo rge_chipinit(sc); 6678cbc3b0aSkevlo 6688cbc3b0aSkevlo if (rge_phy_config(sc)) 6698cbc3b0aSkevlo return; 6708cbc3b0aSkevlo 6718cbc3b0aSkevlo RGE_SETBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); 6728cbc3b0aSkevlo 6738cbc3b0aSkevlo RGE_CLRBIT_1(sc, 0xf1, 0x80); 6748cbc3b0aSkevlo rge_disable_aspm_clkreq(sc); 6758cbc3b0aSkevlo RGE_WRITE_2(sc, RGE_EEE_TXIDLE_TIMER, 6768cbc3b0aSkevlo RGE_JUMBO_MTU + ETHER_HDR_LEN + 32); 6778cbc3b0aSkevlo 678be4e4fa3Skevlo /* Load the addresses of the RX and TX lists into the chip. */ 679be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_RXDESC_ADDR_LO, 680804ff404Skevlo RGE_ADDR_LO(q->q_rx.rge_rx_list_map->dm_segs[0].ds_addr)); 681be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_RXDESC_ADDR_HI, 682804ff404Skevlo RGE_ADDR_HI(q->q_rx.rge_rx_list_map->dm_segs[0].ds_addr)); 683be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_TXDESC_ADDR_LO, 684804ff404Skevlo RGE_ADDR_LO(q->q_tx.rge_tx_list_map->dm_segs[0].ds_addr)); 685be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_TXDESC_ADDR_HI, 686804ff404Skevlo RGE_ADDR_HI(q->q_tx.rge_tx_list_map->dm_segs[0].ds_addr)); 687be4e4fa3Skevlo 6883f3cdc7cSkevlo /* Set the initial RX and TX configurations. */ 68974263a62Skevlo if (sc->rge_type == MAC_CFG3) 69074263a62Skevlo rxconf = RGE_RXCFG_CONFIG; 69174263a62Skevlo else if (sc->rge_type == MAC_CFG5) 69274263a62Skevlo rxconf = RGE_RXCFG_CONFIG_8125B; 69374263a62Skevlo else 69474263a62Skevlo rxconf = RGE_RXCFG_CONFIG_8126; 69574263a62Skevlo RGE_WRITE_4(sc, RGE_RXCFG, rxconf); 696be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_TXCFG, RGE_TXCFG_CONFIG); 697be4e4fa3Skevlo 698be4e4fa3Skevlo val = rge_read_csi(sc, 0x70c) & ~0xff000000; 699be4e4fa3Skevlo rge_write_csi(sc, 0x70c, val | 0x27000000); 700be4e4fa3Skevlo 70174263a62Skevlo if (sc->rge_type == MAC_CFG2_8126) { 70274263a62Skevlo /* Disable L1 timeout. */ 70374263a62Skevlo val = rge_read_csi(sc, 0x890) & ~0x00000001; 70474263a62Skevlo rge_write_csi(sc, 0x890, val); 70574263a62Skevlo } else 706be4e4fa3Skevlo RGE_WRITE_2(sc, 0x0382, 0x221b); 707804ff404Skevlo 708804ff404Skevlo RGE_WRITE_1(sc, RGE_RSS_CTRL, 0); 709804ff404Skevlo 710804ff404Skevlo val = RGE_READ_2(sc, RGE_RXQUEUE_CTRL) & ~0x001c; 711804ff404Skevlo RGE_WRITE_2(sc, RGE_RXQUEUE_CTRL, val | (fls(sc->sc_nqueues) - 1) << 2); 712804ff404Skevlo 713be4e4fa3Skevlo RGE_CLRBIT_1(sc, RGE_CFG1, RGE_CFG1_SPEED_DOWN); 714be4e4fa3Skevlo 715be4e4fa3Skevlo rge_write_mac_ocp(sc, 0xc140, 0xffff); 716be4e4fa3Skevlo rge_write_mac_ocp(sc, 0xc142, 0xffff); 717be4e4fa3Skevlo 718be4e4fa3Skevlo RGE_MAC_SETBIT(sc, 0xeb58, 0x0001); 719be4e4fa3Skevlo 72074263a62Skevlo if (sc->rge_type == MAC_CFG2_8126) 72174263a62Skevlo RGE_CLRBIT_1(sc, 0xd8, 0x02); 72274263a62Skevlo 723be4e4fa3Skevlo val = rge_read_mac_ocp(sc, 0xe614) & ~0x0700; 7248cbc3b0aSkevlo if (sc->rge_type == MAC_CFG3) 7258cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xe614, val | 0x0300); 72674263a62Skevlo else if (sc->rge_type == MAC_CFG5) 72781a23f33Skevlo rge_write_mac_ocp(sc, 0xe614, val | 0x0200); 72874263a62Skevlo else 72974263a62Skevlo rge_write_mac_ocp(sc, 0xe614, val | 0x0400); 730be4e4fa3Skevlo 731804ff404Skevlo val = rge_read_mac_ocp(sc, 0xe63e) & ~0x0c00; 732804ff404Skevlo rge_write_mac_ocp(sc, 0xe63e, val | 733804ff404Skevlo ((fls(sc->sc_nqueues) - 1) & 0x03) << 10); 734be4e4fa3Skevlo 73581a23f33Skevlo RGE_MAC_CLRBIT(sc, 0xe63e, 0x0030); 73674263a62Skevlo if (sc->rge_type != MAC_CFG5) 737804ff404Skevlo RGE_MAC_SETBIT(sc, 0xe63e, 0x0020); 738be4e4fa3Skevlo 739804ff404Skevlo RGE_MAC_CLRBIT(sc, 0xc0b4, 0x0001); 740804ff404Skevlo RGE_MAC_SETBIT(sc, 0xc0b4, 0x0001); 7418cbc3b0aSkevlo 742be4e4fa3Skevlo RGE_MAC_SETBIT(sc, 0xc0b4, 0x000c); 743be4e4fa3Skevlo 74481a23f33Skevlo val = rge_read_mac_ocp(sc, 0xeb6a) & ~0x00ff; 745be4e4fa3Skevlo rge_write_mac_ocp(sc, 0xeb6a, val | 0x0033); 746be4e4fa3Skevlo 747be4e4fa3Skevlo val = rge_read_mac_ocp(sc, 0xeb50) & ~0x03e0; 748be4e4fa3Skevlo rge_write_mac_ocp(sc, 0xeb50, val | 0x0040); 749be4e4fa3Skevlo 7508cbc3b0aSkevlo RGE_MAC_CLRBIT(sc, 0xe056, 0x00f0); 751be4e4fa3Skevlo 752be4e4fa3Skevlo RGE_WRITE_1(sc, RGE_TDFNR, 0x10); 753be4e4fa3Skevlo 754be4e4fa3Skevlo RGE_MAC_CLRBIT(sc, 0xe040, 0x1000); 755be4e4fa3Skevlo 75681a23f33Skevlo val = rge_read_mac_ocp(sc, 0xea1c) & ~0x0003; 75781a23f33Skevlo rge_write_mac_ocp(sc, 0xea1c, val | 0x0001); 75881a23f33Skevlo 7598cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xe0c0, 0x4000); 760be4e4fa3Skevlo 7618cbc3b0aSkevlo RGE_MAC_SETBIT(sc, 0xe052, 0x0060); 7628cbc3b0aSkevlo RGE_MAC_CLRBIT(sc, 0xe052, 0x0088); 763be4e4fa3Skevlo 764be4e4fa3Skevlo val = rge_read_mac_ocp(sc, 0xd430) & ~0x0fff; 7658cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xd430, val | 0x045f); 766be4e4fa3Skevlo 767804ff404Skevlo RGE_SETBIT_1(sc, RGE_DLLPR, RGE_DLLPR_PFM_EN | RGE_DLLPR_TX_10M_PS_EN); 76881a23f33Skevlo 7698cbc3b0aSkevlo if (sc->rge_type == MAC_CFG3) 77081a23f33Skevlo RGE_SETBIT_1(sc, RGE_MCUCMD, 0x01); 771be4e4fa3Skevlo 772be4e4fa3Skevlo /* Disable EEE plus. */ 773be4e4fa3Skevlo RGE_MAC_CLRBIT(sc, 0xe080, 0x0002); 774be4e4fa3Skevlo 77574263a62Skevlo if (sc->rge_type == MAC_CFG2_8126) 77674263a62Skevlo RGE_MAC_CLRBIT(sc, 0xea1c, 0x0304); 77774263a62Skevlo else 778be4e4fa3Skevlo RGE_MAC_CLRBIT(sc, 0xea1c, 0x0004); 779be4e4fa3Skevlo 780be4e4fa3Skevlo RGE_MAC_SETBIT(sc, 0xeb54, 0x0001); 781be4e4fa3Skevlo DELAY(1); 782be4e4fa3Skevlo RGE_MAC_CLRBIT(sc, 0xeb54, 0x0001); 783be4e4fa3Skevlo 7848cbc3b0aSkevlo RGE_CLRBIT_2(sc, 0x1880, 0x0030); 7858cbc3b0aSkevlo 78674263a62Skevlo /* Config interrupt type for RTL8125B/RTL8126. */ 78774263a62Skevlo if (sc->rge_type != MAC_CFG3) 7888cbc3b0aSkevlo RGE_CLRBIT_1(sc, RGE_INT_CFG0, RGE_INT_CFG0_EN); 7898cbc3b0aSkevlo 7908cbc3b0aSkevlo /* Clear timer interrupts. */ 7918cbc3b0aSkevlo RGE_WRITE_4(sc, RGE_TIMERINT0, 0); 7928cbc3b0aSkevlo RGE_WRITE_4(sc, RGE_TIMERINT1, 0); 7938cbc3b0aSkevlo RGE_WRITE_4(sc, RGE_TIMERINT2, 0); 7948cbc3b0aSkevlo RGE_WRITE_4(sc, RGE_TIMERINT3, 0); 7958cbc3b0aSkevlo 7968cbc3b0aSkevlo num_miti = (sc->rge_type == MAC_CFG3) ? 64 : 32; 7978cbc3b0aSkevlo /* Clear interrupt moderation timer. */ 7988cbc3b0aSkevlo for (i = 0; i < num_miti; i++) 7998cbc3b0aSkevlo RGE_WRITE_4(sc, RGE_INTMITI(i), 0); 8008cbc3b0aSkevlo 8018cbc3b0aSkevlo if (sc->rge_type == MAC_CFG5) { 8028cbc3b0aSkevlo RGE_CLRBIT_1(sc, RGE_INT_CFG0, 8038cbc3b0aSkevlo RGE_INT_CFG0_TIMEOUT_BYPASS | 8048cbc3b0aSkevlo RGE_INT_CFG0_MITIGATION_BYPASS); 8058cbc3b0aSkevlo RGE_WRITE_2(sc, RGE_INT_CFG1, 0); 8068cbc3b0aSkevlo } 8078cbc3b0aSkevlo 8088cbc3b0aSkevlo RGE_MAC_SETBIT(sc, 0xc0ac, 0x1f80); 809be4e4fa3Skevlo 810be4e4fa3Skevlo rge_write_mac_ocp(sc, 0xe098, 0xc302); 811be4e4fa3Skevlo 8128cbc3b0aSkevlo RGE_MAC_CLRBIT(sc, 0xe032, 0x0003); 8138cbc3b0aSkevlo val = rge_read_csi(sc, 0x98) & ~0x0000ff00; 8148cbc3b0aSkevlo rge_write_csi(sc, 0x98, val); 8158cbc3b0aSkevlo 8168cbc3b0aSkevlo val = rge_read_mac_ocp(sc, 0xe092) & ~0x00ff; 8178cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xe092, val); 8188cbc3b0aSkevlo 819be4e4fa3Skevlo if (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING) 820be4e4fa3Skevlo RGE_SETBIT_4(sc, RGE_RXCFG, RGE_RXCFG_VLANSTRIP); 821be4e4fa3Skevlo 822be4e4fa3Skevlo RGE_SETBIT_2(sc, RGE_CPLUSCMD, RGE_CPLUSCMD_RXCSUM); 823be4e4fa3Skevlo 8248cbc3b0aSkevlo /* Set Maximum frame size. */ 8258cbc3b0aSkevlo RGE_WRITE_2(sc, RGE_RXMAXSIZE, RGE_JUMBO_FRAMELEN); 826be4e4fa3Skevlo 827be4e4fa3Skevlo /* Disable RXDV gate. */ 828be4e4fa3Skevlo RGE_CLRBIT_1(sc, RGE_PPSW, 0x08); 829be4e4fa3Skevlo DELAY(2000); 830be4e4fa3Skevlo 8318cbc3b0aSkevlo /* Program promiscuous mode and multicast filters. */ 8328cbc3b0aSkevlo rge_iff(sc); 8338cbc3b0aSkevlo 8348cbc3b0aSkevlo rge_disable_aspm_clkreq(sc); 8358cbc3b0aSkevlo 8368cbc3b0aSkevlo RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); 8378cbc3b0aSkevlo DELAY(10); 8388cbc3b0aSkevlo 839be4e4fa3Skevlo rge_ifmedia_upd(ifp); 840be4e4fa3Skevlo 841be4e4fa3Skevlo /* Enable transmit and receive. */ 842be4e4fa3Skevlo RGE_WRITE_1(sc, RGE_CMD, RGE_CMD_TXENB | RGE_CMD_RXENB); 843be4e4fa3Skevlo 844be4e4fa3Skevlo /* Enable interrupts. */ 845be4e4fa3Skevlo rge_setup_intr(sc, RGE_IMTYPE_SIM); 846be4e4fa3Skevlo 847be4e4fa3Skevlo ifp->if_flags |= IFF_RUNNING; 848be4e4fa3Skevlo ifq_clr_oactive(&ifp->if_snd); 849be4e4fa3Skevlo 850be4e4fa3Skevlo timeout_add_sec(&sc->sc_timeout, 1); 851be4e4fa3Skevlo } 852be4e4fa3Skevlo 853be4e4fa3Skevlo /* 854be4e4fa3Skevlo * Stop the adapter and free any mbufs allocated to the RX and TX lists. 855be4e4fa3Skevlo */ 856be4e4fa3Skevlo void 857be4e4fa3Skevlo rge_stop(struct ifnet *ifp) 858be4e4fa3Skevlo { 859be4e4fa3Skevlo struct rge_softc *sc = ifp->if_softc; 860804ff404Skevlo struct rge_queues *q = sc->sc_queues; 861be4e4fa3Skevlo int i; 862be4e4fa3Skevlo 863be4e4fa3Skevlo timeout_del(&sc->sc_timeout); 864be4e4fa3Skevlo 865be4e4fa3Skevlo ifp->if_timer = 0; 866be4e4fa3Skevlo ifp->if_flags &= ~IFF_RUNNING; 867be4e4fa3Skevlo sc->rge_timerintr = 0; 868be4e4fa3Skevlo 869be4e4fa3Skevlo RGE_CLRBIT_4(sc, RGE_RXCFG, RGE_RXCFG_ALLPHYS | RGE_RXCFG_INDIV | 870be4e4fa3Skevlo RGE_RXCFG_MULTI | RGE_RXCFG_BROAD | RGE_RXCFG_RUNT | 871be4e4fa3Skevlo RGE_RXCFG_ERRPKT); 872be4e4fa3Skevlo 8738cbc3b0aSkevlo rge_hw_reset(sc); 87481a23f33Skevlo 8758cbc3b0aSkevlo RGE_MAC_CLRBIT(sc, 0xc0ac, 0x1f80); 876be4e4fa3Skevlo 877be4e4fa3Skevlo intr_barrier(sc->sc_ih); 878be4e4fa3Skevlo ifq_barrier(&ifp->if_snd); 879be4e4fa3Skevlo ifq_clr_oactive(&ifp->if_snd); 880be4e4fa3Skevlo 881e21346faSdlg if (q->q_rx.rge_head != NULL) { 882e21346faSdlg m_freem(q->q_rx.rge_head); 883e21346faSdlg q->q_rx.rge_head = NULL; 884e21346faSdlg q->q_rx.rge_tail = &q->q_rx.rge_head; 885e21346faSdlg } 886e21346faSdlg 887be4e4fa3Skevlo /* Free the TX list buffers. */ 888be4e4fa3Skevlo for (i = 0; i < RGE_TX_LIST_CNT; i++) { 889804ff404Skevlo if (q->q_tx.rge_txq[i].txq_mbuf != NULL) { 890be4e4fa3Skevlo bus_dmamap_unload(sc->sc_dmat, 891804ff404Skevlo q->q_tx.rge_txq[i].txq_dmamap); 892804ff404Skevlo m_freem(q->q_tx.rge_txq[i].txq_mbuf); 893804ff404Skevlo q->q_tx.rge_txq[i].txq_mbuf = NULL; 894be4e4fa3Skevlo } 895be4e4fa3Skevlo } 896be4e4fa3Skevlo 897be4e4fa3Skevlo /* Free the RX list buffers. */ 898be4e4fa3Skevlo for (i = 0; i < RGE_RX_LIST_CNT; i++) { 899804ff404Skevlo if (q->q_rx.rge_rxq[i].rxq_mbuf != NULL) { 900be4e4fa3Skevlo bus_dmamap_unload(sc->sc_dmat, 901804ff404Skevlo q->q_rx.rge_rxq[i].rxq_dmamap); 902804ff404Skevlo m_freem(q->q_rx.rge_rxq[i].rxq_mbuf); 903804ff404Skevlo q->q_rx.rge_rxq[i].rxq_mbuf = NULL; 904be4e4fa3Skevlo } 905be4e4fa3Skevlo } 906be4e4fa3Skevlo } 907be4e4fa3Skevlo 908be4e4fa3Skevlo /* 909be4e4fa3Skevlo * Set media options. 910be4e4fa3Skevlo */ 911be4e4fa3Skevlo int 912be4e4fa3Skevlo rge_ifmedia_upd(struct ifnet *ifp) 913be4e4fa3Skevlo { 914be4e4fa3Skevlo struct rge_softc *sc = ifp->if_softc; 915be4e4fa3Skevlo struct ifmedia *ifm = &sc->sc_media; 916be4e4fa3Skevlo int anar, gig, val; 917be4e4fa3Skevlo 918be4e4fa3Skevlo if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 919be4e4fa3Skevlo return (EINVAL); 920be4e4fa3Skevlo 921be4e4fa3Skevlo /* Disable Gigabit Lite. */ 922be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xa428, 0x0200); 923be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xa5ea, 0x0001); 92474263a62Skevlo if (sc->rge_type == MAC_CFG2_8126) 92574263a62Skevlo RGE_PHY_CLRBIT(sc, 0xa5ea, 0x0002); 926be4e4fa3Skevlo 927be4e4fa3Skevlo val = rge_read_phy_ocp(sc, 0xa5d4); 928be4e4fa3Skevlo val &= ~RGE_ADV_2500TFDX; 92974263a62Skevlo if (sc->rge_type == MAC_CFG2_8126) 93074263a62Skevlo val &= ~RGE_ADV_5000TFDX; 931be4e4fa3Skevlo 93274263a62Skevlo anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10; 93374263a62Skevlo gig = GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX; 93474263a62Skevlo 935be4e4fa3Skevlo switch (IFM_SUBTYPE(ifm->ifm_media)) { 936be4e4fa3Skevlo case IFM_AUTO: 93774263a62Skevlo val |= (sc->rge_type != MAC_CFG2_8126) ? 93874263a62Skevlo RGE_ADV_2500TFDX : (RGE_ADV_2500TFDX | RGE_ADV_5000TFDX); 93974263a62Skevlo break; 94074263a62Skevlo case IFM_5000_T: 94174263a62Skevlo val |= RGE_ADV_5000TFDX; 94274263a62Skevlo ifp->if_baudrate = IF_Gbps(5); 943be4e4fa3Skevlo break; 944be4e4fa3Skevlo case IFM_2500_T: 945be4e4fa3Skevlo val |= RGE_ADV_2500TFDX; 946be4e4fa3Skevlo ifp->if_baudrate = IF_Mbps(2500); 947be4e4fa3Skevlo break; 948be4e4fa3Skevlo case IFM_1000_T: 949be4e4fa3Skevlo ifp->if_baudrate = IF_Gbps(1); 950be4e4fa3Skevlo break; 951be4e4fa3Skevlo case IFM_100_TX: 952dfa3bc0bSkevlo gig = rge_read_phy(sc, 0, MII_100T2CR) & 953dfa3bc0bSkevlo ~(GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX); 954dfa3bc0bSkevlo anar = ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) ? 955dfa3bc0bSkevlo ANAR_TX | ANAR_TX_FD | ANAR_10_FD | ANAR_10 : 956dfa3bc0bSkevlo ANAR_TX | ANAR_10_FD | ANAR_10; 957be4e4fa3Skevlo ifp->if_baudrate = IF_Mbps(100); 958be4e4fa3Skevlo break; 959be4e4fa3Skevlo case IFM_10_T: 960dfa3bc0bSkevlo gig = rge_read_phy(sc, 0, MII_100T2CR) & 961dfa3bc0bSkevlo ~(GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX); 962dfa3bc0bSkevlo anar = ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) ? 963dfa3bc0bSkevlo ANAR_10_FD | ANAR_10 : ANAR_10; 964be4e4fa3Skevlo ifp->if_baudrate = IF_Mbps(10); 965be4e4fa3Skevlo break; 966be4e4fa3Skevlo default: 967be4e4fa3Skevlo printf("%s: unsupported media type\n", sc->sc_dev.dv_xname); 968be4e4fa3Skevlo return (EINVAL); 969be4e4fa3Skevlo } 970be4e4fa3Skevlo 971be4e4fa3Skevlo rge_write_phy(sc, 0, MII_ANAR, anar | ANAR_PAUSE_ASYM | ANAR_FC); 972be4e4fa3Skevlo rge_write_phy(sc, 0, MII_100T2CR, gig); 973be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xa5d4, val); 974dfa3bc0bSkevlo rge_write_phy(sc, 0, MII_BMCR, BMCR_RESET | BMCR_AUTOEN | 975dfa3bc0bSkevlo BMCR_STARTNEG); 976be4e4fa3Skevlo 977be4e4fa3Skevlo return (0); 978be4e4fa3Skevlo } 979be4e4fa3Skevlo 980be4e4fa3Skevlo /* 981be4e4fa3Skevlo * Report current media status. 982be4e4fa3Skevlo */ 983be4e4fa3Skevlo void 984be4e4fa3Skevlo rge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 985be4e4fa3Skevlo { 986be4e4fa3Skevlo struct rge_softc *sc = ifp->if_softc; 987be4e4fa3Skevlo uint16_t status = 0; 988be4e4fa3Skevlo 989be4e4fa3Skevlo ifmr->ifm_status = IFM_AVALID; 990be4e4fa3Skevlo ifmr->ifm_active = IFM_ETHER; 991be4e4fa3Skevlo 992be4e4fa3Skevlo if (rge_get_link_status(sc)) { 993be4e4fa3Skevlo ifmr->ifm_status |= IFM_ACTIVE; 994be4e4fa3Skevlo 995be4e4fa3Skevlo status = RGE_READ_2(sc, RGE_PHYSTAT); 996be4e4fa3Skevlo if ((status & RGE_PHYSTAT_FDX) || 99774263a62Skevlo (status & (RGE_PHYSTAT_2500MBPS | RGE_PHYSTAT_5000MBPS))) 998be4e4fa3Skevlo ifmr->ifm_active |= IFM_FDX; 999be4e4fa3Skevlo else 1000be4e4fa3Skevlo ifmr->ifm_active |= IFM_HDX; 1001be4e4fa3Skevlo 1002be4e4fa3Skevlo if (status & RGE_PHYSTAT_10MBPS) 1003be4e4fa3Skevlo ifmr->ifm_active |= IFM_10_T; 1004be4e4fa3Skevlo else if (status & RGE_PHYSTAT_100MBPS) 1005be4e4fa3Skevlo ifmr->ifm_active |= IFM_100_TX; 1006be4e4fa3Skevlo else if (status & RGE_PHYSTAT_1000MBPS) 1007be4e4fa3Skevlo ifmr->ifm_active |= IFM_1000_T; 1008be4e4fa3Skevlo else if (status & RGE_PHYSTAT_2500MBPS) 1009be4e4fa3Skevlo ifmr->ifm_active |= IFM_2500_T; 101074263a62Skevlo else if (status & RGE_PHYSTAT_5000MBPS) 101174263a62Skevlo ifmr->ifm_active |= IFM_5000_T; 1012be4e4fa3Skevlo } 1013be4e4fa3Skevlo } 1014be4e4fa3Skevlo 1015be4e4fa3Skevlo /* 1016be4e4fa3Skevlo * Allocate memory for RX/TX rings. 1017be4e4fa3Skevlo */ 1018be4e4fa3Skevlo int 1019be4e4fa3Skevlo rge_allocmem(struct rge_softc *sc) 1020be4e4fa3Skevlo { 1021804ff404Skevlo struct rge_queues *q = sc->sc_queues; 1022be4e4fa3Skevlo int error, i; 1023be4e4fa3Skevlo 1024be4e4fa3Skevlo /* Allocate DMA'able memory for the TX ring. */ 1025be4e4fa3Skevlo error = bus_dmamap_create(sc->sc_dmat, RGE_TX_LIST_SZ, 1, 10268cbc3b0aSkevlo RGE_TX_LIST_SZ, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 10278cbc3b0aSkevlo &q->q_tx.rge_tx_list_map); 1028be4e4fa3Skevlo if (error) { 1029be4e4fa3Skevlo printf("%s: can't create TX list map\n", sc->sc_dev.dv_xname); 1030be4e4fa3Skevlo return (error); 1031be4e4fa3Skevlo } 1032be4e4fa3Skevlo error = bus_dmamem_alloc(sc->sc_dmat, RGE_TX_LIST_SZ, RGE_ALIGN, 0, 1033804ff404Skevlo &q->q_tx.rge_tx_listseg, 1, &q->q_tx.rge_tx_listnseg, 1034be4e4fa3Skevlo BUS_DMA_NOWAIT| BUS_DMA_ZERO); 1035be4e4fa3Skevlo if (error) { 1036be4e4fa3Skevlo printf("%s: can't alloc TX list\n", sc->sc_dev.dv_xname); 1037be4e4fa3Skevlo return (error); 1038be4e4fa3Skevlo } 1039be4e4fa3Skevlo 1040be4e4fa3Skevlo /* Load the map for the TX ring. */ 1041804ff404Skevlo error = bus_dmamem_map(sc->sc_dmat, &q->q_tx.rge_tx_listseg, 1042804ff404Skevlo q->q_tx.rge_tx_listnseg, RGE_TX_LIST_SZ, 1043804ff404Skevlo (caddr_t *)&q->q_tx.rge_tx_list, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 1044be4e4fa3Skevlo if (error) { 1045be4e4fa3Skevlo printf("%s: can't map TX dma buffers\n", sc->sc_dev.dv_xname); 1046804ff404Skevlo bus_dmamem_free(sc->sc_dmat, &q->q_tx.rge_tx_listseg, 1047804ff404Skevlo q->q_tx.rge_tx_listnseg); 1048be4e4fa3Skevlo return (error); 1049be4e4fa3Skevlo } 1050804ff404Skevlo error = bus_dmamap_load(sc->sc_dmat, q->q_tx.rge_tx_list_map, 1051804ff404Skevlo q->q_tx.rge_tx_list, RGE_TX_LIST_SZ, NULL, BUS_DMA_NOWAIT); 1052be4e4fa3Skevlo if (error) { 1053be4e4fa3Skevlo printf("%s: can't load TX dma map\n", sc->sc_dev.dv_xname); 1054804ff404Skevlo bus_dmamap_destroy(sc->sc_dmat, q->q_tx.rge_tx_list_map); 1055be4e4fa3Skevlo bus_dmamem_unmap(sc->sc_dmat, 1056804ff404Skevlo (caddr_t)q->q_tx.rge_tx_list, RGE_TX_LIST_SZ); 1057804ff404Skevlo bus_dmamem_free(sc->sc_dmat, &q->q_tx.rge_tx_listseg, 1058804ff404Skevlo q->q_tx.rge_tx_listnseg); 1059be4e4fa3Skevlo return (error); 1060be4e4fa3Skevlo } 1061be4e4fa3Skevlo 1062be4e4fa3Skevlo /* Create DMA maps for TX buffers. */ 1063be4e4fa3Skevlo for (i = 0; i < RGE_TX_LIST_CNT; i++) { 1064be4e4fa3Skevlo error = bus_dmamap_create(sc->sc_dmat, RGE_JUMBO_FRAMELEN, 10658cbc3b0aSkevlo RGE_TX_NSEGS, RGE_JUMBO_FRAMELEN, 0, 10668cbc3b0aSkevlo BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 1067804ff404Skevlo &q->q_tx.rge_txq[i].txq_dmamap); 1068be4e4fa3Skevlo if (error) { 1069be4e4fa3Skevlo printf("%s: can't create DMA map for TX\n", 1070be4e4fa3Skevlo sc->sc_dev.dv_xname); 1071be4e4fa3Skevlo return (error); 1072be4e4fa3Skevlo } 1073be4e4fa3Skevlo } 1074be4e4fa3Skevlo 1075be4e4fa3Skevlo /* Allocate DMA'able memory for the RX ring. */ 1076be4e4fa3Skevlo error = bus_dmamap_create(sc->sc_dmat, RGE_RX_LIST_SZ, 1, 10778cbc3b0aSkevlo RGE_RX_LIST_SZ, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 10788cbc3b0aSkevlo &q->q_rx.rge_rx_list_map); 1079be4e4fa3Skevlo if (error) { 1080be4e4fa3Skevlo printf("%s: can't create RX list map\n", sc->sc_dev.dv_xname); 1081be4e4fa3Skevlo return (error); 1082be4e4fa3Skevlo } 1083be4e4fa3Skevlo error = bus_dmamem_alloc(sc->sc_dmat, RGE_RX_LIST_SZ, RGE_ALIGN, 0, 1084804ff404Skevlo &q->q_rx.rge_rx_listseg, 1, &q->q_rx.rge_rx_listnseg, 1085be4e4fa3Skevlo BUS_DMA_NOWAIT| BUS_DMA_ZERO); 1086be4e4fa3Skevlo if (error) { 1087be4e4fa3Skevlo printf("%s: can't alloc RX list\n", sc->sc_dev.dv_xname); 1088be4e4fa3Skevlo return (error); 1089be4e4fa3Skevlo } 1090be4e4fa3Skevlo 1091be4e4fa3Skevlo /* Load the map for the RX ring. */ 1092804ff404Skevlo error = bus_dmamem_map(sc->sc_dmat, &q->q_rx.rge_rx_listseg, 1093804ff404Skevlo q->q_rx.rge_rx_listnseg, RGE_RX_LIST_SZ, 1094804ff404Skevlo (caddr_t *)&q->q_rx.rge_rx_list, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 1095be4e4fa3Skevlo if (error) { 1096be4e4fa3Skevlo printf("%s: can't map RX dma buffers\n", sc->sc_dev.dv_xname); 1097804ff404Skevlo bus_dmamem_free(sc->sc_dmat, &q->q_rx.rge_rx_listseg, 1098804ff404Skevlo q->q_rx.rge_rx_listnseg); 1099be4e4fa3Skevlo return (error); 1100be4e4fa3Skevlo } 1101804ff404Skevlo error = bus_dmamap_load(sc->sc_dmat, q->q_rx.rge_rx_list_map, 1102804ff404Skevlo q->q_rx.rge_rx_list, RGE_RX_LIST_SZ, NULL, BUS_DMA_NOWAIT); 1103be4e4fa3Skevlo if (error) { 1104be4e4fa3Skevlo printf("%s: can't load RX dma map\n", sc->sc_dev.dv_xname); 1105804ff404Skevlo bus_dmamap_destroy(sc->sc_dmat, q->q_rx.rge_rx_list_map); 1106be4e4fa3Skevlo bus_dmamem_unmap(sc->sc_dmat, 1107804ff404Skevlo (caddr_t)q->q_rx.rge_rx_list, RGE_RX_LIST_SZ); 1108804ff404Skevlo bus_dmamem_free(sc->sc_dmat, &q->q_rx.rge_rx_listseg, 1109804ff404Skevlo q->q_rx.rge_rx_listnseg); 1110be4e4fa3Skevlo return (error); 1111be4e4fa3Skevlo } 1112be4e4fa3Skevlo 1113be4e4fa3Skevlo /* Create DMA maps for RX buffers. */ 1114be4e4fa3Skevlo for (i = 0; i < RGE_RX_LIST_CNT; i++) { 1115be4e4fa3Skevlo error = bus_dmamap_create(sc->sc_dmat, RGE_JUMBO_FRAMELEN, 1, 11168cbc3b0aSkevlo RGE_JUMBO_FRAMELEN, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, 1117804ff404Skevlo &q->q_rx.rge_rxq[i].rxq_dmamap); 1118be4e4fa3Skevlo if (error) { 1119be4e4fa3Skevlo printf("%s: can't create DMA map for RX\n", 1120be4e4fa3Skevlo sc->sc_dev.dv_xname); 1121be4e4fa3Skevlo return (error); 1122be4e4fa3Skevlo } 1123be4e4fa3Skevlo } 1124be4e4fa3Skevlo 1125be4e4fa3Skevlo return (error); 1126be4e4fa3Skevlo } 1127be4e4fa3Skevlo 1128be4e4fa3Skevlo /* 1129be4e4fa3Skevlo * Initialize the RX descriptor and attach an mbuf cluster. 1130be4e4fa3Skevlo */ 1131be4e4fa3Skevlo int 1132804ff404Skevlo rge_newbuf(struct rge_queues *q) 1133be4e4fa3Skevlo { 1134804ff404Skevlo struct rge_softc *sc = q->q_sc; 1135be4e4fa3Skevlo struct mbuf *m; 1136be4e4fa3Skevlo struct rge_rx_desc *r; 1137be4e4fa3Skevlo struct rge_rxq *rxq; 1138be4e4fa3Skevlo bus_dmamap_t rxmap; 11392ef55e5bSdlg uint32_t cmdsts; 114081a23f33Skevlo int idx; 1141be4e4fa3Skevlo 1142da1cde29Sdlg m = MCLGETL(NULL, M_DONTWAIT, MCLBYTES); 1143be4e4fa3Skevlo if (m == NULL) 1144be4e4fa3Skevlo return (ENOBUFS); 1145be4e4fa3Skevlo 1146da1cde29Sdlg m->m_len = m->m_pkthdr.len = MCLBYTES; 11471361d169Sdlg m_adj(m, ETHER_ALIGN); 1148be4e4fa3Skevlo 1149804ff404Skevlo idx = q->q_rx.rge_rxq_prodidx; 1150804ff404Skevlo rxq = &q->q_rx.rge_rxq[idx]; 1151be4e4fa3Skevlo rxmap = rxq->rxq_dmamap; 1152be4e4fa3Skevlo 115381a23f33Skevlo if (bus_dmamap_load_mbuf(sc->sc_dmat, rxmap, m, BUS_DMA_NOWAIT)) { 115481a23f33Skevlo m_freem(m); 115581a23f33Skevlo return (ENOBUFS); 115681a23f33Skevlo } 1157be4e4fa3Skevlo 1158be4e4fa3Skevlo bus_dmamap_sync(sc->sc_dmat, rxmap, 0, rxmap->dm_mapsize, 1159be4e4fa3Skevlo BUS_DMASYNC_PREREAD); 1160be4e4fa3Skevlo 1161be4e4fa3Skevlo /* Map the segments into RX descriptors. */ 1162804ff404Skevlo r = &q->q_rx.rge_rx_list[idx]; 1163be4e4fa3Skevlo 1164be4e4fa3Skevlo rxq->rxq_mbuf = m; 1165be4e4fa3Skevlo 11662ef55e5bSdlg cmdsts = rxmap->dm_segs[0].ds_len; 11672ef55e5bSdlg if (idx == RGE_RX_LIST_CNT - 1) 11682ef55e5bSdlg cmdsts |= RGE_RDCMDSTS_EOR; 11692ef55e5bSdlg 11702ef55e5bSdlg r->hi_qword1.rx_qword4.rge_cmdsts = htole32(cmdsts); 11712ef55e5bSdlg r->hi_qword1.rx_qword4.rge_extsts = htole32(0); 117293baed4dSkevlo r->hi_qword0.rge_addr = htole64(rxmap->dm_segs[0].ds_addr); 1173be4e4fa3Skevlo 11742ef55e5bSdlg bus_dmamap_sync(sc->sc_dmat, q->q_rx.rge_rx_list_map, 11752ef55e5bSdlg idx * sizeof(struct rge_rx_desc), sizeof(struct rge_rx_desc), 11762ef55e5bSdlg BUS_DMASYNC_PREWRITE); 1177be4e4fa3Skevlo 11782ef55e5bSdlg bus_dmamap_sync(sc->sc_dmat, q->q_rx.rge_rx_list_map, 11792ef55e5bSdlg idx * sizeof(struct rge_rx_desc), sizeof(struct rge_rx_desc), 11802ef55e5bSdlg BUS_DMASYNC_POSTWRITE); 11812ef55e5bSdlg cmdsts |= RGE_RDCMDSTS_OWN; 11822ef55e5bSdlg r->hi_qword1.rx_qword4.rge_cmdsts = htole32(cmdsts); 1183804ff404Skevlo bus_dmamap_sync(sc->sc_dmat, q->q_rx.rge_rx_list_map, 1184be4e4fa3Skevlo idx * sizeof(struct rge_rx_desc), sizeof(struct rge_rx_desc), 1185be4e4fa3Skevlo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1186be4e4fa3Skevlo 1187804ff404Skevlo q->q_rx.rge_rxq_prodidx = RGE_NEXT_RX_DESC(idx); 118881a23f33Skevlo 1189be4e4fa3Skevlo return (0); 1190be4e4fa3Skevlo } 1191be4e4fa3Skevlo 1192be4e4fa3Skevlo void 1193804ff404Skevlo rge_rx_list_init(struct rge_queues *q) 1194be4e4fa3Skevlo { 1195804ff404Skevlo memset(q->q_rx.rge_rx_list, 0, RGE_RX_LIST_SZ); 1196be4e4fa3Skevlo 1197804ff404Skevlo q->q_rx.rge_rxq_prodidx = q->q_rx.rge_rxq_considx = 0; 1198e21346faSdlg q->q_rx.rge_head = NULL; 1199e21346faSdlg q->q_rx.rge_tail = &q->q_rx.rge_head; 1200be4e4fa3Skevlo 12012ef55e5bSdlg if_rxr_init(&q->q_rx.rge_rx_ring, 32, RGE_RX_LIST_CNT - 1); 1202804ff404Skevlo rge_fill_rx_ring(q); 120381a23f33Skevlo } 120481a23f33Skevlo 120581a23f33Skevlo void 1206804ff404Skevlo rge_fill_rx_ring(struct rge_queues *q) 120781a23f33Skevlo { 1208804ff404Skevlo struct if_rxring *rxr = &q->q_rx.rge_rx_ring; 120981a23f33Skevlo int slots; 121081a23f33Skevlo 121181a23f33Skevlo for (slots = if_rxr_get(rxr, RGE_RX_LIST_CNT); slots > 0; slots--) { 12128cbc3b0aSkevlo if (rge_newbuf(q)) 121381a23f33Skevlo break; 121481a23f33Skevlo } 121581a23f33Skevlo if_rxr_put(rxr, slots); 1216be4e4fa3Skevlo } 1217be4e4fa3Skevlo 1218be4e4fa3Skevlo void 1219804ff404Skevlo rge_tx_list_init(struct rge_queues *q) 1220be4e4fa3Skevlo { 1221804ff404Skevlo struct rge_softc *sc = q->q_sc; 12228cbc3b0aSkevlo struct rge_tx_desc *d; 1223be4e4fa3Skevlo int i; 1224be4e4fa3Skevlo 1225804ff404Skevlo memset(q->q_tx.rge_tx_list, 0, RGE_TX_LIST_SZ); 1226be4e4fa3Skevlo 1227be4e4fa3Skevlo for (i = 0; i < RGE_TX_LIST_CNT; i++) 1228804ff404Skevlo q->q_tx.rge_txq[i].txq_mbuf = NULL; 1229be4e4fa3Skevlo 12308cbc3b0aSkevlo d = &q->q_tx.rge_tx_list[RGE_TX_LIST_CNT - 1]; 12318cbc3b0aSkevlo d->rge_cmdsts = htole32(RGE_TDCMDSTS_EOR); 12328cbc3b0aSkevlo 1233804ff404Skevlo bus_dmamap_sync(sc->sc_dmat, q->q_tx.rge_tx_list_map, 0, 1234804ff404Skevlo q->q_tx.rge_tx_list_map->dm_mapsize, 1235be4e4fa3Skevlo BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1236be4e4fa3Skevlo 1237804ff404Skevlo q->q_tx.rge_txq_prodidx = q->q_tx.rge_txq_considx = 0; 1238be4e4fa3Skevlo } 1239be4e4fa3Skevlo 1240be4e4fa3Skevlo int 1241804ff404Skevlo rge_rxeof(struct rge_queues *q) 1242be4e4fa3Skevlo { 1243804ff404Skevlo struct rge_softc *sc = q->q_sc; 1244be4e4fa3Skevlo struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 1245be4e4fa3Skevlo struct mbuf *m; 1246be4e4fa3Skevlo struct ifnet *ifp = &sc->sc_arpcom.ac_if; 1247804ff404Skevlo struct if_rxring *rxr = &q->q_rx.rge_rx_ring; 1248be4e4fa3Skevlo struct rge_rx_desc *cur_rx; 1249be4e4fa3Skevlo struct rge_rxq *rxq; 1250be4e4fa3Skevlo uint32_t rxstat, extsts; 1251e21346faSdlg int i, mlen, rx = 0; 12522ef55e5bSdlg int cons; 1253be4e4fa3Skevlo 12542ef55e5bSdlg i = cons = q->q_rx.rge_rxq_considx; 1255be4e4fa3Skevlo 12562ef55e5bSdlg while (if_rxr_inuse(rxr) > 0) { 1257804ff404Skevlo cur_rx = &q->q_rx.rge_rx_list[i]; 12582ef55e5bSdlg 12592ef55e5bSdlg bus_dmamap_sync(sc->sc_dmat, q->q_rx.rge_rx_list_map, 12602ef55e5bSdlg i * sizeof(*cur_rx), sizeof(*cur_rx), 12612ef55e5bSdlg BUS_DMASYNC_POSTREAD); 126293baed4dSkevlo rxstat = letoh32(cur_rx->hi_qword1.rx_qword4.rge_cmdsts); 12632ef55e5bSdlg if (rxstat & RGE_RDCMDSTS_OWN) { 12642ef55e5bSdlg bus_dmamap_sync(sc->sc_dmat, q->q_rx.rge_rx_list_map, 12652ef55e5bSdlg i * sizeof(*cur_rx), sizeof(*cur_rx), 12662ef55e5bSdlg BUS_DMASYNC_PREREAD); 12678cbc3b0aSkevlo break; 12682ef55e5bSdlg } 12698cbc3b0aSkevlo 1270804ff404Skevlo rxq = &q->q_rx.rge_rxq[i]; 1271be4e4fa3Skevlo bus_dmamap_sync(sc->sc_dmat, rxq->rxq_dmamap, 0, 1272be4e4fa3Skevlo rxq->rxq_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); 1273be4e4fa3Skevlo bus_dmamap_unload(sc->sc_dmat, rxq->rxq_dmamap); 12742ef55e5bSdlg m = rxq->rxq_mbuf; 12752ef55e5bSdlg rxq->rxq_mbuf = NULL; 1276be4e4fa3Skevlo 12772ef55e5bSdlg i = RGE_NEXT_RX_DESC(i); 12782ef55e5bSdlg if_rxr_put(rxr, 1); 12792ef55e5bSdlg rx = 1; 12802ef55e5bSdlg 1281e21346faSdlg if (ISSET(rxstat, RGE_RDCMDSTS_SOF)) { 1282e21346faSdlg if (q->q_rx.rge_head != NULL) { 128367d345deSkevlo ifp->if_ierrors++; 1284e21346faSdlg m_freem(q->q_rx.rge_head); 1285e21346faSdlg q->q_rx.rge_tail = &q->q_rx.rge_head; 1286e21346faSdlg } 1287e21346faSdlg 1288e21346faSdlg m->m_pkthdr.len = 0; 1289e21346faSdlg } else if (q->q_rx.rge_head == NULL) { 129067d345deSkevlo m_freem(m); 1291be4e4fa3Skevlo continue; 1292e21346faSdlg } else 1293e21346faSdlg CLR(m->m_flags, M_PKTHDR); 1294e21346faSdlg 1295e21346faSdlg *q->q_rx.rge_tail = m; 1296e21346faSdlg q->q_rx.rge_tail = &m->m_next; 1297e21346faSdlg 1298e21346faSdlg mlen = rxstat & RGE_RDCMDSTS_FRAGLEN; 1299e21346faSdlg m->m_len = mlen; 1300e21346faSdlg 1301e21346faSdlg m = q->q_rx.rge_head; 1302e21346faSdlg m->m_pkthdr.len += mlen; 1303be4e4fa3Skevlo 1304be4e4fa3Skevlo if (rxstat & RGE_RDCMDSTS_RXERRSUM) { 1305be4e4fa3Skevlo ifp->if_ierrors++; 130667d345deSkevlo m_freem(m); 1307e21346faSdlg q->q_rx.rge_head = NULL; 1308e21346faSdlg q->q_rx.rge_tail = &q->q_rx.rge_head; 1309be4e4fa3Skevlo continue; 1310be4e4fa3Skevlo } 1311be4e4fa3Skevlo 1312e21346faSdlg if (!ISSET(rxstat, RGE_RDCMDSTS_EOF)) 1313e21346faSdlg continue; 1314e21346faSdlg 1315e21346faSdlg q->q_rx.rge_head = NULL; 1316e21346faSdlg q->q_rx.rge_tail = &q->q_rx.rge_head; 1317e21346faSdlg 1318e21346faSdlg m_adj(m, -ETHER_CRC_LEN); 13192ef55e5bSdlg 13202ef55e5bSdlg extsts = letoh32(cur_rx->hi_qword1.rx_qword4.rge_extsts); 1321be4e4fa3Skevlo 1322be4e4fa3Skevlo /* Check IP header checksum. */ 132393baed4dSkevlo if (!(extsts & RGE_RDEXTSTS_IPCSUMERR) && 1324be4e4fa3Skevlo (extsts & RGE_RDEXTSTS_IPV4)) 1325be4e4fa3Skevlo m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK; 1326be4e4fa3Skevlo 1327be4e4fa3Skevlo /* Check TCP/UDP checksum. */ 1328be4e4fa3Skevlo if ((extsts & (RGE_RDEXTSTS_IPV4 | RGE_RDEXTSTS_IPV6)) && 132993baed4dSkevlo (((extsts & RGE_RDEXTSTS_TCPPKT) && 133093baed4dSkevlo !(extsts & RGE_RDEXTSTS_TCPCSUMERR)) || 133193baed4dSkevlo ((extsts & RGE_RDEXTSTS_UDPPKT) && 133293baed4dSkevlo !(extsts & RGE_RDEXTSTS_UDPCSUMERR)))) 1333be4e4fa3Skevlo m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK | 1334be4e4fa3Skevlo M_UDP_CSUM_IN_OK; 1335be4e4fa3Skevlo 1336be4e4fa3Skevlo #if NVLAN > 0 1337be4e4fa3Skevlo if (extsts & RGE_RDEXTSTS_VTAG) { 1338be4e4fa3Skevlo m->m_pkthdr.ether_vtag = 1339be4e4fa3Skevlo ntohs(extsts & RGE_RDEXTSTS_VLAN_MASK); 1340be4e4fa3Skevlo m->m_flags |= M_VLANTAG; 1341be4e4fa3Skevlo } 1342be4e4fa3Skevlo #endif 1343be4e4fa3Skevlo 1344be4e4fa3Skevlo ml_enqueue(&ml, m); 1345be4e4fa3Skevlo } 1346be4e4fa3Skevlo 13472ef55e5bSdlg if (!rx) 13482ef55e5bSdlg return (0); 13492ef55e5bSdlg 13502ef55e5bSdlg if (i >= cons) { 13512ef55e5bSdlg bus_dmamap_sync(sc->sc_dmat, q->q_rx.rge_rx_list_map, 13522ef55e5bSdlg cons * sizeof(*cur_rx), (i - cons) * sizeof(*cur_rx), 13532ef55e5bSdlg BUS_DMASYNC_POSTWRITE); 13542ef55e5bSdlg } else { 13552ef55e5bSdlg bus_dmamap_sync(sc->sc_dmat, q->q_rx.rge_rx_list_map, 13562ef55e5bSdlg cons * sizeof(*cur_rx), 13572ef55e5bSdlg (RGE_RX_LIST_CNT - cons) * sizeof(*cur_rx), 13582ef55e5bSdlg BUS_DMASYNC_POSTWRITE); 13592ef55e5bSdlg if (i > 0) { 13602ef55e5bSdlg bus_dmamap_sync(sc->sc_dmat, q->q_rx.rge_rx_list_map, 13612ef55e5bSdlg 0, i * sizeof(*cur_rx), 13622ef55e5bSdlg BUS_DMASYNC_POSTWRITE); 13632ef55e5bSdlg } 13642ef55e5bSdlg } 13652ef55e5bSdlg 136661f1e1c4Skevlo if (ifiq_input(&ifp->if_rcv, &ml)) 136761f1e1c4Skevlo if_rxr_livelocked(rxr); 136861f1e1c4Skevlo 1369804ff404Skevlo q->q_rx.rge_rxq_considx = i; 1370804ff404Skevlo rge_fill_rx_ring(q); 1371be4e4fa3Skevlo 13722ef55e5bSdlg return (1); 1373be4e4fa3Skevlo } 1374be4e4fa3Skevlo 1375be4e4fa3Skevlo int 1376804ff404Skevlo rge_txeof(struct rge_queues *q) 1377be4e4fa3Skevlo { 1378804ff404Skevlo struct rge_softc *sc = q->q_sc; 1379be4e4fa3Skevlo struct ifnet *ifp = &sc->sc_arpcom.ac_if; 1380be4e4fa3Skevlo struct rge_txq *txq; 1381be4e4fa3Skevlo uint32_t txstat; 1382c6c75c18Sdlg int cons, prod, cur, idx; 1383be4e4fa3Skevlo int free = 0; 1384be4e4fa3Skevlo 1385804ff404Skevlo prod = q->q_tx.rge_txq_prodidx; 1386804ff404Skevlo cons = q->q_tx.rge_txq_considx; 1387be4e4fa3Skevlo 1388c6c75c18Sdlg idx = cons; 1389c6c75c18Sdlg while (idx != prod) { 1390c6c75c18Sdlg txq = &q->q_tx.rge_txq[idx]; 1391c6c75c18Sdlg cur = txq->txq_descidx; 1392be4e4fa3Skevlo 1393c6c75c18Sdlg rge_tx_list_sync(sc, q, cur, 1, BUS_DMASYNC_POSTREAD); 1394c6c75c18Sdlg txstat = q->q_tx.rge_tx_list[cur].rge_cmdsts; 1395c6c75c18Sdlg rge_tx_list_sync(sc, q, cur, 1, BUS_DMASYNC_PREREAD); 1396c6c75c18Sdlg if (ISSET(txstat, htole32(RGE_TDCMDSTS_OWN))) { 1397be4e4fa3Skevlo free = 2; 1398be4e4fa3Skevlo break; 1399be4e4fa3Skevlo } 1400be4e4fa3Skevlo 1401be4e4fa3Skevlo bus_dmamap_sync(sc->sc_dmat, txq->txq_dmamap, 0, 1402be4e4fa3Skevlo txq->txq_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE); 1403be4e4fa3Skevlo bus_dmamap_unload(sc->sc_dmat, txq->txq_dmamap); 1404be4e4fa3Skevlo m_freem(txq->txq_mbuf); 1405be4e4fa3Skevlo txq->txq_mbuf = NULL; 1406be4e4fa3Skevlo 1407c6c75c18Sdlg if (ISSET(txstat, 1408c6c75c18Sdlg htole32(RGE_TDCMDSTS_EXCESSCOLL | RGE_TDCMDSTS_COLL))) 1409be4e4fa3Skevlo ifp->if_collisions++; 1410c6c75c18Sdlg if (ISSET(txstat, htole32(RGE_TDCMDSTS_TXERR))) 1411be4e4fa3Skevlo ifp->if_oerrors++; 1412be4e4fa3Skevlo 1413c6c75c18Sdlg idx = RGE_NEXT_TX_DESC(cur); 1414be4e4fa3Skevlo free = 1; 1415be4e4fa3Skevlo } 1416be4e4fa3Skevlo 1417be4e4fa3Skevlo if (free == 0) 1418be4e4fa3Skevlo return (0); 1419be4e4fa3Skevlo 1420c6c75c18Sdlg if (idx >= cons) { 1421c6c75c18Sdlg rge_tx_list_sync(sc, q, cons, idx - cons, 1422c6c75c18Sdlg BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1423c6c75c18Sdlg } else { 1424c6c75c18Sdlg rge_tx_list_sync(sc, q, cons, RGE_TX_LIST_CNT - cons, 1425c6c75c18Sdlg BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1426c6c75c18Sdlg rge_tx_list_sync(sc, q, 0, idx, 1427c6c75c18Sdlg BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1428c6c75c18Sdlg } 1429c6c75c18Sdlg 1430c6c75c18Sdlg q->q_tx.rge_txq_considx = idx; 1431be4e4fa3Skevlo 1432be4e4fa3Skevlo if (ifq_is_oactive(&ifp->if_snd)) 1433be4e4fa3Skevlo ifq_restart(&ifp->if_snd); 1434be4e4fa3Skevlo else if (free == 2) 1435be4e4fa3Skevlo ifq_serialize(&ifp->if_snd, &sc->sc_task); 1436be4e4fa3Skevlo else 1437be4e4fa3Skevlo ifp->if_timer = 0; 1438be4e4fa3Skevlo 1439be4e4fa3Skevlo return (1); 1440be4e4fa3Skevlo } 1441be4e4fa3Skevlo 1442be4e4fa3Skevlo void 1443be4e4fa3Skevlo rge_reset(struct rge_softc *sc) 1444be4e4fa3Skevlo { 1445be4e4fa3Skevlo int i; 1446be4e4fa3Skevlo 14478cbc3b0aSkevlo RGE_CLRBIT_4(sc, RGE_RXCFG, RGE_RXCFG_ALLPHYS | RGE_RXCFG_INDIV | 14488cbc3b0aSkevlo RGE_RXCFG_MULTI | RGE_RXCFG_BROAD | RGE_RXCFG_RUNT | 14498cbc3b0aSkevlo RGE_RXCFG_ERRPKT); 14508cbc3b0aSkevlo 1451be4e4fa3Skevlo /* Enable RXDV gate. */ 1452be4e4fa3Skevlo RGE_SETBIT_1(sc, RGE_PPSW, 0x08); 1453be4e4fa3Skevlo DELAY(2000); 1454be4e4fa3Skevlo 14558cbc3b0aSkevlo RGE_SETBIT_1(sc, RGE_CMD, RGE_CMD_STOPREQ); 145674263a62Skevlo if (sc->rge_type != MAC_CFG2_8126) { 14578cbc3b0aSkevlo for (i = 0; i < 20; i++) { 14588cbc3b0aSkevlo DELAY(10); 14598cbc3b0aSkevlo if (!(RGE_READ_1(sc, RGE_CMD) & RGE_CMD_STOPREQ)) 14608cbc3b0aSkevlo break; 14618cbc3b0aSkevlo } 146274263a62Skevlo } 14638cbc3b0aSkevlo 146481a23f33Skevlo for (i = 0; i < 3000; i++) { 146581a23f33Skevlo DELAY(50); 1466be4e4fa3Skevlo if ((RGE_READ_1(sc, RGE_MCUCMD) & (RGE_MCUCMD_RXFIFO_EMPTY | 1467be4e4fa3Skevlo RGE_MCUCMD_TXFIFO_EMPTY)) == (RGE_MCUCMD_RXFIFO_EMPTY | 1468be4e4fa3Skevlo RGE_MCUCMD_TXFIFO_EMPTY)) 1469be4e4fa3Skevlo break; 1470be4e4fa3Skevlo } 14718cbc3b0aSkevlo if (sc->rge_type != MAC_CFG3) { 147281a23f33Skevlo for (i = 0; i < 3000; i++) { 147381a23f33Skevlo DELAY(50); 147481a23f33Skevlo if ((RGE_READ_2(sc, RGE_IM) & 0x0103) == 0x0103) 147581a23f33Skevlo break; 147681a23f33Skevlo } 147781a23f33Skevlo } 147881a23f33Skevlo 147981a23f33Skevlo DELAY(2000); 1480be4e4fa3Skevlo 1481be4e4fa3Skevlo /* Soft reset. */ 1482be4e4fa3Skevlo RGE_WRITE_1(sc, RGE_CMD, RGE_CMD_RESET); 1483be4e4fa3Skevlo 1484be4e4fa3Skevlo for (i = 0; i < RGE_TIMEOUT; i++) { 1485be4e4fa3Skevlo DELAY(100); 1486be4e4fa3Skevlo if (!(RGE_READ_1(sc, RGE_CMD) & RGE_CMD_RESET)) 1487be4e4fa3Skevlo break; 1488be4e4fa3Skevlo } 1489be4e4fa3Skevlo if (i == RGE_TIMEOUT) 1490be4e4fa3Skevlo printf("%s: reset never completed!\n", sc->sc_dev.dv_xname); 1491be4e4fa3Skevlo } 1492be4e4fa3Skevlo 1493be4e4fa3Skevlo void 1494be4e4fa3Skevlo rge_iff(struct rge_softc *sc) 1495be4e4fa3Skevlo { 1496be4e4fa3Skevlo struct ifnet *ifp = &sc->sc_arpcom.ac_if; 1497be4e4fa3Skevlo struct arpcom *ac = &sc->sc_arpcom; 1498be4e4fa3Skevlo struct ether_multi *enm; 1499be4e4fa3Skevlo struct ether_multistep step; 1500be4e4fa3Skevlo uint32_t hashes[2]; 1501be4e4fa3Skevlo uint32_t rxfilt; 1502be4e4fa3Skevlo int h = 0; 1503be4e4fa3Skevlo 1504be4e4fa3Skevlo rxfilt = RGE_READ_4(sc, RGE_RXCFG); 1505be4e4fa3Skevlo rxfilt &= ~(RGE_RXCFG_ALLPHYS | RGE_RXCFG_MULTI); 1506be4e4fa3Skevlo ifp->if_flags &= ~IFF_ALLMULTI; 1507be4e4fa3Skevlo 1508be4e4fa3Skevlo /* 1509be4e4fa3Skevlo * Always accept frames destined to our station address. 1510be4e4fa3Skevlo * Always accept broadcast frames. 1511be4e4fa3Skevlo */ 1512be4e4fa3Skevlo rxfilt |= RGE_RXCFG_INDIV | RGE_RXCFG_BROAD; 1513be4e4fa3Skevlo 1514be4e4fa3Skevlo if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { 1515be4e4fa3Skevlo ifp->if_flags |= IFF_ALLMULTI; 1516be4e4fa3Skevlo rxfilt |= RGE_RXCFG_MULTI; 1517be4e4fa3Skevlo if (ifp->if_flags & IFF_PROMISC) 1518be4e4fa3Skevlo rxfilt |= RGE_RXCFG_ALLPHYS; 1519be4e4fa3Skevlo hashes[0] = hashes[1] = 0xffffffff; 1520be4e4fa3Skevlo } else { 1521be4e4fa3Skevlo rxfilt |= RGE_RXCFG_MULTI; 1522be4e4fa3Skevlo /* Program new filter. */ 1523be4e4fa3Skevlo memset(hashes, 0, sizeof(hashes)); 1524be4e4fa3Skevlo 1525be4e4fa3Skevlo ETHER_FIRST_MULTI(step, ac, enm); 1526be4e4fa3Skevlo while (enm != NULL) { 1527be4e4fa3Skevlo h = ether_crc32_be(enm->enm_addrlo, 1528be4e4fa3Skevlo ETHER_ADDR_LEN) >> 26; 1529be4e4fa3Skevlo 1530be4e4fa3Skevlo if (h < 32) 1531be4e4fa3Skevlo hashes[0] |= (1 << h); 1532be4e4fa3Skevlo else 1533be4e4fa3Skevlo hashes[1] |= (1 << (h - 32)); 1534be4e4fa3Skevlo 1535be4e4fa3Skevlo ETHER_NEXT_MULTI(step, enm); 1536be4e4fa3Skevlo } 1537be4e4fa3Skevlo } 1538be4e4fa3Skevlo 1539be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_RXCFG, rxfilt); 1540be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_MAR0, swap32(hashes[1])); 1541be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_MAR4, swap32(hashes[0])); 1542be4e4fa3Skevlo } 1543be4e4fa3Skevlo 1544be4e4fa3Skevlo void 15458cbc3b0aSkevlo rge_chipinit(struct rge_softc *sc) 15468cbc3b0aSkevlo { 15478cbc3b0aSkevlo rge_exit_oob(sc); 15488cbc3b0aSkevlo rge_set_phy_power(sc, 1); 15498cbc3b0aSkevlo rge_hw_init(sc); 15508cbc3b0aSkevlo rge_hw_reset(sc); 15518cbc3b0aSkevlo } 15528cbc3b0aSkevlo 15538cbc3b0aSkevlo void 1554be4e4fa3Skevlo rge_set_phy_power(struct rge_softc *sc, int on) 1555be4e4fa3Skevlo { 1556be4e4fa3Skevlo int i; 1557be4e4fa3Skevlo 1558be4e4fa3Skevlo if (on) { 1559be4e4fa3Skevlo RGE_SETBIT_1(sc, RGE_PMCH, 0xc0); 1560be4e4fa3Skevlo 1561be4e4fa3Skevlo rge_write_phy(sc, 0, MII_BMCR, BMCR_AUTOEN); 1562be4e4fa3Skevlo 1563be4e4fa3Skevlo for (i = 0; i < RGE_TIMEOUT; i++) { 15641943b9bcSkrw if ((rge_read_phy_ocp(sc, 0xa420) & 0x0007) == 3) 1565be4e4fa3Skevlo break; 1566be4e4fa3Skevlo DELAY(1000); 1567be4e4fa3Skevlo } 156881a23f33Skevlo } else { 1569be4e4fa3Skevlo rge_write_phy(sc, 0, MII_BMCR, BMCR_AUTOEN | BMCR_PDOWN); 157081a23f33Skevlo RGE_CLRBIT_1(sc, RGE_PMCH, 0x80); 157181a23f33Skevlo RGE_CLRBIT_1(sc, RGE_PPSW, 0x40); 157281a23f33Skevlo } 1573be4e4fa3Skevlo } 1574be4e4fa3Skevlo 1575be4e4fa3Skevlo void 15768cbc3b0aSkevlo rge_ephy_config(struct rge_softc *sc) 1577be4e4fa3Skevlo { 157881a23f33Skevlo switch (sc->rge_type) { 157981a23f33Skevlo case MAC_CFG3: 15808cbc3b0aSkevlo rge_ephy_config_mac_cfg3(sc); 158181a23f33Skevlo break; 158281a23f33Skevlo case MAC_CFG5: 15838cbc3b0aSkevlo rge_ephy_config_mac_cfg5(sc); 158481a23f33Skevlo break; 158581a23f33Skevlo default: 158674263a62Skevlo break; /* Nothing to do. */ 1587be4e4fa3Skevlo } 1588be4e4fa3Skevlo } 1589be4e4fa3Skevlo 159081a23f33Skevlo void 15918cbc3b0aSkevlo rge_ephy_config_mac_cfg3(struct rge_softc *sc) 159281a23f33Skevlo { 159381a23f33Skevlo uint16_t val; 159481a23f33Skevlo int i; 159581a23f33Skevlo 1596be4e4fa3Skevlo for (i = 0; i < nitems(rtl8125_mac_cfg3_ephy); i++) 1597be4e4fa3Skevlo rge_write_ephy(sc, rtl8125_mac_cfg3_ephy[i].reg, 1598be4e4fa3Skevlo rtl8125_mac_cfg3_ephy[i].val); 1599be4e4fa3Skevlo 160081a23f33Skevlo val = rge_read_ephy(sc, 0x002a) & ~0x7000; 160181a23f33Skevlo rge_write_ephy(sc, 0x002a, val | 0x3000); 160281a23f33Skevlo RGE_EPHY_CLRBIT(sc, 0x0019, 0x0040); 160381a23f33Skevlo RGE_EPHY_SETBIT(sc, 0x001b, 0x0e00); 160481a23f33Skevlo RGE_EPHY_CLRBIT(sc, 0x001b, 0x7000); 160581a23f33Skevlo rge_write_ephy(sc, 0x0002, 0x6042); 160681a23f33Skevlo rge_write_ephy(sc, 0x0006, 0x0014); 160781a23f33Skevlo val = rge_read_ephy(sc, 0x006a) & ~0x7000; 160881a23f33Skevlo rge_write_ephy(sc, 0x006a, val | 0x3000); 160981a23f33Skevlo RGE_EPHY_CLRBIT(sc, 0x0059, 0x0040); 161081a23f33Skevlo RGE_EPHY_SETBIT(sc, 0x005b, 0x0e00); 161181a23f33Skevlo RGE_EPHY_CLRBIT(sc, 0x005b, 0x7000); 161281a23f33Skevlo rge_write_ephy(sc, 0x0042, 0x6042); 161381a23f33Skevlo rge_write_ephy(sc, 0x0046, 0x0014); 16148cbc3b0aSkevlo } 16158cbc3b0aSkevlo 16168cbc3b0aSkevlo void 16178cbc3b0aSkevlo rge_ephy_config_mac_cfg5(struct rge_softc *sc) 16188cbc3b0aSkevlo { 16198cbc3b0aSkevlo int i; 16208cbc3b0aSkevlo 16218cbc3b0aSkevlo for (i = 0; i < nitems(rtl8125_mac_cfg5_ephy); i++) 16228cbc3b0aSkevlo rge_write_ephy(sc, rtl8125_mac_cfg5_ephy[i].reg, 16238cbc3b0aSkevlo rtl8125_mac_cfg5_ephy[i].val); 16248cbc3b0aSkevlo } 16258cbc3b0aSkevlo 16268cbc3b0aSkevlo int 16278cbc3b0aSkevlo rge_phy_config(struct rge_softc *sc) 16288cbc3b0aSkevlo { 16298cbc3b0aSkevlo int i; 16308cbc3b0aSkevlo 16318cbc3b0aSkevlo rge_ephy_config(sc); 16328cbc3b0aSkevlo 16338cbc3b0aSkevlo /* PHY reset. */ 16348cbc3b0aSkevlo rge_write_phy(sc, 0, MII_ANAR, 16358cbc3b0aSkevlo rge_read_phy(sc, 0, MII_ANAR) & 16368cbc3b0aSkevlo ~(ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10)); 16378cbc3b0aSkevlo rge_write_phy(sc, 0, MII_100T2CR, 16388cbc3b0aSkevlo rge_read_phy(sc, 0, MII_100T2CR) & 16398cbc3b0aSkevlo ~(GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX)); 164074263a62Skevlo if (sc->rge_type == MAC_CFG2_8126) 164174263a62Skevlo RGE_PHY_CLRBIT(sc, 0xa5d4, RGE_ADV_2500TFDX | RGE_ADV_5000TFDX); 164274263a62Skevlo else 16438cbc3b0aSkevlo RGE_PHY_CLRBIT(sc, 0xa5d4, RGE_ADV_2500TFDX); 16448cbc3b0aSkevlo rge_write_phy(sc, 0, MII_BMCR, BMCR_RESET | BMCR_AUTOEN | 16458cbc3b0aSkevlo BMCR_STARTNEG); 16468cbc3b0aSkevlo for (i = 0; i < 2500; i++) { 16478cbc3b0aSkevlo if (!(rge_read_phy(sc, 0, MII_BMCR) & BMCR_RESET)) 16488cbc3b0aSkevlo break; 16498cbc3b0aSkevlo DELAY(1000); 16508cbc3b0aSkevlo } 16518cbc3b0aSkevlo if (i == 2500) { 16528cbc3b0aSkevlo printf("%s: PHY reset failed\n", sc->sc_dev.dv_xname); 16538cbc3b0aSkevlo return (ETIMEDOUT); 16548cbc3b0aSkevlo } 16558cbc3b0aSkevlo 16568cbc3b0aSkevlo /* Read microcode version. */ 16578cbc3b0aSkevlo rge_write_phy_ocp(sc, 0xa436, 0x801e); 16588cbc3b0aSkevlo sc->rge_mcodever = rge_read_phy_ocp(sc, 0xa438); 16598cbc3b0aSkevlo 16608cbc3b0aSkevlo switch (sc->rge_type) { 166174263a62Skevlo case MAC_CFG2_8126: 166274263a62Skevlo rge_phy_config_mac_cfg2_8126(sc); 166374263a62Skevlo break; 16648cbc3b0aSkevlo case MAC_CFG3: 16658cbc3b0aSkevlo rge_phy_config_mac_cfg3(sc); 16668cbc3b0aSkevlo break; 16678cbc3b0aSkevlo case MAC_CFG5: 16688cbc3b0aSkevlo rge_phy_config_mac_cfg5(sc); 16698cbc3b0aSkevlo break; 16708cbc3b0aSkevlo default: 16718cbc3b0aSkevlo break; /* Can't happen. */ 16728cbc3b0aSkevlo } 16738cbc3b0aSkevlo 16748cbc3b0aSkevlo RGE_PHY_CLRBIT(sc, 0xa5b4, 0x8000); 16758cbc3b0aSkevlo 16768cbc3b0aSkevlo /* Disable EEE. */ 16778cbc3b0aSkevlo RGE_MAC_CLRBIT(sc, 0xe040, 0x0003); 16788cbc3b0aSkevlo if (sc->rge_type == MAC_CFG3) { 16798cbc3b0aSkevlo RGE_MAC_CLRBIT(sc, 0xeb62, 0x0006); 16808cbc3b0aSkevlo RGE_PHY_CLRBIT(sc, 0xa432, 0x0010); 168174263a62Skevlo } else if (sc->rge_type == MAC_CFG5) 168274263a62Skevlo RGE_PHY_SETBIT(sc, 0xa432, 0x0010); 168374263a62Skevlo 16848cbc3b0aSkevlo RGE_PHY_CLRBIT(sc, 0xa5d0, 0x0006); 16858cbc3b0aSkevlo RGE_PHY_CLRBIT(sc, 0xa6d4, 0x0001); 168674263a62Skevlo if (sc->rge_type == MAC_CFG2_8126) 168774263a62Skevlo RGE_PHY_CLRBIT(sc, 0xa6d4, 0x0002); 16888cbc3b0aSkevlo RGE_PHY_CLRBIT(sc, 0xa6d8, 0x0010); 16898cbc3b0aSkevlo RGE_PHY_CLRBIT(sc, 0xa428, 0x0080); 16908cbc3b0aSkevlo RGE_PHY_CLRBIT(sc, 0xa4a2, 0x0200); 16918cbc3b0aSkevlo 169274263a62Skevlo /* Disable advanced EEE. */ 16938cbc3b0aSkevlo RGE_MAC_CLRBIT(sc, 0xe052, 0x0001); 16948cbc3b0aSkevlo RGE_PHY_CLRBIT(sc, 0xa442, 0x3000); 16958cbc3b0aSkevlo RGE_PHY_CLRBIT(sc, 0xa430, 0x8000); 16968cbc3b0aSkevlo 16978cbc3b0aSkevlo return (0); 16988cbc3b0aSkevlo } 16998cbc3b0aSkevlo 17008cbc3b0aSkevlo void 170174263a62Skevlo rge_phy_config_mac_cfg2_8126(struct rge_softc *sc) 170274263a62Skevlo { 170374263a62Skevlo uint16_t val; 170474263a62Skevlo int i; 170574263a62Skevlo static const uint16_t mac_cfg2_a438_value[] = 170674263a62Skevlo { 0x0044, 0x00a8, 0x00d6, 0x00ec, 0x00f6, 0x00fc, 0x00fe, 170774263a62Skevlo 0x00fe, 0x00bc, 0x0058, 0x002a, 0x003f, 0x3f02, 0x023c, 170874263a62Skevlo 0x3b0a, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000 }; 170974263a62Skevlo 171074263a62Skevlo static const uint16_t mac_cfg2_b87e_value[] = 171174263a62Skevlo { 0x03ed, 0x03ff, 0x0009, 0x03fe, 0x000b, 0x0021, 0x03f7, 171274263a62Skevlo 0x03b8, 0x03e0, 0x0049, 0x0049, 0x03e0, 0x03b8, 0x03f7, 171374263a62Skevlo 0x0021, 0x000b, 0x03fe, 0x0009, 0x03ff, 0x03ed, 0x000e, 171474263a62Skevlo 0x03fe, 0x03ed, 0x0006, 0x001a, 0x03f1, 0x03d8, 0x0023, 171574263a62Skevlo 0x0054, 0x0322, 0x00dd, 0x03ab, 0x03dc, 0x0027, 0x000e, 171674263a62Skevlo 0x03e5, 0x03f9, 0x0012, 0x0001, 0x03f1 }; 171774263a62Skevlo 171874263a62Skevlo rge_phy_config_mcu(sc, RGE_MAC_CFG2_8126_MCODE_VER); 171974263a62Skevlo 172074263a62Skevlo RGE_PHY_SETBIT(sc, 0xa442, 0x0800); 172174263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x80bf); 172274263a62Skevlo val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00; 172374263a62Skevlo rge_write_phy_ocp(sc, 0xa438, val | 0xed00); 172474263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x80cd); 172574263a62Skevlo val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00; 172674263a62Skevlo rge_write_phy_ocp(sc, 0xa438, val | 0x1000); 172774263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x80d1); 172874263a62Skevlo val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00; 172974263a62Skevlo rge_write_phy_ocp(sc, 0xa438, val | 0xc800); 173074263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x80d4); 173174263a62Skevlo val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00; 173274263a62Skevlo rge_write_phy_ocp(sc, 0xa438, val | 0xc800); 173374263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x80e1); 173474263a62Skevlo rge_write_phy_ocp(sc, 0xa438, 0x10cc); 173574263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x80e5); 173674263a62Skevlo rge_write_phy_ocp(sc, 0xa438, 0x4f0c); 173774263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8387); 173874263a62Skevlo val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00; 173974263a62Skevlo rge_write_phy_ocp(sc, 0xa438, val | 0x4700); 174074263a62Skevlo val = rge_read_phy_ocp(sc, 0xa80c) & ~0x00c0; 174174263a62Skevlo rge_write_phy_ocp(sc, 0xa80c, val | 0x0080); 174274263a62Skevlo RGE_PHY_CLRBIT(sc, 0xac90, 0x0010); 174374263a62Skevlo RGE_PHY_CLRBIT(sc, 0xad2c, 0x8000); 174474263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8321); 174574263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 174674263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x1100); 174774263a62Skevlo RGE_PHY_SETBIT(sc, 0xacf8, 0x000c); 174874263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8183); 174974263a62Skevlo val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00; 175074263a62Skevlo rge_write_phy_ocp(sc, 0xa438, val | 0x5900); 175174263a62Skevlo RGE_PHY_SETBIT(sc, 0xad94, 0x0020); 175274263a62Skevlo RGE_PHY_CLRBIT(sc, 0xa654, 0x0800); 175374263a62Skevlo RGE_PHY_SETBIT(sc, 0xb648, 0x4000); 175474263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x839e); 175574263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 175674263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x2f00); 175774263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x83f2); 175874263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 175974263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0800); 176074263a62Skevlo RGE_PHY_SETBIT(sc, 0xada0, 0x0002); 176174263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x80f3); 176274263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 176374263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x9900); 176474263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8126); 176574263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 176674263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0xc100); 176774263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x893a); 176874263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x8080); 176974263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8647); 177074263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 177174263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0xe600); 177274263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x862c); 177374263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 177474263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x1200); 177574263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x864a); 177674263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 177774263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0xe600); 177874263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x80a0); 177974263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0xbcbc); 178074263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x805e); 178174263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0xbcbc); 178274263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8056); 178374263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x3077); 178474263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8058); 178574263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 178674263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x5a00); 178774263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8098); 178874263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x3077); 178974263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x809a); 179074263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 179174263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x5a00); 179274263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8052); 179374263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x3733); 179474263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8094); 179574263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x3733); 179674263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x807f); 179774263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x7c75); 179874263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x803d); 179974263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x7c75); 180074263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8036); 180174263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 180274263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x3000); 180374263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8078); 180474263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 180574263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x3000); 180674263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8031); 180774263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 180874263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x3300); 180974263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8073); 181074263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 181174263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x3300); 181274263a62Skevlo val = rge_read_phy_ocp(sc, 0xae06) & ~0xfc00; 181374263a62Skevlo rge_write_phy_ocp(sc, 0xae06, val | 0x7c00); 181474263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x89D1); 181574263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x0004); 181674263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8fbd); 181774263a62Skevlo val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00; 181874263a62Skevlo rge_write_phy_ocp(sc, 0xa438, val | 0x0a00); 181974263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8fbe); 182074263a62Skevlo rge_write_phy_ocp(sc, 0xa438, 0x0d09); 182174263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x89cd); 182274263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x0f0f); 182374263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x89cf); 182474263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x0f0f); 182574263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x83a4); 182674263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x6600); 182774263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x83a6); 182874263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x6601); 182974263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x83c0); 183074263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x6600); 183174263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x83c2); 183274263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x6601); 183374263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8414); 183474263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x6600); 183574263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8416); 183674263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x6601); 183774263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x83f8); 183874263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x6600); 183974263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x83fa); 184074263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x6601); 184174263a62Skevlo 184274263a62Skevlo rge_patch_phy_mcu(sc, 1); 184374263a62Skevlo val = rge_read_phy_ocp(sc, 0xbd96) & ~0x1f00; 184474263a62Skevlo rge_write_phy_ocp(sc, 0xbd96, val | 0x1000); 184574263a62Skevlo val = rge_read_phy_ocp(sc, 0xbf1c) & ~0x0007; 184674263a62Skevlo rge_write_phy_ocp(sc, 0xbf1c, val | 0x0007); 184774263a62Skevlo RGE_PHY_CLRBIT(sc, 0xbfbe, 0x8000); 184874263a62Skevlo val = rge_read_phy_ocp(sc, 0xbf40) & ~0x0380; 184974263a62Skevlo rge_write_phy_ocp(sc, 0xbf40, val | 0x0280); 185074263a62Skevlo val = rge_read_phy_ocp(sc, 0xbf90) & ~0x0080; 185174263a62Skevlo rge_write_phy_ocp(sc, 0xbf90, val | 0x0060); 185274263a62Skevlo val = rge_read_phy_ocp(sc, 0xbf90) & ~0x0010; 185374263a62Skevlo rge_write_phy_ocp(sc, 0xbf90, val | 0x000c); 185474263a62Skevlo rge_patch_phy_mcu(sc, 0); 185574263a62Skevlo 185674263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x843b); 185774263a62Skevlo val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00; 185874263a62Skevlo rge_write_phy_ocp(sc, 0xa438, val | 0x2000); 185974263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x843d); 186074263a62Skevlo val = rge_read_phy_ocp(sc, 0xa438) & ~0xff00; 186174263a62Skevlo rge_write_phy_ocp(sc, 0xa438, val | 0x2000); 186274263a62Skevlo RGE_PHY_CLRBIT(sc, 0xb516, 0x007f); 186374263a62Skevlo RGE_PHY_CLRBIT(sc, 0xbf80, 0x0030); 186474263a62Skevlo 186574263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8188); 186674263a62Skevlo for (i = 0; i < 11; i++) 186774263a62Skevlo rge_write_phy_ocp(sc, 0xa438, mac_cfg2_a438_value[i]); 186874263a62Skevlo 186974263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8015); 187074263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 187174263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0800); 187274263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8ffd); 187374263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 187474263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0); 187574263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8fff); 187674263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 187774263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x7f00); 187874263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8ffb); 187974263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 188074263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0100); 188174263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8fe9); 188274263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x0002); 188374263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8fef); 188474263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x00a5); 188574263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8ff1); 188674263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x0106); 188774263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8fe1); 188874263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x0102); 188974263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8fe3); 189074263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 189174263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0400); 189274263a62Skevlo RGE_PHY_SETBIT(sc, 0xa654, 0x0800); 189374263a62Skevlo RGE_PHY_CLRBIT(sc, 0xa654, 0x0003); 189474263a62Skevlo rge_write_phy_ocp(sc, 0xac3a, 0x5851); 189574263a62Skevlo val = rge_read_phy_ocp(sc, 0xac3c) & ~0xd000; 189674263a62Skevlo rge_write_phy_ocp(sc, 0xac3c, val | 0x2000); 189774263a62Skevlo val = rge_read_phy_ocp(sc, 0xac42) & ~0x0200; 189874263a62Skevlo rge_write_phy_ocp(sc, 0xac42, val | 0x01c0); 189974263a62Skevlo RGE_PHY_CLRBIT(sc, 0xac3e, 0xe000); 190074263a62Skevlo RGE_PHY_CLRBIT(sc, 0xac42, 0x0038); 190174263a62Skevlo val = rge_read_phy_ocp(sc, 0xac42) & ~0x0002; 190274263a62Skevlo rge_write_phy_ocp(sc, 0xac42, val | 0x0005); 190374263a62Skevlo rge_write_phy_ocp(sc, 0xac1a, 0x00db); 190474263a62Skevlo rge_write_phy_ocp(sc, 0xade4, 0x01b5); 190574263a62Skevlo RGE_PHY_CLRBIT(sc, 0xad9c, 0x0c00); 190674263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x814b); 190774263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 190874263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x1100); 190974263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x814d); 191074263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 191174263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x1100); 191274263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x814f); 191374263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 191474263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0b00); 191574263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8142); 191674263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 191774263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0100); 191874263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8144); 191974263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 192074263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0100); 192174263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8150); 192274263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 192374263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0100); 192474263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8118); 192574263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 192674263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0700); 192774263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x811a); 192874263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 192974263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0700); 193074263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x811c); 193174263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 193274263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0500); 193374263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x810f); 193474263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 193574263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0100); 193674263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8111); 193774263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 193874263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0100); 193974263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x811d); 194074263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 194174263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0100); 194274263a62Skevlo RGE_PHY_SETBIT(sc, 0xac36, 0x1000); 194374263a62Skevlo RGE_PHY_CLRBIT(sc, 0xad1c, 0x0100); 194474263a62Skevlo val = rge_read_phy_ocp(sc, 0xade8) & ~0xffc0; 194574263a62Skevlo rge_write_phy_ocp(sc, 0xade8, val | 0x1400); 194674263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x864b); 194774263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 194874263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x9d00); 194974263a62Skevlo 195074263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8f97); 195174263a62Skevlo for (; i < nitems(mac_cfg2_a438_value); i++) 195274263a62Skevlo rge_write_phy_ocp(sc, 0xa438, mac_cfg2_a438_value[i]); 195374263a62Skevlo 195474263a62Skevlo RGE_PHY_SETBIT(sc, 0xad9c, 0x0020); 195574263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8122); 195674263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 195774263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0c00); 195874263a62Skevlo 195974263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x82c8); 196074263a62Skevlo for (i = 0; i < 20; i++) 196174263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, mac_cfg2_b87e_value[i]); 196274263a62Skevlo 196374263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x80ef); 196474263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 196574263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0c00); 196674263a62Skevlo 196774263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x82a0); 196874263a62Skevlo for (; i < nitems(mac_cfg2_b87e_value); i++) 196974263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, mac_cfg2_b87e_value[i]); 197074263a62Skevlo 197174263a62Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8018); 197274263a62Skevlo RGE_PHY_SETBIT(sc, 0xa438, 0x2000); 197374263a62Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8fe4); 197474263a62Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 197574263a62Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0); 197674263a62Skevlo val = rge_read_phy_ocp(sc, 0xb54c) & ~0xffc0; 197774263a62Skevlo rge_write_phy_ocp(sc, 0xb54c, val | 0x3700); 197874263a62Skevlo } 197974263a62Skevlo 198074263a62Skevlo void 19818cbc3b0aSkevlo rge_phy_config_mac_cfg3(struct rge_softc *sc) 19828cbc3b0aSkevlo { 19838cbc3b0aSkevlo uint16_t val; 19848cbc3b0aSkevlo int i; 19858cbc3b0aSkevlo static const uint16_t mac_cfg3_a438_value[] = 19868cbc3b0aSkevlo { 0x0043, 0x00a7, 0x00d6, 0x00ec, 0x00f6, 0x00fb, 0x00fd, 0x00ff, 19878cbc3b0aSkevlo 0x00bb, 0x0058, 0x0029, 0x0013, 0x0009, 0x0004, 0x0002 }; 19888cbc3b0aSkevlo 19898cbc3b0aSkevlo static const uint16_t mac_cfg3_b88e_value[] = 19908cbc3b0aSkevlo { 0xc091, 0x6e12, 0xc092, 0x1214, 0xc094, 0x1516, 0xc096, 0x171b, 19918cbc3b0aSkevlo 0xc098, 0x1b1c, 0xc09a, 0x1f1f, 0xc09c, 0x2021, 0xc09e, 0x2224, 19928cbc3b0aSkevlo 0xc0a0, 0x2424, 0xc0a2, 0x2424, 0xc0a4, 0x2424, 0xc018, 0x0af2, 19938cbc3b0aSkevlo 0xc01a, 0x0d4a, 0xc01c, 0x0f26, 0xc01e, 0x118d, 0xc020, 0x14f3, 19948cbc3b0aSkevlo 0xc022, 0x175a, 0xc024, 0x19c0, 0xc026, 0x1c26, 0xc089, 0x6050, 19958cbc3b0aSkevlo 0xc08a, 0x5f6e, 0xc08c, 0x6e6e, 0xc08e, 0x6e6e, 0xc090, 0x6e12 }; 1996be4e4fa3Skevlo 199781a23f33Skevlo rge_phy_config_mcu(sc, RGE_MAC_CFG3_MCODE_VER); 1998be4e4fa3Skevlo 1999be4e4fa3Skevlo RGE_PHY_SETBIT(sc, 0xad4e, 0x0010); 2000be4e4fa3Skevlo val = rge_read_phy_ocp(sc, 0xad16) & ~0x03ff; 2001be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xad16, val | 0x03ff); 2002be4e4fa3Skevlo val = rge_read_phy_ocp(sc, 0xad32) & ~0x003f; 2003be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xad32, val | 0x0006); 2004be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xac08, 0x1000); 2005be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xac08, 0x0100); 2006be4e4fa3Skevlo val = rge_read_phy_ocp(sc, 0xacc0) & ~0x0003; 2007be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xacc0, val | 0x0002); 2008be4e4fa3Skevlo val = rge_read_phy_ocp(sc, 0xad40) & ~0x00e0; 2009be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xad40, val | 0x0040); 2010be4e4fa3Skevlo val = rge_read_phy_ocp(sc, 0xad40) & ~0x0007; 2011be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xad40, val | 0x0004); 2012be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xac14, 0x0080); 2013be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xac80, 0x0300); 2014be4e4fa3Skevlo val = rge_read_phy_ocp(sc, 0xac5e) & ~0x0007; 2015be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xac5e, val | 0x0002); 2016be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xad4c, 0x00a8); 2017be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xac5c, 0x01ff); 2018be4e4fa3Skevlo val = rge_read_phy_ocp(sc, 0xac8a) & ~0x00f0; 2019be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xac8a, val | 0x0030); 202081a23f33Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8157); 202181a23f33Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 202281a23f33Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0500); 202381a23f33Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8159); 202481a23f33Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 202581a23f33Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0700); 2026be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x80a2); 2027be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x0153); 2028be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x809c); 2029be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x0153); 2030be4e4fa3Skevlo 2031be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xa436, 0x81b3); 2032be4e4fa3Skevlo for (i = 0; i < nitems(mac_cfg3_a438_value); i++) 2033be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xa438, mac_cfg3_a438_value[i]); 2034be4e4fa3Skevlo for (i = 0; i < 26; i++) 2035be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xa438, 0); 2036be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8257); 2037be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xa438, 0x020f); 2038be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xa436, 0x80ea); 2039be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xa438, 0x7843); 2040be4e4fa3Skevlo 2041be4e4fa3Skevlo rge_patch_phy_mcu(sc, 1); 2042be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xb896, 0x0001); 2043be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xb892, 0xff00); 2044be4e4fa3Skevlo for (i = 0; i < nitems(mac_cfg3_b88e_value); i += 2) { 2045be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xb88e, mac_cfg3_b88e_value[i]); 204681a23f33Skevlo rge_write_phy_ocp(sc, 0xb890, mac_cfg3_b88e_value[i + 1]); 2047be4e4fa3Skevlo } 2048be4e4fa3Skevlo RGE_PHY_SETBIT(sc, 0xb896, 0x0001); 2049be4e4fa3Skevlo rge_patch_phy_mcu(sc, 0); 2050be4e4fa3Skevlo 2051be4e4fa3Skevlo RGE_PHY_SETBIT(sc, 0xd068, 0x2000); 2052be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xa436, 0x81a2); 2053be4e4fa3Skevlo RGE_PHY_SETBIT(sc, 0xa438, 0x0100); 2054be4e4fa3Skevlo val = rge_read_phy_ocp(sc, 0xb54c) & ~0xff00; 2055be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xb54c, val | 0xdb00); 2056be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xa454, 0x0001); 2057be4e4fa3Skevlo RGE_PHY_SETBIT(sc, 0xa5d4, 0x0020); 2058be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xad4e, 0x0010); 2059be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xa86a, 0x0001); 2060be4e4fa3Skevlo RGE_PHY_SETBIT(sc, 0xa442, 0x0800); 20618cbc3b0aSkevlo RGE_PHY_SETBIT(sc, 0xa424, 0x0008); 206281a23f33Skevlo } 206381a23f33Skevlo 206481a23f33Skevlo void 206581a23f33Skevlo rge_phy_config_mac_cfg5(struct rge_softc *sc) 206681a23f33Skevlo { 206781a23f33Skevlo uint16_t val; 206881a23f33Skevlo int i; 206981a23f33Skevlo 207081a23f33Skevlo rge_phy_config_mcu(sc, RGE_MAC_CFG5_MCODE_VER); 207181a23f33Skevlo 207281a23f33Skevlo RGE_PHY_SETBIT(sc, 0xa442, 0x0800); 207381a23f33Skevlo val = rge_read_phy_ocp(sc, 0xac46) & ~0x00f0; 207481a23f33Skevlo rge_write_phy_ocp(sc, 0xac46, val | 0x0090); 207581a23f33Skevlo val = rge_read_phy_ocp(sc, 0xad30) & ~0x0003; 207681a23f33Skevlo rge_write_phy_ocp(sc, 0xad30, val | 0x0001); 207781a23f33Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x80f5); 207881a23f33Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x760e); 207981a23f33Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8107); 208081a23f33Skevlo rge_write_phy_ocp(sc, 0xb87e, 0x360e); 208181a23f33Skevlo rge_write_phy_ocp(sc, 0xb87c, 0x8551); 208281a23f33Skevlo val = rge_read_phy_ocp(sc, 0xb87e) & ~0xff00; 208381a23f33Skevlo rge_write_phy_ocp(sc, 0xb87e, val | 0x0800); 208481a23f33Skevlo val = rge_read_phy_ocp(sc, 0xbf00) & ~0xe000; 208581a23f33Skevlo rge_write_phy_ocp(sc, 0xbf00, val | 0xa000); 208681a23f33Skevlo val = rge_read_phy_ocp(sc, 0xbf46) & ~0x0f00; 208781a23f33Skevlo rge_write_phy_ocp(sc, 0xbf46, val | 0x0300); 208881a23f33Skevlo for (i = 0; i < 10; i++) { 208981a23f33Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8044 + i * 6); 209081a23f33Skevlo rge_write_phy_ocp(sc, 0xa438, 0x2417); 209181a23f33Skevlo } 209281a23f33Skevlo RGE_PHY_SETBIT(sc, 0xa4ca, 0x0040); 209361f1e1c4Skevlo val = rge_read_phy_ocp(sc, 0xbf84) & ~0xe000; 209461f1e1c4Skevlo rge_write_phy_ocp(sc, 0xbf84, val | 0xa000); 2095804ff404Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8170); 2096804ff404Skevlo val = rge_read_phy_ocp(sc, 0xa438) & ~0x2700; 2097804ff404Skevlo rge_write_phy_ocp(sc, 0xa438, val | 0xd800); 20988cbc3b0aSkevlo RGE_PHY_SETBIT(sc, 0xa424, 0x0008); 209981a23f33Skevlo } 210081a23f33Skevlo 210181a23f33Skevlo void 210281a23f33Skevlo rge_phy_config_mcu(struct rge_softc *sc, uint16_t mcode_version) 210381a23f33Skevlo { 210481a23f33Skevlo if (sc->rge_mcodever != mcode_version) { 210581a23f33Skevlo int i; 2106be4e4fa3Skevlo 2107be4e4fa3Skevlo rge_patch_phy_mcu(sc, 1); 210881a23f33Skevlo 21098cbc3b0aSkevlo if (sc->rge_type == MAC_CFG3) { 211081a23f33Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8024); 211181a23f33Skevlo rge_write_phy_ocp(sc, 0xa438, 0x8601); 211281a23f33Skevlo rge_write_phy_ocp(sc, 0xa436, 0xb82e); 211381a23f33Skevlo rge_write_phy_ocp(sc, 0xa438, 0x0001); 211481a23f33Skevlo 211581a23f33Skevlo RGE_PHY_SETBIT(sc, 0xb820, 0x0080); 211681a23f33Skevlo 211781a23f33Skevlo for (i = 0; i < nitems(rtl8125_mac_cfg3_mcu); i++) { 211881a23f33Skevlo rge_write_phy_ocp(sc, 211981a23f33Skevlo rtl8125_mac_cfg3_mcu[i].reg, 212081a23f33Skevlo rtl8125_mac_cfg3_mcu[i].val); 212181a23f33Skevlo } 212281a23f33Skevlo 212381a23f33Skevlo RGE_PHY_CLRBIT(sc, 0xb820, 0x0080); 212481a23f33Skevlo 212581a23f33Skevlo rge_write_phy_ocp(sc, 0xa436, 0); 212681a23f33Skevlo rge_write_phy_ocp(sc, 0xa438, 0); 212781a23f33Skevlo RGE_PHY_CLRBIT(sc, 0xb82e, 0x0001); 212881a23f33Skevlo rge_write_phy_ocp(sc, 0xa436, 0x8024); 212981a23f33Skevlo rge_write_phy_ocp(sc, 0xa438, 0); 21308cbc3b0aSkevlo } else if (sc->rge_type == MAC_CFG5) { 21318cbc3b0aSkevlo for (i = 0; i < nitems(rtl8125_mac_cfg5_mcu); i++) { 21328cbc3b0aSkevlo rge_write_phy_ocp(sc, 21338cbc3b0aSkevlo rtl8125_mac_cfg5_mcu[i].reg, 21348cbc3b0aSkevlo rtl8125_mac_cfg5_mcu[i].val); 21358cbc3b0aSkevlo } 213674263a62Skevlo } else if (sc->rge_type == MAC_CFG2_8126) { 213774263a62Skevlo for (i = 0; i < nitems(rtl8126_mac_cfg2_mcu); i++) { 213874263a62Skevlo rge_write_phy_ocp(sc, 213974263a62Skevlo rtl8126_mac_cfg2_mcu[i].reg, 214074263a62Skevlo rtl8126_mac_cfg2_mcu[i].val); 214174263a62Skevlo } 214281a23f33Skevlo } 214381a23f33Skevlo 2144be4e4fa3Skevlo rge_patch_phy_mcu(sc, 0); 214581a23f33Skevlo 214681a23f33Skevlo /* Write microcode version. */ 214781a23f33Skevlo rge_write_phy_ocp(sc, 0xa436, 0x801e); 214881a23f33Skevlo rge_write_phy_ocp(sc, 0xa438, mcode_version); 214981a23f33Skevlo } 2150be4e4fa3Skevlo } 2151be4e4fa3Skevlo 2152be4e4fa3Skevlo void 2153be4e4fa3Skevlo rge_set_macaddr(struct rge_softc *sc, const uint8_t *addr) 2154be4e4fa3Skevlo { 2155be4e4fa3Skevlo RGE_SETBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); 2156be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_MAC0, 2157be4e4fa3Skevlo addr[3] << 24 | addr[2] << 16 | addr[1] << 8 | addr[0]); 2158be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_MAC4, 2159be4e4fa3Skevlo addr[5] << 8 | addr[4]); 2160be4e4fa3Skevlo RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); 2161be4e4fa3Skevlo } 2162be4e4fa3Skevlo 2163be4e4fa3Skevlo void 2164be4e4fa3Skevlo rge_get_macaddr(struct rge_softc *sc, uint8_t *addr) 2165be4e4fa3Skevlo { 21668cbc3b0aSkevlo int i; 21678cbc3b0aSkevlo 21688cbc3b0aSkevlo for (i = 0; i < ETHER_ADDR_LEN; i++) 21698cbc3b0aSkevlo addr[i] = RGE_READ_1(sc, RGE_MAC0 + i); 21708cbc3b0aSkevlo 2171be4e4fa3Skevlo *(uint32_t *)&addr[0] = RGE_READ_4(sc, RGE_ADDR0); 2172be4e4fa3Skevlo *(uint16_t *)&addr[4] = RGE_READ_2(sc, RGE_ADDR1); 21738cbc3b0aSkevlo 21748cbc3b0aSkevlo rge_set_macaddr(sc, addr); 2175be4e4fa3Skevlo } 2176be4e4fa3Skevlo 2177be4e4fa3Skevlo void 2178be4e4fa3Skevlo rge_hw_init(struct rge_softc *sc) 2179be4e4fa3Skevlo { 21808cbc3b0aSkevlo uint16_t reg; 21818cbc3b0aSkevlo int i, npages; 2182be4e4fa3Skevlo 21838cbc3b0aSkevlo rge_disable_aspm_clkreq(sc); 2184be4e4fa3Skevlo RGE_CLRBIT_1(sc, 0xf1, 0x80); 2185be4e4fa3Skevlo 2186be4e4fa3Skevlo /* Disable UPS. */ 2187be4e4fa3Skevlo RGE_MAC_CLRBIT(sc, 0xd40a, 0x0010); 2188be4e4fa3Skevlo 21898cbc3b0aSkevlo /* Disable MAC MCU. */ 21908cbc3b0aSkevlo rge_disable_aspm_clkreq(sc); 21918cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xfc48, 0); 21928cbc3b0aSkevlo for (reg = 0xfc28; reg < 0xfc48; reg += 2) 21938cbc3b0aSkevlo rge_write_mac_ocp(sc, reg, 0); 2194be4e4fa3Skevlo DELAY(3000); 2195be4e4fa3Skevlo rge_write_mac_ocp(sc, 0xfc26, 0); 2196be4e4fa3Skevlo 2197be4e4fa3Skevlo if (sc->rge_type == MAC_CFG3) { 21988cbc3b0aSkevlo for (npages = 0; npages < 3; npages++) { 21998cbc3b0aSkevlo rge_switch_mcu_ram_page(sc, npages); 220081a23f33Skevlo for (i = 0; i < nitems(rtl8125_mac_bps); i++) { 22018cbc3b0aSkevlo if (npages == 0) 22028cbc3b0aSkevlo rge_write_mac_ocp(sc, 22038cbc3b0aSkevlo rtl8125_mac_bps[i].reg, 220481a23f33Skevlo rtl8125_mac_bps[i].val); 22058cbc3b0aSkevlo else if (npages == 1) 22068cbc3b0aSkevlo rge_write_mac_ocp(sc, 22078cbc3b0aSkevlo rtl8125_mac_bps[i].reg, 0); 22088cbc3b0aSkevlo else { 22098cbc3b0aSkevlo if (rtl8125_mac_bps[i].reg < 0xf9f8) 22108cbc3b0aSkevlo rge_write_mac_ocp(sc, 22118cbc3b0aSkevlo rtl8125_mac_bps[i].reg, 0); 221281a23f33Skevlo } 22138cbc3b0aSkevlo } 22148cbc3b0aSkevlo if (npages == 2) { 22158cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xf9f8, 0x6486); 22168cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xf9fa, 0x0b15); 22178cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xf9fc, 0x090e); 22188cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xf9fe, 0x1139); 22198cbc3b0aSkevlo } 22208cbc3b0aSkevlo } 22218cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xfc26, 0x8000); 22228cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xfc2a, 0x0540); 22238cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xfc2e, 0x0a06); 22248cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xfc30, 0x0eb8); 22258cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xfc32, 0x3a5c); 22268cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xfc34, 0x10a8); 22278cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xfc40, 0x0d54); 22288cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xfc42, 0x0e24); 22298cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xfc48, 0x307a); 223081a23f33Skevlo } else if (sc->rge_type == MAC_CFG5) { 22318cbc3b0aSkevlo rge_switch_mcu_ram_page(sc, 0); 223281a23f33Skevlo for (i = 0; i < nitems(rtl8125b_mac_bps); i++) { 223381a23f33Skevlo rge_write_mac_ocp(sc, rtl8125b_mac_bps[i].reg, 223481a23f33Skevlo rtl8125b_mac_bps[i].val); 223581a23f33Skevlo } 2236be4e4fa3Skevlo } 2237be4e4fa3Skevlo 2238be4e4fa3Skevlo /* Disable PHY power saving. */ 223974263a62Skevlo if (sc->rge_type == MAC_CFG3) 2240be4e4fa3Skevlo rge_disable_phy_ocp_pwrsave(sc); 2241be4e4fa3Skevlo 2242be4e4fa3Skevlo /* Set PCIe uncorrectable error status. */ 2243be4e4fa3Skevlo rge_write_csi(sc, 0x108, 2244be4e4fa3Skevlo rge_read_csi(sc, 0x108) | 0x00100000); 22458cbc3b0aSkevlo } 22467bcadffeSkevlo 22478cbc3b0aSkevlo void 22488cbc3b0aSkevlo rge_hw_reset(struct rge_softc *sc) 22498cbc3b0aSkevlo { 22508cbc3b0aSkevlo /* Disable interrupts */ 22518cbc3b0aSkevlo RGE_WRITE_4(sc, RGE_IMR, 0); 22528cbc3b0aSkevlo RGE_WRITE_4(sc, RGE_ISR, RGE_READ_4(sc, RGE_ISR)); 22538cbc3b0aSkevlo 22548cbc3b0aSkevlo /* Clear timer interrupts. */ 22558cbc3b0aSkevlo RGE_WRITE_4(sc, RGE_TIMERINT0, 0); 22568cbc3b0aSkevlo RGE_WRITE_4(sc, RGE_TIMERINT1, 0); 22578cbc3b0aSkevlo RGE_WRITE_4(sc, RGE_TIMERINT2, 0); 22588cbc3b0aSkevlo RGE_WRITE_4(sc, RGE_TIMERINT3, 0); 22598cbc3b0aSkevlo 22608cbc3b0aSkevlo rge_reset(sc); 2261be4e4fa3Skevlo } 2262be4e4fa3Skevlo 2263be4e4fa3Skevlo void 2264be4e4fa3Skevlo rge_disable_phy_ocp_pwrsave(struct rge_softc *sc) 2265be4e4fa3Skevlo { 2266be4e4fa3Skevlo if (rge_read_phy_ocp(sc, 0xc416) != 0x0500) { 2267be4e4fa3Skevlo rge_patch_phy_mcu(sc, 1); 2268be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xc416, 0); 2269be4e4fa3Skevlo rge_write_phy_ocp(sc, 0xc416, 0x0500); 2270be4e4fa3Skevlo rge_patch_phy_mcu(sc, 0); 2271be4e4fa3Skevlo } 2272be4e4fa3Skevlo } 2273be4e4fa3Skevlo 2274be4e4fa3Skevlo void 2275be4e4fa3Skevlo rge_patch_phy_mcu(struct rge_softc *sc, int set) 2276be4e4fa3Skevlo { 2277be4e4fa3Skevlo int i; 2278be4e4fa3Skevlo 2279be4e4fa3Skevlo if (set) 2280be4e4fa3Skevlo RGE_PHY_SETBIT(sc, 0xb820, 0x0010); 2281be4e4fa3Skevlo else 2282be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xb820, 0x0010); 2283be4e4fa3Skevlo 2284be4e4fa3Skevlo for (i = 0; i < 1000; i++) { 22858cbc3b0aSkevlo if (set) { 22868cbc3b0aSkevlo if ((rge_read_phy_ocp(sc, 0xb800) & 0x0040) != 0) 2287be4e4fa3Skevlo break; 22888cbc3b0aSkevlo } else { 22898cbc3b0aSkevlo if (!(rge_read_phy_ocp(sc, 0xb800) & 0x0040)) 22908cbc3b0aSkevlo break; 22918cbc3b0aSkevlo } 229281a23f33Skevlo DELAY(100); 2293be4e4fa3Skevlo } 22948cbc3b0aSkevlo if (i == 1000) 22958cbc3b0aSkevlo printf("%s: timeout waiting to patch phy mcu\n", 22968cbc3b0aSkevlo sc->sc_dev.dv_xname); 2297be4e4fa3Skevlo } 2298be4e4fa3Skevlo 2299be4e4fa3Skevlo void 2300be4e4fa3Skevlo rge_add_media_types(struct rge_softc *sc) 2301be4e4fa3Skevlo { 2302be4e4fa3Skevlo ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T, 0, NULL); 2303be4e4fa3Skevlo ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL); 2304be4e4fa3Skevlo ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX, 0, NULL); 2305be4e4fa3Skevlo ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL); 2306be4e4fa3Skevlo ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_T, 0, NULL); 2307be4e4fa3Skevlo ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL); 2308be4e4fa3Skevlo ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_2500_T, 0, NULL); 2309be4e4fa3Skevlo ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_2500_T | IFM_FDX, 0, NULL); 231074263a62Skevlo 231174263a62Skevlo if (sc->rge_type == MAC_CFG2_8126) { 231274263a62Skevlo ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_5000_T, 0, NULL); 231374263a62Skevlo ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_5000_T | IFM_FDX, 231474263a62Skevlo 0, NULL); 231574263a62Skevlo } 2316be4e4fa3Skevlo } 2317be4e4fa3Skevlo 2318be4e4fa3Skevlo void 2319be4e4fa3Skevlo rge_config_imtype(struct rge_softc *sc, int imtype) 2320be4e4fa3Skevlo { 2321be4e4fa3Skevlo switch (imtype) { 2322be4e4fa3Skevlo case RGE_IMTYPE_NONE: 2323be4e4fa3Skevlo sc->rge_intrs = RGE_INTRS; 2324be4e4fa3Skevlo break; 2325be4e4fa3Skevlo case RGE_IMTYPE_SIM: 2326be4e4fa3Skevlo sc->rge_intrs = RGE_INTRS_TIMER; 2327be4e4fa3Skevlo break; 2328be4e4fa3Skevlo default: 2329be4e4fa3Skevlo panic("%s: unknown imtype %d", sc->sc_dev.dv_xname, imtype); 2330be4e4fa3Skevlo } 2331be4e4fa3Skevlo } 2332be4e4fa3Skevlo 2333be4e4fa3Skevlo void 23348cbc3b0aSkevlo rge_disable_aspm_clkreq(struct rge_softc *sc) 23358cbc3b0aSkevlo { 23368cbc3b0aSkevlo RGE_SETBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); 233774263a62Skevlo if (sc->rge_type == MAC_CFG2_8126) 233874263a62Skevlo RGE_CLRBIT_1(sc, RGE_INT_CFG0, 0x08); 233974263a62Skevlo else 23408cbc3b0aSkevlo RGE_CLRBIT_1(sc, RGE_CFG2, RGE_CFG2_CLKREQ_EN); 23418cbc3b0aSkevlo RGE_CLRBIT_1(sc, RGE_CFG5, RGE_CFG5_PME_STS); 23428cbc3b0aSkevlo RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); 23438cbc3b0aSkevlo } 23448cbc3b0aSkevlo 23458cbc3b0aSkevlo void 234681a23f33Skevlo rge_disable_hw_im(struct rge_softc *sc) 234781a23f33Skevlo { 234881a23f33Skevlo RGE_WRITE_2(sc, RGE_IM, 0); 234981a23f33Skevlo } 235081a23f33Skevlo 235181a23f33Skevlo void 2352be4e4fa3Skevlo rge_disable_sim_im(struct rge_softc *sc) 2353be4e4fa3Skevlo { 235481a23f33Skevlo RGE_WRITE_4(sc, RGE_TIMERINT0, 0); 2355be4e4fa3Skevlo sc->rge_timerintr = 0; 2356be4e4fa3Skevlo } 2357be4e4fa3Skevlo 2358be4e4fa3Skevlo void 2359be4e4fa3Skevlo rge_setup_sim_im(struct rge_softc *sc) 2360be4e4fa3Skevlo { 236181a23f33Skevlo RGE_WRITE_4(sc, RGE_TIMERINT0, 0x2600); 2362be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_TIMERCNT, 1); 2363be4e4fa3Skevlo sc->rge_timerintr = 1; 2364be4e4fa3Skevlo } 2365be4e4fa3Skevlo 2366be4e4fa3Skevlo void 2367be4e4fa3Skevlo rge_setup_intr(struct rge_softc *sc, int imtype) 2368be4e4fa3Skevlo { 2369be4e4fa3Skevlo rge_config_imtype(sc, imtype); 2370be4e4fa3Skevlo 2371be4e4fa3Skevlo /* Enable interrupts. */ 2372be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_IMR, sc->rge_intrs); 2373be4e4fa3Skevlo 2374be4e4fa3Skevlo switch (imtype) { 2375be4e4fa3Skevlo case RGE_IMTYPE_NONE: 2376be4e4fa3Skevlo rge_disable_sim_im(sc); 237781a23f33Skevlo rge_disable_hw_im(sc); 2378be4e4fa3Skevlo break; 2379be4e4fa3Skevlo case RGE_IMTYPE_SIM: 238081a23f33Skevlo rge_disable_hw_im(sc); 2381be4e4fa3Skevlo rge_setup_sim_im(sc); 2382be4e4fa3Skevlo break; 2383be4e4fa3Skevlo default: 2384be4e4fa3Skevlo panic("%s: unknown imtype %d", sc->sc_dev.dv_xname, imtype); 2385be4e4fa3Skevlo } 2386be4e4fa3Skevlo } 2387be4e4fa3Skevlo 2388be4e4fa3Skevlo void 23898cbc3b0aSkevlo rge_switch_mcu_ram_page(struct rge_softc *sc, int page) 23908cbc3b0aSkevlo { 23918cbc3b0aSkevlo uint16_t val; 23928cbc3b0aSkevlo 23938cbc3b0aSkevlo val = rge_read_mac_ocp(sc, 0xe446) & ~0x0003; 23948cbc3b0aSkevlo val |= page; 23958cbc3b0aSkevlo rge_write_mac_ocp(sc, 0xe446, val); 23968cbc3b0aSkevlo } 23978cbc3b0aSkevlo 23988cbc3b0aSkevlo void 2399be4e4fa3Skevlo rge_exit_oob(struct rge_softc *sc) 2400be4e4fa3Skevlo { 2401be4e4fa3Skevlo int i; 2402be4e4fa3Skevlo 2403be4e4fa3Skevlo RGE_CLRBIT_4(sc, RGE_RXCFG, RGE_RXCFG_ALLPHYS | RGE_RXCFG_INDIV | 2404be4e4fa3Skevlo RGE_RXCFG_MULTI | RGE_RXCFG_BROAD | RGE_RXCFG_RUNT | 2405be4e4fa3Skevlo RGE_RXCFG_ERRPKT); 2406be4e4fa3Skevlo 2407be4e4fa3Skevlo /* Disable RealWoW. */ 2408be4e4fa3Skevlo rge_write_mac_ocp(sc, 0xc0bc, 0x00ff); 2409be4e4fa3Skevlo 2410be4e4fa3Skevlo rge_reset(sc); 2411be4e4fa3Skevlo 2412be4e4fa3Skevlo /* Disable OOB. */ 2413be4e4fa3Skevlo RGE_CLRBIT_1(sc, RGE_MCUCMD, RGE_MCUCMD_IS_OOB); 2414be4e4fa3Skevlo 2415be4e4fa3Skevlo RGE_MAC_CLRBIT(sc, 0xe8de, 0x4000); 2416be4e4fa3Skevlo 2417be4e4fa3Skevlo for (i = 0; i < 10; i++) { 2418be4e4fa3Skevlo DELAY(100); 2419be4e4fa3Skevlo if (RGE_READ_2(sc, RGE_TWICMD) & 0x0200) 2420be4e4fa3Skevlo break; 2421be4e4fa3Skevlo } 2422be4e4fa3Skevlo 2423be4e4fa3Skevlo rge_write_mac_ocp(sc, 0xc0aa, 0x07d0); 242481a23f33Skevlo rge_write_mac_ocp(sc, 0xc0a6, 0x01b5); 2425be4e4fa3Skevlo rge_write_mac_ocp(sc, 0xc01e, 0x5555); 2426be4e4fa3Skevlo 2427be4e4fa3Skevlo for (i = 0; i < 10; i++) { 2428be4e4fa3Skevlo DELAY(100); 2429be4e4fa3Skevlo if (RGE_READ_2(sc, RGE_TWICMD) & 0x0200) 2430be4e4fa3Skevlo break; 2431be4e4fa3Skevlo } 2432be4e4fa3Skevlo 2433be4e4fa3Skevlo if (rge_read_mac_ocp(sc, 0xd42c) & 0x0100) { 2434be4e4fa3Skevlo for (i = 0; i < RGE_TIMEOUT; i++) { 24351943b9bcSkrw if ((rge_read_phy_ocp(sc, 0xa420) & 0x0007) == 2) 2436be4e4fa3Skevlo break; 2437be4e4fa3Skevlo DELAY(1000); 2438be4e4fa3Skevlo } 24398cbc3b0aSkevlo RGE_MAC_CLRBIT(sc, 0xd42c, 0x0100); 24408cbc3b0aSkevlo if (sc->rge_type != MAC_CFG3) 244181a23f33Skevlo RGE_PHY_CLRBIT(sc, 0xa466, 0x0001); 2442be4e4fa3Skevlo RGE_PHY_CLRBIT(sc, 0xa468, 0x000a); 2443be4e4fa3Skevlo } 2444be4e4fa3Skevlo } 2445be4e4fa3Skevlo 2446be4e4fa3Skevlo void 2447be4e4fa3Skevlo rge_write_csi(struct rge_softc *sc, uint32_t reg, uint32_t val) 2448be4e4fa3Skevlo { 2449be4e4fa3Skevlo int i; 2450be4e4fa3Skevlo 2451be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_CSIDR, val); 245281a23f33Skevlo RGE_WRITE_4(sc, RGE_CSIAR, (reg & RGE_CSIAR_ADDR_MASK) | 2453be4e4fa3Skevlo (RGE_CSIAR_BYTE_EN << RGE_CSIAR_BYTE_EN_SHIFT) | RGE_CSIAR_BUSY); 2454be4e4fa3Skevlo 24558cbc3b0aSkevlo for (i = 0; i < 20000; i++) { 24568cbc3b0aSkevlo DELAY(1); 2457be4e4fa3Skevlo if (!(RGE_READ_4(sc, RGE_CSIAR) & RGE_CSIAR_BUSY)) 2458be4e4fa3Skevlo break; 2459be4e4fa3Skevlo } 2460be4e4fa3Skevlo 2461be4e4fa3Skevlo DELAY(20); 2462be4e4fa3Skevlo } 2463be4e4fa3Skevlo 2464be4e4fa3Skevlo uint32_t 2465be4e4fa3Skevlo rge_read_csi(struct rge_softc *sc, uint32_t reg) 2466be4e4fa3Skevlo { 2467be4e4fa3Skevlo int i; 2468be4e4fa3Skevlo 246981a23f33Skevlo RGE_WRITE_4(sc, RGE_CSIAR, (reg & RGE_CSIAR_ADDR_MASK) | 2470be4e4fa3Skevlo (RGE_CSIAR_BYTE_EN << RGE_CSIAR_BYTE_EN_SHIFT)); 2471be4e4fa3Skevlo 24728cbc3b0aSkevlo for (i = 0; i < 20000; i++) { 24738cbc3b0aSkevlo DELAY(1); 2474be4e4fa3Skevlo if (RGE_READ_4(sc, RGE_CSIAR) & RGE_CSIAR_BUSY) 2475be4e4fa3Skevlo break; 2476be4e4fa3Skevlo } 2477be4e4fa3Skevlo 2478be4e4fa3Skevlo DELAY(20); 2479be4e4fa3Skevlo 2480be4e4fa3Skevlo return (RGE_READ_4(sc, RGE_CSIDR)); 2481be4e4fa3Skevlo } 2482be4e4fa3Skevlo 2483be4e4fa3Skevlo void 2484be4e4fa3Skevlo rge_write_mac_ocp(struct rge_softc *sc, uint16_t reg, uint16_t val) 2485be4e4fa3Skevlo { 2486be4e4fa3Skevlo uint32_t tmp; 2487be4e4fa3Skevlo 2488be4e4fa3Skevlo tmp = (reg >> 1) << RGE_MACOCP_ADDR_SHIFT; 2489be4e4fa3Skevlo tmp += val; 2490be4e4fa3Skevlo tmp |= RGE_MACOCP_BUSY; 2491be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_MACOCP, tmp); 2492be4e4fa3Skevlo } 2493be4e4fa3Skevlo 2494be4e4fa3Skevlo uint16_t 2495be4e4fa3Skevlo rge_read_mac_ocp(struct rge_softc *sc, uint16_t reg) 2496be4e4fa3Skevlo { 2497be4e4fa3Skevlo uint32_t val; 2498be4e4fa3Skevlo 2499be4e4fa3Skevlo val = (reg >> 1) << RGE_MACOCP_ADDR_SHIFT; 2500be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_MACOCP, val); 2501be4e4fa3Skevlo 2502be4e4fa3Skevlo return (RGE_READ_4(sc, RGE_MACOCP) & RGE_MACOCP_DATA_MASK); 2503be4e4fa3Skevlo } 2504be4e4fa3Skevlo 2505be4e4fa3Skevlo void 2506be4e4fa3Skevlo rge_write_ephy(struct rge_softc *sc, uint16_t reg, uint16_t val) 2507be4e4fa3Skevlo { 2508be4e4fa3Skevlo uint32_t tmp; 2509be4e4fa3Skevlo int i; 2510be4e4fa3Skevlo 2511be4e4fa3Skevlo tmp = (reg & RGE_EPHYAR_ADDR_MASK) << RGE_EPHYAR_ADDR_SHIFT; 2512be4e4fa3Skevlo tmp |= RGE_EPHYAR_BUSY | (val & RGE_EPHYAR_DATA_MASK); 2513be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_EPHYAR, tmp); 2514be4e4fa3Skevlo 2515be4e4fa3Skevlo for (i = 0; i < 10; i++) { 2516be4e4fa3Skevlo DELAY(100); 2517be4e4fa3Skevlo if (!(RGE_READ_4(sc, RGE_EPHYAR) & RGE_EPHYAR_BUSY)) 2518be4e4fa3Skevlo break; 2519be4e4fa3Skevlo } 2520be4e4fa3Skevlo 2521be4e4fa3Skevlo DELAY(20); 2522be4e4fa3Skevlo } 2523be4e4fa3Skevlo 252481a23f33Skevlo uint16_t 252581a23f33Skevlo rge_read_ephy(struct rge_softc *sc, uint16_t reg) 252681a23f33Skevlo { 252781a23f33Skevlo uint32_t val; 252881a23f33Skevlo int i; 252981a23f33Skevlo 253081a23f33Skevlo val = (reg & RGE_EPHYAR_ADDR_MASK) << RGE_EPHYAR_ADDR_SHIFT; 253181a23f33Skevlo RGE_WRITE_4(sc, RGE_EPHYAR, val); 253281a23f33Skevlo 253381a23f33Skevlo for (i = 0; i < 10; i++) { 253481a23f33Skevlo DELAY(100); 253581a23f33Skevlo val = RGE_READ_4(sc, RGE_EPHYAR); 253681a23f33Skevlo if (val & RGE_EPHYAR_BUSY) 253781a23f33Skevlo break; 253881a23f33Skevlo } 253981a23f33Skevlo 254081a23f33Skevlo DELAY(20); 254181a23f33Skevlo 254281a23f33Skevlo return (val & RGE_EPHYAR_DATA_MASK); 254381a23f33Skevlo } 254481a23f33Skevlo 2545be4e4fa3Skevlo void 2546be4e4fa3Skevlo rge_write_phy(struct rge_softc *sc, uint16_t addr, uint16_t reg, uint16_t val) 2547be4e4fa3Skevlo { 2548be4e4fa3Skevlo uint16_t off, phyaddr; 2549be4e4fa3Skevlo 2550be4e4fa3Skevlo phyaddr = addr ? addr : RGE_PHYBASE + (reg / 8); 2551be4e4fa3Skevlo phyaddr <<= 4; 2552be4e4fa3Skevlo 2553be4e4fa3Skevlo off = addr ? reg : 0x10 + (reg % 8); 2554be4e4fa3Skevlo 2555be4e4fa3Skevlo phyaddr += (off - 16) << 1; 2556be4e4fa3Skevlo 2557be4e4fa3Skevlo rge_write_phy_ocp(sc, phyaddr, val); 2558be4e4fa3Skevlo } 2559be4e4fa3Skevlo 2560dfa3bc0bSkevlo uint16_t 2561dfa3bc0bSkevlo rge_read_phy(struct rge_softc *sc, uint16_t addr, uint16_t reg) 2562dfa3bc0bSkevlo { 2563dfa3bc0bSkevlo uint16_t off, phyaddr; 2564dfa3bc0bSkevlo 2565dfa3bc0bSkevlo phyaddr = addr ? addr : RGE_PHYBASE + (reg / 8); 2566dfa3bc0bSkevlo phyaddr <<= 4; 2567dfa3bc0bSkevlo 2568dfa3bc0bSkevlo off = addr ? reg : 0x10 + (reg % 8); 2569dfa3bc0bSkevlo 2570dfa3bc0bSkevlo phyaddr += (off - 16) << 1; 2571dfa3bc0bSkevlo 2572dfa3bc0bSkevlo return (rge_read_phy_ocp(sc, phyaddr)); 2573dfa3bc0bSkevlo } 2574dfa3bc0bSkevlo 2575be4e4fa3Skevlo void 2576be4e4fa3Skevlo rge_write_phy_ocp(struct rge_softc *sc, uint16_t reg, uint16_t val) 2577be4e4fa3Skevlo { 2578be4e4fa3Skevlo uint32_t tmp; 2579be4e4fa3Skevlo int i; 2580be4e4fa3Skevlo 2581be4e4fa3Skevlo tmp = (reg >> 1) << RGE_PHYOCP_ADDR_SHIFT; 2582be4e4fa3Skevlo tmp |= RGE_PHYOCP_BUSY | val; 2583be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_PHYOCP, tmp); 2584be4e4fa3Skevlo 2585be4e4fa3Skevlo for (i = 0; i < RGE_TIMEOUT; i++) { 2586be4e4fa3Skevlo DELAY(1); 2587be4e4fa3Skevlo if (!(RGE_READ_4(sc, RGE_PHYOCP) & RGE_PHYOCP_BUSY)) 2588be4e4fa3Skevlo break; 2589be4e4fa3Skevlo } 2590be4e4fa3Skevlo } 2591be4e4fa3Skevlo 2592be4e4fa3Skevlo uint16_t 2593be4e4fa3Skevlo rge_read_phy_ocp(struct rge_softc *sc, uint16_t reg) 2594be4e4fa3Skevlo { 2595be4e4fa3Skevlo uint32_t val; 2596be4e4fa3Skevlo int i; 2597be4e4fa3Skevlo 2598be4e4fa3Skevlo val = (reg >> 1) << RGE_PHYOCP_ADDR_SHIFT; 2599be4e4fa3Skevlo RGE_WRITE_4(sc, RGE_PHYOCP, val); 2600be4e4fa3Skevlo 2601be4e4fa3Skevlo for (i = 0; i < RGE_TIMEOUT; i++) { 2602be4e4fa3Skevlo DELAY(1); 2603be4e4fa3Skevlo val = RGE_READ_4(sc, RGE_PHYOCP); 2604be4e4fa3Skevlo if (val & RGE_PHYOCP_BUSY) 2605be4e4fa3Skevlo break; 2606be4e4fa3Skevlo } 2607be4e4fa3Skevlo 2608be4e4fa3Skevlo return (val & RGE_PHYOCP_DATA_MASK); 2609be4e4fa3Skevlo } 2610be4e4fa3Skevlo 2611be4e4fa3Skevlo int 2612be4e4fa3Skevlo rge_get_link_status(struct rge_softc *sc) 2613be4e4fa3Skevlo { 2614be4e4fa3Skevlo return ((RGE_READ_2(sc, RGE_PHYSTAT) & RGE_PHYSTAT_LINK) ? 1 : 0); 2615be4e4fa3Skevlo } 2616be4e4fa3Skevlo 2617be4e4fa3Skevlo void 2618be4e4fa3Skevlo rge_txstart(void *arg) 2619be4e4fa3Skevlo { 2620be4e4fa3Skevlo struct rge_softc *sc = arg; 2621be4e4fa3Skevlo 2622be4e4fa3Skevlo RGE_WRITE_2(sc, RGE_TXSTART, RGE_TXSTART_START); 2623be4e4fa3Skevlo } 2624be4e4fa3Skevlo 2625be4e4fa3Skevlo void 2626be4e4fa3Skevlo rge_tick(void *arg) 2627be4e4fa3Skevlo { 2628be4e4fa3Skevlo struct rge_softc *sc = arg; 2629be4e4fa3Skevlo int s; 2630be4e4fa3Skevlo 2631be4e4fa3Skevlo s = splnet(); 2632be4e4fa3Skevlo rge_link_state(sc); 2633be4e4fa3Skevlo splx(s); 2634be4e4fa3Skevlo 2635be4e4fa3Skevlo timeout_add_sec(&sc->sc_timeout, 1); 2636be4e4fa3Skevlo } 2637be4e4fa3Skevlo 2638be4e4fa3Skevlo void 2639be4e4fa3Skevlo rge_link_state(struct rge_softc *sc) 2640be4e4fa3Skevlo { 2641be4e4fa3Skevlo struct ifnet *ifp = &sc->sc_arpcom.ac_if; 2642be4e4fa3Skevlo int link = LINK_STATE_DOWN; 2643be4e4fa3Skevlo 2644be4e4fa3Skevlo if (rge_get_link_status(sc)) 2645be4e4fa3Skevlo link = LINK_STATE_UP; 2646be4e4fa3Skevlo 2647be4e4fa3Skevlo if (ifp->if_link_state != link) { 2648be4e4fa3Skevlo ifp->if_link_state = link; 2649be4e4fa3Skevlo if_link_state_change(ifp); 2650be4e4fa3Skevlo } 2651be4e4fa3Skevlo } 26527bcadffeSkevlo 26537bcadffeSkevlo #ifndef SMALL_KERNEL 26547bcadffeSkevlo int 26557bcadffeSkevlo rge_wol(struct ifnet *ifp, int enable) 26567bcadffeSkevlo { 26577bcadffeSkevlo struct rge_softc *sc = ifp->if_softc; 26587bcadffeSkevlo 26597bcadffeSkevlo if (enable) { 26607bcadffeSkevlo if (!(RGE_READ_1(sc, RGE_CFG1) & RGE_CFG1_PM_EN)) { 26617bcadffeSkevlo printf("%s: power management is disabled, " 26627bcadffeSkevlo "cannot do WOL\n", sc->sc_dev.dv_xname); 26637bcadffeSkevlo return (ENOTSUP); 26647bcadffeSkevlo } 26657bcadffeSkevlo 26667bcadffeSkevlo } 26677bcadffeSkevlo 26687bcadffeSkevlo rge_iff(sc); 26697bcadffeSkevlo 26707bcadffeSkevlo if (enable) 26717bcadffeSkevlo RGE_MAC_SETBIT(sc, 0xc0b6, 0x0001); 26727bcadffeSkevlo else 26737bcadffeSkevlo RGE_MAC_CLRBIT(sc, 0xc0b6, 0x0001); 26747bcadffeSkevlo 26757bcadffeSkevlo RGE_SETBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); 26767bcadffeSkevlo RGE_CLRBIT_1(sc, RGE_CFG5, RGE_CFG5_WOL_LANWAKE | RGE_CFG5_WOL_UCAST | 26777bcadffeSkevlo RGE_CFG5_WOL_MCAST | RGE_CFG5_WOL_BCAST); 26787bcadffeSkevlo RGE_CLRBIT_1(sc, RGE_CFG3, RGE_CFG3_WOL_LINK | RGE_CFG3_WOL_MAGIC); 26797bcadffeSkevlo if (enable) 26807bcadffeSkevlo RGE_SETBIT_1(sc, RGE_CFG5, RGE_CFG5_WOL_LANWAKE); 26817bcadffeSkevlo RGE_CLRBIT_1(sc, RGE_EECMD, RGE_EECMD_WRITECFG); 26827bcadffeSkevlo 26837bcadffeSkevlo return (0); 26847bcadffeSkevlo } 26857bcadffeSkevlo 26867bcadffeSkevlo void 26877bcadffeSkevlo rge_wol_power(struct rge_softc *sc) 26887bcadffeSkevlo { 26897bcadffeSkevlo /* Disable RXDV gate. */ 26907bcadffeSkevlo RGE_CLRBIT_1(sc, RGE_PPSW, 0x08); 26917bcadffeSkevlo DELAY(2000); 26927bcadffeSkevlo 26937bcadffeSkevlo RGE_SETBIT_1(sc, RGE_CFG1, RGE_CFG1_PM_EN); 26947bcadffeSkevlo RGE_SETBIT_1(sc, RGE_CFG2, RGE_CFG2_PMSTS_EN); 26957bcadffeSkevlo } 26967bcadffeSkevlo #endif 26971b7ab755Sdlg 26981b7ab755Sdlg #if NKSTAT > 0 26991b7ab755Sdlg 27001b7ab755Sdlg #define RGE_DTCCR_CMD (1U << 3) 27011b7ab755Sdlg #define RGE_DTCCR_LO 0x10 27021b7ab755Sdlg #define RGE_DTCCR_HI 0x14 27031b7ab755Sdlg 27041b7ab755Sdlg struct rge_kstats { 27051b7ab755Sdlg struct kstat_kv tx_ok; 27061b7ab755Sdlg struct kstat_kv rx_ok; 27071b7ab755Sdlg struct kstat_kv tx_er; 27081b7ab755Sdlg struct kstat_kv rx_er; 27091b7ab755Sdlg struct kstat_kv miss_pkt; 27101b7ab755Sdlg struct kstat_kv fae; 27111b7ab755Sdlg struct kstat_kv tx_1col; 27121b7ab755Sdlg struct kstat_kv tx_mcol; 27131b7ab755Sdlg struct kstat_kv rx_ok_phy; 27141b7ab755Sdlg struct kstat_kv rx_ok_brd; 27151b7ab755Sdlg struct kstat_kv rx_ok_mul; 27161b7ab755Sdlg struct kstat_kv tx_abt; 27171b7ab755Sdlg struct kstat_kv tx_undrn; 27181b7ab755Sdlg }; 27191b7ab755Sdlg 27201b7ab755Sdlg static const struct rge_kstats rge_kstats_tpl = { 27211b7ab755Sdlg .tx_ok = KSTAT_KV_UNIT_INITIALIZER("TxOk", 27221b7ab755Sdlg KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), 27231b7ab755Sdlg .rx_ok = KSTAT_KV_UNIT_INITIALIZER("RxOk", 27241b7ab755Sdlg KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), 27251b7ab755Sdlg .tx_er = KSTAT_KV_UNIT_INITIALIZER("TxEr", 27261b7ab755Sdlg KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), 27271b7ab755Sdlg .rx_er = KSTAT_KV_UNIT_INITIALIZER("RxEr", 27281b7ab755Sdlg KSTAT_KV_T_COUNTER32, KSTAT_KV_U_PACKETS), 27291b7ab755Sdlg .miss_pkt = KSTAT_KV_UNIT_INITIALIZER("MissPkt", 27301b7ab755Sdlg KSTAT_KV_T_COUNTER16, KSTAT_KV_U_PACKETS), 27311b7ab755Sdlg .fae = KSTAT_KV_UNIT_INITIALIZER("FAE", 27321b7ab755Sdlg KSTAT_KV_T_COUNTER16, KSTAT_KV_U_PACKETS), 27331b7ab755Sdlg .tx_1col = KSTAT_KV_UNIT_INITIALIZER("Tx1Col", 27341b7ab755Sdlg KSTAT_KV_T_COUNTER32, KSTAT_KV_U_PACKETS), 27351b7ab755Sdlg .tx_mcol = KSTAT_KV_UNIT_INITIALIZER("TxMCol", 27361b7ab755Sdlg KSTAT_KV_T_COUNTER32, KSTAT_KV_U_PACKETS), 27371b7ab755Sdlg .rx_ok_phy = KSTAT_KV_UNIT_INITIALIZER("RxOkPhy", 27381b7ab755Sdlg KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), 27391b7ab755Sdlg .rx_ok_brd = KSTAT_KV_UNIT_INITIALIZER("RxOkBrd", 27401b7ab755Sdlg KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS), 27411b7ab755Sdlg .rx_ok_mul = KSTAT_KV_UNIT_INITIALIZER("RxOkMul", 27421b7ab755Sdlg KSTAT_KV_T_COUNTER32, KSTAT_KV_U_PACKETS), 27431b7ab755Sdlg .tx_abt = KSTAT_KV_UNIT_INITIALIZER("TxAbt", 27441b7ab755Sdlg KSTAT_KV_T_COUNTER16, KSTAT_KV_U_PACKETS), 27451b7ab755Sdlg .tx_undrn = KSTAT_KV_UNIT_INITIALIZER("TxUndrn", 27461b7ab755Sdlg KSTAT_KV_T_COUNTER16, KSTAT_KV_U_PACKETS), 27471b7ab755Sdlg }; 27481b7ab755Sdlg 27491b7ab755Sdlg struct rge_kstat_softc { 27501b7ab755Sdlg struct rge_stats *rge_ks_sc_stats; 27511b7ab755Sdlg 27521b7ab755Sdlg bus_dmamap_t rge_ks_sc_map; 27531b7ab755Sdlg bus_dma_segment_t rge_ks_sc_seg; 27541b7ab755Sdlg int rge_ks_sc_nsegs; 27551b7ab755Sdlg 27561b7ab755Sdlg struct rwlock rge_ks_sc_rwl; 27571b7ab755Sdlg }; 27581b7ab755Sdlg 27591b7ab755Sdlg static int 27601b7ab755Sdlg rge_kstat_read(struct kstat *ks) 27611b7ab755Sdlg { 27621b7ab755Sdlg struct rge_softc *sc = ks->ks_softc; 27631b7ab755Sdlg struct rge_kstat_softc *rge_ks_sc = ks->ks_ptr; 27641b7ab755Sdlg bus_dmamap_t map; 27651b7ab755Sdlg uint64_t cmd; 27661b7ab755Sdlg uint32_t reg; 27671b7ab755Sdlg uint8_t command; 27681b7ab755Sdlg int tmo; 27691b7ab755Sdlg 27701b7ab755Sdlg command = RGE_READ_1(sc, RGE_CMD); 27711b7ab755Sdlg if (!ISSET(command, RGE_CMD_RXENB) || command == 0xff) 27721b7ab755Sdlg return (ENETDOWN); 27731b7ab755Sdlg 27741b7ab755Sdlg map = rge_ks_sc->rge_ks_sc_map; 27751b7ab755Sdlg cmd = map->dm_segs[0].ds_addr | RGE_DTCCR_CMD; 27761b7ab755Sdlg 27771b7ab755Sdlg bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 27781b7ab755Sdlg BUS_DMASYNC_PREREAD); 27791b7ab755Sdlg 27801b7ab755Sdlg RGE_WRITE_4(sc, RGE_DTCCR_HI, cmd >> 32); 27811b7ab755Sdlg bus_space_barrier(sc->rge_btag, sc->rge_bhandle, RGE_DTCCR_HI, 8, 27821b7ab755Sdlg BUS_SPACE_BARRIER_WRITE); 27831b7ab755Sdlg RGE_WRITE_4(sc, RGE_DTCCR_LO, cmd); 27841b7ab755Sdlg bus_space_barrier(sc->rge_btag, sc->rge_bhandle, RGE_DTCCR_LO, 4, 27851b7ab755Sdlg BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); 27861b7ab755Sdlg 27871b7ab755Sdlg tmo = 1000; 27881b7ab755Sdlg do { 27891b7ab755Sdlg reg = RGE_READ_4(sc, RGE_DTCCR_LO); 27901b7ab755Sdlg if (!ISSET(reg, RGE_DTCCR_CMD)) 27911b7ab755Sdlg break; 27921b7ab755Sdlg 27931b7ab755Sdlg delay(10); 27941b7ab755Sdlg bus_space_barrier(sc->rge_btag, sc->rge_bhandle, 27951b7ab755Sdlg RGE_DTCCR_LO, 4, BUS_SPACE_BARRIER_READ); 27961b7ab755Sdlg } while (--tmo); 27971b7ab755Sdlg 27981b7ab755Sdlg bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 27991b7ab755Sdlg BUS_DMASYNC_POSTREAD); 28001b7ab755Sdlg 28011b7ab755Sdlg if (ISSET(reg, RGE_DTCCR_CMD)) 28021b7ab755Sdlg return (EIO); 28031b7ab755Sdlg 28041b7ab755Sdlg nanouptime(&ks->ks_updated); 28051b7ab755Sdlg 28061b7ab755Sdlg return (0); 28071b7ab755Sdlg } 28081b7ab755Sdlg 28091b7ab755Sdlg static int 28101b7ab755Sdlg rge_kstat_copy(struct kstat *ks, void *dst) 28111b7ab755Sdlg { 28121b7ab755Sdlg struct rge_kstat_softc *rge_ks_sc = ks->ks_ptr; 28131b7ab755Sdlg struct rge_stats *rs = rge_ks_sc->rge_ks_sc_stats; 28141b7ab755Sdlg struct rge_kstats *kvs = dst; 28151b7ab755Sdlg 28161b7ab755Sdlg *kvs = rge_kstats_tpl; 28171b7ab755Sdlg kstat_kv_u64(&kvs->tx_ok) = lemtoh64(&rs->rge_tx_ok); 28181b7ab755Sdlg kstat_kv_u64(&kvs->rx_ok) = lemtoh64(&rs->rge_rx_ok); 28191b7ab755Sdlg kstat_kv_u64(&kvs->tx_er) = lemtoh64(&rs->rge_tx_er); 28201b7ab755Sdlg kstat_kv_u32(&kvs->rx_er) = lemtoh32(&rs->rge_rx_er); 28211b7ab755Sdlg kstat_kv_u16(&kvs->miss_pkt) = lemtoh16(&rs->rge_miss_pkt); 28221b7ab755Sdlg kstat_kv_u16(&kvs->fae) = lemtoh16(&rs->rge_fae); 28231b7ab755Sdlg kstat_kv_u32(&kvs->tx_1col) = lemtoh32(&rs->rge_tx_1col); 28241b7ab755Sdlg kstat_kv_u32(&kvs->tx_mcol) = lemtoh32(&rs->rge_tx_mcol); 28251b7ab755Sdlg kstat_kv_u64(&kvs->rx_ok_phy) = lemtoh64(&rs->rge_rx_ok_phy); 28261b7ab755Sdlg kstat_kv_u64(&kvs->rx_ok_brd) = lemtoh64(&rs->rge_rx_ok_brd); 28271b7ab755Sdlg kstat_kv_u32(&kvs->rx_ok_mul) = lemtoh32(&rs->rge_rx_ok_mul); 28281b7ab755Sdlg kstat_kv_u16(&kvs->tx_abt) = lemtoh16(&rs->rge_tx_abt); 28291b7ab755Sdlg kstat_kv_u16(&kvs->tx_undrn) = lemtoh16(&rs->rge_tx_undrn); 28301b7ab755Sdlg 28311b7ab755Sdlg return (0); 28321b7ab755Sdlg } 28331b7ab755Sdlg 28341b7ab755Sdlg void 28351b7ab755Sdlg rge_kstat_attach(struct rge_softc *sc) 28361b7ab755Sdlg { 28371b7ab755Sdlg struct rge_kstat_softc *rge_ks_sc; 28381b7ab755Sdlg struct kstat *ks; 28391b7ab755Sdlg 28401b7ab755Sdlg rge_ks_sc = malloc(sizeof(*rge_ks_sc), M_DEVBUF, M_NOWAIT); 28411b7ab755Sdlg if (rge_ks_sc == NULL) { 28421b7ab755Sdlg printf("%s: cannot allocate kstat softc\n", 28431b7ab755Sdlg sc->sc_dev.dv_xname); 28441b7ab755Sdlg return; 28451b7ab755Sdlg } 28461b7ab755Sdlg 28471b7ab755Sdlg if (bus_dmamap_create(sc->sc_dmat, 28481b7ab755Sdlg sizeof(struct rge_stats), 1, sizeof(struct rge_stats), 0, 28491b7ab755Sdlg BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, 28501b7ab755Sdlg &rge_ks_sc->rge_ks_sc_map) != 0) { 28511b7ab755Sdlg printf("%s: cannot create counter dma memory map\n", 28521b7ab755Sdlg sc->sc_dev.dv_xname); 28531b7ab755Sdlg goto free; 28541b7ab755Sdlg } 28551b7ab755Sdlg 28561b7ab755Sdlg if (bus_dmamem_alloc(sc->sc_dmat, 28571b7ab755Sdlg sizeof(struct rge_stats), RGE_STATS_ALIGNMENT, 0, 28581b7ab755Sdlg &rge_ks_sc->rge_ks_sc_seg, 1, &rge_ks_sc->rge_ks_sc_nsegs, 28591b7ab755Sdlg BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0) { 28601b7ab755Sdlg printf("%s: cannot allocate counter dma memory\n", 28611b7ab755Sdlg sc->sc_dev.dv_xname); 28621b7ab755Sdlg goto destroy; 28631b7ab755Sdlg } 28641b7ab755Sdlg 28651b7ab755Sdlg if (bus_dmamem_map(sc->sc_dmat, 28661b7ab755Sdlg &rge_ks_sc->rge_ks_sc_seg, rge_ks_sc->rge_ks_sc_nsegs, 28671b7ab755Sdlg sizeof(struct rge_stats), (caddr_t *)&rge_ks_sc->rge_ks_sc_stats, 28681b7ab755Sdlg BUS_DMA_NOWAIT) != 0) { 28691b7ab755Sdlg printf("%s: cannot map counter dma memory\n", 28701b7ab755Sdlg sc->sc_dev.dv_xname); 28711b7ab755Sdlg goto freedma; 28721b7ab755Sdlg } 28731b7ab755Sdlg 28741b7ab755Sdlg if (bus_dmamap_load(sc->sc_dmat, rge_ks_sc->rge_ks_sc_map, 28751b7ab755Sdlg (caddr_t)rge_ks_sc->rge_ks_sc_stats, sizeof(struct rge_stats), 28761b7ab755Sdlg NULL, BUS_DMA_NOWAIT) != 0) { 28771b7ab755Sdlg printf("%s: cannot load counter dma memory\n", 28781b7ab755Sdlg sc->sc_dev.dv_xname); 28791b7ab755Sdlg goto unmap; 28801b7ab755Sdlg } 28811b7ab755Sdlg 28821b7ab755Sdlg ks = kstat_create(sc->sc_dev.dv_xname, 0, "re-stats", 0, 28831b7ab755Sdlg KSTAT_T_KV, 0); 28841b7ab755Sdlg if (ks == NULL) { 28851b7ab755Sdlg printf("%s: cannot create re-stats kstat\n", 28861b7ab755Sdlg sc->sc_dev.dv_xname); 28871b7ab755Sdlg goto unload; 28881b7ab755Sdlg } 28891b7ab755Sdlg 28901b7ab755Sdlg ks->ks_datalen = sizeof(rge_kstats_tpl); 28911b7ab755Sdlg 28921b7ab755Sdlg rw_init(&rge_ks_sc->rge_ks_sc_rwl, "rgestats"); 28931b7ab755Sdlg kstat_set_wlock(ks, &rge_ks_sc->rge_ks_sc_rwl); 28941b7ab755Sdlg ks->ks_softc = sc; 28951b7ab755Sdlg ks->ks_ptr = rge_ks_sc; 28961b7ab755Sdlg ks->ks_read = rge_kstat_read; 28971b7ab755Sdlg ks->ks_copy = rge_kstat_copy; 28981b7ab755Sdlg 28991b7ab755Sdlg kstat_install(ks); 29001b7ab755Sdlg 29011b7ab755Sdlg sc->sc_kstat = ks; 29021b7ab755Sdlg 29031b7ab755Sdlg return; 29041b7ab755Sdlg 29051b7ab755Sdlg unload: 29061b7ab755Sdlg bus_dmamap_unload(sc->sc_dmat, rge_ks_sc->rge_ks_sc_map); 29071b7ab755Sdlg unmap: 29081b7ab755Sdlg bus_dmamem_unmap(sc->sc_dmat, 29091b7ab755Sdlg (caddr_t)rge_ks_sc->rge_ks_sc_stats, sizeof(struct rge_stats)); 29101b7ab755Sdlg freedma: 29111b7ab755Sdlg bus_dmamem_free(sc->sc_dmat, &rge_ks_sc->rge_ks_sc_seg, 1); 29121b7ab755Sdlg destroy: 29131b7ab755Sdlg bus_dmamap_destroy(sc->sc_dmat, rge_ks_sc->rge_ks_sc_map); 29141b7ab755Sdlg free: 29151b7ab755Sdlg free(rge_ks_sc, M_DEVBUF, sizeof(*rge_ks_sc)); 29161b7ab755Sdlg } 29171b7ab755Sdlg #endif /* NKSTAT > 0 */ 2918