1*5eec54d3Sjsg /* $OpenBSD: if_mc.c,v 1.35 2024/09/06 10:54:08 jsg Exp $ */ 295b52b4dSgwk /* $NetBSD: if_mc.c,v 1.9.16.1 2006/06/21 14:53:13 yamt Exp $ */ 395b52b4dSgwk 495b52b4dSgwk /*- 595b52b4dSgwk * Copyright (c) 1997 David Huang <khym@bga.com> 695b52b4dSgwk * All rights reserved. 795b52b4dSgwk * 895b52b4dSgwk * Portions of this code are based on code by Denton Gentry <denny1@home.com> 995b52b4dSgwk * and Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>. 1095b52b4dSgwk * 1195b52b4dSgwk * Redistribution and use in source and binary forms, with or without 1295b52b4dSgwk * modification, are permitted provided that the following conditions 1395b52b4dSgwk * are met: 1495b52b4dSgwk * 1. Redistributions of source code must retain the above copyright 1595b52b4dSgwk * notice, this list of conditions and the following disclaimer. 1695b52b4dSgwk * 2. The name of the author may not be used to endorse or promote products 1795b52b4dSgwk * derived from this software without specific prior written permission 1895b52b4dSgwk * 1995b52b4dSgwk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2095b52b4dSgwk * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2195b52b4dSgwk * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2295b52b4dSgwk * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2395b52b4dSgwk * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2495b52b4dSgwk * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2595b52b4dSgwk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2695b52b4dSgwk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2795b52b4dSgwk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2895b52b4dSgwk * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2995b52b4dSgwk * 3095b52b4dSgwk */ 3195b52b4dSgwk 3295b52b4dSgwk /* 3395b52b4dSgwk * AMD AM79C940 (MACE) driver with DBDMA bus attachment and DMA routines 3495b52b4dSgwk * for onboard ethernet found on most old world macs. 3595b52b4dSgwk */ 3695b52b4dSgwk 3795b52b4dSgwk #include <sys/param.h> 3895b52b4dSgwk #include <sys/systm.h> 3995b52b4dSgwk #include <sys/mbuf.h> 4095b52b4dSgwk #include <sys/buf.h> 4195b52b4dSgwk #include <sys/socket.h> 4295b52b4dSgwk #include <sys/syslog.h> 4395b52b4dSgwk #include <sys/ioctl.h> 4495b52b4dSgwk #include <sys/errno.h> 4595b52b4dSgwk #include <sys/device.h> 463f1243dcSderaadt #include <sys/timeout.h> 4795b52b4dSgwk 4895b52b4dSgwk #include <net/if.h> 4995b52b4dSgwk #include <net/if_media.h> 5095b52b4dSgwk 5195b52b4dSgwk #include <netinet/in.h> 5295b52b4dSgwk #include <netinet/if_ether.h> 5395b52b4dSgwk 5495b52b4dSgwk #include "bpfilter.h" 5595b52b4dSgwk #if NBPFILTER > 0 5695b52b4dSgwk #include <net/bpf.h> 5795b52b4dSgwk #endif 5895b52b4dSgwk 5995b52b4dSgwk #include <dev/ofw/openfirm.h> 6095b52b4dSgwk #include <machine/pio.h> 6195b52b4dSgwk #include <machine/bus.h> 6295b52b4dSgwk #include <machine/autoconf.h> 6395b52b4dSgwk 6495b52b4dSgwk #include <macppc/dev/dbdma.h> 6595b52b4dSgwk 6695b52b4dSgwk #define MC_REGSPACING 16 6795b52b4dSgwk #define MC_REGSIZE MACE_NREGS * MC_REGSPACING 6895b52b4dSgwk #define MACE_REG(x) ((x)*MC_REGSPACING) 6995b52b4dSgwk #define MACE_BUFLEN 2048 7095b52b4dSgwk #define MACE_TXBUFS 2 7195b52b4dSgwk #define MACE_RXBUFS 8 7295b52b4dSgwk 7395b52b4dSgwk #define MC_RXDMABUFS 4 7495b52b4dSgwk 7595b52b4dSgwk #define MACE_BUFSZ ((MACE_RXBUFS + MACE_TXBUFS + 2) * MACE_BUFLEN) 7695b52b4dSgwk 7795b52b4dSgwk #define NIC_GET(sc, reg) (in8rb(sc->sc_reg + MACE_REG(reg))) 7895b52b4dSgwk 7995b52b4dSgwk #define NIC_PUT(sc, reg, val) (out8rb(sc->sc_reg + MACE_REG(reg), (val))) 8095b52b4dSgwk 8195b52b4dSgwk /* 8295b52b4dSgwk * AMD MACE (Am79C940) register definitions 8395b52b4dSgwk */ 8495b52b4dSgwk #define MACE_RCVFIFO 0 /* Receive FIFO [15-00] (read only) */ 8595b52b4dSgwk #define MACE_XMTFIFO 1 /* Transmit FIFO [15-00] (write only) */ 8695b52b4dSgwk #define MACE_XMTFC 2 /* Transmit Frame Control (read/write) */ 8795b52b4dSgwk #define MACE_XMTFS 3 /* Transmit Frame Status (read only) */ 8895b52b4dSgwk #define MACE_XMTRC 4 /* Transmit Retry Count (read only) */ 8995b52b4dSgwk #define MACE_RCVFC 5 /* Receive Frame Control (read/write) */ 9095b52b4dSgwk #define MACE_RCVFS 6 /* Receive Frame Status (4 bytes) (read only) */ 9195b52b4dSgwk #define MACE_FIFOFC 7 /* FIFO Frame Count (read only) */ 9295b52b4dSgwk #define MACE_IR 8 /* Interrupt Register (read only) */ 9395b52b4dSgwk #define MACE_IMR 9 /* Interrupt Mask Register (read/write) */ 9495b52b4dSgwk #define MACE_PR 10 /* Poll Register (read only) */ 9595b52b4dSgwk #define MACE_BIUCC 11 /* BIU Configuration Control (read/write) */ 9695b52b4dSgwk #define MACE_FIFOCC 12 /* FIFO Configuration Control (read/write) */ 9795b52b4dSgwk #define MACE_MACCC 13 /* MAC Configuration Control (read/write) */ 9895b52b4dSgwk #define MACE_PLSCC 14 /* PLS Configuration Control (read/write) */ 99*5eec54d3Sjsg #define MACE_PHYCC 15 /* PHY Configuration Control (read/write) */ 10095b52b4dSgwk #define MACE_CHIPIDL 16 /* Chip ID Register [07-00] (read only) */ 10195b52b4dSgwk #define MACE_CHIPIDH 17 /* Chip ID Register [15-08] (read only) */ 10295b52b4dSgwk #define MACE_IAC 18 /* Internal Address Configuration (read/write) */ 10395b52b4dSgwk /* RESERVED 19 Reserved (read/write as 0) */ 10495b52b4dSgwk #define MACE_LADRF 20 /* Logical Address Filter (8 bytes) (read/write) */ 10595b52b4dSgwk #define MACE_PADR 21 /* Physical Address (6 bytes) (read/write) */ 10695b52b4dSgwk /* RESERVED 22 Reserved (read/write as 0) */ 10795b52b4dSgwk /* RESERVED 23 Reserved (read/write as 0) */ 10895b52b4dSgwk #define MACE_MPC 24 /* Missed Packet Count (read only) */ 10995b52b4dSgwk /* RESERVED 25 Reserved (read/write as 0) */ 11095b52b4dSgwk #define MACE_RNTPC 26 /* Runt Packet Count (read only) */ 11195b52b4dSgwk #define MACE_RCVCC 27 /* Receive Collision Count (read only) */ 11295b52b4dSgwk /* RESERVED 28 Reserved (read/write as 0) */ 11395b52b4dSgwk #define MACE_UTR 29 /* User Test Register (read/write) */ 11495b52b4dSgwk #define MACE_RTR1 30 /* Reserved Test Register 1 (read/write as 0) */ 11595b52b4dSgwk #define MACE_RTR2 31 /* Reserved Test Register 2 (read/write as 0) */ 11695b52b4dSgwk 11795b52b4dSgwk #define MACE_NREGS 32 11895b52b4dSgwk 11995b52b4dSgwk /* 2: Transmit Frame Control (XMTFC) */ 12095b52b4dSgwk #define DRTRY 0x80 /* Disable Retry */ 12195b52b4dSgwk #define DXMTFCS 0x08 /* Disable Transmit FCS */ 12295b52b4dSgwk #define APADXMT 0x01 /* Auto Pad Transmit */ 12395b52b4dSgwk 12495b52b4dSgwk /* 3: Transmit Frame Status (XMTFS) */ 12595b52b4dSgwk #define XMTSV 0x80 /* Transmit Status Valid */ 12695b52b4dSgwk #define UFLO 0x40 /* Underflow */ 12795b52b4dSgwk #define LCOL 0x20 /* Late Collision */ 12895b52b4dSgwk #define MORE 0x10 /* More than one retry needed */ 12995b52b4dSgwk #define ONE 0x08 /* Exactly one retry needed */ 13095b52b4dSgwk #define DEFER 0x04 /* Transmission deferred */ 13195b52b4dSgwk #define LCAR 0x02 /* Loss of Carrier */ 13295b52b4dSgwk #define RTRY 0x01 /* Retry Error */ 13395b52b4dSgwk 13495b52b4dSgwk /* 4: Transmit Retry Count (XMTRC) */ 13595b52b4dSgwk #define EXDEF 0x80 /* Excessive Defer */ 13695b52b4dSgwk #define XMTRC 0x0f /* Transmit Retry Count */ 13795b52b4dSgwk 13895b52b4dSgwk /* 5: Receive Frame Control (RCVFC) */ 13995b52b4dSgwk #define LLRCV 0x08 /* Low Latency Receive */ 14095b52b4dSgwk #define MR 0x04 /* Match/Reject */ 14195b52b4dSgwk #define ASTRPRCV 0x01 /* Auto Strip Receive */ 14295b52b4dSgwk 14395b52b4dSgwk /* 6: Receive Frame Status (RCVFS) */ 14495b52b4dSgwk /* 4 byte register; read 4 times to get all of the bytes */ 14595b52b4dSgwk /* Read 1: RFS0 - Receive Message Byte Count [7-0] (RCVCNT) */ 14695b52b4dSgwk 14795b52b4dSgwk /* Read 2: RFS1 - Receive Status (RCVSTS) */ 14895b52b4dSgwk #define OFLO 0x80 /* Overflow flag */ 14995b52b4dSgwk #define CLSN 0x40 /* Collision flag */ 15095b52b4dSgwk #define FRAM 0x20 /* Framing Error flag */ 15195b52b4dSgwk #define FCS 0x10 /* FCS Error flag */ 15295b52b4dSgwk #define RCVCNT 0x0f /* Receive Message Byte Count [11-8] */ 15395b52b4dSgwk 15495b52b4dSgwk /* Read 3: RFS2 - Runt Packet Count (RNTPC) [7-0] */ 15595b52b4dSgwk 15695b52b4dSgwk /* Read 4: RFS3 - Receive Collision Count (RCVCC) [7-0] */ 15795b52b4dSgwk 15895b52b4dSgwk /* 7: FIFO Frame Count (FIFOFC) */ 15995b52b4dSgwk #define RCVFC 0xf0 /* Receive Frame Count */ 16095b52b4dSgwk #define XMTFC 0x0f /* Transmit Frame Count */ 16195b52b4dSgwk 16295b52b4dSgwk /* 8: Interrupt Register (IR) */ 16395b52b4dSgwk #define JAB 0x80 /* Jabber Error */ 16495b52b4dSgwk #define BABL 0x40 /* Babble Error */ 16595b52b4dSgwk #define CERR 0x20 /* Collision Error */ 16695b52b4dSgwk #define RCVCCO 0x10 /* Receive Collision Count Overflow */ 16795b52b4dSgwk #define RNTPCO 0x08 /* Runt Packet Count Overflow */ 16895b52b4dSgwk #define MPCO 0x04 /* Missed Packet Count Overflow */ 16995b52b4dSgwk #define RCVINT 0x02 /* Receive Interrupt */ 17095b52b4dSgwk #define XMTINT 0x01 /* Transmit Interrupt */ 17195b52b4dSgwk 17236fd90dcSjsg /* 9: Interrupt Mask Register (IMR) */ 17395b52b4dSgwk #define JABM 0x80 /* Jabber Error Mask */ 17495b52b4dSgwk #define BABLM 0x40 /* Babble Error Mask */ 17595b52b4dSgwk #define CERRM 0x20 /* Collision Error Mask */ 17695b52b4dSgwk #define RCVCCOM 0x10 /* Receive Collision Count Overflow Mask */ 17795b52b4dSgwk #define RNTPCOM 0x08 /* Runt Packet Count Overflow Mask */ 17895b52b4dSgwk #define MPCOM 0x04 /* Missed Packet Count Overflow Mask */ 17995b52b4dSgwk #define RCVINTM 0x02 /* Receive Interrupt Mask */ 18095b52b4dSgwk #define XMTINTM 0x01 /* Transmit Interrupt Mask */ 18195b52b4dSgwk 18295b52b4dSgwk /* 10: Poll Register (PR) */ 18395b52b4dSgwk #define XMTSV 0x80 /* Transmit Status Valid */ 18495b52b4dSgwk #define TDTREQ 0x40 /* Transmit Data Transfer Request */ 18595b52b4dSgwk #define RDTREQ 0x20 /* Receive Data Transfer Request */ 18695b52b4dSgwk 18795b52b4dSgwk /* 11: BIU Configuration Control (BIUCC) */ 18895b52b4dSgwk #define BSWP 0x40 /* Byte Swap */ 18995b52b4dSgwk #define XMTSP 0x30 /* Transmit Start Point */ 19095b52b4dSgwk #define XMTSP_4 0x00 /* 4 bytes */ 19195b52b4dSgwk #define XMTSP_16 0x10 /* 16 bytes */ 19295b52b4dSgwk #define XMTSP_64 0x20 /* 64 bytes */ 19395b52b4dSgwk #define XMTSP_112 0x30 /* 112 bytes */ 19495b52b4dSgwk #define SWRST 0x01 /* Software Reset */ 19595b52b4dSgwk 19695b52b4dSgwk /* 12: FIFO Configuration Control (FIFOCC) */ 19795b52b4dSgwk #define XMTFW 0xc0 /* Transmit FIFO Watermark */ 19895b52b4dSgwk #define XMTFW_8 0x00 /* 8 write cycles */ 19995b52b4dSgwk #define XMTFW_16 0x40 /* 16 write cycles */ 20095b52b4dSgwk #define XMTFW_32 0x80 /* 32 write cycles */ 20195b52b4dSgwk #define RCVFW 0x30 /* Receive FIFO Watermark */ 20295b52b4dSgwk #define RCVFW_16 0x00 /* 16 bytes */ 20395b52b4dSgwk #define RCVFW_32 0x10 /* 32 bytes */ 20495b52b4dSgwk #define RCVFW_64 0x20 /* 64 bytes */ 20595b52b4dSgwk #define XMTFWU 0x08 /* Transmit FIFO Watermark Update */ 20695b52b4dSgwk #define RCVFWU 0x04 /* Receive FIFO Watermark Update */ 20795b52b4dSgwk #define XMTBRST 0x02 /* Transmit Burst */ 20895b52b4dSgwk #define RCVBRST 0x01 /* Receive Burst */ 20995b52b4dSgwk 21095b52b4dSgwk /* 13: MAC Configuration (MACCC) */ 21195b52b4dSgwk #define PROM 0x80 /* Promiscuous */ 21295b52b4dSgwk #define DXMT2PD 0x40 /* Disable Transmit Two Part Deferral */ 21395b52b4dSgwk #define EMBA 0x20 /* Enable Modified Back-off Algorithm */ 21495b52b4dSgwk #define DRCVPA 0x08 /* Disable Receive Physical Address */ 21595b52b4dSgwk #define DRCVBC 0x04 /* Disable Receive Broadcast */ 21695b52b4dSgwk #define ENXMT 0x02 /* Enable Transmit */ 21795b52b4dSgwk #define ENRCV 0x01 /* Enable Receive */ 21895b52b4dSgwk 21995b52b4dSgwk /* 14: PLS Configuration Control (PLSCC) */ 22095b52b4dSgwk #define XMTSEL 0x08 /* Transmit Mode Select */ 22195b52b4dSgwk #define PORTSEL 0x06 /* Port Select */ 22295b52b4dSgwk #define PORTSEL_AUI 0x00 /* Select AUI */ 22395b52b4dSgwk #define PORTSEL_10BT 0x02 /* Select 10BASE-T */ 22495b52b4dSgwk #define PORTSEL_DAI 0x04 /* Select DAI port */ 22595b52b4dSgwk #define PORTSEL_GPSI 0x06 /* Select GPSI */ 22695b52b4dSgwk #define ENPLSIO 0x01 /* Enable PLS I/O */ 22795b52b4dSgwk 22895b52b4dSgwk /* 15: PHY Configuration (PHYCC) */ 22995b52b4dSgwk #define LNKFL 0x80 /* Link Fail */ 23095b52b4dSgwk #define DLNKTST 0x40 /* Disable Link Test */ 23195b52b4dSgwk #define REVPOL 0x20 /* Reversed Polarity */ 23295b52b4dSgwk #define DAPC 0x10 /* Disable Auto Polarity Correction */ 23395b52b4dSgwk #define LRT 0x08 /* Low Receive Threshold */ 23495b52b4dSgwk #define ASEL 0x04 /* Auto Select */ 23595b52b4dSgwk #define RWAKE 0x02 /* Remote Wake */ 23695b52b4dSgwk #define AWAKE 0x01 /* Auto Wake */ 23795b52b4dSgwk 23895b52b4dSgwk /* 18: Internal Address Configuration (IAC) */ 23995b52b4dSgwk #define ADDRCHG 0x80 /* Address Change */ 24095b52b4dSgwk #define PHYADDR 0x04 /* Physical Address Reset */ 24195b52b4dSgwk #define LOGADDR 0x02 /* Logical Address Reset */ 24295b52b4dSgwk 24395b52b4dSgwk /* 28: User Test Register (UTR) */ 24495b52b4dSgwk #define RTRE 0x80 /* Reserved Test Register Enable */ 24595b52b4dSgwk #define RTRD 0x40 /* Reserved Test Register Disable */ 24695b52b4dSgwk #define RPA 0x20 /* Run Packet Accept */ 24795b52b4dSgwk #define FCOLL 0x10 /* Force Collision */ 24895b52b4dSgwk #define RCVFCSE 0x08 /* Receive FCS Enable */ 24995b52b4dSgwk #define LOOP 0x06 /* Loopback Control */ 25095b52b4dSgwk #define LOOP_NONE 0x00 /* No Loopback */ 25195b52b4dSgwk #define LOOP_EXT 0x02 /* External Loopback */ 25295b52b4dSgwk #define LOOP_INT 0x04 /* Internal Loopback, excludes MENDEC */ 25395b52b4dSgwk #define LOOP_INT_MENDEC 0x06 /* Internal Loopback, includes MENDEC */ 25495b52b4dSgwk 25595b52b4dSgwk struct mc_rxframe { 25695b52b4dSgwk u_int8_t rx_rcvcnt; 25795b52b4dSgwk u_int8_t rx_rcvsts; 25895b52b4dSgwk u_int8_t rx_rntpc; 25995b52b4dSgwk u_int8_t rx_rcvcc; 26095b52b4dSgwk u_char *rx_frame; 26195b52b4dSgwk }; 26295b52b4dSgwk 26395b52b4dSgwk struct mc_softc { 26495b52b4dSgwk struct device sc_dev; /* base device glue */ 26595b52b4dSgwk struct arpcom sc_arpcom; /* Ethernet common part */ 26695b52b4dSgwk struct timeout sc_tick_ch; 26795b52b4dSgwk 26895b52b4dSgwk struct mc_rxframe sc_rxframe; 26995b52b4dSgwk u_int8_t sc_biucc; 27095b52b4dSgwk u_int8_t sc_fifocc; 27195b52b4dSgwk u_int8_t sc_plscc; 27295b52b4dSgwk u_int8_t sc_enaddr[6]; 27395b52b4dSgwk u_int8_t sc_pad[2]; 27495b52b4dSgwk int sc_havecarrier; /* carrier status */ 27595b52b4dSgwk 27695b52b4dSgwk char *sc_reg; 27795b52b4dSgwk bus_dma_tag_t sc_dmat; 27895b52b4dSgwk bus_dmamap_t sc_bufmap; 27995b52b4dSgwk bus_dma_segment_t sc_bufseg[1]; 28095b52b4dSgwk 28195b52b4dSgwk dbdma_regmap_t *sc_txdma; 28295b52b4dSgwk dbdma_regmap_t *sc_rxdma; 28395b52b4dSgwk dbdma_command_t *sc_txdmacmd; 28495b52b4dSgwk dbdma_command_t *sc_rxdmacmd; 28595b52b4dSgwk dbdma_t sc_txdbdma; 28695b52b4dSgwk dbdma_t sc_rxdbdma; 28795b52b4dSgwk 28895b52b4dSgwk caddr_t sc_txbuf; 28995b52b4dSgwk caddr_t sc_rxbuf; 29095b52b4dSgwk paddr_t sc_txbuf_pa; 29195b52b4dSgwk paddr_t sc_rxbuf_pa; 29295b52b4dSgwk int sc_tail; 29395b52b4dSgwk int sc_rxset; 29495b52b4dSgwk int sc_txset; 29595b52b4dSgwk int sc_txseti; 29695b52b4dSgwk }; 29795b52b4dSgwk 29895b52b4dSgwk int mc_match(struct device *, void *, void *); 29995b52b4dSgwk void mc_attach(struct device *, struct device *, void *); 30095b52b4dSgwk 301471aeecfSnaddy const struct cfattach mc_ca = { 30295b52b4dSgwk sizeof(struct mc_softc), mc_match, mc_attach 30395b52b4dSgwk }; 30495b52b4dSgwk 30595b52b4dSgwk struct cfdriver mc_cd = { 30695b52b4dSgwk NULL, "mc", DV_IFNET 30795b52b4dSgwk }; 30895b52b4dSgwk 309947a7310Sgwk void mc_init(struct mc_softc *sc); 31095b52b4dSgwk int mc_dmaintr(void *arg); 31195b52b4dSgwk void mc_reset_rxdma(struct mc_softc *sc); 31295b52b4dSgwk void mc_reset_txdma(struct mc_softc *sc); 31395b52b4dSgwk int mc_stop(struct mc_softc *sc); 31495b52b4dSgwk int mc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 31595b52b4dSgwk void mc_start(struct ifnet *ifp); 31695b52b4dSgwk void mc_reset(struct mc_softc *sc); 31795b52b4dSgwk void mc_tint(struct mc_softc *sc); 31895b52b4dSgwk void mc_rint(struct mc_softc *sc); 31995b52b4dSgwk int mc_intr(void *); 32095b52b4dSgwk void mc_watchdog(struct ifnet *ifp); 32195b52b4dSgwk 32295b52b4dSgwk u_int maceput(struct mc_softc *sc, struct mbuf *); 32395b52b4dSgwk void mace_read(struct mc_softc *, caddr_t, int); 32495b52b4dSgwk struct mbuf *mace_get(struct mc_softc *, caddr_t, int); 325947a7310Sgwk static void mace_calcladrf(struct mc_softc *, u_int8_t *); 32695b52b4dSgwk void mc_putpacket(struct mc_softc *, u_int); 32795b52b4dSgwk 32895b52b4dSgwk int 32995b52b4dSgwk mc_match(struct device *parent, void *arg, void *aux) 33095b52b4dSgwk { 33195b52b4dSgwk struct confargs *ca = aux; 33295b52b4dSgwk 33395b52b4dSgwk if (strcmp(ca->ca_name, "mace") != 0) 33495b52b4dSgwk return 0; 33595b52b4dSgwk 33695b52b4dSgwk /* requires 6 regs */ 33795b52b4dSgwk if (ca->ca_nreg / sizeof(int) != 6) 33895b52b4dSgwk return 0; 33995b52b4dSgwk 34095b52b4dSgwk /* requires 3 intrs */ 34195b52b4dSgwk if (ca->ca_nintr / sizeof(int) != 3) 34295b52b4dSgwk return 0; 34395b52b4dSgwk 34495b52b4dSgwk return 1; 34595b52b4dSgwk } 34695b52b4dSgwk 34795b52b4dSgwk void 34895b52b4dSgwk mc_attach(struct device *parent, struct device *self, void *aux) 34995b52b4dSgwk { 35095b52b4dSgwk struct confargs *ca = aux; 35195b52b4dSgwk struct mc_softc *sc = (struct mc_softc *)self; 35295b52b4dSgwk struct ifnet *ifp = &sc->sc_arpcom.ac_if; 35395b52b4dSgwk u_int8_t lladdr[ETHER_ADDR_LEN]; 35495b52b4dSgwk int nseg, error; 35595b52b4dSgwk 356e6734d7fSgwk if (OF_getprop(ca->ca_node, "local-mac-address", lladdr, 357e6734d7fSgwk ETHER_ADDR_LEN) != ETHER_ADDR_LEN) { 35895b52b4dSgwk printf(": failed to get MAC address.\n"); 35995b52b4dSgwk return; 36095b52b4dSgwk } 36195b52b4dSgwk 36295b52b4dSgwk ca->ca_reg[0] += ca->ca_baseaddr; 36395b52b4dSgwk ca->ca_reg[2] += ca->ca_baseaddr; 36495b52b4dSgwk ca->ca_reg[4] += ca->ca_baseaddr; 36595b52b4dSgwk 366e6734d7fSgwk if ((sc->sc_reg = mapiodev(ca->ca_reg[0], ca->ca_reg[1])) == NULL) { 367e6734d7fSgwk printf(": cannot map registers\n"); 368e6734d7fSgwk return; 369e6734d7fSgwk } 37095b52b4dSgwk 371e6734d7fSgwk sc->sc_dmat = ca->ca_dmat; 37295b52b4dSgwk sc->sc_tail = 0; 373e6734d7fSgwk 374e6734d7fSgwk if ((sc->sc_txdma = mapiodev(ca->ca_reg[2], ca->ca_reg[3])) == NULL) { 375e6734d7fSgwk printf(": cannot map TX DMA registers\n"); 376e6734d7fSgwk goto notxdma; 377e6734d7fSgwk } 378e6734d7fSgwk if ((sc->sc_rxdma = mapiodev(ca->ca_reg[4], ca->ca_reg[5])) == NULL) { 379e6734d7fSgwk printf(": cannot map RX DMA registers\n"); 380e6734d7fSgwk goto norxdma; 381e6734d7fSgwk } 382e6734d7fSgwk if ((sc->sc_txdbdma = dbdma_alloc(sc->sc_dmat, 2)) == NULL) { 383e6734d7fSgwk printf(": cannot alloc TX DMA descriptors\n"); 384e6734d7fSgwk goto notxdbdma; 385e6734d7fSgwk } 38695b52b4dSgwk sc->sc_txdmacmd = sc->sc_txdbdma->d_addr; 387e6734d7fSgwk 388e6734d7fSgwk if ((sc->sc_rxdbdma = dbdma_alloc(sc->sc_dmat, 8 + 1)) == NULL) { 389e6734d7fSgwk printf(": cannot alloc RX DMA descriptors\n"); 390e6734d7fSgwk goto norxdbdma; 391e6734d7fSgwk } 39295b52b4dSgwk sc->sc_rxdmacmd = sc->sc_rxdbdma->d_addr; 39395b52b4dSgwk 394e6734d7fSgwk if ((error = bus_dmamem_alloc(sc->sc_dmat, MACE_BUFSZ, PAGE_SIZE, 0, 395e6734d7fSgwk sc->sc_bufseg, 1, &nseg, BUS_DMA_NOWAIT))) { 396e6734d7fSgwk printf(": cannot allocate DMA mem (%d)\n", error); 397e6734d7fSgwk goto nodmamem; 39895b52b4dSgwk } 39995b52b4dSgwk 400e6734d7fSgwk if ((error = bus_dmamem_map(sc->sc_dmat, sc->sc_bufseg, nseg, 401e6734d7fSgwk MACE_BUFSZ, &sc->sc_txbuf, BUS_DMA_NOWAIT))) { 402e6734d7fSgwk printf(": cannot map DMA mem (%d)\n", error); 403e6734d7fSgwk goto nodmamap; 40495b52b4dSgwk } 40595b52b4dSgwk 406e6734d7fSgwk if ((error = bus_dmamap_create(sc->sc_dmat, MACE_BUFSZ, 1, MACE_BUFSZ, 407e6734d7fSgwk 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->sc_bufmap))) { 408e6734d7fSgwk printf(": cannot create DMA map (%d)\n", error); 409e6734d7fSgwk goto nodmacreate; 41095b52b4dSgwk } 41195b52b4dSgwk 412e6734d7fSgwk if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_bufmap, sc->sc_txbuf, 413e6734d7fSgwk MACE_BUFSZ, NULL, BUS_DMA_NOWAIT))) { 414e6734d7fSgwk printf(": cannot load DMA map (%d)\n", error); 415e6734d7fSgwk goto nodmaload; 41695b52b4dSgwk } 41795b52b4dSgwk 41895b52b4dSgwk sc->sc_txbuf_pa = sc->sc_bufmap->dm_segs->ds_addr; 41995b52b4dSgwk sc->sc_rxbuf = sc->sc_txbuf + MACE_BUFLEN * MACE_TXBUFS; 42095b52b4dSgwk sc->sc_rxbuf_pa = sc->sc_txbuf_pa + MACE_BUFLEN * MACE_TXBUFS; 42195b52b4dSgwk 422e6734d7fSgwk printf(": irq %d,%d,%d", ca->ca_intr[0], ca->ca_intr[1], 423e6734d7fSgwk ca->ca_intr[2]); 42495b52b4dSgwk 42595b52b4dSgwk /* disable receive DMA */ 42695b52b4dSgwk dbdma_reset(sc->sc_rxdma); 42795b52b4dSgwk 42895b52b4dSgwk /* disable transmit DMA */ 42995b52b4dSgwk dbdma_reset(sc->sc_txdma); 43095b52b4dSgwk 43195b52b4dSgwk /* install interrupt handlers */ 43295b52b4dSgwk mac_intr_establish(parent, ca->ca_intr[2], IST_LEVEL, IPL_NET, 4331ac74572Sderaadt mc_dmaintr, sc, sc->sc_dev.dv_xname); 43495b52b4dSgwk mac_intr_establish(parent, ca->ca_intr[0], IST_LEVEL, IPL_NET, 4351ac74572Sderaadt mc_intr, sc, sc->sc_dev.dv_xname); 43695b52b4dSgwk 43795b52b4dSgwk sc->sc_biucc = XMTSP_64; 43895b52b4dSgwk sc->sc_fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU | 43995b52b4dSgwk XMTBRST | RCVBRST; 44095b52b4dSgwk sc->sc_plscc = PORTSEL_GPSI | ENPLSIO; 44195b52b4dSgwk 44295b52b4dSgwk /* reset the chip and disable all interrupts */ 44395b52b4dSgwk NIC_PUT(sc, MACE_BIUCC, SWRST); 44495b52b4dSgwk DELAY(100); 44595b52b4dSgwk 44695b52b4dSgwk NIC_PUT(sc, MACE_IMR, ~0); 44795b52b4dSgwk 44895b52b4dSgwk bcopy(lladdr, sc->sc_enaddr, ETHER_ADDR_LEN); 44995b52b4dSgwk bcopy(sc->sc_enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); 45095b52b4dSgwk printf(": address %s\n", ether_sprintf(lladdr)); 45195b52b4dSgwk 45295b52b4dSgwk bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); 45395b52b4dSgwk ifp->if_softc = sc; 45495b52b4dSgwk ifp->if_ioctl = mc_ioctl; 45595b52b4dSgwk ifp->if_start = mc_start; 45695b52b4dSgwk ifp->if_flags = 4579d022f3eStedu IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 45895b52b4dSgwk ifp->if_watchdog = mc_watchdog; 45995b52b4dSgwk ifp->if_timer = 0; 46095b52b4dSgwk 46195b52b4dSgwk if_attach(ifp); 46295b52b4dSgwk ether_ifattach(ifp); 463e6734d7fSgwk 464e6734d7fSgwk return; 465e6734d7fSgwk nodmaload: 466e6734d7fSgwk bus_dmamap_destroy(sc->sc_dmat, sc->sc_bufmap); 467e6734d7fSgwk nodmacreate: 468e6734d7fSgwk bus_dmamem_unmap(sc->sc_dmat, sc->sc_txbuf, MACE_BUFSZ); 469e6734d7fSgwk nodmamap: 470e6734d7fSgwk bus_dmamem_free(sc->sc_dmat, sc->sc_bufseg, 1); 471e6734d7fSgwk nodmamem: 472e6734d7fSgwk dbdma_free(sc->sc_rxdbdma); 473e6734d7fSgwk norxdbdma: 474e6734d7fSgwk dbdma_free(sc->sc_txdbdma); 475e6734d7fSgwk notxdbdma: 4764471727cSkettenis unmapiodev((void *)sc->sc_rxdma, ca->ca_reg[5]); 477e6734d7fSgwk norxdma: 4784471727cSkettenis unmapiodev((void *)sc->sc_txdma, ca->ca_reg[3]); 479e6734d7fSgwk notxdma: 4804471727cSkettenis unmapiodev(sc->sc_reg, ca->ca_reg[1]); 48195b52b4dSgwk } 48295b52b4dSgwk 48395b52b4dSgwk int 48495b52b4dSgwk mc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 48595b52b4dSgwk { 48695b52b4dSgwk struct mc_softc *sc = ifp->if_softc; 487967f68a4Sbrad int s, err = 0; 48895b52b4dSgwk 489967f68a4Sbrad s = splnet(); 49095b52b4dSgwk 49195b52b4dSgwk switch (cmd) { 49295b52b4dSgwk case SIOCSIFADDR: 49395b52b4dSgwk ifp->if_flags |= IFF_UP; 494947a7310Sgwk if (!(ifp->if_flags & IFF_RUNNING)) 495947a7310Sgwk mc_init(sc); 49695b52b4dSgwk break; 49795b52b4dSgwk 49895b52b4dSgwk case SIOCSIFFLAGS: 49995b52b4dSgwk if ((ifp->if_flags & IFF_UP) == 0 && 50095b52b4dSgwk (ifp->if_flags & IFF_RUNNING) != 0) { 50195b52b4dSgwk /* 50295b52b4dSgwk * If interface is marked down and it is running, 50395b52b4dSgwk * then stop it. 50495b52b4dSgwk */ 50595b52b4dSgwk mc_stop(sc); 50695b52b4dSgwk } else if ((ifp->if_flags & IFF_UP) != 0 && 50795b52b4dSgwk (ifp->if_flags & IFF_RUNNING) == 0) { 50895b52b4dSgwk /* 50995b52b4dSgwk * If interface is marked up and it is stopped, 51095b52b4dSgwk * then start it. 51195b52b4dSgwk */ 512947a7310Sgwk mc_init(sc); 51395b52b4dSgwk } else { 51495b52b4dSgwk /* 51595b52b4dSgwk * reset the interface to pick up any other changes 51695b52b4dSgwk * in flags 51795b52b4dSgwk */ 51895b52b4dSgwk mc_reset(sc); 51995b52b4dSgwk mc_start(ifp); 52095b52b4dSgwk } 52195b52b4dSgwk break; 52295b52b4dSgwk 52334f0f0fdSbrad default: 52434f0f0fdSbrad err = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data); 52534f0f0fdSbrad } 52695b52b4dSgwk 52795b52b4dSgwk if (err == ENETRESET) { 52895b52b4dSgwk if (ifp->if_flags & IFF_RUNNING) 52995b52b4dSgwk mc_reset(sc); 53095b52b4dSgwk err = 0; 53195b52b4dSgwk } 532775775feSbrad 53395b52b4dSgwk splx(s); 53495b52b4dSgwk return (err); 53595b52b4dSgwk } 53695b52b4dSgwk 53795b52b4dSgwk /* 53895b52b4dSgwk * Encapsulate a packet of type family for the local net. 53995b52b4dSgwk */ 54095b52b4dSgwk void 54195b52b4dSgwk mc_start(struct ifnet *ifp) 54295b52b4dSgwk { 54395b52b4dSgwk struct mc_softc *sc = ifp->if_softc; 54495b52b4dSgwk struct mbuf *m; 54595b52b4dSgwk 546de6cd8fbSdlg if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd)) 54795b52b4dSgwk return; 54895b52b4dSgwk 54995b52b4dSgwk while (1) { 550de6cd8fbSdlg if (ifq_is_oactive(&ifp->if_snd)) 55195b52b4dSgwk return; 55295b52b4dSgwk 55363bcfa73Spatrick m = ifq_dequeue(&ifp->if_snd); 5549e3a439eSgwk if (m == NULL) 55595b52b4dSgwk return; 55695b52b4dSgwk 55795b52b4dSgwk #if NBPFILTER > 0 55895b52b4dSgwk /* 55995b52b4dSgwk * If bpf is listening on this interface, let it 56095b52b4dSgwk * see the packet before we commit it to the wire. 56195b52b4dSgwk */ 56295b52b4dSgwk if (ifp->if_bpf) 56395b52b4dSgwk bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); 56495b52b4dSgwk #endif 56595b52b4dSgwk 56695b52b4dSgwk /* 56795b52b4dSgwk * Copy the mbuf chain into the transmit buffer. 56895b52b4dSgwk */ 569de6cd8fbSdlg ifq_set_oactive(&ifp->if_snd); 57095b52b4dSgwk maceput(sc, m); 57195b52b4dSgwk } 57295b52b4dSgwk } 57395b52b4dSgwk 57495b52b4dSgwk /* 57595b52b4dSgwk * reset and restart the MACE. Called in case of fatal 57695b52b4dSgwk * hardware/software errors. 57795b52b4dSgwk */ 57895b52b4dSgwk void 57995b52b4dSgwk mc_reset(struct mc_softc *sc) 58095b52b4dSgwk { 58195b52b4dSgwk mc_stop(sc); 58295b52b4dSgwk mc_init(sc); 58395b52b4dSgwk } 58495b52b4dSgwk 585947a7310Sgwk void 58695b52b4dSgwk mc_init(struct mc_softc *sc) 58795b52b4dSgwk { 588947a7310Sgwk struct ifnet *ifp = &sc->sc_arpcom.ac_if; 58995b52b4dSgwk u_int8_t maccc, ladrf[8]; 590947a7310Sgwk int s, i; 59195b52b4dSgwk 59295b52b4dSgwk s = splnet(); 59395b52b4dSgwk 59495b52b4dSgwk NIC_PUT(sc, MACE_BIUCC, sc->sc_biucc); 59595b52b4dSgwk NIC_PUT(sc, MACE_FIFOCC, sc->sc_fifocc); 59695b52b4dSgwk NIC_PUT(sc, MACE_IMR, ~0); /* disable all interrupts */ 59795b52b4dSgwk NIC_PUT(sc, MACE_PLSCC, sc->sc_plscc); 59895b52b4dSgwk 59995b52b4dSgwk NIC_PUT(sc, MACE_UTR, RTRD); /* disable reserved test registers */ 60095b52b4dSgwk 60195b52b4dSgwk /* set MAC address */ 60295b52b4dSgwk NIC_PUT(sc, MACE_IAC, ADDRCHG); 60395b52b4dSgwk while (NIC_GET(sc, MACE_IAC) & ADDRCHG) 60495b52b4dSgwk ; 60595b52b4dSgwk NIC_PUT(sc, MACE_IAC, PHYADDR); 60695b52b4dSgwk for (i = 0; i < ETHER_ADDR_LEN; i++) 60795b52b4dSgwk out8rb(sc->sc_reg + MACE_REG(MACE_PADR) + i, 60895b52b4dSgwk sc->sc_enaddr[i]); 60995b52b4dSgwk 61095b52b4dSgwk /* set logical address filter */ 611947a7310Sgwk mace_calcladrf(sc, ladrf); 61295b52b4dSgwk 61395b52b4dSgwk NIC_PUT(sc, MACE_IAC, ADDRCHG); 61495b52b4dSgwk while (NIC_GET(sc, MACE_IAC) & ADDRCHG) 61595b52b4dSgwk ; 61695b52b4dSgwk NIC_PUT(sc, MACE_IAC, LOGADDR); 61795b52b4dSgwk for (i = 0; i < 8; i++) 61895b52b4dSgwk out8rb(sc->sc_reg + MACE_REG(MACE_LADRF) + i, 61995b52b4dSgwk ladrf[i]); 62095b52b4dSgwk 62195b52b4dSgwk NIC_PUT(sc, MACE_XMTFC, APADXMT); 62295b52b4dSgwk /* 62395b52b4dSgwk * No need to autostrip padding on receive... Ethernet frames 62495b52b4dSgwk * don't have a length field, unlike 802.3 frames, so the MACE 62595b52b4dSgwk * can't figure out the length of the packet anyways. 62695b52b4dSgwk */ 62795b52b4dSgwk NIC_PUT(sc, MACE_RCVFC, 0); 62895b52b4dSgwk 62995b52b4dSgwk maccc = ENXMT | ENRCV; 630947a7310Sgwk if (ifp->if_flags & IFF_PROMISC) 63195b52b4dSgwk maccc |= PROM; 63295b52b4dSgwk 63395b52b4dSgwk NIC_PUT(sc, MACE_MACCC, maccc); 63495b52b4dSgwk 63595b52b4dSgwk mc_reset_rxdma(sc); 63695b52b4dSgwk mc_reset_txdma(sc); 63795b52b4dSgwk /* 63895b52b4dSgwk * Enable all interrupts except receive, since we use the DMA 63995b52b4dSgwk * completion interrupt for that. 64095b52b4dSgwk */ 64195b52b4dSgwk NIC_PUT(sc, MACE_IMR, RCVINTM); 64295b52b4dSgwk 64395b52b4dSgwk /* flag interface as "running" */ 644947a7310Sgwk ifp->if_flags |= IFF_RUNNING; 645de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd); 64695b52b4dSgwk 64795b52b4dSgwk splx(s); 64895b52b4dSgwk } 64995b52b4dSgwk 65095b52b4dSgwk /* 65195b52b4dSgwk * Close down an interface and free its buffers. 65295b52b4dSgwk * Called on final close of device, or if mcinit() fails 65395b52b4dSgwk * part way through. 65495b52b4dSgwk */ 65595b52b4dSgwk int 65695b52b4dSgwk mc_stop(struct mc_softc *sc) 65795b52b4dSgwk { 658947a7310Sgwk struct ifnet *ifp = &sc->sc_arpcom.ac_if; 659947a7310Sgwk int s; 660947a7310Sgwk 661947a7310Sgwk s = splnet(); 66295b52b4dSgwk 66395b52b4dSgwk NIC_PUT(sc, MACE_BIUCC, SWRST); 66495b52b4dSgwk DELAY(100); 66595b52b4dSgwk 666947a7310Sgwk ifp->if_timer = 0; 667de6cd8fbSdlg ifp->if_flags &= ~IFF_RUNNING; 668de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd); 66995b52b4dSgwk 67095b52b4dSgwk splx(s); 67195b52b4dSgwk return (0); 67295b52b4dSgwk } 67395b52b4dSgwk 67495b52b4dSgwk /* 67595b52b4dSgwk * Called if any Tx packets remain unsent after 5 seconds, 67695b52b4dSgwk * In all cases we just reset the chip, and any retransmission 67795b52b4dSgwk * will be handled by higher level protocol timeouts. 67895b52b4dSgwk */ 67995b52b4dSgwk void 68095b52b4dSgwk mc_watchdog(struct ifnet *ifp) 68195b52b4dSgwk { 68295b52b4dSgwk struct mc_softc *sc = ifp->if_softc; 68395b52b4dSgwk 68495b52b4dSgwk printf("mcwatchdog: resetting chip\n"); 68595b52b4dSgwk mc_reset(sc); 68695b52b4dSgwk } 68795b52b4dSgwk 68895b52b4dSgwk int 68995b52b4dSgwk mc_intr(void *arg) 69095b52b4dSgwk { 69195b52b4dSgwk struct mc_softc *sc = arg; 692415e1820Sgwk struct ifnet *ifp = &sc->sc_arpcom.ac_if; 69395b52b4dSgwk u_int8_t ir; 69495b52b4dSgwk 69595b52b4dSgwk ir = NIC_GET(sc, MACE_IR) & ~NIC_GET(sc, MACE_IMR); 696415e1820Sgwk 69795b52b4dSgwk if (ir & JAB) { 69895b52b4dSgwk #ifdef MCDEBUG 69995b52b4dSgwk printf("%s: jabber error\n", sc->sc_dev.dv_xname); 70095b52b4dSgwk #endif 701415e1820Sgwk ifp->if_oerrors++; 70295b52b4dSgwk } 70395b52b4dSgwk 70495b52b4dSgwk if (ir & BABL) { 70595b52b4dSgwk #ifdef MCDEBUG 70695b52b4dSgwk printf("%s: babble\n", sc->sc_dev.dv_xname); 70795b52b4dSgwk #endif 708415e1820Sgwk ifp->if_oerrors++; 70995b52b4dSgwk } 71095b52b4dSgwk 71195b52b4dSgwk if (ir & CERR) { 71295b52b4dSgwk #ifdef MCDEBUG 71395b52b4dSgwk printf("%s: collision error\n", sc->sc_dev.dv_xname); 71495b52b4dSgwk #endif 715415e1820Sgwk ifp->if_collisions++; 71695b52b4dSgwk } 71795b52b4dSgwk 71895b52b4dSgwk /* 71995b52b4dSgwk * Pretend we have carrier; if we don't this will be cleared 72095b52b4dSgwk * shortly. 72195b52b4dSgwk */ 72295b52b4dSgwk sc->sc_havecarrier = 1; 72395b52b4dSgwk 72495b52b4dSgwk if (ir & XMTINT) 72595b52b4dSgwk mc_tint(sc); 72695b52b4dSgwk 72795b52b4dSgwk if (ir & RCVINT) 72895b52b4dSgwk mc_rint(sc); 72995b52b4dSgwk 73095b52b4dSgwk return(1); 73195b52b4dSgwk } 73295b52b4dSgwk 73395b52b4dSgwk void 73495b52b4dSgwk mc_tint(struct mc_softc *sc) 73595b52b4dSgwk { 736415e1820Sgwk struct ifnet *ifp = &sc->sc_arpcom.ac_if; 73795b52b4dSgwk u_int8_t xmtrc, xmtfs; 73895b52b4dSgwk 73995b52b4dSgwk xmtrc = NIC_GET(sc, MACE_XMTRC); 74095b52b4dSgwk xmtfs = NIC_GET(sc, MACE_XMTFS); 74195b52b4dSgwk 74295b52b4dSgwk if ((xmtfs & XMTSV) == 0) 74395b52b4dSgwk return; 74495b52b4dSgwk 74595b52b4dSgwk if (xmtfs & UFLO) { 74695b52b4dSgwk printf("%s: underflow\n", sc->sc_dev.dv_xname); 74795b52b4dSgwk mc_reset(sc); 74895b52b4dSgwk return; 74995b52b4dSgwk } 75095b52b4dSgwk 75195b52b4dSgwk if (xmtfs & LCOL) { 75295b52b4dSgwk printf("%s: late collision\n", sc->sc_dev.dv_xname); 753415e1820Sgwk ifp->if_oerrors++; 754415e1820Sgwk ifp->if_collisions++; 75595b52b4dSgwk } 75695b52b4dSgwk 75795b52b4dSgwk if (xmtfs & MORE) 75895b52b4dSgwk /* Real number is unknown. */ 759415e1820Sgwk ifp->if_collisions += 2; 76095b52b4dSgwk else if (xmtfs & ONE) 761415e1820Sgwk ifp->if_collisions++; 76295b52b4dSgwk else if (xmtfs & RTRY) { 76395b52b4dSgwk printf("%s: excessive collisions\n", sc->sc_dev.dv_xname); 764415e1820Sgwk ifp->if_collisions += 16; 765415e1820Sgwk ifp->if_oerrors++; 76695b52b4dSgwk } 76795b52b4dSgwk 76895b52b4dSgwk if (xmtfs & LCAR) { 76995b52b4dSgwk sc->sc_havecarrier = 0; 77095b52b4dSgwk printf("%s: lost carrier\n", sc->sc_dev.dv_xname); 771415e1820Sgwk ifp->if_oerrors++; 77295b52b4dSgwk } 77395b52b4dSgwk 774de6cd8fbSdlg ifq_clr_oactive(&ifp->if_snd); 775415e1820Sgwk ifp->if_timer = 0; 776415e1820Sgwk mc_start(ifp); 77795b52b4dSgwk } 77895b52b4dSgwk 77995b52b4dSgwk void 78095b52b4dSgwk mc_rint(struct mc_softc *sc) 78195b52b4dSgwk { 782415e1820Sgwk struct ifnet *ifp = &sc->sc_arpcom.ac_if; 78395b52b4dSgwk #define rxf sc->sc_rxframe 78495b52b4dSgwk u_int len; 78595b52b4dSgwk 78695b52b4dSgwk len = (rxf.rx_rcvcnt | ((rxf.rx_rcvsts & 0xf) << 8)) - 4; 78795b52b4dSgwk 78895b52b4dSgwk #ifdef MCDEBUG 78995b52b4dSgwk if (rxf.rx_rcvsts & 0xf0) 79095b52b4dSgwk printf("%s: rcvcnt %02x rcvsts %02x rntpc 0x%02x rcvcc 0x%02x\n", 79195b52b4dSgwk sc->sc_dev.dv_xname, rxf.rx_rcvcnt, rxf.rx_rcvsts, 79295b52b4dSgwk rxf.rx_rntpc, rxf.rx_rcvcc); 79395b52b4dSgwk #endif 79495b52b4dSgwk 79595b52b4dSgwk if (rxf.rx_rcvsts & OFLO) { 79695b52b4dSgwk #ifdef MCDEBUG 79795b52b4dSgwk printf("%s: receive FIFO overflow\n", sc->sc_dev.dv_xname); 79895b52b4dSgwk #endif 799415e1820Sgwk ifp->if_ierrors++; 80095b52b4dSgwk return; 80195b52b4dSgwk } 80295b52b4dSgwk 80395b52b4dSgwk if (rxf.rx_rcvsts & CLSN) 804415e1820Sgwk ifp->if_collisions++; 80595b52b4dSgwk 80695b52b4dSgwk if (rxf.rx_rcvsts & FRAM) { 80795b52b4dSgwk #ifdef MCDEBUG 80895b52b4dSgwk printf("%s: framing error\n", sc->sc_dev.dv_xname); 80995b52b4dSgwk #endif 810415e1820Sgwk ifp->if_ierrors++; 81195b52b4dSgwk return; 81295b52b4dSgwk } 81395b52b4dSgwk 81495b52b4dSgwk if (rxf.rx_rcvsts & FCS) { 81595b52b4dSgwk #ifdef MCDEBUG 81695b52b4dSgwk printf("%s: frame control checksum error\n", sc->sc_dev.dv_xname); 81795b52b4dSgwk #endif 818415e1820Sgwk ifp->if_ierrors++; 81995b52b4dSgwk return; 82095b52b4dSgwk } 82195b52b4dSgwk 82295b52b4dSgwk mace_read(sc, rxf.rx_frame, len); 82395b52b4dSgwk #undef rxf 82495b52b4dSgwk } 82595b52b4dSgwk /* 82695b52b4dSgwk * stuff packet into MACE (at splnet) 82795b52b4dSgwk */ 82895b52b4dSgwk u_int 82995b52b4dSgwk maceput(struct mc_softc *sc, struct mbuf *m) 83095b52b4dSgwk { 831415e1820Sgwk struct ifnet *ifp = &sc->sc_arpcom.ac_if; 83295b52b4dSgwk struct mbuf *n; 83395b52b4dSgwk u_int len, totlen = 0; 83495b52b4dSgwk u_char *buff; 83595b52b4dSgwk 83695b52b4dSgwk buff = sc->sc_txbuf; 83795b52b4dSgwk 83895b52b4dSgwk for (; m; m = n) { 83995b52b4dSgwk u_char *data = mtod(m, u_char *); 84095b52b4dSgwk len = m->m_len; 84195b52b4dSgwk totlen += len; 84295b52b4dSgwk bcopy(data, buff, len); 84395b52b4dSgwk buff += len; 844822e8206Smpi n = m_free(m); 84595b52b4dSgwk } 84695b52b4dSgwk 84795b52b4dSgwk if (totlen > PAGE_SIZE) 84895b52b4dSgwk panic("%s: maceput: packet overflow", sc->sc_dev.dv_xname); 84995b52b4dSgwk 85095b52b4dSgwk #if 0 85195b52b4dSgwk if (totlen < ETHERMIN + sizeof(struct ether_header)) { 85295b52b4dSgwk int pad = ETHERMIN + sizeof(struct ether_header) - totlen; 85395b52b4dSgwk bzero(sc->sc_txbuf + totlen, pad); 85495b52b4dSgwk totlen = ETHERMIN + sizeof(struct ether_header); 85595b52b4dSgwk } 85695b52b4dSgwk #endif 85795b52b4dSgwk 85895b52b4dSgwk 85995b52b4dSgwk /* 5 seconds to watch for failing to transmit */ 860415e1820Sgwk ifp->if_timer = 5; 86195b52b4dSgwk mc_putpacket(sc, totlen); 86295b52b4dSgwk return (totlen); 86395b52b4dSgwk } 86495b52b4dSgwk 86595b52b4dSgwk void 86695b52b4dSgwk mace_read(struct mc_softc *sc, caddr_t pkt, int len) 86795b52b4dSgwk { 86895b52b4dSgwk struct ifnet *ifp = &sc->sc_arpcom.ac_if; 86986666264Sdlg struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 87095b52b4dSgwk struct mbuf *m; 87195b52b4dSgwk 87295b52b4dSgwk if (len <= sizeof(struct ether_header) || 87395b52b4dSgwk len > ETHERMTU + sizeof(struct ether_header)) { 87495b52b4dSgwk #ifdef MCDEBUG 87595b52b4dSgwk printf("%s: invalid packet size %d; dropping\n", 87695b52b4dSgwk sc->sc_dev.dv_xname, len); 87795b52b4dSgwk #endif 87895b52b4dSgwk ifp->if_ierrors++; 87995b52b4dSgwk return; 88095b52b4dSgwk } 88195b52b4dSgwk 88295b52b4dSgwk m = mace_get(sc, pkt, len); 88395b52b4dSgwk if (m == NULL) { 88495b52b4dSgwk ifp->if_ierrors++; 88595b52b4dSgwk return; 88695b52b4dSgwk } 88795b52b4dSgwk 88886666264Sdlg ml_enqueue(&ml, m); 88986666264Sdlg if_input(ifp, &ml); 89095b52b4dSgwk } 89195b52b4dSgwk 89295b52b4dSgwk /* 89395b52b4dSgwk * Pull data off an interface. 89495b52b4dSgwk * Len is length of data, with local net header stripped. 89595b52b4dSgwk * We copy the data into mbufs. When full cluster sized units are present 89695b52b4dSgwk * we copy into clusters. 89795b52b4dSgwk */ 89895b52b4dSgwk struct mbuf * 89995b52b4dSgwk mace_get(struct mc_softc *sc, caddr_t pkt, int totlen) 90095b52b4dSgwk { 90195b52b4dSgwk struct mbuf *m; 90295b52b4dSgwk struct mbuf *top, **mp; 90395b52b4dSgwk int len; 90495b52b4dSgwk 90595b52b4dSgwk MGETHDR(m, M_DONTWAIT, MT_DATA); 9069e3a439eSgwk if (m == NULL) 9079e3a439eSgwk return (NULL); 9089e3a439eSgwk 90995b52b4dSgwk m->m_pkthdr.len = totlen; 91095b52b4dSgwk len = MHLEN; 91195b52b4dSgwk top = 0; 91295b52b4dSgwk mp = ⊤ 91395b52b4dSgwk 91495b52b4dSgwk while (totlen > 0) { 91595b52b4dSgwk if (top) { 91695b52b4dSgwk MGET(m, M_DONTWAIT, MT_DATA); 9179e3a439eSgwk if (m == NULL) { 91895b52b4dSgwk m_freem(top); 9199e3a439eSgwk return (NULL); 92095b52b4dSgwk } 92195b52b4dSgwk len = MLEN; 92295b52b4dSgwk } 92395b52b4dSgwk if (totlen >= MINCLSIZE) { 92495b52b4dSgwk MCLGET(m, M_DONTWAIT); 92595b52b4dSgwk if ((m->m_flags & M_EXT) == 0) { 92695b52b4dSgwk m_free(m); 92795b52b4dSgwk m_freem(top); 9289e3a439eSgwk return (NULL); 92995b52b4dSgwk } 93095b52b4dSgwk len = MCLBYTES; 93195b52b4dSgwk } 93295b52b4dSgwk m->m_len = len = min(totlen, len); 93395b52b4dSgwk bcopy(pkt, mtod(m, caddr_t), len); 93495b52b4dSgwk pkt += len; 93595b52b4dSgwk totlen -= len; 93695b52b4dSgwk *mp = m; 93795b52b4dSgwk mp = &m->m_next; 93895b52b4dSgwk } 93995b52b4dSgwk 94095b52b4dSgwk return (top); 94195b52b4dSgwk } 94295b52b4dSgwk 94395b52b4dSgwk void 94495b52b4dSgwk mc_putpacket(struct mc_softc *sc, u_int len) 94595b52b4dSgwk { 94695b52b4dSgwk dbdma_command_t *cmd = sc->sc_txdmacmd; 94795b52b4dSgwk 94895b52b4dSgwk DBDMA_BUILD(cmd, DBDMA_CMD_OUT_LAST, 0, len, sc->sc_txbuf_pa, 94995b52b4dSgwk DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 95095b52b4dSgwk cmd++; 951947a7310Sgwk DBDMA_BUILD(cmd, DBDMA_CMD_STOP, 0, 0, 0, DBDMA_INT_ALWAYS, 952947a7310Sgwk DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 95395b52b4dSgwk 95495b52b4dSgwk dbdma_start(sc->sc_txdma, sc->sc_txdbdma); 95595b52b4dSgwk } 95695b52b4dSgwk 95795b52b4dSgwk /* 95895b52b4dSgwk * Interrupt handler for the MACE DMA completion interrupts 95995b52b4dSgwk */ 96095b52b4dSgwk int 96195b52b4dSgwk mc_dmaintr(void *arg) 96295b52b4dSgwk { 96395b52b4dSgwk struct mc_softc *sc = arg; 96495b52b4dSgwk int status, offset, statoff; 96595b52b4dSgwk int datalen, resid; 96695b52b4dSgwk int i, n, count; 96795b52b4dSgwk dbdma_command_t *cmd; 96895b52b4dSgwk 96995b52b4dSgwk /* We've received some packets from the MACE */ 97095b52b4dSgwk /* Loop through, processing each of the packets */ 97195b52b4dSgwk i = sc->sc_tail; 97295b52b4dSgwk for (n = 0; n < MC_RXDMABUFS; n++, i++) { 97395b52b4dSgwk if (i == MC_RXDMABUFS) 97495b52b4dSgwk i = 0; 97595b52b4dSgwk 97695b52b4dSgwk cmd = &sc->sc_rxdmacmd[i]; 97795b52b4dSgwk status = dbdma_ld16(&cmd->d_status); 97895b52b4dSgwk resid = dbdma_ld16(&cmd->d_resid); 97995b52b4dSgwk 98095b52b4dSgwk if ((status & DBDMA_CNTRL_ACTIVE) == 0) { 98195b52b4dSgwk continue; 98295b52b4dSgwk } 98395b52b4dSgwk 98495b52b4dSgwk count = dbdma_ld16(&cmd->d_count); 98595b52b4dSgwk datalen = count - resid; 98695b52b4dSgwk datalen -= 4; /* 4 == status bytes */ 98795b52b4dSgwk 98895b52b4dSgwk if (datalen < 4 + sizeof(struct ether_header)) { 98995b52b4dSgwk printf("short packet len=%d\n", datalen); 99095b52b4dSgwk /* continue; */ 99195b52b4dSgwk goto next; 99295b52b4dSgwk } 99395b52b4dSgwk DBDMA_BUILD_CMD(cmd, DBDMA_CMD_STOP, 0, 0, 0, 0); 99495b52b4dSgwk 99595b52b4dSgwk offset = i * MACE_BUFLEN; 99695b52b4dSgwk statoff = offset + datalen; 99795b52b4dSgwk sc->sc_rxframe.rx_rcvcnt = sc->sc_rxbuf[statoff + 0]; 99895b52b4dSgwk sc->sc_rxframe.rx_rcvsts = sc->sc_rxbuf[statoff + 1]; 99995b52b4dSgwk sc->sc_rxframe.rx_rntpc = sc->sc_rxbuf[statoff + 2]; 100095b52b4dSgwk sc->sc_rxframe.rx_rcvcc = sc->sc_rxbuf[statoff + 3]; 100195b52b4dSgwk sc->sc_rxframe.rx_frame = sc->sc_rxbuf + offset; 100295b52b4dSgwk 100395b52b4dSgwk mc_rint(sc); 100495b52b4dSgwk 100595b52b4dSgwk next: 100695b52b4dSgwk DBDMA_BUILD_CMD(cmd, DBDMA_CMD_IN_LAST, 0, DBDMA_INT_ALWAYS, 100795b52b4dSgwk DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 1008e67a46f3Sgwk 100995b52b4dSgwk cmd->d_status = 0; 101095b52b4dSgwk cmd->d_resid = 0; 101195b52b4dSgwk sc->sc_tail = i + 1; 101295b52b4dSgwk } 101395b52b4dSgwk 101495b52b4dSgwk dbdma_continue(sc->sc_rxdma); 101595b52b4dSgwk 101695b52b4dSgwk return 1; 101795b52b4dSgwk } 101895b52b4dSgwk 101995b52b4dSgwk void 102095b52b4dSgwk mc_reset_rxdma(struct mc_softc *sc) 102195b52b4dSgwk { 102295b52b4dSgwk dbdma_command_t *cmd = sc->sc_rxdmacmd; 102395b52b4dSgwk int i; 102495b52b4dSgwk u_int8_t maccc; 102595b52b4dSgwk 102695b52b4dSgwk /* Disable receiver, reset the DMA channels */ 102795b52b4dSgwk maccc = NIC_GET(sc, MACE_MACCC); 102895b52b4dSgwk NIC_PUT(sc, MACE_MACCC, maccc & ~ENRCV); 102995b52b4dSgwk 103095b52b4dSgwk dbdma_reset(sc->sc_rxdma); 103195b52b4dSgwk 103295b52b4dSgwk bzero(sc->sc_rxdmacmd, 8 * sizeof(dbdma_command_t)); 103395b52b4dSgwk for (i = 0; i < MC_RXDMABUFS; i++) { 103495b52b4dSgwk DBDMA_BUILD(cmd, DBDMA_CMD_IN_LAST, 0, MACE_BUFLEN, 103595b52b4dSgwk sc->sc_rxbuf_pa + MACE_BUFLEN * i, DBDMA_INT_ALWAYS, 103695b52b4dSgwk DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 103795b52b4dSgwk cmd++; 103895b52b4dSgwk } 103995b52b4dSgwk 104095b52b4dSgwk DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0, 104195b52b4dSgwk DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS); 104295b52b4dSgwk dbdma_st32(&cmd->d_cmddep, sc->sc_rxdbdma->d_paddr); 104395b52b4dSgwk cmd++; 104495b52b4dSgwk 104595b52b4dSgwk sc->sc_tail = 0; 104695b52b4dSgwk 104795b52b4dSgwk dbdma_start(sc->sc_rxdma, sc->sc_rxdbdma); 104895b52b4dSgwk /* Reenable receiver, reenable DMA */ 104995b52b4dSgwk NIC_PUT(sc, MACE_MACCC, maccc); 105095b52b4dSgwk } 105195b52b4dSgwk 105295b52b4dSgwk void 105395b52b4dSgwk mc_reset_txdma(struct mc_softc *sc) 105495b52b4dSgwk { 105595b52b4dSgwk dbdma_command_t *cmd = sc->sc_txdmacmd; 105695b52b4dSgwk dbdma_regmap_t *dmareg = sc->sc_txdma; 105795b52b4dSgwk u_int8_t maccc; 105895b52b4dSgwk 105995b52b4dSgwk /* disable transmitter */ 106095b52b4dSgwk maccc = NIC_GET(sc, MACE_MACCC); 106195b52b4dSgwk NIC_PUT(sc, MACE_MACCC, maccc & ~ENXMT); 106295b52b4dSgwk 106395b52b4dSgwk dbdma_reset(sc->sc_txdma); 106495b52b4dSgwk 106595b52b4dSgwk bzero(sc->sc_txdmacmd, 2 * sizeof(dbdma_command_t)); 106695b52b4dSgwk DBDMA_BUILD(cmd, DBDMA_CMD_OUT_LAST, 0, 0, sc->sc_txbuf_pa, 106795b52b4dSgwk DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 106895b52b4dSgwk cmd++; 106995b52b4dSgwk DBDMA_BUILD(cmd, DBDMA_CMD_STOP, 0, 0, 0, 107095b52b4dSgwk DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 107195b52b4dSgwk 107295b52b4dSgwk out32rb(&dmareg->d_cmdptrhi, 0); 107395b52b4dSgwk out32rb(&dmareg->d_cmdptrlo, sc->sc_txdbdma->d_paddr); 107495b52b4dSgwk 107595b52b4dSgwk /* restore old value */ 107695b52b4dSgwk NIC_PUT(sc, MACE_MACCC, maccc); 107795b52b4dSgwk } 107895b52b4dSgwk 107995b52b4dSgwk /* 108095b52b4dSgwk * Go through the list of multicast addresses and calculate the logical 108195b52b4dSgwk * address filter. 108295b52b4dSgwk */ 108395b52b4dSgwk void 1084947a7310Sgwk mace_calcladrf(struct mc_softc *sc, u_int8_t *af) 108595b52b4dSgwk { 108695b52b4dSgwk struct ether_multi *enm; 108795b52b4dSgwk u_int32_t crc; 1088947a7310Sgwk struct ifnet *ifp = &sc->sc_arpcom.ac_if; 1089947a7310Sgwk struct arpcom *ac = &sc->sc_arpcom; 109095b52b4dSgwk struct ether_multistep step; 109195b52b4dSgwk /* 109295b52b4dSgwk * Set up multicast address filter by passing all multicast addresses 109395b52b4dSgwk * through a crc generator, and then using the high order 6 bits as an 109495b52b4dSgwk * index into the 64 bit logical address filter. The high order bit 109595b52b4dSgwk * selects the word, while the rest of the bits select the bit within 109695b52b4dSgwk * the word. 109795b52b4dSgwk */ 109895b52b4dSgwk 1099ef787866Smpi if (ac->ac_multirangecnt > 0) 1100ef787866Smpi goto allmulti; 1101ef787866Smpi 110295b52b4dSgwk *((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0; 110395b52b4dSgwk ETHER_FIRST_MULTI(step, ac, enm); 110495b52b4dSgwk while (enm != NULL) { 110595b52b4dSgwk crc = ether_crc32_le(enm->enm_addrlo, sizeof(enm->enm_addrlo)); 110695b52b4dSgwk 110795b52b4dSgwk /* Just want the 6 most significant bits. */ 110895b52b4dSgwk crc >>= 26; 110995b52b4dSgwk 111095b52b4dSgwk /* Set the corresponding bit in the filter. */ 111195b52b4dSgwk af[crc >> 3] |= 1 << (crc & 7); 111295b52b4dSgwk 111395b52b4dSgwk ETHER_NEXT_MULTI(step, enm); 111495b52b4dSgwk } 111595b52b4dSgwk ifp->if_flags &= ~IFF_ALLMULTI; 111695b52b4dSgwk return; 111795b52b4dSgwk 111895b52b4dSgwk allmulti: 111995b52b4dSgwk ifp->if_flags |= IFF_ALLMULTI; 112095b52b4dSgwk *((u_int32_t *)af) = *((u_int32_t *)af + 1) = 0xffffffff; 112195b52b4dSgwk } 1122