summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authoritojun <itojun@NetBSD.org>1999-07-01 08:12:45 +0000
committeritojun <itojun@NetBSD.org>1999-07-01 08:12:45 +0000
commit118d2b1d4f3b4a47cda5be4fa2293d494c90fde5 (patch)
tree4e6801afd74e4cdfbbb5003a967ffaf06bf9bfba /sys/dev
parent9765602d90691610d9a664d382721284a2a84a47 (diff)
IPv6 kernel code, based on KAME/NetBSD 1.4, SNAP kit 19990628.
(Sorry for a big commit, I can't separate this into several pieces...) Pls check sys/netinet6/TODO and sys/netinet6/IMPLEMENTATION for details. - sys/kern: do not assume single mbuf, accept chained mbuf on passing data from userland to kernel (or other way round). - "midway" ATM card: ATM PVC pseudo device support, like those done in ALTQ package (ftp://ftp.csl.sony.co.jp/pub/kjc/). - sys/netinet/tcp*: IPv4/v6 dual stack tcp support. - sys/netinet/{ip6,icmp6}.h, sys/net/pfkeyv2.h: IETF document assumes those file to be there so we patch it up. - sys/netinet: IPsec additions are here and there. - sys/netinet6/*: most of IPv6 code sits here. - sys/netkey: IPsec key management code - dev/pci/pcidevs: regen In my understanding no code here is subject to export control so it should be safe.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/midway.c858
-rw-r--r--sys/dev/ic/midwayreg.h3
-rw-r--r--sys/dev/ic/midwayvar.h22
-rw-r--r--sys/dev/pci/if_en_pci.c150
-rw-r--r--sys/dev/pci/pcidevs.h8
-rw-r--r--sys/dev/pci/pcidevs_data.h4
6 files changed, 1004 insertions, 41 deletions
diff --git a/sys/dev/ic/midway.c b/sys/dev/ic/midway.c
index c0715750b4a..0bbbe8d18b5 100644
--- a/sys/dev/ic/midway.c
+++ b/sys/dev/ic/midway.c
@@ -1,4 +1,4 @@
-/* $NetBSD: midway.c,v 1.38 1999/02/12 00:57:42 thorpej Exp $ */
+/* $NetBSD: midway.c,v 1.39 1999/07/01 08:12:46 itojun Exp $ */
/* (sync'd to midway.c 1.68) */
/*
@@ -46,7 +46,26 @@
* I would also like to thank Werner for promptly answering email and being
* generally helpful.
*/
-
+/*
+ * 1997/12/02, major update on 1999/04/06 kjc
+ * new features added:
+ * - BPF support (link type is DLT_ATM_RFC1483)
+ * BPF understands only LLC/SNAP!! (because bpf can't
+ * handle variable link header length.)
+ * (bpfwrite should work if atm_pseudohdr and LLC/SNAP are prepended.)
+ * - support vc shaping
+ * - integrate IPv6 support.
+ * - support pvc sub interface
+ *
+ * initial work on per-pvc-interface for ipv6 was done
+ * by Katsushi Kobayashi <ikob@cc.uec.ac.jp> of the WIDE Project.
+ * some of the extensions for pvc subinterfaces are merged from
+ * the CAIRN project written by Suresh Bhogavilli (suresh@isi.edu).
+ *
+ * code cleanup:
+ * - remove WMAYBE related code. ENI WMAYBE DMA doen't work.
+ * - remove updating if_lastchange for every packet.
+ */
#undef EN_DEBUG
#undef EN_DEBUG_RANGE /* check ranges on en_read/en_write's? */
@@ -133,24 +152,34 @@
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
+#include <sys/queue.h>
#include <net/if.h>
#include <net/if_atm.h>
#include <vm/vm.h>
-#ifdef INET
+#if defined(INET) || defined(INET6)
+#include <netinet/in.h>
#include <netinet/if_atm.h>
+#ifdef INET6
+#include <netinet6/in6_var.h>
+#endif
#endif
#ifdef NATM
+#if !(defined(INET) || defined(INET6))
#include <netinet/in.h>
+#endif
#include <netnatm/natm.h>
#endif
#if !defined(__FreeBSD__)
#include <machine/bus.h>
+
+#define LIST_FOREACH(var, head, field) \
+ for((var) = (head)->lh_first; (var); (var) = (var)->field.le_next)
#endif
#if defined(__NetBSD__) || defined(__OpenBSD__)
@@ -180,6 +209,18 @@
#endif /* __FreeBSD__ */
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#ifdef __FreeBSD__
+#define BPFATTACH(ifp, dlt, hlen) bpfattach((ifp), (dlt), (hlen))
+#define BPF_MTAP(ifp, m) bpf_mtap((ifp), (m))
+#else
+#define BPFATTACH(ifp, dlt, hlen) bpfattach(&(ifp)->if_bpf, (ifp), (dlt), (hlen))
+#define BPF_MTAP(ifp, m) bpf_mtap((ifp)->if_bpf, (m))
+#endif
+#endif /* NBPFILTER > 0 */
+
/*
* params
*/
@@ -305,6 +346,17 @@ STATIC INLINE int en_sz2b __P((int)) __attribute__ ((unused));
STATIC INLINE void en_write __P((struct en_softc *, u_int32_t,
u_int32_t)) __attribute__ ((unused));
+#ifdef ATM_PVCEXT
+static void rrp_add __P((struct en_softc *, struct ifnet *));
+static struct ifnet *en_pvcattach __P((struct ifnet *));
+static int en_txctl __P((struct en_softc *, int, int, int));
+static int en_pvctx __P((struct en_softc *, struct pvctxreq *));
+static int en_pvctxget __P((struct en_softc *, struct pvctxreq *));
+static int en_pcr2txspeed __P((int));
+static int en_txspeed2pcr __P((int));
+static struct ifnet *en_vci2ifp __P((struct en_softc *, int));
+#endif
+
/*
* macros/inline
*/
@@ -432,10 +484,8 @@ u_int32_t r;
{
#ifdef EN_DEBUG_RANGE
- if (r > MID_MAXOFF || (r % 4)) {
- printf("en_read out of range, r=0x%x\n", r);
- panic("en_read");
- }
+ if (r > MID_MAXOFF || (r % 4))
+ panic("en_read out of range, r=0x%x", r);
#endif
return(bus_space_read_4(sc->en_memt, sc->en_base, r));
@@ -453,10 +503,8 @@ u_int32_t r, v;
{
#ifdef EN_DEBUG_RANGE
- if (r > MID_MAXOFF || (r % 4)) {
- printf("en_write out of range, r=0x%x\n", r);
- panic("en_write");
- }
+ if (r > MID_MAXOFF || (r % 4))
+ panic("en_write out of range, r=0x%x", r);
#endif
bus_space_write_4(sc->en_memt, sc->en_base, r, v);
@@ -773,6 +821,9 @@ done_probe:
sz -= (EN_TXSZ * 1024);
sc->txslot[lcv].stop = ptr;
sc->txslot[lcv].nref = 0;
+#ifdef ATM_PVCEXT
+ sc->txrrp = NULL;
+#endif
bzero(&sc->txslot[lcv].indma, sizeof(sc->txslot[lcv].indma));
bzero(&sc->txslot[lcv].q, sizeof(sc->txslot[lcv].q));
#ifdef EN_DEBUG
@@ -831,6 +882,9 @@ done_probe:
printf("%s: %d %dKB receive buffers, %d %dKB transmit buffers allocated\n",
sc->sc_dev.dv_xname, sc->en_nrx, EN_RXSZ, EN_NTX, EN_TXSZ);
+ printf("%s: End Station Identifier (mac address) %s\n",
+ sc->sc_dev.dv_xname, ether_sprintf(sc->macaddr));
+
/*
* final commit
*/
@@ -838,6 +892,12 @@ done_probe:
if_attach(ifp);
atm_ifattach(ifp);
+#if NBPFILTER > 0
+ BPFATTACH(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
+#endif
+#ifdef ATM_PVCEXT
+ rrp_add(sc, ifp);
+#endif
}
@@ -1121,18 +1181,31 @@ caddr_t data;
break;
#endif
case SIOCSIFADDR:
+#ifdef INET6
+ case SIOCSIFADDR_IN6:
+#endif
ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
#ifdef INET
- if (ifa->ifa_addr->sa_family == AF_INET) {
+ case AF_INET:
+ en_reset(sc);
+ en_init(sc);
+ ifa->ifa_rtrequest = atm_rtrequest; /* ??? */
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
en_reset(sc);
en_init(sc);
ifa->ifa_rtrequest = atm_rtrequest; /* ??? */
break;
+#endif
+ default:
+ /* what to do if not INET? */
+ en_reset(sc);
+ en_init(sc);
+ break;
}
-#endif /* INET */
- /* what to do if not INET? */
- en_reset(sc);
- en_init(sc);
break;
case SIOCGIFADDR:
@@ -1140,7 +1213,16 @@ caddr_t data;
break;
case SIOCSIFFLAGS:
+#ifdef ATM_PVCEXT
+ /* point-2-point pvc is allowed to change if_flags */
+ if (((ifp->if_flags & IFF_UP) && !(ifp->if_flags & IFF_RUNNING))
+ || (!(ifp->if_flags & IFF_UP) && (ifp->if_flags & IFF_RUNNING))) {
+ en_reset(sc);
+ en_init(sc);
+ }
+#else
error = EINVAL;
+#endif
break;
#if defined(SIOCSIFMTU) /* ??? copied from if_de */
@@ -1164,6 +1246,74 @@ caddr_t data;
break;
#endif /* SIOCSIFMTU */
+#ifdef ATM_PVCEXT
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if (ifp == &sc->enif || ifr == 0) {
+ error = EAFNOSUPPORT; /* XXX */
+ break;
+ }
+ switch (ifr->ifr_addr.sa_family) {
+#ifdef INET
+ case AF_INET:
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ break;
+#endif
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
+ break;
+
+ case SIOCGPVCSIF:
+ if (ifp != &sc->enif) {
+#ifdef __NetBSD__
+ strcpy(ifr->ifr_name, sc->enif.if_xname);
+#else
+ sprintf(ifr->ifr_name, "%s%d",
+ sc->enif.if_name, sc->enif.if_unit);
+#endif
+ }
+ else
+ error = EINVAL;
+ break;
+
+ case SIOCSPVCSIF:
+ if (ifp == &sc->enif) {
+ struct ifnet *sifp;
+
+ if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) != 0)
+ break;
+
+ if ((sifp = en_pvcattach(ifp)) != NULL) {
+#ifdef __NetBSD__
+ strcpy(ifr->ifr_name, sifp->if_xname);
+#else
+ sprintf(ifr->ifr_name, "%s%d",
+ sifp->if_name, sifp->if_unit);
+#endif
+ }
+ else
+ error = ENOMEM;
+ }
+ else
+ error = EINVAL;
+ break;
+
+ case SIOCGPVCTX:
+ error = en_pvctxget(sc, (struct pvctxreq *)data);
+ break;
+
+ case SIOCSPVCTX:
+ if ((error = suser(curproc->p_ucred, &curproc->p_acflag)) == 0)
+ error = en_pvctx(sc, (struct pvctxreq *)data);
+ break;
+
+#endif /* ATM_PVCEXT */
+
default:
error = EINVAL;
break;
@@ -1357,8 +1507,23 @@ struct en_softc *sc;
{
int vc, slot;
u_int32_t loc;
+#ifdef ATM_PVCEXT
+ struct pvcsif *pvcsif;
+#endif
if ((sc->enif.if_flags & IFF_UP) == 0) {
+#ifdef ATM_PVCEXT
+ LIST_FOREACH(pvcsif, &sc->sif_list, sif_links) {
+ if (pvcsif->sif_if.if_flags & IFF_UP) {
+ /*
+ * down the device only when there is no active pvc subinterface.
+ * if there is, we have to go through the init sequence to reflect
+ * the software states to the device.
+ */
+ goto up;
+ }
+ }
+#endif
#ifdef EN_DEBUG
printf("%s: going down\n", sc->sc_dev.dv_xname);
#endif
@@ -1367,10 +1532,18 @@ struct en_softc *sc;
return;
}
+#ifdef ATM_PVCEXT
+ up:
+#endif
#ifdef EN_DEBUG
printf("%s: going up\n", sc->sc_dev.dv_xname);
#endif
sc->enif.if_flags |= IFF_RUNNING; /* enable */
+#ifdef ATM_PVCEXT
+ LIST_FOREACH(pvcsif, &sc->sif_list, sif_links) {
+ pvcsif->sif_if.if_flags |= IFF_RUNNING;
+ }
+#endif
if (sc->en_busreset)
sc->en_busreset(sc);
@@ -1674,6 +1847,8 @@ struct ifnet *ifp;
* en_mfix: fix a stupid mbuf
*/
+#ifndef __FreeBSD__
+
STATIC int en_mfix(sc, mm, prev)
struct en_softc *sc;
@@ -1748,6 +1923,136 @@ struct mbuf **mm, *prev;
return(1);
}
+#else /* __FreeBSD__ */
+
+STATIC int en_makeexclusive(struct en_softc *, struct mbuf **, struct mbuf *);
+
+STATIC int en_makeexclusive(sc, mm, prev)
+ struct en_softc *sc;
+ struct mbuf **mm, *prev;
+{
+ struct mbuf *m, *new;
+
+ m = *mm;
+
+ if (m->m_flags & M_EXT) {
+ if (m->m_ext.ext_free) {
+ /* external buffer isn't an ordinary mbuf cluster! */
+ printf("%s: mfix: special buffer! can't make a copy!\n",
+ sc->sc_dev.dv_xname);
+ return (0);
+ }
+
+ if (mclrefcnt[mtocl(m->m_ext.ext_buf)] > 1) {
+ /* make a real copy of the M_EXT mbuf since it is shared */
+ MGET(new, M_DONTWAIT, MT_DATA);
+ if (!new) {
+ EN_COUNT(sc->mfixfail);
+ return(0);
+ }
+ if (m->m_flags & M_PKTHDR)
+ M_COPY_PKTHDR(new, m);
+ MCLGET(new, M_DONTWAIT);
+ if ((new->m_flags & M_EXT) == 0) {
+ m_free(new);
+ EN_COUNT(sc->mfixfail);
+ return(0);
+ }
+ bcopy(m->m_data, new->m_data, m->m_len);
+ new->m_len = m->m_len;
+ new->m_next = m->m_next;
+ if (prev)
+ prev->m_next = new;
+ m_free(m);
+ *mm = new;
+ }
+ else {
+ /* the buffer is not shared, align the data offset using
+ this buffer. */
+ u_char *d = mtod(m, u_char *);
+ int off = ((u_long)d) % sizeof(u_int32_t);
+
+ if (off > 0) {
+ bcopy(d, d - off, m->m_len);
+ m->m_data = (caddr_t)d - off;
+ }
+ }
+ }
+ return (1);
+}
+
+STATIC int en_mfix(sc, mm, prev)
+
+struct en_softc *sc;
+struct mbuf **mm, *prev;
+
+{
+ struct mbuf *m;
+ u_char *d, *cp;
+ int off;
+ struct mbuf *nxt;
+
+ m = *mm;
+
+ EN_COUNT(sc->mfix); /* count # of calls */
+#ifdef EN_DEBUG
+ printf("%s: mfix mbuf m_data=0x%x, m_len=%d\n", sc->sc_dev.dv_xname,
+ m->m_data, m->m_len);
+#endif
+
+ d = mtod(m, u_char *);
+ off = ((unsigned long) d) % sizeof(u_int32_t);
+
+ if (off) {
+ if ((m->m_flags & M_EXT) == 0) {
+ bcopy(d, d - off, m->m_len); /* ALIGN! (with costly data copy...) */
+ d -= off;
+ m->m_data = (caddr_t)d;
+ } else {
+ /* can't write to an M_EXT mbuf since it may be shared */
+ if (en_makeexclusive(sc, &m, prev) == 0)
+ return (0);
+ *mm = m; /* note: 'd' now invalid */
+ }
+ }
+
+ off = m->m_len % sizeof(u_int32_t);
+ if (off == 0)
+ return(1);
+
+ if (m->m_flags & M_EXT) {
+ /* can't write to an M_EXT mbuf since it may be shared */
+ if (en_makeexclusive(sc, &m, prev) == 0)
+ return (0);
+ *mm = m; /* note: 'd' now invalid */
+ }
+
+ d = mtod(m, u_char *) + m->m_len;
+ off = sizeof(u_int32_t) - off;
+
+ nxt = m->m_next;
+ while (off--) {
+ if (nxt != NULL && nxt->m_len == 0) {
+ /* remove an empty mbuf. this avoids odd byte padding to an empty
+ last mbuf. */
+ m->m_next = nxt = m_free(nxt);
+ }
+ if (nxt == NULL) { /* out of data, zero fill */
+ *d++ = 0;
+ continue; /* next "off" */
+ }
+ cp = mtod(nxt, u_char *);
+ *d++ = *cp++;
+ m->m_len++;
+ nxt->m_len--;
+ nxt->m_data = (caddr_t)cp;
+ }
+ if (nxt != NULL && nxt->m_len == 0)
+ m->m_next = m_free(nxt);
+ return(1);
+}
+
+#endif /* __FreeBSD__ */
/*
* en_txdma: start trasmit DMA, if possible
@@ -1764,6 +2069,7 @@ int chan;
struct en_launch launch;
int datalen = 0, dtqneed, len, ncells;
u_int8_t *cp;
+ struct ifnet *ifp;
#ifdef EN_DEBUG
printf("%s: tx%d: starting...\n", sc->sc_dev.dv_xname, chan);
@@ -1910,7 +2216,14 @@ again:
*/
EN_COUNT(sc->launch);
- sc->enif.if_opackets++;
+#ifdef ATM_PVCEXT
+ /* if there's a subinterface for this vci, override ifp. */
+ ifp = en_vci2ifp(sc, launch.atm_vci);
+#else
+ ifp = &sc->enif;
+#endif
+ ifp->if_opackets++;
+
if ((launch.atm_flags & EN_OBHDR) == 0) {
EN_COUNT(sc->lheader);
/* store tbd1/tbd2 in host byte order */
@@ -1923,7 +2236,27 @@ again:
}
en_txlaunch(sc, chan, &launch);
-
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf) {
+ /*
+ * adjust the top of the mbuf to skip the pseudo atm header
+ * (and TBD, if present) before passing the packet to bpf,
+ * restore it afterwards.
+ */
+ int size = sizeof(struct atm_pseudohdr);
+ if (launch.atm_flags & EN_OBHDR)
+ size += MID_TBD_SIZE;
+
+ launch.t->m_data += size;
+ launch.t->m_len -= size;
+
+ BPF_MTAP(ifp, launch.t);
+
+ launch.t->m_data -= size;
+ launch.t->m_len += size;
+ }
+#endif /* NBPFILTER > 0 */
/*
* do some housekeeping and get the next packet
*/
@@ -2319,6 +2652,7 @@ void *arg;
struct en_softc *sc = (struct en_softc *) arg;
struct mbuf *m;
struct atm_pseudohdr ah;
+ struct ifnet *ifp;
u_int32_t reg, kick, val, mask, chip, vci, slot, dtq, drq;
int lcv, idx, need_softserv = 0;
@@ -2340,7 +2674,11 @@ void *arg;
sc->sc_dev.dv_xname, reg, MID_INTBITS);
#ifdef EN_DEBUG
#ifdef DDB
+#ifdef __FreeBSD__
+ Debugger("en: unexpected error");
+#else
Debugger();
+#endif
#endif /* DDB */
sc->enif.if_flags &= ~IFF_RUNNING; /* FREEZE! */
#else
@@ -2412,7 +2750,7 @@ void *arg;
m_freem(m);
}
EN_WRAPADD(0, MID_DTQ_N, idx, 1);
- }
+ };
sc->dtq_chip = MID_DTQ_REG2A(val); /* sync softc */
}
@@ -2453,10 +2791,9 @@ void *arg;
m = NULL;
} else {
IF_DEQUEUE(&sc->rxslot[slot].indma, m);
- if (!m) {
- printf("%s: lost mbuf in slot %d!\n", sc->sc_dev.dv_xname, slot);
- panic("enintr: drqsync");
- }
+ if (!m)
+ panic("enintr: drqsync: %s: lost mbuf in slot %d!",
+ sc->sc_dev.dv_xname, slot);
}
/* do something with this mbuf */
if (sc->rxslot[slot].oth_flags & ENOTHER_DRAIN) { /* drain? */
@@ -2484,14 +2821,28 @@ void *arg;
sc->sc_dev.dv_xname, slot, sc->rxslot[slot].atm_vci, m,
EN_DQ_LEN(drq), sc->rxslot[slot].rxhand);
#endif
- sc->enif.if_ipackets++;
- atm_input(&sc->enif, &ah, m, sc->rxslot[slot].rxhand);
+#ifdef ATM_PVCEXT
+ /* if there's a subinterface for this vci, override ifp. */
+ ifp = en_vci2ifp(sc, sc->rxslot[slot].atm_vci);
+ ifp->if_ipackets++;
+ m->m_pkthdr.rcvif = ifp; /* XXX */
+#else
+ ifp = &sc->enif;
+ ifp->if_ipackets++;
+#endif
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ BPF_MTAP(ifp, m);
+#endif
+
+ atm_input(ifp, &ah, m, sc->rxslot[slot].rxhand);
}
}
EN_WRAPADD(0, MID_DRQ_N, idx, 1);
- }
+ };
sc->drq_chip = MID_DRQ_REG2A(val); /* sync softc */
if (sc->need_drqs) { /* true if we had a DRQ shortage */
@@ -2543,7 +2894,7 @@ void *arg;
printf("%s: added VCI %d to swslist\n", sc->sc_dev.dv_xname, vci);
#endif
}
- }
+ };
}
/*
@@ -2676,16 +3027,21 @@ defer: /* defer processing */
llc = (aal5 && (sc->rxslot[slot].atm_flags & ATM_PH_LLCSNAP)) ? 1 : 0;
rbd = EN_READ(sc, cur);
if (MID_RBD_ID(rbd) != MID_RBD_STDID)
- panic("en_service: id mismatch\n");
+ panic("en_service: id mismatch");
if (rbd & MID_RBD_T) {
mlen = 0; /* we've got trash */
fill = MID_RBD_SIZE;
EN_COUNT(sc->ttrash);
+#ifdef EN_DEBUG
+ printf("RX overflow lost %d cells!\n", MID_RBD_CNT(rbd));
+#endif
} else if (!aal5) {
mlen = MID_RBD_SIZE + MID_CHDR_SIZE + MID_ATMDATASZ; /* 1 cell (ick!) */
fill = 0;
} else {
+ struct ifnet *ifp;
+
tlen = (MID_RBD_CNT(rbd) * MID_ATMDATASZ) + MID_RBD_SIZE;
pdu = cur + tlen - MID_PDU_SIZE;
if (pdu >= stop)
@@ -2693,12 +3049,29 @@ defer: /* defer processing */
pdu = EN_READ(sc, pdu); /* get PDU in correct byte order */
fill = tlen - MID_RBD_SIZE - MID_PDU_LEN(pdu);
if (fill < 0 || (rbd & MID_RBD_CRCERR) != 0) {
- printf("%s: %s, dropping frame\n", sc->sc_dev.dv_xname,
- (rbd & MID_RBD_CRCERR) ? "CRC error" : "invalid AAL5 PDU length");
- printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x)\n",
- sc->sc_dev.dv_xname, MID_RBD_CNT(rbd), tlen - MID_RBD_SIZE,
- MID_PDU_LEN(pdu), pdu);
+ static int first = 1;
+
+ if (first) {
+ printf("%s: %s, dropping frame\n", sc->sc_dev.dv_xname,
+ (rbd & MID_RBD_CRCERR) ?
+ "CRC error" : "invalid AAL5 PDU length");
+ printf("%s: got %d cells (%d bytes), AAL5 len is %d bytes (pdu=0x%x)\n",
+ sc->sc_dev.dv_xname, MID_RBD_CNT(rbd),
+ tlen - MID_RBD_SIZE, MID_PDU_LEN(pdu), pdu);
+#ifndef EN_DEBUG
+ printf("CRC error report disabled from now on!\n");
+ first = 0;
+#endif
+ }
fill = tlen;
+
+#ifdef ATM_PVCEXT
+ ifp = en_vci2ifp(sc, vci);
+#else
+ ifp = &sc->enif;
+#endif
+ ifp->if_ierrors++;
+
}
mlen = tlen - fill;
}
@@ -3156,7 +3529,6 @@ int unit, level;
printf("0x%x ", sc->swslist[cnt]);
printf("\n");
}
-
}
return(0);
}
@@ -3193,5 +3565,423 @@ int unit, addr, len;
}
#endif
+#ifdef ATM_PVCEXT
+/*
+ * ATM PVC extention: shaper control and pvc subinterfaces
+ */
+
+/*
+ * the list of the interfaces sharing the physical device.
+ * in order to avoid starvation, the interfaces are scheduled in
+ * a round-robin fashion when en_start is called from tx complete
+ * interrupts.
+ */
+static void rrp_add(sc, ifp)
+ struct en_softc *sc;
+ struct ifnet *ifp;
+{
+ struct rrp *head, *p, *new;
+
+ head = sc->txrrp;
+ if ((p = head) != NULL) {
+ while (1) {
+ if (p->ifp == ifp) {
+ /* an entry for this ifp already exits */
+ p->nref++;
+ return;
+ }
+ if (p->next == head)
+ break;
+ p = p->next;
+ }
+ }
+
+ /* create a new entry */
+ MALLOC(new, struct rrp *, sizeof(struct rrp), M_DEVBUF, M_WAITOK);
+ if (new == NULL) {
+ printf("en_rrp_add: malloc failed!\n");
+ return;
+ }
+
+ new->ifp = ifp;
+ new->nref = 1;
+
+ if (p == NULL) {
+ /* this is the only one in the list */
+ new->next = new;
+ sc->txrrp = new;
+ }
+ else {
+ /* add the new entry at the tail of the list */
+ new->next = p->next;
+ p->next = new;
+ }
+}
+
+#if 0 /* not used */
+static void rrp_delete(sc, ifp)
+ struct en_softc *sc;
+ struct ifnet *ifp;
+{
+ struct rrp *head, *p, *prev;
+
+ head = sc->txrrp;
+
+ prev = head;
+ if (prev == NULL) {
+ printf("rrp_delete: no list!\n");
+ return;
+ }
+ p = prev->next;
+
+ while (1) {
+ if (p->ifp == ifp) {
+ p->nref--;
+ if (p->nref > 0)
+ return;
+ /* remove this entry */
+ if (p == prev) {
+ /* this is the only entry in the list */
+ sc->txrrp = NULL;
+ }
+ else {
+ prev->next = p->next;
+ if (head == p)
+ sc->txrrp = p->next;
+ }
+ FREE(p, M_DEVBUF);
+ }
+ prev = p;
+ p = prev->next;
+ if (prev == head) {
+ printf("rrp_delete: no matching entry!\n");
+ return;
+ }
+ }
+}
+#endif
+
+static struct ifnet *
+en_vci2ifp(sc, vci)
+ struct en_softc *sc;
+ int vci;
+{
+ struct pvcsif *pvcsif;
+
+ LIST_FOREACH(pvcsif, &sc->sif_list, sif_links) {
+ if (vci == pvcsif->sif_vci)
+ return (&pvcsif->sif_if);
+ }
+ return (&sc->enif);
+}
+
+/*
+ * create and attach per pvc subinterface
+ * (currently detach is not supported)
+ */
+static struct ifnet *
+en_pvcattach(ifp)
+ struct ifnet *ifp;
+{
+ struct en_softc *sc = (struct en_softc *) ifp->if_softc;
+ struct ifnet *pvc_ifp;
+ int s;
+
+ if ((pvc_ifp = pvcsif_alloc()) == NULL)
+ return (NULL);
+
+ pvc_ifp->if_softc = sc;
+ pvc_ifp->if_ioctl = en_ioctl;
+ pvc_ifp->if_start = en_start;
+ pvc_ifp->if_flags = (IFF_POINTOPOINT|IFF_MULTICAST) |
+ (ifp->if_flags & (IFF_RUNNING|IFF_SIMPLEX|IFF_NOTRAILERS));
+
+ s = splimp();
+ LIST_INSERT_HEAD(&sc->sif_list, (struct pvcsif *)pvc_ifp, sif_links);
+ if_attach(pvc_ifp);
+ atm_ifattach(pvc_ifp);
+
+#if NBPFILTER > 0
+ BPFATTACH(pvc_ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
+#endif
+#ifdef ATM_PVCEXT
+ rrp_add(sc, pvc_ifp);
+#endif
+ splx(s);
+
+ return (pvc_ifp);
+}
+
+
+/* txspeed conversion derived from linux drivers/atm/eni.c
+ by Werner Almesberger, EPFL LRC */
+static const int pre_div[] = { 4,16,128,2048 };
+
+static int en_pcr2txspeed(pcr)
+ int pcr;
+{
+ int pre, res, div;
+
+ if (pcr == 0 || pcr > 347222)
+ pre = res = 0; /* max rate */
+ else {
+ for (pre = 0; pre < 3; pre++)
+ if (25000000/pre_div[pre]/64 <= pcr)
+ break;
+ div = pre_div[pre]*(pcr);
+#if 1
+ /*
+ * the shaper value should be rounded down,
+ * instead of rounded up.
+ * (which means "res" should be rounded up.)
+ */
+ res = (25000000 + div -1)/div - 1;
+#else
+ res = 25000000/div-1;
+#endif
+ if (res < 0)
+ res = 0;
+ if (res > 63)
+ res = 63;
+ }
+ return ((pre << 6) + res);
+}
+
+static int en_txspeed2pcr(txspeed)
+ int txspeed;
+{
+ int pre, res, pcr;
+
+ pre = (txspeed >> 6) & 0x3;
+ res = txspeed & 0x3f;
+ pcr = 25000000 / pre_div[pre] / (res+1);
+ return (pcr);
+}
+
+/*
+ * en_txctl selects a hardware transmit channel and sets the shaper value.
+ * en_txctl should be called after enabling the vc by en_rxctl
+ * since it assumes a transmit channel is already assigned by en_rxctl
+ * to the vc.
+ */
+static int en_txctl(sc, vci, joint_vci, pcr)
+ struct en_softc *sc;
+ int vci;
+ int joint_vci;
+ int pcr;
+{
+ int txspeed, txchan, s;
+
+ if (pcr)
+ txspeed = en_pcr2txspeed(pcr);
+ else
+ txspeed = 0;
+
+ s = splimp();
+ txchan = sc->txvc2slot[vci];
+ sc->txslot[txchan].nref--;
+
+ /* select a slot */
+ if (joint_vci != 0)
+ /* use the same channel */
+ txchan = sc->txvc2slot[joint_vci];
+ else if (pcr == 0)
+ txchan = 0;
+ else {
+ for (txchan = 1; txchan < EN_NTX; txchan++) {
+ if (sc->txslot[txchan].nref == 0)
+ break;
+ }
+ }
+ if (txchan == EN_NTX) {
+#if 1
+ /* no free slot! */
+ splx(s);
+ return (ENOSPC);
+#else
+ /*
+ * to allow multiple vc's to share a slot,
+ * use a slot with the smallest reference count
+ */
+ int slot = 1;
+ txchan = 1;
+ for (slot = 2; slot < EN_NTX; slot++)
+ if (sc->txslot[slot].nref < sc->txslot[txchan].nref)
+ txchan = slot;
+#endif
+ }
+
+ sc->txvc2slot[vci] = txchan;
+ sc->txslot[txchan].nref++;
+
+ /* set the shaper parameter */
+ sc->txspeed[vci] = (u_int8_t)txspeed;
+
+ splx(s);
+#ifdef EN_DEBUG
+ printf("VCI:%d PCR set to %d, tx channel %d\n", vci, pcr, txchan);
+ if (joint_vci != 0)
+ printf(" slot shared with VCI:%d\n", joint_vci);
+#endif
+ return (0);
+}
+
+static int en_pvctx(sc, pvcreq)
+ struct en_softc *sc;
+ struct pvctxreq *pvcreq;
+{
+ struct ifnet *ifp;
+ struct atm_pseudoioctl api;
+ struct atm_pseudohdr *pvc_aph, *pvc_joint;
+ int vci, joint_vci, pcr;
+ int error = 0;
+
+ /* check vpi:vci values */
+ pvc_aph = &pvcreq->pvc_aph;
+ pvc_joint = &pvcreq->pvc_joint;
+
+ vci = ATM_PH_VCI(pvc_aph);
+ joint_vci = ATM_PH_VCI(pvc_joint);
+ pcr = pvcreq->pvc_pcr;
+
+ if (ATM_PH_VPI(pvc_aph) != 0 || vci >= MID_N_VC ||
+ ATM_PH_VPI(pvc_joint) != 0 || joint_vci >= MID_N_VC)
+ return (EADDRNOTAVAIL);
+
+ if ((ifp = ifunit(pvcreq->pvc_ifname)) == NULL)
+ return (ENXIO);
+
+ if (pcr < 0) {
+ /* negative pcr means disable the vc. */
+ if (sc->rxvc2slot[vci] == RX_NONE)
+ /* already disabled */
+ return 0;
+
+ ATM_PH_FLAGS(&api.aph) = 0;
+ ATM_PH_VPI(&api.aph) = 0;
+ ATM_PH_SETVCI(&api.aph, vci);
+ api.rxhand = NULL;
+
+ error = en_rxctl(sc, &api, 0);
+
+ if (error == 0 && &sc->enif != ifp) {
+ /* clear vc info of this subinterface */
+ struct pvcsif *pvcsif = (struct pvcsif *)ifp;
+
+ ATM_PH_SETVCI(&api.aph, 0);
+ pvcsif->sif_aph = api.aph;
+ pvcsif->sif_vci = 0;
+ }
+ return (error);
+ }
+
+ if (&sc->enif == ifp) {
+ /* called for an en interface */
+ if (sc->rxvc2slot[vci] == RX_NONE) {
+ /* vc is not active */
+#ifdef __NetBSD__
+ printf("%s: en_pvctx: rx not active! vci=%d\n",
+ ifp->if_xname, vci);
+#else
+ printf("%s%d: en_pvctx: rx not active! vci=%d\n",
+ ifp->if_name, ifp->if_unit, vci);
+#endif
+ return (EINVAL);
+ }
+ }
+ else {
+ /* called for a pvc subinterface */
+ struct pvcsif *pvcsif = (struct pvcsif *)ifp;
+
+#ifdef __NetBSD__
+ strcpy(pvcreq->pvc_ifname, sc->enif.if_xname);
+#else
+ sprintf(pvcreq->pvc_ifname, "%s%d",
+ sc->enif.if_name, sc->enif.if_unit);
+#endif
+ ATM_PH_FLAGS(&api.aph) =
+ (ATM_PH_FLAGS(pvc_aph) & (ATM_PH_AAL5|ATM_PH_LLCSNAP));
+ ATM_PH_VPI(&api.aph) = 0;
+ ATM_PH_SETVCI(&api.aph, vci);
+ api.rxhand = NULL;
+ pvcsif->sif_aph = api.aph;
+ pvcsif->sif_vci = ATM_PH_VCI(&api.aph);
+
+ if (sc->rxvc2slot[vci] == RX_NONE) {
+ /* vc is not active, enable rx */
+ error = en_rxctl(sc, &api, 1);
+ if (error)
+ return error;
+ }
+ else {
+ /* vc is already active, update aph in softc */
+ sc->rxslot[sc->rxvc2slot[vci]].atm_flags =
+ ATM_PH_FLAGS(&api.aph);
+ }
+ }
+
+ error = en_txctl(sc, vci, joint_vci, pcr);
+
+ if (error == 0) {
+ if (sc->txspeed[vci] != 0)
+ pvcreq->pvc_pcr = en_txspeed2pcr(sc->txspeed[vci]);
+ else
+ pvcreq->pvc_pcr = 0;
+ }
+
+ return error;
+}
+
+static int en_pvctxget(sc, pvcreq)
+ struct en_softc *sc;
+ struct pvctxreq *pvcreq;
+{
+ struct pvcsif *pvcsif;
+ struct ifnet *ifp;
+ int vci, slot;
+
+ if ((ifp = ifunit(pvcreq->pvc_ifname)) == NULL)
+ return (ENXIO);
+
+ if (ifp == &sc->enif) {
+ /* physical interface: assume vci is specified */
+ struct atm_pseudohdr *pvc_aph;
+
+ pvc_aph = &pvcreq->pvc_aph;
+ vci = ATM_PH_VCI(pvc_aph);
+ if ((slot = sc->rxvc2slot[vci]) == RX_NONE)
+ ATM_PH_FLAGS(pvc_aph) = 0;
+ else
+ ATM_PH_FLAGS(pvc_aph) = sc->rxslot[slot].atm_flags;
+ ATM_PH_VPI(pvc_aph) = 0;
+ }
+ else {
+ /* pvc subinterface */
+#ifdef __NetBSD__
+ strcpy(pvcreq->pvc_ifname, sc->enif.if_xname);
+#else
+ sprintf(pvcreq->pvc_ifname, "%s%d",
+ sc->enif.if_name, sc->enif.if_unit);
+#endif
+
+ pvcsif = (struct pvcsif *)ifp;
+ pvcreq->pvc_aph = pvcsif->sif_aph;
+ vci = pvcsif->sif_vci;
+ }
+
+ if ((slot = sc->rxvc2slot[vci]) == RX_NONE) {
+ /* vc is not active */
+ ATM_PH_FLAGS(&pvcreq->pvc_aph) = 0;
+ pvcreq->pvc_pcr = -1;
+ }
+ else if (sc->txspeed[vci])
+ pvcreq->pvc_pcr = en_txspeed2pcr(sc->txspeed[vci]);
+ else
+ pvcreq->pvc_pcr = 0;
+
+ return (0);
+}
+
+#endif /* ATM_PVCEXT */
#endif /* NEN > 0 || !defined(__FreeBSD__) */
diff --git a/sys/dev/ic/midwayreg.h b/sys/dev/ic/midwayreg.h
index a7ca409aead..20fd9a32a44 100644
--- a/sys/dev/ic/midwayreg.h
+++ b/sys/dev/ic/midwayreg.h
@@ -1,4 +1,4 @@
-/* $NetBSD: midwayreg.h,v 1.8 1999/03/03 12:58:14 pk Exp $ */
+/* $NetBSD: midwayreg.h,v 1.9 1999/07/01 08:12:46 itojun Exp $ */
/*
* m i d w a y r e g . h
@@ -66,6 +66,7 @@ typedef caddr_t bus_addr_t;
/*
* prom & phy: not defined here
*/
+#define MID_ADPMACOFF 0xffc0 /* mac address offset (adaptec only) */
/*
* midway regs (byte offsets from en_base)
diff --git a/sys/dev/ic/midwayvar.h b/sys/dev/ic/midwayvar.h
index c17db92b3ad..15884900f97 100644
--- a/sys/dev/ic/midwayvar.h
+++ b/sys/dev/ic/midwayvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: midwayvar.h,v 1.10 1997/03/20 21:34:46 chuck Exp $ */
+/* $NetBSD: midwayvar.h,v 1.11 1999/07/01 08:12:46 itojun Exp $ */
/*
*
@@ -90,6 +90,16 @@ struct cfdriver {
#endif
+#if 1 /* for ATM_PVCEXT */
+#include <sys/queue.h>
+
+/* round-robin scheduler */
+struct rrp {
+ struct rrp *next;
+ struct ifnet *ifp;
+ int nref;
+};
+#endif
/*
* softc
@@ -144,6 +154,10 @@ struct en_softc {
u_int8_t txspeed[MID_N_VC]; /* speed of tx on a VC */
u_int8_t txvc2slot[MID_N_VC]; /* map VC to slot */
+#if 1 /* for ATM_PVCEXT */
+ struct rrp *txrrp; /* round-robin pointer to ifnet */
+#endif
+
/* recv vc ctrl. (per vc). maps VC number to recv slot */
u_int16_t rxvc2slot[MID_N_VC];
int en_nrx; /* # of active rx slots */
@@ -162,6 +176,8 @@ struct en_softc {
struct ifqueue q; /* mbufs waiting for dma now */
} rxslot[EN_MAXNRX]; /* recv info */
+ u_int8_t macaddr[6]; /* card unique mac address */
+
/* stats */
u_int32_t vtrash; /* sw copy of counter */
u_int32_t otrash; /* sw copy of counter */
@@ -194,6 +210,10 @@ struct en_softc {
u_int8_t bestburstmask; /* bits to check if not multiple of burst */
u_int8_t alburst; /* align dma bursts? */
u_int8_t is_adaptec; /* adaptec version of midway? */
+
+#if 1 /* for ATM_PVCEXT */
+ LIST_HEAD(sif_list, pvcsif) sif_list; /* pvc subinterface list */
+#endif
};
/*
diff --git a/sys/dev/pci/if_en_pci.c b/sys/dev/pci/if_en_pci.c
index 2cf03b46b8c..2a883085173 100644
--- a/sys/dev/pci/if_en_pci.c
+++ b/sys/dev/pci/if_en_pci.c
@@ -1,4 +1,4 @@
-/* $NetBSD: if_en_pci.c,v 1.12 1999/03/24 18:47:51 cgd Exp $ */
+/* $NetBSD: if_en_pci.c,v 1.13 1999/07/01 08:12:46 itojun Exp $ */
/*
*
@@ -77,6 +77,15 @@ struct en_pci_softc {
* local defines (PCI specific stuff)
*/
+#if !defined(MIDWAY_ENIONLY)
+static void eni_get_macaddr __P((struct en_pci_softc *,
+ struct pci_attach_args *));
+#endif
+#if !defined(MIDWAY_ADPONLY)
+static void adp_get_macaddr __P((struct en_pci_softc *,
+ struct pci_attach_args *));
+#endif
+
/*
* address of config base memory address register in PCI config space
* (this is card specific)
@@ -246,6 +255,7 @@ void *aux;
#if !defined(MIDWAY_ENIONLY)
if (sc->is_adaptec) {
+ adp_get_macaddr(scp, pa);
sc->en_busreset = adp_busreset;
adp_busreset(sc);
}
@@ -253,6 +263,7 @@ void *aux;
#if !defined(MIDWAY_ADPONLY)
if (!sc->is_adaptec) {
+ eni_get_macaddr(scp, pa);
sc->en_busreset = NULL;
pci_conf_write(scp->en_pc, pa->pa_tag, EN_TONGA,
(TONGA_SWAP_DMA|TONGA_SWAP_WORD));
@@ -266,3 +277,140 @@ void *aux;
en_attach(sc);
}
+
+#if 0
+static void
+en_pci_shutdown(
+ int howto,
+ void *sc)
+{
+ struct en_pci_softc *psc = (struct en_pci_softc *)sc;
+
+ en_reset(&psc->esc);
+ DELAY(10);
+}
+#endif
+
+#if !defined(MIDWAY_ENIONLY)
+
+#if defined(sparc) || defined(__FreeBSD__)
+#define bus_space_read_1(t, h, o) \
+ ((void)t, (*(volatile u_int8_t *)((h) + (o))))
+#endif
+
+static void
+adp_get_macaddr(scp, pa)
+ struct en_pci_softc *scp;
+ struct pci_attach_args *pa;
+{
+ struct en_softc * sc = (struct en_softc *)scp;
+ int lcv;
+
+ for (lcv = 0; lcv < sizeof(sc->macaddr); lcv++)
+ sc->macaddr[lcv] = bus_space_read_1(sc->en_memt, sc->en_base,
+ MID_ADPMACOFF + lcv);
+}
+
+#endif /* MIDWAY_ENIONLY */
+
+#if !defined(MIDWAY_ADPONLY)
+
+/*
+ * Read station (MAC) address from serial EEPROM.
+ * derived from linux drivers/atm/eni.c by Werner Almesberger, EPFL LRC.
+ */
+#define EN_PROM_MAGIC 0x0c
+#define EN_PROM_DATA 0x02
+#define EN_PROM_CLK 0x01
+#define EN_ESI 64
+
+static void
+eni_get_macaddr(scp, pa)
+ struct en_pci_softc *scp;
+ struct pci_attach_args *pa;
+{
+ struct en_softc *sc = (struct en_softc *)scp;
+ pci_chipset_tag_t id = scp->en_pc;
+ pcitag_t tag = pa->pa_tag;
+ int i, j, address, status;
+ u_int32_t data, t_data;
+ u_int8_t tmp;
+
+ t_data = pci_conf_read(id, tag, EN_TONGA) & 0xffffff00;
+
+ data = EN_PROM_MAGIC | EN_PROM_DATA | EN_PROM_CLK;
+ pci_conf_write(id, tag, EN_TONGA, data);
+
+ for (i = 0; i < sizeof(sc->macaddr); i ++){
+ /* start operation */
+ data |= EN_PROM_DATA ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data |= EN_PROM_CLK ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data &= ~EN_PROM_DATA ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data &= ~EN_PROM_CLK ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ /* send address with serial line */
+ address = ((i + EN_ESI) << 1) + 1;
+ for ( j = 7 ; j >= 0 ; j --){
+ data = (address >> j) & 1 ? data | EN_PROM_DATA :
+ data & ~EN_PROM_DATA;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data |= EN_PROM_CLK ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data &= ~EN_PROM_CLK ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ }
+ /* get ack */
+ data |= EN_PROM_DATA ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data |= EN_PROM_CLK ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data = pci_conf_read(id, tag, EN_TONGA);
+ status = data & EN_PROM_DATA;
+ data &= ~EN_PROM_CLK ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data |= EN_PROM_DATA ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+
+ tmp = 0;
+
+ for ( j = 7 ; j >= 0 ; j --){
+ tmp <<= 1;
+ data |= EN_PROM_DATA ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data |= EN_PROM_CLK ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data = pci_conf_read(id, tag, EN_TONGA);
+ if(data & EN_PROM_DATA) tmp |= 1;
+ data &= ~EN_PROM_CLK ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data |= EN_PROM_DATA ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ }
+ /* get ack */
+ data |= EN_PROM_DATA ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data |= EN_PROM_CLK ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data = pci_conf_read(id, tag, EN_TONGA);
+ status = data & EN_PROM_DATA;
+ data &= ~EN_PROM_CLK ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data |= EN_PROM_DATA ;
+ pci_conf_write(id, tag, EN_TONGA, data);
+
+ sc->macaddr[i] = tmp;
+ }
+ /* stop operation */
+ data &= ~EN_PROM_DATA;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data |= EN_PROM_CLK;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ data |= EN_PROM_DATA;
+ pci_conf_write(id, tag, EN_TONGA, data);
+ pci_conf_write(id, tag, EN_TONGA, t_data);
+}
+
+#endif /* !MIDWAY_ADPONLY */
diff --git a/sys/dev/pci/pcidevs.h b/sys/dev/pci/pcidevs.h
index a6820bee810..00d6c4bfb37 100644
--- a/sys/dev/pci/pcidevs.h
+++ b/sys/dev/pci/pcidevs.h
@@ -1,10 +1,10 @@
-/* $NetBSD: pcidevs.h,v 1.139 1999/06/27 15:15:00 drochner Exp $ */
+/* $NetBSD: pcidevs.h,v 1.140 1999/07/01 08:12:46 itojun Exp $ */
/*
* THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.
*
* generated from:
- * NetBSD: pcidevs,v 1.132 1999/06/27 15:13:54 drochner Exp
+ * NetBSD: pcidevs,v 1.133 1999/06/30 16:52:52 fair Exp
*/
/*
@@ -41,6 +41,10 @@
/*
* NOTE: a fairly complete list of PCI codes can be found at:
*
+ * http://members.hyperlink.net.au/~chart/pci.htm
+ *
+ * which replaces the database previously found at
+ *
* http://www.halcyon.com/scripts/jboemler/pci/pcicode
*
* (but it doesn't always seem to match vendor documentation)
diff --git a/sys/dev/pci/pcidevs_data.h b/sys/dev/pci/pcidevs_data.h
index 30eb3f2f025..1bd9f179819 100644
--- a/sys/dev/pci/pcidevs_data.h
+++ b/sys/dev/pci/pcidevs_data.h
@@ -1,10 +1,10 @@
-/* $NetBSD: pcidevs_data.h,v 1.137 1999/06/27 15:15:00 drochner Exp $ */
+/* $NetBSD: pcidevs_data.h,v 1.138 1999/07/01 08:12:47 itojun Exp $ */
/*
* THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT.
*
* generated from:
- * NetBSD: pcidevs,v 1.132 1999/06/27 15:13:54 drochner Exp
+ * NetBSD: pcidevs,v 1.133 1999/06/30 16:52:52 fair Exp
*/
/*