1: /* 2: * Copyright (c) 1982, 1986 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: * 6: * @(#)uipc_mbuf.c 2.0 (2.11BSD) 12/24/92 7: */ 8: 9: #include "param.h" 10: #ifdef INET 11: #include "user.h" 12: #include "mbuf.h" 13: #include "kernel.h" 14: #include "domain.h" 15: #include "protosw.h" 16: 17: struct mbuf *mbuf, *mbutl, xmbuf[NMBUFS + 1]; 18: struct mbuf xmbutl[(NMBCLUSTERS*CLBYTES/sizeof (struct mbuf))+7]; 19: memaddr miobase; /* click address of dma region */ 20: /* this is altered during allocation */ 21: memaddr miostart; /* click address of dma region */ 22: /* this stays unchanged */ 23: ubadr_t mioumr; /* base UNIBUS virtual address */ 24: /* miostart and mioumr stay 0 for */ 25: /* non-UNIBUS machines */ 26: u_short miosize = 16384; /* two umr's worth */ 27: 28: mbinit() 29: { 30: register int s; 31: 32: s = splimp(); 33: nmbclusters = NMBCLUSTERS; 34: /* 35: * if the following two lines look strange, it's because they are. 36: * mbufs are aligned on a MSIZE byte boundary and clusters are 37: * aligned on CLBYTES byte boundary. extra room has been allocated 38: * in the arrays to allow for the array origin not being aligned, 39: * in which case we move part way thru and start there. 40: */ 41: mbutl = (struct mbuf *)(((int)xmbutl | CLBYTES-1) + 1); 42: mbuf = (struct mbuf *)(((int)xmbuf | MSIZE-1) + 1); 43: mbinit2(mbuf, MPG_MBUFS, NMBUFS); 44: mbinit2(mbutl, MPG_CLUSTERS, NMBCLUSTERS); 45: splx(s); 46: return; 47: } 48: 49: mbinit2(mem, how, num) 50: char *mem; 51: int how; 52: register int num; 53: { 54: register struct mbuf *m; 55: register int i; 56: 57: m = (struct mbuf *)mem; 58: switch (how) { 59: case MPG_CLUSTERS: 60: for (i = 0; i < num; i++) { 61: m->m_off = 0; 62: m->m_next = mclfree; 63: mclfree = m; 64: m += NMBPCL; 65: mbstat.m_clfree++; 66: } 67: mbstat.m_clusters = num; 68: break; 69: case MPG_MBUFS: 70: for (i = num; i > 0; i--) { 71: m->m_off = 0; 72: m->m_type = MT_DATA; 73: mbstat.m_mtypes[MT_DATA]++; 74: (void) m_free(m); 75: m++; 76: } 77: mbstat.m_mbufs = NMBUFS; 78: break; 79: } 80: } 81: 82: /* 83: * Allocate a contiguous buffer for DMA IO. Called from if_ubainit(). 84: * TODO: fix net device drivers to handle scatter/gather to mbufs 85: * on their own; thus avoiding the copy to/from this area. 86: */ 87: u_int 88: m_ioget(size) 89: u_int size; /* Number of bytes to allocate */ 90: { 91: memaddr base; 92: u_int csize; 93: 94: csize = btoc(size); /* size in clicks */ 95: size = ctob(csize); /* round up byte size */ 96: 97: if (size > miosize) 98: return(0); 99: miosize -= size; 100: base = miobase; 101: miobase += csize; 102: return (base); 103: } 104: 105: /* 106: * Must be called at splimp. 107: */ 108: m_expand(canwait) 109: int canwait; 110: { 111: register struct domain *dp; 112: register struct protosw *pr; 113: register int tries; 114: 115: for (tries = 0;; ) { 116: #ifdef pdp11 117: if (mfree) 118: return (1); 119: #else 120: if (m_clalloc(1, MPG_MBUFS, canwait)) 121: return (1); 122: #endif 123: if (canwait == M_DONTWAIT || tries++) 124: return (0); 125: 126: /* ask protocols to free space */ 127: for (dp = domains; dp; dp = dp->dom_next) 128: for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; 129: pr++) 130: if (pr->pr_drain) 131: (*pr->pr_drain)(); 132: mbstat.m_drain++; 133: } 134: } 135: 136: /* NEED SOME WAY TO RELEASE SPACE */ 137: 138: /* 139: * Space allocation routines. 140: * These are also available as macros 141: * for critical paths. 142: */ 143: struct mbuf * 144: m_get(canwait, type) 145: int canwait, type; 146: { 147: register struct mbuf *m; 148: 149: MGET(m, canwait, type); 150: return (m); 151: } 152: 153: struct mbuf * 154: m_getclr(canwait, type) 155: int canwait, type; 156: { 157: register struct mbuf *m; 158: 159: MGET(m, canwait, type); 160: if (m == 0) 161: return (0); 162: bzero(mtod(m, caddr_t), MLEN); 163: return (m); 164: } 165: 166: struct mbuf * 167: m_free(m) 168: struct mbuf *m; 169: { 170: register struct mbuf *n; 171: 172: MFREE(m, n); 173: return (n); 174: } 175: 176: /* 177: * Get more mbufs; called from MGET macro if mfree list is empty. 178: * Must be called at splimp. 179: */ 180: /*ARGSUSED*/ 181: struct mbuf * 182: m_more(canwait, type) 183: int canwait, type; 184: { 185: register struct mbuf *m; 186: 187: while (m_expand(canwait) == 0) { 188: if (canwait == M_WAIT) { 189: mbstat.m_wait++; 190: m_want++; 191: SLEEP((caddr_t)&mfree, PZERO - 1); 192: } else { 193: mbstat.m_drops++; 194: return (NULL); 195: } 196: } 197: #define m_more(x,y) (panic("m_more"), (struct mbuf *)0) 198: MGET(m, canwait, type); 199: #undef m_more 200: return (m); 201: } 202: 203: m_freem(m) 204: register struct mbuf *m; 205: { 206: register struct mbuf *n; 207: register int s; 208: 209: if (m == NULL) 210: return; 211: s = splimp(); 212: do { 213: MFREE(m, n); 214: } while (m = n); 215: splx(s); 216: } 217: 218: /* 219: * Mbuffer utility routines. 220: */ 221: 222: /* 223: * Make a copy of an mbuf chain starting "off" bytes from the beginning, 224: * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. 225: * Should get M_WAIT/M_DONTWAIT from caller. 226: */ 227: struct mbuf * 228: m_copy(m, off, len) 229: register struct mbuf *m; 230: int off; 231: register int len; 232: { 233: register struct mbuf *n, **np; 234: struct mbuf *top, *p; 235: 236: if (len == 0) 237: return (0); 238: if (off < 0 || len < 0) 239: panic("m_copy"); 240: while (off > 0) { 241: if (m == 0) 242: panic("m_copy"); 243: if (off < m->m_len) 244: break; 245: off -= m->m_len; 246: m = m->m_next; 247: } 248: np = ⊤ 249: top = 0; 250: while (len > 0) { 251: if (m == 0) { 252: if (len != M_COPYALL) 253: panic("m_copy"); 254: break; 255: } 256: MGET(n, M_DONTWAIT, m->m_type); 257: *np = n; 258: if (n == 0) 259: goto nospace; 260: n->m_len = MIN(len, m->m_len - off); 261: if (m->m_off > MMAXOFF) { 262: p = mtod(m, struct mbuf *); 263: n->m_off = ((int)p - (int)n) + off; 264: mclrefcnt[mtocl(p)]++; 265: } else 266: bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), 267: (unsigned)n->m_len); 268: if (len != M_COPYALL) 269: len -= n->m_len; 270: off = 0; 271: m = m->m_next; 272: np = &n->m_next; 273: } 274: return (top); 275: nospace: 276: m_freem(top); 277: return (0); 278: } 279: 280: m_cat(m, n) 281: register struct mbuf *m, *n; 282: { 283: while (m->m_next) 284: m = m->m_next; 285: while (n) { 286: if (m->m_off >= MMAXOFF || 287: m->m_off + m->m_len + n->m_len > MMAXOFF) { 288: /* just join the two chains */ 289: m->m_next = n; 290: return; 291: } 292: /* splat the data from one into the other */ 293: bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, 294: (u_int)n->m_len); 295: m->m_len += n->m_len; 296: n = m_free(n); 297: } 298: } 299: 300: m_adj(mp, len) 301: struct mbuf *mp; 302: register int len; 303: { 304: register struct mbuf *m; 305: register count; 306: 307: if ((m = mp) == NULL) 308: return; 309: if (len >= 0) { 310: while (m != NULL && len > 0) { 311: if (m->m_len <= len) { 312: len -= m->m_len; 313: m->m_len = 0; 314: m = m->m_next; 315: } else { 316: m->m_len -= len; 317: m->m_off += len; 318: break; 319: } 320: } 321: } else { 322: /* 323: * Trim from tail. Scan the mbuf chain, 324: * calculating its length and finding the last mbuf. 325: * If the adjustment only affects this mbuf, then just 326: * adjust and return. Otherwise, rescan and truncate 327: * after the remaining size. 328: */ 329: len = -len; 330: count = 0; 331: for (;;) { 332: count += m->m_len; 333: if (m->m_next == (struct mbuf *)0) 334: break; 335: m = m->m_next; 336: } 337: if (m->m_len >= len) { 338: m->m_len -= len; 339: return; 340: } 341: count -= len; 342: /* 343: * Correct length for chain is "count". 344: * Find the mbuf with last data, adjust its length, 345: * and toss data from remaining mbufs on chain. 346: */ 347: for (m = mp; m; m = m->m_next) { 348: if (m->m_len >= count) { 349: m->m_len = count; 350: break; 351: } 352: count -= m->m_len; 353: } 354: while (m = m->m_next) 355: m->m_len = 0; 356: } 357: } 358: 359: /* 360: * Rearange an mbuf chain so that len bytes are contiguous 361: * and in the data area of an mbuf (so that mtod and dtom 362: * will work for a structure of size len). Returns the resulting 363: * mbuf chain on success, frees it and returns null on failure. 364: * If there is room, it will add up to MPULL_EXTRA bytes to the 365: * contiguous region in an attempt to avoid being called next time. 366: */ 367: struct mbuf * 368: m_pullup(n, len) 369: register struct mbuf *n; 370: int len; 371: { 372: register struct mbuf *m; 373: register int count; 374: int space; 375: 376: if (n->m_off + len <= MMAXOFF && n->m_next) { 377: m = n; 378: n = n->m_next; 379: len -= m->m_len; 380: } else { 381: if (len > MLEN) 382: goto bad; 383: MGET(m, M_DONTWAIT, n->m_type); 384: if (m == 0) 385: goto bad; 386: m->m_len = 0; 387: } 388: space = MMAXOFF - m->m_off; 389: do { 390: count = MIN(MIN(space - m->m_len, len + MPULL_EXTRA), n->m_len); 391: bcopy(mtod(n, caddr_t), mtod(m, caddr_t)+m->m_len, 392: (unsigned)count); 393: len -= count; 394: m->m_len += count; 395: n->m_len -= count; 396: if (n->m_len) 397: n->m_off += count; 398: else 399: n = m_free(n); 400: } while (len > 0 && n); 401: if (len > 0) { 402: (void) m_free(m); 403: goto bad; 404: } 405: m->m_next = n; 406: return (m); 407: bad: 408: m_freem(n); 409: return (0); 410: } 411: #endif