summaryrefslogtreecommitdiff
path: root/sys/arch/socppc/dev/if_tsec.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/socppc/dev/if_tsec.c')
-rw-r--r--sys/arch/socppc/dev/if_tsec.c1335
1 files changed, 0 insertions, 1335 deletions
diff --git a/sys/arch/socppc/dev/if_tsec.c b/sys/arch/socppc/dev/if_tsec.c
deleted file mode 100644
index 832345ade8d..00000000000
--- a/sys/arch/socppc/dev/if_tsec.c
+++ /dev/null
@@ -1,1335 +0,0 @@
-/* $OpenBSD: if_tsec.c,v 1.44 2017/01/22 10:17:37 dlg Exp $ */
-
-/*
- * Copyright (c) 2008 Mark Kettenis
- *
- * 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 TSEC interface on the MPC8349E processors.
- */
-
-#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/autoconf.h>
-#include <machine/bus.h>
-
-#include <net/if.h>
-#include <net/if_media.h>
-
-#include <dev/ofw/openfirm.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>
-
-extern void myetheraddr(u_char *);
-
-/*
- * TSEC registers.
- */
-
-#define TSEC_IEVENT 0x010
-#define TSEC_IEVENT_BABR 0x80000000
-#define TSEC_IEVENT_RXC 0x40000000
-#define TSEC_IEVENT_BSY 0x20000000
-#define TSEC_IEVENT_EBERR 0x10000000
-#define TSEC_IEVENT_MSRO 0x04000000
-#define TSEC_IEVENT_GTSC 0x02000000
-#define TSEC_IEVENT_BABT 0x01000000
-#define TSEC_IEVENT_TXC 0x00800000
-#define TSEC_IEVENT_TXE 0x00400000
-#define TSEC_IEVENT_TXB 0x00200000
-#define TSEC_IEVENT_TXF 0x00100000
-#define TSEC_IEVENT_LC 0x00040000
-#define TSEC_IEVENT_CRL 0x00020000
-#define TSEC_IEVENT_DXA TSEC_IEVENT_CRL
-#define TSEC_IEVENT_XFUN 0x00010000
-#define TSEC_IEVENT_RXB 0x00008000
-#define TSEC_IEVENT_MMRD 0x00000400
-#define TSEC_IEVENT_MMWR 0x00000200
-#define TSEC_IEVENT_GRSC 0x00000100
-#define TSEC_IEVENT_RXF 0x00000080
-#define TSEC_IEVENT_FMT "\020" "\040BABR" "\037RXC" "\036BSY" \
- "\035EBERR" "\033MSRO" "\032GTSC" "\031BABT" "\030TXC" "\027TXE" \
- "\026TXB" "\025TXF" "\023LC" "\022CRL/XDA" "\021XFUN" "\020RXB" \
- "\013MMRD" "\012MMRW" "\011GRSC" "\010RXF"
-#define TSEC_IMASK 0x014
-#define TSEC_IMASK_BREN 0x80000000
-#define TSEC_IMASK_RXCEN 0x40000000
-#define TSEC_IMASK_BSYEN 0x20000000
-#define TSEC_IMASK_EBERREN 0x10000000
-#define TSEC_IMASK_MSROEN 0x04000000
-#define TSEC_IMASK_GTSCEN 0x02000000
-#define TSEC_IMASK_BTEN 0x01000000
-#define TSEC_IMASK_TXCEN 0x00800000
-#define TSEC_IMASK_TXEEN 0x00400000
-#define TSEC_IMASK_TXBEN 0x00200000
-#define TSEC_IMASK_TXFEN 0x00100000
-#define TSEC_IMASK_LCEN 0x00040000
-#define TSEC_IMASK_CRLEN 0x00020000
-#define TSEC_IMASK_DXAEN TSEC_IMASK_CRLEN
-#define TSEC_IMASK_XFUNEN 0x00010000
-#define TSEC_IMASK_RXBEN 0x00008000
-#define TSEC_IMASK_MMRD 0x00000400
-#define TSEC_IMASK_MMWR 0x00000200
-#define TSEC_IMASK_GRSCEN 0x00000100
-#define TSEC_IMASK_RXFEN 0x00000080
-#define TSEC_EDIS 0x018
-#define TSEC_ECNTRL 0x020
-#define TSEC_ECNTRL_R100M 0x00000008 /* RGMII 100 mode */
-#define TSEC_MINFLR 0x024
-#define TSEC_PTV 0x028
-#define TSEC_DMACTRL 0x02c
-#define TSEC_DMACTRL_TDSEN 0x00000080
-#define TSEC_DMACTRL_TBDSEN 0x00000040
-#define TSEC_DMACTRL_GRS 0x00000010 /* Graceful receive stop */
-#define TSEC_DMACTRL_GTS 0x00000008 /* Graceful transmit stop */
-#define TSEC_DMACTRL_WWR 0x00000002
-#define TSEC_DMACTRL_WOP 0x00000001
-#define TSEC_TBIPA 0x030
-
-#define TSEC_TCTRL 0x100
-#define TSEC_TSTAT 0x104
-#define TSEC_TSTAT_THLT 0x80000000
-#define TSEC_TBPTR 0x184
-#define TSEC_TBASE 0x204
-
-#define TSEC_RCTRL 0x300
-#define TSEC_RCTRL_PROM 0x00000008
-#define TSEC_RSTAT 0x304
-#define TSEC_RSTAT_QHLT 0x00800000
-#define TSEC_MRBLR 0x340
-#define TSEC_RBPTR 0x384
-#define TSEC_RBASE 0x404
-
-#define TSEC_MACCFG1 0x500
-#define TSEC_MACCFG1_TXEN 0x00000001
-#define TSEC_MACCFG1_RXEN 0x00000004
-#define TSEC_MACCFG1_RESET 0x80000000
-#define TSEC_MACCFG2 0x504
-#define TSEC_MACCFG2_IF_MODE 0x00000300 /* I/F mode */
-#define TSEC_MACCFG2_IF_MII 0x00000100 /* I/F mode */
-#define TSEC_MACCFG2_IF_GMII 0x00000200 /* I/F mode */
-#define TSEC_MACCFG2_PAD 0x00000004
-#define TSEC_MACCFG2_CRC 0x00000002
-#define TSEC_MACCFG2_FDX 0x00000001 /* Full duplex */
-#define TSEC_MIIMCFG 0x520
-#define TSEC_MIIMCFG_RESET 0x80000000 /* Reset */
-#define TSEC_MIIMCOM 0x524
-#define TSEC_MIIMCOM_READ 0x00000001 /* Read cycle */
-#define TSEC_MIIMCOM_SCAN 0x00000002 /* Scan cycle */
-#define TSEC_MIIMADD 0x528
-#define TSEC_MIIMCON 0x52c
-#define TSEC_MIIMSTAT 0x530
-#define TSEC_MIIMIND 0x534
-#define TSEC_MIIMIND_BUSY 0x00000001 /* Busy */
-#define TSEC_MIIMIND_SCAN 0x00000002 /* Scan in progress */
-#define TSEC_MIIMIND_NOTVALID 0x00000004 /* Not valid */
-#define TSEC_MACSTNADDR1 0x540
-#define TSEC_MACSTNADDR2 0x544
-#define TSEC_IADDR0 0x800
-#define TSEC_IADDR1 0x804
-#define TSEC_IADDR2 0x818
-#define TSEC_IADDR3 0x81c
-#define TSEC_IADDR4 0x810
-#define TSEC_IADDR5 0x814
-#define TSEC_IADDR6 0x818
-#define TSEC_IADDR7 0x81c
-#define TSEC_GADDR0 0x880
-#define TSEC_GADDR1 0x884
-#define TSEC_GADDR2 0x888
-#define TSEC_GADDR3 0x88c
-#define TSEC_GADDR4 0x890
-#define TSEC_GADDR5 0x894
-#define TSEC_GADDR6 0x898
-#define TSEC_GADDR7 0x89c
-
-#define TSEC_ATTR 0xbf8
-#define TSEC_ATTR_RDSEN 0x00000080
-#define TSEC_ATTR_RBDSEN 0x00000040
-
-/*
- * TSEC descriptors.
- */
-
-struct tsec_desc {
- uint16_t td_status;
- uint16_t td_len;
- uint32_t td_addr;
-};
-
-/* Tx status bits. */
-#define TSEC_TX_TXTRUNC 0x0001 /* TX truncation */
-#define TSEC_TX_UN 0x0002 /* Underrun */
-#define TSEC_TX_RC 0x003c /* Retry count */
-#define TSEC_TX_RL 0x0040 /* Retransmission limit */
-#define TSEC_TX_HFE 0x0080 /* Huge frame enable/late collision */
-#define TSEC_TX_LC TSEC_TX_HFE
-#define TSEC_TX_TO1 0x0100 /* Transmit software ownership bit */
-#define TSEC_TX_DEF 0x0200 /* Defer indication */
-#define TSEC_TX_TC 0x0400 /* Tx CRC */
-#define TSEC_TX_L 0x0800 /* Last in frame */
-#define TSEC_TX_I 0x1000 /* Interrupt */
-#define TSEC_TX_W 0x2000 /* Wrap */
-#define TSEC_TX_PAD 0x4000 /* PAD/CRC */
-#define TSEC_TX_R 0x8000 /* Ready */
-
-/* Rx status bits */
-#define TSEC_RX_TR 0x0001 /* Truncation */
-#define TSEC_RX_OV 0x0002 /* Overrun */
-#define TSEC_RX_CR 0x0004 /* Rx CRC error */
-#define TSEC_RX_SH 0x0008 /* Short frame */
-#define TSEC_RX_NO 0x0010 /* Rx non-octet aligned frame */
-#define TSEC_RX_LG 0x0020 /* Rx framelength violation */
-#define TSEC_RX_MC 0x0040 /* Multicast */
-#define TSEC_RX_BC 0x0080 /* Broadcast */
-#define TSEC_RX_M 0x0100 /* Miss */
-#define TSEC_RX_F 0x0400 /* First in frame */
-#define TSEC_RX_L 0x0800 /* Last in frame */
-#define TSEC_RX_I TSEC_TX_I
-#define TSEC_RX_W TSEC_TX_W
-#define TSEC_RX_RO1 0x4000 /* Receive software ownership bit */
-#define TSEC_RX_E 0x8000 /* Empty */
-
-struct tsec_buf {
- bus_dmamap_t tb_map;
- struct mbuf *tb_m;
-};
-
-#define TSEC_NTXDESC 256
-#define TSEC_NTXSEGS 16
-
-#define TSEC_NRXDESC 256
-
-struct tsec_dmamem {
- bus_dmamap_t tdm_map;
- bus_dma_segment_t tdm_seg;
- size_t tdm_size;
- caddr_t tdm_kva;
-};
-#define TSEC_DMA_MAP(_tdm) ((_tdm)->tdm_map)
-#define TSEC_DMA_LEN(_tdm) ((_tdm)->tdm_size)
-#define TSEC_DMA_DVA(_tdm) ((_tdm)->tdm_map->dm_segs[0].ds_addr)
-#define TSEC_DMA_KVA(_tdm) ((void *)(_tdm)->tdm_kva)
-
-struct tsec_softc {
- struct device sc_dev;
- bus_space_tag_t sc_iot;
- bus_space_handle_t sc_ioh;
- bus_space_handle_t sc_mii_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;
-
- struct tsec_dmamem *sc_txring;
- struct tsec_buf *sc_txbuf;
- struct tsec_desc *sc_txdesc;
- int sc_tx_prod;
- int sc_tx_cnt;
- int sc_tx_cons;
-
- struct tsec_dmamem *sc_rxring;
- struct tsec_buf *sc_rxbuf;
- struct tsec_desc *sc_rxdesc;
- int sc_rx_prod;
- struct if_rxring sc_rx_ring;
- int sc_rx_cons;
-
- struct timeout sc_tick;
-};
-
-#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
-
-int tsec_match(struct device *, void *, void *);
-void tsec_attach(struct device *, struct device *, void *);
-
-struct cfattach tsec_ca = {
- sizeof(struct tsec_softc), tsec_match, tsec_attach
-};
-
-struct cfdriver tsec_cd = {
- NULL, "tsec", DV_IFNET
-};
-
-int tsec_find_phy(int, int);
-
-uint32_t tsec_read(struct tsec_softc *, bus_addr_t);
-void tsec_write(struct tsec_softc *, bus_addr_t, uint32_t);
-uint32_t tsec_mii_read(struct tsec_softc *, bus_addr_t);
-void tsec_mii_write(struct tsec_softc *, bus_addr_t, uint32_t);
-
-int tsec_ioctl(struct ifnet *, u_long, caddr_t);
-void tsec_start(struct ifnet *);
-void tsec_watchdog(struct ifnet *);
-
-int tsec_media_change(struct ifnet *);
-void tsec_media_status(struct ifnet *, struct ifmediareq *);
-
-int tsec_mii_readreg(struct device *, int, int);
-void tsec_mii_writereg(struct device *, int, int, int);
-void tsec_mii_statchg(struct device *);
-
-void tsec_lladdr_write(struct tsec_softc *);
-
-void tsec_tick(void *);
-
-int tsec_txintr(void *);
-int tsec_rxintr(void *);
-int tsec_errintr(void *);
-
-void tsec_tx_proc(struct tsec_softc *);
-void tsec_rx_proc(struct tsec_softc *);
-
-void tsec_up(struct tsec_softc *);
-void tsec_down(struct tsec_softc *);
-void tsec_iff(struct tsec_softc *);
-int tsec_encap(struct tsec_softc *, struct mbuf *, int *);
-
-void tsec_reset(struct tsec_softc *);
-void tsec_stop_dma(struct tsec_softc *);
-
-struct tsec_dmamem *
- tsec_dmamem_alloc(struct tsec_softc *, bus_size_t, bus_size_t);
-void tsec_dmamem_free(struct tsec_softc *, struct tsec_dmamem *);
-struct mbuf *tsec_alloc_mbuf(struct tsec_softc *, bus_dmamap_t);
-void tsec_fill_rx_ring(struct tsec_softc *);
-
-/*
- * The MPC8349E processor has two TSECs but only one external
- * management interface to control external PHYs. The registers
- * controlling the management interface are part of TSEC1. So to
- * control a PHY attached to TSEC2, one needs to access TSEC1's
- * registers. To deal with this, the first TSEC that attaches maps
- * the register space for both TSEC1 and TSEC2 and stores the bus
- * space tag and bus space handle in these global variables. We use
- * these to create subregions for each individual interface and the
- * management interface.
- */
-bus_space_tag_t tsec_iot;
-bus_space_handle_t tsec_ioh;
-
-int
-tsec_match(struct device *parent, void *cfdata, void *aux)
-{
- struct obio_attach_args *oa = aux;
- char buf[32];
-
- if (OF_getprop(oa->oa_node, "device_type", buf, sizeof(buf)) <= 0 ||
- strcmp(buf, "network") != 0)
- return (0);
-
- if (OF_getprop(oa->oa_node, "compatible", buf, sizeof(buf)) <= 0 ||
- strcmp(buf, "gianfar") != 0)
- return (0);
-
- return (1);
-}
-
-void
-tsec_attach(struct device *parent, struct device *self, void *aux)
-{
- struct tsec_softc *sc = (void *)self;
- struct obio_attach_args *oa = aux;
- struct ifnet *ifp;
- int phy, n;
-
- if (OF_getprop(oa->oa_node, "phy-handle", &phy,
- sizeof(phy)) == sizeof(phy)) {
- int node, reg;
-
- node = tsec_find_phy(OF_peer(0), phy);
- if (node == -1 || OF_getprop(node, "reg", &reg,
- sizeof(reg)) != sizeof(reg)) {
- printf(": can't find PHY\n");
- return;
- }
-
- oa->oa_phy = reg;
- }
-
- /* Map registers for TSEC1 & TSEC2 if they're not mapped yet. */
- if (oa->oa_iot != tsec_iot) {
- tsec_iot = oa->oa_iot;
- if (bus_space_map(tsec_iot, oa->oa_offset & 0xffffc000,
- 8192, 0, &tsec_ioh)) {
- printf(": can't map registers\n");
- return;
- }
- }
-
- sc->sc_iot = tsec_iot;
- sc->sc_dmat = oa->oa_dmat;
-
- /* Ethernet Controller registers. */
- bus_space_subregion(tsec_iot, tsec_ioh, oa->oa_offset & 0x3fff,
- 3072, &sc->sc_ioh);
-
- /* MII Management registers. */
- bus_space_subregion(tsec_iot, tsec_ioh, 0, 3072, &sc->sc_mii_ioh);
-
- myetheraddr(sc->sc_lladdr);
- printf(": address %s\n", ether_sprintf(sc->sc_lladdr));
-
- timeout_set(&sc->sc_tick, tsec_tick, sc);
-
- ifp = &sc->sc_ac.ac_if;
- ifp->if_softc = sc;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = tsec_ioctl;
- ifp->if_start = tsec_start;
- ifp->if_watchdog = tsec_watchdog;
- IFQ_SET_MAXLEN(&ifp->if_snd, TSEC_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 = tsec_mii_readreg;
- sc->sc_mii.mii_writereg = tsec_mii_writereg;
- sc->sc_mii.mii_statchg = tsec_mii_statchg;
-
- ifmedia_init(&sc->sc_media, 0, tsec_media_change, tsec_media_status);
-
- tsec_reset(sc);
-
- /* Reset management. */
- tsec_write(sc, TSEC_MIIMCFG, TSEC_MIIMCFG_RESET);
- tsec_write(sc, TSEC_MIIMCFG, 0x00000003);
- for (n = 0; n < 100; n++) {
- if ((tsec_read(sc, TSEC_MIIMIND) & TSEC_MIIMIND_BUSY) == 0)
- break;
- }
-
- mii_attach(self, &sc->sc_mii, 0xffffffff, oa->oa_phy,
- 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);
-
- intr_establish(oa->oa_ivec, IST_LEVEL, IPL_NET, tsec_txintr, sc,
- sc->sc_dev.dv_xname);
- intr_establish(oa->oa_ivec + 1, IST_LEVEL, IPL_NET, tsec_rxintr, sc,
- sc->sc_dev.dv_xname);
- intr_establish(oa->oa_ivec + 2, IST_LEVEL, IPL_NET, tsec_errintr, sc,
- sc->sc_dev.dv_xname);
-}
-
-int
-tsec_find_phy(int node, int phy)
-{
- int child, handle;
-
- if (OF_getprop(node, "linux,phandle", &handle,
- sizeof(handle)) == sizeof(handle) && phy == handle)
- return (node);
-
- for (child = OF_child(node); child != 0; child = OF_peer(child)) {
- node = tsec_find_phy(child, phy);
- if (node != -1)
- return node;
- }
-
- return (-1);
-}
-
-uint32_t
-tsec_read(struct tsec_softc *sc, bus_addr_t addr)
-{
- return (letoh32(bus_space_read_4(sc->sc_iot, sc->sc_ioh, addr)));
-}
-
-void
-tsec_write(struct tsec_softc *sc, bus_addr_t addr, uint32_t data)
-{
- bus_space_write_4(sc->sc_iot, sc->sc_ioh, addr, htole32(data));
-}
-
-uint32_t
-tsec_mii_read(struct tsec_softc *sc, bus_addr_t addr)
-{
- return (letoh32(bus_space_read_4(sc->sc_iot, sc->sc_mii_ioh, addr)));
-}
-
-void
-tsec_mii_write(struct tsec_softc *sc, bus_addr_t addr, uint32_t data)
-{
- bus_space_write_4(sc->sc_iot, sc->sc_mii_ioh, addr, htole32(data));
-}
-
-void
-tsec_lladdr_write(struct tsec_softc *sc)
-{
- uint32_t addr1, addr2;
-
- addr1 = sc->sc_lladdr[5] << 24 | sc->sc_lladdr[4] << 16 |
- sc->sc_lladdr[3] << 8 | sc->sc_lladdr[2];
- addr2 = sc->sc_lladdr[1] << 24 | sc->sc_lladdr[0] << 16;
- tsec_write(sc, TSEC_MACSTNADDR1, addr1);
- tsec_write(sc, TSEC_MACSTNADDR2, addr2);
-}
-
-void
-tsec_start(struct ifnet *ifp)
-{
- struct tsec_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].td_status & TSEC_TX_TO1) == 0) {
- m = ifq_deq_begin(&ifp->if_snd);
- if (m == NULL)
- break;
-
- error = tsec_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
-tsec_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
-{
- struct tsec_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
- tsec_up(sc);
- } else {
- if (ifp->if_flags & IFF_RUNNING)
- tsec_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)
- tsec_iff(sc);
- error = 0;
- }
-
- splx(s);
- return (error);
-}
-
-void
-tsec_watchdog(struct ifnet *ifp)
-{
- printf("%s\n", __func__);
-}
-
-int
-tsec_media_change(struct ifnet *ifp)
-{
- struct tsec_softc *sc = ifp->if_softc;
-
- if (LIST_FIRST(&sc->sc_mii.mii_phys))
- mii_mediachg(&sc->sc_mii);
-
- return (0);
-}
-
-void
-tsec_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
-{
- struct tsec_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
-tsec_mii_readreg(struct device *self, int phy, int reg)
-{
- struct tsec_softc *sc = (void *)self;
- uint32_t v;
- int n;
-
- tsec_mii_write(sc, TSEC_MIIMADD, (phy << 8) | reg);
- tsec_mii_write(sc, TSEC_MIIMCOM, 0);
- tsec_mii_write(sc, TSEC_MIIMCOM, TSEC_MIIMCOM_READ);
- for (n = 0; n < 100; n++) {
- v = tsec_mii_read(sc, TSEC_MIIMIND);
- if ((v & (TSEC_MIIMIND_NOTVALID | TSEC_MIIMIND_BUSY)) == 0)
- return (tsec_mii_read(sc, TSEC_MIIMSTAT));
- delay(10);
- }
-
- printf("%s: mii_read timeout\n", sc->sc_dev.dv_xname);
- return (0);
-}
-
-void
-tsec_mii_writereg(struct device *self, int phy, int reg, int val)
-{
- struct tsec_softc *sc = (void *)self;
- uint32_t v;
- int n;
-
- tsec_mii_write(sc, TSEC_MIIMADD, (phy << 8) | reg);
- tsec_mii_write(sc, TSEC_MIIMCON, val);
- for (n = 0; n < 100; n++) {
- v = tsec_mii_read(sc, TSEC_MIIMIND);
- if ((v & TSEC_MIIMIND_BUSY) == 0)
- return;
- delay(10);
- }
-
- printf("%s: mii_write timeout\n", sc->sc_dev.dv_xname);
-}
-
-void
-tsec_mii_statchg(struct device *self)
-{
- struct tsec_softc *sc = (void *)self;
- uint32_t maccfg2, ecntrl;
-
- ecntrl = tsec_read(sc, TSEC_ECNTRL);
- maccfg2 = tsec_read(sc, TSEC_MACCFG2);
- maccfg2 &= ~TSEC_MACCFG2_IF_MODE;
-
- 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:
- maccfg2 |= TSEC_MACCFG2_IF_GMII;
- sc->sc_link = 1;
- break;
- case IFM_100_TX:
- ecntrl |= TSEC_ECNTRL_R100M;
- maccfg2 |= TSEC_MACCFG2_IF_MII;
- sc->sc_link = 1;
- break;
- case IFM_10_T:
- ecntrl &= ~TSEC_ECNTRL_R100M;
- maccfg2 |= TSEC_MACCFG2_IF_MII;
- sc->sc_link = 1;
- break;
- default:
- sc->sc_link = 0;
- return;
- }
-
- if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX)
- maccfg2 |= TSEC_MACCFG2_FDX;
- else
- maccfg2 &= ~TSEC_MACCFG2_FDX;
-
- tsec_write(sc, TSEC_MACCFG2, maccfg2);
- tsec_write(sc, TSEC_ECNTRL, ecntrl);
-}
-
-void
-tsec_tick(void *arg)
-{
- struct tsec_softc *sc = arg;
- int s;
-
- s = splnet();
- mii_tick(&sc->sc_mii);
- splx(s);
-
- timeout_add_sec(&sc->sc_tick, 1);
-}
-
-int
-tsec_txintr(void *arg)
-{
- struct tsec_softc *sc = arg;
- uint32_t ievent;
-
- ievent = tsec_read(sc, TSEC_IEVENT);
- if ((ievent & (TSEC_IEVENT_TXC | TSEC_IEVENT_TXE |
- TSEC_IEVENT_TXB | TSEC_IEVENT_TXF)) == 0)
- printf("%s: tx %b\n", DEVNAME(sc), ievent, TSEC_IEVENT_FMT);
- ievent &= (TSEC_IEVENT_TXC | TSEC_IEVENT_TXE |
- TSEC_IEVENT_TXB | TSEC_IEVENT_TXF);
- tsec_write(sc, TSEC_IEVENT, ievent);
-
- tsec_tx_proc(sc);
-
- return (1);
-}
-
-int
-tsec_rxintr(void *arg)
-{
- struct tsec_softc *sc = arg;
- uint32_t ievent;
-
- ievent = tsec_read(sc, TSEC_IEVENT);
- if ((ievent & (TSEC_IEVENT_RXB | TSEC_IEVENT_RXF)) == 0)
- printf("%s: rx %b\n", DEVNAME(sc), ievent, TSEC_IEVENT_FMT);
- ievent &= (TSEC_IEVENT_RXB | TSEC_IEVENT_RXF);
- tsec_write(sc, TSEC_IEVENT, ievent);
-
- tsec_rx_proc(sc);
-
- return (1);
-}
-
-int
-tsec_errintr(void *arg)
-{
- struct tsec_softc *sc = arg;
- struct ifnet *ifp = &sc->sc_ac.ac_if;
- uint32_t ievent;
-
- ievent = tsec_read(sc, TSEC_IEVENT);
- if ((ievent & TSEC_IEVENT_BSY) == 0)
- printf("%s: err %b\n", DEVNAME(sc), ievent, TSEC_IEVENT_FMT);
- ievent &= TSEC_IEVENT_BSY;
- tsec_write(sc, TSEC_IEVENT, ievent);
-
- if (ievent & TSEC_IEVENT_BSY) {
- /*
- * We ran out of buffers and dropped one (or more)
- * packets. We must clear RSTAT[QHLT] after
- * processing the ring to get things started again.
- */
- tsec_rx_proc(sc);
- tsec_write(sc, TSEC_RSTAT, TSEC_RSTAT_QHLT);
- ifp->if_ierrors++;
- }
-
- return (1);
-}
-
-void
-tsec_tx_proc(struct tsec_softc *sc)
-{
- struct ifnet *ifp = &sc->sc_ac.ac_if;
- struct tsec_desc *txd;
- struct tsec_buf *txb;
- int idx;
-
- bus_dmamap_sync(sc->sc_dmat, TSEC_DMA_MAP(sc->sc_txring), 0,
- TSEC_DMA_LEN(sc->sc_txring),
- BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
-
- while (sc->sc_tx_cnt > 0) {
- idx = sc->sc_tx_cons;
- KASSERT(idx < TSEC_NTXDESC);
-
- txd = &sc->sc_txdesc[idx];
- if (txd->td_status & TSEC_TX_R)
- 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 (txd->td_status & TSEC_TX_W)
- sc->sc_tx_cons = 0;
- else
- sc->sc_tx_cons++;
-
- __asm volatile("eieio" ::: "memory");
- txd->td_status &= TSEC_TX_W;
- }
-
- if (sc->sc_tx_cnt == 0)
- ifp->if_timer = 0;
-}
-
-void
-tsec_rx_proc(struct tsec_softc *sc)
-{
- struct ifnet *ifp = &sc->sc_ac.ac_if;
- struct tsec_desc *rxd;
- struct tsec_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, TSEC_DMA_MAP(sc->sc_rxring), 0,
- TSEC_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 < TSEC_NRXDESC);
-
- rxd = &sc->sc_rxdesc[idx];
- if (rxd->td_status & TSEC_RX_E)
- break;
-
- len = rxd->td_len;
- 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 (rxd->td_status & TSEC_RX_W)
- sc->sc_rx_cons = 0;
- else
- sc->sc_rx_cons++;
- }
-
- tsec_fill_rx_ring(sc);
-
- bus_dmamap_sync(sc->sc_dmat, TSEC_DMA_MAP(sc->sc_rxring), 0,
- TSEC_DMA_LEN(sc->sc_rxring),
- BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
-
- if_input(ifp, &ml);
-}
-
-void
-tsec_up(struct tsec_softc *sc)
-{
- struct ifnet *ifp = &sc->sc_ac.ac_if;
- struct tsec_desc *txd, *rxd;
- struct tsec_buf *txb, *rxb;
- uint32_t maccfg1, maccfg2, ecntrl, dmactrl, attr;
- int i;
-
- /* Allocate Tx descriptor ring. */
- sc->sc_txring = tsec_dmamem_alloc(sc,
- TSEC_NTXDESC * sizeof(struct tsec_desc), 8);
- sc->sc_txdesc = TSEC_DMA_KVA(sc->sc_txring);
-
- sc->sc_txbuf = malloc(sizeof(struct tsec_buf) * TSEC_NTXDESC,
- M_DEVBUF, M_WAITOK);
- for (i = 0; i < TSEC_NTXDESC; i++) {
- txb = &sc->sc_txbuf[i];
- bus_dmamap_create(sc->sc_dmat, MCLBYTES, TSEC_NTXSEGS,
- MCLBYTES, 0, BUS_DMA_WAITOK, &txb->tb_map);
- txb->tb_m = NULL;
- }
-
- /* Set wrap bit on last descriptor. */
- txd = &sc->sc_txdesc[TSEC_NTXDESC - 1];
- txd->td_status = TSEC_TX_W;
- bus_dmamap_sync(sc->sc_dmat, TSEC_DMA_MAP(sc->sc_txring),
- (TSEC_NTXDESC - 1) * sizeof(*txd), sizeof(*txd),
- BUS_DMASYNC_PREWRITE);
-
- sc->sc_tx_prod = sc->sc_tx_cons = 0;
- sc->sc_tx_cnt = 0;
-
- tsec_write(sc, TSEC_TBASE, TSEC_DMA_DVA(sc->sc_txring));
-
- /* Allocate Rx descriptor ring. */
- sc->sc_rxring = tsec_dmamem_alloc(sc,
- TSEC_NRXDESC * sizeof(struct tsec_desc), 8);
- sc->sc_rxdesc = TSEC_DMA_KVA(sc->sc_rxring);
-
- sc->sc_rxbuf = malloc(sizeof(struct tsec_buf) * TSEC_NRXDESC,
- M_DEVBUF, M_WAITOK);
-
- for (i = 0; i < TSEC_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;
- }
-
- /* Set wrap bit on last descriptor. */
- rxd = &sc->sc_rxdesc[TSEC_NRXDESC - 1];
- rxd->td_status |= TSEC_RX_W;
- bus_dmamap_sync(sc->sc_dmat, TSEC_DMA_MAP(sc->sc_rxring),
- 0, TSEC_DMA_LEN(sc->sc_rxring), BUS_DMASYNC_PREWRITE);
-
- sc->sc_rx_prod = sc->sc_rx_cons = 0;
-
- if_rxr_init(&sc->sc_rx_ring, 2, TSEC_NRXDESC);
- tsec_fill_rx_ring(sc);
-
- tsec_write(sc, TSEC_MRBLR, MCLBYTES);
-
- tsec_write(sc, TSEC_RBASE, TSEC_DMA_DVA(sc->sc_rxring));
-
- tsec_lladdr_write(sc);
-
- tsec_write(sc, TSEC_IADDR0, 0);
- tsec_write(sc, TSEC_IADDR1, 0);
- tsec_write(sc, TSEC_IADDR2, 0);
- tsec_write(sc, TSEC_IADDR3, 0);
- tsec_write(sc, TSEC_IADDR4, 0);
- tsec_write(sc, TSEC_IADDR5, 0);
- tsec_write(sc, TSEC_IADDR6, 0);
- tsec_write(sc, TSEC_IADDR7, 0);
- tsec_write(sc, TSEC_GADDR0, 0);
- tsec_write(sc, TSEC_GADDR1, 0);
- tsec_write(sc, TSEC_GADDR2, 0);
- tsec_write(sc, TSEC_GADDR3, 0);
- tsec_write(sc, TSEC_GADDR4, 0);
- tsec_write(sc, TSEC_GADDR5, 0);
- tsec_write(sc, TSEC_GADDR6, 0);
- tsec_write(sc, TSEC_GADDR7, 0);
-
- maccfg1 = tsec_read(sc, TSEC_MACCFG1);
- maccfg1 |= TSEC_MACCFG1_TXEN;
- maccfg1 |= TSEC_MACCFG1_RXEN;
- tsec_write(sc, TSEC_MACCFG1, maccfg1);
-
- /*
- * Default to full-duplex MII mode, which is the mode most
- * likely used by a directly connected integrated switch. For
- * a real PHY the mode will be set later, based on the
- * parameters negotiaded by the PHY.
- */
- maccfg2 = tsec_read(sc, TSEC_MACCFG2);
- maccfg2 &= ~TSEC_MACCFG2_IF_MODE;
- maccfg2 |= TSEC_MACCFG2_IF_MII | TSEC_MACCFG2_FDX;
- tsec_write(sc, TSEC_MACCFG2, maccfg2 | TSEC_MACCFG2_PAD);
-
- ecntrl = tsec_read(sc, TSEC_ECNTRL);
- tsec_write(sc, TSEC_ECNTRL, ecntrl | TSEC_ECNTRL_R100M);
-
- dmactrl = tsec_read(sc, TSEC_DMACTRL);
- dmactrl |= TSEC_DMACTRL_TDSEN;
- dmactrl |= TSEC_DMACTRL_TBDSEN;
- dmactrl |= TSEC_DMACTRL_WWR;
- dmactrl |= TSEC_DMACTRL_WOP;
- dmactrl &= ~(TSEC_DMACTRL_GTS | TSEC_DMACTRL_GRS);
- tsec_write(sc, TSEC_DMACTRL, dmactrl);
-
- attr = tsec_read(sc, TSEC_ATTR);
- attr |= TSEC_ATTR_RDSEN;
- attr |= TSEC_ATTR_RBDSEN;
- tsec_write(sc, TSEC_ATTR, attr);
-
- tsec_write(sc, TSEC_TSTAT, TSEC_TSTAT_THLT);
- tsec_write(sc, TSEC_RSTAT, TSEC_RSTAT_QHLT);
-
- /* Configure media. */
- if (LIST_FIRST(&sc->sc_mii.mii_phys))
- mii_mediachg(&sc->sc_mii);
-
- /* Program promiscuous mode and multicast filters. */
- tsec_iff(sc);
-
- ifp->if_flags |= IFF_RUNNING;
- ifq_clr_oactive(&ifp->if_snd);
-
- tsec_write(sc, TSEC_IMASK, TSEC_IMASK_TXEEN |
- TSEC_IMASK_TXBEN | TSEC_IMASK_TXFEN |
- TSEC_IMASK_RXBEN | TSEC_IMASK_RXFEN | TSEC_IMASK_BSYEN);
-
- timeout_add_sec(&sc->sc_tick, 1);
-}
-
-void
-tsec_down(struct tsec_softc *sc)
-{
- struct ifnet *ifp = &sc->sc_ac.ac_if;
- struct tsec_buf *txb, *rxb;
- uint32_t maccfg1;
- int i;
-
- timeout_del(&sc->sc_tick);
-
- ifp->if_flags &= ~IFF_RUNNING;
- ifq_clr_oactive(&ifp->if_snd);
- ifp->if_timer = 0;
-
- tsec_stop_dma(sc);
-
- maccfg1 = tsec_read(sc, TSEC_MACCFG1);
- maccfg1 &= ~TSEC_MACCFG1_TXEN;
- maccfg1 &= ~TSEC_MACCFG1_RXEN;
- tsec_write(sc, TSEC_MACCFG1, maccfg1);
-
- for (i = 0; i < TSEC_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);
- }
-
- tsec_dmamem_free(sc, sc->sc_txring);
- free(sc->sc_txbuf, M_DEVBUF, 0);
-
- for (i = 0; i < TSEC_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);
- }
-
- tsec_dmamem_free(sc, sc->sc_rxring);
- free(sc->sc_rxbuf, M_DEVBUF, 0);
-}
-
-void
-tsec_iff(struct tsec_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[8];
- uint32_t rctrl;
- int i;
-
- rctrl = tsec_read(sc, TSEC_RCTRL);
- rctrl &= ~TSEC_RCTRL_PROM;
- ifp->if_flags &= ~IFF_ALLMULTI;
-
- if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
- ifp->if_flags |= IFF_ALLMULTI;
- rctrl |= TSEC_RCTRL_PROM;
- bzero(hash, sizeof(hash));
- } else {
- ETHER_FIRST_MULTI(step, ac, enm);
- while (enm != NULL) {
- crc = ether_crc32_be(enm->enm_addrlo,
- ETHER_ADDR_LEN);
-
- crc >>= 24;
- hash[crc / 32] |= 1 << (31 - (crc % 32));
-
- ETHER_NEXT_MULTI(step, enm);
- }
- }
-
- for (i = 0; i < nitems(hash); i++)
- tsec_write(sc, TSEC_GADDR0 + i * 4, hash[i]);
-
- tsec_write(sc, TSEC_RCTRL, rctrl);
-}
-
-int
-tsec_encap(struct tsec_softc *sc, struct mbuf *m, int *idx)
-{
- struct tsec_desc *txd;
- bus_dmamap_t map;
- int cur, frag, i;
- uint16_t status;
-
- 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 > (TSEC_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 = &sc->sc_txdesc[frag];
- for (i = 0; i < map->dm_nsegs; i++) {
- status = txd->td_status & TSEC_TX_W;
- status |= TSEC_TX_TO1;
- if (i == (map->dm_nsegs - 1))
- status |= TSEC_TX_L;
- txd->td_len = map->dm_segs[i].ds_len;
- txd->td_addr = map->dm_segs[i].ds_addr;
- __asm volatile("eieio" ::: "memory");
- txd->td_status = status | TSEC_TX_R | TSEC_TX_I | TSEC_TX_TC;
-
- bus_dmamap_sync(sc->sc_dmat, TSEC_DMA_MAP(sc->sc_txring),
- frag * sizeof(*txd), sizeof(*txd), BUS_DMASYNC_PREWRITE);
-
- cur = frag;
- if (status & TSEC_TX_W) {
- txd = &sc->sc_txdesc[0];
- frag = 0;
- } else {
- txd++;
- frag++;
- }
- KASSERT(frag != sc->sc_tx_cons);
-
- tsec_write(sc, TSEC_TSTAT, TSEC_TSTAT_THLT);
- }
-
- 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
-tsec_reset(struct tsec_softc *sc)
-{
- tsec_stop_dma(sc);
-
- /* Set, then clear MACCFG1[Soft_Reset]. */
- tsec_write(sc, TSEC_MACCFG1, TSEC_MACCFG1_RESET);
- tsec_write(sc, TSEC_MACCFG1, 0);
-
- /* Clear IEVENT. */
- tsec_write(sc, TSEC_IEVENT, 0xffffffff);
-}
-
-void
-tsec_stop_dma(struct tsec_softc *sc)
-{
- uint32_t dmactrl, ievent;
- int n;
-
- /* Stop DMA. */
- dmactrl = tsec_read(sc, TSEC_DMACTRL);
- dmactrl |= TSEC_DMACTRL_GTS;
- tsec_write(sc, TSEC_DMACTRL, dmactrl);
-
- for (n = 0; n < 100; n++) {
- ievent = tsec_read(sc, TSEC_IEVENT);
- if (ievent & TSEC_IEVENT_GTSC)
- break;
- }
- KASSERT(n != 100);
-
- dmactrl = tsec_read(sc, TSEC_DMACTRL);
- dmactrl |= TSEC_DMACTRL_GRS;
- tsec_write(sc, TSEC_DMACTRL, dmactrl);
-
- for (n = 0; n < 100; n++) {
- ievent = tsec_read(sc, TSEC_IEVENT);
- if (ievent & TSEC_IEVENT_GRSC)
- break;
- }
- KASSERT(n != 100);
-}
-
-struct tsec_dmamem *
-tsec_dmamem_alloc(struct tsec_softc *sc, bus_size_t size, bus_size_t align)
-{
- struct tsec_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) != 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
-tsec_dmamem_free(struct tsec_softc *sc, struct tsec_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 *
-tsec_alloc_mbuf(struct tsec_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;
-
- 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
-tsec_fill_rx_ring(struct tsec_softc *sc)
-{
- struct tsec_desc *rxd;
- struct tsec_buf *rxb;
- u_int slots;
-
- for (slots = if_rxr_get(&sc->sc_rx_ring, TSEC_NRXDESC);
- slots > 0; slots--) {
- rxb = &sc->sc_rxbuf[sc->sc_rx_prod];
- rxb->tb_m = tsec_alloc_mbuf(sc, rxb->tb_map);
- if (rxb->tb_m == NULL)
- break;
-
- rxd = &sc->sc_rxdesc[sc->sc_rx_prod];
- rxd->td_len = 0;
- rxd->td_addr = rxb->tb_map->dm_segs[0].ds_addr;
- __asm volatile("eieio" ::: "memory");
- rxd->td_status |= TSEC_RX_E | TSEC_RX_I;
-
- if (rxd->td_status & TSEC_RX_W)
- sc->sc_rx_prod = 0;
- else
- sc->sc_rx_prod++;
- }
- if_rxr_put(&sc->sc_rx_ring, slots);
-}