on uba reset remap already allocated pages
[unix-history] / usr / src / sys / vax / if / if_uba.c
index 6396e92..c9298a2 100644 (file)
@@ -1,14 +1,20 @@
-/*     if_uba.c        4.1     81/11/25        */
+/*     if_uba.c        4.11    82/05/19        */
 
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/mbuf.h"
 #include "../h/map.h"
 #include "../h/pte.h"
 
 #include "../h/param.h"
 #include "../h/systm.h"
 #include "../h/mbuf.h"
 #include "../h/map.h"
 #include "../h/pte.h"
+#include "../h/buf.h"
 #include "../h/ubareg.h"
 #include "../h/ubavar.h"
 #include "../h/cmap.h"
 #include "../h/mtpr.h"
 #include "../h/ubareg.h"
 #include "../h/ubavar.h"
 #include "../h/cmap.h"
 #include "../h/mtpr.h"
+#include "../h/vmmac.h"
+#include "../h/socket.h"
+#include "../net/in.h"
+#include "../net/in_systm.h"
+#include "../net/if.h"
 #include "../net/if_uba.h"
 
 /*
 #include "../net/if_uba.h"
 
 /*
@@ -29,138 +35,127 @@ if_ubainit(ifu, uban, hlen, nmr)
        register struct ifuba *ifu;
        int uban, hlen, nmr;
 {
        register struct ifuba *ifu;
        int uban, hlen, nmr;
 {
-       register caddr_t cp = m_pgalloc(2 * (nmr + 1));
+       register caddr_t cp;
+       int i, ncl;
 
 
-       if (cp == 0)
-               return (0);
-       ifu->if_uban = uban;
-       ifu->if_uba = &uba_hd[uban]->uh_uba;
-       ifu->if_r.if_addr = cp + NMBPG - hlen;
-       ifu->if_w.if_addr = ifu->if_r.if_addr + (nmr + 1) * NMBPG;
-       if (if_ubaalloc(ifu, &ifu->if_r) == 0)
+COUNT(IF_UBAINIT);
+       ncl = clrnd(nmr + CLSIZE) / CLSIZE;
+       if (ifu->ifu_r.ifrw_addr)
+               cp = ifu->ifu_r.ifrw_addr - (CLBYTES - hlen);
+       else {
+               cp = m_clalloc(2 * ncl, MPG_SPACE);
+               if (cp == 0)
+                       return (0);
+               ifu->ifu_r.ifrw_addr = cp + CLBYTES - hlen;
+               ifu->ifu_w.ifrw_addr = ifu->ifu_r.ifrw_addr + ncl * CLBYTES;
+               ifu->ifu_hlen = hlen;
+               ifu->ifu_uban = uban;
+               ifu->ifu_uba = uba_hd[uban].uh_uba;
+       }
+       if (if_ubaalloc(ifu, &ifu->ifu_r, nmr) == 0)
                goto bad;
                goto bad;
-       if (if_ubaalloc(ifu, &ifu->if_w) == 0)
+       if (if_ubaalloc(ifu, &ifu->ifu_w, nmr) == 0)
                goto bad2;
                goto bad2;
-       for (i = 0; i < IF_NUBAMR; i++)
-               ifu->if_xmap[i] = ifu->if_w.if_map[i+1];
-       ifu->if_xswapd = 0;
+       for (i = 0; i < nmr; i++)
+               ifu->ifu_wmap[i] = ifu->ifu_w.ifrw_mr[i];
+       ifu->ifu_xswapd = 0;
        return (1);
 bad2:
        return (1);
 bad2:
-       ubafree(ifu->ifu_uban, ifu->if_r.ifrw_info);
+       ubarelse(ifu->ifu_uban, &ifu->ifu_r.ifrw_info);
 bad:
 bad:
-       m_pgfree(cp, 2 * (nmr + 1));
+       m_pgfree(cp, 2 * ncl);
+       ifu->ifu_r.ifrw_addr = 0;
        return (0);
 }
 
 /*
  * Setup either a ifrw structure by allocating UNIBUS map registers,
        return (0);
 }
 
 /*
  * Setup either a ifrw structure by allocating UNIBUS map registers,
- * a buffered data path, and initializing the fields of the ifrw structure
- * to minimize run-time overhead.
+ * possibly a buffered data path, and initializing the fields of
+ * the ifrw structure to minimize run-time overhead.
  */
 static
  */
 static
