Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Dec 1997 14:43:38 +0600 (NS)
From:      Semen Ustimenko <semen@iclub.nsu.ru>
To:        FreeBSD-gnats-submit@FreeBSD.ORG
Subject:   kern/5271: SMC9432TX Driver
Message-ID:  <199712110843.OAA22002@iclub.nsu.ru>
Resent-Message-ID: <199712110850.AAA20532@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         5271
>Category:       kern
>Synopsis:       New version of driver
>Confidential:   yes
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Dec 11 00:50:01 PST 1997
>Last-Modified:
>Originator:     Semen Ustimenko
>Organization:
>Release:        FreeBSD 2.2.5-STABLE i386
>Environment:

	

>Description:

	

>How-To-Repeat:

	

>Fix:
	
	

# 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:
#
#	if_tx.c
#	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 * version: stable-162
X *
X */
X
X/*
X * EtherPower II 10/100  Fast Ethernet (tx0)
X * (aka SMC9432TX based on SMC83c170 EPIC chip)
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 * TODO:
X *	Add IFF_MULTICAST support
X *	Fix serious collision counter behaviour
X *	Fix RX_TO_MBUF option
X *	I still have no description on EtherPower II
X *	Add media control code (there is no such at all)
X *	
X * stable-140:
X *	first stable version
X *
X * stable-160:
X *	added BPF support
X *	fixed several bugs
X *
X * stable-161:
X *	fixed BPF support
X *	fixed several bugs
X *
X * stable-162:
X *	fixed IFF_PROMISC mode support
X *	added speed info displayed at startup (MII info)
X *
X */
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/errno.h>
X#include <sys/malloc.h>
X#include <sys/kernel.h>
X#include <sys/ioctl.h>			/* makes problem in FreeBSD 3.x */
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#include "bpfilter.h"
X#if NBPFILTER > 0
X#include <net/bpf.h>
X#include <net/bpfdesc.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
Xstatic int
Xepic_ifioctl(register struct ifnet * ifp, int command, caddr_t data){
X	epic_softc_t *sc = ifp->if_softc;
X	struct ifreq *ifr = (struct ifreq *) data;
X	int x, error = 0;
X
X	x = splimp();
X
X	switch (command) {
X
X	case SIOCSIFADDR:
X	case SIOCGIFADDR:
X		ether_ioctl(ifp, command, data);
X		break;
X
X	case SIOCSIFFLAGS:
X		/*
X		 * If the interface is marked up and stopped, then start it.
X		 * If it is marked down and running, then stop it.
X		 */
X		if (ifp->if_flags & IFF_UP) {
X			if ((ifp->if_flags & IFF_RUNNING) == 0)
X				epic_init(sc);
X		} else {
X			if (ifp->if_flags & IFF_RUNNING) {
X				epic_stop(sc);
X				ifp->if_flags &= ~IFF_RUNNING;
X			}
X		}
X
X#if NBPFILTER > 0
X		/* Set promisc mode */
X		if( ifp->if_flags & IFF_PROMISC )
X			outl( sc->iobase + RxCtrl, 0x0024 );
X		else
X			outl( sc->iobase + RxCtrl, 0x0004 );
X#endif
X		break;
X
X#if 0				/* XXXXXXXX: no multicast filtering */
X	case SIOCADDMULTI:
X	case SIOCDELMULTI:
X		/*
X		 * Update out multicast list.
X		 */
X		error = (command == SIOCADDMULTI) ?
X		    ether_addmulti(ifr, &sc->arpcom) :
X		    ether_delmulti(ifr, &sc->arpcom);
X
X		if (error == ENETRESET) {
X
X			/*
X			 * Multicast list has changed; set the hardware filter
X			 * accordingly.
X			 */
X			ed_setrcr(sc);
X			error = 0;
X		}
X		break;
X#endif
X
X	case SIOCSIFMTU:
X		/*
X		 * Set the interface MTU.
X		 */
X		if (ifr->ifr_mtu > ETHERMTU) {
X			error = EINVAL;
X		} else {
X			ifp->if_mtu = ifr->ifr_mtu;
X		}
X		break;
X
X	default:
X		error = EINVAL;
X	}
X	splx(x);
X
X	return error;
X}
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 ) break;
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		/* Set watchdog timer */
X		ifp->if_timer = 4;
X
X#if NBPFILTER > 0
X		if( ifp->if_bpf ) bpf_mtap( ifp, m0 );
X#endif
X
X		m_freem( m0 );
X
X		/* Trigger an immediate transmit demand. */
X		outl(sc->iobase + COMMAND, 0x0004);
X
X		sc->cur_tx = ( sc->cur_tx + 1 ) % TX_RING_SIZE;
X		sc->pending_txs++;
X	}
X
X#if defined(EPIC_DEBUG)
X	printf("tx%d: txring overflowed\n",sc->unit);
X#endif
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	int x;
X	int i;
X
X	x = splimp();
X	printf("tx%d: device timeout %d packets\n",sc->unit,sc->pending_txs);
X	ifp->if_oerrors+=sc->pending_txs;
X
X	epic_stop(sc);
X	epic_init(sc);
X
X	epic_ifstart(&sc->epic_if);
X
X	splx(x);
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#if defined(EPIC_DEBUG)
X			printf("tx%d: restart transmit\n",sc->unit);
X#endif
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|RxOverflow) )
X		epic_rx_done( sc );
X
X	if( status & (TxDone|TxUnderrun) )
X		epic_tx_done( sc );
X
X	/* If no packets are pending, thus no timeouts */
X	if( sc->pending_txs == 0 ){
X		sc->epic_if.if_timer = 0;
X		if( sc->cur_tx != sc->dirty_tx ){
X			printf("tx%d: algorithm error1\n",sc->unit);
X		}
X	}
X
X	/* We should clear all interrupt sources. */
X	outl(iobase + INTSTAT, 0x0001ffff );
X
X	return;
X}
X
Xvoid
Xepic_rx_done(
X	epic_softc_t *sc )
X{
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 )			/* XXXXX: to panic */
X			panic("tx: low mbufs");		/* or not to panic?*/
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 = len;
X		m->m_len = len;
X
X#if NBPFILTER > 0
X		if( sc->epic_if.if_bpf ) bpf_mtap( &sc->epic_if, m );
X
X		/* Accept only our packets */
X		if((eh->ether_dhost[0] & 1) == 0 &&
X		    bcmp(eh->ether_dhost,sc->epic_ac.ac_enaddr,ETHER_ADDR_LEN)){
X			m_freem(m);
X			goto rxerror;
X		}
X
X#endif
X		m->m_pkthdr.len = len - sizeof(struct ether_header);
X		m->m_len = len - sizeof( struct ether_header );
X		m->m_data += sizeof( struct ether_header );
X
X#if defined(EPIC_DEBUG)
X		printf("tx%d: received %d bytes\n",sc->unit,len);
X#endif
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	epic_ifstart( &sc->epic_if );
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	while(i++ < TX_RING_SIZE){
X		struct epic_tx_buffer *buf = sc->tx_buffer + sc->dirty_tx;
X		u_int16_t len = buf->desc.txlength;
X		stt =  buf->desc.status;
X
X		if( stt & 0x8000 )
X			break;	/* following packets are not Txed yet */
X
X		if( stt == 0 ){
X			if( sc->pending_txs != 0 ||
X			    sc->dirty_tx != sc->cur_tx ) 
X				printf("tx%d: algoritm error\n",sc->unit);
X			if_flags = ~IFF_OACTIVE;
X			break;
X		}
X
X		sc->pending_txs--;		/* packet is finished */
X		sc->dirty_tx = (sc->dirty_tx + 1) % TX_RING_SIZE;
X
X		coll = (stt >> 8) & 0xF;	/* number of collisions*/
X
X		if( stt & 0x0001 ){
X			sc->epic_if.if_opackets++;
X		} else {
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)	/* What does it mean? */
X			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
X		if_flags = ~IFF_OACTIVE;
X	}
X
X	sc->epic_if.if_flags &= if_flags;
X
X	outl( sc->iobase + INTSTAT, TxDone );
X
X	if( !(sc->epic_if.if_flags & IFF_OACTIVE) )
X		epic_ifstart( &sc->epic_if );
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(" type SMC9432TX [");
X
X	i = epic_read_phy_register(iobase,0);
X	if( i & 0x1000 ) printf("Auto-Neg.");
X	if( i & 0x2000 ) printf(" 100 Mb/s");
X	else printf(" 10 Mb/s");
X	if( i & 0x100 ) printf(" Full-duplex");
X	else printf(" Half-duplex");
X
X	printf("]\n");
X
X	/*
X	 * Dump EEPROM
X	 */
X	#if defined(EPIC_DEBUG)
X		printf("tx%d: EEPROM contents\n", sc->unit);
X		for (i = 0; i < 64; i++)
X			printf(" %04x", epic_read_eeprom(iobase, i));
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 = epic_ifioctl;
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#if NBPFILTER > 0
X	bpfattach(ifp,DLT_EN10MB, sizeof(struct ether_header));
X#endif
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
Xstatic void
Xepic_stop(epic_softc_t * const sc){
X	int iobase = sc->iobase;
X
X	outl( iobase + INTMASK, 0 );
X	outl( iobase + COMMAND, 0x61 );
X
X	sc->epic_if.if_timer = 0;
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(epic_softc_t * sc){
X	int i;
X	struct mbuf *m;
X
X	sc->cur_rx = sc->cur_tx = sc->dirty_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_FRAME_LEN, 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_FRAME_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_FRAME_LEN, 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_FRAME_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 int epic_read_phy_register(u_int16_t iobase, u_int16_t loc){
X	int i;
X
X	outl( iobase + MIICtrl, ((loc << 4) | 0x0601) );
X
X	for( i=0;i<0x1000;i++) if( !(inl( iobase + MIICtrl )&1) ) break;
X
X	return inl( iobase + MIIData );
X}
X
Xstatic void epic_write_phy_register(u_int16_t iobase, u_int16_t loc,u_int16_t val){
X	int i;
X
X	outl( iobase + MIIData, val );
X	outl( iobase + MIICtrl, ((loc << 4) | 0x0602) );
X
X	for( i=0;i<0x1000;i++) if( !(inl( iobase + MIICtrl )&2) ) break;
X
X	return;
X}
END-of-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*/		/* IT IS BUGGY */
X/*#define	EPIC_DEBUG	1*/
X#define TX_RING_SIZE	16
X#define RX_RING_SIZE	16
X
X#define ETHER_MAX_FRAME_LEN	(ETHER_MAX_LEN + ETHER_CRC_LEN)
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	0x80		/* 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		dirty_tx;
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 int epic_ifioctl(register struct ifnet *, int, caddr_t);
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);
Xstatic void epic_stop(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);
X
Xstatic int epic_read_phy_register(u_int16_t, u_int16_t);
Xstatic void epic_write_phy_register(u_int16_t, u_int16_t,u_int16_t);
END-of-smc83c170.h
exit

>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199712110843.OAA22002>