|
|
Power 6/32 Unix version 1.2b
#include "veiu.h"
#include "conf.h"
#include "const.h"
#include "pte.h"
#define ACEBASE 0xff0000 /* ACE device base address */
#define ACEVECTOR 0x90 /* */
#define RXHDLR 0x90 /* Receive vector interrupt */
#define TXHDLR 0x91 /* Transmit vector interrupt */
#define VEIU_LEN 1 /* 1K for I/O registers */
#define DPM_SIZE 32 /* 32K DMP */
#define LOWBUF 0 /* lowest dmp buffer index */
#define HIGHBUF 15 /* highest dmp buffer index */
/*
Errors
*/
struct errors {
short tx_retries; /* number of retries */
short tx_discarded; /* discarded packet count */
short tx_datagrams; /* transmitted packet count */
short rx_overrn; /* overrun error count */
short rx_oddbit; /* odd # of bits count */
short rx_crcerr; /* crc error */
short rx_undern; /* underrun error */
short rx_datagrams; /* received packet count */
short rx_mismtch; /* Xmit & Rec msgs mismatched */
short rx_rbcerr /* rbc (of received messg) error*/
};
/*
Xmit / Receive queue tracking pointers
*/
struct XRqueue {
short currnd; /* current random number */
short boundry; /* Xmit/Rec boundary */
char *dpmptr; /* Pointer to dpm */
short Rptr; /* Rx segment tracking ptr */
short Xptr; /* Tx segment tracking ptr */
short Xnxt; /* Next avail Xmit buffer */
struct errors stats; /* error tracker */
};
struct XRqueue aceq;
struct acedevice *addr; /* Pointer to device I/O registers */
long IObase;
#define NACE 2 /* No. of V/EIU devices */
#define NOFRAME 16 /* No. of available frames */
#define FRAMESZ 2048 /* Frames size: 2K */
/*
Oftenly-used write routines
*/
#define NL writes("\n");
long ace[NACE]; /* V/EIU address slots */
long dpmmap[] = {0xfff80000,0xfff90000};/* dpm address */
extern long savvec3, unused, clk_cnt, proc_no;
long oldunu;
char ace_station[6*NACE] = { /* addresses */
~0x8,~0x0,~0x3,~0x0,~0x0,~0x1,
~0x8,~0x0,~0x3,~0x0,~0x0,~0x2,
};
/* Test message */
char testmsg[] = "ABCDEFGHIJKLMNOPQRSTXYUYWZ0123456789\
abcdefghijklmnopqrstxyuv";
#define TMSGSZ (sizeof(testmsg) -1 )
char ace_hash_code[8*NACE]={ /* hash tables */
~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,/*u 0*/
~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,/*u 1*/
};
short random_mask_tbl[16] = { /* backoff table*/
0x0040, 0x00C0, 0x01C0, 0x03C0,
0x07C0, 0x0FC0, 0x1FC0, 0x3FC0,
0x7FC0, 0xFFC0, 0xFFC0, 0xFFC0,
0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0
};
short msgno, testno, reddy, firstrep; /* global variables */
veiu()
{ short ix;
short Csr;
for (ix=0; (ix < NACE) && ace[ix] ; ix++) {
NL; writes("\nBEGIN TESTING V/EIU NO. "); writed(ix); NL;
if (!veiu_reset(ix)) {
writes("\n3. MODE 2 TEST------------------------------> ");
NL; NL;
testno = 2; /* current test number */
veiu_ex(); /* Test this ACE */
DELAY(0x200000);
Csr = (short)addr->csr;
Csr &= ~CSR_GO; /* turn off mode 2 */
movew((short)Csr,&addr->csr);/* stop mode 2 */
movew((short)CSR_GO,&addr->csr);
Csr = (short)addr->csr;
if (Csr & CSR_ACTIVE)
{
Csr |= CSR_ENINT | CSR_LOOP3 | CSR_PROMISCUOUS;
movew(Csr,&addr->csr);
}
else
{
writes("*** Controller would not go active.");
writes(" Test aborted ***");
}
NL;
writes("\n4. MODE 3 TEST------------------------------> ");
NL; NL;
testno = 3; /* current test number */
init_erc();
veiu_ex(); /* Test this ACE */
DELAY(0x200000);
Csr = (short)addr->csr;
Csr |= CSR_ENXMITODD; /* enable oddbit */
movew((short)Csr,&addr->csr);/* update csr word */
NL;
writes("\n5. MODE 3, ODD # OF BITS ERROR TEST---------> ");
NL; NL;
testno = 4; /* current test number */
init_erc();
veiu_ex(); /* Test this ACE */
DELAY(0x200000);
Csr = (short)addr->csr;
Csr &= ~CSR_ENXMITODD; /* disable oddbit */
Csr |= CSR_NOXMITCRC; /* suppressed crc */
movew((short)Csr,&addr->csr);/* update csr word */
NL;
/*
writes("\n6. MODE 3, CRC ERROR TEST-------------------> ");
NL; NL;
testno = 5;
init_erc();
veiu_ex();
DELAY(200000);
NL;
writes("\n7. MODE 3, OVERRUN ERROR TEST---------------> ");
NL; NL;
testno = 6;
init_erc();
firstrep = 25;
veiu_ex();
*/
writes("\nEND TESTING OF UNIT: "); writed(ix); NL;
}
} /* end for loop */
}
/*
Diagnostic routine
*/
veiu_ex()
{
short mxnofmsg, lostmsg, timecount; /* max. number of messages */
if (testno == 2)
mxnofmsg = 22;
else /* mode 3 */
mxnofmsg = 13;
lostmsg = 0;
for (msgno = 2; msgno < mxnofmsg; msgno++)
{
load_txbf(); /* fill up tx buffer */
reddy = 1; /* block next message */
timecount = 0;
while (reddy) { /* wait for rcvr to response */
DELAY(0x5000); /* wait for receiver to finish */
timecount++; /* count waiting time */
if (timecount > 100) /* is receiver still not responding */
{ /* time out */
lostmsg++; /* count lost message */
reddy = 0; /* unlock next message */
}
}
} /* OK!ready for next message */
report(lostmsg); /* generate report */
}
/*
load transmit buffer
*/
load_txbf()
{
register struct XRqueue *is = &aceq;
register struct tx_segment *txmbf;
short ix, iy, cmd, bfptr, length, repetition;
txmbf = (struct tx_segment *) (is->dpmptr + (is->Xnxt << 11));
bfptr = 0;
is->stats.tx_retries = 0; /* init number of retries */
switch (testno) {
case 2: {
repetition = msgno;
length = TMSGSZ;
break;
}
case 3:
case 4:
case 5: {
length = 5*msgno;
repetition = 1;
break;
}
case 6: {
repetition = firstrep++;
length = TMSGSZ;
}
};
/* now, fill up buffer */
for (ix=0; ix < repetition; ix++)
for (iy=0; iy < length; iy++)
txmbf->tx_data[bfptr++] = testmsg[iy]; /* fill buffer up */
/* update transmit command word & issue transmit command */
/*
if (testno > 2) {
writes("Transmit message #"); writed(msgno-1);
DELAY(1000);
}
*/
cmd = (bfptr & TCS_TBC) | TCS_TBFULL; /* update rbc */
movew((short)cmd,&(txmbf->tx_csr));
if (++is->Xnxt >= 16) /* reach buf upper limit ? */
is->Xnxt = is->boundry; /* so, point to buf lower limit */
}
/*
Report generator
*/
report(lostmsg)
short lostmsg; /* no of msgs sent but not received */
{
short ix;
register struct XRqueue *is = &aceq;
NL; writes("Transmit: ");
writed(is->stats.tx_datagrams); writes(" messages"); NL;
writes("Receive : ");
writed(is->stats.rx_datagrams); writes(" message(s)"); NL;
writes("Discard: ");
writed(is->stats.tx_discarded); writes(" message(s)"); NL;
if (lostmsg) { /* there're lost msgs, report... */
writes("Warning: Reveiver not responding. ");writed(lostmsg);
writes(" message(s) are lost.\n\n");
}
if (testno > 2) {
NL; NL; writes("\t Number of Message(s) With"); NL;
NL; writes("Overrun Underrun CRC Odd # of bits");
NL; NL; writes(" ");
writed(is->stats.rx_overrn); writes(" ");
writed(is->stats.rx_undern); writes(" ");
writed(is->stats.rx_crcerr); writes(" ");
writed(is->stats.rx_oddbit); NL; NL;
}
writes("Done with: ");
writed(is->stats.rx_mismtch);
writes(" mismatched message(s)"); NL;
if (testno > 2) {
writes(" ");
writed(is->stats.rx_rbcerr);
writes(" received message(s) w/ incorrect byte count"); NL; NL;
}
DELAY(0x10000); /* relax */
}
/*
VEIU test routine
Return code: 0-----------------Error
1-----------------Good
*/
veiu_reset(unit)
short unit; /* current vioc no */
{ register long ix, vbase;
int veiu_init();
NL; writes("\n1. RESET AND INITIALIZATION------------------>");
vbase = ace[unit];
NL; writes("\nInitialize V/EIU at: "); writeh(vbase);
m_veiu(unit,vbase); /* Set up map for IO space */
if (veiu_init(unit)) /* Reset and init. VEIU */
return(1);
return(0); /* good return */
}
/*
Check vioc controllers' buffer address
*/
chk_veiu_adr()
{ register long curadr; /* current examine vioc address */
short len, aceno, naces; /* address length */
len = 2;
naces = 0;
curadr = ACEBASE + IOBASE; /* first ACE buffer address */
writes("\nProbing for V/EIUs...");
for (aceno= 0; aceno < NACE; aceno++)
{
if (!badaddr(curadr,len))
{
ace[aceno] = curadr - IOBASE;
writes("\nV/EIU no. "); writed(aceno);
writes(" at virtual address ");
writeh((long)curadr);
naces++;
}
else /* bad address return */
{
ace[aceno] = 0; /* bad address indicator */
}
curadr += 0x100; /* get to next dev io regs' address */
}
NL; writed(naces); writes(" V/EIUs found."); NL;
return(naces);
}
/* Routine to Reset VEIU
1---------------Good
0---------------Error
*/
veiu_init(unit)
short unit;
{
short Csr;
writes("\nReset V/EIU unit no. "); writed(unit); NL; NL;
/*
* Reset the controller, initialize the recieve buffers,
* and turn the controller on again and set board online.
*/
movew((short)CSR_RESET,&addr->csr);
DELAY(10000);
/* clean up dpm since the controller might jumble dpm after
reset */
if (acesetetaddr(unit)) /* set station addr & */
return(1); /* emergency return */
Csr = (short)addr->csr;
aceclean();
movew((short)CSR_GO,&addr->csr); /* addr->csr = CSR_GO; */
Csr = (short)addr->csr;
if (Csr & CSR_ACTIVE)
{
movew((short)ACEVECTOR,&addr->ivct);
Csr |= CSR_ENINT | CSR_LOOP2 | CSR_PROMISCUOUS;
movew(Csr,&addr->csr);
return(0);
}
else
{
writes("*** Controller would not go active.");
writes(" Test aborted ***"); NL;
return(1); /* bad return */
}
}
acesetetaddr(unit)
short unit;
{
register short *pData0, i;
register char *pData1;
short Csr;
for (pData0 = (short *)&(addr->rar.station_addr[0]),
pData1 = &ace_station[unit*6], i = 6; --i >= 0;) {
movew((short)(*pData1++),(pData0++));
}
for (pData0 = (short *)&(addr->rar.mcast_hash_code[0]),
pData1 = &ace_hash_code[unit * 8], i = 8;
--i >= 0;){
movew((short)(*pData1++),(pData0++));
}
movew((short)0x0,&addr->rar.broadcast_en[0]);
movew((short)0x0,&addr->rar.broadcast_en[1]);
Csr = (short)addr->csr;
if (Csr & CSR_ACTIVE) /* make sure ctlr is not active before */
{ /* reading RARs */
Csr |= ~CSR_ACTIVE;
movew((short)Csr,&addr->csr);
}
if (reg_test(unit,(short *)&addr->rar.station_addr[0]))
{
writes("\nRVT Fatal error(s) detected. Test aborted.");
return(1); /* bad return */
}
return(0); /* good return*/
}
Xd_int()
{
asm(".align 2");
asm(".globl Xd_hdlr");
asm("Xd_hdlr:");
chk_Xd();
asm("rei");
}
/*
* Transmit done handler.
*/
chk_Xd()
{
register struct XRqueue *is = &aceq;
register struct tx_segment *txseg; /* ptr to V/EIU tx seg */
short eostat;
txseg = (struct tx_segment *)((is->Xptr << 11) + is->dpmptr);
if (((eostat = txseg->tx_csr) & TCS_TBFULL) == 0) {
is->stats.tx_retries += (eostat & TCS_RTC);
if (eostat & TCS_RTFAIL) {
is->stats.tx_discarded++;
reddy = 0; /* unlock next message Xmission */
}
else
is->stats.tx_datagrams++;
if (++is->Xptr >= 16)
is->Xptr = is->boundry;
}
}
/*
* Ethernet interface receiver interrupt.
* If input error just drop packet.
* Otherwise purge input buffered data path and examine
* packet to determine type. If can't determine length
* from type, then have to drop packet. Othewise decapsulate
* packet based on type and pass to type specific higher-level
* input routine.
*/
Rxd_int()
{
asm(".align 2");
asm(".globl Rxd_hdlr");
asm("Rxd_hdlr:");
chk_Rxd();
asm("rei");
}
chk_Rxd()
{
register struct XRqueue *is = &aceq;
register struct rx_segment *rxseg; /* ptr to V/EIU rx seg */
short eistat;
int len;
DELAY(0x1000); /* To make sure crs is updated */
rxseg = (struct rx_segment *)((is->Rptr << 11) + is->dpmptr);
/*
if (testno > 2) {
writes("...receive status: "); writeh(rxseg->rx_csr & 0xFFFF); NL;
DELAY(5000);
}
if (testno >= 3) {
dumpchar(&(rxseg->rx_data[0]),5*msgno);
DELAY(100000);
}
*/
if ((eistat = rxseg->rx_csr) & RCS_RBFULL)
{
if (++is->Rptr >= is->boundry)
is->Rptr = 0;
len = (eistat & RCS_RBC);
if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) ||
(len > (ET_MAXLEN+CRC_SIZE)))
{
if (eistat & RCS_ROVRN) is->stats.rx_overrn++;
if (eistat & RCS_RCRC) is->stats.rx_crcerr++;
if (eistat & RCS_RODD) is->stats.rx_oddbit++;
if ((testno > 2) & (len < ET_MINLEN)) is->stats.rx_undern++;
if (len > (ET_MAXLEN+CRC_SIZE)) is->stats.rx_overrn++;
compare(rxseg,is); /* compare receive & Xmit mssgs */
}
else
compare(rxseg,is); /* compare receive & Xmit mssgs */
}
is->stats.rx_datagrams++;
rxseg->rx_csr = 0;
reddy = 0; /* unlock next message Xmission */
}
/*
Initialize Tahoe SCB vectors to handle Rec & Xmit interrupts
*/
init_veiu_vec()
{ long old_vec1, old_vec2, old_vec3;
asm("movab Rxd_hdlr,_savvec3");
set_handler(RXHDLR,&old_vec1,savvec3); /* Set handler for VEIU Rxr */
asm("movab Xd_hdlr,_savvec3");
set_handler(TXHDLR,&old_vec2,savvec3); /* Set handler for VEIU Txr */
}
/*
I/O registers access routines
*/
movew(data,to)
short data;
short *to;
{
asm("movow 6(fp),*8(fp)");
}
aceclean()
{
register struct XRqueue *is = &aceq;
register short i, data;
register char *pData1;
short ix;
init_erc();
is->currnd = (short)49123;
for (pData1 = (char *)(is->dpmptr + (is->boundry << 11)),
i = (SEG_MAX + 1) - is->boundry;
(--i >= 0); pData1 += sizeof (struct tx_segment))
acebakoff(((struct tx_segment*)pData1),15);
}
/*
Initialize error counts & clear dpm buffer
*/
init_erc()
{
register struct XRqueue *is = &aceq;
short *bptr, ix, reg;
bptr = (short *)is->dpmptr;
for (ix=0; ix < 16383; ix++)
{
*bptr = 0;
bptr++;
}
is->stats.tx_datagrams = 0;
is->stats.tx_discarded = 0;
is->stats.rx_datagrams = 0;
is->stats.rx_overrn = 0;
is->stats.rx_crcerr = 0;
is->stats.rx_undern = 0;
is->stats.rx_oddbit = 0;
is->stats.rx_mismtch = 0;
is->stats.rx_rbcerr = 0;
DELAY(0x2000); /* try to avoid machine check error */
reg = (short)addr->rseg;
DELAY(0x2000);
is->Rptr = (reg & 0x7800) >> 11;
DELAY(0x2000);
reg = (short)addr->tseg;
DELAY(0x2000);
is->Xptr = is->Xnxt = (reg & 0x7800) >> 11;
}
/*
back off
*/
acebakoff(txseg, retries)
struct tx_segment *txseg; /* ptr to V/EIU tx seg */
register int retries; /* # of randoms to generate */
{
short *pMask; /* ptr to mask table. */
register short *pBakNum; /* ptr to # entry in Tx seg table */
register short random_num; /* random number value. */
pMask = &random_mask_tbl[0];
pBakNum = &txseg->tx_backoff[0];
for (; --retries >= 0;)
{
random_num = (aceq.currnd = (aceq.currnd * 18741)-13849);
random_num &= *(pMask++);
*(pBakNum++) = random_num ^ (short)(0xFF00 | 0x00FC);
}
return(0);
}
/*
Compare receive msg against Xmit msg to see if they are matched
*/
compare(rxbuf,is)
struct rx_segment *rxbuf;
struct XRqueue *is;
{
short bytc, rbc, ix, iy;
switch(testno) {
case 2: {
bytc = msgno*TMSGSZ;
break;
}
case 3:
case 4: { /* received with crc */
rbc = (rxbuf->rx_csr & (short)RCS_RBC) - (short)CRC_SIZE;
bytc = msgno*5;
if (rbc != bytc)
is->stats.rx_rbcerr++;
break;
}
case 5: { /* crc suppressed */
rbc = (rxbuf->rx_csr & (short)RCS_RBC);
bytc = msgno*5;
if (rbc != bytc)
is->stats.rx_rbcerr++;
}
default:
break;
};
iy = 0;
for (ix=0; ix < bytc; ix++, iy++)
{
if (iy >= TMSGSZ)
iy = 0;
if (rxbuf->rx_data[ix] != testmsg[iy]) {
is->stats.rx_mismtch++;
break;
}
}
return(0); /* matched */
}
/*
Routine to map VEIU :
VEIU space is map from 1st unused virtual page on
*/
m_veiu(unit,vbase)
long unit, vbase; /* device's base address */
{
register long phys_pg, pte, which1;
register struct XRqueue *is = &aceq;
long old_pte, at;
if (!unit) {
phys_pg = ((vbase+IOBASE) >> PGSHIFT) & 0x3fffff;
/* 1st physical page of VEIU IOR space */
pte = phys_pg | PG_KW | PG_V | PG_NC;
fix_pte(SBR,unused,&old_pte,pte);
addr = (struct acedevice *)(unused << PGSHIFT);
IObase = (long)addr;
unused++; /* Next unused PTE in system map */
}
else
addr = (struct acedevice *)(IObase + 0x100);
phys_pg = (dpmmap[unit] >> PGSHIFT) & 0x3fffff;
/* 1st physical page of DMP */
pte = phys_pg | PG_KW | PG_V | PG_NC;
for (which1=unused; which1<(unused+DPM_SIZE); which1++) {
fix_pte(SBR,which1,&old_pte,pte);
pte++;
}
is->dpmptr = (char *)((unused << PGSHIFT));
unused = which1;
asm("mfpr $SLR,_savvec3");
savvec3 += (DPM_SIZE + VEIU_LEN);
asm("mtpr _savvec3,$SLR");
asm("mtpr $1,$TBIA");
asm("mtpr $1,$PADC");
}
/*
Print mismatched message - For debuging aid only
*/
print_msg(ptr,bytcnt)
char *ptr; /* pointer to received data */
short bytcnt; /* number of char in rev buffer */
{
short ix;
for (ix=0; ix < bytcnt; ix++)
writec(ptr[ix]);
NL;
}
/*
Debuging aid
*/
dumpchar(addr,size)
register char *addr;
long size;
{
register long ix;
for (;size > 0; size-=30) {
for (ix=30;ix;--ix) {
writec((*addr++)&0xff); writes(" ");
}
NL;
}
}
/*
Registers validation test
*/
reg_test(unit,pdata0)
short unit;
short *pdata0;
{
register struct XRqueue *is = &aceq;
short ix, reg, regerr, xseg, rseg, errcode = 0;
char *pdata1;
writes("2. REGISTER VALIDATION TEST------------------>");
NL; NL;
regerr = 0;
pdata1 = (char *)&ace_station[unit*6];
for (ix=0; ix < 6; ix++, pdata0++, pdata1++)
{
reg = *pdata0;
if ((char)(reg & 0xff)!= (char)(*pdata1 & 0xff)) {
regerr++;
}
}
for (ix=0; ix < 2; ix++, pdata0++)
{
reg = *pdata0;
if ((char)(reg & 0x00)) {
regerr++;
}
}
pdata1 = (char *)&ace_hash_code[unit*8];
for (ix=0; ix < 8; ix++, pdata0++, pdata1++)
{
reg = *pdata0;
if ( (char)(reg & 0xff) != (char)(*pdata1 & 0xff)) {
regerr++;
}
}
writes("RAR registers test: ");
writed(regerr); writes(" error(s)\n\n");
writes("Transmit segment register (tseg): ");
DELAY(0x2000); /* wait for write done */
reg = (short)addr->tseg;
DELAY(0x2000); /* wait for data avail */
xseg = (reg & 0x7800) >> 11;
writed(xseg); NL;
writes("Receive segment register (rseg): ");
DELAY(0x2000);
reg = (short)addr->rseg;
DELAY(0x2000);
rseg = (reg & 0x7800) >> 11;
writed(rseg); NL;
writes("Segment boundary register (segb): ");
DELAY(0x2000);
reg = (short)addr->segb;
DELAY(0x2000);
is->boundry = (reg & 0x7800) >> 11;
writed(is->boundry); NL;
if (rseg)
writes("\nWarning: rseg is not pointing at the 1st recv buffer");
if (rseg > is->boundry)
writes("\nWarning: rseg register > segb register");
if (xseg != is->boundry)
writes("\nWarning: tseg register <> segb register");
DELAY(0x10000); /* just to take a break */
return(errcode); /* good return */
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.