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>
index | next in thread | raw e-mail
>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:
help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199711191058.QAA08722>
