The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/if_cx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Cronyx-Sigma adapter driver for FreeBSD.
    3  * Supports PPP/HDLC and Cisco/HDLC protocol in synchronous mode,
    4  * and asyncronous channels with full modem control.
    5  * Keepalive protocol implemented in both Cisco and PPP modes.
    6  *
    7  * Copyright (C) 1994 Cronyx Ltd.
    8  * Author: Serge Vakulenko, <vak@zebub.msk.su>
    9  *
   10  * This software is distributed with NO WARRANTIES, not even the implied
   11  * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
   12  *
   13  * Authors grant any other persons or organisations permission to use
   14  * or modify this software as long as this message is kept with the software,
   15  * all derivative works or modified versions.
   16  *
   17  * Version 1.9, Wed Oct  4 18:58:15 MSK 1995
   18  */
   19 #undef DEBUG
   20 
   21 #include "cx.h"
   22 #include "bpfilter.h"
   23 
   24 #include <sys/param.h>
   25 #include <sys/systm.h>
   26 #include <sys/kernel.h>
   27 #include <sys/mbuf.h>
   28 #include <sys/ioctl.h>
   29 #include <sys/socket.h>
   30 #include <sys/conf.h>
   31 #include <sys/errno.h>
   32 
   33 #include <net/if.h>
   34 #include <net/if_types.h>
   35 
   36 #if NBPFILTER > 0
   37 #include <net/bpf.h>
   38 #include <net/bpfdesc.h>
   39 #endif
   40 
   41 #include <i386/isa/isa_device.h>
   42 #ifdef DEVFS
   43 extern struct cdevsw cx_cdevsw;
   44 #include <sys/devfsext.h>
   45 #endif /*DEVFS*/
   46 #define watchdog_func_t void(*)(struct ifnet *)
   47 #define start_func_t    void(*)(struct ifnet*)
   48 
   49 #include <net/if_sppp.h>
   50 #include <machine/cronyx.h>
   51 #include <i386/isa/cxreg.h>
   52 
   53 /* XXX exported. */
   54 void cxswitch (cx_chan_t *c, cx_soft_opt_t new);
   55 
   56 static int cxprobe __P((struct isa_device *id));
   57 static int cxattach __P((struct isa_device *id));
   58 static void cxput __P((cx_chan_t *c, char b));
   59 static void cxsend __P((cx_chan_t *c));
   60 static void cxrinth __P((cx_chan_t *c));
   61 static int cxtinth __P((cx_chan_t *c));
   62 
   63 #ifdef DEBUG
   64 #   define print(s)     printf s
   65 #else
   66 #   define print(s)     {/*void*/}
   67 #endif
   68 
   69 #define TXTIMEOUT       10              /* transmit timeout in seconds */
   70 #define DMABUFSZ        (6*256)         /* buffer size */
   71 #define PPP_HEADER_LEN  4               /* size of PPP header */
   72 
   73 /*
   74  * Under BSDI it's possible to use general p2p protocol scheme,
   75  * as well as our own one.  Switching is done via IFF_ALTPHYS flag.
   76  * Our ifnet pointer holds the buffer large enough to contain
   77  * any of sppp and p2p structures.
   78  */
   79 #define IFSTRUCTSZ   (sizeof (struct sppp))
   80 #define IFNETSZ         (sizeof (struct ifnet))
   81 
   82 static int cxsioctl (struct ifnet *ifp, int cmd, caddr_t data);
   83 static void cxstart (struct ifnet *ifp);
   84 static void cxwatchdog (struct ifnet *ifp);
   85 static void cxinput (cx_chan_t *c, void *buf, unsigned len);
   86 extern int cxrinta (cx_chan_t *c);
   87 extern void cxtinta (cx_chan_t *c);
   88 extern void cxmint (cx_chan_t *c);
   89 extern void cxtimeout (caddr_t a);
   90 static void cxdown (cx_chan_t *c);
   91 static void cxup (cx_chan_t *c);
   92 
   93 cx_board_t cxboard [NCX];           /* adapter state structures */
   94 cx_chan_t *cxchan [NCX*NCHAN];      /* unit to channel struct pointer */
   95 
   96 static unsigned short irq_valid_values [] = { 3, 5, 7, 10, 11, 12, 15, 0 };
   97 static unsigned short drq_valid_values [] = { 5, 6, 7, 0 };
   98 static unsigned short port_valid_values [] = {
   99         0x240, 0x260, 0x280, 0x300, 0x320, 0x380, 0x3a0, 0,
  100 };
  101 
  102 /*
  103  * Check that the value is contained in the list of correct values.
  104  */
  105 static int valid (unsigned short value, unsigned short *list)
  106 {
  107         while (*list)
  108                 if (value == *list++)
  109                         return (1);
  110         return (0);
  111 }
  112 
  113 /*
  114  * Print the mbuf chain, for debug purposes only.
  115  */
  116 static void printmbuf (struct mbuf *m)
  117 {
  118         printf ("mbuf:");
  119         for (; m; m=m->m_next) {
  120                 if (m->m_flags & M_PKTHDR)
  121                         printf (" HDR %d:", m->m_pkthdr.len);
  122                 if (m->m_flags & M_EXT)
  123                         printf (" EXT:");
  124                 printf (" %d", m->m_len);
  125         }
  126         printf ("\n");
  127 }
  128 
  129 /*
  130  * Make an mbuf from data.
  131  */
  132 static struct mbuf *makembuf (void *buf, unsigned len)
  133 {
  134         struct mbuf *m, *o, *p;
  135 
  136         MGETHDR (m, M_DONTWAIT, MT_DATA);
  137         if (! m)
  138                 return (0);
  139         if (len >= MINCLSIZE)
  140                 MCLGET (m, M_DONTWAIT);
  141         m->m_pkthdr.len = len;
  142         m->m_len = 0;
  143 
  144         p = m;
  145         while (len) {
  146                 unsigned n = M_TRAILINGSPACE (p);
  147                 if (n > len)
  148                         n = len;
  149 
  150                 if (! n) {
  151                         /* Allocate new mbuf. */
  152                         o = p;
  153                         MGET (p, M_DONTWAIT, MT_DATA);
  154                         if (! p) {
  155                                 m_freem (m);
  156                                 return (0);
  157                         }
  158                         if (len >= MINCLSIZE)
  159                                 MCLGET (p, M_DONTWAIT);
  160                         p->m_len = 0;
  161                         o->m_next = p;
  162 
  163                         n = M_TRAILINGSPACE (p);
  164                         if (n > len)
  165                                 n = len;
  166                 }
  167 
  168                 bcopy (buf, mtod (p, caddr_t) + p->m_len, n);
  169 
  170                 p->m_len += n;
  171                 buf = (char *)buf + n;
  172                 len -= n;
  173         }
  174         return (m);
  175 }
  176 
  177 /*
  178  * Test the presence of the adapter on the given i/o port.
  179  */
  180 static int
  181 cxprobe (struct isa_device *id)
  182 {
  183         int unit = id->id_unit;
  184         int iobase = id->id_iobase;
  185         int irq = id->id_irq;
  186         int drq = id->id_drq;
  187         int irqnum;
  188         irqnum = ffs (irq) - 1;
  189 
  190         print (("cx%d: probe iobase=0x%x irq=%d drq=%d\n",
  191                 unit, iobase, irqnum, drq));
  192         if (! valid (irqnum, irq_valid_values)) {
  193                 printf ("cx%d: Incorrect IRQ: %d\n", unit, irqnum);
  194                 return (0);
  195         }
  196         if (! valid (iobase, port_valid_values)) {
  197                 printf ("cx%d: Incorrect port address: 0x%x\n", unit, iobase);
  198                 return (0);
  199         }
  200         if (! valid (drq, drq_valid_values)) {
  201                 printf ("cx%d: Incorrect DMA channel: %d\n", unit, drq);
  202                 return (0);
  203         }
  204         if (! cx_probe_board (iobase))
  205                 return (0);
  206 
  207         return (1);
  208 }
  209 
  210 /*
  211  * The adapter is present, initialize the driver structures.
  212  */
  213 
  214 #ifdef DEVFS
  215 static void *cx_devfs_token;
  216 #endif 
  217 
  218 static int
  219 cxattach (struct isa_device *id)
  220 {
  221         int unit = id->id_unit;
  222         int iobase = id->id_iobase;
  223         int irq = id->id_irq;
  224         int drq = id->id_drq;
  225         cx_board_t *b = cxboard + unit;
  226         int i;
  227 
  228         /* Initialize the board structure. */
  229         cx_init (b, unit, iobase, ffs(irq)-1, drq);
  230 
  231         for (i=0; i<NCHAN; ++i) {
  232                 cx_chan_t *c = b->chan + i;
  233                 int u = b->num*NCHAN + i;
  234                 cxchan[u] = c;
  235 
  236                 if (c->type == T_NONE)
  237                         continue;
  238 
  239                 /* Allocate the buffer memory. */
  240                 c->arbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
  241                 c->brbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
  242                 c->atbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
  243                 c->btbuf = malloc (DMABUFSZ, M_DEVBUF, M_NOWAIT);
  244 
  245                 /* All buffers should be located in lower 16M of memory! */
  246                 if (!c->arbuf || !c->brbuf || !c->atbuf || !c->btbuf) {
  247                         printf ("cx%d.%d: No memory for channel buffers\n",
  248                                 c->board->num, c->num);
  249                         c->type = T_NONE;
  250                 }
  251 
  252                 switch (c->type) {
  253                 case T_SYNC_RS232:
  254                 case T_SYNC_V35:
  255                 case T_SYNC_RS449:
  256                 case T_UNIV_RS232:
  257                 case T_UNIV_RS449:
  258                 case T_UNIV_V35:
  259                         c->ifp = malloc (IFSTRUCTSZ, M_DEVBUF, M_NOWAIT);
  260                         if (! c->ifp) {
  261                                 printf ("cx%d.%d: No memory for ifnet buffer\n",
  262                                         c->board->num, c->num);
  263                                 c->type = T_NONE;
  264                                 continue;
  265                         }
  266                         bzero (c->ifp, IFSTRUCTSZ);
  267                         c->master = c->ifp;
  268                         c->ifp->if_softc = c;
  269                         c->ifp->if_unit = u;
  270                         c->ifp->if_name = "cx";
  271                         c->ifp->if_mtu = PP_MTU;
  272                         c->ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
  273                         c->ifp->if_ioctl = cxsioctl;
  274                         c->ifp->if_start = (start_func_t) cxstart;
  275                         c->ifp->if_watchdog = (watchdog_func_t) cxwatchdog;
  276                         /* Init routine is never called by upper level? */
  277                         sppp_attach (c->ifp);
  278                         if_attach (c->ifp);
  279 #if NBPFILTER > 0
  280                         /* If BPF is in the kernel, call the attach for it. */
  281                         bpfattach (c->ifp, DLT_PPP, PPP_HEADER_LEN);
  282 #endif
  283                 }
  284         }
  285 
  286         /* Reset the adapter. */
  287         cx_setup_board (b);
  288 
  289         /* Activate the timeout routine. */
  290         if (unit == 0)
  291                 timeout ((timeout_func_t) cxtimeout, 0, hz*5);
  292 
  293         printf ("cx%d: <Cronyx-%s>\n", unit, b->name);
  294 #ifdef DEVFS
  295         cx_devfs_token =
  296                 devfs_add_devswf(&cx_cdevsw, 0, DV_CHR, 0, 0, 0600, "cx");
  297 #endif
  298         return (1);
  299 }
  300 
  301 struct isa_driver cxdriver = { cxprobe, cxattach, "cx" };
  302 
  303 /*
  304  * Process an ioctl request.
  305  */
  306 static int
  307 cxsioctl (struct ifnet *ifp, int cmd, caddr_t data)
  308 {
  309         cx_chan_t *q, *c = ifp->if_softc;
  310         int error, s, was_up, should_be_up;
  311 
  312         /*
  313          * No socket ioctls while the channel is in async mode.
  314          */
  315         if (c->type==T_NONE || c->mode==M_ASYNC)
  316                 return (EINVAL);
  317 
  318         /*
  319          * Socket ioctls on slave subchannels are not allowed.
  320          */
  321         if (c->master != c->ifp)
  322                 return (EBUSY);
  323 
  324         was_up = (ifp->if_flags & IFF_RUNNING) != 0;
  325         error = sppp_ioctl (ifp, cmd, data);
  326         if (error)
  327                 return (error);
  328 
  329         print (("cxioctl (%d.%d, ", c->board->num, c->num));
  330         switch (cmd) {
  331         default:
  332                 print (("0x%x)\n", cmd));
  333                 return (0);
  334         case SIOCADDMULTI:
  335                 print (("SIOCADDMULTI)\n"));
  336                 return (0);
  337         case SIOCDELMULTI:
  338                 print (("SIOCDELMULTI)\n"));
  339                 return (0);
  340         case SIOCSIFFLAGS:
  341                 print (("SIOCSIFFLAGS)\n"));
  342                 break;
  343         case SIOCSIFADDR:
  344                 print (("SIOCSIFADDR)\n"));
  345                 break;
  346         }
  347 
  348         /* We get here only in case of SIFFLAGS or SIFADDR. */
  349         s = splimp ();
  350         should_be_up = (ifp->if_flags & IFF_RUNNING) != 0;
  351         if (!was_up && should_be_up) {
  352                 /* Interface goes up -- start it. */
  353                 cxup (c);
  354 
  355                 /* Start all slave subchannels. */
  356                 for (q=c->slaveq; q; q=q->slaveq)
  357                         cxup (q);
  358 
  359                 cxstart (c->ifp);
  360         } else if (was_up && !should_be_up) {
  361                 /* Interface is going down -- stop it. */
  362                 cxdown (c);
  363 
  364                 /* Stop all slave subchannels. */
  365                 for (q=c->slaveq; q; q=q->slaveq)
  366                         cxdown (q);
  367 
  368                 /* Flush the interface output queue */
  369                 if (! c->sopt.ext)
  370                         sppp_flush (c->ifp);
  371         }
  372         splx (s);
  373         return (0);
  374 }
  375 
  376 /*
  377  * Stop the interface.  Called on splimp().
  378  */
  379 static void
  380 cxdown (cx_chan_t *c)
  381 {
  382         unsigned short port = c->chip->port;
  383 
  384         print (("cx%d.%d: cxdown\n", c->board->num, c->num));
  385 
  386         /* The interface is down, stop it */
  387         c->ifp->if_flags &= ~IFF_OACTIVE;
  388 
  389         /* Reset the channel (for sync modes only) */
  390                 outb (CAR(port), c->num & 3);
  391                 outb (STCR(port), STC_ABORTTX | STC_SNDSPC);
  392 
  393         cx_setup_chan (c);
  394 }
  395 
  396 /*
  397  * Start the interface.  Called on splimp().
  398  */
  399 static void
  400 cxup (cx_chan_t *c)
  401 {
  402         unsigned short port = c->chip->port;
  403 
  404                 /* The interface is up, start it */
  405                 print (("cx%d.%d: cxup\n", c->board->num, c->num));
  406 
  407                 /* Initialize channel, enable receiver and transmitter */
  408                 cx_cmd (port, CCR_INITCH | CCR_ENRX | CCR_ENTX);
  409                 /* Repeat the command, to avoid the rev.H bug */
  410                 cx_cmd (port, CCR_INITCH | CCR_ENRX | CCR_ENTX);
  411 
  412                 /* Start receiver */
  413                 outw (ARBCNT(port), DMABUFSZ);
  414                 outb (ARBSTS(port), BSTS_OWN24);
  415                 outw (BRBCNT(port), DMABUFSZ);
  416                 outb (BRBSTS(port), BSTS_OWN24);
  417 
  418                 /* Raise DTR and RTS */
  419                 cx_chan_dtr (c, 1);
  420                 cx_chan_rts (c, 1);
  421 
  422                 /* Enable interrupts */
  423                 outb (IER(port), IER_RXD | IER_TXD);
  424 }
  425 
  426 /*
  427  * Fill transmitter buffer with data.
  428  */
  429 static void 
  430 cxput (cx_chan_t *c, char b)
  431 {
  432         struct mbuf *m;
  433         unsigned char *buf;
  434         unsigned short port = c->chip->port, len, cnt_port, sts_port;
  435 
  436         /* Choose the buffer. */
  437         if (b == 'A') {
  438                 buf      = c->atbuf;
  439                 cnt_port = ATBCNT(port);
  440                 sts_port = ATBSTS(port);
  441         } else {
  442                 buf      = c->btbuf;
  443                 cnt_port = BTBCNT(port);
  444                 sts_port = BTBSTS(port);
  445         }
  446 
  447         /* Is it busy? */
  448         if (inb (sts_port) & BSTS_OWN24) {
  449                 if (c->ifp->if_flags & IFF_DEBUG)
  450                         print (("cx%d.%d: tbuf %c already busy, bsts=%b\n",
  451                                 c->board->num, c->num, b,
  452                                 inb (sts_port), BSTS_BITS));
  453                 goto ret;
  454         }
  455 
  456         /* Get the packet to send. */
  457         m = sppp_dequeue (c->master);
  458         if (! m)
  459                 return;
  460         len = m->m_pkthdr.len;
  461 
  462         /* Count the transmitted bytes to the subchannel, not the master. */
  463         c->master->if_obytes -= len + 3;
  464         c->ifp->if_obytes += len + 3;
  465         c->stat->obytes += len + 3;
  466 
  467         if (len >= DMABUFSZ) {
  468                 printf ("cx%d.%d: too long packet: %d bytes: ",
  469                         c->board->num, c->num, len);
  470                 printmbuf (m);
  471                 m_freem (m);
  472                 return;
  473         }
  474         m_copydata (m, 0, len, buf);
  475 #if NBPFILTER > 0
  476         if (c->ifp->if_bpf)
  477                 bpf_mtap (c->ifp, m);
  478 #endif
  479         m_freem (m);
  480 
  481         /* Start transmitter. */
  482         outw (cnt_port, len);
  483         outb (sts_port, BSTS_EOFR | BSTS_INTR | BSTS_OWN24);
  484 
  485         if (c->ifp->if_flags & IFF_DEBUG)
  486                 print (("cx%d.%d: enqueue %d bytes to %c\n",
  487                         c->board->num, c->num, len, buf==c->atbuf ? 'A' : 'B'));
  488 ret:
  489         c->ifp->if_flags |= IFF_OACTIVE;
  490 }
  491 
  492 /*
  493  * Start output on the (slave) interface.  Get another datagram to send
  494  * off of the interface queue, and copy it to the interface
  495  * before starting the output.
  496  */
  497 static void
  498 cxsend (cx_chan_t *c)
  499 {
  500         unsigned short port = c->chip->port;
  501 
  502         if (c->ifp->if_flags & IFF_DEBUG)
  503                 print (("cx%d.%d: cxsend\n", c->board->num, c->num));
  504 
  505         /* No output if the interface is down. */
  506         if (! (c->ifp->if_flags & IFF_RUNNING))
  507                 return;
  508 
  509         /* Set the current channel number. */
  510         outb (CAR(port), c->num & 3);
  511 
  512         /* Determine the buffer order. */
  513         if (inb (DMABSTS(port)) & DMABSTS_NTBUF) {
  514                 cxput (c, 'B');
  515                 cxput (c, 'A');
  516         } else {
  517                 cxput (c, 'A');
  518                 cxput (c, 'B');
  519         }
  520 
  521         /* Set up transmit timeout. */
  522         if (c->master->if_flags & IFF_OACTIVE)
  523                 c->master->if_timer = TXTIMEOUT;
  524 
  525         /*
  526          * Enable TXMPTY interrupt,
  527          * to catch the case when the second buffer is empty.
  528          */
  529         if ((inb (ATBSTS(port)) & BSTS_OWN24) &&
  530             (inb (BTBSTS(port)) & BSTS_OWN24)) {
  531                 outb (IER(port), IER_RXD | IER_TXD | IER_TXMPTY);
  532         } else
  533                 outb (IER(port), IER_RXD | IER_TXD);
  534 }
  535 
  536 /*
  537  * Start output on the (master) interface and all slave interfaces.
  538  * Always called on splimp().
  539  */
  540 static void
  541 cxstart (struct ifnet *ifp)
  542 {
  543         cx_chan_t *q, *c = ifp->if_softc;
  544 
  545         if (c->ifp->if_flags & IFF_DEBUG)
  546                 print (("cx%d.%d: cxstart\n", c->board->num, c->num));
  547 
  548         /* Start the master subchannel. */
  549         cxsend (c);
  550 
  551         /* Start all slave subchannels. */
  552         if (c->slaveq && ! sppp_isempty (c->master))
  553                 for (q=c->slaveq; q; q=q->slaveq)
  554                         if ((q->ifp->if_flags & IFF_RUNNING) &&
  555                             ! (q->ifp->if_flags & IFF_OACTIVE))
  556                                 cxsend (q);
  557 }
  558 
  559 /*
  560  * Handle transmit timeouts.
  561  * Recover after lost transmit interrupts.
  562  * Always called on splimp().
  563  */
  564 static void
  565 cxwatchdog (struct ifnet *ifp)
  566 {
  567         cx_chan_t *q, *c = ifp->if_softc;
  568 
  569         if (! (ifp->if_flags & IFF_RUNNING))
  570                 return;
  571         if (ifp->if_flags & IFF_DEBUG)
  572                 printf ("cx%d.%d: device timeout\n", c->board->num, c->num);
  573 
  574         cxdown (c);
  575         for (q=c->slaveq; q; q=q->slaveq)
  576                 cxdown (q);
  577 
  578         cxup (c);
  579         for (q=c->slaveq; q; q=q->slaveq)
  580                 cxup (q);
  581 
  582                 cxstart (ifp);
  583 }
  584 
  585 /*
  586  * Handle receive interrupts, including receive errors and
  587  * receive timeout interrupt.
  588  */
  589 static void 
  590 cxrinth (cx_chan_t *c)
  591 {
  592         unsigned short port = c->chip->port;
  593         unsigned short len, risr = inw (RISR(port));
  594 
  595         /* Receive errors. */
  596         if (risr & (RIS_BUSERR | RIS_OVERRUN | RISH_CRCERR | RISH_RXABORT)) {
  597                 if (c->ifp->if_flags & IFF_DEBUG)
  598                         printf ("cx%d.%d: receive error, risr=%b\n",
  599                                 c->board->num, c->num, risr, RISH_BITS);
  600                 ++c->ifp->if_ierrors;
  601                 ++c->stat->ierrs;
  602                 if (risr & RIS_OVERRUN)
  603                         ++c->ifp->if_collisions;
  604         } else if (risr & RIS_EOBUF) {
  605                 if (c->ifp->if_flags & IFF_DEBUG)
  606                         print (("cx%d.%d: hdlc receive interrupt, risr=%b, arbsts=%b, brbsts=%b\n",
  607                                 c->board->num, c->num, risr, RISH_BITS,
  608                                 inb (ARBSTS(port)), BSTS_BITS,
  609                                 inb (BRBSTS(port)), BSTS_BITS));
  610                 ++c->stat->ipkts;
  611 
  612                 /* Handle received data. */
  613                 len = (risr & RIS_BB) ? inw(BRBCNT(port)) : inw(ARBCNT(port));
  614                 c->stat->ibytes += len;
  615                 if (len > DMABUFSZ) {
  616                         /* Fatal error: actual DMA transfer size
  617                          * exceeds our buffer size.  It could be caused
  618                          * by incorrectly programmed DMA register or
  619                          * hardware fault.  Possibly, should panic here. */
  620                         printf ("cx%d.%d: panic! DMA buffer overflow: %d bytes\n",
  621                                c->board->num, c->num, len);
  622                         ++c->ifp->if_ierrors;
  623                 } else if (! (risr & RIS_EOFR)) {
  624                         /* The received frame does not fit in the DMA buffer.
  625                          * It could be caused by serial lie noise,
  626                          * or if the peer has too big MTU. */
  627                         if (c->ifp->if_flags & IFF_DEBUG)
  628                                 printf ("cx%d.%d: received frame length exceeds MTU, risr=%b\n",
  629                                         c->board->num, c->num, risr, RISH_BITS);
  630                         ++c->ifp->if_ierrors;
  631                 } else {
  632                         /* Valid frame received. */
  633                         if (c->ifp->if_flags & IFF_DEBUG)
  634                                 print (("cx%d.%d: hdlc received %d bytes\n",
  635                                 c->board->num, c->num, len));
  636                         cxinput (c, (risr & RIS_BB) ? c->brbuf : c->arbuf, len);
  637                         ++c->ifp->if_ipackets;
  638                 }
  639         } else if (c->ifp->if_flags & IFF_DEBUG) {
  640                 print (("cx%d.%d: unknown hdlc receive interrupt, risr=%b\n",
  641                         c->board->num, c->num, risr, RISH_BITS));
  642                 ++c->stat->ierrs;
  643         }
  644 
  645         /* Restart receiver. */
  646         if (! (inb (ARBSTS(port)) & BSTS_OWN24)) {
  647                 outw (ARBCNT(port), DMABUFSZ);
  648                 outb (ARBSTS(port), BSTS_OWN24);
  649         }
  650         if (! (inb (BRBSTS(port)) & BSTS_OWN24)) {
  651                 outw (BRBCNT(port), DMABUFSZ);
  652                 outb (BRBSTS(port), BSTS_OWN24);
  653         }
  654 }
  655 
  656 /*
  657  * Handle transmit interrupt.
  658  */
  659 static int
  660 cxtinth (cx_chan_t *c)
  661 {
  662         unsigned short port = c->chip->port;
  663         unsigned char tisr = inb (TISR(port));
  664         unsigned char teoir = 0;
  665 
  666         c->ifp->if_flags &= ~IFF_OACTIVE;
  667         if (c->ifp == c->master)
  668                 c->ifp->if_timer = 0;
  669 
  670         if (tisr & (TIS_BUSERR | TIS_UNDERRUN)) {
  671                 /* if (c->ifp->if_flags & IFF_DEBUG) */
  672                         print (("cx%d.%d: transmit error, tisr=%b, atbsts=%b, btbsts=%b\n",
  673                                 c->board->num, c->num, tisr, TIS_BITS,
  674                                 inb (ATBSTS(port)), BSTS_BITS,
  675                                 inb (BTBSTS(port)), BSTS_BITS));
  676                 ++c->ifp->if_oerrors;
  677                 ++c->stat->oerrs;
  678 
  679                 /* Terminate the failed buffer. */
  680                 /* teoir = TEOI_TERMBUFF; */
  681         } else if (c->ifp->if_flags & IFF_DEBUG)
  682                 print (("cx%d.%d: hdlc transmit interrupt, tisr=%b, atbsts=%b, btbsts=%b\n",
  683                         c->board->num, c->num, tisr, TIS_BITS,
  684                         inb (ATBSTS(port)), BSTS_BITS,
  685                         inb (BTBSTS(port)), BSTS_BITS));
  686 
  687         if (tisr & TIS_EOFR) {
  688                 ++c->ifp->if_opackets;
  689                 ++c->stat->opkts;
  690         }
  691 
  692         /* Start output on the (sub-) channel. */
  693         cxsend (c);
  694 
  695         return (teoir);
  696 }
  697 
  698 void
  699 cxintr (int bnum)
  700 {
  701         cx_board_t *b = cxboard + bnum;
  702         while (! (inw (BSR(b->port)) & BSR_NOINTR)) {
  703                 /* Acknowledge the interrupt to enter the interrupt context. */
  704                 /* Read the local interrupt vector register. */
  705                 unsigned char livr = inb (IACK(b->port, BRD_INTR_LEVEL));
  706                 cx_chan_t *c = b->chan + (livr>>2 & 0xf);
  707                 unsigned short port = c->chip->port;
  708                 unsigned short eoiport = REOIR(port);
  709                 unsigned char eoi = 0;
  710 
  711                 if (c->type == T_NONE) {
  712                         printf ("cx%d.%d: unexpected interrupt, livr=0x%x\n",
  713                                 c->board->num, c->num, livr);
  714                         continue;       /* incorrect channel number? */
  715                 }
  716                 /* print (("cx%d.%d: interrupt, livr=0x%x\n",
  717                         c->board->num, c->num, livr)); */
  718 
  719                 /* Clear RTS to stop receiver data flow while we are busy
  720                  * processing the interrupt, thus avoiding underruns. */
  721                 if (! c->sopt.norts) {
  722                         outb (MSVR_RTS(port), 0);
  723                         c->rts = 0;
  724                 }
  725 
  726                 switch (livr & 3) {
  727                 case LIV_EXCEP:         /* receive exception */
  728                 case LIV_RXDATA:        /* receive interrupt */
  729                         ++c->stat->rintr;
  730                         switch (c->mode) {
  731                         case M_ASYNC: eoi = cxrinta (c); break;
  732                         case M_HDLC:  cxrinth (c);       break;
  733                         default:;       /* No bisync and X.21 yet */
  734                         }
  735                         break;
  736                 case LIV_TXDATA:        /* transmit interrupt */
  737                         ++c->stat->tintr;
  738                         eoiport = TEOIR(port);
  739                         switch (c->mode) {
  740                         case M_ASYNC: cxtinta (c);       break;
  741                         case M_HDLC:  eoi = cxtinth (c); break;
  742                         default:;       /* No bisync and X.21 yet */
  743                         }
  744                         break;
  745                 case LIV_MODEM:         /* modem/timer interrupt */
  746                         ++c->stat->mintr;
  747                         eoiport = MEOIR(port);
  748                         cxmint (c);
  749                         break;
  750                 }
  751 
  752                 /* Raise RTS for this channel if and only if
  753                  * both receive buffers are empty. */
  754                 if (! c->sopt.norts && (inb (CSR(port)) & CSRA_RXEN) &&
  755                     (inb (ARBSTS(port)) & BSTS_OWN24) &&
  756                     (inb (BRBSTS(port)) & BSTS_OWN24)) {
  757                         outb (MSVR_RTS(port), MSV_RTS);
  758                         c->rts = 1;
  759                 }
  760 
  761                 /* Exit from interrupt context. */
  762                 outb (eoiport, eoi);
  763 
  764                 /* Master channel - start output on all idle subchannels. */
  765                 if (c->master == c->ifp && c->slaveq &&
  766                     (livr & 3) == LIV_TXDATA && c->mode == M_HDLC &&
  767                     ! sppp_isempty (c->ifp)) {
  768                         cx_chan_t *q;
  769 
  770                         for (q=c->slaveq; q; q=q->slaveq)
  771                                 if ((q->ifp->if_flags & IFF_RUNNING) &&
  772                                     ! (q->ifp->if_flags & IFF_OACTIVE))
  773                                         cxsend (q);
  774                 }
  775         }
  776 }
  777 
  778 /*
  779  * Process the received packet.
  780  */
  781 static void 
  782 cxinput (cx_chan_t *c, void *buf, unsigned len)
  783 {
  784         /* Make an mbuf. */
  785         struct mbuf *m = makembuf (buf, len);
  786         if (! m) {
  787                 if (c->ifp->if_flags & IFF_DEBUG)
  788                         printf ("cx%d.%d: no memory for packet\n",
  789                                 c->board->num, c->num);
  790                 ++c->ifp->if_iqdrops;
  791                 return;
  792         }
  793         m->m_pkthdr.rcvif = c->master;
  794 #ifdef DEBUG
  795         if (c->ifp->if_flags & IFF_DEBUG)
  796         printmbuf (m);
  797 #endif
  798 
  799 #if NBPFILTER > 0
  800         /*
  801          * Check if there's a BPF listener on this interface.
  802          * If so, hand off the raw packet to bpf.
  803          */
  804         if (c->ifp->if_bpf)
  805                 bpf_tap (c->ifp, buf, len);
  806 #endif
  807 
  808         /* Count the received bytes to the subchannel, not the master. */
  809         c->master->if_ibytes -= len + 3;
  810         c->ifp->if_ibytes += len + 3;
  811 
  812         sppp_input (c->master, m);
  813 }
  814 
  815 void cxswitch (cx_chan_t *c, cx_soft_opt_t new)
  816 {
  817         new.ext = 0;
  818         if (! new.ext) {
  819                 struct sppp *sp = (struct sppp*) c->ifp;
  820 
  821                 if (new.cisco)
  822                         sp->pp_flags |= PP_CISCO;
  823                 else
  824                         sp->pp_flags &= ~PP_CISCO;
  825                 if (new.keepalive)
  826                         sp->pp_flags |= PP_KEEPALIVE;
  827                 else
  828                         sp->pp_flags &= ~PP_KEEPALIVE;
  829         }
  830         c->sopt = new;
  831 }

Cache object: 48dfdb41f5b844d2521878ad704ea578


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.