[BACK]Return to am7990.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / ic

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /src/sys/dev/ic/am7990.c between version 1.50 and 1.51

version 1.50, 1998/07/07 14:13:51 version 1.51, 1998/07/21 17:26:45
Line 76 
Line 76 
  *      @(#)if_le.c     8.2 (Berkeley) 11/16/93   *      @(#)if_le.c     8.2 (Berkeley) 11/16/93
  */   */
   
 #include "opt_ddb.h"  
 #include "opt_inet.h"  
 #include "opt_ccitt.h"  
 #include "opt_llc.h"  
 #include "opt_ns.h"  
 #include "bpfilter.h"  #include "bpfilter.h"
 #include "rnd.h"  #include "rnd.h"
   
Line 102 
Line 97 
 #include <net/if_ether.h>  #include <net/if_ether.h>
 #include <net/if_media.h>  #include <net/if_media.h>
   
 #ifdef INET  
 #include <netinet/in.h>  
 #include <netinet/if_inarp.h>  
 #include <netinet/in_systm.h>  
 #include <netinet/in_var.h>  
 #include <netinet/ip.h>  
 #endif  
   
 #ifdef NS  
 #include <netns/ns.h>  
 #include <netns/ns_if.h>  
 #endif  
   
 #if defined(CCITT) && defined(LLC)  
 #include <sys/socketvar.h>  
 #include <netccitt/x25.h>  
 #include <netccitt/pk.h>  
 #include <netccitt/pk_var.h>  
 #include <netccitt/pk_extern.h>  
 #endif  
   
 #if NBPFILTER > 0  #if NBPFILTER > 0
 #include <net/bpf.h>  #include <net/bpf.h>
 #include <net/bpfdesc.h>  #include <net/bpfdesc.h>
 #endif  #endif
   
   #include <dev/ic/lancereg.h>
   #include <dev/ic/lancevar.h>
 #include <dev/ic/am7990reg.h>  #include <dev/ic/am7990reg.h>
 #include <dev/ic/am7990var.h>  #include <dev/ic/am7990var.h>
   
 #ifdef LEDEBUG  void am7990_meminit __P((struct lance_softc *));
 void am7990_recv_print __P((struct am7990_softc *, int));  void am7990_start __P((struct ifnet *));
 void am7990_xmit_print __P((struct am7990_softc *, int));  
 #endif  
   
 integrate void am7990_rint __P((struct am7990_softc *));  
 integrate void am7990_tint __P((struct am7990_softc *));  
   
 integrate int am7990_put __P((struct am7990_softc *, int, struct mbuf *));  
 integrate struct mbuf *am7990_get __P((struct am7990_softc *, int, int));  
 integrate void am7990_read __P((struct am7990_softc *, int, int));  
   
 hide void am7990_shutdown __P((void *));  
   
 int am7990_mediachange __P((struct ifnet *));  #if defined(_KERNEL) && !defined(_LKM)
 void am7990_mediastatus __P((struct ifnet *, struct ifmediareq *));  #include "opt_ddb.h"
   #endif
 #define ifp     (&sc->sc_ethercom.ec_if)  
   
 static inline u_int16_t ether_cmp __P((void *, void *));  
   
 /*  
  * Compare two Ether/802 addresses for equality, inlined and  
  * unrolled for speed.  Use this like bcmp().  
  *  
  * XXX: Add <machine/inlines.h> for stuff like this?  
  * XXX: or maybe add it to libkern.h instead?  
  *  
  * "I'd love to have an inline assembler version of this."  
  * XXX: Who wanted that? mycroft?  I wrote one, but this  
  * version in C is as good as hand-coded assembly. -gwr  
  *  
  * Please do NOT tweak this without looking at the actual  
  * assembly code generated before and after your tweaks!  
  */  
 static inline u_int16_t  
 ether_cmp(one, two)  
         void *one, *two;  
 {  
         register u_int16_t *a = (u_short *) one;  
         register u_int16_t *b = (u_short *) two;  
         register u_int16_t diff;  
   
 #ifdef  m68k  #ifdef DDB
         /*  #define integrate
          * The post-increment-pointer form produces the best  #define hide
          * machine code for m68k.  This was carefully tuned  
          * so it compiles to just 8 short (2-byte) op-codes!  
          */  
         diff  = *a++ - *b++;  
         diff |= *a++ - *b++;  
         diff |= *a++ - *b++;  
 #else  #else
         /*  #define integrate       static __inline
          * Most modern CPUs do better with a single expresion.  #define hide            static
          * Note that short-cut evaluation is NOT helpful here,  
          * because it just makes the code longer, not faster!  
          */  
         diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);  
 #endif  #endif
   
         return (diff);  integrate void am7990_rint __P((struct lance_softc *));
 }  integrate void am7990_tint __P((struct lance_softc *));
   
 #define ETHER_CMP       ether_cmp  
   
 #ifdef LANCE_REVC_BUG  #ifdef LEDEBUG
 /* Make sure this is short-aligned, for ether_cmp(). */  void am7990_recv_print __P((struct lance_softc *, int));
 static u_int16_t bcast_enaddr[3] = { ~0, ~0, ~0 };  void am7990_xmit_print __P((struct lance_softc *, int));
 #endif  #endif
   
   #define ifp     (&sc->sc_ethercom.ec_if)
   
 void  void
 am7990_config(sc)  am7990_config(sc)
         struct am7990_softc *sc;          struct am7990_softc *sc;
 {  {
         int mem, i;          int mem, i;
   
         /* Make sure the chip is stopped. */          sc->lsc.sc_meminit = am7990_meminit;
         am7990_stop(sc);          sc->lsc.sc_start = am7990_start;
   
         /* Initialize ifnet structure. */  
         bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);  
         ifp->if_softc = sc;  
         ifp->if_start = am7990_start;  
         ifp->if_ioctl = am7990_ioctl;  
         ifp->if_watchdog = am7990_watchdog;  
         ifp->if_flags =  
             IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;  
 #ifdef LANCE_REVC_BUG  
         ifp->if_flags &= ~IFF_MULTICAST;  
 #endif  
   
         /* Initialize ifmedia structures. */  
         ifmedia_init(&sc->sc_media, 0, am7990_mediachange, am7990_mediastatus);  
         if (sc->sc_supmedia != NULL) {  
                 for (i = 0; i < sc->sc_nsupmedia; i++)  
                         ifmedia_add(&sc->sc_media, sc->sc_supmedia[i],  
                            0, NULL);  
                 ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);  
         } else {  
                 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);  
                 ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);  
         }  
   
         /* Attach the interface. */  
         if_attach(ifp);  
         ether_ifattach(ifp, sc->sc_enaddr);  
   
 #if NBPFILTER > 0          lance_config(&sc->lsc);
         bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));  
 #endif  
   
         switch (sc->sc_memsize) {  
         case 8192:  
                 sc->sc_nrbuf = 4;  
                 sc->sc_ntbuf = 1;  
                 break;  
         case 16384:  
                 sc->sc_nrbuf = 8;  
                 sc->sc_ntbuf = 2;  
                 break;  
         case 32768:  
                 sc->sc_nrbuf = 16;  
                 sc->sc_ntbuf = 4;  
                 break;  
         case 65536:  
                 sc->sc_nrbuf = 32;  
                 sc->sc_ntbuf = 8;  
                 break;  
         case 131072:  
                 sc->sc_nrbuf = 64;  
                 sc->sc_ntbuf = 16;  
                 break;  
         default:  
                 panic("am7990_config: weird memory size");  
         }  
   
         printf(": address %s\n", ether_sprintf(sc->sc_enaddr));  
         printf("%s: %d receive buffers, %d transmit buffers\n",  
             sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);  
   
         sc->sc_sh = shutdownhook_establish(am7990_shutdown, sc);  
         if (sc->sc_sh == NULL)  
                 panic("am7990_config: can't establish shutdownhook");  
         sc->sc_rbufaddr = malloc(sc->sc_nrbuf * sizeof(int), M_DEVBUF,  
                                         M_WAITOK);  
         sc->sc_tbufaddr = malloc(sc->sc_ntbuf * sizeof(int), M_DEVBUF,  
                                         M_WAITOK);  
   
         mem = 0;          mem = 0;
         sc->sc_initaddr = mem;          sc->lsc.sc_initaddr = mem;
         mem += sizeof(struct leinit);          mem += sizeof(struct leinit);
         sc->sc_rmdaddr = mem;          sc->lsc.sc_rmdaddr = mem;
         mem += sizeof(struct lermd) * sc->sc_nrbuf;          mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf;
         sc->sc_tmdaddr = mem;          sc->lsc.sc_tmdaddr = mem;
         mem += sizeof(struct letmd) * sc->sc_ntbuf;          mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf;
         for (i = 0; i < sc->sc_nrbuf; i++, mem += LEBLEN)          for (i = 0; i < sc->lsc.sc_nrbuf; i++, mem += LEBLEN)
                 sc->sc_rbufaddr[i] = mem;                  sc->lsc.sc_rbufaddr[i] = mem;
         for (i = 0; i < sc->sc_ntbuf; i++, mem += LEBLEN)          for (i = 0; i < sc->lsc.sc_ntbuf; i++, mem += LEBLEN)
                 sc->sc_tbufaddr[i] = mem;                  sc->lsc.sc_tbufaddr[i] = mem;
 #ifdef notyet  #ifdef notyet
         if (mem > ...)          if (mem > ...)
                 panic(...);                  panic(...);
 #endif  #endif
   
 #if NRND > 0  
         rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,  
                           RND_TYPE_NET);  
 #endif  
 }  
   
 void  
 am7990_reset(sc)  
         struct am7990_softc *sc;  
 {  
         int s;  
   
         s = splimp();  
         am7990_init(sc);  
         splx(s);  
 }  }
   
 /*  /*
Line 318  am7990_reset(sc)
Line 165  am7990_reset(sc)
  */   */
 void  void
 am7990_meminit(sc)  am7990_meminit(sc)
         register struct am7990_softc *sc;          register struct lance_softc *sc;
 {  {
         u_long a;          u_long a;
         int bix;          int bix;
Line 346  am7990_meminit(sc)
Line 193  am7990_meminit(sc)
         init.init_padr[0] = (myaddr[1] << 8) | myaddr[0];          init.init_padr[0] = (myaddr[1] << 8) | myaddr[0];
         init.init_padr[1] = (myaddr[3] << 8) | myaddr[2];          init.init_padr[1] = (myaddr[3] << 8) | myaddr[2];
         init.init_padr[2] = (myaddr[5] << 8) | myaddr[4];          init.init_padr[2] = (myaddr[5] << 8) | myaddr[4];
         am7990_setladrf(&sc->sc_ethercom, init.init_ladrf);          lance_setladrf(&sc->sc_ethercom, init.init_ladrf);
   
         sc->sc_last_rd = 0;          sc->sc_last_rd = 0;
         sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;          sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
Line 390  am7990_meminit(sc)
Line 237  am7990_meminit(sc)
         }          }
 }  }
   
 void  
 am7990_stop(sc)  
         struct am7990_softc *sc;  
 {  
   
         (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);  
 }  
   
 /*  
  * Initialization of interface; set up initialization block  
  * and transmit/receive descriptor rings.  
  */  
 void  
 am7990_init(sc)  
         register struct am7990_softc *sc;  
 {  
         register int timo;  
         u_long a;  
   
         (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);  
         DELAY(100);  
   
         /* Newer LANCE chips have a reset register */  
         if (sc->sc_hwreset)  
                 (*sc->sc_hwreset)(sc);  
   
         /* Set the correct byte swapping mode, etc. */  
         (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);  
   
         /* Set up LANCE init block. */  
         am7990_meminit(sc);  
   
         /* Give LANCE the physical address of its init block. */  
         a = sc->sc_addr + LE_INITADDR(sc);  
         (*sc->sc_wrcsr)(sc, LE_CSR1, a);  
         (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);  
   
         /* Try to initialize the LANCE. */  
         DELAY(100);  
         (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);  
   
         /* Wait for initialization to finish. */  
         for (timo = 100000; timo; timo--)  
                 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)  
                         break;  
   
         if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {  
                 /* Start the LANCE. */  
                 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT |  
                     LE_C0_IDON);  
                 ifp->if_flags |= IFF_RUNNING;  
                 ifp->if_flags &= ~IFF_OACTIVE;  
                 ifp->if_timer = 0;  
                 am7990_start(ifp);  
         } else  
                 printf("%s: controller failed to initialize\n",  
                         sc->sc_dev.dv_xname);  
         if (sc->sc_hwinit)  
                 (*sc->sc_hwinit)(sc);  
 }  
   
 /*  
  * Routine to copy from mbuf chain to transmit buffer in  
  * network buffer memory.  
  */  
 integrate int  
 am7990_put(sc, boff, m)  
         struct am7990_softc *sc;  
         int boff;  
         register struct mbuf *m;  
 {  
         register struct mbuf *n;  
         register int len, tlen = 0;  
   
         for (; m; m = n) {  
                 len = m->m_len;  
                 if (len == 0) {  
                         MFREE(m, n);  
                         continue;  
                 }  
                 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);  
                 boff += len;  
                 tlen += len;  
                 MFREE(m, n);  
         }  
         if (tlen < LEMINSIZE) {  
                 (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);  
                 tlen = LEMINSIZE;  
         }  
         return (tlen);  
 }  
   
 /*  
  * Pull data off an interface.  
  * Len is length of data, with local net header stripped.  
  * We copy the data into mbufs.  When full cluster sized units are present  
  * we copy into clusters.  
  */  
 integrate struct mbuf *  
 am7990_get(sc, boff, totlen)  
         struct am7990_softc *sc;  
         int boff, totlen;  
 {  
         register struct mbuf *m;  
         struct mbuf *top, **mp;  
         int len;  
   
         MGETHDR(m, M_DONTWAIT, MT_DATA);  
         if (m == 0)  
                 return (0);  
         m->m_pkthdr.rcvif = ifp;  
         m->m_pkthdr.len = totlen;  
         len = MHLEN;  
         top = 0;  
         mp = &top;  
   
         while (totlen > 0) {  
                 if (top) {  
                         MGET(m, M_DONTWAIT, MT_DATA);  
                         if (m == 0) {  
                                 m_freem(top);  
                                 return 0;  
                         }  
                         len = MLEN;  
                 }  
                 if (totlen >= MINCLSIZE) {  
                         MCLGET(m, M_DONTWAIT);  
                         if ((m->m_flags & M_EXT) == 0) {  
                                 m_free(m);  
                                 m_freem(top);  
                                 return 0;  
                         }  
                         len = MCLBYTES;  
                 }  
                 if (!top) {  
                         register int pad =  
                             ALIGN(sizeof(struct ether_header)) -  
                                 sizeof(struct ether_header);  
                         m->m_data += pad;  
                         len -= pad;  
                 }  
                 m->m_len = len = min(totlen, len);  
                 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);  
                 boff += len;  
                 totlen -= len;  
                 *mp = m;  
                 mp = &m->m_next;  
         }  
   
         return (top);  
 }  
   
 /*  
  * Pass a packet to the higher levels.  
  */  
 integrate void  
 am7990_read(sc, boff, len)  
         register struct am7990_softc *sc;  
         int boff, len;  
 {  
         struct mbuf *m;  
         struct ether_header *eh;  
   
         if (len <= sizeof(struct ether_header) ||  
             len > ETHERMTU + sizeof(struct ether_header)) {  
 #ifdef LEDEBUG  
                 printf("%s: invalid packet size %d; dropping\n",  
                     sc->sc_dev.dv_xname, len);  
 #endif  
                 ifp->if_ierrors++;  
                 return;  
         }  
   
         /* Pull packet off interface. */  
         m = am7990_get(sc, boff, len);  
         if (m == 0) {  
                 ifp->if_ierrors++;  
                 return;  
         }  
   
         ifp->if_ipackets++;  
   
         /* We assume that the header fit entirely in one mbuf. */  
         eh = mtod(m, struct ether_header *);  
   
 #if NBPFILTER > 0  
         /*  
          * Check if there's a BPF listener on this interface.  
          * If so, hand off the raw packet to BPF.  
          */  
         if (ifp->if_bpf) {  
                 bpf_mtap(ifp->if_bpf, m);  
   
 #ifndef LANCE_REVC_BUG  
                 /*  
                  * Note that the interface cannot be in promiscuous mode if  
                  * there are no BPF listeners.  And if we are in promiscuous  
                  * mode, we have to check if this packet is really ours.  
                  */  
                 if ((ifp->if_flags & IFF_PROMISC) != 0 &&  
                     (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */  
                     ETHER_CMP(eh->ether_dhost, sc->sc_enaddr)) {  
                         m_freem(m);  
                         return;  
                 }  
 #endif  
         }  
 #endif  
   
 #ifdef LANCE_REVC_BUG  
         /*  
          * The old LANCE (Rev. C) chips have a bug which causes  
          * garbage to be inserted in front of the received packet.  
          * The work-around is to ignore packets with an invalid  
          * destination address (garbage will usually not match).  
          * Of course, this precludes multicast support...  
          */  
         if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) &&  
             ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {  
                 m_freem(m);  
                 return;  
         }  
 #endif  
   
         /* Pass the packet up, with the ether header sort-of removed. */  
         m_adj(m, sizeof(struct ether_header));  
         ether_input(ifp, eh, m);  
 }  
   
 integrate void  integrate void
 am7990_rint(sc)  am7990_rint(sc)
         struct am7990_softc *sc;          struct lance_softc *sc;
 {  {
         register int bix;          register int bix;
         int rp;          int rp;
Line 668  am7990_rint(sc)
Line 286  am7990_rint(sc)
                         if (sc->sc_debug)                          if (sc->sc_debug)
                                 am7990_recv_print(sc, sc->sc_last_rd);                                  am7990_recv_print(sc, sc->sc_last_rd);
 #endif  #endif
                         am7990_read(sc, LE_RBUFADDR(sc, bix),                          lance_read(sc, LE_RBUFADDR(sc, bix),
                             (int)rmd.rmd3 - 4);                                     (int)rmd.rmd3 - 4);
                 }                  }
   
                 rmd.rmd1_bits = LE_R1_OWN;                  rmd.rmd1_bits = LE_R1_OWN;
