diff options
author | 2019-09-29 13:04:03 +0000 | |
---|---|---|
committer | 2019-09-29 13:04:03 +0000 | |
commit | 3f5722111e94285b5cc9b9505ea26905f65d02d8 (patch) | |
tree | 6196f744bc55532bc9854a0b0f4a3372ddc5a46e | |
parent | Improve MSI support by parsing the "msi-map" attribute. Taken from (diff) | |
download | wireguard-openbsd-3f5722111e94285b5cc9b9505ea26905f65d02d8.tar.xz wireguard-openbsd-3f5722111e94285b5cc9b9505ea26905f65d02d8.zip |
Replace dwge(4) with a new driver based on dwxe(4). There are many
similarities between the two and using a common approach helps fixing bugs.
The new driver is better integrated with the device tree framework and
is faster (mainly because the DMA engine is configured properly now).
Tested on all currently supported variants of the hardware.
ok jsg@, jmatthew@
-rw-r--r-- | sys/conf/files | 7 | ||||
-rw-r--r-- | sys/dev/fdt/files.fdt | 8 | ||||
-rw-r--r-- | sys/dev/fdt/if_dwge.c | 1499 | ||||
-rw-r--r-- | sys/dev/fdt/if_dwge_fdt.c | 379 | ||||
-rw-r--r-- | sys/dev/fdt/if_dwxe.c | 7 | ||||
-rw-r--r-- | sys/dev/ic/dwc_gmac.c | 1419 | ||||
-rw-r--r-- | sys/dev/ic/dwc_gmac_reg.h | 231 | ||||
-rw-r--r-- | sys/dev/ic/dwc_gmac_var.h | 96 |
8 files changed, 1508 insertions, 2138 deletions
diff --git a/sys/conf/files b/sys/conf/files index 4a8d3f430c4..a8a08a19475 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.673 2019/08/01 03:06:35 dlg Exp $ +# $OpenBSD: files,v 1.674 2019/09/29 13:04:03 kettenis Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -312,11 +312,6 @@ file dev/ic/i82596.c ie & (ie_pci | ie_eisa | ie_gsc) device gem: ether, ifnet, ifmedia, mii file dev/ic/gem.c gem -# Synopsis Designware GMAC core, as found on Allwinner A20 -# and other SoCs -device dwge: ether, ifnet, ifmedia, mii -file dev/ic/dwc_gmac.c dwge - device ti: ether, ifnet, ifmedia, mii, firmload file dev/ic/ti.c ti diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index 28390fee6dc..5786cbc5bc4 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $OpenBSD: files.fdt,v 1.92 2019/09/07 13:32:36 patrick Exp $ +# $OpenBSD: files.fdt,v 1.93 2019/09/29 13:04:03 kettenis Exp $ # # Config file and device description for machine-independent FDT code. # Included by ports that need it. @@ -107,8 +107,10 @@ file dev/fdt/virtio_mmio.c virtio_mmio attach ahci at fdt with ahci_fdt file dev/fdt/ahci_fdt.c ahci_fdt -attach dwge at fdt with dwge_fdt -file dev/fdt/if_dwge_fdt.c dwge_fdt +# Synopsis Designware GMAC core +device dwge: ether, ifnet, mii, ifmedia +attach dwge at fdt +file dev/fdt/if_dwge.c dwge attach ehci at fdt with ehci_fdt file dev/fdt/ehci_fdt.c ehci_fdt diff --git a/sys/dev/fdt/if_dwge.c b/sys/dev/fdt/if_dwge.c new file mode 100644 index 00000000000..55928b49759 --- /dev/null +++ b/sys/dev/fdt/if_dwge.c @@ -0,0 +1,1499 @@ +/* $OpenBSD: if_dwge.c,v 1.1 2019/09/29 13:04:03 kettenis Exp $ */ +/* + * Copyright (c) 2008, 2019 Mark Kettenis <kettenis@openbsd.org> + * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Driver for the Synopsys Designware ethernet controller. + */ + +#include "bpfilter.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/timeout.h> + +#include <machine/bus.h> +#include <machine/fdt.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/ofw_clock.h> +#include <dev/ofw/ofw_gpio.h> +#include <dev/ofw/ofw_misc.h> +#include <dev/ofw/ofw_pinctrl.h> +#include <dev/ofw/ofw_regulator.h> +#include <dev/ofw/fdt.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#if NBPFILTER > 0 +#include <net/bpf.h> +#endif + +#include <netinet/in.h> +#include <netinet/if_ether.h> + +/* Registers */ + +#define GMAC_MAC_CONF 0x0000 +#define GMAC_MAC_CONF_JD (1 << 22) +#define GMAC_MAC_CONF_BE (1 << 21) +#define GMAC_MAC_CONF_DCRS (1 << 16) +#define GMAC_MAC_CONF_PS (1 << 15) +#define GMAC_MAC_CONF_FES (1 << 14) +#define GMAC_MAC_CONF_LM (1 << 12) +#define GMAC_MAC_CONF_DM (1 << 11) +#define GMAC_MAC_CONF_TE (1 << 3) +#define GMAC_MAC_CONF_RE (1 << 2) +#define GMAC_MAC_FRM_FILT 0x0004 +#define GMAC_MAC_FRM_FILT_PM (1 << 4) +#define GMAC_MAC_FRM_FILT_HMC (1 << 2) +#define GMAC_MAC_FRM_FILT_PR (1 << 0) +#define GMAC_HASH_TAB_HI 0x0008 +#define GMAC_HASH_TAB_LO 0x000c +#define GMAC_GMII_ADDR 0x0010 +#define GMAC_GMII_ADDR_PA_SHIFT 11 +#define GMAC_GMII_ADDR_GR_SHIFT 6 +#define GMAC_GMII_ADDR_CR_SHIFT 2 +#define GMAC_GMII_ADDR_CR_MASK 0xf +#define GMAC_GMII_ADDR_CR_DIV_42 0 +#define GMAC_GMII_ADDR_CR_DIV_62 1 +#define GMAC_GMII_ADDR_CR_DIV_16 2 +#define GMAC_GMII_ADDR_CR_DIV_26 3 +#define GMAC_GMII_ADDR_CR_DIV_102 4 +#define GMAC_GMII_ADDR_CR_DIV_124 5 +#define GMAC_GMII_ADDR_GW (1 << 1) +#define GMAC_GMII_ADDR_GB (1 << 0) +#define GMAC_GMII_DATA 0x0014 +#define GMAC_INT_MASK 0x003c +#define GMAC_INT_MASK_PIM (1 << 3) +#define GMAC_INT_MASK_RIM (1 << 0) +#define GMAC_MAC_ADDR0_HI 0x0040 +#define GMAC_MAC_ADDR0_LO 0x0044 +#define GMAC_MMC_RX_INT_MSK 0x010c +#define GMAC_MMC_TX_INT_MSK 0x0110 +#define GMAC_MMC_IPC_INT_MSK 0x0200 +#define GMAC_BUS_MODE 0x1000 +#define GMAC_BUS_MODE_8XPBL (1 << 24) +#define GMAC_BUS_MODE_USP (1 << 23) +#define GMAC_BUS_MODE_RPBL_MASK (0x3f << 17) +#define GMAC_BUS_MODE_RPBL_SHIFT 17 +#define GMAC_BUS_MODE_FB (1 << 16) +#define GMAC_BUS_MODE_PBL_MASK (0x3f << 8) +#define GMAC_BUS_MODE_PBL_SHIFT 8 +#define GMAC_BUS_MODE_SWR (1 << 0) +#define GMAC_TX_POLL_DEMAND 0x1004 +#define GMAC_RX_DESC_LIST_ADDR 0x100c +#define GMAC_TX_DESC_LIST_ADDR 0x1010 +#define GMAC_STATUS 0x1014 +#define GMAC_STATUS_RI (1 << 6) +#define GMAC_STATUS_TU (1 << 2) +#define GMAC_STATUS_TI (1 << 0) +#define GMAC_OP_MODE 0x1018 +#define GMAC_OP_MODE_RSF (1 << 25) +#define GMAC_OP_MODE_TSF (1 << 21) +#define GMAC_OP_MODE_FTF (1 << 20) +#define GMAC_OP_MODE_TTC_MASK (0x7 << 14) +#define GMAC_OP_MODE_TTC_64 (0x0 << 14) +#define GMAC_OP_MODE_TTC_128 (0x1 << 14) +#define GMAC_OP_MODE_ST (1 << 13) +#define GMAC_OP_MODE_RTC_MASK (0x3 << 3) +#define GMAC_OP_MODE_RTC_64 (0x0 << 3) +#define GMAC_OP_MODE_RTC_128 (0x3 << 3) +#define GMAC_OP_MODE_OSF (1 << 2) +#define GMAC_OP_MODE_SR (1 << 1) +#define GMAC_INT_ENA 0x101c +#define GMAC_INT_ENA_NIE (1 << 16) +#define GMAC_INT_ENA_RIE (1 << 6) +#define GMAC_INT_ENA_TUE (1 << 2) +#define GMAC_INT_ENA_TIE (1 << 0) + +/* + * DWGE descriptors. + */ + +struct dwge_desc { + uint32_t sd_status; + uint32_t sd_len; + uint32_t sd_addr; + uint32_t sd_next; +}; + +/* Tx status bits. */ +#define TDES0_DB (1 << 0) +#define TDES0_UF (1 << 1) +#define TDES0_ED (1 << 2) +#define TDES0_CC_MASK (0xf << 3) +#define TDES0_CC_SHIFT 3 +#define TDES0_EC (1 << 8) +#define TDES0_LC (1 << 9) +#define TDES0_NC (1 << 10) +#define TDES0_PCE (1 << 12) +#define TDES0_JT (1 << 14) +#define TDES0_IHE (1 << 16) +#define TDES0_OWN (1 << 31) + +/* Rx status bits */ +#define RDES0_PE (1 << 0) +#define RDES0_CE (1 << 1) +#define RDES0_RE (1 << 3) +#define RDES0_RWT (1 << 4) +#define RDES0_FT (1 << 5) +#define RDES0_LC (1 << 6) +#define RDES0_IPC (1 << 7) +#define RDES0_LS (1 << 8) +#define RDES0_FS (1 << 9) +#define RDES0_OE (1 << 11) +#define RDES0_SAF (1 << 13) +#define RDES0_DE (1 << 14) +#define RDES0_FL_MASK 0x3fff +#define RDES0_FL_SHIFT 16 +#define RDES0_AFM (1 << 30) +#define RDES0_OWN (1 << 31) + +/* Tx size bits */ +#define TDES1_TBS1 (0xfff << 0) +#define TDES1_TCH (1 << 24) +#define TDES1_DC (1 << 26) +#define TDES1_CIC_MASK (0x3 << 27) +#define TDES1_CIC_IP (1 << 27) +#define TDES1_CIC_NO_PSE (2 << 27) +#define TDES1_CIC_FULL (3 << 27) +#define TDES1_FS (1 << 29) +#define TDES1_LS (1 << 30) +#define TDES1_IC (1 << 31) + +/* Rx size bits */ +#define RDES1_RBS1 (0xfff << 0) +#define RDES1_RCH (1 << 24) +#define RDES1_DIC (1 << 31) + +struct dwge_buf { + bus_dmamap_t tb_map; + struct mbuf *tb_m; +}; + +#define DWGE_NTXDESC 512 +#define DWGE_NTXSEGS 16 + +#define DWGE_NRXDESC 512 + +struct dwge_dmamem { + bus_dmamap_t tdm_map; + bus_dma_segment_t tdm_seg; + size_t tdm_size; + caddr_t tdm_kva; +}; +#define DWGE_DMA_MAP(_tdm) ((_tdm)->tdm_map) +#define DWGE_DMA_LEN(_tdm) ((_tdm)->tdm_size) +#define DWGE_DMA_DVA(_tdm) ((_tdm)->tdm_map->dm_segs[0].ds_addr) +#define DWGE_DMA_KVA(_tdm) ((void *)(_tdm)->tdm_kva) + +struct dwge_softc { + struct device sc_dev; + int sc_node; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + bus_dma_tag_t sc_dmat; + + struct arpcom sc_ac; +#define sc_lladdr sc_ac.ac_enaddr + struct mii_data sc_mii; +#define sc_media sc_mii.mii_media + int sc_link; + int sc_phyloc; + int sc_force_thresh_dma_mode; + + struct dwge_dmamem *sc_txring; + struct dwge_buf *sc_txbuf; + struct dwge_desc *sc_txdesc; + int sc_tx_prod; + int sc_tx_cnt; + int sc_tx_cons; + + struct dwge_dmamem *sc_rxring; + struct dwge_buf *sc_rxbuf; + struct dwge_desc *sc_rxdesc; + int sc_rx_prod; + struct if_rxring sc_rx_ring; + int sc_rx_cons; + + struct timeout sc_tick; + struct timeout sc_rxto; + + uint32_t sc_clk; + + bus_size_t sc_clk_sel; + uint32_t sc_clk_sel_125; + uint32_t sc_clk_sel_25; + uint32_t sc_clk_sel_2_5; +}; + +#define DEVNAME(_s) ((_s)->sc_dev.dv_xname) + +int dwge_match(struct device *, void *, void *); +void dwge_attach(struct device *, struct device *, void *); +void dwge_setup_allwinner(struct dwge_softc *); +void dwge_setup_rockchip(struct dwge_softc *); + +struct cfattach dwge_ca = { + sizeof(struct dwge_softc), dwge_match, dwge_attach +}; + +struct cfdriver dwge_cd = { + NULL, "dwge", DV_IFNET +}; + +void dwge_reset_phy(struct dwge_softc *); + +uint32_t dwge_read(struct dwge_softc *, bus_addr_t); +void dwge_write(struct dwge_softc *, bus_addr_t, uint32_t); + +int dwge_ioctl(struct ifnet *, u_long, caddr_t); +void dwge_start(struct ifnet *); +void dwge_watchdog(struct ifnet *); + +int dwge_media_change(struct ifnet *); +void dwge_media_status(struct ifnet *, struct ifmediareq *); + +int dwge_mii_readreg(struct device *, int, int); +void dwge_mii_writereg(struct device *, int, int, int); +void dwge_mii_statchg(struct device *); + +void dwge_lladdr_read(struct dwge_softc *, uint8_t *); +void dwge_lladdr_write(struct dwge_softc *); + +void dwge_tick(void *); +void dwge_rxtick(void *); + +int dwge_intr(void *); +void dwge_tx_proc(struct dwge_softc *); +void dwge_rx_proc(struct dwge_softc *); + +void dwge_up(struct dwge_softc *); +void dwge_down(struct dwge_softc *); +void dwge_iff(struct dwge_softc *); +int dwge_encap(struct dwge_softc *, struct mbuf *, int *); + +void dwge_reset(struct dwge_softc *); +void dwge_stop_dma(struct dwge_softc *); + +struct dwge_dmamem * + dwge_dmamem_alloc(struct dwge_softc *, bus_size_t, bus_size_t); +void dwge_dmamem_free(struct dwge_softc *, struct dwge_dmamem *); +struct mbuf *dwge_alloc_mbuf(struct dwge_softc *, bus_dmamap_t); +void dwge_fill_rx_ring(struct dwge_softc *); + +int +dwge_match(struct device *parent, void *cfdata, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return (OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-gmac") || + OF_is_compatible(faa->fa_node, "amlogic,meson-axg-dwmac") || + OF_is_compatible(faa->fa_node, "rockchip,rk3288-gmac") || + OF_is_compatible(faa->fa_node, "rockchip,rk3328-gmac") || + OF_is_compatible(faa->fa_node, "rockchip,rk3399-gmac")); +} + +void +dwge_attach(struct device *parent, struct device *self, void *aux) +{ + struct dwge_softc *sc = (void *)self; + struct fdt_attach_args *faa = aux; + struct ifnet *ifp; + uint32_t phy, phy_supply; + uint32_t mode, pbl; + int node; + + sc->sc_node = faa->fa_node; + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[0].size, 0, &sc->sc_ioh)) { + printf("%s: cannot map registers\n", self->dv_xname); + return; + } + sc->sc_dmat = faa->fa_dmat; + + /* Lookup PHY. */ + phy = OF_getpropint(faa->fa_node, "phy", 0); + if (phy == 0) + phy = OF_getpropint(faa->fa_node, "phy-handle", 0); + node = OF_getnodebyphandle(phy); + if (node) + sc->sc_phyloc = OF_getpropint(node, "reg", MII_PHY_ANY); + else + sc->sc_phyloc = MII_PHY_ANY; + + pinctrl_byname(faa->fa_node, "default"); + + /* Enable clock. */ + clock_enable(faa->fa_node, "stmmaceth"); + reset_deassert(faa->fa_node, "stmmaceth"); + delay(5000); + + /* Power up PHY. */ + phy_supply = OF_getpropint(faa->fa_node, "phy-supply", 0); + if (phy_supply) + regulator_enable(phy_supply); + + /* Reset PHY */ + dwge_reset_phy(sc); + + sc->sc_clk = clock_get_frequency(faa->fa_node, "stmmaceth"); + if (sc->sc_clk > 250000000) + sc->sc_clk = GMAC_GMII_ADDR_CR_DIV_124; + else if (sc->sc_clk > 150000000) + sc->sc_clk = GMAC_GMII_ADDR_CR_DIV_102; + else if (sc->sc_clk > 100000000) + sc->sc_clk = GMAC_GMII_ADDR_CR_DIV_62; + else if (sc->sc_clk > 60000000) + sc->sc_clk = GMAC_GMII_ADDR_CR_DIV_42; + else if (sc->sc_clk > 35000000) + sc->sc_clk = GMAC_GMII_ADDR_CR_DIV_26; + else + sc->sc_clk = GMAC_GMII_ADDR_CR_DIV_16; + + if (OF_getprop(faa->fa_node, "local-mac-address", + &sc->sc_lladdr, ETHER_ADDR_LEN) != ETHER_ADDR_LEN) + dwge_lladdr_read(sc, sc->sc_lladdr); + printf(": address %s\n", ether_sprintf(sc->sc_lladdr)); + + timeout_set(&sc->sc_tick, dwge_tick, sc); + timeout_set(&sc->sc_rxto, dwge_rxtick, sc); + + ifp = &sc->sc_ac.ac_if; + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = dwge_ioctl; + ifp->if_start = dwge_start; + ifp->if_watchdog = dwge_watchdog; + IFQ_SET_MAXLEN(&ifp->if_snd, DWGE_NTXDESC - 1); + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + + ifp->if_capabilities = IFCAP_VLAN_MTU; + + sc->sc_mii.mii_ifp = ifp; + sc->sc_mii.mii_readreg = dwge_mii_readreg; + sc->sc_mii.mii_writereg = dwge_mii_writereg; + sc->sc_mii.mii_statchg = dwge_mii_statchg; + + ifmedia_init(&sc->sc_media, 0, dwge_media_change, dwge_media_status); + + /* Do hardware specific initializations. */ + if (OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-gmac")) + dwge_setup_allwinner(sc); + else if (OF_is_compatible(faa->fa_node, "rockchip,rk3288-gmac")) + dwge_setup_rockchip(sc); + else if (OF_is_compatible(faa->fa_node, "rockchip,rk3328-gmac")) + dwge_setup_rockchip(sc); + else if (OF_is_compatible(faa->fa_node, "rockchip,rk3399-gmac")) + dwge_setup_rockchip(sc); + + if (OF_getproplen(faa->fa_node, "snps,force_thresh_dma_mode") == 0) + sc->sc_force_thresh_dma_mode = 1; + + dwge_reset(sc); + + /* Configure MAC. */ + dwge_write(sc, GMAC_MAC_CONF, dwge_read(sc, GMAC_MAC_CONF) | + GMAC_MAC_CONF_JD | GMAC_MAC_CONF_BE | GMAC_MAC_CONF_DCRS); + + /* Configure DMA engine. */ + mode = dwge_read(sc, GMAC_BUS_MODE); + mode |= GMAC_BUS_MODE_8XPBL | GMAC_BUS_MODE_USP; + mode &= ~(GMAC_BUS_MODE_RPBL_MASK | GMAC_BUS_MODE_PBL_MASK); + pbl = OF_getpropint(faa->fa_node, "snps,pbl", 8); + mode |= pbl << GMAC_BUS_MODE_RPBL_SHIFT; + mode |= pbl << GMAC_BUS_MODE_PBL_SHIFT; + if (OF_getproplen(faa->fa_node, "snps,fixed-burst") == 0) + mode |= GMAC_BUS_MODE_FB; + dwge_write(sc, GMAC_BUS_MODE, mode); + + mii_attach(self, &sc->sc_mii, 0xffffffff, sc->sc_phyloc, + (sc->sc_phyloc == MII_PHY_ANY) ? 0 : MII_OFFSET_ANY, 0); + if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { + printf("%s: no PHY found!\n", sc->sc_dev.dv_xname); + ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); + ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL); + } else + ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO); + + if_attach(ifp); + ether_ifattach(ifp); + + /* Disable interrupts. */ + dwge_write(sc, GMAC_INT_ENA, 0); + dwge_write(sc, GMAC_INT_MASK, GMAC_INT_MASK_PIM | GMAC_INT_MASK_RIM); + dwge_write(sc, GMAC_MMC_RX_INT_MSK, 0xffffffff); + dwge_write(sc, GMAC_MMC_TX_INT_MSK, 0xffffffff); + dwge_write(sc, GMAC_MMC_IPC_INT_MSK, 0xffffffff); + + fdt_intr_establish(faa->fa_node, IPL_NET, dwge_intr, sc, + sc->sc_dev.dv_xname); +} + +void +dwge_reset_phy(struct dwge_softc *sc) +{ + uint32_t *gpio; + uint32_t delays[3]; + int active = 1; + int len; + + len = OF_getproplen(sc->sc_node, "snps,reset-gpio"); + if (len <= 0) + return; + + gpio = malloc(len, M_TEMP, M_WAITOK); + + /* Gather information. */ + OF_getpropintarray(sc->sc_node, "snps,reset-gpio", gpio, len); + if (OF_getproplen(sc->sc_node, "snps-reset-active-low") == 0) + active = 0; + delays[0] = delays[1] = delays[2] = 0; + OF_getpropintarray(sc->sc_node, "snps,reset-delay-us", delays, + sizeof(delays)); + + /* Perform reset sequence. */ + gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT); + gpio_controller_set_pin(gpio, !active); + delay(delays[0]); + gpio_controller_set_pin(gpio, active); + delay(delays[1]); + gpio_controller_set_pin(gpio, !active); + delay(delays[2]); + + free(gpio, M_TEMP, len); +} + +uint32_t +dwge_read(struct dwge_softc *sc, bus_addr_t addr) +{ + return bus_space_read_4(sc->sc_iot, sc->sc_ioh, addr); +} + +void +dwge_write(struct dwge_softc *sc, bus_addr_t addr, uint32_t data) +{ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, addr, data); +} + +void +dwge_lladdr_read(struct dwge_softc *sc, uint8_t *lladdr) +{ + uint32_t machi, maclo; + + machi = dwge_read(sc, GMAC_MAC_ADDR0_HI); + maclo = dwge_read(sc, GMAC_MAC_ADDR0_LO); + + lladdr[0] = (maclo >> 0) & 0xff; + lladdr[1] = (maclo >> 8) & 0xff; + lladdr[2] = (maclo >> 16) & 0xff; + lladdr[3] = (maclo >> 24) & 0xff; + lladdr[4] = (machi >> 0) & 0xff; + lladdr[5] = (machi >> 8) & 0xff; +} + +void +dwge_lladdr_write(struct dwge_softc *sc) +{ + dwge_write(sc, GMAC_MAC_ADDR0_HI, + sc->sc_lladdr[5] << 8 | sc->sc_lladdr[4] << 0); + dwge_write(sc, GMAC_MAC_ADDR0_LO, + sc->sc_lladdr[3] << 24 | sc->sc_lladdr[2] << 16 | + sc->sc_lladdr[1] << 8 | sc->sc_lladdr[0] << 0); +} + +void +dwge_start(struct ifnet *ifp) +{ + struct dwge_softc *sc = ifp->if_softc; + struct mbuf *m; + int error, idx; + + if (!(ifp->if_flags & IFF_RUNNING)) + return; + if (ifq_is_oactive(&ifp->if_snd)) + return; + if (IFQ_IS_EMPTY(&ifp->if_snd)) + return; + if (!sc->sc_link) + return; + + idx = sc->sc_tx_prod; + while ((sc->sc_txdesc[idx].sd_status & TDES0_OWN) == 0) { + m = ifq_deq_begin(&ifp->if_snd); + if (m == NULL) + break; + + error = dwge_encap(sc, m, &idx); + if (error == ENOBUFS) { + ifq_deq_rollback(&ifp->if_snd, m); + ifq_set_oactive(&ifp->if_snd); + break; + } + if (error == EFBIG) { + ifq_deq_commit(&ifp->if_snd, m); + m_freem(m); /* give up: drop it */ + ifp->if_oerrors++; + continue; + } + + /* Now we are committed to transmit the packet. */ + ifq_deq_commit(&ifp->if_snd, m); + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); +#endif + } + + if (sc->sc_tx_prod != idx) { + sc->sc_tx_prod = idx; + + /* Set a timeout in case the chip goes out to lunch. */ + ifp->if_timer = 5; + } +} + +int +dwge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr) +{ + struct dwge_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)addr; + int error = 0, s; + + s = splnet(); + + switch (cmd) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + /* FALLTHROUGH */ + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (ifp->if_flags & IFF_RUNNING) + error = ENETRESET; + else + dwge_up(sc); + } else { + if (ifp->if_flags & IFF_RUNNING) + dwge_down(sc); + } + break; + + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); + break; + + case SIOCGIFRXR: + error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data, + NULL, MCLBYTES, &sc->sc_rx_ring); + break; + + default: + error = ether_ioctl(ifp, &sc->sc_ac, cmd, addr); + break; + } + + if (error == ENETRESET) { + if (ifp->if_flags & IFF_RUNNING) + dwge_iff(sc); + error = 0; + } + + splx(s); + return (error); +} + +void +dwge_watchdog(struct ifnet *ifp) +{ + printf("%s\n", __func__); +} + +int +dwge_media_change(struct ifnet *ifp) +{ + struct dwge_softc *sc = ifp->if_softc; + + if (LIST_FIRST(&sc->sc_mii.mii_phys)) + mii_mediachg(&sc->sc_mii); + + return (0); +} + +void +dwge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct dwge_softc *sc = ifp->if_softc; + + if (LIST_FIRST(&sc->sc_mii.mii_phys)) { + mii_pollstat(&sc->sc_mii); + ifmr->ifm_active = sc->sc_mii.mii_media_active; + ifmr->ifm_status = sc->sc_mii.mii_media_status; + } +} + +int +dwge_mii_readreg(struct device *self, int phy, int reg) +{ + struct dwge_softc *sc = (void *)self; + int n; + + dwge_write(sc, GMAC_GMII_ADDR, + sc->sc_clk << GMAC_GMII_ADDR_CR_SHIFT | + phy << GMAC_GMII_ADDR_PA_SHIFT | + reg << GMAC_GMII_ADDR_GR_SHIFT | + GMAC_GMII_ADDR_GB); + for (n = 0; n < 1000; n++) { + if ((dwge_read(sc, GMAC_GMII_ADDR) & GMAC_GMII_ADDR_GB) == 0) + return dwge_read(sc, GMAC_GMII_DATA); + delay(10); + } + + printf("%s: mii_read timeout\n", sc->sc_dev.dv_xname); + return (0); +} + +void +dwge_mii_writereg(struct device *self, int phy, int reg, int val) +{ + struct dwge_softc *sc = (void *)self; + int n; + + dwge_write(sc, GMAC_GMII_DATA, val); + dwge_write(sc, GMAC_GMII_ADDR, + sc->sc_clk << GMAC_GMII_ADDR_CR_SHIFT | + phy << GMAC_GMII_ADDR_PA_SHIFT | + reg << GMAC_GMII_ADDR_GR_SHIFT | + GMAC_GMII_ADDR_GW | GMAC_GMII_ADDR_GB); + for (n = 0; n < 1000; n++) { + if ((dwge_read(sc, GMAC_GMII_ADDR) & GMAC_GMII_ADDR_GB) == 0) + return; + delay(10); + } + + printf("%s: mii_write timeout\n", sc->sc_dev.dv_xname); +} + +void +dwge_mii_statchg(struct device *self) +{ + struct dwge_softc *sc = (void *)self; + uint32_t conf; + + conf = dwge_read(sc, GMAC_MAC_CONF); + conf &= ~(GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES); + + switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) { + case IFM_1000_SX: + case IFM_1000_LX: + case IFM_1000_CX: + case IFM_1000_T: + sc->sc_link = 1; + break; + case IFM_100_TX: + conf |= GMAC_MAC_CONF_PS | GMAC_MAC_CONF_FES; + sc->sc_link = 1; + break; + case IFM_10_T: + conf |= GMAC_MAC_CONF_PS; + sc->sc_link = 1; + break; + default: + sc->sc_link = 0; + return; + } + + if (sc->sc_link == 0) + return; + + conf &= ~GMAC_MAC_CONF_DM; + if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX) + conf |= GMAC_MAC_CONF_DM; + + /* XXX: RX/TX flow control? */ + + dwge_write(sc, GMAC_MAC_CONF, conf); +} + +void +dwge_tick(void *arg) +{ + struct dwge_softc *sc = arg; + int s; + + s = splnet(); + mii_tick(&sc->sc_mii); + splx(s); + + timeout_add_sec(&sc->sc_tick, 1); +} + +void +dwge_rxtick(void *arg) +{ + struct dwge_softc *sc = arg; + uint32_t mode; + int s; + + s = splnet(); + + mode = dwge_read(sc, GMAC_OP_MODE); + dwge_write(sc, GMAC_OP_MODE, mode & ~GMAC_OP_MODE_SR); + + bus_dmamap_sync(sc->sc_dmat, DWGE_DMA_MAP(sc->sc_rxring), + 0, DWGE_DMA_LEN(sc->sc_rxring), + BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); + + dwge_write(sc, GMAC_RX_DESC_LIST_ADDR, 0); + + sc->sc_rx_prod = sc->sc_rx_cons = 0; + dwge_fill_rx_ring(sc); + + bus_dmamap_sync(sc->sc_dmat, DWGE_DMA_MAP(sc->sc_rxring), + 0, DWGE_DMA_LEN(sc->sc_rxring), + BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + + dwge_write(sc, GMAC_RX_DESC_LIST_ADDR, DWGE_DMA_DVA(sc->sc_rxring)); + dwge_write(sc, GMAC_OP_MODE, mode); + + splx(s); +} + +int +dwge_intr(void *arg) +{ + struct dwge_softc *sc = arg; + uint32_t reg; + + reg = dwge_read(sc, GMAC_STATUS); + dwge_write(sc, GMAC_STATUS, reg); + + if (reg & GMAC_STATUS_RI) + dwge_rx_proc(sc); + + if (reg & GMAC_STATUS_TI || + reg & GMAC_STATUS_TU) + dwge_tx_proc(sc); + + return (1); +} + +void +dwge_tx_proc(struct dwge_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct dwge_desc *txd; + struct dwge_buf *txb; + int idx; + + bus_dmamap_sync(sc->sc_dmat, DWGE_DMA_MAP(sc->sc_txring), 0, + DWGE_DMA_LEN(sc->sc_txring), + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + while (sc->sc_tx_cnt > 0) { + idx = sc->sc_tx_cons; + KASSERT(idx < DWGE_NTXDESC); + + txd = &sc->sc_txdesc[idx]; + if (txd->sd_status & TDES0_OWN) + break; + + txb = &sc->sc_txbuf[idx]; + if (txb->tb_m) { + bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0, + txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, txb->tb_map); + + m_freem(txb->tb_m); + txb->tb_m = NULL; + } + + ifq_clr_oactive(&ifp->if_snd); + + sc->sc_tx_cnt--; + + if (sc->sc_tx_cons == (DWGE_NTXDESC - 1)) + sc->sc_tx_cons = 0; + else + sc->sc_tx_cons++; + + txd->sd_status = 0; + } + + if (sc->sc_tx_cnt == 0) + ifp->if_timer = 0; +} + +void +dwge_rx_proc(struct dwge_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct dwge_desc *rxd; + struct dwge_buf *rxb; + struct mbuf_list ml = MBUF_LIST_INITIALIZER(); + struct mbuf *m; + int idx, len; + + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + + bus_dmamap_sync(sc->sc_dmat, DWGE_DMA_MAP(sc->sc_rxring), 0, + DWGE_DMA_LEN(sc->sc_rxring), + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + while (if_rxr_inuse(&sc->sc_rx_ring) > 0) { + idx = sc->sc_rx_cons; + KASSERT(idx < DWGE_NRXDESC); + + rxd = &sc->sc_rxdesc[idx]; + if (rxd->sd_status & RDES0_OWN) + break; + + len = (rxd->sd_status >> RDES0_FL_SHIFT) & RDES0_FL_MASK; + rxb = &sc->sc_rxbuf[idx]; + KASSERT(rxb->tb_m); + + bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0, + len, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, rxb->tb_map); + + /* Strip off CRC. */ + len -= ETHER_CRC_LEN; + KASSERT(len > 0); + + m = rxb->tb_m; + rxb->tb_m = NULL; + m->m_pkthdr.len = m->m_len = len; + + ml_enqueue(&ml, m); + + if_rxr_put(&sc->sc_rx_ring, 1); + if (sc->sc_rx_cons == (DWGE_NRXDESC - 1)) + sc->sc_rx_cons = 0; + else + sc->sc_rx_cons++; + } + + dwge_fill_rx_ring(sc); + + bus_dmamap_sync(sc->sc_dmat, DWGE_DMA_MAP(sc->sc_rxring), 0, + DWGE_DMA_LEN(sc->sc_rxring), + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + + if_input(ifp, &ml); +} + +void +dwge_up(struct dwge_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct dwge_buf *txb, *rxb; + uint32_t mode; + int i; + + /* Allocate Tx descriptor ring. */ + sc->sc_txring = dwge_dmamem_alloc(sc, + DWGE_NTXDESC * sizeof(struct dwge_desc), 8); + sc->sc_txdesc = DWGE_DMA_KVA(sc->sc_txring); + + sc->sc_txbuf = malloc(sizeof(struct dwge_buf) * DWGE_NTXDESC, + M_DEVBUF, M_WAITOK); + for (i = 0; i < DWGE_NTXDESC; i++) { + txb = &sc->sc_txbuf[i]; + bus_dmamap_create(sc->sc_dmat, MCLBYTES, DWGE_NTXSEGS, + MCLBYTES, 0, BUS_DMA_WAITOK, &txb->tb_map); + txb->tb_m = NULL; + + sc->sc_txdesc[i].sd_next = + DWGE_DMA_DVA(sc->sc_txring) + + ((i+1) % DWGE_NTXDESC) * sizeof(struct dwge_desc); + } + + bus_dmamap_sync(sc->sc_dmat, DWGE_DMA_MAP(sc->sc_txring), + 0, DWGE_DMA_LEN(sc->sc_txring), BUS_DMASYNC_PREWRITE); + + sc->sc_tx_prod = sc->sc_tx_cons = 0; + sc->sc_tx_cnt = 0; + + dwge_write(sc, GMAC_TX_DESC_LIST_ADDR, DWGE_DMA_DVA(sc->sc_txring)); + + /* Allocate descriptor ring. */ + sc->sc_rxring = dwge_dmamem_alloc(sc, + DWGE_NRXDESC * sizeof(struct dwge_desc), 8); + sc->sc_rxdesc = DWGE_DMA_KVA(sc->sc_rxring); + + sc->sc_rxbuf = malloc(sizeof(struct dwge_buf) * DWGE_NRXDESC, + M_DEVBUF, M_WAITOK); + + for (i = 0; i < DWGE_NRXDESC; i++) { + rxb = &sc->sc_rxbuf[i]; + bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, + MCLBYTES, 0, BUS_DMA_WAITOK, &rxb->tb_map); + rxb->tb_m = NULL; + + sc->sc_rxdesc[i].sd_next = + DWGE_DMA_DVA(sc->sc_rxring) + + ((i+1) % DWGE_NRXDESC) * sizeof(struct dwge_desc); + } + + if_rxr_init(&sc->sc_rx_ring, 2, DWGE_NRXDESC); + + sc->sc_rx_prod = sc->sc_rx_cons = 0; + dwge_fill_rx_ring(sc); + + bus_dmamap_sync(sc->sc_dmat, DWGE_DMA_MAP(sc->sc_rxring), + 0, DWGE_DMA_LEN(sc->sc_rxring), + BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); + + dwge_write(sc, GMAC_RX_DESC_LIST_ADDR, DWGE_DMA_DVA(sc->sc_rxring)); + + dwge_lladdr_write(sc); + + /* Configure media. */ + if (LIST_FIRST(&sc->sc_mii.mii_phys)) + mii_mediachg(&sc->sc_mii); + + /* Program promiscuous mode and multicast filters. */ + dwge_iff(sc); + + ifp->if_flags |= IFF_RUNNING; + ifq_clr_oactive(&ifp->if_snd); + + dwge_write(sc, GMAC_INT_ENA, GMAC_INT_ENA_NIE | + GMAC_INT_ENA_RIE | GMAC_INT_ENA_TIE | GMAC_INT_ENA_TUE); + + mode = dwge_read(sc, GMAC_OP_MODE); + if (sc->sc_force_thresh_dma_mode) { + mode &= ~(GMAC_OP_MODE_TSF | GMAC_OP_MODE_TTC_MASK); + mode |= GMAC_OP_MODE_TTC_128; + mode &= ~(GMAC_OP_MODE_RSF | GMAC_OP_MODE_RTC_MASK); + mode |= GMAC_OP_MODE_RTC_128; + } else { + mode |= GMAC_OP_MODE_TSF | GMAC_OP_MODE_OSF; + mode |= GMAC_OP_MODE_RSF; + } + dwge_write(sc, GMAC_OP_MODE, mode | GMAC_OP_MODE_ST | GMAC_OP_MODE_SR); + + dwge_write(sc, GMAC_MAC_CONF, dwge_read(sc, GMAC_MAC_CONF) | + GMAC_MAC_CONF_TE | GMAC_MAC_CONF_RE); + + timeout_add_sec(&sc->sc_tick, 1); +} + +void +dwge_down(struct dwge_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct dwge_buf *txb, *rxb; + uint32_t dmactrl; + int i; + + timeout_del(&sc->sc_rxto); + timeout_del(&sc->sc_tick); + + ifp->if_flags &= ~IFF_RUNNING; + ifq_clr_oactive(&ifp->if_snd); + ifp->if_timer = 0; + + dwge_stop_dma(sc); + + dwge_write(sc, GMAC_MAC_CONF, dwge_read(sc, + GMAC_MAC_CONF) & ~(GMAC_MAC_CONF_TE | GMAC_MAC_CONF_RE)); + + dmactrl = dwge_read(sc, GMAC_OP_MODE); + dmactrl &= ~(GMAC_OP_MODE_ST | GMAC_OP_MODE_SR); + dwge_write(sc, GMAC_OP_MODE, dmactrl); + + dwge_write(sc, GMAC_INT_ENA, 0); + + for (i = 0; i < DWGE_NTXDESC; i++) { + txb = &sc->sc_txbuf[i]; + if (txb->tb_m) { + bus_dmamap_sync(sc->sc_dmat, txb->tb_map, 0, + txb->tb_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dmat, txb->tb_map); + m_freem(txb->tb_m); + } + bus_dmamap_destroy(sc->sc_dmat, txb->tb_map); + } + + dwge_dmamem_free(sc, sc->sc_txring); + free(sc->sc_txbuf, M_DEVBUF, 0); + + for (i = 0; i < DWGE_NRXDESC; i++) { + rxb = &sc->sc_rxbuf[i]; + if (rxb->tb_m) { + bus_dmamap_sync(sc->sc_dmat, rxb->tb_map, 0, + rxb->tb_map->dm_mapsize, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->sc_dmat, rxb->tb_map); + m_freem(rxb->tb_m); + } + bus_dmamap_destroy(sc->sc_dmat, rxb->tb_map); + } + + dwge_dmamem_free(sc, sc->sc_rxring); + free(sc->sc_rxbuf, M_DEVBUF, 0); +} + +/* Bit Reversal - http://aggregate.org/MAGIC/#Bit%20Reversal */ +static uint32_t +bitrev32(uint32_t x) +{ + x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); + x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); + x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); + x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); + + return (x >> 16) | (x << 16); +} + +void +dwge_iff(struct dwge_softc *sc) +{ + struct arpcom *ac = &sc->sc_ac; + struct ifnet *ifp = &sc->sc_ac.ac_if; + struct ether_multi *enm; + struct ether_multistep step; + uint32_t crc, hash[2], hashbit, hashreg; + uint32_t reg; + + reg = 0; + + ifp->if_flags &= ~IFF_ALLMULTI; + bzero(hash, sizeof(hash)); + if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { + ifp->if_flags |= IFF_ALLMULTI; + reg |= GMAC_MAC_FRM_FILT_PM; + if (ifp->if_flags & IFF_PROMISC) + reg |= GMAC_MAC_FRM_FILT_PR; + } else { + reg |= GMAC_MAC_FRM_FILT_HMC; + ETHER_FIRST_MULTI(step, ac, enm); + while (enm != NULL) { + crc = ether_crc32_le(enm->enm_addrlo, + ETHER_ADDR_LEN) & 0x7f; + + crc = bitrev32(~crc) >> 26; + hashreg = (crc >> 5); + hashbit = (crc & 0x1f); + hash[hashreg] |= (1 << hashbit); + + ETHER_NEXT_MULTI(step, enm); + } + } + + dwge_lladdr_write(sc); + + dwge_write(sc, GMAC_HASH_TAB_HI, hash[1]); + dwge_write(sc, GMAC_HASH_TAB_LO, hash[0]); + + dwge_write(sc, GMAC_MAC_FRM_FILT, reg); +} + +int +dwge_encap(struct dwge_softc *sc, struct mbuf *m, int *idx) +{ + struct dwge_desc *txd, *txd_start; + bus_dmamap_t map; + int cur, frag, i; + + cur = frag = *idx; + map = sc->sc_txbuf[cur].tb_map; + + if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) { + if (m_defrag(m, M_DONTWAIT)) + return (EFBIG); + if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT)) + return (EFBIG); + } + + if (map->dm_nsegs > (DWGE_NTXDESC - sc->sc_tx_cnt - 2)) { + bus_dmamap_unload(sc->sc_dmat, map); + return (ENOBUFS); + } + + /* Sync the DMA map. */ + bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, + BUS_DMASYNC_PREWRITE); + + txd = txd_start = &sc->sc_txdesc[frag]; + for (i = 0; i < map->dm_nsegs; i++) { + txd->sd_addr = map->dm_segs[i].ds_addr; + txd->sd_len = map->dm_segs[i].ds_len | TDES1_TCH; + if (i == 0) + txd->sd_len |= TDES1_FS; + if (i == (map->dm_nsegs - 1)) + txd->sd_len |= TDES1_LS | TDES1_IC; + if (i != 0) + txd->sd_status = TDES0_OWN; + + bus_dmamap_sync(sc->sc_dmat, DWGE_DMA_MAP(sc->sc_txring), + frag * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); + + cur = frag; + if (frag == (DWGE_NTXDESC - 1)) { + txd = &sc->sc_txdesc[0]; + frag = 0; + } else { + txd++; + frag++; + } + KASSERT(frag != sc->sc_tx_cons); + } + + txd_start->sd_status = TDES0_OWN; + bus_dmamap_sync(sc->sc_dmat, DWGE_DMA_MAP(sc->sc_txring), + *idx * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE); + + dwge_write(sc, GMAC_TX_POLL_DEMAND, 0xffffffff); + + KASSERT(sc->sc_txbuf[cur].tb_m == NULL); + sc->sc_txbuf[*idx].tb_map = sc->sc_txbuf[cur].tb_map; + sc->sc_txbuf[cur].tb_map = map; + sc->sc_txbuf[cur].tb_m = m; + + sc->sc_tx_cnt += map->dm_nsegs; + *idx = frag; + + return (0); +} + +void +dwge_reset(struct dwge_softc *sc) +{ + int n; + + dwge_stop_dma(sc); + + dwge_write(sc, GMAC_BUS_MODE, dwge_read(sc, GMAC_BUS_MODE) | + GMAC_BUS_MODE_SWR); + + for (n = 0; n < 30000; n++) { + if ((dwge_read(sc, GMAC_BUS_MODE) & + GMAC_BUS_MODE_SWR) == 0) + return; + delay(10); + } + + printf("%s: reset timeout\n", sc->sc_dev.dv_xname); +} + +void +dwge_stop_dma(struct dwge_softc *sc) +{ + uint32_t dmactrl; + + /* Stop DMA. */ + dmactrl = dwge_read(sc, GMAC_OP_MODE); + dmactrl &= ~GMAC_OP_MODE_ST; + dmactrl |= GMAC_OP_MODE_FTF; + dwge_write(sc, GMAC_OP_MODE, dmactrl); +} + +struct dwge_dmamem * +dwge_dmamem_alloc(struct dwge_softc *sc, bus_size_t size, bus_size_t align) +{ + struct dwge_dmamem *tdm; + int nsegs; + + tdm = malloc(sizeof(*tdm), M_DEVBUF, M_WAITOK | M_ZERO); + tdm->tdm_size = size; + + if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, + BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &tdm->tdm_map) != 0) + goto tdmfree; + + if (bus_dmamem_alloc(sc->sc_dmat, size, align, 0, &tdm->tdm_seg, 1, + &nsegs, BUS_DMA_WAITOK) != 0) + goto destroy; + + if (bus_dmamem_map(sc->sc_dmat, &tdm->tdm_seg, nsegs, size, + &tdm->tdm_kva, BUS_DMA_WAITOK | BUS_DMA_COHERENT) != 0) + goto free; + + if (bus_dmamap_load(sc->sc_dmat, tdm->tdm_map, tdm->tdm_kva, size, + NULL, BUS_DMA_WAITOK) != 0) + goto unmap; + + bzero(tdm->tdm_kva, size); + + return (tdm); + +unmap: + bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, size); +free: + bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1); +destroy: + bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map); +tdmfree: + free(tdm, M_DEVBUF, 0); + + return (NULL); +} + +void +dwge_dmamem_free(struct dwge_softc *sc, struct dwge_dmamem *tdm) +{ + bus_dmamem_unmap(sc->sc_dmat, tdm->tdm_kva, tdm->tdm_size); + bus_dmamem_free(sc->sc_dmat, &tdm->tdm_seg, 1); + bus_dmamap_destroy(sc->sc_dmat, tdm->tdm_map); + free(tdm, M_DEVBUF, 0); +} + +struct mbuf * +dwge_alloc_mbuf(struct dwge_softc *sc, bus_dmamap_t map) +{ + struct mbuf *m = NULL; + + m = MCLGETI(NULL, M_DONTWAIT, NULL, MCLBYTES); + if (!m) + return (NULL); + m->m_len = m->m_pkthdr.len = MCLBYTES; + m_adj(m, ETHER_ALIGN); + + if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, BUS_DMA_NOWAIT) != 0) { + printf("%s: could not load mbuf DMA map", DEVNAME(sc)); + m_freem(m); + return (NULL); + } + + bus_dmamap_sync(sc->sc_dmat, map, 0, + m->m_pkthdr.len, BUS_DMASYNC_PREREAD); + + return (m); +} + +void +dwge_fill_rx_ring(struct dwge_softc *sc) +{ + struct dwge_desc *rxd; + struct dwge_buf *rxb; + u_int slots; + + for (slots = if_rxr_get(&sc->sc_rx_ring, DWGE_NRXDESC); + slots > 0; slots--) { + rxb = &sc->sc_rxbuf[sc->sc_rx_prod]; + rxb->tb_m = dwge_alloc_mbuf(sc, rxb->tb_map); + if (rxb->tb_m == NULL) + break; + + rxd = &sc->sc_rxdesc[sc->sc_rx_prod]; + rxd->sd_len = rxb->tb_map->dm_segs[0].ds_len | RDES1_RCH; + rxd->sd_addr = rxb->tb_map->dm_segs[0].ds_addr; + rxd->sd_status = RDES0_OWN; + + if (sc->sc_rx_prod == (DWGE_NRXDESC - 1)) + sc->sc_rx_prod = 0; + else + sc->sc_rx_prod++; + } + if_rxr_put(&sc->sc_rx_ring, slots); + + if (if_rxr_inuse(&sc->sc_rx_ring) == 0) + timeout_add(&sc->sc_rxto, 1); +} + +/* + * Allwinner A20/A31. + */ + +void +dwge_setup_allwinner(struct dwge_softc *sc) +{ + char phy_mode[8]; + uint32_t freq; + + /* default to RGMII */ + OF_getprop(sc->sc_node, "phy-mode", phy_mode, sizeof(phy_mode)); + if (strcmp(phy_mode, "mii") == 0) + freq = 25000000; + else + freq = 125000000; + clock_set_frequency(sc->sc_node, "allwinner_gmac_tx", freq); +} + +/* + * Rockchip RK3288/RK3399. + */ + +/* RK3288 registers */ +#define RK3288_GRF_SOC_CON1 0x0248 +#define RK3288_GMAC_PHY_INTF_SEL_RGMII ((0x7 << 6) << 16 | (0x1 << 6)) +#define RK3288_GMAC_PHY_INTF_SEL_RMII ((0x7 << 6) << 16 | (0x4 << 6)) +#define RK3288_RMII_MODE_RMII ((1 << 14) << 16 | (1 << 14)) +#define RK3288_RMII_MODE_MII ((1 << 14) << 16 | (0 << 14)) +#define RK3288_GMAC_CLK_SEL_125 ((0x3 << 12) << 16 | (0x0 << 12)) +#define RK3288_GMAC_CLK_SEL_25 ((0x3 << 12) << 16 | (0x3 << 12)) +#define RK3288_GMAC_CLK_SEL_2_5 ((0x3 << 12) << 16 | (0x2 << 12)) + +#define RK3288_GRF_SOC_CON3 0x0250 +#define RK3288_GMAC_RXCLK_DLY_ENA ((1 << 15) << 16 | (1 << 15)) +#define RK3288_GMAC_CLK_RX_DL_CFG(val) ((0x7f << 7) << 16 | ((val) << 7)) +#define RK3288_GMAC_TXCLK_DLY_ENA ((1 << 14) << 16 | (1 << 14)) +#define RK3288_GMAC_CLK_TX_DL_CFG(val) ((0x7f << 0) << 16 | ((val) << 0)) + +/* RK3328 registers */ +#define RK3328_GRF_MAC_CON0 0x0900 +#define RK3328_GMAC_CLK_RX_DL_CFG(val) ((0x7f << 7) << 16 | ((val) << 7)) +#define RK3328_GMAC_CLK_TX_DL_CFG(val) ((0x7f << 0) << 16 | ((val) << 0)) + +#define RK3328_GRF_MAC_CON1 0x0904 +#define RK3328_GMAC_PHY_INTF_SEL_RGMII ((0x7 << 4) << 16 | (0x1 << 4)) +#define RK3328_GMAC_PHY_INTF_SEL_RMII ((0x7 << 4) << 16 | (0x4 << 4)) +#define RK3328_RMII_MODE_RMII ((1 << 9) << 16 | (1 << 9)) +#define RK3328_RMII_MODE_MII ((1 << 9) << 16 | (0 << 9)) +#define RK3328_GMAC_CLK_SEL_125 ((0x3 << 11) << 16 | (0x0 << 11)) +#define RK3328_GMAC_CLK_SEL_25 ((0x3 << 11) << 16 | (0x3 << 11)) +#define RK3328_GMAC_CLK_SEL_2_5 ((0x3 << 11) << 16 | (0x2 << 11)) +#define RK3328_GMAC_RXCLK_DLY_ENA ((1 << 1) << 16 | (1 << 1)) +#define RK3328_GMAC_TXCLK_DLY_ENA ((1 << 0) << 16 | (1 << 0)) + +/* RK3399 registers */ +#define RK3399_GRF_SOC_CON5 0xc214 +#define RK3399_GMAC_PHY_INTF_SEL_RGMII ((0x7 << 9) << 16 | (0x1 << 9)) +#define RK3399_GMAC_PHY_INTF_SEL_RMII ((0x7 << 9) << 16 | (0x4 << 9)) +#define RK3399_RMII_MODE_RMII ((1 << 6) << 16 | (1 << 6)) +#define RK3399_RMII_MODE_MII ((1 << 6) << 16 | (0 << 6)) +#define RK3399_GMAC_CLK_SEL_125 ((0x3 << 4) << 16 | (0x0 << 4)) +#define RK3399_GMAC_CLK_SEL_25 ((0x3 << 4) << 16 | (0x3 << 4)) +#define RK3399_GMAC_CLK_SEL_2_5 ((0x3 << 4) << 16 | (0x2 << 4)) +#define RK3399_GRF_SOC_CON6 0xc218 +#define RK3399_GMAC_RXCLK_DLY_ENA ((1 << 15) << 16 | (1 << 15)) +#define RK3399_GMAC_CLK_RX_DL_CFG(val) ((0x7f << 8) << 16 | ((val) << 8)) +#define RK3399_GMAC_TXCLK_DLY_ENA ((1 << 7) << 16 | (1 << 7)) +#define RK3399_GMAC_CLK_TX_DL_CFG(val) ((0x7f << 0) << 16 | ((val) << 0)) + +void dwge_mii_statchg_rockchip(struct device *); + +void +dwge_setup_rockchip(struct dwge_softc *sc) +{ + struct regmap *rm; + uint32_t grf; + int tx_delay, rx_delay; + + grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0); + rm = regmap_byphandle(grf); + if (rm == NULL) + return; + + clock_set_assigned(sc->sc_node); + clock_enable(sc->sc_node, "mac_clk_rx"); + clock_enable(sc->sc_node, "mac_clk_tx"); + clock_enable(sc->sc_node, "aclk_mac"); + clock_enable(sc->sc_node, "pclk_mac"); + + tx_delay = OF_getpropint(sc->sc_node, "tx_delay", 0x30); + rx_delay = OF_getpropint(sc->sc_node, "rx_delay", 0x10); + + if (OF_is_compatible(sc->sc_node, "rockchip,rk3288-gmac")) { + /* Use RGMII interface. */ + regmap_write_4(rm, RK3288_GRF_SOC_CON1, + RK3288_GMAC_PHY_INTF_SEL_RGMII | RK3288_RMII_MODE_MII); + + /* Program clock delay lines. */ + regmap_write_4(rm, RK3288_GRF_SOC_CON3, + RK3288_GMAC_TXCLK_DLY_ENA | RK3288_GMAC_RXCLK_DLY_ENA | + RK3288_GMAC_CLK_TX_DL_CFG(tx_delay) | + RK3288_GMAC_CLK_RX_DL_CFG(rx_delay)); + + /* Clock speed bits. */ + sc->sc_clk_sel = RK3288_GRF_SOC_CON1; + sc->sc_clk_sel_2_5 = RK3288_GMAC_CLK_SEL_2_5; + sc->sc_clk_sel_25 = RK3288_GMAC_CLK_SEL_25; + sc->sc_clk_sel_125 = RK3288_GMAC_CLK_SEL_125; + } else if (OF_is_compatible(sc->sc_node, "rockchip,rk3328-gmac")) { + /* Use RGMII interface. */ + regmap_write_4(rm, RK3328_GRF_MAC_CON1, + RK3328_GMAC_PHY_INTF_SEL_RGMII | RK3328_RMII_MODE_MII); + + /* Program clock delay lines. */ + regmap_write_4(rm, RK3328_GRF_MAC_CON0, + RK3328_GMAC_CLK_TX_DL_CFG(tx_delay) | + RK3328_GMAC_CLK_RX_DL_CFG(rx_delay)); + regmap_write_4(rm, RK3328_GRF_MAC_CON1, + RK3328_GMAC_TXCLK_DLY_ENA | RK3328_GMAC_RXCLK_DLY_ENA); + + /* Clock speed bits. */ + sc->sc_clk_sel = RK3328_GRF_MAC_CON1; + sc->sc_clk_sel_2_5 = RK3328_GMAC_CLK_SEL_2_5; + sc->sc_clk_sel_25 = RK3328_GMAC_CLK_SEL_25; + sc->sc_clk_sel_125 = RK3328_GMAC_CLK_SEL_125; + } else { + /* Use RGMII interface. */ + regmap_write_4(rm, RK3399_GRF_SOC_CON5, + RK3399_GMAC_PHY_INTF_SEL_RGMII | RK3399_RMII_MODE_MII); + + /* Program clock delay lines. */ + regmap_write_4(rm, RK3399_GRF_SOC_CON6, + RK3399_GMAC_TXCLK_DLY_ENA | RK3399_GMAC_RXCLK_DLY_ENA | + RK3399_GMAC_CLK_TX_DL_CFG(tx_delay) | + RK3399_GMAC_CLK_RX_DL_CFG(rx_delay)); + + /* Clock speed bits. */ + sc->sc_clk_sel = RK3399_GRF_SOC_CON5; + sc->sc_clk_sel_2_5 = RK3399_GMAC_CLK_SEL_2_5; + sc->sc_clk_sel_25 = RK3399_GMAC_CLK_SEL_25; + sc->sc_clk_sel_125 = RK3399_GMAC_CLK_SEL_125; + } + + sc->sc_mii.mii_statchg = dwge_mii_statchg_rockchip; +} + +void +dwge_mii_statchg_rockchip(struct device *self) +{ + struct dwge_softc *sc = (void *)self; + struct regmap *rm; + uint32_t grf; + uint32_t gmac_clk_sel = 0; + + dwge_mii_statchg(self); + + grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0); + rm = regmap_byphandle(grf); + if (rm == NULL) + return; + + switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) { + case IFM_10_T: + gmac_clk_sel = sc->sc_clk_sel_2_5; + break; + case IFM_100_TX: + gmac_clk_sel = sc->sc_clk_sel_25; + break; + case IFM_1000_T: + gmac_clk_sel = sc->sc_clk_sel_125; + break; + } + + regmap_write_4(rm, sc->sc_clk_sel, gmac_clk_sel); +} diff --git a/sys/dev/fdt/if_dwge_fdt.c b/sys/dev/fdt/if_dwge_fdt.c deleted file mode 100644 index dd9a8617e07..00000000000 --- a/sys/dev/fdt/if_dwge_fdt.c +++ /dev/null @@ -1,379 +0,0 @@ -/* $OpenBSD: if_dwge_fdt.c,v 1.11 2019/09/12 03:17:13 jsg Exp $ */ -/* - * Copyright (c) 2016 Patrick Wildt <patrick@blueri.se> - * Copyright (c) 2016 Mark Kettenis <kettenis@openbsd.org> - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/device.h> -#include <sys/queue.h> -#include <sys/socket.h> - -#include <machine/bus.h> -#include <machine/fdt.h> - -#include <net/if.h> -#include <net/if_media.h> - -#include <netinet/in.h> -#include <netinet/if_ether.h> - -#include <dev/mii/mii.h> -#include <dev/mii/miivar.h> - -#include <dev/ic/dwc_gmac_var.h> -#include <dev/ic/dwc_gmac_reg.h> - -#include <dev/ofw/openfirm.h> -#include <dev/ofw/ofw_clock.h> -#include <dev/ofw/ofw_gpio.h> -#include <dev/ofw/ofw_misc.h> -#include <dev/ofw/ofw_pinctrl.h> -#include <dev/ofw/ofw_regulator.h> -#include <dev/ofw/fdt.h> - -int dwge_fdt_match(struct device *, void *, void *); -void dwge_fdt_attach(struct device *, struct device *, void *); - -struct dwge_fdt_softc { - struct dwc_gmac_softc sc_core; - void *sc_ih; - int sc_node; - - bus_size_t sc_clk_sel; - uint32_t sc_clk_sel_125; - uint32_t sc_clk_sel_25; - uint32_t sc_clk_sel_2_5; -}; - -struct cfattach dwge_fdt_ca = { - sizeof(struct dwge_fdt_softc), dwge_fdt_match, dwge_fdt_attach, -}; - -void dwge_fdt_reset_phy(struct dwge_fdt_softc *); -int dwge_fdt_intr(void *); -void dwge_fdt_attach_allwinner(struct dwge_fdt_softc *); -void dwge_fdt_attach_rockchip(struct dwge_fdt_softc *); - -int -dwge_fdt_match(struct device *parent, void *match, void *aux) -{ - struct fdt_attach_args *faa = aux; - - return (OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-gmac") || - OF_is_compatible(faa->fa_node, "amlogic,meson-axg-dwmac") || - OF_is_compatible(faa->fa_node, "rockchip,rk3288-gmac") || - OF_is_compatible(faa->fa_node, "rockchip,rk3328-gmac") || - OF_is_compatible(faa->fa_node, "rockchip,rk3399-gmac")); -} - -void -dwge_fdt_attach(struct device *parent, struct device *self, void *aux) -{ - struct dwge_fdt_softc *fsc = (struct dwge_fdt_softc *)self; - struct dwc_gmac_softc *sc = &fsc->sc_core; - struct fdt_attach_args *faa = aux; - int phyloc = MII_PHY_ANY; - uint32_t phy_supply; - uint32_t phy; - int node; - - if (faa->fa_nreg < 1) { - printf(": no registers\n"); - return; - } - - fsc->sc_node = faa->fa_node; - sc->sc_bst = faa->fa_iot; - sc->sc_dmat = faa->fa_dmat; - - if (bus_space_map(sc->sc_bst, faa->fa_reg[0].addr, - faa->fa_reg[0].size, 0, &sc->sc_bsh)) { - printf(": can't map registers\n"); - return; - } - - printf("\n"); - - /* Lookup PHY. */ - phy = OF_getpropint(faa->fa_node, "phy", 0); - if (phy == 0) - phy = OF_getpropint(faa->fa_node, "phy-handle", 0); - node = OF_getnodebyphandle(phy); - if (node) - phyloc = OF_getpropint(node, "reg", phyloc); - - pinctrl_byname(faa->fa_node, "default"); - - /* Do hardware specific initializations. */ - if (OF_is_compatible(faa->fa_node, "allwinner,sun7i-a20-gmac")) - dwge_fdt_attach_allwinner(fsc); - else if (OF_is_compatible(faa->fa_node, "rockchip,rk3288-gmac")) - dwge_fdt_attach_rockchip(fsc); - else if (OF_is_compatible(faa->fa_node, "rockchip,rk3328-gmac")) - dwge_fdt_attach_rockchip(fsc); - else if (OF_is_compatible(faa->fa_node, "rockchip,rk3399-gmac")) - dwge_fdt_attach_rockchip(fsc); - - /* Enable clock. */ - clock_enable(faa->fa_node, "stmmaceth"); - reset_deassert(faa->fa_node, "stmmaceth"); - delay(5000); - - /* Power up PHY. */ - phy_supply = OF_getpropint(faa->fa_node, "phy-supply", 0); - if (phy_supply) - regulator_enable(phy_supply); - - /* Reset PHY */ - dwge_fdt_reset_phy(fsc); - - fsc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_NET, - dwge_fdt_intr, sc, sc->sc_dev.dv_xname); - if (fsc->sc_ih == NULL) { - printf(": can't establish interrupt\n"); - goto clrpwr; - } - - dwc_gmac_attach(sc, GMAC_MII_CLK_150_250M_DIV102, phyloc); - - return; - -clrpwr: - if (phy_supply) - regulator_disable(phy_supply); - clock_disable(faa->fa_node, "stmmaceth"); - bus_space_unmap(sc->sc_bst, sc->sc_bsh, faa->fa_reg[0].size); -} - -void -dwge_fdt_reset_phy(struct dwge_fdt_softc *sc) -{ - uint32_t *gpio; - uint32_t delays[3]; - int active = 1; - int len; - - len = OF_getproplen(sc->sc_node, "snps,reset-gpio"); - if (len <= 0) - return; - - gpio = malloc(len, M_TEMP, M_WAITOK); - - /* Gather information. */ - OF_getpropintarray(sc->sc_node, "snps,reset-gpio", gpio, len); - if (OF_getproplen(sc->sc_node, "snps-reset-active-low") == 0) - active = 0; - delays[0] = delays[1] = delays[2] = 0; - OF_getpropintarray(sc->sc_node, "snps,reset-delay-us", delays, - sizeof(delays)); - - /* Perform reset sequence. */ - gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT); - gpio_controller_set_pin(gpio, !active); - delay(delays[0]); - gpio_controller_set_pin(gpio, active); - delay(delays[1]); - gpio_controller_set_pin(gpio, !active); - delay(delays[2]); - - free(gpio, M_TEMP, len); -} - -int -dwge_fdt_intr(void *arg) -{ - struct dwge_fdt_softc *sc = arg; - - return dwc_gmac_intr(&sc->sc_core); -} - -/* - * Allwinner A20/A31. - */ - -void -dwge_fdt_attach_allwinner(struct dwge_fdt_softc *sc) -{ - char phy_mode[8]; - uint32_t freq; - - /* default to RGMII */ - OF_getprop(sc->sc_node, "phy-mode", phy_mode, sizeof(phy_mode)); - if (strcmp(phy_mode, "mii") == 0) - freq = 25000000; - else - freq = 125000000; - clock_set_frequency(sc->sc_node, "allwinner_gmac_tx", freq); -} - -/* - * Rockchip RK3288/RK3399. - */ - -/* RK3288 registers */ -#define RK3288_GRF_SOC_CON1 0x0248 -#define RK3288_GMAC_PHY_INTF_SEL_RGMII ((0x7 << 6) << 16 | (0x1 << 6)) -#define RK3288_GMAC_PHY_INTF_SEL_RMII ((0x7 << 6) << 16 | (0x4 << 6)) -#define RK3288_RMII_MODE_RMII ((1 << 14) << 16 | (1 << 14)) -#define RK3288_RMII_MODE_MII ((1 << 14) << 16 | (0 << 14)) -#define RK3288_GMAC_CLK_SEL_125 ((0x3 << 12) << 16 | (0x0 << 12)) -#define RK3288_GMAC_CLK_SEL_25 ((0x3 << 12) << 16 | (0x3 << 12)) -#define RK3288_GMAC_CLK_SEL_2_5 ((0x3 << 12) << 16 | (0x2 << 12)) - -#define RK3288_GRF_SOC_CON3 0x0250 -#define RK3288_GMAC_RXCLK_DLY_ENA ((1 << 15) << 16 | (1 << 15)) -#define RK3288_GMAC_CLK_RX_DL_CFG(val) ((0x7f << 7) << 16 | ((val) << 7)) -#define RK3288_GMAC_TXCLK_DLY_ENA ((1 << 14) << 16 | (1 << 14)) -#define RK3288_GMAC_CLK_TX_DL_CFG(val) ((0x7f << 0) << 16 | ((val) << 0)) - -/* RK3328 registers */ -#define RK3328_GRF_MAC_CON0 0x0900 -#define RK3328_GMAC_CLK_RX_DL_CFG(val) ((0x7f << 7) << 16 | ((val) << 7)) -#define RK3328_GMAC_CLK_TX_DL_CFG(val) ((0x7f << 0) << 16 | ((val) << 0)) - -#define RK3328_GRF_MAC_CON1 0x0904 -#define RK3328_GMAC_PHY_INTF_SEL_RGMII ((0x7 << 4) << 16 | (0x1 << 4)) -#define RK3328_GMAC_PHY_INTF_SEL_RMII ((0x7 << 4) << 16 | (0x4 << 4)) -#define RK3328_RMII_MODE_RMII ((1 << 9) << 16 | (1 << 9)) -#define RK3328_RMII_MODE_MII ((1 << 9) << 16 | (0 << 9)) -#define RK3328_GMAC_CLK_SEL_125 ((0x3 << 11) << 16 | (0x0 << 11)) -#define RK3328_GMAC_CLK_SEL_25 ((0x3 << 11) << 16 | (0x3 << 11)) -#define RK3328_GMAC_CLK_SEL_2_5 ((0x3 << 11) << 16 | (0x2 << 11)) -#define RK3328_GMAC_RXCLK_DLY_ENA ((1 << 1) << 16 | (1 << 1)) -#define RK3328_GMAC_TXCLK_DLY_ENA ((1 << 0) << 16 | (1 << 0)) - -/* RK3399 registers */ -#define RK3399_GRF_SOC_CON5 0xc214 -#define RK3399_GMAC_PHY_INTF_SEL_RGMII ((0x7 << 9) << 16 | (0x1 << 9)) -#define RK3399_GMAC_PHY_INTF_SEL_RMII ((0x7 << 9) << 16 | (0x4 << 9)) -#define RK3399_RMII_MODE_RMII ((1 << 6) << 16 | (1 << 6)) -#define RK3399_RMII_MODE_MII ((1 << 6) << 16 | (0 << 6)) -#define RK3399_GMAC_CLK_SEL_125 ((0x3 << 4) << 16 | (0x0 << 4)) -#define RK3399_GMAC_CLK_SEL_25 ((0x3 << 4) << 16 | (0x3 << 4)) -#define RK3399_GMAC_CLK_SEL_2_5 ((0x3 << 4) << 16 | (0x2 << 4)) -#define RK3399_GRF_SOC_CON6 0xc218 -#define RK3399_GMAC_RXCLK_DLY_ENA ((1 << 15) << 16 | (1 << 15)) -#define RK3399_GMAC_CLK_RX_DL_CFG(val) ((0x7f << 8) << 16 | ((val) << 8)) -#define RK3399_GMAC_TXCLK_DLY_ENA ((1 << 7) << 16 | (1 << 7)) -#define RK3399_GMAC_CLK_TX_DL_CFG(val) ((0x7f << 0) << 16 | ((val) << 0)) - -void dwge_fdt_statchg_rockchip(struct device *); - -void -dwge_fdt_attach_rockchip(struct dwge_fdt_softc *sc) -{ - struct regmap *rm; - uint32_t grf; - int tx_delay, rx_delay; - - grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0); - rm = regmap_byphandle(grf); - if (rm == NULL) - return; - - clock_enable(sc->sc_node, "mac_clk_rx"); - clock_enable(sc->sc_node, "mac_clk_tx"); - clock_enable(sc->sc_node, "aclk_mac"); - clock_enable(sc->sc_node, "pclk_mac"); - - tx_delay = OF_getpropint(sc->sc_node, "tx_delay", 0x30); - rx_delay = OF_getpropint(sc->sc_node, "rx_delay", 0x10); - - if (OF_is_compatible(sc->sc_node, "rockchip,rk3288-gmac")) { - /* Use RGMII interface. */ - regmap_write_4(rm, RK3288_GRF_SOC_CON1, - RK3288_GMAC_PHY_INTF_SEL_RGMII | RK3288_RMII_MODE_MII); - - /* Program clock delay lines. */ - regmap_write_4(rm, RK3288_GRF_SOC_CON3, - RK3288_GMAC_TXCLK_DLY_ENA | RK3288_GMAC_RXCLK_DLY_ENA | - RK3288_GMAC_CLK_TX_DL_CFG(tx_delay) | - RK3288_GMAC_CLK_RX_DL_CFG(rx_delay)); - - /* Clock speed bits. */ - sc->sc_clk_sel = RK3288_GRF_SOC_CON1; - sc->sc_clk_sel_2_5 = RK3288_GMAC_CLK_SEL_2_5; - sc->sc_clk_sel_25 = RK3288_GMAC_CLK_SEL_25; - sc->sc_clk_sel_125 = RK3288_GMAC_CLK_SEL_125; - } else if (OF_is_compatible(sc->sc_node, "rockchip,rk3328-gmac")) { - /* Use RGMII interface. */ - regmap_write_4(rm, RK3328_GRF_MAC_CON1, - RK3328_GMAC_PHY_INTF_SEL_RGMII | RK3328_RMII_MODE_MII); - - /* Program clock delay lines. */ - regmap_write_4(rm, RK3328_GRF_MAC_CON0, - RK3328_GMAC_CLK_TX_DL_CFG(tx_delay) | - RK3328_GMAC_CLK_RX_DL_CFG(rx_delay)); - regmap_write_4(rm, RK3328_GRF_MAC_CON1, - RK3328_GMAC_TXCLK_DLY_ENA | RK3328_GMAC_RXCLK_DLY_ENA); - - /* Clock speed bits. */ - sc->sc_clk_sel = RK3328_GRF_MAC_CON1; - sc->sc_clk_sel_2_5 = RK3328_GMAC_CLK_SEL_2_5; - sc->sc_clk_sel_25 = RK3328_GMAC_CLK_SEL_25; - sc->sc_clk_sel_125 = RK3328_GMAC_CLK_SEL_125; - } else { - /* Use RGMII interface. */ - regmap_write_4(rm, RK3399_GRF_SOC_CON5, - RK3399_GMAC_PHY_INTF_SEL_RGMII | RK3399_RMII_MODE_MII); - - /* Program clock delay lines. */ - regmap_write_4(rm, RK3399_GRF_SOC_CON6, - RK3399_GMAC_TXCLK_DLY_ENA | RK3399_GMAC_RXCLK_DLY_ENA | - RK3399_GMAC_CLK_TX_DL_CFG(tx_delay) | - RK3399_GMAC_CLK_RX_DL_CFG(rx_delay)); - - /* Clock speed bits. */ - sc->sc_clk_sel = RK3399_GRF_SOC_CON5; - sc->sc_clk_sel_2_5 = RK3399_GMAC_CLK_SEL_2_5; - sc->sc_clk_sel_25 = RK3399_GMAC_CLK_SEL_25; - sc->sc_clk_sel_125 = RK3399_GMAC_CLK_SEL_125; - } - - sc->sc_core.sc_statchg = dwge_fdt_statchg_rockchip; -} - -void -dwge_fdt_statchg_rockchip(struct device *dev) -{ - struct dwge_fdt_softc *sc = (struct dwge_fdt_softc *)dev; - struct regmap *rm; - uint32_t grf; - uint32_t gmac_clk_sel = 0; - - grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0); - rm = regmap_byphandle(grf); - if (rm == NULL) - return; - - switch (IFM_SUBTYPE(sc->sc_core.sc_mii.mii_media_active)) { - case IFM_10_T: - gmac_clk_sel = sc->sc_clk_sel_2_5; - break; - case IFM_100_TX: - gmac_clk_sel = sc->sc_clk_sel_25; - break; - case IFM_1000_T: - gmac_clk_sel = sc->sc_clk_sel_125; - break; - } - - regmap_write_4(rm, sc->sc_clk_sel, gmac_clk_sel); -} diff --git a/sys/dev/fdt/if_dwxe.c b/sys/dev/fdt/if_dwxe.c index 3fd8a33f332..fcbcebb6ed3 100644 --- a/sys/dev/fdt/if_dwxe.c +++ b/sys/dev/fdt/if_dwxe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_dwxe.c,v 1.13 2019/09/06 15:22:24 deraadt Exp $ */ +/* $OpenBSD: if_dwxe.c,v 1.14 2019/09/29 13:04:03 kettenis Exp $ */ /* * Copyright (c) 2008 Mark Kettenis * Copyright (c) 2017 Patrick Wildt <patrick@blueri.se> @@ -372,7 +372,8 @@ dwxe_attach(struct device *parent, struct device *self, void *aux) struct dwxe_softc *sc = (void *)self; struct fdt_attach_args *faa = aux; struct ifnet *ifp; - int phy, phy_supply, node; + uint32_t phy, phy_supply; + int node; sc->sc_node = faa->fa_node; sc->sc_iot = faa->fa_iot; @@ -772,12 +773,10 @@ dwxe_mii_statchg(struct device *self) case IFM_1000_LX: case IFM_1000_CX: case IFM_1000_T: - basicctrl &= ~DWXE_BASIC_CTL0_SPEED_MASK; basicctrl |= DWXE_BASIC_CTL0_SPEED_1000; sc->sc_link = 1; break; case IFM_100_TX: - basicctrl &= ~DWXE_BASIC_CTL0_SPEED_MASK; basicctrl |= DWXE_BASIC_CTL0_SPEED_100; sc->sc_link = 1; break; diff --git a/sys/dev/ic/dwc_gmac.c b/sys/dev/ic/dwc_gmac.c deleted file mode 100644 index 7ee5d91352d..00000000000 --- a/sys/dev/ic/dwc_gmac.c +++ /dev/null @@ -1,1419 +0,0 @@ -/* $OpenBSD: dwc_gmac.c,v 1.12 2019/09/15 15:52:14 kettenis Exp $ */ -/* $NetBSD: dwc_gmac.c,v 1.34 2015/08/21 20:12:29 jmcneill Exp $ */ - -/*- - * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Matt Thomas of 3am Software Foundry and Martin Husemann. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * This driver supports the Synopsis Designware GMAC core, as found - * on Allwinner A20 cores and others. - * - * Real documentation seems to not be available, the marketing product - * documents could be found here: - * - * http://www.synopsys.com/dw/ipdir.php?ds=dwc_ether_mac10_100_1000_unive - */ - -/* #define DWC_GMAC_DEBUG 1 */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/sockio.h> -#include <sys/queue.h> -#include <sys/malloc.h> -#include <sys/device.h> -#include <sys/evcount.h> -#include <sys/socket.h> -#include <sys/timeout.h> -#include <sys/mbuf.h> -#include <machine/intr.h> -#include <machine/bus.h> - -#include "bpfilter.h" - -#include <net/if.h> -#include <net/if_media.h> -#if NBPFILTER > 0 -#include <net/bpf.h> -#endif - -#include <netinet/in.h> -#include <netinet/if_ether.h> - -#include <dev/mii/mii.h> -#include <dev/mii/miivar.h> - -#include <dev/ic/dwc_gmac_reg.h> -#include <dev/ic/dwc_gmac_var.h> - -int dwc_gmac_ifmedia_upd(struct ifnet *); -void dwc_gmac_ifmedia_sts(struct ifnet *, struct ifmediareq *); - -int dwc_gmac_miibus_read_reg(struct device *, int, int); -void dwc_gmac_miibus_write_reg(struct device *, int, int, int); -void dwc_gmac_miibus_statchg(struct device *); - -int dwc_gmac_reset(struct dwc_gmac_softc *); -void dwc_gmac_write_hwaddr(struct dwc_gmac_softc *, uint8_t *enaddr); -int dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *); -void dwc_gmac_free_dma_rings(struct dwc_gmac_softc *); -int dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); -void dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); -void dwc_gmac_free_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *); -int dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); -void dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); -void dwc_gmac_free_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *); -void dwc_gmac_txdesc_sync(struct dwc_gmac_softc *, int, int, int); -int dwc_gmac_init(struct ifnet *); -void dwc_gmac_stop(struct ifnet *, int); -void dwc_gmac_start(struct ifnet *); -int dwc_gmac_queue(struct dwc_gmac_softc *, struct mbuf *); -int dwc_gmac_ioctl(struct ifnet *, u_long, caddr_t); -void dwc_gmac_tx_intr(struct dwc_gmac_softc *); -void dwc_gmac_rx_intr(struct dwc_gmac_softc *); -void dwc_gmac_iff(struct dwc_gmac_softc *); -static uint32_t bitrev32(uint32_t); - -#define TX_DESC_OFFSET(N) ((DWGE_RX_RING_COUNT+(N)) \ - *sizeof(struct dwc_gmac_dev_dmadesc)) -#define TX_NEXT(N) (((N)+1) & (DWGE_TX_RING_COUNT-1)) - -#define RX_DESC_OFFSET(N) ((N)*sizeof(struct dwc_gmac_dev_dmadesc)) -#define RX_NEXT(N) (((N)+1) & (DWGE_RX_RING_COUNT-1)) - - - -#define GMAC_DEF_DMA_INT_MASK (GMAC_DMA_INT_TIE|GMAC_DMA_INT_RIE| \ - GMAC_DMA_INT_NIE|GMAC_DMA_INT_AIE| \ - GMAC_DMA_INT_FBE|GMAC_DMA_INT_UNE) - -#define GMAC_DMA_INT_ERRORS (GMAC_DMA_INT_AIE|GMAC_DMA_INT_ERE| \ - GMAC_DMA_INT_FBE| \ - GMAC_DMA_INT_RWE|GMAC_DMA_INT_RUE| \ - GMAC_DMA_INT_UNE|GMAC_DMA_INT_OVE| \ - GMAC_DMA_INT_TJE) - -#define GMAC_DEF_MMC_INT_MASK 0xffffffff - -#define AWIN_DEF_MAC_INTRMASK \ - (AWIN_GMAC_MAC_INT_TSI | AWIN_GMAC_MAC_INT_ANEG | \ - AWIN_GMAC_MAC_INT_LINKCHG | AWIN_GMAC_MAC_INT_RGSMII) - - -#ifdef DWC_GMAC_DEBUG -void dwc_gmac_dump_dma(struct dwc_gmac_softc *sc); -void dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc); -void dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc); -void dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg); -void dwc_dump_status(struct dwc_gmac_softc *sc); -void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt); -#endif - -struct cfdriver dwge_cd = { - NULL, "dwge", DV_IFNET -}; - -void -dwc_gmac_attach(struct dwc_gmac_softc *sc, uint32_t mii_clk, int phyloc) -{ - uint8_t enaddr[ETHER_ADDR_LEN]; - struct mii_data * const mii = &sc->sc_mii; - struct ifnet * const ifp = &sc->sc_ac.ac_if; - uint32_t maclo, machi; - int s; - - mtx_init(&sc->sc_mdio_lock, IPL_NET); - sc->sc_mii_clk = mii_clk & 7; - - /* - * If we did not get an externaly configure address, - * try to read one from the current filter setup, - * before resetting the chip. - */ - maclo = bus_space_read_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_MAC_ADDR0LO); - machi = bus_space_read_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_MAC_ADDR0HI); - - if (maclo == 0xffffffff && (machi & 0xffff) == 0xffff) { - ether_fakeaddr(&sc->sc_ac.ac_if); - memcpy(enaddr, sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN); - } else { - enaddr[0] = maclo & 0x0ff; - enaddr[1] = (maclo >> 8) & 0x0ff; - enaddr[2] = (maclo >> 16) & 0x0ff; - enaddr[3] = (maclo >> 24) & 0x0ff; - enaddr[4] = machi & 0x0ff; - enaddr[5] = (machi >> 8) & 0x0ff; - } - - if (dwc_gmac_reset(sc) != 0) - return; /* not much to cleanup, haven't attached yet */ - - printf("%s: address: %s\n", sc->sc_dev.dv_xname, - ether_sprintf(enaddr)); - memcpy(sc->sc_ac.ac_enaddr, enaddr, ETHER_ADDR_LEN); - - /* - * Allocate Tx and Rx rings - */ - if (dwc_gmac_alloc_dma_rings(sc) != 0) { - printf("%s: could not allocate DMA rings\n", - sc->sc_dev.dv_xname); - goto fail; - } - - if (dwc_gmac_alloc_tx_ring(sc, &sc->sc_txq) != 0) { - printf("%s: could not allocate Tx ring\n", - sc->sc_dev.dv_xname); - goto fail; - } - - mtx_init(&sc->sc_rxq.r_mtx, IPL_NET); - if (dwc_gmac_alloc_rx_ring(sc, &sc->sc_rxq) != 0) { - printf("%s: could not allocate Rx ring\n", - sc->sc_dev.dv_xname); - goto fail; - } - - /* - * Prepare interface data - */ - ifp->if_softc = sc; - strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = dwc_gmac_ioctl; - ifp->if_start = dwc_gmac_start; - ifp->if_capabilities = IFCAP_VLAN_MTU; - - IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); - - /* - * Attach MII subdevices - */ - mii->mii_ifp = ifp; - mii->mii_readreg = dwc_gmac_miibus_read_reg; - mii->mii_writereg = dwc_gmac_miibus_write_reg; - mii->mii_statchg = dwc_gmac_miibus_statchg; - - ifmedia_init(&mii->mii_media, 0, dwc_gmac_ifmedia_upd, - dwc_gmac_ifmedia_sts); - mii_attach((void *)sc, mii, 0xffffffff, phyloc, - (phyloc == MII_PHY_ANY) ? 0 : MII_OFFSET_ANY, MIIF_DOPAUSE); - - if (LIST_EMPTY(&mii->mii_phys)) { - printf("%s: no PHY found!\n", sc->sc_dev.dv_xname); - ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_MANUAL, 0, NULL); - ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_MANUAL); - } else { - ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO); - } - - /* - * Ready, attach interface - */ - if_attach(ifp); - ether_ifattach(ifp); - - /* - * Enable interrupts - */ - s = splnet(); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTMASK, - AWIN_DEF_MAC_INTRMASK); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE, - GMAC_DEF_DMA_INT_MASK); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MMC_RX_INT_MSK, - GMAC_DEF_MMC_INT_MASK); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MMC_TX_INT_MSK, - GMAC_DEF_MMC_INT_MASK); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MMC_IPC_INT_MSK, - GMAC_DEF_MMC_INT_MASK); - splx(s); - - return; - -fail: - dwc_gmac_free_rx_ring(sc, &sc->sc_rxq); - dwc_gmac_free_tx_ring(sc, &sc->sc_txq); -} - -int -dwc_gmac_ifmedia_upd(struct ifnet *ifp) -{ - struct dwc_gmac_softc *sc = ifp->if_softc; - struct mii_data *mii = &sc->sc_mii; - int err; - if (mii->mii_instance) { - struct mii_softc *miisc; - - LIST_FOREACH(miisc, &mii->mii_phys, mii_list) - mii_phy_reset(miisc); - } - err = mii_mediachg(mii); - return (err); -} - -void -dwc_gmac_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) -{ - struct dwc_gmac_softc *sc = ifp->if_softc; - struct mii_data *mii = &sc->sc_mii; - - mii_pollstat(mii); - - ifmr->ifm_active = mii->mii_media_active; - ifmr->ifm_status = mii->mii_media_status; -} - -int -dwc_gmac_reset(struct dwc_gmac_softc *sc) -{ - size_t cnt; - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE) | GMAC_BUSMODE_RESET); - for (cnt = 0; cnt < 30000; cnt++) { - if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE) - & GMAC_BUSMODE_RESET) == 0) - return 0; - delay(10); - } - - printf("%s: reset timed out\n", sc->sc_dev.dv_xname); - return EIO; -} - -void -dwc_gmac_write_hwaddr(struct dwc_gmac_softc *sc, uint8_t *enaddr) -{ - uint32_t hi, lo; - - hi = enaddr[4] | (enaddr[5] << 8); - lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16) - | (enaddr[3] << 24); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0HI, hi); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0LO, lo); -} - -int -dwc_gmac_miibus_read_reg(struct device *self, int phy, int reg) -{ - struct dwc_gmac_softc * const sc = (struct dwc_gmac_softc *)self; - uint16_t mii; - size_t cnt; - int rv = 0; - - mii = ((phy & GMAC_MII_PHY_MASK) << GMAC_MII_PHY_SHIFT) - | ((reg & GMAC_MII_REG_MASK) << GMAC_MII_REG_SHIFT) - | ((sc->sc_mii_clk & GMAC_MII_CLKMASK_MASK) - << GMAC_MII_CLKMASK_SHIFT) - | GMAC_MII_BUSY; - - mtx_enter(&sc->sc_mdio_lock); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii); - - for (cnt = 0; cnt < 1000; cnt++) { - if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY)) { - rv = bus_space_read_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_MAC_MIIDATA); - break; - } - delay(10); - } - - mtx_leave(&sc->sc_mdio_lock); - - return rv; -} - -void -dwc_gmac_miibus_write_reg(struct device *self, int phy, int reg, int val) -{ - struct dwc_gmac_softc * const sc = (struct dwc_gmac_softc *)self; - uint16_t mii; - size_t cnt; - - mii = ((phy & GMAC_MII_PHY_MASK) << GMAC_MII_PHY_SHIFT) - | ((reg & GMAC_MII_REG_MASK) << GMAC_MII_REG_SHIFT) - | ((sc->sc_mii_clk & GMAC_MII_CLKMASK_MASK) - << GMAC_MII_CLKMASK_SHIFT) - | GMAC_MII_BUSY | GMAC_MII_WRITE; - - mtx_enter(&sc->sc_mdio_lock); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIDATA, val); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii); - - for (cnt = 0; cnt < 1000; cnt++) { - if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY)) - break; - delay(10); - } - - mtx_leave(&sc->sc_mdio_lock); -} - -int -dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *sc, - struct dwc_gmac_rx_ring *ring) -{ - struct dwc_gmac_rx_data *data; - bus_addr_t physaddr; - const size_t descsize = DWGE_RX_RING_COUNT * sizeof(*ring->r_desc); - int error, i, next; - - ring->r_cur = ring->r_next = 0; - memset(ring->r_desc, 0, descsize); - - /* - * Pre-allocate Rx buffers and populate Rx ring. - */ - for (i = 0; i < DWGE_RX_RING_COUNT; i++) { - struct dwc_gmac_dev_dmadesc *desc; - - data = &sc->sc_rxq.r_data[i]; - - MGETHDR(data->rd_m, M_DONTWAIT, MT_DATA); - if (data->rd_m == NULL) { - printf("%s: could not allocate rx mbuf #%d\n", - sc->sc_dev.dv_xname, i); - error = ENOMEM; - goto fail; - } - error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, - MCLBYTES, 0, BUS_DMA_NOWAIT, &data->rd_map); - if (error != 0) { - printf("%s: could not create DMA map\n", - sc->sc_dev.dv_xname); - data->rd_map = NULL; - goto fail; - } - MCLGET(data->rd_m, M_DONTWAIT); - if (!(data->rd_m->m_flags & M_EXT)) { - printf("%s: could not allocate mbuf cluster #%d\n", - sc->sc_dev.dv_xname, i); - error = ENOMEM; - goto fail; - } - - error = bus_dmamap_load(sc->sc_dmat, data->rd_map, - mtod(data->rd_m, void *), MCLBYTES, NULL, - BUS_DMA_READ | BUS_DMA_NOWAIT); - if (error != 0) { - printf("%s: could not load rx buf DMA map #%d", - sc->sc_dev.dv_xname, i); - goto fail; - } - physaddr = data->rd_map->dm_segs[0].ds_addr; - - desc = &sc->sc_rxq.r_desc[i]; - desc->ddesc_data = htole32(physaddr); - next = RX_NEXT(i); - desc->ddesc_next = htole32(ring->r_physaddr - + next * sizeof(*desc)); - desc->ddesc_cntl = htole32( - ((DWGE_MAX_PACKET & DDESC_CNTL_SIZE1MASK) - << DDESC_CNTL_SIZE1SHIFT) | DDESC_CNTL_RXCHAIN); - desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV); - } - - bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0, - DWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), - BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, - ring->r_physaddr); - - return 0; - -fail: - dwc_gmac_free_rx_ring(sc, ring); - return error; -} - -void -dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *sc, - struct dwc_gmac_rx_ring *ring) -{ - struct dwc_gmac_dev_dmadesc *desc; - int i; - - for (i = 0; i < DWGE_RX_RING_COUNT; i++) { - desc = &sc->sc_rxq.r_desc[i]; - desc->ddesc_cntl = htole32( - ((DWGE_MAX_PACKET & DDESC_CNTL_SIZE1MASK) - << DDESC_CNTL_SIZE1SHIFT) | DDESC_CNTL_RXCHAIN); - desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV); - } - - bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0, - DWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - - ring->r_cur = ring->r_next = 0; - /* reset DMA address to start of ring */ - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, - sc->sc_rxq.r_physaddr); -} - -int -dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *sc) -{ - const size_t descsize = DWGE_TOTAL_RING_COUNT * - sizeof(struct dwc_gmac_dev_dmadesc); - int error, nsegs; - caddr_t rings; - - error = bus_dmamap_create(sc->sc_dmat, descsize, 1, descsize, 0, - BUS_DMA_NOWAIT, &sc->sc_dma_ring_map); - if (error != 0) { - printf("%s: could not create desc DMA map\n", sc->sc_dev.dv_xname); - sc->sc_dma_ring_map = NULL; - goto fail; - } - - error = bus_dmamem_alloc(sc->sc_dmat, descsize, PAGE_SIZE, 0, - &sc->sc_dma_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); - if (error != 0) { - printf("%s: could not map DMA memory\n", sc->sc_dev.dv_xname); - goto fail; - } - - error = bus_dmamem_map(sc->sc_dmat, &sc->sc_dma_ring_seg, nsegs, - descsize, &rings, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); - if (error != 0) { - printf("%s: could not allocate DMA memory\n", sc->sc_dev.dv_xname); - goto fail; - } - - error = bus_dmamap_load(sc->sc_dmat, sc->sc_dma_ring_map, rings, - descsize, NULL, BUS_DMA_NOWAIT|BUS_DMA_COHERENT); - if (error != 0) { - printf("%s: could not load desc DMA map\n", sc->sc_dev.dv_xname); - goto fail; - } - - /* give first DWGE_RX_RING_COUNT to the RX side */ - sc->sc_rxq.r_desc = (struct dwc_gmac_dev_dmadesc *)rings; - sc->sc_rxq.r_physaddr = sc->sc_dma_ring_map->dm_segs[0].ds_addr; - - /* and next rings to the TX side */ - sc->sc_txq.t_desc = sc->sc_rxq.r_desc + DWGE_RX_RING_COUNT; - sc->sc_txq.t_physaddr = sc->sc_rxq.r_physaddr + - DWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc); - - return 0; - -fail: - dwc_gmac_free_dma_rings(sc); - return error; -} - -void -dwc_gmac_free_dma_rings(struct dwc_gmac_softc *sc) -{ - bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0, - sc->sc_dma_ring_map->dm_mapsize, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->sc_dmat, sc->sc_dma_ring_map); - bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_rxq.r_desc, - DWGE_TOTAL_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc)); - bus_dmamem_free(sc->sc_dmat, &sc->sc_dma_ring_seg, 1); -} - -void -dwc_gmac_free_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *ring) -{ - struct dwc_gmac_rx_data *data; - int i; - - if (ring->r_desc == NULL) - return; - - - for (i = 0; i < DWGE_RX_RING_COUNT; i++) { - data = &ring->r_data[i]; - - if (data->rd_map != NULL) { - bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, - DWGE_RX_RING_COUNT - *sizeof(struct dwc_gmac_dev_dmadesc), - BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(sc->sc_dmat, data->rd_map); - bus_dmamap_destroy(sc->sc_dmat, data->rd_map); - } - m_freem(data->rd_m); - } -} - -int -dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *sc, - struct dwc_gmac_tx_ring *ring) -{ - int i, error = 0; - - ring->t_queued = 0; - ring->t_cur = ring->t_next = 0; - - memset(ring->t_desc, 0, DWGE_TX_RING_COUNT*sizeof(*ring->t_desc)); - bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, - TX_DESC_OFFSET(0), - DWGE_TX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), - BUS_DMASYNC_POSTWRITE); - - for (i = 0; i < DWGE_TX_RING_COUNT; i++) { - error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, - DWGE_TX_RING_COUNT, MCLBYTES, 0, - BUS_DMA_NOWAIT|BUS_DMA_COHERENT, - &ring->t_data[i].td_map); - if (error != 0) { - printf("%s: could not create TX DMA map #%d\n", - sc->sc_dev.dv_xname, i); - ring->t_data[i].td_map = NULL; - goto fail; - } - ring->t_desc[i].ddesc_next = htole32( - ring->t_physaddr + sizeof(struct dwc_gmac_dev_dmadesc) - *TX_NEXT(i)); - } - - return 0; - -fail: - dwc_gmac_free_tx_ring(sc, ring); - return error; -} - -void -dwc_gmac_txdesc_sync(struct dwc_gmac_softc *sc, int start, int end, int ops) -{ - /* 'end' is pointing one descriptor beyound the last we want to sync */ - if (end > start) { - bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, - TX_DESC_OFFSET(start), - TX_DESC_OFFSET(end)-TX_DESC_OFFSET(start), - ops); - return; - } - /* sync from 'start' to end of ring */ - bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, - TX_DESC_OFFSET(start), - TX_DESC_OFFSET(DWGE_TX_RING_COUNT)-TX_DESC_OFFSET(start), - ops); - /* sync from start of ring to 'end' */ - bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, - TX_DESC_OFFSET(0), - TX_DESC_OFFSET(end)-TX_DESC_OFFSET(0), - ops); -} - -void -dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *sc, - struct dwc_gmac_tx_ring *ring) -{ - int i; - - for (i = 0; i < DWGE_TX_RING_COUNT; i++) { - struct dwc_gmac_tx_data *data = &ring->t_data[i]; - - if (data->td_m != NULL) { - bus_dmamap_sync(sc->sc_dmat, data->td_active, - 0, data->td_active->dm_mapsize, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->sc_dmat, data->td_active); - m_freem(data->td_m); - data->td_m = NULL; - } - } - - bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, - TX_DESC_OFFSET(0), - DWGE_TX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc), - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR, - sc->sc_txq.t_physaddr); - - ring->t_queued = 0; - ring->t_cur = ring->t_next = 0; -} - -void -dwc_gmac_free_tx_ring(struct dwc_gmac_softc *sc, - struct dwc_gmac_tx_ring *ring) -{ - int i; - - /* unload the maps */ - for (i = 0; i < DWGE_TX_RING_COUNT; i++) { - struct dwc_gmac_tx_data *data = &ring->t_data[i]; - - if (data->td_m != NULL) { - bus_dmamap_sync(sc->sc_dmat, data->td_active, - 0, data->td_map->dm_mapsize, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->sc_dmat, data->td_active); - m_freem(data->td_m); - data->td_m = NULL; - } - } - - /* and actually free them */ - for (i = 0; i < DWGE_TX_RING_COUNT; i++) { - struct dwc_gmac_tx_data *data = &ring->t_data[i]; - - bus_dmamap_destroy(sc->sc_dmat, data->td_map); - } -} - -void -dwc_gmac_miibus_statchg(struct device *dev) -{ - struct dwc_gmac_softc * const sc = (struct dwc_gmac_softc *)dev; - struct mii_data * const mii = &sc->sc_mii; - uint32_t conf, flow; - - /* - * Set MII or GMII interface based on the speed - * negotiated by the PHY. - */ - conf = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_CONF); - conf &= ~(AWIN_GMAC_MAC_CONF_FES100|AWIN_GMAC_MAC_CONF_MIISEL - |AWIN_GMAC_MAC_CONF_FULLDPLX); - conf |= AWIN_GMAC_MAC_CONF_FRAMEBURST - | AWIN_GMAC_MAC_CONF_DISABLERXOWN - | AWIN_GMAC_MAC_CONF_DISABLEJABBER - | AWIN_GMAC_MAC_CONF_ACS - | AWIN_GMAC_MAC_CONF_RXENABLE - | AWIN_GMAC_MAC_CONF_TXENABLE; - switch (IFM_SUBTYPE(mii->mii_media_active)) { - case IFM_10_T: - conf |= AWIN_GMAC_MAC_CONF_MIISEL; - break; - case IFM_100_TX: - conf |= AWIN_GMAC_MAC_CONF_FES100 | - AWIN_GMAC_MAC_CONF_MIISEL; - break; - case IFM_1000_T: - break; - } - - flow = 0; - if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { - conf |= AWIN_GMAC_MAC_CONF_FULLDPLX; - flow |= ((0x200 & AWIN_GMAC_MAC_FLOWCTRL_PAUSE_MASK) - << AWIN_GMAC_MAC_FLOWCTRL_PAUSE_SHIFT); - } - if (mii->mii_media_active & IFM_ETH_TXPAUSE) { - flow |= AWIN_GMAC_MAC_FLOWCTRL_TFE; - } - if (mii->mii_media_active & IFM_ETH_RXPAUSE) { - flow |= AWIN_GMAC_MAC_FLOWCTRL_RFE; - } - bus_space_write_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_MAC_FLOWCTRL, flow); - - if (sc->sc_statchg) - sc->sc_statchg(dev); - -#ifdef DWC_GMAC_DEBUG - printf("%s: setting MAC conf register: %08x\n", - sc->sc_dev.dv_xname, conf); -#endif - - bus_space_write_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_MAC_CONF, conf); -} - -int -dwc_gmac_init(struct ifnet *ifp) -{ - struct dwc_gmac_softc *sc = ifp->if_softc; - - dwc_gmac_stop(ifp, 0); - - /* - * Configure DMA burst/transfer mode and RX/TX priorities. - * XXX - the GMAC_BUSMODE_PRIORXTX bits are undocumented. - */ - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE, - GMAC_BUSMODE_FIXEDBURST | GMAC_BUSMODE_4PBL | - 2 << GMAC_BUSMODE_RPBL_SHIFT | - 2 << GMAC_BUSMODE_PBL_SHIFT); - - /* - * Program address filters - */ - dwc_gmac_write_hwaddr(sc, sc->sc_ac.ac_enaddr); - dwc_gmac_iff(sc); - - /* - * Set up dma pointer for RX and TX ring - */ - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, - sc->sc_rxq.r_physaddr); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR, - sc->sc_txq.t_physaddr); - - /* - * Start RX/TX part - */ - bus_space_write_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_DMA_OPMODE, GMAC_DMA_OP_RXSTART | GMAC_DMA_OP_TXSTART | - GMAC_DMA_OP_RXSTOREFORWARD | GMAC_DMA_OP_TXSTOREFORWARD); - - ifq_clr_oactive(&ifp->if_snd); - ifp->if_flags |= IFF_RUNNING; - - return 0; -} - -void -dwc_gmac_start(struct ifnet *ifp) -{ - struct dwc_gmac_softc *sc = ifp->if_softc; - int old = sc->sc_txq.t_queued; - int start = sc->sc_txq.t_cur; - struct mbuf *m_head = NULL; - - if (ifq_is_oactive(&ifp->if_snd) || !(ifp->if_flags & IFF_RUNNING)) - return; - - for (;;) { - m_head = ifq_deq_begin(&ifp->if_snd); - if (m_head == NULL) - break; - if (dwc_gmac_queue(sc, m_head) != 0) { - ifq_deq_rollback(&ifp->if_snd, m_head); - ifq_set_oactive(&ifp->if_snd); - break; - } - - ifq_deq_commit(&ifp->if_snd, m_head); - -#if NBPFILTER > 0 - if (ifp->if_bpf) - bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT); -#endif - - if (sc->sc_txq.t_queued == DWGE_TX_RING_COUNT) { - ifq_set_oactive(&ifp->if_snd); - break; - } - } - - if (sc->sc_txq.t_queued != old) { - /* packets have been queued, kick it off */ - dwc_gmac_txdesc_sync(sc, start, sc->sc_txq.t_cur, - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - - bus_space_write_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_DMA_TXPOLL, ~0U); -#ifdef DWC_GMAC_DEBUG - dwc_dump_status(sc); -#endif - } -} - -void -dwc_gmac_stop(struct ifnet *ifp, int disable) -{ - struct dwc_gmac_softc *sc = ifp->if_softc; - - ifp->if_flags &= ~IFF_RUNNING; - ifq_clr_oactive(&ifp->if_snd); - - bus_space_write_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_DMA_OPMODE, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_DMA_OPMODE) - & ~(GMAC_DMA_OP_TXSTART|GMAC_DMA_OP_RXSTART)); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_DMA_OPMODE, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_DMA_OPMODE) | GMAC_DMA_OP_FLUSHTX); - - mii_down(&sc->sc_mii); - dwc_gmac_reset_tx_ring(sc, &sc->sc_txq); - dwc_gmac_reset_rx_ring(sc, &sc->sc_rxq); -} - -/* - * Add m0 to the TX ring - */ -int -dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0) -{ - struct dwc_gmac_dev_dmadesc *desc = NULL; - struct dwc_gmac_tx_data *data = NULL; - bus_dmamap_t map; - uint32_t flags, len, status; - int error, i, first; - -#ifdef DWC_GMAC_DEBUG - printf("%s: dwc_gmac_queue: adding mbuf chain %p\n", - sc->sc_dev.dv_xname, m0); -#endif - - first = sc->sc_txq.t_cur; - map = sc->sc_txq.t_data[first].td_map; - - error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m0, - BUS_DMA_WRITE|BUS_DMA_NOWAIT); - if (error != 0) { - printf("%s: could not map mbuf (len: %d, error %d)\n", - sc->sc_dev.dv_xname, m0->m_pkthdr.len, error); - return error; - } - - if (sc->sc_txq.t_queued + map->dm_nsegs > DWGE_TX_RING_COUNT) { - bus_dmamap_unload(sc->sc_dmat, map); - return ENOBUFS; - } - - flags = DDESC_CNTL_TXFIRST|DDESC_CNTL_TXCHAIN; - status = 0; - for (i = 0; i < map->dm_nsegs; i++) { - data = &sc->sc_txq.t_data[sc->sc_txq.t_cur]; - desc = &sc->sc_txq.t_desc[sc->sc_txq.t_cur]; - - desc->ddesc_data = htole32(map->dm_segs[i].ds_addr); - len = (map->dm_segs[i].ds_len & DDESC_CNTL_SIZE1MASK) - << DDESC_CNTL_SIZE1SHIFT; - -#ifdef DWC_GMAC_DEBUG - printf("%s: enqueing desc #%d data %08lx " - "len %lu (flags: %08x, len: %08x)\n", - sc->sc_dev.dv_xname, sc->sc_txq.t_cur, - (unsigned long)map->dm_segs[i].ds_addr, - (unsigned long)map->dm_segs[i].ds_len, - flags, len); -#endif - - desc->ddesc_cntl = htole32(len|flags); - flags &= ~DDESC_CNTL_TXFIRST; - - /* - * Defer passing ownership of the first descriptor - * until we are done. - */ - desc->ddesc_status = htole32(status); - status |= DDESC_STATUS_OWNEDBYDEV; - - sc->sc_txq.t_queued++; - sc->sc_txq.t_cur = TX_NEXT(sc->sc_txq.t_cur); - } - - desc->ddesc_cntl |= htole32(DDESC_CNTL_TXLAST|DDESC_CNTL_TXINT); - - data->td_m = m0; - data->td_active = map; - - bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, - BUS_DMASYNC_PREWRITE); - - /* Pass first to device */ - sc->sc_txq.t_desc[first].ddesc_status = - htole32(DDESC_STATUS_OWNEDBYDEV); - - return 0; -} - -/* - * Reverse order of bits - http://aggregate.org/MAGIC/#Bit%20Reversal - */ -static uint32_t -bitrev32(uint32_t x) -{ - x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1)); - x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2)); - x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4)); - x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8)); - - return (x >> 16) | (x << 16); -} - -void -dwc_gmac_iff(struct dwc_gmac_softc *sc) -{ - struct ifnet * const ifp = &sc->sc_ac.ac_if; - struct arpcom *ac = &sc->sc_ac; - struct ether_multi *enm; - struct ether_multistep step; - uint32_t hashes[2] = { 0, 0 }; - uint32_t ffilt, h; - int mcnt = 0; - - ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT); - ffilt &= ~(AWIN_GMAC_MAC_FFILT_DBF | AWIN_GMAC_MAC_FFILT_HMC | - AWIN_GMAC_MAC_FFILT_PM | AWIN_GMAC_MAC_FFILT_PR | - AWIN_GMAC_MAC_FFILT_RA); - ifp->if_flags &= ~IFF_ALLMULTI; - - if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { - ifp->if_flags |= IFF_ALLMULTI; - if (ifp->if_flags & IFF_PROMISC) - ffilt |= AWIN_GMAC_MAC_FFILT_PR; - else - ffilt |= AWIN_GMAC_MAC_FFILT_PM; - hashes[0] = hashes[1] = 0xffffffff; - } else { - ETHER_FIRST_MULTI(step, ac, enm); - while (enm != NULL) { - h = bitrev32(~ether_crc32_le(enm->enm_addrlo, - ETHER_ADDR_LEN)) >> 26; - hashes[h >> 5] |= (1 << (h & 0x1f)); - - mcnt++; - ETHER_NEXT_MULTI(step, enm); - } - - if (mcnt) - ffilt |= AWIN_GMAC_MAC_FFILT_HMC; - } - - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, - hashes[0]); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, - hashes[1]); - bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, - ffilt); - -#ifdef DWC_GMAC_DEBUG - dwc_gmac_dump_ffilt(sc, ffilt); -#endif -} - -int -dwc_gmac_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) -{ - struct dwc_gmac_softc *sc = ifp->if_softc; - struct ifreq *ifr = (struct ifreq *)data; - int s, error = 0; - - s = splnet(); - - switch(cmd) { - case SIOCSIFADDR: - ifp->if_flags |= IFF_UP; - if (!(ifp->if_flags & IFF_RUNNING)) - dwc_gmac_init(ifp); - break; - - case SIOCSIFFLAGS: - if (ifp->if_flags & IFF_UP) { - if (ifp->if_flags & IFF_RUNNING) - error = ENETRESET; - else - dwc_gmac_init(ifp); - } else { - if (ifp->if_flags & IFF_RUNNING) - dwc_gmac_stop(ifp, 0); - } - break; - - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); - break; - - default: - error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); - } - - if (error == ENETRESET) { - if (ifp->if_flags & IFF_RUNNING) - dwc_gmac_iff(sc); - error = 0; - } - - splx(s); - return error; -} - -void -dwc_gmac_tx_intr(struct dwc_gmac_softc *sc) -{ - struct ifnet *ifp = &sc->sc_ac.ac_if; - struct dwc_gmac_tx_data *data; - struct dwc_gmac_dev_dmadesc *desc; - uint32_t status; - int i, nsegs; - - for (i = sc->sc_txq.t_next; sc->sc_txq.t_queued > 0; i = TX_NEXT(i)) { -#ifdef DWC_GMAC_DEBUG - printf("%s: dwc_gmac_tx_intr: checking desc #%d (t_queued: %d)\n", - sc->sc_dev.dv_xname, i, sc->sc_txq.t_queued); -#endif - - /* - * i+1 does not need to be a valid descriptor, - * this is just a special notion to just sync - * a single tx descriptor (i) - */ - dwc_gmac_txdesc_sync(sc, i, i+1, - BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); - - desc = &sc->sc_txq.t_desc[i]; - status = le32toh(desc->ddesc_status); - if (status & DDESC_STATUS_OWNEDBYDEV) - break; - - data = &sc->sc_txq.t_data[i]; - if (data->td_m == NULL) - continue; - - nsegs = data->td_active->dm_nsegs; - bus_dmamap_sync(sc->sc_dmat, data->td_active, 0, - data->td_active->dm_mapsize, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->sc_dmat, data->td_active); - -#ifdef DWC_GMAC_DEBUG - printf("%s: dwc_gmac_tx_intr: done with packet at desc #%d, " - "freeing mbuf %p\n", sc->sc_dev.dv_xname, i, data->td_m); -#endif - - m_freem(data->td_m); - data->td_m = NULL; - - sc->sc_txq.t_queued -= nsegs; - } - - sc->sc_txq.t_next = i; - - if (sc->sc_txq.t_queued < DWGE_TX_RING_COUNT) { - ifq_clr_oactive(&ifp->if_snd); - } -} - -void -dwc_gmac_rx_intr(struct dwc_gmac_softc *sc) -{ - struct ifnet *ifp = &sc->sc_ac.ac_if; - struct dwc_gmac_dev_dmadesc *desc; - struct dwc_gmac_rx_data *data; - bus_addr_t physaddr; - uint32_t status; - struct mbuf *m, *mnew; - int i, len, error; - struct mbuf_list ml = MBUF_LIST_INITIALIZER(); - - for (i = sc->sc_rxq.r_cur; ; i = RX_NEXT(i)) { - bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, - RX_DESC_OFFSET(i), sizeof(*desc), - BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); - desc = &sc->sc_rxq.r_desc[i]; - data = &sc->sc_rxq.r_data[i]; - - status = le32toh(desc->ddesc_status); - if (status & DDESC_STATUS_OWNEDBYDEV) - break; - - if (status & (DDESC_STATUS_RXERROR|DDESC_STATUS_RXTRUNCATED)) { -#ifdef DWC_GMAC_DEBUG - printf("%s: RX error: descriptor status %08x, skipping\n", - sc->sc_dev.dv_xname, status); -#endif - ifp->if_ierrors++; - goto skip; - } - - len = (status >> DDESC_STATUS_FRMLENSHIFT) - & DDESC_STATUS_FRMLENMSK; - -#ifdef DWC_GMAC_DEBUG - printf("%s: rx int: device is done with descriptor #%d, len: %d\n", - sc->sc_dev.dv_xname, i, len); -#endif - - /* - * Try to get a new mbuf before passing this one - * up, if that fails, drop the packet and reuse - * the existing one. - */ - MGETHDR(mnew, M_DONTWAIT, MT_DATA); - if (mnew == NULL) { - ifp->if_ierrors++; - goto skip; - } - MCLGET(mnew, M_DONTWAIT); - if ((mnew->m_flags & M_EXT) == 0) { - m_freem(mnew); - ifp->if_ierrors++; - goto skip; - } - - /* unload old DMA map */ - bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, - data->rd_map->dm_mapsize, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(sc->sc_dmat, data->rd_map); - - /* and reload with new mbuf */ - error = bus_dmamap_load(sc->sc_dmat, data->rd_map, - mtod(mnew, void*), MCLBYTES, NULL, - BUS_DMA_READ | BUS_DMA_NOWAIT); - if (error != 0) { - m_freem(mnew); - /* try to reload old mbuf */ - error = bus_dmamap_load(sc->sc_dmat, data->rd_map, - mtod(data->rd_m, void*), MCLBYTES, NULL, - BUS_DMA_READ | BUS_DMA_NOWAIT); - if (error != 0) { - panic("%s: could not load old rx mbuf", - sc->sc_dev.dv_xname); - } - ifp->if_ierrors++; - goto skip; - } - physaddr = data->rd_map->dm_segs[0].ds_addr; - - /* - * New mbuf loaded, update RX ring and continue - */ - m = data->rd_m; - data->rd_m = mnew; - desc->ddesc_data = htole32(physaddr); - - /* finalize mbuf */ -#ifdef __STRICT_ALIGNMENT - { - struct mbuf *m0; - m0 = m_devget(mtod(m, caddr_t), len, ETHER_ALIGN); - m_freem(m); - if (m0 == NULL) { - ifp->if_ierrors++; - goto skip; - } - m = m0; - } -#else - m->m_pkthdr.len = m->m_len = len; -#endif - - ml_enqueue(&ml, m); - -skip: - bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0, - data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD); - desc->ddesc_cntl = htole32( - ((DWGE_MAX_PACKET & DDESC_CNTL_SIZE1MASK) - << DDESC_CNTL_SIZE1SHIFT) | DDESC_CNTL_RXCHAIN); - desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV); - bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, - RX_DESC_OFFSET(i), sizeof(*desc), - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - } - - /* update RX pointer */ - sc->sc_rxq.r_cur = i; - - if_input(ifp, &ml); -} - -int -dwc_gmac_intr(struct dwc_gmac_softc *sc) -{ - uint32_t status, dma_status; - int rv = 0; - - status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR); - if (status & AWIN_GMAC_MII_IRQ) { - (void)bus_space_read_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_MII_STATUS); - rv = 1; - mii_pollstat(&sc->sc_mii); - } - - dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_DMA_STATUS); - - if (dma_status & (GMAC_DMA_INT_NIE|GMAC_DMA_INT_AIE)) - rv = 1; - - if (dma_status & GMAC_DMA_INT_TIE) - dwc_gmac_tx_intr(sc); - - if (dma_status & GMAC_DMA_INT_RIE) - dwc_gmac_rx_intr(sc); - - /* - * Check error conditions - */ - if (dma_status & GMAC_DMA_INT_ERRORS) { - sc->sc_ac.ac_if.if_oerrors++; -#ifdef DWC_GMAC_DEBUG - dwc_dump_and_abort(sc, "interrupt error condition"); -#endif - } - - /* ack interrupt */ - if (dma_status) - bus_space_write_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_DMA_STATUS, dma_status & GMAC_DMA_INT_MASK); - - /* - * Get more packets - */ - if (rv) - sc->sc_ac.ac_if.if_start(&sc->sc_ac.ac_if); - - return rv; -} - -#ifdef DWC_GMAC_DEBUG -void -dwc_gmac_dump_dma(struct dwc_gmac_softc *sc) -{ - printf("%s: busmode: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE)); - printf("%s: tx poll: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TXPOLL)); - printf("%s: rx poll: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RXPOLL)); - printf("%s: rx descriptors: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR)); - printf("%s: tx descriptors: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR)); - printf("%s: status: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_STATUS)); - printf("%s: op mode: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE)); - printf("%s: int enable: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE)); - printf("%s: cur tx: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_DESC)); - printf("%s: cur rx: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_DESC)); - printf("%s: cur tx buffer: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_BUFADDR)); - printf("%s: cur rx buffer: %08x\n", sc->sc_dev.dv_xname, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_BUFADDR)); -} - -void -dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc) -{ - int i; - - printf("%s: TX queue: cur=%d, next=%d, queued=%d\n", - sc->sc_dev.dv_xname, sc->sc_txq.t_cur, - sc->sc_txq.t_next, sc->sc_txq.t_queued); - printf("%s: TX DMA descriptors:\n", sc->sc_dev.dv_xname); - for (i = 0; i < DWGE_TX_RING_COUNT; i++) { - struct dwc_gmac_dev_dmadesc *desc = &sc->sc_txq.t_desc[i]; - printf("#%d (%08lx): status: %08x cntl: %08x " - "data: %08x next: %08x\n", - i, sc->sc_txq.t_physaddr + - i*sizeof(struct dwc_gmac_dev_dmadesc), - le32toh(desc->ddesc_status), le32toh(desc->ddesc_cntl), - le32toh(desc->ddesc_data), le32toh(desc->ddesc_next)); - } -} - -void -dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc) -{ - int i; - - printf("%s: RX queue: cur=%d, next=%d\n", sc->sc_dev.dv_xname, - sc->sc_rxq.r_cur, sc->sc_rxq.r_next); - printf("%s: RX DMA descriptors:\n", sc->sc_dev.dv_xname); - for (i = 0; i < DWGE_RX_RING_COUNT; i++) { - struct dwc_gmac_dev_dmadesc *desc = &sc->sc_rxq.r_desc[i]; - printf("#%d (%08lx): status: %08x cntl: %08x " - "data: %08x next: %08x\n", - i, sc->sc_rxq.r_physaddr + - i*sizeof(struct dwc_gmac_dev_dmadesc), - le32toh(desc->ddesc_status), le32toh(desc->ddesc_cntl), - le32toh(desc->ddesc_data), le32toh(desc->ddesc_next)); - } -} - -void -dwc_dump_status(struct dwc_gmac_softc *sc) -{ - uint32_t status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_MAC_INTR); - uint32_t dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, - AWIN_GMAC_DMA_STATUS); - char buf[200]; - - /* print interrupt state */ - snprintb(buf, sizeof(buf), "\177\20" - "b\x10""NI\0" - "b\x0f""AI\0" - "b\x0e""ER\0" - "b\x0d""FB\0" - "b\x0a""ET\0" - "b\x09""RW\0" - "b\x08""RS\0" - "b\x07""RU\0" - "b\x06""RI\0" - "b\x05""UN\0" - "b\x04""OV\0" - "b\x03""TJ\0" - "b\x02""TU\0" - "b\x01""TS\0" - "b\x00""TI\0" - "\0", dma_status); - printf("%s: INTR status: %08x, DMA status: %s\n", - sc->sc_dev.dv_xname, status, buf); -} - -void -dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg) -{ - dwc_dump_status(sc); - dwc_gmac_dump_ffilt(sc, - bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT)); - dwc_gmac_dump_dma(sc); - dwc_gmac_dump_tx_desc(sc); - dwc_gmac_dump_rx_desc(sc); - - panic("%s", msg); -} - -void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt) -{ - char buf[200]; - - /* print filter setup */ - snprintb(buf, sizeof(buf), "\177\20" - "b\x1f""RA\0" - "b\x0a""HPF\0" - "b\x09""SAF\0" - "b\x08""SAIF\0" - "b\x05""DBF\0" - "b\x04""PM\0" - "b\x03""DAIF\0" - "b\x02""HMC\0" - "b\x01""HUC\0" - "b\x00""PR\0" - "\0", ffilt); - printf("%s: FFILT: %s\n", sc->sc_dev.dv_xname, buf); -} -#endif diff --git a/sys/dev/ic/dwc_gmac_reg.h b/sys/dev/ic/dwc_gmac_reg.h deleted file mode 100644 index ce6ac1162af..00000000000 --- a/sys/dev/ic/dwc_gmac_reg.h +++ /dev/null @@ -1,231 +0,0 @@ -/* $OpenBSD: dwc_gmac_reg.h,v 1.2 2019/09/15 15:52:14 kettenis Exp $ */ -/* $NetBSD: dwc_gmac_reg.h,v 1.15 2015/11/21 16:04:11 martin Exp $ */ - -/*- - * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Matt Thomas of 3am Software Foundry and Martin Husemann. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#define AWIN_GMAC_MAC_CONF 0x0000 -#define AWIN_GMAC_MAC_FFILT 0x0004 -#define AWIN_GMAC_MAC_HTHIGH 0x0008 -#define AWIN_GMAC_MAC_HTLOW 0x000c -#define AWIN_GMAC_MAC_MIIADDR 0x0010 -#define AWIN_GMAC_MAC_MIIDATA 0x0014 -#define AWIN_GMAC_MAC_FLOWCTRL 0x0018 -#define AWIN_GMAC_MAC_VLANTAG 0x001c -#define AWIN_GMAC_MAC_VERSION 0x0020 /* not always implemented? */ -#define AWIN_GMAC_MAC_INTR 0x0038 -#define AWIN_GMAC_MAC_INTMASK 0x003c -#define AWIN_GMAC_MAC_ADDR0HI 0x0040 -#define AWIN_GMAC_MAC_ADDR0LO 0x0044 -#define AWIN_GMAC_MII_STATUS 0x00D8 - -#define AWIN_GMAC_MAC_CONF_DISABLEJABBER (1 << 22) /* jabber disable */ -#define AWIN_GMAC_MAC_CONF_FRAMEBURST (1 << 21) /* allow TX frameburst when - in half duplex mode */ -#define AWIN_GMAC_MAC_CONF_MIISEL (1 << 15) /* select MII phy */ -#define AWIN_GMAC_MAC_CONF_FES100 (1 << 14) /* 100 mbit mode */ -#define AWIN_GMAC_MAC_CONF_DISABLERXOWN (1 << 13) /* do not receive our own - TX frames in half duplex - mode */ -#define AWIN_GMAC_MAC_CONF_FULLDPLX (1 << 11) /* select full duplex */ -#define AWIN_GMAC_MAC_CONF_ACS (1 << 7) /* auto pad/CRC stripping */ -#define AWIN_GMAC_MAC_CONF_TXENABLE (1 << 3) /* enable TX dma engine */ -#define AWIN_GMAC_MAC_CONF_RXENABLE (1 << 2) /* enable RX dma engine */ - -#define AWIN_GMAC_MAC_FFILT_RA (1U << 31) /* receive all mode */ -#define AWIN_GMAC_MAC_FFILT_HPF (1 << 10) /* hash or perfect filter */ -#define AWIN_GMAC_MAC_FFILT_SAF (1 << 9) /* source address filter */ -#define AWIN_GMAC_MAC_FFILT_SAIF (1 << 8) /* inverse filtering */ -#define AWIN_GMAC_MAC_FFILT_DBF (1 << 5) /* disable broadcast frames */ -#define AWIN_GMAC_MAC_FFILT_PM (1 << 4) /* promiscious multicast */ -#define AWIN_GMAC_MAC_FFILT_DAIF (1 << 3) /* DA inverse filtering */ -#define AWIN_GMAC_MAC_FFILT_HMC (1 << 2) /* multicast hash compare */ -#define AWIN_GMAC_MAC_FFILT_HUC (1 << 1) /* unicast hash compare */ -#define AWIN_GMAC_MAC_FFILT_PR (1 << 0) /* promiscious mode */ - -#define AWIN_GMAC_MAC_INT_LPI (1 << 10) -#define AWIN_GMAC_MAC_INT_TSI (1 << 9) -#define AWIN_GMAC_MAC_INT_ANEG (1 << 2) -#define AWIN_GMAC_MAC_INT_LINKCHG (1 << 1) -#define AWIN_GMAC_MAC_INT_RGSMII (1 << 0) - -#define AWIN_GMAC_MAC_FLOWCTRL_PAUSE_SHIFT 16 -#define AWIN_GMAC_MAC_FLOWCTRL_PAUSE_MASK 0xffff -#define AWIN_GMAC_MAC_FLOWCTRL_RFE (1 << 2) -#define AWIN_GMAC_MAC_FLOWCTRL_TFE (1 << 1) -#define AWIN_GMAC_MAC_FLOWCTRL_BUSY (1 << 0) - -#define AWIN_GMAC_MMC_RX_INT_MSK 0x010c -#define AWIN_GMAC_MMC_TX_INT_MSK 0x0110 -#define AWIN_GMAC_MMC_IPC_INT_MSK 0x0200 - -#define AWIN_GMAC_DMA_BUSMODE 0x1000 -#define AWIN_GMAC_DMA_TXPOLL 0x1004 -#define AWIN_GMAC_DMA_RXPOLL 0x1008 -#define AWIN_GMAC_DMA_RX_ADDR 0x100c -#define AWIN_GMAC_DMA_TX_ADDR 0x1010 -#define AWIN_GMAC_DMA_STATUS 0x1014 -#define AWIN_GMAC_DMA_OPMODE 0x1018 -#define AWIN_GMAC_DMA_INTENABLE 0x101c -#define AWIN_GMAC_DMA_CUR_TX_DESC 0x1048 -#define AWIN_GMAC_DMA_CUR_RX_DESC 0x104c -#define AWIN_GMAC_DMA_CUR_TX_BUFADDR 0x1050 -#define AWIN_GMAC_DMA_CUR_RX_BUFADDR 0x1054 -#define AWIN_GMAC_DMA_HWFEATURES 0x1058 /* not always implemented? */ - -#define GMAC_MII_PHY_SHIFT 11 -#define GMAC_MII_PHY_MASK 0x1f -#define GMAC_MII_REG_SHIFT 6 -#define GMAC_MII_REG_MASK 0x1f - -#define GMAC_MII_BUSY (1 << 0) -#define GMAC_MII_WRITE (1 << 1) -#define GMAC_MII_CLK_60_100M_DIV42 0x0 -#define GMAC_MII_CLK_100_150M_DIV62 0x1 -#define GMAC_MII_CLK_25_35M_DIV16 0x2 -#define GMAC_MII_CLK_35_60M_DIV26 0x3 -#define GMAC_MII_CLK_150_250M_DIV102 0x4 -#define GMAC_MII_CLK_250_300M_DIV124 0x5 -#define GMAC_MII_CLK_DIV4 0x8 -#define GMAC_MII_CLK_DIV6 0x9 -#define GMAC_MII_CLK_DIV8 0xa -#define GMAC_MII_CLK_DIV10 0xb -#define GMAC_MII_CLK_DIV12 0xc -#define GMAC_MII_CLK_DIV14 0xd -#define GMAC_MII_CLK_DIV16 0xe -#define GMAC_MII_CLK_DIV18 0xf -#define GMAC_MII_CLKMASK_SHIFT 2 -#define GMAC_MII_CLKMASK_MASK 0xf - -#define GMAC_BUSMODE_4PBL (1 << 24) -#define GMAC_BUSMODE_RPBL_SHIFT 17 -#define GMAC_BUSMODE_RPBL_MASK 0x3f -#define GMAC_BUSMODE_FIXEDBURST (1 << 16) -#define GMAC_BUSMODE_PRIORXTX_SHIFT 14 -#define GMAC_BUSMODE_PRIORXTX_MASK 0x3 -#define GMAC_BUSMODE_PRIORXTX_41 3 -#define GMAC_BUSMODE_PRIORXTX_31 2 -#define GMAC_BUSMODE_PRIORXTX_21 1 -#define GMAC_BUSMODE_PRIORXTX_11 0 -#define GMAC_BUSMODE_PBL_SHIFT 8 -#define GMAC_BUSMODE_PBL_MASK 0x3f /* possible DMA - burst len */ -#define GMAC_BUSMODE_RESET (1 << 0) - -#define AWIN_GMAC_MII_IRQ (1 << 0) - - -#define GMAC_DMA_OP_DISABLECSDROP (1 << 26) /* disable dropping of - frames with TCP/IP - checksum errors */ -#define GMAC_DMA_OP_RXSTOREFORWARD (1 << 25) /* start RX when a - full frame is available */ -#define GMAC_DMA_OP_DISABLERXFLUSH (1 << 24) /* Do not drop frames - when out of RX descr. */ -#define GMAC_DMA_OP_TXSTOREFORWARD (1 << 21) /* start TX when a - full frame is available */ -#define GMAC_DMA_OP_FLUSHTX (1 << 20) /* flush TX fifo */ -#define GMAC_DMA_OP_TXSTART (1 << 13) /* start TX DMA engine */ -#define GMAC_DMA_OP_RXSTART (1 << 1) /* start RX DMA engine */ - -#define GMAC_DMA_INT_NIE (1 << 16) /* Normal/Summary */ -#define GMAC_DMA_INT_AIE (1 << 15) /* Abnormal/Summary */ -#define GMAC_DMA_INT_ERE (1 << 14) /* Early receive */ -#define GMAC_DMA_INT_FBE (1 << 13) /* Fatal bus error */ -#define GMAC_DMA_INT_ETE (1 << 10) /* Early transmit */ -#define GMAC_DMA_INT_RWE (1 << 9) /* Receive watchdog */ -#define GMAC_DMA_INT_RSE (1 << 8) /* Receive stopped */ -#define GMAC_DMA_INT_RUE (1 << 7) /* Receive buffer unavail. */ -#define GMAC_DMA_INT_RIE (1 << 6) /* Receive interrupt */ -#define GMAC_DMA_INT_UNE (1 << 5) /* Tx underflow */ -#define GMAC_DMA_INT_OVE (1 << 4) /* Receive overflow */ -#define GMAC_DMA_INT_TJE (1 << 3) /* Transmit jabber */ -#define GMAC_DMA_INT_TUE (1 << 2) /* Transmit buffer unavail. */ -#define GMAC_DMA_INT_TSE (1 << 1) /* Transmit stopped */ -#define GMAC_DMA_INT_TIE (1 << 0) /* Transmit interrupt */ - -#define GMAC_DMA_INT_MASK 0x1ffff /* all possible intr bits */ - -struct dwc_gmac_dev_dmadesc { - uint32_t ddesc_status; -/* both: */ -#define DDESC_STATUS_OWNEDBYDEV (1U << 31) - -/* for RX descriptors */ -#define DDESC_STATUS_DAFILTERFAIL (1 << 30) -#define DDESC_STATUS_FRMLENMSK 0x3fff -#define DDESC_STATUS_FRMLENSHIFT 16 -#define DDESC_STATUS_RXERROR (1 << 15) -#define DDESC_STATUS_RXTRUNCATED (1 << 14) -#define DDESC_STATUS_SAFILTERFAIL (1 << 13) -#define DDESC_STATUS_RXIPC_GIANTFRAME (1 << 12) -#define DDESC_STATUS_RXDAMAGED (1 << 11) -#define DDESC_STATUS_RXVLANTAG (1 << 10) -#define DDESC_STATUS_RXFIRST (1 << 9) -#define DDESC_STATUS_RXLAST (1 << 8) -#define DDESC_STATUS_RXIPC_GIANT (1 << 7) -#define DDESC_STATUS_RXCOLLISION (1 << 6) -#define DDESC_STATUS_RXFRAMEETHER (1 << 5) -#define DDESC_STATUS_RXWATCHDOG (1 << 4) -#define DDESC_STATUS_RXMIIERROR (1 << 3) -#define DDESC_STATUS_RXDRIBBLING (1 << 2) -#define DDESC_STATUS_RXCRC (1 << 1) - - uint32_t ddesc_cntl; - -/* for TX descriptors */ -#define DDESC_CNTL_TXINT (1U << 31) -#define DDESC_CNTL_TXLAST (1 << 30) -#define DDESC_CNTL_TXFIRST (1 << 29) -#define DDESC_CNTL_TXCHECKINSCTRL __BITS(27,28) - -#define DDESC_TXCHECK_DISABLED 0 -#define DDESC_TXCHECK_IP 1 -#define DDESC_TXCHECK_IP_NO_PSE 2 -#define DDESC_TXCHECK_FULL 3 - -#define DDESC_CNTL_TXCRCDIS (1 << 26) -#define DDESC_CNTL_TXRINGEND (1 << 25) -#define DDESC_CNTL_TXCHAIN (1 << 24) -#define DDESC_CNTL_TXDISPAD (1 << 23) - -/* for RX descriptors */ -#define DDESC_CNTL_RXINTDIS (1U << 31) -#define DDESC_CNTL_RXRINGEND (1 << 25) -#define DDESC_CNTL_RXCHAIN (1 << 24) - -/* both */ -#define DDESC_CNTL_SIZE1MASK 0x7ff -#define DDESC_CNTL_SIZE1SHIFT 0 -#define DDESC_CNTL_SIZE2MASK 0x7ff -#define DDESC_CNTL_SIZE2SHIFT 11 - - uint32_t ddesc_data; /* pointer to buffer data */ - uint32_t ddesc_next; /* link to next descriptor */ -}; diff --git a/sys/dev/ic/dwc_gmac_var.h b/sys/dev/ic/dwc_gmac_var.h deleted file mode 100644 index c2b3ce97e92..00000000000 --- a/sys/dev/ic/dwc_gmac_var.h +++ /dev/null @@ -1,96 +0,0 @@ -/* $OpenBSD: dwc_gmac_var.h,v 1.4 2017/05/21 11:52:04 kettenis Exp $ */ -/* $NetBSD: dwc_gmac_var.h,v 1.6 2014/11/22 18:31:03 jmcneill Exp $ */ - -/*- - * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Matt Thomas of 3am Software Foundry and Martin Husemann. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -/* - * We could use 1024 DMA descriptors to fill up an 8k page (each is 16 byte). - * However, on TX we probably will not need that many, and on RX we allocate - * a full mbuf cluster for each, so secondary memory consumption will grow - * rapidly. - * So currently we waste half a page of dma memory and consume 512k Byte of - * RAM for mbuf clusters. - * XXX Maybe fine-tune later, or reconsider unsharing of RX/TX dmamap. - */ -#define DWGE_RX_RING_COUNT 256 -#define DWGE_TX_RING_COUNT 256 -#define DWGE_TOTAL_RING_COUNT \ - (DWGE_RX_RING_COUNT + DWGE_TX_RING_COUNT) - -#define DWGE_MAX_PACKET 0x7ff - - - -struct dwc_gmac_rx_data { - bus_dmamap_t rd_map; - struct mbuf *rd_m; -}; - -struct dwc_gmac_tx_data { - bus_dmamap_t td_map; - bus_dmamap_t td_active; - struct mbuf *td_m; -}; - -struct dwc_gmac_tx_ring { - bus_addr_t t_physaddr; /* PA of TX ring start */ - struct dwc_gmac_dev_dmadesc *t_desc; /* VA of TX ring start */ - struct dwc_gmac_tx_data t_data[DWGE_TX_RING_COUNT]; - int t_cur, t_next, t_queued; -}; - -struct dwc_gmac_rx_ring { - bus_addr_t r_physaddr; /* PA of RX ring start */ - struct dwc_gmac_dev_dmadesc *r_desc; /* VA of RX ring start */ - struct dwc_gmac_rx_data r_data[DWGE_RX_RING_COUNT]; - int r_cur, r_next; - struct mutex r_mtx; -}; - -struct dwc_gmac_softc { - struct device sc_dev; - bus_space_tag_t sc_bst; - bus_space_handle_t sc_bsh; - bus_dma_tag_t sc_dmat; - struct arpcom sc_ac; - struct mii_data sc_mii; - struct mutex sc_mdio_lock; - bus_dmamap_t sc_dma_ring_map; /* common dma memory for RX */ - bus_dma_segment_t sc_dma_ring_seg; /* and TX ring */ - struct dwc_gmac_rx_ring sc_rxq; - struct dwc_gmac_tx_ring sc_txq; - uint16_t sc_mii_clk; - - void (*sc_statchg)(struct device *); -}; - -void dwc_gmac_attach(struct dwc_gmac_softc*, uint32_t, int); -int dwc_gmac_intr(struct dwc_gmac_softc*); |