midway.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,376 行 · 第 1/5 页

C
2,376
字号
/*	$NetBSD: midway.c,v 1.30 1997/09/29 17:40:38 chuck Exp $	*//*	(sync'd to midway.c 1.68)	*//* * * Copyright (c) 1996 Charles D. Cranor and Washington University. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *      This product includes software developed by Charles D. Cranor and *	Washington University. * 4. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *//* * * m i d w a y . c   e n i 1 5 5   d r i v e r  * * author: Chuck Cranor <chuck@ccrc.wustl.edu> * started: spring, 1996 (written from scratch). * * notes from the author: *   Extra special thanks go to Werner Almesberger, EPFL LRC.   Werner's *   ENI driver was especially useful in figuring out how this card works. *   I would also like to thank Werner for promptly answering email and being *   generally helpful. */#undef	EN_DEBUG#undef	EN_DEBUG_RANGE		/* check ranges on en_read/en_write's? */#define	EN_MBUF_OPT		/* try and put more stuff in mbuf? */#define	EN_DIAG#define	EN_STAT#ifndef EN_DMA#define EN_DMA		1	/* use dma? */#endif#define EN_NOTXDMA	0	/* hook to disable tx dma only */#define EN_NORXDMA	0	/* hook to disable rx dma only */#define EN_DDBHOOK	1	/* compile in ddb functions */#if defined(MIDWAY_ADPONLY)#define EN_ENIDMAFIX	0	/* no ENI cards to worry about */#else#define EN_ENIDMAFIX	1	/* avoid byte DMA on the ENI card (see below) */#endif/* * note on EN_ENIDMAFIX: the byte aligner on the ENI version of the card * appears to be broken.   it works just fine if there is no load... however * when the card is loaded the data get corrupted.   to see this, one only * has to use "telnet" over ATM.   do the following command in "telnet": * 	cat /usr/share/misc/termcap * "telnet" seems to generate lots of 1023 byte mbufs (which make great * use of the byte aligner).   watch "netstat -s" for checksum errors. *  * I further tested this by adding a function that compared the transmit  * data on the card's SRAM with the data in the mbuf chain _after_ the  * "transmit DMA complete" interrupt.   using the "telnet" test I got data * mismatches where the byte-aligned data should have been.   using ddb * and en_dumpmem() I verified that the DTQs fed into the card were  * absolutely correct.   thus, we are forced to concluded that the ENI * hardware is buggy.   note that the Adaptec version of the card works * just fine with byte DMA. * * bottom line: we set EN_ENIDMAFIX to 1 to avoid byte DMAs on the ENI * card. */#if defined(DIAGNOSTIC) && !defined(EN_DIAG)#define EN_DIAG			/* link in with master DIAG option */#endif#ifdef EN_STAT#define EN_COUNT(X) (X)++#else#define EN_COUNT(X) /* nothing */#endif#ifdef EN_DEBUG#undef	EN_DDBHOOK#define	EN_DDBHOOK	1#define STATIC /* nothing */#define INLINE /* nothing */#else /* EN_DEBUG */#define STATIC static#define INLINE __inline#endif /* EN_DEBUG */#ifdef __FreeBSD__#include "en.h"#include "opt_inet.h"#include "opt_natm.h"#include "opt_ddb.h"/* enable DDBHOOK when DDB is available */#undef	EN_DDBHOOK#ifdef DDB#define	EN_DDBHOOK	1#endif#endif#if NEN > 0 || !defined(__FreeBSD__)#include <sys/param.h>#include <sys/systm.h>#include <sys/queue.h>#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__)#include <sys/device.h>#endif#include <sys/sockio.h>#include <sys/malloc.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/proc.h>#include <net/if.h>#include <net/if_atm.h>#include <vm/vm.h>#if defined(INET) || defined(INET6)#include <netinet/in.h>#include <netinet/if_atm.h>#endif#ifdef NATM#include <netnatm/natm.h>#endif#if !defined(sparc) && !defined(__FreeBSD__)#include <machine/bus.h>#endif#if defined(__NetBSD__) || defined(__OpenBSD__)#include <dev/ic/midwayreg.h>#include <dev/ic/midwayvar.h>#if defined(__alpha__)/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */#undef vtophys#define	vtophys(va)	alpha_XXX_dmamap((vm_offset_t)(va))#endif#elif defined(__FreeBSD__)#include <machine/clock.h>              /* for DELAY */#include <dev/en/midwayreg.h>#include <dev/en/midwayvar.h>#include <vm/pmap.h>			/* for vtophys proto */#ifndef IFF_NOTRAILERS#define IFF_NOTRAILERS 0#endif#endif	/* __FreeBSD__ */#include "bpfilter.h"#if NBPFILTER > 0#include <net/bpf.h>#ifdef __FreeBSD__#define BPFATTACH(ifp, dlt, hlen)	bpfattach((ifp), (dlt), (hlen))#define BPF_MTAP(ifp, m)		bpf_mtap((ifp), (m))#else#define BPFATTACH(ifp, dlt, hlen)	bpfattach(&(ifp)->if_bpf, (ifp), (dlt), (hlen))#define BPF_MTAP(ifp, m)		bpf_mtap((ifp)->if_bpf, (m))#endif#endif /* NBPFILTER > 0 *//* * params */#ifndef EN_TXHIWAT#define EN_TXHIWAT	(64*1024)	/* max 64 KB waiting to be DMAd out */#endif#ifndef EN_MINDMA#define EN_MINDMA	32	/* don't DMA anything less than this (bytes) */#endif#define RX_NONE		0xffff	/* recv VC not in use */#define EN_OBHDR	ATM_PH_DRIVER7  /* TBD in first mbuf ! */#define EN_OBTRL	ATM_PH_DRIVER8  /* PDU trailier in last mbuf ! */#define ENOTHER_FREE	0x01		/* free rxslot */#define ENOTHER_DRAIN	0x02		/* almost free (drain DRQ dma) */#define ENOTHER_RAW	0x04		/* 'raw' access  (aka boodi mode) */#define ENOTHER_SWSL	0x08		/* in software service list */static int en_dma = EN_DMA;		/* use DMA (switch off for dbg) *//* * autoconfig attachments */struct cfdriver en_cd = {    0, "en", DV_IFNET,};/* * local structures *//* * params to en_txlaunch() function */struct en_launch {  u_int32_t tbd1;		/* TBD 1 */  u_int32_t tbd2;		/* TBD 2 */  u_int32_t pdu1;		/* PDU 1 (aal5) */  int nodma;			/* don't use DMA */  int need;			/* total space we need (pad out if less data) */  int mlen;			/* length of mbuf (for dtq) */  struct mbuf *t;		/* data */  u_int32_t aal;		/* aal code */  u_int32_t atm_vci;		/* vci */  u_int8_t atm_flags;		/* flags */};/* * dma table (index by # of words) * * plan A: use WMAYBE (obsolete) * plan B: avoid WMAYBE */struct en_dmatab {  u_int8_t bcode;		/* code */  u_int8_t divshift;		/* byte divisor */};static struct en_dmatab en_dma_planB[] = {  { 0, 0 },		/* 0 */		{ MIDDMA_WORD, 2},	/* 1 */  { MIDDMA_2WORD, 3},	/* 2 */		{ MIDDMA_WORD, 2},	/* 3 */  { MIDDMA_4WORD, 4},	/* 4 */		{ MIDDMA_WORD, 2},	/* 5 */  { MIDDMA_2WORD, 3},	/* 6 */		{ MIDDMA_WORD, 2},	/* 7 */  { MIDDMA_8WORD, 5},   /* 8 */		{ MIDDMA_WORD, 2},	/* 9 */  { MIDDMA_2WORD, 3},	/* 10 */	{ MIDDMA_WORD, 2},	/* 11 */  { MIDDMA_4WORD, 4},	/* 12 */	{ MIDDMA_WORD, 2},	/* 13 */  { MIDDMA_2WORD, 3},	/* 14 */	{ MIDDMA_WORD, 2},	/* 15 */  { MIDDMA_16WORD, 6},  /* 16 */};static struct en_dmatab *en_dmaplan = en_dma_planB;/* * prototypes */STATIC INLINE	int en_b2sz __P((int)) __attribute__ ((unused));#ifdef EN_DDBHOOK		int en_dump __P((int,int));		int en_dumpmem __P((int,int,int));#endifSTATIC		void en_dmaprobe __P((struct en_softc *));STATIC		int en_dmaprobe_doit __P((struct en_softc *, u_int8_t *, 		    u_int8_t *, int));STATIC INLINE	int en_dqneed __P((struct en_softc *, caddr_t, u_int,		    u_int)) __attribute__ ((unused));STATIC		void en_init __P((struct en_softc *));STATIC		int en_ioctl __P((struct ifnet *, EN_IOCTL_CMDT, caddr_t));STATIC INLINE	int en_k2sz __P((int)) __attribute__ ((unused));STATIC		void en_loadvc __P((struct en_softc *, int));STATIC		int en_mfix __P((struct en_softc *, struct mbuf **,		    struct mbuf *));STATIC INLINE	struct mbuf *en_mget __P((struct en_softc *, u_int,		    u_int *)) __attribute__ ((unused));STATIC INLINE	u_int32_t en_read __P((struct en_softc *,		    u_int32_t)) __attribute__ ((unused));STATIC		int en_rxctl __P((struct en_softc *, struct atm_pseudoioctl *,		    int));STATIC		void en_txdma __P((struct en_softc *, int));STATIC		void en_txlaunch __P((struct en_softc *, int,		    struct en_launch *));STATIC		void en_service __P((struct en_softc *));STATIC		void en_start __P((struct ifnet *));STATIC INLINE	int en_sz2b __P((int)) __attribute__ ((unused));STATIC INLINE	void en_write __P((struct en_softc *, u_int32_t,		    u_int32_t)) __attribute__ ((unused));/* * macros/inline *//* * raw read/write macros */#define EN_READDAT(SC,R) en_read(SC,R)#define EN_WRITEDAT(SC,R,V) en_write(SC,R,V)/* * cooked read/write macros */#define EN_READ(SC,R) ntohl(en_read(SC,R))#define EN_WRITE(SC,R,V) en_write(SC,R, htonl(V))#define EN_WRAPADD(START,STOP,CUR,VAL) { \	(CUR) = (CUR) + (VAL); \	if ((CUR) >= (STOP)) \		(CUR) = (START) + ((CUR) - (STOP)); \	}#define WORD_IDX(START, X) (((X) - (START)) / sizeof(u_int32_t))/* we store sc->dtq and sc->drq data in the following format... */#define EN_DQ_MK(SLOT,LEN) (((SLOT) << 20)|(LEN)|(0x80000))					/* the 0x80000 ensures we != 0 */#define EN_DQ_SLOT(X) ((X) >> 20)#define EN_DQ_LEN(X) ((X) & 0x3ffff)/* format of DTQ/DRQ word 1 differs between ENI and ADP */#if defined(MIDWAY_ENIONLY)#define MID_MK_TXQ(SC,CNT,CHAN,END,BCODE) \	EN_WRITE((SC), (SC)->dtq_us, \		MID_MK_TXQ_ENI((CNT), (CHAN), (END), (BCODE))); #define MID_MK_RXQ(SC,CNT,VCI,END,BCODE) \	EN_WRITE((SC), (SC)->drq_us, \		MID_MK_RXQ_ENI((CNT), (VCI), (END), (BCODE))); #elif defined(MIDWAY_ADPONLY)#define MID_MK_TXQ(SC,CNT,CHAN,END,JK) \	EN_WRITE((SC), (SC)->dtq_us, \		MID_MK_TXQ_ADP((CNT), (CHAN), (END), (JK))); #define MID_MK_RXQ(SC,CNT,VCI,END,JK) \	EN_WRITE((SC), (SC)->drq_us, \		MID_MK_RXQ_ADP((CNT), (VCI), (END), (JK))); #else#define MID_MK_TXQ(SC,CNT,CHAN,END,JK_OR_BCODE) { \	if ((SC)->is_adaptec) \	  EN_WRITE((SC), (SC)->dtq_us, \		  MID_MK_TXQ_ADP((CNT), (CHAN), (END), (JK_OR_BCODE))); \	else \	  EN_WRITE((SC), (SC)->dtq_us, \		  MID_MK_TXQ_ENI((CNT), (CHAN), (END), (JK_OR_BCODE))); \	}#define MID_MK_RXQ(SC,CNT,VCI,END,JK_OR_BCODE) { \	if ((SC)->is_adaptec) \	  EN_WRITE((SC), (SC)->drq_us, \		  MID_MK_RXQ_ADP((CNT), (VCI), (END), (JK_OR_BCODE))); \	else \	  EN_WRITE((SC), (SC)->drq_us, \		   MID_MK_RXQ_ENI((CNT), (VCI), (END), (JK_OR_BCODE))); \	}#endif/* add an item to the DTQ */#define EN_DTQADD(SC,CNT,CHAN,JK_OR_BCODE,ADDR,LEN,END) { \	if (END) \	  (SC)->dtq[MID_DTQ_A2REG((SC)->dtq_us)] = EN_DQ_MK(CHAN,LEN); \	MID_MK_TXQ(SC,CNT,CHAN,END,JK_OR_BCODE); \	(SC)->dtq_us += 4; \	EN_WRITE((SC), (SC)->dtq_us, (ADDR)); \	EN_WRAPADD(MID_DTQOFF, MID_DTQEND, (SC)->dtq_us, 4); \	(SC)->dtq_free--; \	if (END) \	  EN_WRITE((SC), MID_DMA_WRTX, MID_DTQ_A2REG((SC)->dtq_us)); \}/* DRQ add macro */#define EN_DRQADD(SC,CNT,VCI,JK_OR_BCODE,ADDR,LEN,SLOT,END) { \	if (END) \	  (SC)->drq[MID_DRQ_A2REG((SC)->drq_us)] = EN_DQ_MK(SLOT,LEN); \	MID_MK_RXQ(SC,CNT,VCI,END,JK_OR_BCODE); \	(SC)->drq_us += 4; \	EN_WRITE((SC), (SC)->drq_us, (ADDR)); \	EN_WRAPADD(MID_DRQOFF, MID_DRQEND, (SC)->drq_us, 4); \	(SC)->drq_free--; \	if (END) \	  EN_WRITE((SC), MID_DMA_WRRX, MID_DRQ_A2REG((SC)->drq_us)); \}/* * the driver code * * the code is arranged in a specific way: * [1] short/inline functions * [2] autoconfig stuff * [3] ioctl stuff * [4] reset -> init -> trasmit -> intr -> receive functions * *//***********************************************************************//* * en_read: read a word from the card.   this is the only function * that reads from the card. */STATIC INLINE u_int32_t en_read(sc, r)struct en_softc *sc;u_int32_t r;{#ifdef EN_DEBUG_RANGE  if (r > MID_MAXOFF || (r % 4))    panic("en_read out of range, r=0x%x", r);#endif  return(bus_space_read_4(sc->en_memt, sc->en_base, r));}/* * en_write: write a word to the card.   this is the only function that * writes to the card. */STATIC INLINE void en_write(sc, r, v)struct en_softc *sc;u_int32_t r, v;{#ifdef EN_DEBUG_RANGE  if (r > MID_MAXOFF || (r % 4))    panic("en_write out of range, r=0x%x", r);#endif  bus_space_write_4(sc->en_memt, sc->en_base, r, v);}/* * en_k2sz: convert KBytes to a size parameter (a log2) */STATIC INLINE int en_k2sz(k)int k;{  switch(k) {    case 1:   return(0);    case 2:   return(1);    case 4:   return(2);    case 8:   return(3);    case 16:  return(4);    case 32:  return(5);    case 64:  return(6);    case 128: return(7);    default: panic("en_k2sz");  }  return(0);}#define en_log2(X) en_k2sz(X)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?