home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / unix / bsd / 10393 < prev    next >
Encoding:
Internet Message Format  |  1992-12-21  |  22.0 KB

  1. Path: sparky!uunet!hoptoad!curt
  2. From: curt@hoptoad.uucp (Curt Mayer)
  3. Newsgroups: comp.unix.bsd
  4. Subject: Shitty NE2000 NFS performance problem fixed right (source code)
  5. Message-ID: <30089@hoptoad.uucp>
  6. Date: 18 Dec 92 21:20:25 GMT
  7. Distribution: world
  8. Organization: hardcore driver hackerz
  9. Lines: 854
  10. Summary: buggy driver, RTFM
  11.  
  12. after playing with if_ne for a day or two, i have made 8K NFS mounts solid.
  13. ftp performance is twice what the previous driver was. NFS is now filesystem
  14. limited, the way it should be.
  15.  
  16. bad buffer management, coupled with not using a high performance mode the
  17. ns8390, made the old driver lose bad when you got a lot of back to back
  18. packets.
  19.  
  20. CAVEATS:
  21.     ne1000 mode is untested, as I do not have one. I put the ne2000 clone
  22. I have into 8 bit mode, and tested the 8 bit stuff. because of this, consider
  23. this driver beta.
  24.  
  25. anyway, the new driver:
  26.  
  27. # This is a shell archive.  Save it in a file, remove anything before
  28. # this line, and then unpack it by entering "sh file".  Note, it may
  29. # create directories; files and directories will be owned by you and
  30. # have default permissions.
  31. #
  32. # This archive contains:
  33. #
  34. #    if_ne.c
  35. #
  36. echo x - if_ne.c
  37. sed 's/^X//' >if_ne.c << 'END-of-if_ne.c'
  38. X/*-
  39. X * Copyright (c) 1990, 1991 William F. Jolitz.
  40. X * Copyright (c) 1990 The Regents of the University of California.
  41. X * All rights reserved.
  42. X *
  43. X * Redistribution and use in source and binary forms, with or without
  44. X * modification, are permitted provided that the following conditions
  45. X * are met:
  46. X * 1. Redistributions of source code must retain the above copyright
  47. X *    notice, this list of conditions and the following disclaimer.
  48. X * 2. Redistributions in binary form must reproduce the above copyright
  49. X *    notice, this list of conditions and the following disclaimer in the
  50. X *    documentation and/or other materials provided with the distribution.
  51. X * 3. All advertising materials mentioning features or use of this software
  52. X *    must display the following acknowledgement:
  53. X *    This product includes software developed by the University of
  54. X *    California, Berkeley and its contributors.
  55. X * 4. Neither the name of the University nor the names of its contributors
  56. X *    may be used to endorse or promote products derived from this software
  57. X *    without specific prior written permission.
  58. X *
  59. X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  60. X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  61. X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  62. X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  63. X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  64. X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  65. X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  66. X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  67. X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  68. X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  69. X * SUCH DAMAGE.
  70. X *
  71. X *    @(#)if_ne.c    7.4 (Berkeley) 5/21/91
  72. X */
  73. X
  74. X/*
  75. X * NE2000 Ethernet driver
  76. X *
  77. X * Parts inspired from Tim Tucker's if_wd driver for the wd8003,
  78. X * insight on the ne2000 gained from Robert Clements PC/FTP driver.
  79. X *
  80. X * receive bottom end totally rewritten by Curt Mayer, Dec 1992.
  81. X * no longer loses back to back packets. 
  82. X * note to driver writers: RTFM!
  83. X */
  84. X
  85. X#include "ne.h"
  86. X#if NNE > 0
  87. X
  88. X#include "param.h"
  89. X#include "systm.h"
  90. X#include "mbuf.h"
  91. X#include "buf.h"
  92. X#include "protosw.h"
  93. X#include "socket.h"
  94. X#include "ioctl.h"
  95. X#include "errno.h"
  96. X#include "syslog.h"
  97. X
  98. X#include "net/if.h"
  99. X#include "net/netisr.h"
  100. X#include "net/route.h"
  101. X
  102. X#ifdef INET
  103. X#include "netinet/in.h"
  104. X#include "netinet/in_systm.h"
  105. X#include "netinet/in_var.h"
  106. X#include "netinet/ip.h"
  107. X#include "netinet/if_ether.h"
  108. X#endif
  109. X
  110. X#ifdef NS
  111. X#include "netns/ns.h"
  112. X#include "netns/ns_if.h"
  113. X#endif
  114. X
  115. X#include "i386/isa/isa_device.h"
  116. X#include "i386/isa/if_nereg.h"
  117. X#include "i386/isa/icu.h"
  118. X
  119. Xint    neprobe(), neattach(), neintr();
  120. Xint    nestart(),neinit(), ether_output(), neioctl();
  121. X
  122. Xstruct    isa_driver nedriver = {
  123. X    neprobe, neattach, "ne",
  124. X};
  125. X
  126. Xstruct    mbuf *neget();
  127. X
  128. X#define ETHER_MIN_LEN 64
  129. X#define ETHER_MAX_LEN 1536
  130. X
  131. X/*
  132. X * Ethernet software status per interface.
  133. X *
  134. X * Each interface is referenced by a network interface structure,
  135. X * ns_if, which the routing code uses to locate the interface.
  136. X * This structure contains the output queue for the interface, its address, ...
  137. X */
  138. Xstruct    ne_softc {
  139. X    struct    arpcom ns_ac;        /* Ethernet common part */
  140. X#define    ns_if    ns_ac.ac_if        /* network-visible interface */
  141. X#define    ns_addr    ns_ac.ac_enaddr        /* hardware Ethernet address */
  142. X    int    ns_flags;
  143. X#define    DSF_LOCK    1        /* block re-entering enstart */
  144. X    int    ns_oactive;
  145. X    int    ns_mask;
  146. X    struct    prhdr    ns_ph;        /* hardware header of incoming packet*/
  147. X    u_char    ns_pb[2048];
  148. X    u_char    ns_txstart;        /* transmitter buffer start */
  149. X    u_char    ns_rxstart;        /* receiver buffer start */
  150. X    u_char    ns_rxend;        /* receiver buffer end */
  151. X    short    ns_port;        /* i/o port base */
  152. X    short    ns_mode;        /* word/byte mode */
  153. X} ne_softc[NNE] ;
  154. X#define    ENBUFSIZE    (sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN)
  155. X
  156. X#define    PAT(n)    (0xa55a + 37*(n))
  157. X
  158. Xu_short boarddata[16];
  159. Xneprobe(dvp)
  160. X    struct isa_device *dvp;
  161. X{
  162. X    int val, i, s, sum, pat;
  163. X    register struct ne_softc *ns = &ne_softc[0];
  164. X    register nec;
  165. X
  166. X#ifdef lint
  167. X    neintr(0);
  168. X#endif
  169. X
  170. X    nec = ns->ns_port = dvp->id_iobase;
  171. X    s = splimp();
  172. X
  173. X    /* Byte Transfers, Burst Mode Select, Fifo at 8 bytes */
  174. X    ns->ns_mode = DSDC_BMS|DSDC_FT1;
  175. X    ns->ns_txstart = TBUF8 / DS_PGSIZE;
  176. X    ns->ns_rxend = RBUFEND8 / DS_PGSIZE;
  177. X
  178. Xtryagain:
  179. X
  180. X    ns->ns_rxstart = ns->ns_txstart + (PKTSZ / DS_PGSIZE);
  181. X
  182. X    /* Reset the bastard */
  183. X    val = inb(nec + ne_reset);
  184. X    DELAY(200);
  185. X    outb(nec + ne_reset, val);
  186. X    DELAY(200);
  187. X
  188. X    outb(nec + ds_cmd, DSCM_STOP|DSCM_NODMA);
  189. X    
  190. X    i = 10000;
  191. X    while ((inb(nec + ds0_isr) & DSIS_RESET) == 0 && i-- > 0);
  192. X    if (i < 0) return (0);
  193. X
  194. X    outb(nec + ds0_isr, 0xff);
  195. X    outb(nec + ds0_dcr, ns->ns_mode);
  196. X    outb(nec + ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
  197. X    DELAY(1000);
  198. X
  199. X    /* Check cmd reg and fail if not right */
  200. X    if ((i = inb(nec + ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))
  201. X        return(0);
  202. X
  203. X    outb(nec + ds0_tcr, 0);
  204. X    outb(nec + ds0_rcr, DSRC_MON);
  205. X    outb(nec + ds0_pstart, ns->ns_rxstart);
  206. X    outb(nec + ds0_pstop, ns->ns_rxend);
  207. X    outb(nec + ds0_imr, 0);
  208. X    outb(nec + ds0_isr, 0);
  209. X    outb(nec + ds0_bnry, ns->ns_rxstart);
  210. X    outb(nec + ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
  211. X    outb(nec + ds1_curr, ns->ns_rxstart);
  212. X    outb(nec + ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
  213. X
  214. X    /*
  215. X     * <groan> detect difference between units
  216. X     * solely by where the RAM is decoded.
  217. X     */
  218. X    pat = PAT(0);
  219. X    neput(ns, &pat, ns->ns_txstart * DS_PGSIZE, 4);
  220. X    nefetch(ns, &pat, ns->ns_txstart * DS_PGSIZE, 4);
  221. X    if (pat != PAT(0)) {
  222. X        if (ns->ns_mode & DSDC_WTS)
  223. X            return (0);
  224. X
  225. X        /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
  226. X        ns->ns_mode = DSDC_WTS|DSDC_BMS|DSDC_FT1;
  227. X        ns->ns_txstart = TBUF16 / DS_PGSIZE;
  228. X        ns->ns_rxend = RBUFEND16 / DS_PGSIZE;
  229. X        goto tryagain;
  230. X    }
  231. X
  232. X
  233. X    /* Extract board address */
  234. X    nefetch (ns, (caddr_t)boarddata, 0, sizeof(boarddata));
  235. X
  236. X    for(i=0; i < 6; i++)
  237. X        ns->ns_addr[i] = boarddata[i];
  238. X    splx(s);
  239. X    return (1);
  240. X}
  241. X
  242. X/*
  243. X * Fetch from onboard ROM/RAM
  244. X */
  245. Xnefetch (ns, up, ad, len) struct ne_softc *ns; caddr_t up; {
  246. X    u_char cmd;
  247. X    register nec = ns->ns_port;
  248. X    int counter = 100000;
  249. X
  250. X    cmd = inb (nec + ds_cmd);
  251. X    outb (nec + ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
  252. X
  253. X    /* Setup remote dma */
  254. X    outb (nec + ds0_isr, DSIS_RDC);
  255. X
  256. X    if ((ns->ns_mode & DSDC_WTS) && (len & 1))
  257. X        len++;        /* roundup to words */
  258. X
  259. X    outb (nec+ds0_rbcr0, len);
  260. X    outb (nec+ds0_rbcr1, len>>8);
  261. X    outb (nec+ds0_rsar0, ad);
  262. X    outb (nec+ds0_rsar1, ad>>8);
  263. X
  264. X    /* Execute & extract from card */
  265. X    outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
  266. X
  267. X    if (ns->ns_mode & DSDC_WTS)
  268. X        insw (nec+ne_data, up, len/2);
  269. X    else
  270. X        insb (nec+ne_data, up, len);
  271. X
  272. X    /* Wait till done, then shutdown feature */
  273. X    while ((inb (nec+ds0_isr) & DSIS_RDC) == 0 && counter-- > 0)
  274. X        ;
  275. X    outb (nec+ds0_isr, DSIS_RDC);
  276. X    outb (nec+ds_cmd, cmd);
  277. X}
  278. X
  279. X/*
  280. X * Put to onboard RAM
  281. X */
  282. Xneput (ns, up, ad, len) struct ne_softc *ns; caddr_t up; {
  283. X    u_char cmd;
  284. X    register nec = ns->ns_port;
  285. X    int counter = 100000;
  286. X
  287. X    cmd = inb(nec+ds_cmd);
  288. X    outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
  289. X
  290. X    /* Setup for remote dma */
  291. X    outb (nec+ds0_isr, DSIS_RDC);
  292. X
  293. X    if ((ns->ns_mode & DSDC_WTS) && (len & 1))
  294. X        len++;        /* roundup to words */
  295. X
  296. X    outb (nec+ds0_rbcr0, len);
  297. X    outb (nec+ds0_rbcr1, len>>8);
  298. X    outb (nec+ds0_rsar0, ad);
  299. X    outb (nec+ds0_rsar1, ad>>8);
  300. X
  301. X    /* Execute & stuff to card */
  302. X    outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
  303. X    if (ns->ns_mode & DSDC_WTS)
  304. X        outsw (nec+ne_data, up, len/2);
  305. X    else
  306. X        outsb (nec+ne_data, up, len);
  307. X    
  308. X    /* Wait till done, then shutdown feature */
  309. X    while ((inb (nec+ds0_isr) & DSIS_RDC) == 0 && counter-- > 0)
  310. X        ;
  311. X    outb (nec+ds0_isr, DSIS_RDC);
  312. X    outb (nec+ds_cmd, cmd);
  313. X}
  314. X
  315. X/*
  316. X * Reset of interface.
  317. X */
  318. Xnereset(unit, uban)
  319. X    int unit, uban;
  320. X{
  321. X    if (unit >= NNE)
  322. X        return;
  323. X    printf("ne%d: reset\n", unit);
  324. X    ne_softc[unit].ns_flags &= ~DSF_LOCK;
  325. X    neinit(unit);
  326. X}
  327. X/*
  328. X * Interface exists: make available by filling in network interface
  329. X * record.  System will initialize the interface when it is ready
  330. X * to accept packets.  We get the ethernet address here.
  331. X */
  332. Xneattach(dvp)
  333. X    struct isa_device *dvp;
  334. X{
  335. X    int unit = dvp->id_unit;
  336. X    register struct ne_softc *ns = &ne_softc[unit];
  337. X    register struct ifnet *ifp = &ns->ns_if;
  338. X
  339. X    ifp->if_unit = unit;
  340. X    ifp->if_name = nedriver.name ;
  341. X    ifp->if_mtu = ETHERMTU;
  342. X    printf (" ne%d, address %s", 
  343. X        (ns->ns_mode & DSDC_WTS) ? 2000 : 1000,
  344. X        ether_sprintf(ns->ns_addr)) ;
  345. X    ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
  346. X    ifp->if_init = neinit;
  347. X    ifp->if_output = ether_output;
  348. X    ifp->if_start = nestart;
  349. X    ifp->if_ioctl = neioctl;
  350. X    ifp->if_reset = nereset;
  351. X    ifp->if_watchdog = 0;
  352. X    if_attach(ifp);
  353. X}
  354. X
  355. X/*
  356. X * Initialization of interface; set up initialization block
  357. X * and transmit/receive descriptor rings.
  358. X */
  359. Xneinit(unit)
  360. X    int unit;
  361. X{
  362. X    register struct ne_softc *ns = &ne_softc[unit];
  363. X    struct ifnet *ifp = &ns->ns_if;
  364. X    int s;
  365. X    int i; char *cp;
  366. X    register nec = ns->ns_port;
  367. X
  368. X     if (ifp->if_addrlist == (struct ifaddr *)0) return;
  369. X    if (ifp->if_flags & IFF_RUNNING) return;
  370. X
  371. X    s = splimp();
  372. X
  373. X    /* set physical address on ethernet */
  374. X    outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
  375. X    for (i=0 ; i < 6 ; i++) outb(nec+ds1_par0+i,ns->ns_addr[i]);
  376. X
  377. X    /* clr logical address hash filter for now */
  378. X    for (i=0 ; i < 8 ; i++) outb(nec+ds1_mar0+i,0xff);
  379. X
  380. X    /* init regs */
  381. X    outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
  382. X    outb (nec+ds0_rbcr0, 0);
  383. X    outb (nec+ds0_rbcr1, 0);
  384. X    outb (nec+ds0_imr, 0);
  385. X    outb (nec+ds0_isr, 0xff);
  386. X    outb(nec+ds0_dcr, ns->ns_mode);
  387. X    outb(nec+ds0_tcr, 0);
  388. X    outb (nec+ds0_rcr, DSRC_MON);
  389. X    outb (nec+ds0_tpsr, 0);
  390. X    outb(nec+ds0_pstart, ns->ns_rxstart);
  391. X    outb(nec+ds0_pstop, ns->ns_rxend);
  392. X    outb(nec+ds0_bnry, ns->ns_rxstart);
  393. X    outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
  394. X    outb(nec+ds1_curr, ns->ns_rxstart);
  395. X    outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
  396. X    outb (nec+ds0_rcr, DSRC_AB);
  397. X    outb(nec+ds0_dcr, ns->ns_mode);
  398. X    outb (nec+ds0_imr, 0xff);
  399. X
  400. X    ns->ns_if.if_flags |= IFF_RUNNING;
  401. X    ns->ns_flags &= ~DSF_LOCK;
  402. X    ns->ns_oactive = 0; ns->ns_mask = ~0;
  403. X    nestart(ifp);
  404. X    splx(s);
  405. X}
  406. X
  407. X/*
  408. X * Setup output on interface.
  409. X * Get another datagram to send off of the interface queue,
  410. X * and map it to the interface before starting the output.
  411. X * called only at splimp or interrupt level.
  412. X */
  413. Xnestart(ifp)
  414. X    struct ifnet *ifp;
  415. X{
  416. X    register struct ne_softc *ns = &ne_softc[ifp->if_unit];
  417. X    struct mbuf *m0, *m;
  418. X    int buffer;
  419. X    int len = 0, i, total,t;
  420. X    register nec = ns->ns_port;
  421. X
  422. X    /*
  423. X     * The DS8390 has only one transmit buffer, if it is busy we
  424. X     * must wait until the transmit interrupt completes.
  425. X     */
  426. X    outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
  427. X
  428. X    if (ns->ns_flags & DSF_LOCK)
  429. X        return;
  430. X
  431. X    if (inb(nec+ds_cmd) & DSCM_TRANS)
  432. X        return;
  433. X
  434. X    if ((ns->ns_if.if_flags & IFF_RUNNING) == 0)
  435. X        return;
  436. X
  437. X    IF_DEQUEUE(&ns->ns_if.if_snd, m);
  438. X    if (m == 0)
  439. X        return;
  440. X
  441. X    /*
  442. X     * Copy the mbuf chain into the transmit buffer
  443. X     */
  444. X
  445. X    ns->ns_flags |= DSF_LOCK;    /* prevent entering nestart */
  446. X    buffer = ns->ns_txstart * DS_PGSIZE; 
  447. X    len = i = 0;
  448. X    t = 0;
  449. X    for (m0 = m; m != 0; m = m->m_next)
  450. X        t += m->m_len;
  451. X        
  452. X    m = m0;
  453. X    total = t;
  454. X    for (m0 = m; m != 0; ) {
  455. X        
  456. X        if (m->m_len&1 && t > m->m_len) {
  457. X            neput(ns, mtod(m, caddr_t), buffer, m->m_len - 1);
  458. X            t -= m->m_len - 1;
  459. X            buffer += m->m_len - 1;
  460. X            m->m_data += m->m_len - 1;
  461. X            m->m_len = 1;
  462. X            m = m_pullup(m, 2);
  463. X        } else {
  464. X            neput(ns, mtod(m, caddr_t), buffer, m->m_len);
  465. X            buffer += m->m_len;
  466. X            t -= m->m_len;
  467. X            MFREE(m, m0);
  468. X            m = m0;
  469. X        }
  470. X    }
  471. X
  472. X    /*
  473. X     * Init transmit length registers, and set transmit start flag.
  474. X     */
  475. X
  476. X    len = total;
  477. X    if (len < ETHER_MIN_LEN) len = ETHER_MIN_LEN;
  478. X    outb(nec+ds0_tbcr0,len&0xff);
  479. X    outb(nec+ds0_tbcr1,(len>>8)&0xff);
  480. X    outb(nec+ds0_tpsr, ns->ns_txstart);
  481. X    outb(nec+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START);
  482. X}
  483. X
  484. X/*
  485. X * Controller interrupt.
  486. X */
  487. Xneintr(unit)
  488. X{
  489. X    register struct ne_softc *ns = &ne_softc[unit];
  490. X    u_char cmd,isr;
  491. X    register nec = ns->ns_port;
  492. X    u_char err;
  493. X
  494. X    /* Save cmd, clear interrupt */
  495. X    cmd = inb (nec+ds_cmd);
  496. Xloop:
  497. X    isr = inb (nec+ds0_isr);
  498. X    outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
  499. X    outb(nec+ds0_isr, isr);
  500. X
  501. X    /* Receiver error */
  502. X    if (isr & DSIS_RXE) {
  503. X        /* need to read these registers to clear status */
  504. X        err = inb(nec+ ds0_rsr);
  505. X        (void)inb(nec+0xD); 
  506. X        (void)inb(nec+0xE); 
  507. X        (void)inb(nec+0xF);
  508. X        ns->ns_if.if_ierrors++;
  509. X    }
  510. X
  511. X    /* We received something */
  512. X    if (isr & DSIS_RX) {
  513. X        u_char bnry;
  514. X        u_char curr;
  515. X        int len;
  516. X        int i; 
  517. X        unsigned char c;
  518. X
  519. X        while (1) {
  520. X
  521. X            outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
  522. X            bnry = inb(nec+ds0_bnry);
  523. X            outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
  524. X            curr = inb(nec+ds1_curr); 
  525. X
  526. X#ifdef NEDEBUG
  527. X            printf("neintr: bnry %x curr %x\n", bnry, curr);
  528. X#endif
  529. X
  530. X            /* if ring empty, done! */
  531. X            if (bnry == curr) {
  532. X                break;
  533. X            }
  534. X
  535. X            /* send packet with auto packet release */
  536. X            outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
  537. X            outb (nec+ds0_rbcr1, 0x0f);
  538. X            outb(nec+ds0_dcr, ns->ns_mode | DSDC_AR);
  539. X            outb (nec+ds_cmd, DSCM_SENDP|DSCM_PG0|DSCM_START);
  540. X
  541. X            /* get length */
  542. X            if ((ns->ns_mode & DSDC_WTS))
  543. X                insw (nec+ne_data, (u_short *)&ns->ns_ph, 2);
  544. X            else
  545. X                insb (nec+ne_data, &ns->ns_ph, 4);
  546. X
  547. X#ifdef NEDEBUG
  548. X            printf("neintr: sendp packet hdr: %x %x %x %x\n",
  549. X                ns->ns_ph.pr_status,
  550. X                ns->ns_ph.pr_nxtpg,
  551. X                ns->ns_ph.pr_sz0,
  552. X                ns->ns_ph.pr_sz1);
  553. X#endif
  554. X
  555. X            ns->ns_if.if_ipackets++;
  556. X            len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1<<8);
  557. X            if (len < ETHER_MIN_LEN || len > ETHER_MAX_LEN) {
  558. X                printf("neintr: bnry %x curr %x\n", bnry, curr);
  559. X                printf("neintr: packet hdr: %x %x %x %x\n",
  560. X                    ns->ns_ph.pr_status,
  561. X                    ns->ns_ph.pr_nxtpg,
  562. X                    ns->ns_ph.pr_sz0,
  563. X                    ns->ns_ph.pr_sz1);
  564. X                printf("isr = 0x%x reg_isr=0x%x\n", 
  565. X                    isr, inb(nec+ds0_isr));
  566. X                outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
  567. X                bnry = inb(nec+ds0_bnry);
  568. X                outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
  569. X                curr = inb(nec+ds1_curr); 
  570. X                printf("neintr: new bnry %x curr %x\n", bnry, curr);
  571. X                printf("neintr: bad len %d\n-hanging-\n",
  572. X                    len);
  573. X                while (1) ; 
  574. X            }
  575. X
  576. X#ifdef NEDEBUG
  577. X            printf("neintr: snarfing %d bytes\n", len);
  578. X#endif
  579. X
  580. X            /* read packet */
  581. X            if ((ns->ns_mode & DSDC_WTS)) {
  582. X                insw (nec+ne_data, (u_short *)&ns->ns_pb, 
  583. X                    len / 2);
  584. X                if (len & 1)
  585. X                    ns->ns_pb[len-1] = inb(nec+ne_data);
  586. X            } else {
  587. X                insb (nec+ne_data, ns->ns_pb, len);
  588. X            }
  589. X
  590. X            if (!(inb (nec+ds0_isr) & DSIS_RDC)) {
  591. X                printf("neintr: remote dma not done\nflushing...\n");
  592. X                len = 0;
  593. X                while (1) {
  594. X                    printf("%d %x\n", len, inb(nec+ne_data));
  595. X                    len++;
  596. X                }
  597. X            }
  598. X
  599. X            /* clear RDC */
  600. X            outb (nec + ds0_isr, DSIS_RDC);
  601. X
  602. X            outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
  603. X
  604. X            /* adjust for ether header and checksum */
  605. X            len -= sizeof(struct ether_header) + sizeof(long);
  606. X
  607. X            /* process packet */
  608. X            neread(ns,(caddr_t)(ns->ns_pb), len);
  609. X        }
  610. X    }
  611. X
  612. X    /* Transmit error */
  613. X    if (isr & DSIS_TXE) {
  614. X        ns->ns_flags &= ~DSF_LOCK;
  615. X        /* Need to read these registers to clear status */
  616. X        ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
  617. X        ns->ns_if.if_oerrors++;
  618. X    }
  619. X
  620. X    /* Packet Transmitted */
  621. X    if (isr & DSIS_TX) {
  622. X        ns->ns_flags &= ~DSF_LOCK;
  623. X        ++ns->ns_if.if_opackets;
  624. X        ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
  625. X    }
  626. X
  627. X    /* Receiver ovverun? */
  628. X    if (isr & DSIS_ROVRN) {
  629. X        log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr
  630. X            /*, DSIS_BITS*/);
  631. X        outb(nec+ds0_rbcr0, 0);
  632. X        outb(nec+ds0_rbcr1, 0);
  633. X        outb(nec+ds0_tcr, DSTC_LB0);
  634. X        outb(nec+ds0_rcr, DSRC_MON);
  635. X        outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
  636. X        outb(nec+ds0_rcr, DSRC_AB);
  637. X        outb(nec+ds0_tcr, 0);
  638. X    }
  639. X
  640. X    /* Any more to send? */
  641. X    outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
  642. X    nestart(&ns->ns_if);
  643. X    outb (nec+ds_cmd, cmd);
  644. X    outb (nec+ds0_imr, 0xff);
  645. X
  646. X    /* Still more to do? */
  647. X    isr = inb (nec+ds0_isr);
  648. X    if(isr) goto loop;
  649. X}
  650. X
  651. X/*
  652. X * Pass a packet to the higher levels.
  653. X * We deal with the trailer protocol here.
  654. X */
  655. Xneread(ns, buf, len)
  656. X    register struct ne_softc *ns;
  657. X    char *buf;
  658. X    int len;
  659. X{
  660. X    register struct ether_header *eh;
  661. X        struct mbuf *m;
  662. X    int off, resid;
  663. X    register struct ifqueue *inq;
  664. X
  665. X    /*
  666. X     * Deal with trailer protocol: if type is trailer type
  667. X     * get true type from first 16-bit word past data.
  668. X     * Remember that type was trailer by setting off.
  669. X     */
  670. X    eh = (struct ether_header *)buf;
  671. X    eh->ether_type = ntohs((u_short)eh->ether_type);
  672. X#define    nedataaddr(eh, off, type)    ((type)(((caddr_t)((eh)+1)+(off))))
  673. X    if (eh->ether_type >= ETHERTYPE_TRAIL &&
  674. X        eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
  675. X        off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
  676. X        if (off >= ETHERMTU) return;        /* sanity */
  677. X        eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
  678. X        resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
  679. X        if (off + resid > len) return;        /* sanity */
  680. X        len = off + resid;
  681. X    } else    off = 0;
  682. X
  683. X    if (len == 0) return;
  684. X
  685. X    /*
  686. X     * Pull packet off interface.  Off is nonzero if packet
  687. X     * has trailing header; neget will then force this header
  688. X     * information to be at the front, but we still have to drop
  689. X     * the type and length which are at the front of any trailer data.
  690. X     */
  691. X    m = neget(buf, len, off, &ns->ns_if);
  692. X    if (m == 0) return;
  693. X
  694. X    ether_input(&ns->ns_if, eh, m);
  695. X}
  696. X
  697. X/*
  698. X * Supporting routines
  699. X */
  700. X
  701. X/*
  702. X * Pull read data off a interface.
  703. X * Len is length of data, with local net header stripped.
  704. X * Off is non-zero if a trailer protocol was used, and
  705. X * gives the offset of the trailer information.
  706. X * We copy the trailer information and then all the normal
  707. X * data into mbufs.  When full cluster sized units are present
  708. X * we copy into clusters.
  709. X */
  710. Xstruct mbuf *
  711. Xneget(buf, totlen, off0, ifp)
  712. X    caddr_t buf;
  713. X    int totlen, off0;
  714. X    struct ifnet *ifp;
  715. X{
  716. X    struct mbuf *top, **mp, *m, *p;
  717. X    int off = off0, len;
  718. X    register caddr_t cp = buf;
  719. X    char *epkt;
  720. X
  721. X    buf += sizeof(struct ether_header);
  722. X    cp = buf;
  723. X    epkt = cp + totlen;
  724. X
  725. X
  726. X    if (off) {
  727. X        cp += off + 2 * sizeof(u_short);
  728. X        totlen -= 2 * sizeof(u_short);
  729. X    }
  730. X
  731. X    MGETHDR(m, M_DONTWAIT, MT_DATA);
  732. X    if (m == 0)
  733. X        return (0);
  734. X    m->m_pkthdr.rcvif = ifp;
  735. X    m->m_pkthdr.len = totlen;
  736. X    m->m_len = MHLEN;
  737. X
  738. X    top = 0;
  739. X    mp = ⊤
  740. X    while (totlen > 0) {
  741. X        if (top) {
  742. X            MGET(m, M_DONTWAIT, MT_DATA);
  743. X            if (m == 0) {
  744. X                m_freem(top);
  745. X                return (0);
  746. X            }
  747. X            m->m_len = MLEN;
  748. X        }
  749. X        len = min(totlen, epkt - cp);
  750. X        if (len >= MINCLSIZE) {
  751. X            MCLGET(m, M_DONTWAIT);
  752. X            if (m->m_flags & M_EXT)
  753. X                m->m_len = len = min(len, MCLBYTES);
  754. X            else
  755. X                len = m->m_len;
  756. X        } else {
  757. X            /*
  758. X             * Place initial small packet/header at end of mbuf.
  759. X             */
  760. X            if (len < m->m_len) {
  761. X                if (top == 0 && len + max_linkhdr <= m->m_len)
  762. X                    m->m_data += max_linkhdr;
  763. X                m->m_len = len;
  764. X            } else
  765. X                len = m->m_len;
  766. X        }
  767. X        bcopy(cp, mtod(m, caddr_t), (unsigned)len);
  768. X        cp += len;
  769. X        *mp = m;
  770. X        mp = &m->m_next;
  771. X        totlen -= len;
  772. X        if (cp == epkt)
  773. X            cp = buf;
  774. X    }
  775. X    return (top);
  776. X}
  777. X
  778. X/*
  779. X * Process an ioctl request.
  780. X */
  781. Xneioctl(ifp, cmd, data)
  782. X    register struct ifnet *ifp;
  783. X    int cmd;
  784. X    caddr_t data;
  785. X{
  786. X    register struct ifaddr *ifa = (struct ifaddr *)data;
  787. X    struct ne_softc *ns = &ne_softc[ifp->if_unit];
  788. X    struct ifreq *ifr = (struct ifreq *)data;
  789. X    int s = splimp(), error = 0;
  790. X
  791. X
  792. X    switch (cmd) {
  793. X
  794. X    case SIOCSIFADDR:
  795. X        ifp->if_flags |= IFF_UP;
  796. X
  797. X        switch (ifa->ifa_addr->sa_family) {
  798. X#ifdef INET
  799. X        case AF_INET:
  800. X            neinit(ifp->if_unit);    /* before arpwhohas */
  801. X            ((struct arpcom *)ifp)->ac_ipaddr =
  802. X                IA_SIN(ifa)->sin_addr;
  803. X            arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
  804. X            break;
  805. X#endif
  806. X#ifdef NS
  807. X        case AF_NS:
  808. X            {
  809. X            register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
  810. X
  811. X            if (ns_nullhost(*ina))
  812. X                ina->x_host = *(union ns_host *)(ns->ns_addr);
  813. X            else {
  814. X                /* 
  815. X                 * The manual says we can't change the address 
  816. X                 * while the receiver is armed,
  817. X                 * so reset everything
  818. X                 */
  819. X                ifp->if_flags &= ~IFF_RUNNING; 
  820. X                bcopy((caddr_t)ina->x_host.c_host,
  821. X                    (caddr_t)ns->ns_addr, sizeof(ns->ns_addr));
  822. X            }
  823. X            neinit(ifp->if_unit); /* does ne_setaddr() */
  824. X            break;
  825. X            }
  826. X#endif
  827. X        default:
  828. X            neinit(ifp->if_unit);
  829. X            break;
  830. X        }
  831. X        break;
  832. X
  833. X    case SIOCSIFFLAGS:
  834. X        if ((ifp->if_flags & IFF_UP) == 0 &&
  835. X            ifp->if_flags & IFF_RUNNING) {
  836. X            ifp->if_flags &= ~IFF_RUNNING;
  837. X            outb(ns->ns_port + ds_cmd, DSCM_STOP|DSCM_NODMA);
  838. X        } else if (ifp->if_flags & IFF_UP &&
  839. X            (ifp->if_flags & IFF_RUNNING) == 0)
  840. X            neinit(ifp->if_unit);
  841. X        break;
  842. X
  843. X#ifdef notdef
  844. X    case SIOCGHWADDR:
  845. X        bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data,
  846. X            sizeof(ns->ns_addr));
  847. X        break;
  848. X#endif
  849. X
  850. X    default:
  851. X        error = EINVAL;
  852. X    }
  853. X    splx(s);
  854. X    return (error);
  855. X}
  856. X#endif
  857. END-of-if_ne.c
  858. exit
  859. -- 
  860.     curt mayer
  861.         curt@toad.com
  862.         415-387-0217 home
  863.