Date: Wed, 19 Nov 1997 16:58:25 +0600 (NS) From: Semen.Ustimenko@iclub.nsu.ru To: FreeBSD-gnats-submit@FreeBSD.ORG Subject: kern/5090: Driver for SMC9432TX Fast Ethernet Board Message-ID: <199711191058.QAA08722@iclub.nsu.ru> Resent-Message-ID: <199711191530.HAA22451@hub.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 5090 >Category: kern >Synopsis: Driver for SMC9432TX Fast Ethernet Board >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Class: support >Submitter-Id: current-users >Arrival-Date: Wed Nov 19 07:30:04 PST 1997 >Last-Modified: >Originator: Ustimeko Semen >Organization: none >Release: FreeBSD 2.2.2-RELEASE i386 >Environment: >Description: There is no driver for SMC9432TX Fast Ethernet board. >How-To-Repeat: >Fix: For now driver does not support many useful things, but it works. Following shar archive contains to files, that must be placed in ./pci subdirectory of kernel source tree. The string: pci/if_tx.c optional tx device-driver should be added to ./conf/files file and option 'device tx0' to kernel config file. # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # smc83c170.h # if_tx.c # echo x - smc83c170.h sed 's/^X//' >smc83c170.h << 'END-of-smc83c170.h' X/*- X * Copyright (c) 1997 Semen Ustimenko X * All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X * SUCH DAMAGE. X * X */ X X/* X * smc83c170.h X */ X X/* X * Configuration X */ X#define EPIC_MAX_DEVICES 4 X/*#define RX_TO_MBUF 1*/ X/*#define FAKE_TIMEOUT 1*/ X#define TX_RING_SIZE 128 X#define RX_RING_SIZE 32 X X/* Shall be moved to ../net/if_mib.h */ X#define dot3VendorSMC 8 X#define dot3ChipSetSMC83c170 1 X X/* PCI identification */ X#define SMC_VENDORID 0x10B8 X#define CHIPID_83C170 0x0005 X#define PCI_VENDORID(x) ((x) & 0xFFFF) X#define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF) X X/* PCI configuration */ X#define PCI_CFID 0x00 /* Configuration ID */ X#define PCI_CFCS 0x04 /* Configurtion Command/Status */ X#define PCI_CFRV 0x08 /* Configuration Revision */ X#define PCI_CFLT 0x0c /* Configuration Latency Timer */ X#define PCI_CBIO 0x10 /* Configuration Base IO Address */ X#define PCI_CBMA 0x14 /* Configuration Base Memory Address */ X#define PCI_CFIT 0x3c /* Configuration Interrupt */ X#define PCI_CFDA 0x40 /* Configuration Driver Area */ X X#define PCI_CONF_WRITE(r, v) pci_conf_write(config_id, (r), (v)) X#define PCI_CONF_READ(r) pci_conf_read(config_id, (r)) X X/* EPIC's registers ( from Donald Becker ) */ X#define COMMAND 0x0000 X#define INTSTAT 0x0004 /* Interrupt status. See below */ X#define INTMASK 0x0008 /* Interrupt mask. See below */ X#define GENCTL 0x000C X#define NVCTL 0x0010 X#define EECTL 0x0014 /* EEPROM control **/ X#define TEST1 0x001C /* XXXXX */ X#define CRCCNT 0x0020 /* CRC error counter */ X#define ALICNT 0x0024 /* FrameTooLang error counter */ X#define MPCNT 0x0028 /* MissedFrames error counters */ X#define MIICtrl 0x0030 X#define MIIData 0x0034 X#define MIICfg 0x0038 X#define LAN0 0x0040 /* MAC address */ X#define MC0 0x0050 /* Multicast filter table */ X#define RxCtrl 0x0060 X#define TxCtrl 0x0070 X#define TxSTAT 0x0074 X#define PRxCDAR 0x0084 /* RxRing bus address */ X#define RxSTAT 0x00A4 X#define EarlyRx 0x00B0 X#define PTxCDAR 0x00C4 /* TxRing bus address */ X#define TxThresh 0x00DC X X/* Tx threshold */ X#define TX_FIFO_THRESH 0x40 /* 0x40 or 0x10 */ X X/* Interrupt register bits ( from Donald Becker ) */ X#define TxIdle 0x40000 X#define RxIdle 0x20000 X#define CntFull 0x0200 X#define TxUnderrun 0x0100 X#define TxEmpty 0x0080 X#define TxDone 0x0020 X#define RxError 0x0010 X#define RxOverflow 0x0008 X#define RxFull 0x0004 X#define RxHeader 0x0002 X#define RxDone 0x0001 X X/* X * Structures definition and Functions prototypes X */ X X/* EPIC's descriptors ( from Donald Becker ) */ Xstruct epic_tx_desc { X u_int16_t status; X u_int16_t txlength; X u_int32_t bufaddr; X u_int16_t buflength; X u_int16_t control; X u_int32_t next; X}; Xstruct epic_rx_desc { X u_int16_t status; X u_int16_t rxlength; X u_int32_t bufaddr; X u_int32_t buflength; X u_int32_t next; X}; X Xstruct epic_rx_buffer { X struct epic_rx_desc desc; /* EPIC's descriptor */ X caddr_t data; /* Rx buffer address */ X#if !defined(RX_TO_MBUF) X caddr_t pool; /* Pool, allocated for buffer */ X#else X struct mbuf * mbuf; /* Or mbuf structure */ X#endif X}; X Xstruct epic_tx_buffer { X struct epic_tx_desc desc; /* EPIC's descriptor */ X caddr_t data; /* Tx buffer address */ X caddr_t pool; /* Pool, allocated for buffer */ X}; X Xtypedef struct { X int unit; X struct arpcom epic_ac; X struct epic_rx_buffer rx_buffer[RX_RING_SIZE]; X struct epic_tx_buffer tx_buffer[TX_RING_SIZE]; X u_int32_t cur_tx; X u_int32_t cur_rx; X u_int32_t pending_txs; X u_int32_t iobase; X u_int32_t irq; X struct ifmib_iso_8802_3 dot3stats; X} epic_softc_t; X X#define epic_if epic_ac.ac_if X#define epic_macaddr epic_ac.ac_enaddr X X//extern epic_softc_t *epics[]; X//extern u_long epic_pci_count; X Xstatic void epic_intr_normal(void *); Xstatic void epic_rx_done(epic_softc_t *); Xstatic void epic_tx_done(epic_softc_t *); Xstatic void epic_ifstart(struct ifnet *); Xstatic void epic_ifwatchdog(struct ifnet *); X Xstatic char* epic_pci_probe(pcici_t, pcidi_t); Xstatic void epic_pci_attach(pcici_t, int); Xstatic void epic_init(epic_softc_t * const); X Xstatic void epic_init_rings(epic_softc_t *); X Xstatic int epic_read_eeprom(u_int16_t,u_int16_t); Xstatic void epic_output_eepromw(u_int16_t, u_int16_t); Xstatic u_int16_t epic_input_eepromw(u_int16_t); Xstatic u_int8_t epic_eeprom_clock(u_int16_t,u_int8_t); Xstatic void epic_write_eepromreg(u_int16_t,u_int8_t); Xstatic u_int8_t epic_read_eepromreg(u_int16_t); END-of-smc83c170.h echo x - if_tx.c sed 's/^X//' >if_tx.c << 'END-of-if_tx.c' X/*- X * Copyright (c) 1997 Semen Ustimenko (semen@iclub.nsu.ru) X * All rights reserved. X * X * Redistribution and use in source and binary forms, with or without X * modification, are permitted provided that the following conditions X * are met: X * 1. Redistributions of source code must retain the above copyright X * notice, this list of conditions and the following disclaimer. X * 2. Redistributions in binary form must reproduce the above copyright X * notice, this list of conditions and the following disclaimer in the X * documentation and/or other materials provided with the distribution. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE X * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF X * SUCH DAMAGE. X * X */ X X/* X * SMC9432TX Fast Ethernet (tx0) X * X * Written by Semen Ustimenko. As i have no description on SMC9432 board, X * Linux driver by Donald Becker was used as reference. X */ X#include <sys/param.h> X#include <sys/systm.h> X#include <sys/mbuf.h> X#include <sys/protosw.h> X#include <sys/socket.h> X#include <sys/ioctl.h> X#include <sys/errno.h> X#include <sys/malloc.h> X#include <sys/kernel.h> X#include <machine/clock.h> X#include <net/if.h> X#include <net/if_dl.h> X#include <net/if_mib.h> X#include <net/if_types.h> X#include <net/route.h> X#include <net/netisr.h> X#include <netinet/in.h> X#include <netinet/in_systm.h> X#include <netinet/in_var.h> X#include <netinet/ip.h> X#include <netinet/if_ether.h> X#include <vm/vm.h> X#include <vm/vm_param.h> X#include <vm/vm_kern.h> X#include <vm/pmap.h> X X#include "pci.h" X#if NPCI > 0 X#include <pci/pcivar.h> X#include <pci/smc83c170.h> X#endif X X/* X * Global variables X */ Xstatic u_long epic_pci_count; Xstatic epic_softc_t * epics[EPIC_MAX_DEVICES]; Xstruct pci_device txdevice = { "tx", epic_pci_probe, epic_pci_attach, &epic_pci_count, NULL }; X X/* X * Append this driver to pci drivers list X */ XDATA_SET ( pcidevice_set, txdevice ); X X/* X * IFSTART function X */ Xstatic void Xepic_ifstart(struct ifnet * const ifp){ X epic_softc_t *sc = ifp->if_softc; X X while( sc->pending_txs < TX_RING_SIZE ){ X int entry = sc->cur_tx % TX_RING_SIZE; X struct epic_tx_buffer * buf = sc->tx_buffer + entry; X struct mbuf *m,*m0; X int len; X X if( buf->desc.status ) { X int i; X /* Find free descriptor */ X for(i=0;i<TX_RING_SIZE;i++){ X if( sc->tx_buffer[i].desc.status == 0 ){ X sc->cur_tx = entry = i; X buf = sc->tx_buffer + entry; X break; X } X } X if( i >= TX_RING_SIZE ) break; /* no free descriptors */ X } X X IF_DEQUEUE( &(sc->epic_if.if_snd), m ); X X if( NULL == m ) return; X X m0 = m; X X for (len = 0; m != 0; m = m->m_next) { X bcopy(mtod(m, caddr_t), buf->data + len, m->m_len); X len += m->m_len; X } X X buf->desc.txlength = max(len,ETHER_MIN_LEN-ETHER_CRC_LEN); X buf->desc.control = 0x14; /* Interrupt when done */ X buf->desc.status = 0x8000; /* Pass ownership to the chip */ X X /* Trigger an immediate transmit demand. */ X outl(sc->iobase + COMMAND, 0x0004); X X /* Set watchdog timer */ X ifp->if_timer = 2; X X m_freem( m0 ); X X sc->cur_tx = ( sc->cur_tx + 1 ) % TX_RING_SIZE; X sc->pending_txs++; X#if defined(FAKE_TIMEOUT) X if( (ifp->if_opackets % 10000) == 0 ) sc->pending_txs++; X#endif X } X X /* X * TxRing overflowed X */ X sc->epic_if.if_flags |= IFF_OACTIVE; X X return; X X} X X/* X * IFWATCHDOG function X */ Xstatic void Xepic_ifwatchdog( X struct ifnet *ifp) X{ X epic_softc_t *sc = ifp->if_softc; X X printf("tx%d: device timeout %d packets\n",sc->unit,sc->pending_txs); X ifp->if_oerrors+=sc->pending_txs; X X epic_init( sc ); X} X X/* X * Interrupt function X */ Xstatic void Xepic_intr_normal( X void *arg) X{ X epic_softc_t * sc = (epic_softc_t *) arg; X int iobase = sc->iobase; X int status; X int i; X X status = inl(iobase + INTSTAT); X X /* Acknowledge all of the current interrupt sources ASAP. */ X outl( iobase + INTSTAT, status & 0x00007fff); X X /* X * UPDATE statistics X */ X if (status & (CntFull | TxUnderrun | RxOverflow | RxError)) { X /* X * update dot3 Rx statistics X */ X sc->dot3stats.dot3StatsMissedFrames += inb(iobase + MPCNT); X sc->dot3stats.dot3StatsFrameTooLongs += inb(iobase + ALICNT); X sc->dot3stats.dot3StatsFCSErrors += inb(iobase + CRCCNT); X X /* X * update if Rx statistics X */ X if (status & (RxOverflow | RxError)) X sc->epic_if.if_ierrors++; X X /* Tx FIFO underflow. */ X if (status & TxUnderrun) { X sc->dot3stats.dot3StatsInternalMacTransmitErrors++; X sc->epic_if.if_oerrors++; X outl(iobase + COMMAND, 0x0080);/* Restart the transmit process. */ X } X X /* Clear all error sources. */ X outl(iobase + INTSTAT, status & 0x7f18); X } X X if( status & RxDone ) X epic_rx_done( sc ); X X if( status & TxDone ) X epic_tx_done( sc ); X X /* If no packets are pending, thus no timeouts */ X if( sc->pending_txs == 0 ) sc->epic_if.if_timer = 0; X X /* We should clear all interrupt sources. */ X outl(iobase + INTSTAT, 0x0001ffff ); X X return; X} X Xvoid Xepic_rx_done( epic_softc_t *sc ){ X int i = 0; X u_int16_t len; X struct epic_rx_buffer * buf; X struct mbuf *m; X struct ether_header *eh; X X while( !(sc->rx_buffer[sc->cur_rx].desc.status & 0x8000) && i++ < RX_RING_SIZE ){ X X buf = sc->rx_buffer + sc->cur_rx; X X if( buf->desc.status & 0x2006 ){ X sc->epic_if.if_ierrors++; X goto rxerror; X } X X len = buf->desc.rxlength - ETHER_CRC_LEN; X X#if !defined(RX_TO_MBUF) X /* X * Copy data to new allocated mbuf X */ X MGETHDR(m, M_DONTWAIT, MT_DATA); X if( NULL == m ) goto rxerror; X if( (len+2) > MHLEN ){ X MCLGET(m,M_DONTWAIT); X if( NULL == (m->m_flags & M_EXT) ){ X m_freem( m ); X goto rxerror; X } X } X m->m_data += 2; X X memcpy( mtod(m,void*), buf->data, len ); X#else X m = buf->mbuf; X X buf->mbuf = NULL; X X MGETHDR(buf->mbuf,M_DONTWAIT,MT_DATA); X if( NULL == buf->mbuf ) X panic("tx: low mbufs"); X MCLGET(buf->mbuf,M_DONTWAIT); X if( NULL == buf->mbuf ) X panic("tx: low mbufs"); X X buf->data = mtod( buf->mbuf, caddr_t ); X buf->desc.bufaddr = vtophys( buf->data ); X buf->desc.status = 0x8000; X#endif X X /* X * First mbuf in packet holds the X * ethernet and packet headers X */ X eh = mtod( m, struct ether_header * ); X m->m_pkthdr.rcvif = &(sc->epic_if); X m->m_pkthdr.len = m->m_len = len - sizeof(struct ether_header); X m->m_data += sizeof( struct ether_header ); X X ether_input(&sc->epic_if, eh, m); X X sc->epic_if.if_ipackets++; X Xrxerror: X /* X * Mark descriptor as free X */ X buf->desc.rxlength = 0; X buf->desc.status = 0x8000; X X sc->cur_rx = (sc->cur_rx+1) % RX_RING_SIZE; X } X X outl( sc->iobase + INTSTAT, RxDone ); X} X Xvoid Xepic_tx_done( epic_softc_t *sc ){ X int i = 0; X u_int32_t if_flags=0; X int coll; X u_int16_t stt; X X for(i=0; i<TX_RING_SIZE; i++){ X struct epic_tx_buffer *buf = sc->tx_buffer + i; X u_int16_t len = buf->desc.txlength; X stt = buf->desc.status; X X if( stt & 0x8000 ) continue; /* being Txed */ X X if( stt == 0 ){ /* free */ X if_flags = ~IFF_OACTIVE; X continue; X } X X if( stt & 0x0001 ){ X sc->pending_txs--; X sc->epic_if.if_opackets++; X } X X coll = (stt >> 8) & 0xF; /* number of collisions*/ X X if( stt & 0x1058 ){ X if(stt & 0x0008) X sc->dot3stats.dot3StatsCarrierSenseErrors++; X X if(stt & 0x1050) X sc->dot3stats.dot3StatsInternalMacTransmitErrors++; X X if(stt & 0x1000) coll = 16; X X sc->epic_if.if_oerrors++; X } X X if ( (stt & 0x0002) != 0) sc->dot3stats.dot3StatsDeferredTransmissions++; X X sc->epic_if.if_collisions += coll; X X switch( coll ){ X case 0: X break; X case 16: X sc->dot3stats.dot3StatsExcessiveCollisions++; X sc->dot3stats.dot3StatsCollFrequencies[15]++; X break; X case 1: X sc->dot3stats.dot3StatsSingleCollisionFrames++; X sc->dot3stats.dot3StatsCollFrequencies[0]++; X break; X default: X sc->dot3stats.dot3StatsMultipleCollisionFrames++; X sc->dot3stats.dot3StatsCollFrequencies[coll-1]++; X break; X } X X buf->desc.status = 0; X buf->desc.txlength = 0; X X if_flags = ~IFF_OACTIVE; X X } X X sc->epic_if.if_flags &= if_flags; X X outl( sc->iobase + INTSTAT, TxDone ); X X} X X/* X * Probe function X */ Xstatic char* Xepic_pci_probe( X pcici_t config_id, X pcidi_t device_id) X{ X if (PCI_VENDORID(device_id) != SMC_VENDORID) X return NULL; X X if (PCI_CHIPID(device_id) == CHIPID_83C170) X return "SMC 83c170"; X X return NULL; X} X X/* X * PCI_Attach function X */ Xstatic void Xepic_pci_attach( X pcici_t config_id, X int unit) X{ X struct ifnet * ifp; X epic_softc_t *sc; X u_int32_t iobase; X u_int32_t irq; X int i; X int s; X int phy, phy_idx; X X /* X * Get iobase and irq level X */ X irq = PCI_CONF_READ(PCI_CFIT) & (0xFF); X if (!pci_map_port(config_id, PCI_CBIO,(u_short *) &iobase)) X return; X X /* X * Allocate and preinitialize softc structure X */ X sc = (epic_softc_t *) malloc(sizeof(epic_softc_t), M_DEVBUF, M_NOWAIT); X if (sc == NULL) return; X epics[ unit ] = sc; X X /* X * Zero softc structure X */ X bzero(sc, sizeof(epic_softc_t)); X X /* X * Initialize softc X */ X sc->unit = unit; X sc->iobase = iobase; X sc->irq = irq; X X /* Bring the chip out of low-power mode. */ X outl( iobase + GENCTL, 0x0200); X X /* Magic?! If we don't set this bit the MII interface won't work. */ X outl( iobase + TEST1, 0x0008 ); X X /* This could also be read from the EEPROM. */ X for (i = 0; i < ETHER_ADDR_LEN / sizeof( u_int16_t); i++) X ((u_int16_t *)sc->epic_macaddr)[i] = inw(iobase + LAN0 + i*4); X X printf("tx%d:",sc->unit); X printf(" address %02x:%02x:%02x:%02x:%02x:%02x,",sc->epic_macaddr[0],sc->epic_macaddr[1],sc->epic_macaddr[2],sc->epic_macaddr[3],sc->epic_macaddr[4],sc->epic_macaddr[5]); X printf(" SMC9432TX Fast Ethernet\n"); X X /* X * Dump EEPROM X */ X #if defined(DUMP_EEPROM) X printf("tx%d: EEPROM contents\n", sc->unit); X for (i = 0; i < 64; i++) X printf(" %04x%s", epic_read_eeprom(iobase, i), i % 16 == 15 ? "\n" : ""); X #endif X X /* X * Map interrupt X */ X if (!pci_map_int(config_id, epic_intr_normal, (void*) sc, &net_imask)) { X printf("tx%d: couldn't map interrupt\n",unit); X return; X } X X /* X * Fill ifnet structure X */ X s = splimp(); X X ifp = &sc->epic_if; X X ifp->if_unit = unit; X ifp->if_name = "tx"; X ifp->if_softc = sc; X ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST; X ifp->if_ioctl = (void *)ether_ioctl; X ifp->if_start = epic_ifstart; X ifp->if_watchdog = epic_ifwatchdog; X ifp->if_init = (if_init_f_t*)epic_init; X ifp->if_timer = 0; X ifp->if_output = ether_output; X ifp->if_linkmib = &sc->dot3stats; X ifp->if_linkmiblen = sizeof(struct ifmib_iso_8802_3); X X sc->dot3stats.dot3StatsEtherChipSet = X DOT3CHIPSET(dot3VendorSMC, X dot3ChipSetSMC83c170); X X sc->dot3stats.dot3Compliance = DOT3COMPLIANCE_COLLS; X X /* X * Attach to if manager X */ X if_attach(ifp); X ether_ifattach(ifp); X X splx(s); X X return; X} X X/* X * IFINIT function X */ Xstatic void Xepic_init( X epic_softc_t * const sc) X{ X struct ifnet *ifp = &sc->epic_if; X int iobase = sc->iobase; X int i; X X /* Soft reset the chip. */ X outl(iobase + GENCTL, 0x0001 ); X X /* Wake up */ X outl( iobase + GENCTL, 0x0200); X X /* This next line by Ken Yamaguchi.. ?? (the same is in NT driver) */ X outl( iobase + TEST1, 0x0008); X X /* Initialize rings */ X epic_init_rings( sc ); X X /* Put node address to EPIC */ X outl( iobase + LAN0 + 0x0, ((u_int16_t *)sc->epic_macaddr)[0] ); X outl( iobase + LAN0 + 0x4, ((u_int16_t *)sc->epic_macaddr)[1] ); X outl( iobase + LAN0 + 0x8, ((u_int16_t *)sc->epic_macaddr)[2] ); X X /* Enable interrupts, and set for PCI read multiple. */ X outl( iobase + GENCTL, 0x0512 ); /* possibly better 0x112 */ X X /* Set transmit threshold */ X outl( iobase + TxThresh, TX_FIFO_THRESH ); X X /* Start the chip's Rx process. */ X outl( iobase + RxCtrl, 0x0004 ); X outl( iobase + COMMAND, 0x000A ); X X /* Enable interrupts by setting the interrupt mask. */ X outl( iobase + INTMASK, CntFull | TxUnderrun | TxDone X | RxError | RxOverflow | RxFull | RxHeader | RxDone); X X /* Mark interface running ... */ X if( ifp->if_flags & IFF_UP ) ifp->if_flags |= IFF_RUNNING; X else ifp->if_flags &= ~IFF_RUNNING; X X /* ... and free */ X ifp->if_flags &= ~IFF_OACTIVE; X X} X X/* X * Initialize Rx ad Tx rings and give them to EPIC X * X * If RX_TO_MBUF option is enabled, mbuf cluster is allocated instead of X * static buffer. X */ Xstatic void Xepic_init_rings( X epic_softc_t * sc) X{ X int i; X struct mbuf *m; X X sc->cur_rx = sc->cur_tx = sc->pending_txs = 0; X X for (i = 0; i < RX_RING_SIZE; i++) { X struct epic_rx_buffer *buf = sc->rx_buffer + i; X X buf->desc.status = 0x0000; /* Owned by Epic chip */ X buf->desc.buflength = 0; X buf->desc.bufaddr = 0; X buf->desc.next = vtophys(&(sc->rx_buffer[(i+1)%RX_RING_SIZE].desc) ); X X buf->data = NULL; X X#if !defined(RX_TO_MBUF) X if( buf->pool ){ X free( buf->pool, M_DEVBUF ); X buf->pool = buf->data = 0; X } X buf->pool = malloc(ETHER_MAX_LEN + 0x10, M_DEVBUF, M_NOWAIT); X if( buf->pool == NULL ){ X printf("tx%d: malloc failed\n",sc->unit); X continue; X } X buf->data = (caddr_t)((u_int32_t)(buf->pool + 3) & (~0x3)); X#else X if( buf->mbuf ){ X m_freem( buf->mbuf ); X buf->mbuf = NULL; X } X MGETHDR(buf->mbuf,M_DONTWAIT,MT_DATA); X if( NULL == buf->mbuf ) continue; X MCLGET(buf->mbuf,M_DONTWAIT); X if( NULL == (buf->mbuf->m_flags & M_EXT) ){ X m_freem( buf->mbuf ); X continue; X } X X buf->data = mtod( buf->mbuf, caddr_t ); X#endif X buf->desc.bufaddr = vtophys( buf->data ); X buf->desc.buflength = ETHER_MAX_LEN; X buf->desc.status = 0x8000; X X } X X for (i = 0; i < TX_RING_SIZE; i++) { X struct epic_tx_buffer *buf = sc->tx_buffer + i; X X buf->desc.status = 0x0000; X buf->desc.buflength = 0; X buf->desc.bufaddr = 0; X buf->desc.control = 0; X buf->desc.next = vtophys(&(sc->tx_buffer[(i+1)%TX_RING_SIZE].desc) ); X X if( buf->pool ){ X free( buf->pool, M_DEVBUF ); X buf->pool = buf->data = 0; X } X X buf->pool = malloc(ETHER_MAX_LEN + 4, M_DEVBUF, M_NOWAIT); X X if( buf->pool == NULL ){ X printf("tx%d: malloc failed\n",sc->unit); X continue; X } X X /* align on 4 bytes */ X buf->data = (caddr_t)((u_int32_t)(buf->pool + 3) & (~0x3)); X X buf->desc.bufaddr = vtophys( buf->data ); X buf->desc.buflength = ETHER_MAX_LEN; X } X X /* Give rings to EPIC */ X outl( sc->iobase + PRxCDAR, vtophys(&(sc->rx_buffer[0].desc)) ); X outl( sc->iobase + PTxCDAR, vtophys(&(sc->tx_buffer[0].desc)) ); X X} X X/* X * EEPROM operation functions X */ Xstatic void epic_write_eepromreg(u_int16_t regaddr, u_int8_t val){ X u_int16_t i; X X outb( regaddr, val ); X X for( i=0;i<0xFF; i++) X if( !(inb( regaddr ) & 0x20) ) break; X X return; X} X Xstatic u_int8_t epic_read_eepromreg(u_int16_t regaddr){ X return inb( regaddr ); X} X Xstatic u_int8_t epic_eeprom_clock( u_int16_t ioaddr, u_int8_t val ){ X X epic_write_eepromreg( ioaddr + EECTL, val ); X epic_write_eepromreg( ioaddr + EECTL, (val | 0x4) ); X epic_write_eepromreg( ioaddr + EECTL, val ); X X return epic_read_eepromreg( ioaddr + EECTL ); X} X Xstatic void epic_output_eepromw(u_int16_t ioaddr, u_int16_t val){ X int i; X for( i = 0xF; i >= 0; i--){ X if( (val & (1 << i)) ) epic_eeprom_clock( ioaddr, 0x0B ); X else epic_eeprom_clock( ioaddr, 3); X } X} X Xstatic u_int16_t epic_input_eepromw(u_int16_t ioaddr){ X int i; X int tmp; X u_int16_t retval = 0; X X for( i = 0xF; i >= 0; i--) { X tmp = epic_eeprom_clock( ioaddr, 0x3 ); X if( tmp & 0x10 ){ X retval |= (1 << i); X } X } X return retval; X} X Xstatic int epic_read_eeprom(u_int16_t ioaddr, u_int16_t loc){ X int i; X u_int16_t dataval; X u_int16_t read_cmd; X X epic_write_eepromreg(ioaddr + EECTL , 3); X X if( epic_read_eepromreg(ioaddr + EECTL) & 0x40 ) X read_cmd = ( loc & 0x3F ) | 0x180; X else X read_cmd = ( loc & 0xFF ) | 0x600; X X epic_output_eepromw( ioaddr, read_cmd ); X X dataval = epic_input_eepromw( ioaddr ); X X epic_write_eepromreg( ioaddr + EECTL, 1 ); X X return dataval; X} X Xstatic void epic_put_node_address( epic_softc_t * sc ){ X} END-of-if_tx.c exit >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199711191058.QAA08722>