2362 lines · 61.5 KB · C
RawDownload
/* * * Copyright (C) 2007-2009, IBM Corporation,  *                     Eric Van Hensbergen (bergevan@us.ibm.com) * * Description: torus device interface * * All rights reserved * */ /* * TO DO *	+ ilocks on tx/rx state (eg, for SMP) *	- `reception descriptor' is misleading: it's a block of chunks filled as a fifo *          will need to do something for variable-length packets *	- fifo map (eg, set_inj_fifo_map) *	- set or inspect hint bits to determine routing *	- self-addressed messages *	+ check each software ring against interrupt state instead of scanning bit sets *	+ eliminate in32/out32 for memory-mapped access *	- inspect and eliminate values from torus.h */ #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" #include "frag.h" /* Torus definitions from Linux which might need to be cleaned up */#include "torus.h" #define NEXT(x, l)	(((x)+1)%(l))#define PREV(x, l)	(((x) == 0) ? (l)-1: (x)-1) enum {						/* DCRs (page 23) */	Dreset		= 0xd00,	/* DMA Reset */	Dbasectl	= 0xd01,	/* Base Controls */	Didmamin	= 0xd02,	/* Injection Min Valid Addr */	Didmamax	= 0xd03,	/* Injection Max Valid Addr */	Didmatlb	= 0xd12,	/* Injection Range TLB Attributes */	Drdmatlb	= 0xd13,	/* Reception Range TLB Attributes */	Drdmamin	= 0xd14,	/* Reception Min Valid Addr */	Drdmamax	= 0xd15,	/* Reception Max Valid Addr */	Dififowm0	= 0xd24,	/* Torus fifo injection threshold */	Dififowm1	= 0xd25,	/* Torus fifo injection threshold */	Dilocalwm0	= 0xd26,	/* Local inj fifo threshold */	Drfifowm0	= 0xd27,	/* Torus fifo reception threshold */	Drlocalwm0	= 0xd2b,	/* Local rec fifo threshold */	Dififoctl	= 0xd2c,	/* Injection fifo enable */	Drfifoctl	= 0xd30,	/* Reception fifo enable */	Dififopri	= 0xd32,	/* Injection fifo priority */	Diquanta	= 0xd37,	/* Injection Service Quanta */	Drthresh	= 0xd3a,	/* Threshold for recv fifo type 0 (type 1 next) */	Dififomap	= 0xd3c,	/* imFifo to torus inj fifo map */	Dififolocal	= 0xd5c,	/* imFifo is used for local copies */	Drfifomap0	= 0xd60,	/* reception fifo to rmfifo map */	Drfifomap1	= 0xd61,	/* reception fifo to rmfifo map */	Drclrmask	= 0xd68,	/* Recption DMA Fifo Clear enable */	Drhdrclrmask= 0xd6c,	/* Reception DMA header fifo clear */	Drintron	= 0xd71,	/* Reception fifo intr enable */	Dichzintron	= 0xd76,	/* Injection Ctr Hits Zero Intr Enable */	Dfatalon	= 0xd7e,	/* Fatal Error Enable 0 */	Derrthresh	= 0xd89,	/* Thresholds for SRAM ECC errors */	Dififoce	= 0xd8a,	/* Injection fifo ce (start/end) */	Dclear0		= 0xdb1,	/* Clear_0 */	Dclear1		= 0xdb2,	/* Clear_1 */}; enum {						/* Dbasectl */	Rusedma		= IB(0),	/* =1, use DMA; =0, core does the work */	Rstorehdr	= IB(1),	/* =1, store DMA headers in FIFO (debug) */	Rnoprefetch	= IB(2),	/* =1, disable torus prefetch (0 is default) */	RL3burst	= IB(3),	/* enable burst reads to L3 */	Rinjenable	= IB(4),	/* enable injection unit */	Rrcvenable	= IB(5),	/* enable reception unit */	Rimfuenable	= IB(6),	/* enable imfu_arb fifo/counter */	Rrmfuenable	= IB(7),	/* enable rmfu_arb fifo/counter */	RL3noprefetch= IB(8),	/* disable L3 read prefetch for DMA */	Rrdmastop	= IB(28),	/* =1, rdma stop when fifo full; =0, rdma retry when full */	Rrcvsticky	= IB(29),	/* =1, fifo cross threshold not sticky; =0, is sticky (default) */	Rinjsticky	= IB(30),	/* =1, fifo cross threshold not sticky, ... */}; enum {	X		= 0,			/* dimension */	Y		= 1,	Z		= 2,	N		= 3, 	Xp		= 0,			/* direction */	Xm		= 1,	Yp		= 2,	Ym		= 3,	Zp		= 4,	Zm		= 5,	Nd		= 6, 	Hp		= 7,}; enum {	Torushdrlen=	8,	/* hardware header only */	Tpkthdrlen=		16,	/* both hardware and software headers */ 	PayloadSize	= 256-Tpkthdrlen,	Chunk		= 32,			/* Chunk size (bytes) for size field */	Quad		= 16,			/* 128 bits */ 	Ngroup		= 4,			/* groups */	Ninjfifo	= 32,			/* injection fifos (per group) */	Nrcvfifo	= 8,			/* receive fifos (per group) */	Ncounter	= 64,			/* counters per group, for each of injection and reception */	Npid		= 4,			/* [Pid0, Pid1] */	Nregion		= 8,			/* DMA regions (mainly for put/get modes) */ 	/* software choices */	Ntx			= 256,		/* injection fifo entries */	Nrx			= 512,		/* reception fifo entries */ 	KernelGroup		= Ngroup-1,		/* arbitrary, until ron gets started */	KernelPid		= Npid-1,	KernelTxFifo	= Ninjfifo-1,	KernelRxFifo	= Nrcvfifo-1,	KernelRxRegion	= Nregion-1,	/* not really used, see init_rx_queue below */}; /* * Normal (memory FIFO mode) packet header. * The hardware requires an 8-byte header * of which the last two bytes are reserved (they contain a sequence * number and a header checksum inserted by the hardware). * The next 8 bytes are a software header in memory FIFO * mode, which we use for the fragmentation header, * but other formats are possible in the direct-put/remote-get modes. */typedef struct Tpkt Tpkt;struct Tpkt {	/* hardware header */	u8int	sk;					/* Skip Checksum Control */	u8int	hint;				/* Hint|Dp|Pid0 */	u8int	size;				/* Size|Pid1|Dm|Dy|VC */	u8int	dst[N];				/* Destination Coordinates */	u8int	_6_[2];				/* reserved */ 	/* hardware and software headers */	union{		struct{	/* direct-put DMA mode */			u8int	paoff[4];		/* put address offset (updated by hw for large packets) */			u8int	rdma;		/* RDMA counter ID */			u8int	valid;		/* valid bytes in payload (updated by hw) */			u8int	rgflags;		/* remote get flags */			u8int	idma;		/* IDMA FIFO ID */		};		struct{	/* memory FIFO mode */			u8int	putoff[4];		/* put offset (updated by hw) */			u8int	other[4];		/* software */		};		Hdr;		/* our software header (frag.h), variant of memory FIFO */	};	u8int	payload[];}; /* * SKIP is a field in .sk giving the number of 2-bytes * to skip from the top of the packet before including * the packet bytes into the running checksum. * SIZE is a field in .size giving the size of the * packet in 32-byte 'chunks'. * * I realize using this format for the bitfields is * overkill, but bear with me for consistency. */#define SKIP(n)		F(n, 1, 7)#define SIZE(n)		F(n, 5, 3)#define PID0(n)	((n)&2? Pid0: 0)#define PID1(n)	((n)&1? Pid1: 0) enum {	Sk		= 0x01,			/* Skip Checksum */ 	Pid0	= 0x01,			/* Destination Group FIFO MSb */	Dp		= 0x02,			/* Multicast Deposit */	Hzm		= 0x04,			/* Z- Hint */	Hzp		= 0x08,			/* Z+ Hint */	Hym		= 0x10,			/* Y- Hint */	Hyp		= 0x20,			/* Y+ Hint */	Hxm		= 0x40,			/* X- Hint */	Hxp		= 0x80,			/* X+ Hint */ 	Vcd0	= 0x00,			/* Dynamic 0 VC */	Vcd1	= 0x01,			/* Dynamic 1 VC */	Vcbn	= 0x02,			/* Deterministic Bubble VC */	Vcbp	= 0x03,			/* Deterministic Priority VC */	Dy		= 0x04,			/* Dynamic Routing */	Dm		= 0x08,			/* DMA Mode */	Pid1	= 0x10,			/* Destination Group FIFO LSb */}; /* * Reception FIFO is a ring of full packets with hw/sw headers */typedef union Rcvbuf Rcvbuf;union Rcvbuf {	Tpkt;	u8int packet[256];}; /* * Injection descriptors (p. 14) * * Injection FIFO is a ring of DMA control data * (with reference to payload) and packet headers, * payload elsewhere */typedef struct Injdesc Injdesc;struct Injdesc {	u32int	flags;		/* low-order byte: B(0)-B(5) unused; */						/* B(6) pre-fetch on local memmove; */						/* B(7) 1=local, 0=torus */	u32int	counter;	/* low-order byte: injection counter ID */	u32int	base;		/* base physical address (>>4) of payload */	u32int	length;		/* count in bytes */	Tpkt	hdrs;		/* MAC-level header, then software header */}; /* * Injection and Reception FIFO (ring) */typedef struct Fifo Fifo;struct Fifo {	u32int	start;		/* 32-byte aligned */	u32int	end;	u32int	head;		/* 16-byte aligned */	u32int	tail;		/* address to write new descriptor (host owned) */}; /* * DMA Fifos are controlled through a memory-mapped region */typedef struct Fifoctl Fifoctl;struct Fifoctl {	struct {		Fifo	fifo[Ninjfifo];				// 0 - 1ff		u32int	empty;						// 200		u32int	__unused0;					// 204		u32int	avail;						// 208		u32int	__unused1;					// 20c		u32int	threshold;					// 210		u32int	__unused2;					// 214		u32int	clear_threshold;			// 218		u32int	__unused3;					// 21c		u32int	dma_active;					// 220		u32int	dma_activate;				// 224		u32int	dma_deactivate;				// 228		u8int	__unused4[0x100-0x2c];		// 22c - 2ff 		u32int	counter_enabled[2];			// 300		u32int	counter_enable[2];			// 308		u32int	counter_disable[2];			// 310		u32int	__unused5[2];				// 318		u32int	counter_hit_zero[2];		// 320		u32int	counter_clear_hit_zero[2];	// 328		u32int	counter_group_status;		// 330		u8int	__unused6[0x400-0x334];		// 334 - 3ff 		struct {			u32int	counter;			u32int	increment;			u32int	base;			u32int	__unused;		} counter[Ncounter];				// 400 - 7ff	} inj; 	struct {		Fifo	fifo[Nrcvfifo+1];			// 800 - 87f (rcv fifos), 											// 880-88f (special header fifo)		u8int	__unused0[0x900-0x890];		// 890 - 900 		u32int	glob_ints[16];				// 900 - 93f		u8int	__unused1[0xa00-0x940];		// 940 - 9ff 		u32int	notempty[2];				// a00		u32int	available[2];				// a08		u32int	threshold[2];				// a10		u32int	clear_threshold[2];			// a18		u8int	__unused2[0xb00 - 0xa20];	// a20 - aff 		u32int	counter_enabled[2];			// b00		u32int	counter_enable[2];			// b08		u32int	counter_disable[2];			// b10		u32int	__unused3[2];				// b18		u32int	counter_hit_zero[2];		// b20		u32int	counter_clear_hit_zero[2];	// b28		u32int	counter_group_status;		// b30		u8int	__unused4[0xc00 - 0xb34];	// b34 - bff				struct {			u32int	counter;			u32int	increment;			u32int	base;			u32int	limit;		} counter[Ncounter];				// c00 - fff	} rcv;}; /* Software structure to help track tx/rx rings */typedef struct TxRing TxRing;struct TxRing {//	Lock	lock; 	uint	active;	Injdesc*	desc;		/* descriptor ring (in virtual space) */	Block	**blocks;		/* blocks currently on ring */	Fifo*	fifo;			/* hardware memory fifo assigned to ring */	u32int	start;			/* main memory copy of fifo->start */	uint	tail_idx;	uint	pending_idx; 	u32int*	incr;		/* address of increment register for counter */	u32int	ctrid;		/* counter ID for descriptor (group<<6 | fifo-index) */ 	int	ntd;			/* number of transmit descriptors */	int	np;				/* number of packets in fifo */		int full;			/* number of times the txring was full */		QLock	rl;	Rendez	r;		/* wait for free space */ 	int	group;	int	index;	TxRing*	next;}; typedef struct RxRing RxRing;struct RxRing {//	Lock	lock; 	uint	active;	Rcvbuf*	desc;		/* packet buffer ring (in virtual space) */	Fifo*	fifo;		/* hardware memory fifo assigned to ring */	u32int	start;		/* main memory copy of fifo->start */	uint	head_idx; 	/* statistics */	u32int	dropped;	u32int	delivered; 	int	nrd;			/* number of reception descriptors */ 	int	group;	int	index;	RxRing*	next;}; typedef struct Torus Torus;struct Torus {	u8int	addr[N];		/* of this node */	u8int	size[N];		/* of the torus */	u8int	torus[N];		/* in that dimension (!mesh) */	u8int	cp[N];			/* cutoff in [XYZ]p */	u8int	cm[N];			/* cutoff in [XYZ]m */ 	u32int	zmzpymypxmxp;	/* reset FIFOs */	u32int	xpxmypymzpzm;	/* ditto, in IBM field order */ 	QLock	alock;	int	ref; 	Queue*	rcvq; 	/*	 * these counters will need to become per DMA group	 * (eg, in TxRing or RxRing) when more than one fifo is used,	 * to allow concurrent access	 */	uint	rcvintr;	uint	rcvpackets;	uint	rcvtoss;	uint	rcvqfull;	uint	rcvqpass;	uint	rcvqbread;	uint	rcvqread;	uint	rcvpause;	uint	rcvresume;	uint  rcvring;	uint  rcvringdrop;	uint	aror;	uint	activemsg;	uint	activemsgreply;	uint	activemsgmm;	/* last active message x,y,z -- since iprint does not work */	uint ax, ay, az;	uint	lastactiveptr;	uint	injintr;	uint	injgetfifo;	uint	injgetstatus;	uint  injring;	uint	memfifofull;	uint	unreachable;	uint	self;	uint	injpackets;	uint	unaligned; 	Fifoctl*	dma;				/* pointer to memory-mapped hw control structure */	TxRing	txr[Ngroup][Ninjfifo];	/* software data for injection */	RxRing	rxr[Ngroup][Nrcvfifo];	/* software data for reception */ 	Lock	txlock;					/* protect all groups for now */	Lock	rxlock;					/* protect all groups for now */ 	/* reception counters aren't needed for memory FIFO mode */ 	Frags*	frags;}; enum {	DbgRingR=	1<<5,	DbgRingX=	1<<4,	DbgDMA=	1<<2,	DbgSetup=	1<<1,	DbgIO=		1<<0,}; typedef struct Ring Ring; struct Ring {	u32int tag[3];	void *userdata; /* for irecv */	u32int count; /* number of units; bytecount is computed using datatype*/	u32int datatype;	u32int source;	u32int itag;	u32int comm;	u32int status;	u32int xmit; /* if this was an xmit request. */	u32int done;	u32int x, y, z;}; struct Ringb {	u8int *base;	int count;}; /* active message ring.  * received messages from kernel  increment prod * processes eat messages and increment con * if prod-cons is ever > size, then the kernel does two things:  * 1. no longer dq messages, so that nobody can send us any -- this back pressure will  * back up to senders via the torus hardware * 2. no longer allow messages to be sent. You have to be a good boy.  * We'll see how this goes. But for the breadth first search we have to do something like this * as their current code is not scalable -- they allocate a buffer per mpi rank, and that  * just won't do.  I pad to make sure we don't get cache wars -- procs run on core > 0. * ROUND 1: no flow control as described -- let's just go for bandwidth and see what we get.  * it need not be high -- latency is more important just now.  */struct AmRing {        u8int *base;        int size;        int prod;        u8int _116[128-12];        int con;        u8int _124[128-4];}; /* active messages -- if this is on, the rx interrupt will manage the message and not enqueue it *//* enabled by writing a to /dev/torusctl and disabled by writing i to /dev/torusctl */int activemessages = 0; struct AmRing *activering;static u8int *onering = nil;static int ringsize;static int debug_torus = 1; static Torus torus;int torus_dump_cons = 1; static void torusdisable(int cause);static void torusinject(Torus*, TxRing*, Block*);static int quicktorusinject(Torus *t, TxRing *tx, Tpkt *pkt, void *data, int kaddr, int block); /* sorry for the ugliness, I'll search and replace it eventually */#define DUMP_DCR(desc, x) p = seprint(p, e, " " desc "(%ux): %ux\n", (unsigned int)x, dcrget(x)) typedef struct Dcr Dcr;struct Dcr {	u32int	dcr;

Lines 1–500 of 2362.