rminnichmerge57758a716 years agoHistory
810 lines · 20.7 KB · C
RawDownload
/* * * Copyright (C) 2007-2009, IBM Corporation,  *                     Eric Van Hensbergen (bergevan@us.ibm.com) * * Description: collective network implementation * * All rights reserved * */  /* * notes: *	p. 8	PSRx give header and payload counts *		VCFGx has payload watermark level *		NADDR has 24-bit node address *	p. 10	empty receive FIFO and Dprxf *	p. 11	Dprxf clear-on-read and write 1 to set, Dprxen to enable */ #include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h" #include "ureg.h" #include "bgp_personality.h"#include "bgcns.h"#include "io.h" #define ALIGNED(p, a)	(!(((uintptr)(p)) & ((a)-1))) #define TXBITUSE	0 enum{				/* DCRs */	/* verified from u-boot AND KH*/	Drdr0=	0xc00,	/* source and targets for class 0 and class 1 packets */	Drdr1,			/* classes 2 and 3 */	Drdr2,			/* classes 4 and 5 */	Drdr3,			/* classes 6 and 7 */	Drdr4,			/* classes 8 and 9 */	Drdr5,			/* classes 10 and 11 */	Drdr6,			/* classes 12 and 13 */	Drdr7,			/* classes 14 and 15 */	Disra,			/* Idle Sequence Register bits 0..31 */	Disrb,			/* Idle Sequence Register bits 32..63 */ 	Drcfg=	0xc10,	/* general CNRI router configuration */	Drto,				/* router timeout */	Drtime,			/* router time */	Drstat,			/* router status */	Dhd00,			/* next packet header in channel 0, virtual channel 0 */	Dhd01,			/* ... channel 0, virtual channel 1 */	Dhd10,	Dhd11,	Dhd20,	Dhd21,	Dhdi0,			/* header injection vc0 */	Dhdi1,			/* header injection vc1 */	Dforcec,			/* force route control */	Dforcer,			/* force route */	Dforceh,			/* force route header */	Dxstat,			/* router extended status */	Drstat0 = 0xc20,	Drctrl0,	Dsstat0,	Dsctrl0,	Dtnack0,	Dcnack0,	Dtidle0,	Dcidle0, 	/* from KH */	Dch0ctl=	0xc20,	/* channel 0 control registers */	Dch1ctl=	0xc28,	/* channel 1 */	Dch2ctl=	0xc30,	/* channel 2 */ 	Dfptr= 	0xc40,		/* FIFO pointer */ 	/* verified from u- boot */	/* u-boot has two names for the same things, e.g.:		BGP_DCR_TR_GLOB_NADDR 0xc41		BGP_DCR_TR_GLOB_VCFG0 0xc42		BGP_DCR_TR_GLOB_VCFG1 0xc43		BGP_DCR_TREE_REC 0xc44		BGP_DCR_TR_REC_PRXF 0xc44		BGP_DCR_TREE_REC_PRXEN 0xc45		BGP_DCR_TR_REC_PRXEN 0xc45		BGP_DCR_TREE_INJ 0xc48		BGP_DCR_TR_INJ_PIXF 0xc48		BGP_DCR_TREE_INJ_PIXEN 0xc49		BGP_DCR_TR_INJ_PIXEN 0xc49		BGP_DCR_TREE_INJ_CSPY0 0xc4c		BGP_DCR_TREE_INJ_CSHD0 0xc4d		BGP_DCR_TREE_INJ_CSPY1 0xc4e		BGP_DCR_TREE_INJ_CSHD1 0xc4f	 */ 	Dnaddr = 0xc41,		/* node address (for point to point traffic) */	Dvcfg0,			/* VC0 configuration (fifo watermarks and checksum config) */	Dvcfg1,			/* VC1 configuration */	Dprxf,			/* reception interrupt flags */	Dprxen,			/* reception interrupt enables */	Dpixf = 0xc48,			/* injection interrupt flags */	Dpixen,			/* injection interrupt enables */	Dcspy0 = 0xc4c,			/* VC0 payload checksum */	Dcshd0,			/* VC0 header checksum */	Dcspy1,			/* VC1 payload checksum */	Dcshd1,			/* VC1 header checksum */}; /* Confirmed with KH */enum {	/* Dprxf and Dprxen */	RxP0parity=		IB(8),	/* read on P0 port had bad address parity */	RxP1parity=		IB(9),	RxP0align=		IB(10),	/* read on P0 was not quadword aligned */	RxP1align=		IB(11),	RxP0addr=		IB(12),	/* read on P0 with bad address */	RxP1addr=		IB(13),	RxFIFOcollision=	IB(14),	/* simultaneous reads to same FIFO on P0 and P1 */	RxBadECC=		IB(15),	/* uncorrectable SRAM ECC error */	RxVc0nodata=	IB(26),	/* VC0 payload FIFO underrun (critical) */	RxVc1nodata=	IB(27),	RxVc0nohdr=	IB(28),	/* VC0 header FIFO underrun (critical) */	RxVc1nohdr=	IB(29),	RxVc0mark=	IB(30),	/* VC0 payload FIFO exceeds watermark (critical) */	RxVc1mark=	IB(31), 	/* hardware errors can happen rarely */	RxHwErrors=	RxP0parity | RxP1parity | RxBadECC, 	/* software errors `cannot happen' */	RxSwErrors=	RxP0align | RxP1align | RxP0addr | RxP1addr | RxFIFOcollision |				RxVc0nodata | RxVc1nodata | RxVc0nohdr | RxVc1nohdr,};/* confirmed with KH note that bits 6..9 used to be 8..11 but * moved as the addr error is new*/enum {	/* Dpixf and Dpixen */	TxP0parity=	IB(6),	/* write to P0 port had bad address parity */	TxP1parity=	IB(7),	TxP0align=	IB(8),	/* write to P0 port not quadword aligned */	TxP1align=	IB(9),	TxP0addr=	IB(10),	/* write to P0 port address error*/	TxP1addr=	IB(11),	TxP0data=	IB(12),	/* write to P0 had bad data parity */	TxP1data=	IB(13),	TxFIFOcollision= IB(14),	/* simultaneous writes to same FIFO on P0 and P1 */	TxBadECC=	IB(15),	/* uncorrectable SRAM ECC error */ 	TxVc0overdata=	IB(25),	/* VC0 payload FIFO overflow (critical) */	TxVc1overdata=	IB(26),	TxVc0overhdr=	IB(27),	/* VC0 header FIFO overflow (critical) */	TxVc1overhdr=	IB(28),	TxVc0mark=	IB(29),	/* VC0 payload FIFO below watermark (critical) */	TxVc1mark=	IB(30),	InjectionEnable=	IB(31),	/* =0, injection disabled when Dpixen bit is 0; =1, always enabled */ 	/* hardware errors can happen rarely */	TxHwErrors=	TxP0parity | TxP1parity | TxP0data | TxP1data | TxBadECC, 	/* software errors `cannot happen' */	TxSwErrors=	TxP0align | TxP1align | TxFIFOcollision |				TxVc0overdata | TxVc1overdata | TxVc0overhdr | TxVc1overhdr,}; /* This set of enums confirmed from KH */enum {	/* Drcfg */	Src00dis=		IB(0),	/* disable source channel 0, virtual channel 0 */	Src01dis=		IB(1),	/* disable source channel 0, virtual channel 1 */	Tar00dis=		IB(2),	/* disable target channel 0, virtual channel 0 */	Tar01dis=		IB(3),	/* disable target channel 0, virtual channel 1 */	Src10dis=		IB(4),	/* disable source 1, vc0 */	Src11dis=		IB(5),	/* disable source 1, vc1 */	Tar10dis=		IB(6),	/* disable target 1, vc0 */	Tar11dis=		IB(7),	/* disable target 1, vc1 */	Src20dis=		IB(8),	/* disable source 2, vc0 */	Src21dis=		IB(9),	/* disable source 2, vc1 */	Tar20dis=		IB(10),	/* disable target 2, vc0 */	Tar21dis=		IB(11),	/* disable target 2, vc1 */	C2loop=		IB(25),	/* enable channel 2 loop back */	C1loop=		IB(26),	/* enable channel 1 loop back */	C0loop=		IB(27),	/* enable channel 0 loop back */	Timeout0=	IF(0, 28, 2),	/* no timeout interrupt */	Timeout1=	IF(1, 28, 2),	/* normal timeout */	Timeout2=	IF(2, 28, 2),	/* watchdog timeout */	ManualMode=	IB(30),	/* =0, router is enabled */	RouterReset=	IB(31),	/* full router reset */}; enum {	/* Dvcfg0, Dvcfg1 */	ReceiveAll=	IB(0),	/* =1, receiver accepts all p2p addresses; =0, receiver accepts only Dnaddr */	Ice_m=		IF(~0, 8, 8),	/* injection checksum exclusion (1+number of halfwords at start or end to exclude) */	Rmark_m=	IF(~0, 21, 3),	/* reception fifo watermark: exception when this is exceeded */	Imark_m=	IF(~0, 29, 3),	/* injection fifo watermark: exception when <= this value */}; enum {	Nvc=	2, 	Fifo1Offset		=	0x01000000,	PayloadSize		=	256,	Nquads			=	256 / 16,		/* PayloadSize in quads */	HeaderSize		=	4,		/* four byte destination header */ 	/* non-critical interrupts (index from VectorTree0) */	IrqTimeout=	0,		/* router indicates timeout configured in Drcfg and Drto */	IrqNoTarget=	1,		/* receiver had packet but could not find target */	IrqOverflow=	2,		/* ALU overflow */	IrqTxE=		3,		/* injection exception (non-critical) */	IrqRxE=		4,		/* reception exception (non-critical) */	IrqC0Full=	5,		/* arbiter attempted to route to a full channel 0 */	IrqC0TxECC=	6,		/* non-correctable ECC error when reading vc0 memory */	IrqC0TxCRC=	7,		/* parity error sending on link for channel 0 */	IrqC1Full=	8,		/* arbiter attempted to route to a full channel 1 */	IrqC1TxECC=	9,	IrqC1TxCRC=	10,	IrqC2Full=	11,	IrqC2TxECC=	12,	IrqC2TxCRC=	13,	IrqC0RxECC=	14,		/* receiver of channel 0 found hard ECC error */	IrqC0RxCRC=	15,		/* receiver of channel 0 found parity error */	IrqC1RxECC=	16,	IrqC1RxCRC=	17,	IrqC2RxECC=	18,	IrqC2RxCRC=	19,	IrqTx=		20,	/* injection exception  */	IrqRx=		21,	/* reception exception  */	IrqVc0Intr=	22,	/* packet in vc0 has interrupt bit set */	IrqVc1Intr=	23,	/* packet in vc1 has interrupt bit set */	Nirq,}; /* Confirmed from KH */enum {	/* byte offsets to memory mapped registers */	Mpid=	0x00,		/* data injection FIFO */	Mpih=	0x10,		/* header injection FIFO */	Mprd=	0x20,		/* data receive FIFO */	Mprh=	0x30,		/* header receive FIFO */	Mpsr=	0x40,		/* status register */	Mpsra=	0x50,		/* alias for other channel's status register */}; typedef struct Tchan Tchan;struct Tchan {	int	n;		/* virtual channel number */	int	ionode;	/* !=0, this is an IO node not a cpu node */	u32int	p2paddr;	/* our 20-bit address for p2p traffic */	u32int*	regs;		/* memory mapped registers for this virtual channel */	Lock;	uchar*	quads;	/* quad aligned storage */	Queue*	iq;		/* data from tree */	Queue*	oq;		/* data to tree */	u32int	txbit;	/* TxVc[01]mark */	u32int	rxbit;	/* RxVc[01]mark */	ulong	ntxintr;	ulong	ntxkick;	ulong	nrxintr;	ulong	nrxkick;	ulong	ntx;	ulong	nrx;	/* measurement for time in txkick */	u32int	waitempty;	u32int 	timeempty;	u32int	waitdone;	u32int	timedone;	u32int	dropfull;	u32int	badalign;	/* debug info */	u32int	lastheader;};#define	REG(ctlr, r)	((ctlr)->regs[(r)/sizeof(u32int)]) static int rxfifoempty(Tchan*);static int txfifofull(Tchan*); static Tchan	treechan[Nvc];		/* one for each virtual channel */ char *irqnames[] = {	[IrqTimeout] = "IrqTimeout",	[IrqNoTarget] = "IrqNoTarget",	[IrqOverflow] = "IrqOverflow",	[IrqTxE] = "IrqTxE",	[IrqRxE] = "IrqRxE",	[IrqC0Full] = "IrqC0Full",	[IrqC0TxECC] = "IrqC0TxECC",	[IrqC0TxCRC] = "IrqC0TxCRC",	[IrqC1Full] = "IrqC1Full",	[IrqC1TxECC] = "IrqC1TxECC",	[IrqC1TxCRC] = "IrqC1TxCRC",	[IrqC2Full] = "IrqC2Full",	[IrqC2TxECC] = "IrqC2TxECC",	[IrqC2TxCRC] = "IrqC2TxCRC",	[IrqC0RxECC] = "IrqC0RxECC",	[IrqC0RxCRC] = "IrqC0RxCRC",	[IrqC1RxECC] = "IrqC1RxECC",	[IrqC1RxCRC] = "IrqC1RxCRC",	[IrqC2RxECC] = "IrqC2RxECC",	[IrqC2RxCRC] = "IrqC2RxCRC",	[IrqTx] = "injection exception  ",	[IrqRx] = "reception exception  ",	[IrqVc0Intr] = "packet in vc0 has interrupt bit set ",	[IrqVc1Intr] = "packet in vc1 has interrupt bit set ",}; static longtreestats(int vc, char *buf, long n){	int i;	Tchan *t;	char *p, *e;	u32int r; 	t = &treechan[vc];	p = buf;	e = buf+n; 	p = seprint(p, e, "vc%d: p2paddr %#8.8ux\n", vc, dcrget(Dnaddr));	p = seprint(p, e, "vcfg %#8.8ux rcfg %#8.8ux rstat %#8.8ux\n",		 dcrget(Dvcfg0+vc), dcrget(Drcfg), dcrget(Drstat)); 	r = REG(t, Mpsr); 	p = seprint(p, e, "pixen %#8.8ux ntxintr %lud ntx %lud ntxkick %lud\n",		dcrget(Dpixen), t->ntxintr, t->ntx, t->ntxkick);	p = seprint(p, e, "prxen %#8.8ux nrxintr %lud nrx %lud nrxkick %lud\n",		dcrget(Dprxen), t->nrxintr, t->nrx, t->nrxkick);	p = seprint(p, e, "psr: ipc %d iqw %d ihc %d rpc %d rqw %d rhc %d rpi %d\n",		r>>28, (r>>24)&0x0f, (r>>16)&0x0f,		(r>>12)&0xf, (r>>8)&0x0f,		r&0xf, r&0x10);	p = seprint(p, e, "rto %ud xstat %#8.8ux rxempty %d iqfull %d txfull %d\n",		dcrget(Drto), dcrget(Dxstat), rxfifoempty(t), qfull(t->iq), txfifofull(t)); 	i = vc*8;	p = seprint(p, e, "rstat %#8.8ux rctrl %#8.8ux\n",		dcrget(Drstat0+i), dcrget(Drctrl0+i));	p = seprint(p, e, "sstat %#8.8ux sctrl %#8.8ux\n",		dcrget(Dsstat0+i), dcrget(Dsctrl0+i));	p = seprint(p, e, "tnack %#8.8ux cnack %#8.8ux\n",		dcrget(Dtnack0+i), dcrget(Dcnack0+i));	p = seprint(p, e, "tidle %#8.8ux cidle %#8.8ux\n",		dcrget(Dtidle0+i), dcrget(Dcidle0+i));	p = seprint(p, e, "waitempty %ud timeempty %ud waitdone %ud timedone %ud dropfull %ud badalign %ud\n",		t->waitempty, t->timeempty, t->waitdone, t->timedone, t->dropfull, t->badalign);	p = seprint(p, e, "lastheader %#8.8ux\n", t->lastheader);	return p-buf;} /* * Mpsr: *	0: 7		injection payload count (in 16-byte units); bits 0:3 count complete packets *	12: 15	injection header count (in headers) *	16: 23	reception payload count (in 16-byte units); bits 16: 19 count complete packets *	interrupt request:	IB(27)	at least one packet with Interrupt Request bit set *	28: 31	reception header count (in headers) */static intrxfifoempty(Tchan *ctlr){	/* use the payload count, which is updated last (see p. 8),	   and count only complete packets (p. 17) */	return (REG(ctlr, Mpsr) & IF(~0, 16, 4)) == 0;} static inttxfifofull(Tchan *ctlr){	return (dcrget(Dpixf) & ctlr->txbit) == 0;	/* not <= 7, so it's full */} static voidtxstart(Tchan *t){	Block *b;	int size, psize;	uchar *data;	u32int hdr, r;	ulong start; 	while(qlen(t->oq) > 0){		if(txfifofull(t)){			/* give it a chance to empty, in case we can save an interrupt */			start = perfticks();			for(r = 0; txfifofull(t) && r < 10000; r++)				{}			t->waitempty += r;			t->timeempty += perfticks() - start;			if(txfifofull(t)){				/* give up until there's space */				dcrput(Dpixen, dcrget(Dpixen) | t->txbit);				return;			}		}		b = qget(t->oq);		if(b == nil)			break;		size = BLEN(b)-4;		if(size <= 0){			freeb(b);			continue;		}		hdr = (b->rp[0]<<24)|(b->rp[1]<<16)|(b->rp[2]<<8)|b->rp[3];		b->rp += 4;		if(size < PayloadSize || !ALIGNED(b->rp, 16)){			/* need the bounce buffer */			data = t->quads;			if(size < PayloadSize){				psize = PayloadSize-size;				memset(data+size, 0, psize);				data[PayloadSize-1] = psize;				/* TO DO: set a bit in the header to mark a short packet */			}else if(size > PayloadSize)				size = PayloadSize;			memmove(data, b->rp, size);			t->badalign++;		}else			data = b->rp;		/*		 *  the book says order of writing data, hdr is immaterial. That said, I'm having		 * better luck writing data first, then hdr		 */		quad2fifo(&REG(t, Mpid), data, Nquads);		REG(t, Mpih) = hdr;		freeb(b);		t->lastheader = hdr;		t->ntx++;	}	/* clear request for interrupt on low watermark */	r = dcrget(Dpixen);	if(r & t->txbit)		dcrput(Dpixen, r & ~t->txbit);} static void chanreceive(Tchan*); static voidrxkick(void *a){	Tchan *t; 	t = a;	ilock(t);	dcrput(Dprxen, dcrget(Dprxen) | t->rxbit);	/* TO DO: this should probably go elsewhere */	t->nrxkick++;	iunlock(t);	chanreceive(t);} static voidchanreceive(Tchan *t){	u8int len;	u32int hdr;	Block *b; 	ilock(t);	t->nrxintr++; 	while(!rxfifoempty(t) && !qfull(t->iq)){		b = iallocb(PayloadSize + 16);	/* b->wp will be quad-aligned */		hdr = REG(t, Mprh);		b->wp += 12;		/* skip over these to keep payload data aligned after 4 byte header */		b->rp = b->wp;		b->wp[0] = hdr>>24;		b->wp[1] = hdr>>16;		b->wp[2] = hdr>>8;		b->wp[3] = hdr;		fifo2quad(b->wp+4, &REG(t, Mprd), Nquads);	/* it's quad aligned */		b->wp += PayloadSize+4;		if(t->n == 1){ 				/* IP network */			qpassnolim(t->iq, b);		}		else if(sys->ionode){			/* null terminated for now. Later on, we *could* make b->rp[0] the len */			/* we don't need the header that tells us it is for us */			b->rp += 4;			len = strlen((char*)b->rp);			b->wp = b->rp + len;			qpassnolim(t->iq, b);		}		else{ /* we are a CPU node, it's from an IO node */			/* we don't need the header that tells us it is for us */			b->rp += 4;			len = strlen((char*)b->rp);			b->wp = b->rp + len;			//treedumpblock(b, "qnetC");			qpassnolim(t->iq, b);		}		t->nrx++;	}	if(qfull(t->iq)){		/* disable receive interrupt until kicked */		dcrput(Dprxen, dcrget(Dprxen) & ~t->rxbit);	}	iunlock(t);}

Lines 1–500 of 810.