Line 696  am7990_rint(sc)
Line 314  am7990_rint(sc)
   
 integrate void  integrate void
 am7990_tint(sc)  am7990_tint(sc)
         register struct am7990_softc *sc;          register struct lance_softc *sc;
 {  {
         register int bix;          register int bix;
         struct letmd tmd;          struct letmd tmd;
Line 731  am7990_tint(sc)
Line 349  am7990_tint(sc)
                         else if (tmd.tmd3 & LE_T3_UFLO)                          else if (tmd.tmd3 & LE_T3_UFLO)
                                 printf("%s: underflow\n", sc->sc_dev.dv_xname);                                  printf("%s: underflow\n", sc->sc_dev.dv_xname);
                         if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) {                          if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) {
                                 am7990_reset(sc);                                  lance_reset((struct lance_softc *)sc);
                                 return;                                  return;
                         }                          }
                         if (tmd.tmd3 & LE_T3_LCAR) {                          if (tmd.tmd3 & LE_T3_LCAR) {
Line 781  int
Line 399  int
 am7990_intr(arg)  am7990_intr(arg)
         register void *arg;          register void *arg;
 {  {
         register struct am7990_softc *sc = arg;          register struct lance_softc *sc = arg;
         register u_int16_t isr;          register u_int16_t isr;
   
         isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0;          isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0;
Line 818  am7990_intr(arg)
Line 436  am7990_intr(arg)
                 }                  }
                 if (isr & LE_C0_MERR) {                  if (isr & LE_C0_MERR) {
                         printf("%s: memory error\n", sc->sc_dev.dv_xname);                          printf("%s: memory error\n", sc->sc_dev.dv_xname);
                         am7990_reset(sc);                          lance_reset(sc);
                         return (1);                          return (1);
                 }                  }
         }          }
