(none)
J.Crowcroft at ucl-cs.UUCP
J.Crowcroft at ucl-cs.UUCP
Tue Jul 3 23:11:49 AEST 1990
From: J.Crowcroft at uk.ac.ucl.cs
>But didn't you say it was a simple program? I don't really see the point
>of your posting if you can't give any more information. Before IBM
>will accept it as a bug, you will have to reduce it to its smallest
>reproducible level.
>A. Lester Buck buck at siswat.lonestar.org ...!texbell!moray!siswat!buck
okay...small is relative...
what follows is a non working driver for a BICC (lance based) ethernet
card for a PS/2 under AIX 1.1.
interrupts and packet reception come and go depending which
buffers/descriptor rings/initialisation blocks are kmemalloc'd and
which are statics...it occasionally crashes the machine...the compiler
problems referred to in my earlier message are the appearance of
*warnings* only when syntax errors are also detected (I havnt time or
energy to reproduce the smallest program that produces this effect).
If you can make the driver work, you are welcome to it( modulo the
usual saying where it came from). its fairly close to working ... but
very untidy...a variant works under a real time executive on the same
hardware base...if i get it working (and you are interested) i can
repost it...
cheers
jon
--------------------bicc.h-----------------
/*
* (c) Bloomsbury Computer Consortium
*/
/*
* Lance init Block
*/
typedef struct {
u_short mode;
u_char paddr[6]; /* phys address */
u_char ladrf[8]; /* Logicali addr filter */
u_char raddr[3]; /* rx desriptor addr */
u_char rlen; /* rx descriptor length */
u_char taddr[3]; /* tx descriptor addr */
u_char tlen; /* tx descriptor length */
} LanInit;
/*
* Descriptor Ring entry
*/
typedef struct {
u_char addr[3]; /* high 8 bits of buffer addr */
u_char flags;
short bcnt; /* buffer length in bytes */
u_short mcnt; /* message byte count */
} LanDesc;
/*
* Constants for LANCE CSR
*/
#define ERR 0x8000 /* error */
#define BABL 0x4000 /* babble */
#define CERR 0x2000 /* Collision */
#define MISS 0x1000 /* Missed */
#define MERR 0x0800 /* memory error */
#define RINT 0x0400 /* rx interrupt */
#define TINT 0x0200 /* tx interrupt */
#define IDON 0x0100 /* initialisation done */
#define INTR 0x0080 /* interrupt */
#define INEA 0x0040 /* interrupt enable */
#define RXON 0x0020 /* rx on */
#define TXON 0x0010 /* tx on */
#define TDMD 0x0008 /* tx demand */
#define STOP 0x0004 /* stop */
#define STRT 0x0002 /* start */
#define INIT 0x0001 /* initialise */
/*
* Lance Rx Descriptor ring flag bits
*/
#define RxOWN 0x80 /* Lance's */
#define RxERR 0x40 /* Error in rx'd pkt */
#define RxFRAM 0x20 /* Framing Error */
#define RxOFLO 0x10 /* Overflow in rxd pkt */
#define RxCRC 0x08 /* CRC Error - Noize */
#define RxBUFF 0x04 /* Buffer Error */
#define RxSTP 0x02 /* Start of Pkt */
#define RxENP 0x01 /* End of Pkt */
/*
* Lance TX Descriptor ring flag bits
*/
#define TxOWN 0x80 /* Lance's */
#define TxERR 0x40 /* Error in rx'd pkt */
#define TxMORE 0x10 /* More in next descriptor */
#define TxONE 0x08 /* One retry needed to send */
#define TxDEF 0x04 /* Deferred */
#define TxSTP 0x02 /* Start of Pkt */
#define TxENP 0x01 /* End of Pkt */
/*
* Tx Descriptor 3 bits
*/
#define TxBUFF 0x8000 /* Buffer error */
#define TxUFLO 0x4000 /* Underflow */
#define TxLCOL 0x1000 /* Late Collision */
#define TxLCAR 0x0800 /* Carrier sense loss */
#define TxRTRY 0x0400 /* Retry error */
/*
* max ethernet frame size
*/
#define MAXPKTSIZE 1540
#define MINPKTSIZE 60
#define SAFEPKTSIZE 2048
#define EthernetHeaderLength 14
/*
* useful bits
*/
#define BIT0 0x01
#define BIT1 0x02
#define BIT2 0x04
#define BIT3 0x08
#define BIT4 0x010
#define BIT5 0x020
#define BIT6 0x040
#define BIT7 0x080
extern unsigned short ioin();
extern u_long kvtophys();
/*
* Configuration specific ...
*/
/* The Bicc ethernet card is from 0x8280 up to 0x828f */
#define BICCADDR 0x8280
#define CARDID 0x0808;
/* Should be around 8 for decent performance */
#define NRXDS 8
/* and 2**3 = 8, but shift up 5 places for lance... */
#define LN2NRXDS (3 << 5)
/* Force Quad word align (not nec needed...) */
#define QUAD(x) (((u_long)(x) + 3) & 0xfffffffc)
/* use kmemalloc rather than statics for buffers: */
/*
#define DYNBUF
*/
#define DEBUG 1
#define DEBUGI 1
#define DEBUGRI 1
/*
#define DEBUGTI 1
#define DEBUG2 1
*/
---------------bicc.c--------------------
/*
* BICC ISOLANN MAC Ethernet Devicve Driver
* Under AIX PS/2 1.1
*
* Version 1.1
*
* J Crowcroft
* jon at cs.ucl.ac.uk
* jon at uk.ac.ucl.cs
* ccaajac at uk.ac.ucl
*
* (c) Bloomsbury Computer Consortium
*/
/*
* TODO
* Add multiple device support properly
* Add LLC support (at least LLC1).
* Add err logging instead of printfs...
* Deal with lance freeeze...
* Add LPP support...(external to this)
*/
/* We ARE of course in Kernel mode */
#ifndef KERNEL
#define KERNEL
#endif
#ifndef i386
#define i386
#endif
/* And get all required definitions */
#include <sys/param.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/tty.h>
#include <sys/devinfo.h>
#include <sys/errno.h>
#include <sys/conf.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/file.h>
#include <sys/dir.h>
#include <sys/iobuf.h>
#include <sys/ioctl.h>
#include <sys/ioctlcmd.h>
#include <sys/systm.h>
#include <sys/machinfo.h>
#include <sys/erec.h>
#include <sys/i386/pos.h>
#include <sys/i386/cmos.h>
#include <sys/i386/dmaralloc.h>
#include <sys/i386/intr86.h>
#include <sys/callout.h>
#include <sys/i386/mmu386.h>
#include <sys/socket.h>
#include <sys/in.h>
#include <sys/if.h>
#include <sys/if_ieee802.h>
#include <sys/netisr.h>
#include <sys/mbuf.h>
#include <sys/in_var.h>
#include <sys/in_systm.h>
#include <sys/ip.h>
#include <sys/eth.h>
#include <vmalloc.h>
#include "bicc.h"
/*
* Notes:
*
* POS (programmable option select) registers accessed thru I/O
* see posread/poswrite call
* ioin(b) and ioout(b) on PS/2 AIX
*
* buffer allocations etc use
* kmemalloc for internal structures
* m_get, m_getclr, m_free, mtod, dtom, m_copy, m_cat, m_pullup
*
* queuing to IF uses
* IF_ENQUEUE and IF_DEQUEUE
* called on input and output ifq's in
* if device we learn about in lainit()...
*
* critical network code protected by calling
* splnet
* critical mbuf code protected by
* splimp
*
*/
/*
****************** GLOBS ******************
*/
/*
* Stats gathering - inited in lainit
*/
struct laststats {
u_long txd; /* snet */
u_long rxd; /* got */
u_long ovr; /* overrruns */
u_long bad; /* bad frames */
u_long sht; /* short frames */
u_long mst; /* missed frames */
u_long bab; /* babbles */
u_long crc; /* Collisions */
u_long ukn; /* unk type frames */
} Lastats;
#ifdef DYNBUF
#else
/*
* declare static space for init, rings and buffers
*/
static char sbuff[NRXDS][SAFEPKTSIZE];
static char naff0[16];
static char stxbuff[SAFEPKTSIZE];
static char naff1[16];
static LanDesc stxring;
static char naff2[16];
static LanDesc srxring[NRXDS];
static char naff3[16];
static LanInit slaninit;
static char naff4[16];
#endif
/* Save where we kmemalloc space for buffs (for later checks) */
static char *rxbuff[NRXDS];
/* hang onto the tx buff too */
static char *txbuff;
/* Lance Descriptor rings and buffers */
static LanDesc *txring, *rxring;
/* Base addr of BICC card */
static u_long labase = BICCADDR;
/* Cardid we read back on MCA for BICC */
static int cardid = CARDID;
static int initted = 0;
/* Visible Device Driver routines */
int lainit(), laoutput(), laioctl(),
lawatchdog(), lareset(), laintr();
/* following not defined or used - could be for etherfind (NIT) interface
laopen(), laread(), lawrite(),
*/
/* Internal to driver... */
static void la_rxintr(), la_txintr(), larx();
static void lacsrwrite(), ilacsrwrite();
static u_short lacsread(), ilacsread();
static u_long posfind();
static u_short posread();
static void poswrite();
/* Misc things required */
struct iobuf labuf;
int lalevl; /* interrupt level of BICC lance device */
u_short bdn; /* Ether board number */
extern struct devdata devdata[];/* GLobal Device Data structure */
extern struct ifqueue ipintrq; /* The IP s/w interrupt queue */
/*
* Herein should be an Struct arpcom...
* ( which includes an ifnet...)
*/
struct arpcom ether_ifs[1]; /* IFPs */
/*
* our addr - need more than one for multiple bicc support
*/
u_char lanaddr[6];
u_long outipaddr;
/* For timing out a frozen lance... */
static struct callout *freezer = NULL;
/*
*******************************************************************
* Find and Initiailize the BICC card
* Set up any globs for the driver
*
* Here we learn about IF and we tel IF structure about all our entry
* points
*
* Called by Kernel at boot time
*******************************************************************
*/
lainit(dev)
dev_t dev;
{
struct ifnet *ifp;
LanInit *laninit;
LanDesc *rdre;
int i, j, status;
u_long addr;
u_short tmp;
char *data, *buf;
int unit, maj, slot; /* for multiple ether board support */
int s;
#ifdef PROMISC
int promisc = 0;
#endif
#ifdef DEBUG2
printf("lainit\n");
#endif
/* No ints while doin this please */
s = splimp();
unit = minor(dev);
maj = major(dev);
ifp = &(ether_ifs[0].ac_if); /* should be unit */
if ((slot = devexist(cardid, maj, 1, 0)) == -1) {
printf("lainit: no bicc device\n");
splx(s);
return -1;
}
if (!initted) {
DEV_INSTALL(maj, lainit, lareset, nulldev, nulldev,
laintr, ISNOTATTY);
BDEV_INSTALL(maj, nulldev, nulldev, &labuf);
CDEV_INSTALL(maj, nulldev, nulldev, laioctl, nulldev, ISNOTATTY);
}
#ifdef NVRAMBICC
/* AIXPS2 doesnt know about bicc... yet */
lalevl = devdata[slot].pd_pos3;
#else
lalevl = 3;
#endif
#ifdef DEBUG2
printf("lalvl %d\n", lalevl);
#endif
/* And stop the beast before we get it going */
lacsrwrite(0, STOP);
if (!initted)
intrattach(laintr, lalevl, SPL_IMP);
/*
* zero internal stats
*/
Lastats.txd = 0L;
Lastats.rxd = 0L;
Lastats.ovr = 0L;
Lastats.bad = 0L;
Lastats.sht = 0L;
Lastats.mst = 0L;
Lastats.bab = 0L;
Lastats.crc = 0L;
Lastats.ukn = 0L;
/* POS stuff to find BDN BICC/Lance - panics if not present */
bdn = posfind(cardid);
poswrite(bdn, 0x102, 0x11); /* Enable card and sampled timings */
poswrite(bdn, 0x104, 0x88); /* IRQ, Fairness etc */
/* Get mem for lance descriptor, panic if fail */
#ifdef DYNBUF
if (!initted)
laninit = (LanInit *)kmemalloc(sizeof(LanInit),
MA_DBLWD|MA_LONGTERM|MA_OK2SLEEP);
if(laninit == NULL)
panic("lainit: kmemalloc failed");
#else
laninit = QUAD(&slaninit);
#endif
bzero(laninit, sizeof(LanInit));
/* get tx and rxrings */
#ifdef DYNBUF
if (!initted)
txring = (LanDesc *)kmemalloc(sizeof(LanDesc),
MA_DBLWD|MA_LONGTERM|MA_OK2SLEEP);
if(txring == NULL)
panic("lainit: kmemalloc failed");
#else
txring = QUAD(&stxring);
#endif
#ifdef DYNBUF
if (!initted)
rxring = (LanDesc *)kmemalloc(NRXDS*sizeof(LanDesc),
MA_DBLWD|MA_LONGTERM|MA_OK2SLEEP);
if(rxring == NULL)
panic("lainit: kmemalloc failed");
#else
rxring = QUAD(&srxring[0]);
#endif
/* Setup Lance Initialisation bloc */
for(i=0; i<8; i++)
laninit->ladrf[i] = 0;
laninit->tlen = 0; /* 1 entry in tx ring */
laninit->rlen = LN2NRXDS; /* 8 entries in rx ring (2^3)*/
/* Flatten addr of rx and tx descriptor and put in init bloc */
addr = kvtophys(txring);
for(i=0; i<3; i++)
laninit->taddr[i] = ((u_long)(addr >> (8 * i))) & 0xff;
addr = kvtophys(rxring);
for(i=0; i<3; i++)
laninit->raddr[i] = ((u_long)(addr >> (8 * i))) & 0xff;
#ifdef PROMISC
if (promisc)
laninit->mode = 0x8000;
else
laninit->mode = 0;
#else
laninit->mode = 0; /* Normal operation mode */
#endif
txring->flags = 0;
/* setup rx ring */
for(i=0, rdre = rxring; i<NRXDS; i++, rdre++) {
#ifdef DYNBUF
if (!initted)
buf = (char *)kmemalloc(SAFEPKTSIZE,
MA_DBLWD|MA_LONGTERM|MA_OK2SLEEP);
if(buf == NULL)
panic("lainit: kmemalloc failed");
#else
buf = QUAD(sbuff[i]);
#endif
rxbuff[i] = buf; /* record v addr */
addr = kvtophys(buf); /* map to phys */
for(j=0; j<3; j++)
rdre->addr[j] = ((u_long)(addr >> (8 * j))) & 0xff;
rdre->bcnt = -(SAFEPKTSIZE);
rdre->mcnt = 0;
rdre->flags = RxOWN; /* Give to the Lance */
}
/* Receive Descriptor Ring ptr at head of list */
rdre = rxring;
/* Get mem for transmit buffer */
#ifdef DYNBUF
txbuff = (char *)kmemalloc(SAFEPKTSIZE, MA_DBLWD|MA_LONGTERM|MA_OK2SLEEP);
if(txbuff == NULL)
panic("lainit: kmemalloc failed\n");
#else
txbuff = QUAD(&stxbuff[0]);
#endif
addr = kvtophys(txbuff); /* map to phys */
for(j=0; j<3; j++)
txring->addr[j] = ((u_long)(addr >> (8 * j))) & 0xff;
/* get phys addr somewhere more useful */
for(i=0; i<6; i++) {
lanaddr[i] = ioin((u_short)(labase + (i * 2))) & 0xff;
laninit->paddr[i] = lanaddr[i];
ifp->ac_lanaddr[i] = lanaddr[i];
}
#ifdef DEBUG
printf("lainit ea: ");
for(i=0; i<6; i++)
printf("%x.", lanaddr[i]);
printf("\n");
#endif
/* and give it the init block */
addr = kvtophys(laninit);
tmp = (u_short)(addr & 0xffff);
lacsrwrite(1, tmp);
tmp = ((u_long)addr >> 16) & 0xff;
lacsrwrite(2, tmp);
lacsrwrite(3, 0);
lacsrwrite(0, INIT);
/* wait for it to live... */
while(((status = lacsread(0)) & IDON) == 0) {
if (status & ERR) {
printf("lainit err: 0x%x\n", status);
panic("lance initialisation error");
}
}
/* fill in IF information.. */
ifp->if_unit = unit;
ifp->if_name = "la";
ifp->if_mtu = ETHERMTU;
ifp->if_init = lainit;
ifp->if_output = laoutput;
ifp->if_ioctl = laioctl;
ifp->if_reset = lareset;
ifp->if_watchdog = lawatchdog;
ifp->if_timer = 0;
/* Do broadcasts, dont do trailers, am ethenet IEEE */
ifp->if_flags = IFF_BROADCAST | IFF_NOTRAILERS | IFF_ETHERNET;
/*
| IFF_IEEE;
*/
/* Set stats */
ifp->if_ipackets = 0;
ifp->if_opackets = 0;
ifp->if_ierrors = 0;
ifp->if_oerrors = 0;
ifp->if_collisions = 0;
/* tell aix we've started lance... */
if(!initted)
if_attach(ifp);
if(!initted) /* avoid wraparound */
initted++;
lacsrwrite(0, IDON); /* Clear IDON */
lacsrwrite(0, STRT|INEA); /* Start and enable interrupts... */
splx(s);
return 0;
}
/*
*******************************************************************
* output to ethernet
*
*******************************************************************
*/
laoutput(ifp, m0, dst)
struct ifnet *ifp;
struct mbuf *m0;
struct sockaddr *dst;
{
int error;
u_char edst[6], *destn = edst;
struct ip *pip;
struct in_addr idst;
struct mbuf *m = m0;
spl_t s;
int type = 0, usetrailors;
int off;
int hdr_len, mac_len;
u_char *macp;
struct ifqueue *opq; /* The IP output queue */
#ifdef IEEE
int llc_len;
struct ie2_llc_hdr *llcp;
#else
struct eth_header *dix;
struct arphdr *arph;
#endif
#ifdef DEBUG2
printf("laoutput\n");
#endif
/*
* is interface up and running ??
*/
if((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
#ifdef DEBUG2
printf("laoutput %x\n", ifp->if_flags);
#endif
error = ENETDOWN;
goto bad;
}
/* The BIG SWITCH - see AIX Tech Ref Vol 2 */
switch(dst->sa_family) {
case AF_INET:
idst = ((struct sockaddr_in *)(dst))->sin_addr;
if(!arpresolve(ifp, m, &idst, destn, &usetrailors)) {
#ifdef DEBUG2
printf("laoutput: arp failed\n");
#endif
return 0;
}
pip = mtod(m, struct ip *);
off = ntohs(pip->ip_len) - m->m_len;
/* Trailer stuff */
if (usetrailors && off > 0 && (off & 0x1ff) == 0 &&
m->m_off >= MMINOFF + 2 * sizeof(u_short)) {
type = ETHERTYPE_TRAIL + (off>>9);
m->m_off -= 2 * sizeof(u_short);
m->m_len += 2 * sizeof(u_short);
*mtod(m, u_short *) = htons((u_short)LANTYPE_IP);
*(mtod(m, u_short *) +1) = htons((u_short)m->m_len);
goto gottrailortype;
} else {
type = LANTYPE_IP;
off = 0;
goto gottype;
}
break;
case AF_ARP:
type = LANTYPE_ARP;
/* DROP THRU */
case AF_UNSPEC:
bcopy((caddr_t)dst, (caddr_t)edst, 6);
goto gottype;
break;
default:
#ifdef DEBUG2
printf("laoutput: non supported type\n");
#endif
error = EAFNOSUPPORT;
return;
break;
}
gottrailortype:
#ifdef DEBUG2
printf("laoutput: trailer\n");
#endif
while(m->m_next) /* pkt going at end of packet!! */
m = m->m_next;
m->m_next = m0;
m = m0->m_next;
m0->m_next = 0;
m0 = m;
gottype:
mac_len = 2 * sizeof(edst) + sizeof(u_short);
#ifdef IEEE802
/* not llc yet */
llc_len = sizeof(struct ie2_llc_hdr);
hdr_len = mac_len + llc_len;
#endif
hdr_len = mac_len;
arph = mtod(m, struct arphdr *);
/* find header space */
if ((m0->m_off > MMAXOFF) || (MMINOFF + hdr_len > m0->m_off)){
m = m_get(M_DONTWAIT, MT_HEADER);
if (m == 0) {
error = ENOBUFS;
goto bad;
}
m->m_next = m0;
m0 = m;
m0->m_off = MMINOFF;
m0->m_len = hdr_len;
} else {
m0->m_off -= hdr_len;
m0->m_len += hdr_len;
}
/* Fill in mac header, dst, src, type. */
/* THIS IS HEAVILY DIX SPEFICIX */
macp = mtod(m, u_char *);
dix = mtod(m, struct eth_header *);
/* dst */
if (type == LANTYPE_ARP) {
bcopy((char *)arph + sizeof(struct arphdr) + 6 + 4,
(caddr_t)&(dix->eth_dest[0]), ETH_ADDR_SIZE);
bcopy(lanaddr, (char *)arph+sizeof(struct arphdr),
ETH_ADDR_SIZE);
/*
* OVERWRITE 802 part of arp packet
*/
arph->ar_hrd = ntohs(ARPHRD_ETHER);
}
else
bcopy((caddr_t)edst,
(caddr_t)&(dix->eth_dest[0]), ETH_ADDR_SIZE);
/* src */
bcopy((caddr_t)&lanaddr[0],
(caddr_t)&(dix->eth_srce[0]), ETH_ADDR_SIZE);
/* type */
if (type != 0) {
type = htons(type);
bcopy((caddr_t)&type,
(caddr_t)&(dix->eth_type[0]), sizeof(u_short));
}
/*
* Otherwise we'd do the following...
* fill LLC header (only if IEEE ... )
llcp = mac_to_llc(macp);
bcopy((caddr_t)&sap->sa_llc, (caddr_t)llcp, lc_len);
* and we'd need to set length rather than type (suitably swapped?)
*/
/*
* watch out critics region about
* see if we can queue pkt for output, if so start it...
*/
s = splimp();
opq = &(ifp->if_snd);
if (IF_QFULL(opq)) {
IF_DROP(opq);
error = ENOBUFS;
splx(s);
#ifdef DEBUG
printf("la: IP oq full\n");
#endif
goto qfull;
}
IF_ENQUEUE(opq, m);
laostart(ifp);
splx(s);
return 0;
qfull:
m0 = m;
bad:
m_freem(m0);
return error;
}
/*
*******************************************************************
* called if timeout happens (lance frozen?
*******************************************************************
*/
laorestart(ifp)
struct ifnet *ifp;
{
#ifdef DEBUG
printf("laorestart\n");
#endif
if (freezer == NULL)
return;
to_cancel(freezer);
printf("la: frozen lance\n");
/* FOR NOW XXX */
return;
#ifdef DEBUG
lacsrwrite(0, RINT|TINT|INEA); /* Start and enable interrupts... */
#else
lainit(makedev(25,0));
#endif
}
/*
*******************************************************************
* called whenever more work to be done...
* dequue from ifp->if_snd then get lance going...
* Currently called only from la_output, could
* call from lainit & laintr if we want - note
* splimp should have been called before this is...
*******************************************************************
*/
laostart(ifp)
struct ifnet *ifp;
{
/*
* Find from args...
*/
char *dstadr, *data;
int olen, len, i;
u_long addr;
struct mbuf *m;
char *buf;
#ifdef DEBUG2
printf("laostart\n");
#endif
/* dequeue safely packet */
IF_DEQUEUE(&(ifp->if_snd), m);
if (m == NULL) {
printf("laostart: deq null m\n");
return;
}
/* copy in from mbuf, as much as there was */
len = copy_from_mbufs(txbuff, m);
/* fixup min pkt size...else lance wont send */
if (len < MINPKTSIZE)
len = MINPKTSIZE;
else if (len & 1)
len++;
#ifdef DEBUG2
ethdump(txbuff, len);
#endif
addr = kvtophys(txbuff);
for(i=0; i<3; i++)
txring->addr[i] = ((u_long)(addr >> (8 * i))) & 0xff;
txring->bcnt = -(len);
txring->mcnt = 0;
/* Set a timer to deal with LANCE freezing here... */
freezer = ctimeout(laorestart, ifp, 50);
/* Give to Lance and set STP/ENP */
txring->flags = TxOWN|TxSTP|TxENP;
lacsrwrite(0, INEA|TDMD);
if (txring->flags & TxERR) {
txerrp(txring->mcnt);
if (txring->mcnt & TxLCOL)
ifp->if_collisions++;
}
m_freem(m);
Lastats.txd++;
ifp->if_opackets++;
#ifdef DEBUGTI
printf("laostart ret\n");
#endif
}
static
txerrp(txerr)
{
#ifdef DEBUG
printf("La_txintr error 0x%x", txerr);
if (txerr & TxBUFF)
printf("TxBuff");
if (txerr & TxUFLO)
printf("TxUFLO");
if (txerr & TxLCOL) {
printf("TxLCOL");
}
if (txerr & TxLCAR)
printf("TxLCAR");
if (txerr & TxRTRY)
printf("TxRTRY");
printf("\n");
#endif
}
/*
*******************************************************************
* deal with ioctl sys calls to device...
*******************************************************************
*/
laioctl(ifp, cmd, data)
struct ifnet *ifp;
int cmd;
caddr_t data;
{
struct ifaddr *ifa = (struct ifaddr *)data;
struct arpcom *arper = (struct arpcom *)ifp;
int error = 0;
short flags = ifp->if_flags;
spl_t s = splimp();
#ifdef DEBUG2
printf("laioctl: ");
lainfo();
#endif
switch(cmd) {
case (SIOCSIFADDR):
ifp->if_flags |= IFF_UP;
switch(ifa->ifa_addr.sa_family) {
case AF_INET:
arper->ac_ipaddr =
IA_SIN(ifa)->sin_addr;
arpwhohas(arper, &IA_SIN(ifa)->sin_addr);
break;
default:
#ifdef DEBUG
printf("laioctl: arp on non IP?\n");
#endif
break;
}
#ifdef DEBUG
printf("laioctl: %x\n",
ntohl(((struct arpcom *)ifp)->ac_ipaddr));
#endif
/*
* fall thru
*/
case (SIOCSIFFLAGS):
if (ifp->if_flags & IFF_UP) {
if (ifp->if_flags & IFF_RUNNING)
break;
else {
/*
* Bring up the link...
*/
ifp->if_flags |= IFF_RUNNING;
/*
* Set anything else
*/
#ifdef DEBUG
if (flags & IFF_DEBUG)
lainit(makedev(25,0));
#endif
}
} else {
if(ifp->if_flags & IFF_RUNNING) {
/*
* Close down link
*/
ifp->if_flags &= ~IFF_RUNNING;
/*
* Unset anything else
*/
}
}
break;
default:
error = EINVAL;
break;
}
splx(s);
return error;
}
/*
*******************************************************************
* deal with reset
* eg at reboot
*******************************************************************
*/
lareset()
{
#ifdef DEBUG
printf("lareset: called\n");
#endif
/* stop lance */
lacsrwrite(0, STOP);
lacsrwrite(0, MERR|INEA);
}
/*
* watchdog timer - not used...
*/
lawatchdog()
{
#ifdef DEBUG
printf("lawatchdog: called\n");
#endif
lacsrwrite(0, STOP);
lainit(makedev(25,0));
}
/*
*******************************************************************
* The interrupt handler - field in and out...
*******************************************************************
*/
laintr(vec_num)
int vec_num;
{
u_short status;
int done = 0;
struct ifnet *ifp = ðer_ifs[0]; /* should derive from int vec */
/* Should then derive labase from ether_ifs to support multiple i/fs */
ioout(labase + 0x0e, 0); /* get right CSR */
status = ioin(labase + 0x0c); /* read data */
#ifdef DEBUG
if (!initted) {
printf("laintr: not initted\n");
return done;
}
#endif
if (!(status & INTR)) {
printf("la: spurious interrupt\n");
return done;
}
/*
* which kind of interrupt??
* Note lance keeps internal track of rx buffer chain
* need to check own bit then clear rint bit, else
* packet can arrive between own and rint and we miss intr
*/
#ifdef DEBUG
if (status & RINT) {
#else
if ((status & RINT) && (status & RXON)) {
#endif
ilacsrwrite(0, RINT&INEA); /* clr rx int and INEA */
la_rxintr(ifp);
done++;
}
#ifdef DEBUG
if (status & TINT) {
#else
if ((status & TINT) && (status & TXON)) {
#endif
ilacsrwrite(0, TINT&INEA); /* clr tx int and INEA */
la_txintr(ifp);
done++;
}
if ( (status & (BABL | MERR | MISS | TXON | RXON)) != (RXON|TXON) )
la_errintr(status, ifp);
return done;
}
static
la_errintr(status, ifp)
u_short status;
struct ifnet *ifp;
{
int restart = 0;
#ifdef DEBUG
printf("laintr ");
#endif
#ifdef DEBUG2
printf("(%x) ", status);
#endif
if (status & MISS) {
printf("miss ");
ilacsrwrite(0, MISS|INEA);
Lastats.mst++;
}
if (status & BABL) {
printf("babl ");
ilacsrwrite(0, BABL|INEA);
Lastats.bab++;
}
if (status & CERR) {
printf("crc ");
ilacsrwrite(0, CERR|INEA);
Lastats.crc++;
}
/* Next one is bad lose!! */
if (status & MERR) {
printf("mem ");
/* maybe ilacsrwrite(0, STOP); ??? */
ilacsrwrite(0, MERR|INEA);
}
/* Assert the next one never happens :-) */
if (status & IDON) {
printf("ini done ");
ilacsrwrite(0, IDON|INEA);
}
if (!(status & RXON)) {
printf("rx stopped ");
restart++;
}
if (!(status & TXON)) {
printf("tx stopped ");
restart++;
}
printf("\n");
if (restart) {
printf("la: restarting...csr %x\n", status);
lainit(makedev(25,0));
}
}
/*
*******************************************************************
* rx interrupt handler - field in
*******************************************************************
*/
static void
la_rxintr(ifp)
struct ifnet *ifp;
{
register LanDesc *rdre;
register int cnt;
int len;
char *pkt;
#ifdef DEBUG
int j;
u_long addr;
#endif
/* Go round all the rx ring... check which are ours, */
/* Should check STP and ENP in flags... */
for(rdre = rxring, cnt=0; cnt<NRXDS; rdre++, cnt++) {
if ((rdre->flags & RxOWN) != RxOWN) { /* If its ours... */
len = rdre->mcnt;
pkt = rxbuff[cnt];
if (rdre->flags & RxERR)
rdreerr(rdre->flags);
else
larx(pkt, len, ifp);
rdre->bcnt = -(SAFEPKTSIZE);
rdre->mcnt = 0;
rdre->flags = RxOWN; /* and give the lance ownership */
#ifdef DEBUG
/* convert phys addr back to virt and check lance and we agree!! */
addr = (u_long)(rdre->addr[2] << 16) |
(u_long)(rdre->addr[1] << 8) |
(u_long)(rdre->addr[0]);
if (addr != kvtophys(pkt)) {
printf("la: bad rx buffer %x!=%x\n",
addr, kvtophys(pkt));
addr = kvtophys(pkt);
for(j=0; j<3; j++)
rdre->addr[j] =
((u_long)(addr >> (8 * j))) & 0xff;
}
#endif
}
}
ifp->if_ipackets++;
Lastats.rxd++;
#ifdef DEBUG2
printf("r");
lainfo();
#endif
}
/*
*******************************************************************
* Demux frame types
*******************************************************************
*/
static void
larx(pkt, len, ifp)
char *pkt;
int len;
struct ifnet *ifp;
{
struct arpcom *arper = (struct arpcom *)ifp;
int data_len;
char *addr_of_data;
u_short type;
struct mbuf *m, *copy_to_mbufs();
struct ifqueue *ipq; /* The IP s/w interrupt queue */
if ((len < MINPKTSIZE) || (len > MAXPKTSIZE)) {
Lastats.sht++;
#ifdef DEBUGRI
printf("la: rx bad size pkt: %d\n", len);
#endif
return;
}
/*
* the other BIG SWITCH - Find Client for packet type (? LSAP?)
* Now do the mbuf and queuing stuff...
*/
type = ((u_short *)(pkt))[6];
type = htons(type);
addr_of_data = pkt + sizeof(struct eth_header);
data_len = len - sizeof(struct eth_header);
switch(type) {
case LANTYPE_IP:
printf("I");
m = copy_to_mbufs(addr_of_data, data_len, ifp);
if (m == NULL)
break;
ipq = &ipintrq;
if (IF_QFULL(ipq)) {
#ifdef DEBUGRI
printf("larx: IP inq full\n");
#endif
IF_DROP(ipq);
m_freem(m);
return;
}
#ifdef DEBUGRI
printf("larx: IP enq %d\n", data_len);
#endif
IF_ENQUEUE(ipq, m);
schednetisr(NETISR_IP);
break;
case LANTYPE_ARP:
printf("A");
m = copy_to_mbufs(addr_of_data, data_len, ifp);
if (m == NULL)
break;
arpinput(arper, m);
#ifdef DEBUGRI
printf("larx: ARP enq\n");
#endif
break;
default:
/*
* Could cope with IEEE LLC frames here...
* need a registry of LSAPs etc etc...
*/
Lastats.ukn++;
#ifdef DEBUG2
printf("larx unknwn frm type %x len %d\n", type, len);
#endif
break;
}
}
static
rdreerr(flags)
u_short flags;
{
#ifdef DEBUG
printf("laintr: err 0x%x", flags);
if (flags & RxCRC)
printf("CRC");
if (flags & RxBUFF)
printf("BUFF");
if (flags & RxOFLO)
printf("OFLO");
if (flags & RxFRAM)
printf("FRAM");
printf("\n");
#endif
}
/*
*******************************************************************
* handle tx interrupts...
*******************************************************************
*/
static void
la_txintr(ifp)
struct ifnet *ifp;
{
#ifdef DEBUGTI
printf("t");
#endif
if (freezer != NULL) {
to_cancel(freezer);
freezer = NULL;
}
#ifdef DEBUG
if (txring->flags & TxERR) {
txerrp(txring->mcnt);
if (txring->mcnt & TxLCOL)
ifp->if_collisions++;
}
#endif
}
/*
*******************************************************************
* general service routines...
*******************************************************************
*/
/*
* service routine copy from mbuf to contig lance buffer
*/
static
copy_from_mbufs(buf, m)
unsigned char *buf;
struct mbuf *m;
{
int offset;
struct mbuf *mp;
for(offset=0, mp = m; mp; mp = mp->m_next) {
unsigned int len = mp->m_len;
unsigned char *mcp;
if (len != 0) {
mcp = mtod(mp, unsigned char *);
bcopy((caddr_t)mcp, (caddr_t)buf, len);
offset += len;
buf += len;
}
}
return offset;
}
/*
* service routine for la_rxintr
*/
static struct mbuf *
copy_to_mbufs(addr, totlen, ifp)
char *addr;
int totlen;
struct ifnet *ifp;
{
int len;
struct mbuf *m, *top=NULL, **mp = ⊤
char *mcp;
spl_t s = splimp();
ifp->if_ipackets++;
while(totlen > 0) {
MGET(m, M_DONTWAIT, MT_DATA);
if (m == NULL)
goto bad;
len = totlen;
if (ifp != NULL)
len += sizeof(ifp);
if (len >= mincluster) {
printf("ctm: >mcl");
MCLGET(m);
if (m->m_len == CLBYTES)
m->m_len = len = MIN(CLBYTES, len);
else
m->m_len = len = MIN(MLEN, len);
} else {
m->m_len = len = MIN(MLEN, len);
m->m_off = MMINOFF;
}
mcp = mtod(m, u_char *);
if(ifp != NULL) {
*(mtod(m, struct ifnet **)) = ifp;
mcp += sizeof(ifp);
len -= sizeof(ifp);
ifp = NULL;
}
bcopy(addr, mcp, len);
addr += len;
*mp = m;
mp = &m->m_next;
totlen -= len;
}
splx(s);
return top;
bad:
#ifdef DEBUGI
printf("copy_to_mbufs failed, no mbuf\n");
#endif
if (top != NULL)
m_freem(top);
splx(s);
return NULL;
}
ethdump(pkt, len)
char *pkt;
{
struct eth_header *dix = (struct eth_header *)pkt;
int i;
for(i=0; i<6; i++)
printf("%2x:", dix->eth_srce[i] & 0x0ff);
printf("->");
for(i=0; i<6; i++)
printf("%2x:", dix->eth_dest[i] & 0x0ff);
i = *(u_short *)dix->eth_type;
printf("(%x)\n", i);
pkt = pkt + sizeof(struct eth_header);
pktdump(pkt, len);
}
pktdump(pkt, len)
char *pkt;
{
if (len > 80)
len = 80;
while(len-- > 0) {
printf("%2x ", (int)(*pkt) & 0xff);
pkt ++;
}
printf("\n");
}
/*
*************************************
*
* talk to the lance direct
*/
/*
*Write lance csr with intrs off
*/
static void
lacsrwrite(csr, data)
u_short csr, data;
{
spl_t i = splnet();
ioout(labase + 0x0e, csr);
ioout(labase +0x0c, data);
splx(i);
}
/*
*write lance csr with intrs as are
*/
static void
ilacsrwrite(csr, data)
u_short csr, data;
{
ioout(labase + 0x0e, csr);
ioout(labase +0x0c, data);
}
/*
* read lance CSR
*/
static u_short
lacsread(csr)
u_short csr;
{
u_short ret;
spl_t i = splnet();
ioout(labase + 0x0e, csr);
ret = ioin(labase + 0x0c);
splx(i);
return ret;
}
/*
***************************************
*
* POS things to do
*/
static void
poswrite(card,reg,val)
u_short card, reg, val;
{
spl_t i = splnet();
iooutb(0x94, BIT5|BIT7);
iooutb(0x96, BIT3|card);
ioout(0x100|reg, val); /* was iooutb */
splx(i);
}
static u_short
posread(card, reg)
u_short card, reg;
{
u_short ret;
spl_t i = splnet();
iooutb(0x94, BIT5|BIT7);
iooutb(0x96, BIT3|card);
ret = ioin(0x100|reg); /* was ioinb */
splx(i);
return ret;
}
static u_long
posfind(id)
u_short id;
{
u_long i;
for(i=0; i<8; i++) {
if((posread(i, 0x100) << 8) | posread(i, 0x0101) == id)
return i;
}
/*
* else no such slot...
*/
panic("cannot BICC Ether card slot");
/* NOTREACHED */
return -1;
}
/*
* Debugging prints...
*/
#ifdef DEBUG
static
lainfo()
{
int i, j;
LanDesc *rdre;
u_short stat;
stat = lacsread(0);
printf("\nla stat %x\n", stat);
#ifdef DEBUG2
for(i=0; i< 6; i++)
printf("%x.", lanaddr[i]& 0xff);
printf("\n");
printf("txt\trxd\tovr\tbad\tsht\tmst\tbab\n");
printf("%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
Lastats.txd,
Lastats.rxd,
Lastats.ovr,
Lastats.bad,
Lastats.sht,
Lastats.mst,
Lastats.bab );
for(j=0, rdre = rxring; j<NRXDS; j++, rdre++) {
printf("rxbuff %d %x\n", j, rxbuff[j]);
printf("addr:%x,%x,%x flg: %x bcnt %d mcnt %d\n",
rdre->addr[0],
rdre->addr[1],
rdre->addr[2],
rdre->flags,
rdre->bcnt,
rdre->mcnt);
}
#endif
}
#endif
More information about the Comp.unix.aix
mailing list