Skip site navigation (1)Skip section navigation (2)
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>