Annotation of coherent/f/etc/conf/streams/src/ether.c, revision 1.1.1.1

1.1       root        1: /* STREAMS style driver for the DP8390 Ethernet interface */
                      2: /*
                      3:  * An interesting problem is how to manage the interface address binding,
                      4:  * especially for upper protocols (specifically, the Internet ARP protocol)
                      5:  * that need to advertise the physical host address, especially in the
                      6:  * presence of multiple hardware adapters (or network types).
                      7:  *
                      8:  * For now, I am happy with having a specific version of ARP for each network
                      9:  * type, and having ARP catch any M_PROTO SP_BIND messages going past.
                     10:  */
                     11: #include <sys/kernel.h>
                     12: #include <sys/dma.h>
                     13: #include <sys/stream.h>
                     14: #include <sys/strmlib.h>
                     15: #include <sys/strproto.h>
                     16: #include <sys/dp8390.h>
                     17: #include <sys/ether.h>
                     18: #include <sys/ints.h>
                     19: #include <sys/netstuff.h>
                     20: #include <string.h>
                     21: 
                     22: /*
                     23:  * Allow up to 8 minor devices connected to us - each one receives a copy of
                     24:  * all incoming traffic, and each can place datagrams.
                     25:  */
                     26: #define MAXMINOR       8
                     27: static queue_t * minortab[MAXMINOR];
                     28: 
                     29: #ifdef M68K
                     30: /*
                     31:  * The 68070 uses memory mapped I/O exclusively, so treat the 8390 as a
                     32:  * structure at a fixed location in memory. The header file also defines
                     33:  * the padding of the structure on the 16-bit 68000 bus.
                     34:  *
                     35:  * We usually assign this to a local to put the base into an address
                     36:  * register, which gets faster code than using the folded immediate address.
                     37:  */
                     38: #define DP8390         volatile dp8390 *
                     39: #define DP8390_BASE    ((DP8390)(0x1FFC00 + PHYSICAL_SEG))
                     40: #define        DEVICE          _device
                     41: #define DEVICE_REG      DP8390 DEVICE = DP8390_BASE;
                     42: 
                     43: #define input(dev, dp_reg)     (dev)->dp_pg0rd.dp_reg
                     44: #define input1(dev, dp_reg)    (dev)->dp_pg1rdwr.dp_reg
                     45: #define output(dev, dp_reg, val)       (dev)->dp_pg0wr.dp_reg = val
                     46: #define output1(dev, dp_reg, val)      (dev)->dp_pg1rdwr.dp_reg = val
                     47: #endif
                     48: 
                     49: #ifdef IBMPC
                     50: /*
                     51:  * The 8086 has special instructions for I/O, but if we treat the base
                     52:  * address as a NEAR mode pointer (16-bit, current data segment) then cast
                     53:  * it to a short for the I/O instructions, we'll have the right kind of
                     54:  * effect.
                     55:  *
                     56:  * We DON'T assign the base to a local, since better code is produced by
                     57:  * folding the constants and loading a new one into DX every I/O.
                     58:  *
                     59:  * Note that we emit a JMP $+2 just before the I/O instruction to waste a
                     60:  * little time, as a NIC CS should not occur more often than 400ns.
                     61:  */
                     62: #define DP8390                 dp8390 near *
                     63: #define DP8390_BASE    ((DP8390)0x300)
                     64: #define DEVICE         DP8390_BASE
                     65: #define DEVICE_REG
                     66: 
                     67: #define _input(addr)           (_DX=(UWORD)addr, __emit__ (0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEC), _AL)
                     68: #define _output(addr,val)      (_DX=(UWORD)addr, _AL = val, __emit__ (0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEE))
                     69: #define input(dev, dp_reg)     _input (&(dev)->dp_pg0rd.dp_reg)
                     70: #define input1(dev, dp_reg)    _input (&(dev)->dp_pg1rdwr.dp_reg)
                     71: #define output(dev, dp_reg, val)       _output (&(dev)->dp_pg0wr.dp_reg,(val))
                     72: #define output1(dev, dp_reg, val)      _output (&(dev)->dp_pg1rdwr.dp_reg,(val))
                     73: 
                     74: 
                     75: #define ETHER_IRQ      2
                     76: 
                     77: #endif
                     78: 
                     79: 
                     80: /*
                     81:  * For scheduling remote DMA operations on the NIC, since there is only one
                     82:  * channel on the NIC which is shared between remote read and remote write
                     83:  * operations. Complicated since the TX buffer area is held until the NIC has
                     84:  * actually completed the transmission, and because RX DMA may be halted in the
                     85:  * middle of a packet due to STREAMS buffer depletion.
                     86:  *
                     87:  * Made a structure in the anticipation of one day having multiple interfaces.
                     88:  */
                     89: static struct ethcb {          /* control block for a single interface */
                     90:        char    tx_state;       /* TX DMA in progress or TX DMA blocked */
                     91:                                /* cleared when packet send completed */
                     92:        char    rx_state;       /* RX DMA in progress or waiting for buffers */
                     93:        char    rx_pending;     /* flag that RX packets for DMA are waiting */
                     94:        short   rx_length;      /* remaining length of RX packet */
                     95:        UWORD   rx_base;        /* NIC buffer address of RX DMA */
                     96:        mblk_t  * rx_start;     /* first mblk in RX packet */
                     97:        mblk_t  * rx_current;   /* current RX DMA buffer */
                     98:        short   tx_length;      /* length of packet being transmitted */
                     99: 
                    100:        short   tx_count;       /* count packets sent */
                    101:        short   rx_count;       /* RX activity */
                    102: 
                    103:        char    tx_error;       /* packet never ended transmission */
                    104:        short   tx_lastcount;   /* count at last timer tick */
                    105:        short   rx_lastcount;   /* count at last timre tick */
                    106: 
                    107: /*
                    108:  * About write packet queueing - since this device effectively functions as a
                    109:  * kind of multiplexor, flow control needs explicit attention. I use the
                    110:  * general methods developed for the other multiplexing drivers (like TCP),
                    111:  * namely the generic scheduler in my STREAMS implementation.
                    112:  */
                    113:        /* schedule of driver queues that have output packets queued */
                    114:        struct schedule tx_sched;
                    115: 
                    116:        struct dp8390info dp8390info;
                    117: 
                    118:        /* useful addresses that we may wish to keep copies of */
                    119:        Eth_addr myaddr;                /* our own address */
                    120: 
                    121:        /* This flag gets set when the NIC tests OK */
                    122:        int netok;
                    123: 
                    124:        /* error counter extensions */
                    125:        int errcnt0, errcnt1, errcnt2;
                    126: } eth;
                    127: 
                    128: 
                    129: #define ETH    LONG_TO_PTR (eth, struct ethcb *)
                    130: #define QETH   ((struct ethcb *) q->q_ptr)
                    131: 
                    132: /*
                    133:  * Possible states for TX
                    134:  */
                    135: #define TX_IDLE                0
                    136: #define TX_DMA         1
                    137: #define TX_SEND                2
                    138: /*
                    139:  * Possible events for TX
                    140:  */
                    141: #define TXE_CRANK      0
                    142: #define TXE_DMADONE    1
                    143: #define TXE_SENDDONE   2
                    144: 
                    145: /*
                    146:  * Possible states for RX.
                    147:  *
                    148:  * The two states RX_HALT and RX_BLOCKED distinguish whether or not to
                    149:  * continue RX dma after a TX DMA or not.
                    150:  */
                    151: #define RX_IDLE                0
                    152: #define RX_DMA         1
                    153: #define RX_HALT                2
                    154: #define RX_BLOCKED     3
                    155: /*
                    156:  * possible events for RX
                    157:  */
                    158: #define RXE_CRANK      0
                    159: #define RXE_GOTMEM     1
                    160: #define RXE_NOMEM      2
                    161: #define RXE_DMADONE    3
                    162: #define RXE_ALLDONE    4
                    163: 
                    164: /*
                    165:  * To aid in detecting when the cable has been unplugged (which causes a
                    166:  * constant collision state, so the backoff count doesn't get incremented).
                    167:  */
                    168: static P_TIMER eth_timer = NIL_TIMER;
                    169: 
                    170: /*
                    171:  * program the address into the address registers.
                    172:  * Note : assumes that register set 1 has already been chosen!
                    173:  */
                    174: static void set_addr (int selpage)
                    175: {
                    176:        DEVICE_REG
                    177: 
                    178:        if (selpage)
                    179:                output (DEVICE, dp_cr, CR_PS_P1 | CR_DM_ABORT | CR_STA);
                    180:        output1 (DEVICE, dp_par0, eth.myaddr.e[0]);
                    181:        output1 (DEVICE, dp_par1, eth.myaddr.e[1]);
                    182:        output1 (DEVICE, dp_par2, eth.myaddr.e[2]);
                    183:        output1 (DEVICE, dp_par3, eth.myaddr.e[3]);
                    184:        output1 (DEVICE, dp_par4, eth.myaddr.e[4]);
                    185:        output1 (DEVICE, dp_par5, eth.myaddr.e[5]);
                    186:        if (input1 (DEVICE, dp_par0) != eth.myaddr.e[0] ||
                    187:            input1 (DEVICE, dp_par1) != eth.myaddr.e[1] ||
                    188:            input1 (DEVICE, dp_par2) != eth.myaddr.e[2] ||
                    189:            input1 (DEVICE, dp_par3) != eth.myaddr.e[3] ||
                    190:            input1 (DEVICE, dp_par4) != eth.myaddr.e[4] ||
                    191:            input1 (DEVICE, dp_par5) != eth.myaddr.e[5] )
                    192:                STREAMS_DEBUG ("Device not accepting physical address!\n");
                    193:        if (selpage)
                    194:                output (DEVICE, dp_cr, CR_PS_P0 | CR_DM_ABORT | CR_STA);
                    195: }
                    196: 
                    197: /*
                    198:  * Since the DMA channel to the DP8390 is word-wide, I have taken special care
                    199:  * to deal with odd-length subunits of packets, or packets that are not word
                    200:  * aligned with pullupmsg(). It's not fast, but such ugly messages should not
                    201:  * occur often.
                    202:  */
                    203: 
                    204: extern void streams_levels (void);
                    205: 
                    206: static void eth_timer_func (ULONG eth)
                    207: {
                    208:        char buf [4];
                    209:        TIMER_SET (eth_timer, 1, eth_timer_func, eth);
                    210: 
                    211:        if (ETH->tx_lastcount != ETH->tx_count)
                    212:                ETH->tx_lastcount = ETH->tx_count;
                    213:        else if (ETH->tx_state != TX_IDLE &&
                    214:                 ETH->tx_error == 0) {/* packet send taking too long */
                    215:                mblk_t * temp;
                    216: 
                    217:                ETH->tx_error = 1;
                    218: 
                    219:                /* dispose of all the packets queued here */
                    220:                while (ETH->tx_sched.s_head != NULL) {
                    221:                        temp = getq (ETH->tx_sched.s_head);
                    222:                        freemsg (temp);
                    223:                        muxrobin (& ETH->tx_sched);
                    224:                }
                    225: #if 1
                    226:                STREAMS_DEBUG ("Stuck in TX ");
                    227: #endif
                    228:        }
                    229:        if (ETH->rx_lastcount != ETH->rx_count)
                    230:                ETH->rx_lastcount = ETH->rx_count;
                    231:        else if (ETH->rx_state != RX_IDLE &&
                    232:                 ETH->tx_error == 0) {
                    233:                ETH->tx_error = 1;
                    234:                STREAMS_DEBUG ("Stuck in RX ");
                    235:        }
                    236: }
                    237: 
                    238: 
                    239: static UWORD dma_base;         /* DMA base address in NIC */
                    240: static UWORD dma_len;          /* remote DMA length */
                    241: static void *dma_buf;          /* local buffer address */
                    242: static int dma_dir;            /* 1 => remote write */
                    243: 
                    244: /* start a piece of remote DMA, rounding the transfer size up */
                    245: void dma_start (void)
                    246: {
                    247:        DEVICE_REG
                    248:        int xfer_len;
                    249: 
                    250:        if (dma_dir) {
                    251:                output(DEVICE, dp_rbcr0, 15);           /* dummy byte count */
                    252:                output(DEVICE, dp_rbcr1, 0);
                    253:                output(DEVICE, dp_cr, CR_PS_P0 | CR_DM_RR | CR_STA);
                    254: //             for (xfer_len = 0; xfer_len < 5; xfer_len ++)
                    255: //                     ;
                    256:        }
                    257: 
                    258:        output(DEVICE, dp_rsar0, dma_base & 0xff);      /* remote DMA base */
                    259:        output(DEVICE, dp_rsar1, dma_base >> 8 );
                    260:        if ((xfer_len = dma_len) & 1)
                    261:                xfer_len++;
                    262:        output(DEVICE, dp_rbcr0, xfer_len & 0xff);      /* remote DMA count */
                    263:        output(DEVICE, dp_rbcr1, xfer_len >> 8 );
                    264: 
                    265:        output(DEVICE, dp_cr, dma_dir ?
                    266:                CR_PS_P0 | CR_DM_RW | CR_STA :
                    267:                CR_PS_P0 | CR_DM_RR | CR_STA);
                    268: 
                    269:        dma_setup (DMA_0, (char *)dma_buf, xfer_len >> 1,
                    270:                        dma_dir ? DMAF_TODEV|DMAF_WORDWIDE|DMAF_BURST :
                    271:                                DMAF_TOMEM|DMAF_WORDWIDE|DMAF_BURST);
                    272: }
                    273: 
                    274: /*
                    275:  * During test, we want to poll for DMA completion. Also used when reading
                    276:  * NIC packet header, since it's so short.
                    277:  */
                    278: void wait_for_dma (void)
                    279: {
                    280:        DEVICE_REG
                    281: 
                    282:        for (;;) {
                    283:                while ((input (DEVICE, dp_cr) & CR_DM_ABORT) == 0)
                    284:                        ;
                    285:                if (dma_done (DMA_0) == -1)
                    286:                        break;
                    287:                dma_reset (DMA_0);
                    288:                dma_start ();           /* restart */
                    289:        }
                    290: }
                    291: 
                    292: /*
                    293:  * retrieve NIC memory from "base" to "buffer"
                    294:  */
                    295: static INLINE void get_mem (int base, int len, void * buffer)
                    296: {
                    297:        dma_base = base;
                    298:        dma_len = len;
                    299:        dma_buf = buffer;
                    300:        dma_dir = 0;
                    301:        dma_start ();
                    302: }
                    303: static INLINE void set_mem (int base, int len, unsigned char * buf)
                    304: {
                    305:        dma_base = base;
                    306:        dma_len = len;
                    307:        dma_buf = buf;
                    308:        dma_dir = 1;
                    309:        dma_start ();
                    310: }
                    311: 
                    312: /* send streams message block "mp" to NIC */
                    313: static void send_block (queue_t * q, mblk_t * mp)
                    314: {
                    315:        /*
                    316:         * identify the losers, and fix them with pullupmsg(), which both
                    317:         * concatenates (fixing length) and aligns at the same time.
                    318:         */
                    319:        if ((mp->b_cont != NULL && ((mp->b_wptr - mp->b_rptr) & 1) != 0) ||
                    320:                        ((ULONG)mp->b_rptr & 1) != 0)
                    321:                pullupmsg (mp, -1);
                    322: 
                    323:        dma_base = (QETH->dp8390info.dpi_tbuf << 8) + QETH->tx_length;
                    324:        dma_len = mp->b_wptr - mp->b_rptr;
                    325:        dma_buf = mp->b_rptr;
                    326:        dma_dir = 1;
                    327: 
                    328:        dma_start ();
                    329: }
                    330: 
                    331: /* initiate transmission of the buffered packet, with length "len". */
                    332: static void send_pkt (struct ethcb * eth)
                    333: {
                    334:        DEVICE_REG
                    335: 
                    336:        if (eth->tx_length < 64)        /* Ethernet magic */
                    337:                eth->tx_length = 64;
                    338:        output (DEVICE, dp_tbcr0, eth->tx_length & 0xff);
                    339:        output (DEVICE, dp_tbcr1, eth->tx_length >> 8);
                    340:        output (DEVICE, dp_tpsr, eth->dp8390info.dpi_tbuf);
                    341: 
                    342:        output (DEVICE, dp_cr, CR_PS_P0|CR_DM_ABORT|CR_TXP|CR_STA);
                    343: }
                    344: 
                    345: static void rx_next (struct ethcb * eth, int event);
                    346: static void tx_next (struct ethcb * eth, int event)
                    347: {
                    348: again:
                    349:        SCREEN (26) = 'T';
                    350:        SCREEN (28) = eth->tx_state + '0';
                    351:        SCREEN (30) = event + '0';
                    352:        switch (eth->tx_state) {
                    353:        case TX_IDLE:
                    354:                if (event == TXE_CRANK) {
                    355:                        if (eth->tx_sched.s_head != NULL &&
                    356:                            eth->rx_state != RX_DMA) {
                    357:                                eth->tx_count ++;
                    358:                                eth->tx_state = TX_DMA;
                    359:                                eth->tx_length = 0;
                    360:                                send_block (eth->tx_sched.s_head,
                    361:                                            eth->tx_sched.s_head->q_first);
                    362:                        }
                    363:                        return;
                    364:                }
                    365:                break;
                    366:        case TX_DMA:
                    367:                if (event == TXE_DMADONE) {
                    368:                        mblk_t * temp = getq (eth->tx_sched.s_head),
                    369:                               * msg = temp->b_cont;
                    370: 
                    371:                        eth->tx_length += dma_len;
                    372:                        freeb (temp);
                    373:                        if (msg != NULL) {
                    374:                                putbq (eth->tx_sched.s_head, msg);
                    375:                                send_block (eth->tx_sched.s_head, msg);
                    376:                        } else {
                    377:                                send_pkt (eth);         /* spit it out */
                    378:                                muxrobin (& eth->tx_sched);
                    379:                                eth->tx_state = TX_SEND;
                    380: 
                    381:                                rx_next (eth, RXE_CRANK);
                    382:                        }
                    383:                        return;
                    384:                }
                    385:                if (event == TXE_CRANK)
                    386:                        return;
                    387:                break;
                    388:        case TX_SEND:
                    389:                if (event == TXE_SENDDONE) {
                    390:                        eth->tx_error = 0;
                    391:                        eth->tx_state = TX_IDLE;
                    392:                        rx_next (eth, RXE_CRANK);
                    393:                        event = TXE_CRANK;
                    394:                        goto again;
                    395:                }
                    396:                if (event == TXE_CRANK)
                    397:                        return;
                    398:                break;
                    399:        }
                    400:        STREAMS_DEBUG ("Bad TX state/event ");
                    401: }
                    402: 
                    403: static void rx_got_mem (long eth)
                    404: {
                    405:        short s = SPL7 ();
                    406:        rx_next (LONG_TO_PTR (eth, struct ethcb *), RXE_GOTMEM);
                    407:        SPLX (s);
                    408: }
                    409: static void rx_next (struct ethcb * eth, int event)
                    410: {
                    411:        mblk_t * mp;
                    412:        int len;
                    413: 
                    414: again:
                    415:        SCREEN (26) = 'R';
                    416:        SCREEN (28) = eth->rx_state + '0';
                    417:        SCREEN (30) = event + '0';
                    418:        switch (eth->rx_state) {
                    419:        case RX_IDLE:
                    420:                if (event == RXE_CRANK) {
                    421:                        if (eth->rx_pending && eth->tx_state != TX_DMA) {
                    422:                                /* busy wait on the header part */
                    423:                                struct rcvdheader nic;
                    424: 
                    425:                                get_mem (eth->dp8390info.dpi_next << 8, 4, & nic);
                    426:                                wait_for_dma ();
                    427:                                eth->dp8390info.dpi_next = nic.rp_next;
                    428:                                /*
                    429:                                 * count in packet header includes FCS, which we
                    430:                                 * are not really interested in.
                    431:                                 */
                    432:                                eth->rx_length = (nic.rp_rbch << 8) + nic.rp_rbcl - 4;
                    433:                                eth->rx_base = dma_base + 4;
                    434:                                if ((input (DEVICE, dp_isr) & ISR_RDC) == 0)
                    435:                                        STREAMS_DEBUG ("IMPOSSIBLE 1");
                    436:                                output (DEVICE, dp_isr, ISR_RDC);
                    437: 
                    438:                                eth->rx_count ++;
                    439:                                eth->rx_state = RX_DMA;
                    440:                                event = RXE_DMADONE;
                    441: 
                    442:                                if (input (DEVICE, dp_isr) & ISR_RDC)
                    443:                                        STREAMS_DEBUG ("IMPOSSIBLE 2");
                    444:                                goto again;
                    445:                        }
                    446:                        return;
                    447:                }
                    448:                break;
                    449:        case RX_DMA:
                    450:                len = eth->rx_length;
                    451:                if (len > 768) {
                    452:                        if (len > 1024)
                    453:                                len = 1024;
                    454:                } else if (len > 192) {
                    455:                        if (len > 256)
                    456:                                len = 256;
                    457:                } else if (len > 64)
                    458:                        len = 64;
                    459:                if (event == RXE_DMADONE) {
                    460:                        if (len == 0) {
                    461:                                event = RXE_ALLDONE;
                    462:                                goto again;
                    463:                        }
                    464:                        if ((mp = allocb (len, BPRI_MED)) == NULL) {
                    465:                                while (len < 1024) {
                    466:                                        if ((mp = allocb (len, BPRI_LO)) != NULL)
                    467:                                                break;
                    468:                                        len *= 2;
                    469:                                }
                    470:                                if (len >= 1024) {
                    471:                                        event = RXE_NOMEM;
                    472:                                        goto again;
                    473:                                }
                    474:                                if (len > eth->rx_length)
                    475:                                        len = eth->rx_length;
                    476:                        }
                    477: 
                    478:                        eth->rx_count ++;
                    479:                        mp->b_wptr += len;
                    480:                        if (eth->rx_start == NULL)
                    481:                                eth->rx_start = mp;             /* first buffer */
                    482:                        else
                    483:                                eth->rx_current->b_cont = mp;   /* link buffers */
                    484:                        eth->rx_current = mp;
                    485:                        get_mem (eth->rx_base, len, mp->b_rptr);
                    486:                        /* take care to wrap the rx_base! */
                    487:                        if (((eth->rx_base += len) >> 8) >= eth->dp8390info.dpi_pstop)
                    488:                                eth->rx_base -= (eth->dp8390info.dpi_pstop - eth->dp8390info.dpi_pstart) << 8;
                    489:                        eth->rx_length -= len;
                    490:                        return;
                    491:                }
                    492:                if (event == RXE_NOMEM) {
                    493:                        eth->rx_state = RX_HALT;
                    494:                        bufcall (len, BPRI_MED, rx_got_mem, (long) eth);
                    495:                        tx_next (eth, TXE_CRANK);
                    496:                        event = RXE_CRANK;
                    497:                        goto again;
                    498:                }
                    499:                if (event == RXE_ALLDONE) {
                    500:                        /*
                    501:                         * finished a piece of receive DMA - advance buffer
                    502:                         * queue endpoint over just received packet. In
                    503:                         * addition, we should check to see if there are any
                    504:                         * more buffered receive packets.
                    505:                         */
                    506:                        output (DEVICE, dp_bnry, eth->dp8390info.dpi_next == eth->dp8390info.dpi_pstart ?
                    507:                                                eth->dp8390info.dpi_pstop - 1 :
                    508:                                                eth->dp8390info.dpi_next - 1);
                    509:                        output (DEVICE, dp_cr, CR_PS_P1 | CR_DM_ABORT | CR_STA);
                    510:                        if (input1 (DEVICE, dp_curr) == eth->dp8390info.dpi_next)
                    511:                                eth->rx_pending = 0;
                    512:                        output (DEVICE, dp_cr, CR_PS_P0 | CR_DM_ABORT | CR_STA);
                    513:                        if (eth->rx_start != NULL) {
                    514:                                /* send a copy of every message upwards */
                    515:                                for (len = 0; len < MAXMINOR ; len ++)
                    516:                                        if (minortab [len] &&
                    517:                                            (mp = dupmsg (eth->rx_start)) != NULL)
                    518:                                                putq (minortab [len], mp);
                    519:                                SCREEN (22) ++;
                    520:                                freemsg (eth->rx_start);
                    521:                                eth->rx_start = eth->rx_current = NULL;
                    522:                        }
                    523:                        eth->rx_state = RX_IDLE;
                    524:                        tx_next (eth, TXE_CRANK);
                    525:                        event = RXE_CRANK;
                    526:                        goto again;
                    527:                }
                    528:                return;
                    529:        case RX_HALT:
                    530:                if (event == RXE_GOTMEM) {
                    531:                        if (eth->tx_state == TX_DMA) {
                    532:                                eth->rx_state = RX_BLOCKED;
                    533:                                return;
                    534:                        }
                    535:                        eth->rx_state = RX_DMA;
                    536:                        event = RXE_DMADONE;
                    537:                        goto again;
                    538:                }
                    539:                if (event == RXE_CRANK)
                    540:                        return;
                    541:                break;
                    542:        case RX_BLOCKED:
                    543:                if (event == RXE_CRANK && eth->tx_state != TX_DMA) {
                    544:                        eth->rx_state = RX_DMA;
                    545:                        event = RXE_DMADONE;
                    546:                        goto again;
                    547:                }
                    548:                break;
                    549:        default:
                    550:                STREAMS_DEBUG ("Impossible state");
                    551:                return;
                    552:        }
                    553:        STREAMS_DEBUG ("Bad RX state/event combo ");
                    554: }
                    555: 
                    556: 
                    557: /* Referenced in "system.asm", here is the interrupt service routine */
                    558: HW_INT_FUNC (void) etherint (void)
                    559: {
                    560:        DEVICE_REG
                    561:        UBYTE   status = input (DEVICE, dp_isr);
                    562: static UBYTE   reentry;
                    563: 
                    564:        if (reentry ++ != 0) {
                    565:                STREAMS_DEBUG ("Reentry ");
                    566:                reentry --;
                    567:                return;
                    568:        }
                    569: 
                    570:        /*
                    571:         * GCC - specific kernel hack, save all used registers on entry to
                    572:         * this function. We don't use INTERRUPT for the PC version since
                    573:         * hardware IRQ handlers need assembly-language wrappers to give
                    574:         * us enough stack to use STREAMS library routines.
                    575:         */
                    576:        GNU_INTERRUPT;
                    577: 
                    578: rescan:
                    579:        /* reset the flag bits that were indicated for us */
                    580:        output (DEVICE, dp_isr, status);
                    581: 
                    582:        if (eth.netok == 0) {                   /* device not active! */
                    583:                reentry --;
                    584:                return;
                    585:        }
                    586:        if ((status & ISR_PRX) != 0) {
                    587:                eth.rx_pending = 1;
                    588:                rx_next (& eth, RXE_CRANK);
                    589:        }
                    590:        SCREEN (16) ++;
                    591:        if ((status & ISR_PTX) != 0) {
                    592:                if ((input (DEVICE, dp_tsr) & ~(TSR_COL | TSR_CRS | TSR_PTX | TSR_DFR))
                    593:                    != 0)
                    594:                        STREAMS_DEBUG ("Packet TX error\n");
                    595:                SCREEN (18) ++;
                    596:                tx_next (& eth, TXE_SENDDONE);
                    597:        }
                    598:        /*
                    599:         * The ISR_RDC bit is gated with CR_DM_ABORT since the fix for the
                    600:         * NIC remote write problem causes spurious RDCs, which are not
                    601:         * normally detected unless the TX DMA is delayed by arrive DMA to
                    602:         * the NIC local memory.
                    603:         */
                    604:        if ((status & ISR_RDC) != 0 &&
                    605:            (input (DEVICE, dp_cr) & CR_DM_ABORT) != 0)
                    606:                if (dma_done (DMA_0) != -1) {
                    607:                        dma_reset (DMA_0);
                    608:                        dma_start ();
                    609:                } else if (dma_dir)
                    610:                        tx_next (& eth, TXE_DMADONE);
                    611:                else
                    612:                        rx_next (& eth, RXE_DMADONE);
                    613: 
                    614:        if ((status & (ISR_RXE | ISR_TXE | ISR_OVW | ISR_CNT)) != 0) {
                    615:                if (status & ISR_RXE)
                    616:                        STREAMS_DEBUG ("Receive error\n");
                    617:                if (status & ISR_TXE) {
                    618:                        /*
                    619:                         * This can happen due to excessive collisions if
                    620:                         * there is an open cable end or due to a FIFO
                    621:                         * underrun (which indicates a board problem).
                    622:                         */
                    623:                        if ((input (DEVICE, dp_tsr) & (TSR_FU)) != 0)
                    624:                                STREAMS_DEBUG ("TX FIFO underrun");
                    625:                        tx_next (& eth, TXE_SENDDONE);
                    626:                }
                    627:                if (status & ISR_OVW)
                    628:                        STREAMS_DEBUG ("Buffer overflow\n");
                    629:                if (status & ISR_CNT) {
                    630:                        /* reset the error counters by reading them */
                    631:                        eth.errcnt0 += input (DEVICE, dp_cntr0);
                    632:                        eth.errcnt1 += input (DEVICE, dp_cntr1);
                    633:                        eth.errcnt2 += input (DEVICE, dp_cntr2);
                    634:                }
                    635:        }
                    636:        if ((status = input (DEVICE, dp_isr)) != 0)
                    637:                goto rescan;
                    638: 
                    639:        reentry --;
                    640: }
                    641: 
                    642: /*
                    643:  * Routines for reading from/writing to the NIC memory.
                    644:  */
                    645: 
                    646: /* queue a packet for transmission */
                    647: static void queue_packet (queue_t *q, mblk_t *mp)
                    648: {
                    649:        if (QETH->tx_error != 0)
                    650:                return;
                    651: 
                    652:        short s = SPL7 ();
                    653:        /*
                    654:         * We queue the message "normally" for STREAMS so that flow control
                    655:         * operates as one would expect. Then we place the streams queue onto
                    656:         * our own "scheduling" list for processing by the NIC interrupt.
                    657:         */
                    658:        putq (q, mp);
                    659:        qschedule (q, & QETH->tx_sched);
                    660: 
                    661:        /*
                    662:         * If there is no I/O presently being executed, we must start
                    663:         * the ball rolling.
                    664:         */
                    665:        tx_next (QETH, TXE_CRANK);
                    666:        SPLX (s);
                    667: }
                    668: 
                    669: /*
                    670:  * Set up the DP8390. This initialisation procedure comes fairly directly
                    671:  * from the NatSemi manual - much dark magic.
                    672:  */
                    673: static void chipinit (Eth_addr * addr)
                    674: {
                    675:        unsigned char * testbuf, * test2;
                    676:        mblk_t * testmem;
                    677:        int i, start = -1, len;
                    678:        DEVICE_REG
                    679: 
                    680:        if (input (DEVICE, dp_cr) == 0xFF) {
                    681:                eth.netok = -1;
                    682:                return;
                    683:        }
                    684: 
                    685:        /* reset dp8390 */
                    686:        output(DEVICE, dp_cr, CR_STP|CR_PS_P0|CR_DM_ABORT);
                    687: 
                    688: #ifdef M68K
                    689:        output(DEVICE, dp_dcr,
                    690:                DCR_LOOP | DCR_WORDWIDE | DCR_BIGENDIAN | DCR_8BYTES);
                    691: #endif
                    692: #ifdef IBMPC
                    693:        set_hw_int (ETHER_IRQ, etherint);
                    694:        output(DEVICE, dp_dcr, DCR_LOOP | DCR_WORDWIDE | DCR_8BYTES);
                    695: #endif
                    696: 
                    697:        output(DEVICE, dp_rbcr0, 0);
                    698:        output(DEVICE, dp_rbcr1, 0);
                    699:        output(DEVICE, dp_rcr, RCR_AB);
                    700:        output(DEVICE, dp_tcr, TCR_INTERNAL);
                    701:        output(DEVICE, dp_isr, 0xff);
                    702:        output(DEVICE, dp_imr, 0);
                    703: 
                    704:        /*
                    705:         * We start the device here (and shut it down later) since the
                    706:         * Remote DMA doesn't work until we do, and we can't find out how
                    707:         * much memory we have until we can DMA. (Sigh)
                    708:         */
                    709:        output (DEVICE, dp_cr, CR_PS_P0 | CR_DM_ABORT | CR_STA);
                    710: 
                    711:        /*
                    712:         * Since the NIC is in internal loopback mode (TCR_INTERNAL), and
                    713:         * interrupts are disabled, we can now test the NIC's memory to
                    714:         * determine how much there is.
                    715:         */
                    716:        testmem = getbuf (1024);        /* get temporary space */
                    717:        testbuf = testmem->b_rptr;
                    718:        test2 = testbuf + 256;
                    719: 
                    720:        for (i = 0 ; i < 256 ; i ++)
                    721:                testbuf [i] = i;
                    722:        for (i = 0 ; i < 256 ; i ++) {
                    723:                testbuf [0] = i;
                    724:                testbuf [1] = ~i;
                    725:                set_mem (i << 8, 256, testbuf);
                    726:                wait_for_dma ();
                    727:        }
                    728: 
                    729:        /* find start of memory */
                    730:        for (i = 0 ; i < 256 ; i++) {
                    731:                testbuf [0] = i;
                    732:                testbuf [1] = ~i;
                    733:                get_mem (i << 8, 256, test2);
                    734:                wait_for_dma ();
                    735:                if (memcmp (test2, testbuf, 256) == 0)
                    736:                        /* got one - either start or extend a span */
                    737:                        if (start < 0) {
                    738:                                start = i;
                    739:                                len = 1;
                    740:                        } else
                    741:                                len++;
                    742:                else
                    743:                        if (start >= 0)
                    744:                                break;
                    745:        }
                    746:        if (len < 16) {         /* needs at least 4k to work */
                    747:                eth.netok = -1;
                    748:                goto alldone;
                    749:        }
                    750: 
                    751:        eth.dp8390info.dpi_pstart = start + 8;
                    752:        eth.dp8390info.dpi_pstop = start + len;
                    753:        eth.dp8390info.dpi_tbuf = start;
                    754: 
                    755:        /*
                    756:         * Since we're at it... if the board has an address PROM, it should
                    757:         * be at address 0 (where the NIC has trouble locating RAM), so
                    758:         * unless we're given an address, try finding our location.
                    759:         */
                    760:        if (addr != NULL)
                    761:                eth.myaddr = * addr;
                    762:        else if (start > 0) {           /* may have PROM, there's no RAM */
                    763:                get_mem (0, 12, testbuf);
                    764:                wait_for_dma ();
                    765: 
                    766:                /* Fetch the PROM data from every second word */
                    767:                for (i = 0;i < 6;i++)
                    768:                        eth.myaddr.e [i] = testbuf [i + i];
                    769:        }
                    770: 
                    771:        STREAMS_DEBUG_LONG (len << 8, 16);
                    772:        STREAMS_DEBUG ("h bytes of Ethernet memory, Address = $");
                    773:        for (i = 0 ; i < 6 ; i ++)
                    774:                STREAMS_DEBUG_LONG (eth.myaddr.e [i], 16);
                    775:        STREAMS_DEBUG (", IRQ ");
                    776:        STREAMS_DEBUG_LONG (ETHER_IRQ, 10);
                    777:        STREAMS_DEBUG ("\r\n");
                    778: 
                    779:        output (DEVICE, dp_isr, 0xFF);
                    780:        output (DEVICE, dp_tpsr, eth.dp8390info.dpi_tbuf);
                    781:        output (DEVICE, dp_pstart, eth.dp8390info.dpi_pstart);
                    782:        output (DEVICE, dp_bnry, eth.dp8390info.dpi_pstart);
                    783:        output (DEVICE, dp_pstop, eth.dp8390info.dpi_pstop);
                    784: 
                    785:        output (DEVICE, dp_cr, CR_PS_P1|CR_DM_ABORT|CR_STP);
                    786:        output1 (DEVICE, dp_curr, eth.dp8390info.dpi_pstart + 1);
                    787:        eth.dp8390info.dpi_next = eth.dp8390info.dpi_pstart + 1;
                    788: 
                    789:        set_addr (0);
                    790: 
                    791:        output (DEVICE, dp_cr, CR_PS_P0|CR_DM_ABORT|CR_STA);
                    792:        output (DEVICE, dp_tcr, 0);
                    793:        output (DEVICE, dp_imr, 0x7F);  /* all interrupts */
                    794: 
                    795:        if ((eth_timer = TIMER_ALLOC ()) != NIL_TIMER)
                    796:                TIMER_SET (eth_timer, 1, eth_timer_func, (long) & eth);
                    797:        eth.netok ++;
                    798: 
                    799: alldone:
                    800:        freemsg (testmem);
                    801: }
                    802: 
                    803: /*
                    804:  * Shut down the E'net chip. Whenever I get around to it, this will send
                    805:  * the ARP-style packet that indicates this station is dead'n'gone. This
                    806:  * will use the poll-type DMA access shown in the open.
                    807:  */
                    808: static void chipoff (void)
                    809: {
                    810:        DEVICE_REG
                    811: 
                    812:        if (eth.netok < 0)
                    813:                return;
                    814: #ifdef IBMPC
                    815:        set_hw_int (ETHER_IRQ, NULL);
                    816: #endif /* IBMPC */
                    817:        output (DEVICE, dp_imr, 0);
                    818:        output (DEVICE, dp_cr, CR_PS_P0 | CR_DM_ABORT | CR_STP);
                    819: }
                    820: 
                    821: /*
                    822:  * stream open routine for the driver
                    823:  */
                    824: static int ethopen (queue_t * q, dev_t dev, int /* flag */, int sflag)
                    825: {
                    826:        /* refuse to do anything unless everything checked out OK at boot */
                    827:        W (q)->q_ptr = q->q_ptr = & eth;
                    828:        if (QETH->netok < 0)
                    829:                return OPENFAIL;
                    830:        if (QETH->netok == 0) {
                    831:                chipinit (NULL);
                    832:                if (QETH->netok < 0)
                    833:                        return OPENFAIL;
                    834: 
                    835:        } else
                    836:                QETH->netok ++;
                    837:        /* allow regular or clone device open */
                    838:        if (sflag == CLONEOPEN) {
                    839:                for (dev = 0;dev < MAXMINOR;dev++)
                    840:                        if (minortab[dev] == NULL)
                    841:                                break;
                    842:        } else
                    843:                dev = minor(dev);
                    844:        if (dev < 0 || dev >= MAXMINOR)
                    845:                return OPENFAIL;
                    846: 
                    847:        minortab[dev] = q;
                    848:        return dev;
                    849: }
                    850: 
                    851: /* ethernet write put procedure */
                    852: static void ethwput (queue_t * q, mblk_t * mp)
                    853: {
                    854:        Framehdr * frame;
                    855:        struct sp_bind * spbind;
                    856:        Eth_addr * addr;
                    857: 
                    858:        switch (mp->b_datap->db_type) {
                    859:        case M_PROTO:
                    860:                spbind = (struct sp_bind *)mp->b_rptr;
                    861:                addr = (Eth_addr *)(spbind + 1);
                    862:                if (spbind->protoid == SP_BIND) {
                    863:                        if (spbind->family != AF_ENET) {
                    864:                                freemsg (mp);
                    865:                                return;
                    866:                        }
                    867:                        if (mp->b_wptr > (unsigned char *) addr) {
                    868:                                QETH->myaddr = * addr ++;
                    869:                                set_addr (1);
                    870:                        }
                    871:                        freemsg (mp);
                    872:                        mp = allocb (sizeof (struct sp_bind) + sizeof (Eth_addr),
                    873:                                     BPRI_MED);
                    874:                        if (mp != NULL) {
                    875:                                spbind = (struct sp_bind *)mp->b_rptr;
                    876:                                addr = (Eth_addr *)(spbind + 1);
                    877:                                spbind->protoid = SP_BIND;
                    878:                                spbind->family = AF_ENET;
                    879:                                spbind->connect = TPS_BOUND;
                    880:                                * addr ++ = QETH->myaddr;
                    881:                                mp->b_wptr = (unsigned char *) addr;
                    882:                                mp->b_datap->db_type = M_PROTO;
                    883:                                qreply (q, mp);
                    884:                        }
                    885:                        return;
                    886:                }
                    887:        default:
                    888: nogood:
                    889:                freemsg (mp);
                    890:                break;
                    891:        case M_DATA:
                    892:                frame = (Framehdr *)mp->b_rptr;
                    893:                if ((unsigned char *)(frame + 1) > mp->b_wptr)
                    894:                        goto nogood;
                    895:                SCREEN (20) ++;
                    896:                frame->f_srcaddr = QETH->myaddr;
                    897:                queue_packet (q, mp);
                    898:                break;
                    899:        case M_FLUSH:
                    900:                /* canonical flush processing */
                    901:                if ((* mp->b_rptr & FLUSHW) != 0)
                    902:                        flushq (q, FLUSHDATA);
                    903:                if ((* mp->b_rptr & FLUSHR) != 0) {
                    904:                        flushq (RD(q), FLUSHDATA);
                    905:                        * mp->b_rptr &= ~FLUSHW;
                    906:                        qreply (q, mp);
                    907:                } else
                    908:                        freemsg (mp);
                    909:                break;
                    910:        case M_IOCTL:
                    911:                mp->b_datap->db_type = M_IOCNAK;
                    912:                qreply (q, mp);
                    913:                break;
                    914:        }
                    915: }
                    916: 
                    917: /* read service routine */
                    918: static void ethrsrv (queue_t * q)
                    919: {
                    920:        mblk_t * mp;
                    921: 
                    922:        while ((mp = getq (q)) != NULL)
                    923:                if (canput (q->q_next))
                    924:                        putnext (q, mp);
                    925:                else {
                    926:                        putbq (q, mp);
                    927:                        break;
                    928:                }
                    929:        SCREEN (24) ++;
                    930: }
                    931: 
                    932: /* close procedure - called on last close of stream */
                    933: static int ethclose(queue_t *q)
                    934: {
                    935:        int i;
                    936: 
                    937:        if (QETH->netok == 1)
                    938:                chipoff ();
                    939:        QETH->netok --;
                    940:        for (i = 0;i < MAXMINOR;i++)
                    941:                if (minortab[i] == q)
                    942:                        break;
                    943:        minortab[i] = NULL;
                    944:        return(0);
                    945: }
                    946: 
                    947: static struct module_info ethrinfo = {
                    948:        0, "ether", 0, 1024, 1024, 0
                    949: };
                    950: static struct qinit ethread = {
                    951:        NULLFUNC, ethrsrv, ethopen, ethclose, NULLFUNC,
                    952:        &ethrinfo, NULLSTAT
                    953: }, ethwrite = {
                    954:        ethwput, NULLFUNC, NULLFUNC, NULLFUNC, NULLFUNC,
                    955:        &ethrinfo, NULLSTAT
                    956: };
                    957: struct streamtab ethinfo = {
                    958:        &ethread, &ethwrite, NULLINIT, NULLINIT
                    959: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.