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 + -
显示快捷键?