-if_ubaalloc(ifu, ifrw)
+if_ubaalloc(ifu, ifrw, nmr)
        struct ifuba *ifu;
        register struct ifrw *ifrw;
        struct ifuba *ifu;
        register struct ifrw *ifrw;
+       int nmr;
 {
        register int info;
 
 {
        register int info;
 
+COUNT(IF_UBAALLOC);
        info =
        info =
-           uballoc(ifu->ifu_uban, ifrw->ifrw_addr, IF_NUBAMR*NMBPG + hlen,
-               UBA_NEED16|UBA_NEEDBDP);
+           uballoc(ifu->ifu_uban, ifrw->ifrw_addr, nmr*NBPG + ifu->ifu_hlen,
+               ifu->ifu_flags);
        if (info == 0)
        if (info == 0)
-               goto bad;
+               return (0);
        ifrw->ifrw_info = info;
        ifrw->ifrw_bdp = UBAI_BDP(info);
        ifrw->ifrw_info = info;
        ifrw->ifrw_bdp = UBAI_BDP(info);
-       ifrw->ifrw_proto = UBAMR_MRV | UBAI_DPDF(info);
-       ifrw->ifrw_mr = &ifu->if_uba[UBAI_MR(info) + 1];
+       ifrw->ifrw_proto = UBAMR_MRV | (UBAI_BDP(info) << UBAMR_DPSHIFT);
+       ifrw->ifrw_mr = &ifu->ifu_uba->uba_map[UBAI_MR(info) + 1];
+       return (1);
 }
 
 /*
 }
 
 /*
- * Pull read data off a interface, given length.
- * Map the header into a mbuf, and then copy or
- * remap the data into a chain of mbufs.
- * Return 0 if there is no space, or a pointer
- * to the assembled mbuf chain.
+ * Pull read data off a interface.
+ * Len is length of data, with local net header stripped.
+ * Off is non-zero if a trailer protocol was used, and
+ * gives the offset of the trailer information.
+ * We copy the trailer information and then all the normal
+ * data into mbufs.  When full cluster sized units are present
+ * on the interface on cluster boundaries we can get them more
+ * easily by remapping, and take advantage of this here.
  */
 struct mbuf *
  */
 struct mbuf *
-if_rubaget(ifu, len)
+if_rubaget(ifu, totlen, off0)
        register struct ifuba *ifu;
        register struct ifuba *ifu;
-       int len;
+       int totlen, off0;
 {
 {
-       register struct mbuf *m;
-       register caddr_t cp;
-       struct mbuf *mp, *p, *top;
+       struct mbuf *top, **mp, *m;
+       int off = off0, len;
+       register caddr_t cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen;
 
 
-       /*
-        * First pull local net header off into a mbuf.
-        */
-       MGET(m, 0);
-       if (m == 0)
-               return (0);
-       m->m_off = MMINOFF;
-       m->m_len = ifu->if_hlen;
-       top = m;
-       cp = ifu->ifu_r.ifrw_addr;
-       bcopy(cp, mtod(m, caddr_t), ifu->if_hlen);
-       len -= hlen;
-       cp += hlen;
+COUNT(IF_RUBAGET);
 
 
-       /*
-        * Now pull data off.  If whole pages
-        * are there, pull into pages if possible,
-        * otherwise copy small blocks into mbufs.
-        */
-       mp = m;
-       while (len > 0) {
+       top = 0;
+       mp = &top;
+       while (totlen > 0) {
                MGET(m, 0);
                if (m == 0)
                MGET(m, 0);
                if (m == 0)
-                       goto flush;
-               if (len >= CLSIZE) {
+                       goto bad;
+               if (off) {
+                       len = totlen - off;
+                       cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen + off;
+               } else
+                       len = totlen;
+               if (len >= CLBYTES) {
+                       struct mbuf *p;
                        struct pte *cpte, *ppte;
                        struct pte *cpte, *ppte;
-                       int i, x, *ip;
+                       int x, *ip, i;
 
                        MCLGET(p, 1);
                        if (p == 0)
                                goto nopage;
 
                        MCLGET(p, 1);
                        if (p == 0)
                                goto nopage;
-                       m->m_len = CLSIZE;
+                       len = m->m_len = CLBYTES;
                        m->m_off = (int)p - (int)m;
                        m->m_off = (int)p - (int)m;
-                       if ((int)cp & CLOFF)
+                       if (!claligned(cp))
                                goto copy;
 
                        /*
                                goto copy;
 
                        /*
-                        * Cluster size data on cluster size boundary.
-                        * Input by remapping newly allocated pages to
-                        * UNIBUS, and taking pages with data already
-                        * in them.
-                        *
-                        * Cpte is the pte of the virtual memory which
-                        * is mapped to the UNIBUS, and ppte is the pte
-                        * for the fresh pages.  We switch the memory
-                        * copies of these pte's, to make the allocated
-                        * virtual memory contain the data (using the old
-                        * physical pages).  We have to rewrite
-                        * the UNIBUS map so that the newly allocated
-                        * pages will be used for the next UNIBUS read,
-                        * and invalidate the kernel translations
-                        * for the virtual addresses of the pages
-                        * we are flipping.
-                        *
-                        * The idea here is that this is supposed
-                        * to take less time than copying the data.
+                        * Switch pages mapped to UNIBUS with new page p,
+                        * as quick form of copy.  Remap UNIBUS and invalidate.
                         */
                         */
-                       cpte = &Mbmap[mtocl(cp)];
-                       ppte = &Mbmap[mtocl(p)];
-                       x = btop(cp - ifu->if_r.ifrw_addr);
-                       ip = (int *)&ifu->ifu_r.ifrw_mr[x+1];
+                       cpte = &Mbmap[mtocl(cp)*CLSIZE];
+                       ppte = &Mbmap[mtocl(p)*CLSIZE];
+                       x = btop(cp - ifu->ifu_r.ifrw_addr);
+                       ip = (int *)&ifu->ifu_r.ifrw_mr[x];
                        for (i = 0; i < CLSIZE; i++) {
                                struct pte t;
                        for (i = 0; i < CLSIZE; i++) {
                                struct pte t;
-                               t = *ppte; *ppte = *cpte; *cpte = t;
+                               t = *ppte; *ppte++ = *cpte; *cpte = t;
                                *ip++ =
                                *ip++ =
-                                   *cpte++->pg_pfnum|ifu->if_r.ifrw_proto;
+                                   cpte++->pg_pfnum|ifu->ifu_r.ifrw_proto;
                                mtpr(TBIS, cp);
                                mtpr(TBIS, cp);
-                               cp += NMBPG;
+                               cp += NBPG;
                                mtpr(TBIS, (caddr_t)p);
                                mtpr(TBIS, (caddr_t)p);
-                               p += NMBPG / sizeof (*p);
+                               p += NBPG / sizeof (*p);
                        }
                        goto nocopy;
                }
                        }
                        goto nocopy;
                }
@@ -171,9 +166,18 @@ copy:
                bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len);
                cp += m->m_len;
 nocopy:
                bcopy(cp, mtod(m, caddr_t), (unsigned)m->m_len);
                cp += m->m_len;
 nocopy:
-               len -= m->m_len;
-               mp->m_next = m;
-               mp = m;
+               *mp = m;
+               mp = &m->m_next;
+               if (off) {
+                       /* sort of an ALGOL-W style for statement... */
+                       off += m->m_len;
+                       if (off == totlen) {
+                               cp = ifu->ifu_r.ifrw_addr + ifu->ifu_hlen;
+                               off = 0;
+                               totlen = off0;
+                       }
+               } else
+                       totlen -= m->m_len;
        }
        return (top);
 bad:
        }
        return (top);
 bad:
@@ -195,37 +199,56 @@ if_wubaput(ifu, m)
        register struct mbuf *mp;
        register caddr_t cp, dp;
        register int i;
        register struct mbuf *mp;
        register caddr_t cp, dp;
        register int i;
-       int xswapd = ifu->ifu_xswapd;
-       int x;
+       int xswapd = 0;
+       int x, cc;
 
 
-       ifu->ifu_xswapd = 0;
+COUNT(IF_WUBAPUT);
        cp = ifu->ifu_w.ifrw_addr;
        while (m) {
                dp = mtod(m, char *);
        cp = ifu->ifu_w.ifrw_addr;
        while (m) {
                dp = mtod(m, char *);
-               if (claligned(cp) && claligned(dp)) {
+               if (claligned(cp) && claligned(dp) && m->m_len == CLBYTES) {
                        struct pte *pte; int *ip;
                        struct pte *pte; int *ip;
-                       pte = &Mbmap[mtocl(dp)];
+                       pte = &Mbmap[mtocl(dp)*CLSIZE];
                        x = btop(cp - ifu->ifu_w.ifrw_addr);
                        x = btop(cp - ifu->ifu_w.ifrw_addr);
-                       ip = &ifu->ifu_w.ifrw_mr[x + 1];
+                       ip = (int *)&ifu->ifu_w.ifrw_mr[x];
                        for (i = 0; i < CLSIZE; i++)
                                *ip++ =
                                    ifu->ifu_w.ifrw_proto | pte++->pg_pfnum;
                        for (i = 0; i < CLSIZE; i++)
                                *ip++ =
                                    ifu->ifu_w.ifrw_proto | pte++->pg_pfnum;
-                       ifu->ifu_xswapd |= 1 << (x>>CLSHIFT);
-               } else
+                       xswapd |= 1 << (x>>(CLSHIFT-PGSHIFT));
+                       mp = m->m_next;
+                       m->m_next = ifu->ifu_xtofree;
+                       ifu->ifu_xtofree = m;
+                       cp += m->m_len;
+               } else {
                        bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
                        bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
-               cp += m->m_len;
-               MFREE(m, mp);                   /* XXX too soon! */
+                       cp += m->m_len;
+                       MFREE(m, mp);
+               }
                m = mp;
        }
                m = mp;
        }
+
+       /*
+        * Xswapd is the set of clusters we just mapped out.  Ifu->ifu_xswapd
+        * is the set of clusters mapped out from before.  We compute
+        * the number of clusters involved in this operation in x.
+        * Clusters mapped out before and involved in this operation
+        * should be unmapped so original pages will be accessed by the device.
+        */
+       cc = cp - ifu->ifu_w.ifrw_addr;
+       x = ((cc - ifu->ifu_hlen) + CLBYTES - 1) >> CLSHIFT;
+       ifu->ifu_xswapd &= ~xswapd;
        xswapd &= ~ifu->ifu_xswapd;
        xswapd &= ~ifu->ifu_xswapd;
-       if (xswapd)
-               while (i = ffs(xswapd)) {
-                       i--;
-                       xswapd &= ~(1<<i);
-                       i <<= CLSHIFT;
-                       for (x = 0; x < CLSIZE; x++) {
-                               ifu->ifu_rw.ifrw_mr[i] = ifu->ifu_xmap[i];
-                               i++;
-                       }
+       while (i = ffs(ifu->ifu_xswapd)) {
+               i--;
+               if (i >= x)
+                       break;
+               ifu->ifu_xswapd &= ~(1<<i);
+               i *= CLSIZE;
+               for (x = 0; x < CLSIZE; x++) {
+                       ifu->ifu_w.ifrw_mr[i] = ifu->ifu_wmap[i];
+                       i++;
                }
                }
+       }
+       ifu->ifu_xswapd |= xswapd;
+       return (cc);
 }
 }