Line 826  am7990_intr(arg)
Line 444  am7990_intr(arg)
         if ((isr & LE_C0_RXON) == 0) {          if ((isr & LE_C0_RXON) == 0) {
                 printf("%s: receiver disabled\n", sc->sc_dev.dv_xname);                  printf("%s: receiver disabled\n", sc->sc_dev.dv_xname);
                 ifp->if_ierrors++;                  ifp->if_ierrors++;
                 am7990_reset(sc);                  lance_reset(sc);
                 return (1);                  return (1);
         }          }
         if ((isr & LE_C0_TXON) == 0) {          if ((isr & LE_C0_TXON) == 0) {
                 printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname);                  printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname);
                 ifp->if_oerrors++;                  ifp->if_oerrors++;
                 am7990_reset(sc);                  lance_reset(sc);
                 return (1);                  return (1);
         }          }
   
Line 854  am7990_intr(arg)
Line 472  am7990_intr(arg)
         return (1);          return (1);
 }  }
   
 #undef  ifp  #undef ifp
   
 void  
 am7990_watchdog(ifp)  
         struct ifnet *ifp;  
 {  
         struct am7990_softc *sc = ifp->if_softc;  
   
         log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);  
         ++ifp->if_oerrors;  
   
         am7990_reset(sc);  
 }  
   
 int  
 am7990_mediachange(ifp)  
         struct ifnet *ifp;  
 {  
         struct am7990_softc *sc = ifp->if_softc;  
   
         if (sc->sc_mediachange)  
                 return ((*sc->sc_mediachange)(sc));  
         return (EINVAL);  
 }  
   
 void  
 am7990_mediastatus(ifp, ifmr)  
         struct ifnet *ifp;  
         struct ifmediareq *ifmr;  
 {  
         struct am7990_softc *sc = ifp->if_softc;  
   
         if ((ifp->if_flags & IFF_UP) == 0)  
                 return;  
   
         ifmr->ifm_status = IFM_AVALID;  
         if (sc->sc_havecarrier)  
                 ifmr->ifm_status |= IFM_ACTIVE;  
   
         if (sc->sc_mediastatus)  
                 (*sc->sc_mediastatus)(sc, ifmr);  
 }  
   
 /*  /*
  * Setup output on interface.   * Setup output on interface.
Line 907  void
Line 484  void
 am7990_start(ifp)  am7990_start(ifp)
         register struct ifnet *ifp;          register struct ifnet *ifp;
 {  {
         register struct am7990_softc *sc = ifp->if_softc;          register struct lance_softc *sc = ifp->if_softc;
         register int bix;          register int bix;
         register struct mbuf *m;          register struct mbuf *m;
         struct letmd tmd;          struct letmd tmd;
Line 945  am7990_start(ifp)
Line 522  am7990_start(ifp)
                 /*                  /*
                  * Copy the mbuf chain into the transmit buffer.                   * Copy the mbuf chain into the transmit buffer.
                  */                   */
                 len = am7990_put(sc, LE_TBUFADDR(sc, bix), m);                  len = lance_put(sc, LE_TBUFADDR(sc, bix), m);
   
 #ifdef LEDEBUG  #ifdef LEDEBUG
                 if (len > ETHERMTU + sizeof(struct ether_header))                  if (len > ETHERMTU + sizeof(struct ether_header))
