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