Line 983  am7990_start(ifp)
Line 560  am7990_start(ifp)
         sc->sc_last_td = bix;          sc->sc_last_td = bix;
 }  }
   
 /*  
  * Process an ioctl request.  
  */  
 int  
 am7990_ioctl(ifp, cmd, data)  
         register struct ifnet *ifp;  
         u_long cmd;  
         caddr_t data;  
 {  
         register struct am7990_softc *sc = ifp->if_softc;  
         struct ifaddr *ifa = (struct ifaddr *)data;  
         struct ifreq *ifr = (struct ifreq *)data;  
         int s, error = 0;  
   
         s = splimp();  
   
         switch (cmd) {  
   
         case SIOCSIFADDR:  
                 ifp->if_flags |= IFF_UP;  
   
                 switch (ifa->ifa_addr->sa_family) {  
 #ifdef INET  
                 case AF_INET:  
                         am7990_init(sc);  
                         arp_ifinit(ifp, ifa);  
                         break;  
 #endif  
 #ifdef NS  
                 case AF_NS:  
                     {  
                         register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;  
   
                         if (ns_nullhost(*ina))  
                                 ina->x_host =  
                                     *(union ns_host *)LLADDR(ifp->if_sadl);  
                         else {  
                                 bcopy(ina->x_host.c_host,  
                                     LLADDR(ifp->if_sadl),  
                                     sizeof(sc->sc_enaddr));  
                         }  
                         /* Set new address. */  
                         am7990_init(sc);  
                         break;  
                     }  
 #endif  
                 default:  
                         am7990_init(sc);  
                         break;  
                 }  
                 break;  
   
 #if defined(CCITT) && defined(LLC)  
         case SIOCSIFCONF_X25:  
                 ifp->if_flags |= IFF_UP;  
                 ifa->ifa_rtrequest = cons_rtrequest; /* XXX */  
                 error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);  
                 if (error == 0)  
                         am7990_init(sc);  
                 break;  
 #endif /* CCITT && LLC */  
   
         case SIOCSIFFLAGS:  
                 if ((ifp->if_flags & IFF_UP) == 0 &&  
                     (ifp->if_flags & IFF_RUNNING) != 0) {  
                         /*  
                          * If interface is marked down and it is running, then  
                          * stop it.  
                          */  
                         am7990_stop(sc);  
                         ifp->if_flags &= ~IFF_RUNNING;  
                 } else if ((ifp->if_flags & IFF_UP) != 0 &&  
                            (ifp->if_flags & IFF_RUNNING) == 0) {  
                         /*  
                          * If interface is marked up and it is stopped, then  
                          * start it.  
                          */  
                         am7990_init(sc);  
                 } else {  
                         /*  
                          * Reset the interface to pick up changes in any other  
                          * flags that affect hardware registers.  
                          */  
                         /*am7990_stop(sc);*/  
                         am7990_init(sc);  
                 }  
 #ifdef LEDEBUG  
                 if (ifp->if_flags & IFF_DEBUG)  
                         sc->sc_debug = 1;  
                 else  
                         sc->sc_debug = 0;  
 #endif  
                 break;  
   
         case SIOCADDMULTI:  
         case SIOCDELMULTI:  
                 error = (cmd == SIOCADDMULTI) ?  
                     ether_addmulti(ifr, &sc->sc_ethercom) :  
                     ether_delmulti(ifr, &sc->sc_ethercom);  
   
                 if (error == ENETRESET) {  
                         /*  
                          * Multicast list has changed; set the hardware filter  
                          * accordingly.  
                          */  
                         am7990_reset(sc);  
                         error = 0;  
                 }  
                 break;  
   
         case SIOCGIFMEDIA:  
         case SIOCSIFMEDIA:  
                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);  
                 break;  
   
         default:  
                 error = EINVAL;  
                 break;  
         }  
   
         splx(s);  
         return (error);  
 }  
   
 hide void  
 am7990_shutdown(arg)  
         void *arg;  
 {  
   
         am7990_stop((struct am7990_softc *)arg);  
 }  
   
 #ifdef LEDEBUG  #ifdef LEDEBUG
 void  void
 am7990_recv_print(sc, no)  am7990_recv_print(sc, no)
         struct am7990_softc *sc;          struct lance_softc *sc;
         int no;          int no;
 {  {
         struct lermd rmd;          struct lermd rmd;
Line 1145  am7990_recv_print(sc, no)
Line 590  am7990_recv_print(sc, no)
   
 void  void
 am7990_xmit_print(sc, no)  am7990_xmit_print(sc, no)
         struct am7990_softc *sc;          struct lance_softc *sc;
         int no;          int no;
 {  {
         struct letmd tmd;          struct letmd tmd;
Line 1170  am7990_xmit_print(sc, no)
Line 615  am7990_xmit_print(sc, no)
         }          }
 }  }
 #endif /* LEDEBUG */  #endif /* LEDEBUG */
   
 /*  
  * Set up the logical address filter.  
  */  
 void  
 am7990_setladrf(ac, af)  
         struct ethercom *ac;  
         u_int16_t *af;  
 {  
         struct ifnet *ifp = &ac->ec_if;  
         struct ether_multi *enm;  
         register u_char *cp;  
         register u_int32_t crc;  
         static const u_int32_t crctab[] = {  
                 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,  
                 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,  
                 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,  
                 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c  
         };  
         register int len;  
         struct ether_multistep step;  
   
         /*  
          * Set up multicast address filter by passing all multicast addresses  
          * through a crc generator, and then using the high order 6 bits as an  
          * index into the 64 bit logical address filter.  The high order bit  
          * selects the word, while the rest of the bits select the bit within  
          * the word.  
          */  
   
         if (ifp->if_flags & IFF_PROMISC)  
                 goto allmulti;  
   
         af[0] = af[1] = af[2] = af[3] = 0x0000;  
         ETHER_FIRST_MULTI(step, ac, enm);  
         while (enm != NULL) {  
                 if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {  
                         /*  
                          * We must listen to a range of multicast addresses.  
                          * For now, just accept all multicasts, rather than  
                          * trying to set only those filter bits needed to match  
                          * the range.  (At this time, the only use of address  
                          * ranges is for IP multicast routing, for which the  
                          * range is big enough to require all bits set.)  
                          */  
                         goto allmulti;  
                 }  
   
                 cp = enm->enm_addrlo;  
                 crc = 0xffffffff;  
                 for (len = sizeof(enm->enm_addrlo); --len >= 0;) {  
                         crc ^= *cp++;  
                         crc = (crc >> 4) ^ crctab[crc & 0xf];  
                         crc = (crc >> 4) ^ crctab[crc & 0xf];  
                 }  
                 /* Just want the 6 most significant bits. */  
                 crc >>= 26;  
   
                 /* Set the corresponding bit in the filter. */  
                 af[crc >> 4] |= 1 << (crc & 0xf);  
   
                 ETHER_NEXT_MULTI(step, enm);  
         }  
         ifp->if_flags &= ~IFF_ALLMULTI;  
         return;  
   
 allmulti:  
         ifp->if_flags |= IFF_ALLMULTI;  
         af[0] = af[1] = af[2] = af[3] = 0xffff;  
 }  
   
   
 /*  
  * Routines for accessing the transmit and receive buffers.  
  * The various CPU and adapter configurations supported by this  
  * driver require three different access methods for buffers  
  * and descriptors:  
  *      (1) contig (contiguous data; no padding),  
  *      (2) gap2 (two bytes of data followed by two bytes of padding),  
  *      (3) gap16 (16 bytes of data followed by 16 bytes of padding).  
  */  
   
 /*  
  * contig: contiguous data with no padding.  
  *  
  * Buffers may have any alignment.  
  */  
   
 void  
 am7990_copytobuf_contig(sc, from, boff, len)  
         struct am7990_softc *sc;  
         void *from;  
         int boff, len;  
 {  
         volatile caddr_t buf = sc->sc_mem;  
   
         /*  
          * Just call bcopy() to do the work.  
          */  
         bcopy(from, buf + boff, len);  
 }  
   
 void  
 am7990_copyfrombuf_contig(sc, to, boff, len)  
         struct am7990_softc *sc;  
         void *to;  
         int boff, len;  
 {  
         volatile caddr_t buf = sc->sc_mem;  
   
         /*  
          * Just call bcopy() to do the work.  
          */  
         bcopy(buf + boff, to, len);  
 }  
   
 void  
 am7990_zerobuf_contig(sc, boff, len)  
         struct am7990_softc *sc;  
         int boff, len;  
 {  
         volatile caddr_t buf = sc->sc_mem;  
   
         /*  
          * Just let bzero() do the work  
          */  
         bzero(buf + boff, len);  
 }  
   
 #if 0  
 /*  
  * Examples only; duplicate these and tweak (if necessary) in  
  * machine-specific front-ends.  
  */  
   
 /*  
  * gap2: two bytes of data followed by two bytes of pad.  
  *  
  * Buffers must be 4-byte aligned.  The code doesn't worry about  
  * doing an extra byte.  
  */  
   
 void  
 am7990_copytobuf_gap2(sc, fromv, boff, len)  
         struct am7990_softc *sc;  
         void *fromv;  
         int boff;  
         register int len;  
 {  
         volatile caddr_t buf = sc->sc_mem;  
         register caddr_t from = fromv;  
         register volatile u_int16_t *bptr;  
   
         if (boff & 0x1) {  
                 /* handle unaligned first byte */  
                 bptr = ((volatile u_int16_t *)buf) + (boff - 1);  
                 *bptr = (*from++ << 8) | (*bptr & 0xff);  
                 bptr += 2;  
                 len--;  
         } else  
                 bptr = ((volatile u_int16_t *)buf) + boff;  
         while (len > 1) {  
                 *bptr = (from[1] << 8) | (from[0] & 0xff);  
                 bptr += 2;  
                 from += 2;  
                 len -= 2;  
         }  
         if (len == 1)  
                 *bptr = (u_int16_t)*from;  
 }  
   
 void  
 am7990_copyfrombuf_gap2(sc, tov, boff, len)  
         struct am7990_softc *sc;  
         void *tov;  
         int boff, len;  
 {  
         volatile caddr_t buf = sc->sc_mem;  
         register caddr_t to = tov;  
         register volatile u_int16_t *bptr;  
         register u_int16_t tmp;  
   
         if (boff & 0x1) {  
                 /* handle unaligned first byte */  
                 bptr = ((volatile u_int16_t *)buf) + (boff - 1);  
                 *to++ = (*bptr >> 8) & 0xff;  
                 bptr += 2;  
                 len--;  
         } else  
                 bptr = ((volatile u_int16_t *)buf) + boff;  
         while (len > 1) {  
                 tmp = *bptr;  
                 *to++ = tmp & 0xff;  
                 *to++ = (tmp >> 8) & 0xff;  
                 bptr += 2;  
                 len -= 2;  
         }  
         if (len == 1)  
                 *to = *bptr & 0xff;  
 }  
   
 void  
 am7990_zerobuf_gap2(sc, boff, len)  
         struct am7990_softc *sc;  
         int boff, len;  
 {  
         volatile caddr_t buf = sc->sc_mem;  
         register volatile u_int16_t *bptr;  
   
         if ((unsigned)boff & 0x1) {  
                 bptr = ((volatile u_int16_t *)buf) + (boff - 1);  
                 *bptr &= 0xff;  
                 bptr += 2;  
                 len--;  
         } else  
                 bptr = ((volatile u_int16_t *)buf) + boff;  
         while (len > 0) {  
                 *bptr = 0;  
                 bptr += 2;  
                 len -= 2;  
         }  
 }  
   
 /*  
  * gap16: 16 bytes of data followed by 16 bytes of pad.  
  *  
  * Buffers must be 32-byte aligned.  
  */  
   
 void  
 am7990_copytobuf_gap16(sc, fromv, boff, len)  
         struct am7990_softc *sc;  
         void *fromv;  
         int boff;  
         register int len;  
 {  
         volatile caddr_t buf = sc->sc_mem;  
         register caddr_t from = fromv;  
         register caddr_t bptr;  
         register int xfer;  
   
         bptr = buf + ((boff << 1) & ~0x1f);  
         boff &= 0xf;  
         xfer = min(len, 16 - boff);  
         while (len > 0) {  
                 bcopy(from, bptr + boff, xfer);  
                 from += xfer;  
                 bptr += 32;  
                 boff = 0;  
                 len -= xfer;  
                 xfer = min(len, 16);  
         }  
 }  
   
 void  
 am7990_copyfrombuf_gap16(sc, tov, boff, len)  
         struct am7990_softc *sc;  
         void *tov;  
         int boff, len;  
 {  
         volatile caddr_t buf = sc->sc_mem;  
         register caddr_t to = tov;  
         register caddr_t bptr;  
         register int xfer;  
   
         bptr = buf + ((boff << 1) & ~0x1f);  
         boff &= 0xf;  
         xfer = min(len, 16 - boff);  
         while (len > 0) {  
                 bcopy(bptr + boff, to, xfer);  
                 to += xfer;  
                 bptr += 32;  
                 boff = 0;  
                 len -= xfer;  
                 xfer = min(len, 16);  
         }  
 }  
   
 void  
 am7990_zerobuf_gap16(sc, boff, len)  
         struct am7990_softc *sc;  
         int boff, len;  
 {  
         volatile caddr_t buf = sc->sc_mem;  
         register caddr_t bptr;  
         register int xfer;  
   
         bptr = buf + ((boff << 1) & ~0x1f);  
         boff &= 0xf;  
         xfer = min(len, 16 - boff);  
         while (len > 0) {  
                 bzero(bptr + boff, xfer);  
                 bptr += 32;  
                 boff = 0;  
                 len -= xfer;  
                 xfer = min(len, 16);  
         }  
 }  
 #endif /* Example only */  

Legend:
Removed from v.1.50  
changed lines
  Added in v.1.51

CVSweb <webmaster@jp.NetBSD.org>