|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* IOMBufMemoryCursor.cpp created by gvdl on 1999-1-20 */ ! 23: ! 24: #include <sys/cdefs.h> ! 25: ! 26: __BEGIN_DECLS ! 27: #include <IOKit/assert.h> ! 28: ! 29: #include <sys/param.h> ! 30: #include <sys/mbuf.h> ! 31: #include <architecture/byte_order.h> ! 32: __END_DECLS ! 33: ! 34: #include <IOKit/network/IOMBufMemoryCursor.h> ! 35: #include <IOKit/IOLib.h> ! 36: ! 37: #ifndef MIN ! 38: #define MIN(a,b) (((a)<(b))?(a):(b)) ! 39: #endif /* MIN */ ! 40: ! 41: #define next_page(x) trunc_page(x + PAGE_SIZE) ! 42: ! 43: /* Define the meta class stuff for the entire file here */ ! 44: OSDefineMetaClass(IOMBufMemoryCursor, IOMemoryCursor) ! 45: OSDefineAbstractStructors(IOMBufMemoryCursor, IOMemoryCursor) ! 46: ! 47: OSDefineMetaClassAndStructors(IOMBufNaturalMemoryCursor, IOMBufMemoryCursor) ! 48: OSDefineMetaClassAndStructors(IOMBufBigMemoryCursor, IOMBufMemoryCursor) ! 49: OSDefineMetaClassAndStructors(IOMBufLittleMemoryCursor, IOMBufMemoryCursor) ! 50: ! 51: #ifdef __ppc__ ! 52: OSDefineMetaClassAndStructors(IOMBufDBDMAMemoryCursor, IOMBufMemoryCursor) ! 53: #endif /* __ppc__ */ ! 54: ! 55: /*********************** class IOMBufMemoryCursor ***********************/ ! 56: #define super IOMemoryCursor ! 57: ! 58: bool IOMBufMemoryCursor::initWithSpecification(OutputSegmentFunc outSeg, ! 59: UInt maxSegmentSize, ! 60: UInt maxTransferSize, ! 61: UInt align) ! 62: { ! 63: return false; ! 64: } ! 65: ! 66: bool IOMBufMemoryCursor::initWithSpecification(OutputSegmentFunc inOutSeg, ! 67: UInt inMaxSegmentSize, ! 68: UInt inMaxNumSegments) ! 69: { ! 70: if (!super::initWithSpecification(inOutSeg, inMaxSegmentSize, 0, 1)) ! 71: return false; ! 72: ! 73: #if 0 ! 74: // It is too confusing to force the max segment size to be at least ! 75: // as large as a page. Most Enet devices only have 11-12 bit fields, ! 76: // enough for a full size frame, and also the PAGE_SIZE parameter ! 77: // may be architecture dependent. ! 78: ! 79: assert(inMaxSegmentSize >= PAGE_SIZE); ! 80: if (inMaxSegmentSize < PAGE_SIZE) ! 81: return false; ! 82: #else ! 83: if (!inMaxSegmentSize) ! 84: return false; ! 85: #endif ! 86: ! 87: maxSegmentSize = MIN(maxSegmentSize, PAGE_SIZE); ! 88: maxNumSegments = inMaxNumSegments; ! 89: coalesceCount = 0; ! 90: ! 91: return true; ! 92: } ! 93: ! 94: // ! 95: // Copy the src packet into the destination packet. The amount to copy is ! 96: // determined by the dstm->m_len, which is setup by analyseSegments, see below. ! 97: // The source mbuf is not freed nor modified. ! 98: // ! 99: #define BCOPY(s, d, l) do { bcopy((void *) s, (void *) d, l); } while(0) ! 100: ! 101: static inline void coalesceSegments(struct mbuf *srcm, struct mbuf *dstm) ! 102: { ! 103: vm_offset_t src, dst; ! 104: SInt srcLen, dstLen; ! 105: struct mbuf *temp; ! 106: ! 107: srcLen = srcm->m_len; ! 108: src = mtod(srcm, vm_offset_t); ! 109: ! 110: dstLen = dstm->m_len; ! 111: dst = mtod(dstm, vm_offset_t); ! 112: ! 113: for (;;) { ! 114: if (srcLen < dstLen) { ! 115: ! 116: // Copy remainder of src mbuf to current dst. ! 117: BCOPY(src, dst, srcLen); ! 118: dst += srcLen; ! 119: dstLen -= srcLen; ! 120: ! 121: // Move on to the next source mbuf. ! 122: temp = srcm->m_next; assert(temp); ! 123: srcm = temp; ! 124: ! 125: srcLen = srcm->m_len; ! 126: src = mtod(srcm, vm_offset_t); ! 127: } ! 128: else if (srcLen > dstLen) { ! 129: ! 130: // Copy some of src mbuf to remaining space in dst mbuf. ! 131: BCOPY(src, dst, dstLen); ! 132: src += dstLen; ! 133: srcLen -= dstLen; ! 134: ! 135: // Move on to the next destination mbuf. ! 136: temp = dstm->m_next; assert(temp); ! 137: dstm = temp; ! 138: ! 139: dstLen = dstm->m_len; ! 140: dst = mtod(dstm, vm_offset_t); ! 141: } ! 142: else { /* (srcLen == dstLen) */ ! 143: ! 144: // copy remainder of src into remaining space of current dst ! 145: BCOPY(src, dst, srcLen); ! 146: ! 147: // Free current mbuf and move the current onto the next ! 148: srcm = srcm->m_next; ! 149: ! 150: // Do we have any data left to copy? ! 151: if (!dstm->m_next) ! 152: break; ! 153: dstm = dstm->m_next; ! 154: ! 155: assert(srcm); ! 156: dstLen = dstm->m_len; ! 157: dst = mtod(dstm, vm_offset_t); ! 158: srcLen = srcm->m_len; ! 159: src = mtod(srcm, vm_offset_t); ! 160: } ! 161: } ! 162: } ! 163: ! 164: static const UInt kMBufDataCacheSize = 16; ! 165: ! 166: static inline bool analyseSegments( ! 167: struct mbuf *packet, /* input packet mbuf */ ! 168: const UInt mbufsInCache, /* number of entries in segsPerMBuf[] */ ! 169: const UInt segsPerMBuf[], /* segments required per mbuf */ ! 170: SInt numSegs, /* total number of segments */ ! 171: const UInt maxSegs) /* max controller segments per mbuf */ ! 172: { ! 173: struct mbuf *newPacket; // output mbuf chain. ! 174: struct mbuf *out; // current output mbuf link. ! 175: SInt outSize; // size of current output mbuf link. ! 176: SInt outSegs; // segments for current output mbuf link. ! 177: SInt doneSegs; // segments for output mbuf chain. ! 178: SInt outLen; // remaining length of input buffer. ! 179: ! 180: struct mbuf *in = packet; // save the original input packet pointer. ! 181: UInt inIndex = 0; ! 182: ! 183: // Allocate a mbuf (non header mbuf) to begin the output mbuf chain. ! 184: // ! 185: MGET(newPacket, M_DONTWAIT, MT_DATA); ! 186: if (!newPacket) { ! 187: IOLog("analyseSegments: MGET() 1 error\n"); ! 188: return false; ! 189: } ! 190: ! 191: /* Initialise outgoing packet controls */ ! 192: out = newPacket; ! 193: outSize = MLEN; ! 194: doneSegs = outSegs = outLen = 0; ! 195: ! 196: // numSegs stores the delta between the total and the max. For each ! 197: // input mbuf consumed, we decrement numSegs. ! 198: // ! 199: numSegs -= maxSegs; ! 200: ! 201: // Loop through the input packet mbuf 'in' and construct a new mbuf chain ! 202: // large enough to make (numSegs + doneSegs + outSegs) less than or ! 203: // equal to zero. ! 204: // ! 205: do { ! 206: vm_offset_t vmo; ! 207: ! 208: outLen += in->m_len; ! 209: ! 210: while (outLen > outSize) { ! 211: // Oh dear the current outgoing length is too big. ! 212: if (outSize != MCLBYTES) { ! 213: // Current mbuf is not yet a cluster so promote, then ! 214: // check for error. ! 215: ! 216: MCLGET(out, M_DONTWAIT); ! 217: if ( !(out->m_flags & M_EXT) ) { ! 218: IOLog("analyseSegments: MCLGET() error\n"); ! 219: goto bombAnalysis; ! 220: } ! 221: ! 222: outSize = MCLBYTES; ! 223: ! 224: continue; ! 225: } ! 226: ! 227: vmo = mtod(out, vm_offset_t); ! 228: out->m_len = MCLBYTES; /* Fill in target copy size */ ! 229: doneSegs += (round_page(vmo + MCLBYTES) - trunc_page(vmo)) ! 230: / PAGE_SIZE; ! 231: ! 232: // If the number of segments of the output chain, plus ! 233: // the segment for the mbuf we are about to allocate is greater ! 234: // than maxSegs, then abort. ! 235: // ! 236: if (doneSegs + 1 > (int) maxSegs) { ! 237: IOLog("analyseSegments: maxSegs limit 1 reached! %d %d\n", ! 238: doneSegs, maxSegs); ! 239: goto bombAnalysis; ! 240: } ! 241: ! 242: MGET(out->m_next, M_DONTWAIT, MT_DATA); ! 243: if (!out->m_next) { ! 244: IOLog("analyseSegments: MGET() error\n"); ! 245: goto bombAnalysis; ! 246: } ! 247: ! 248: out = out->m_next; ! 249: outSize = MLEN; ! 250: outLen -= MCLBYTES; ! 251: } ! 252: ! 253: // Compute number of segment in current outgoing mbuf. ! 254: vmo = mtod(out, vm_offset_t); ! 255: outSegs = (round_page(vmo + outLen) - trunc_page(vmo)) / PAGE_SIZE; ! 256: if (doneSegs + outSegs > (int) maxSegs) { ! 257: IOLog("analyseSegments: maxSegs limit 2 reached! %d %d %d\n", ! 258: doneSegs, outSegs, maxSegs); ! 259: goto bombAnalysis; ! 260: } ! 261: ! 262: // Get the number of segments in the current inbuf ! 263: if (inIndex < mbufsInCache) ! 264: numSegs -= segsPerMBuf[inIndex]; // Yeah, in cache ! 265: else { ! 266: // Hmm, we have to recompute from scratch. Copy code from genPhys. ! 267: int thisLen = 0, mbufLen; ! 268: ! 269: vmo = mtod(in, vm_offset_t); ! 270: for (mbufLen = in->m_len; mbufLen; mbufLen -= thisLen) { ! 271: thisLen = MIN(next_page(vmo), vmo + mbufLen) - vmo; ! 272: vmo += thisLen; ! 273: numSegs--; ! 274: } ! 275: } ! 276: ! 277: // Walk the incoming buffer on one. ! 278: in = in->m_next; ! 279: inIndex++; ! 280: ! 281: // continue looping until the total number of segments has dropped ! 282: // to an acceptable level, or if we ran out of mbuf links. ! 283: ! 284: } while (in && ((numSegs + doneSegs + outSegs) > 0)); ! 285: ! 286: if ( (int) (numSegs + doneSegs + outSegs) <= 0) { // success ! 287: ! 288: out->m_len = outLen; // Set last mbuf with the remaining length. ! 289: ! 290: // The amount to copy is determine by the segment length in each ! 291: // mbuf linked to newPacket. The sum can be smaller than ! 292: // packet->pkthdr.len; ! 293: // ! 294: coalesceSegments(packet, newPacket); ! 295: ! 296: // Copy complete. ! 297: ! 298: // If 'in' is non zero, then it means that we only need to copy part ! 299: // of the input packet, beginning at the start. The mbuf chain ! 300: // beginning at 'in' must be preserved and linked to the new ! 301: // output packet chain. Everything before 'in', except for the ! 302: // header mbuf can be freed. ! 303: // ! 304: struct mbuf *m = packet->m_next; ! 305: while (m != in) ! 306: m = m_free(m); ! 307: ! 308: // The initial header mbuf is preserved, its length set to zero, and ! 309: // linked to the new packet chain. ! 310: ! 311: packet->m_len = 0; ! 312: packet->m_next = newPacket; ! 313: newPacket->m_next = in; ! 314: ! 315: return true; ! 316: } ! 317: ! 318: bombAnalysis: ! 319: ! 320: m_freem(newPacket); ! 321: return false; ! 322: } ! 323: ! 324: UInt IOMBufMemoryCursor::genPhysicalSegments(struct mbuf *packet, void *vector, ! 325: UInt maxSegs, bool doCoalesce) ! 326: { ! 327: bool doneCoalesce = false; ! 328: ! 329: if (!packet || !(packet->m_flags & M_PKTHDR)) ! 330: return 0; ! 331: ! 332: if (!maxSegs) ! 333: maxSegs = maxNumSegments; ! 334: if (!maxSegs) ! 335: return 0; ! 336: ! 337: if ( packet->m_next == 0 ) ! 338: { ! 339: vm_offset_t src; ! 340: struct IOPhysicalSegment physSeg; ! 341: /* ! 342: * the packet consists of only 1 mbuf ! 343: * so if the data buffer doesn't span a page boundary ! 344: * we can take the simple way out ! 345: */ ! 346: src = mtod(packet, vm_offset_t); ! 347: ! 348: if ( trunc_page(src) == trunc_page(src+packet->m_len-1) ) ! 349: { ! 350: if ((physSeg.location = ! 351: (IOPhysicalAddress)mcl_to_paddr((char *)src)) == 0) ! 352: physSeg.location = (IOPhysicalAddress)pmap_extract(kernel_pmap, src); ! 353: if (!physSeg.location) ! 354: return 0; ! 355: physSeg.length = packet->m_len; ! 356: (*outSeg)(physSeg, vector, 0); ! 357: ! 358: return 1; ! 359: } ! 360: } ! 361: ! 362: if ( doCoalesce == true && maxSegs == 1 ) ! 363: { ! 364: vm_offset_t src; ! 365: vm_offset_t dst; ! 366: struct mbuf *m; ! 367: struct mbuf *mnext; ! 368: struct mbuf *out; ! 369: UInt len = 0; ! 370: struct IOPhysicalSegment physSeg; ! 371: ! 372: m = packet; ! 373: ! 374: MGET(out, M_DONTWAIT, MT_DATA); ! 375: if ( out == 0 ) return 0; ! 376: ! 377: MCLGET(out, M_DONTWAIT); ! 378: if ( !(out->m_flags & M_EXT) ) ! 379: { ! 380: m_free( out ); ! 381: return 0; ! 382: } ! 383: dst = mtod(out, vm_offset_t); ! 384: ! 385: do ! 386: { ! 387: src = mtod(m, vm_offset_t); ! 388: BCOPY( src, dst, m->m_len ); ! 389: dst += m->m_len; ! 390: len += m->m_len; ! 391: } while ( (m = m->m_next) != 0 ); ! 392: ! 393: out->m_len = len; ! 394: ! 395: dst = mtod(out, vm_offset_t); ! 396: if ((physSeg.location = (IOPhysicalAddress)mcl_to_paddr((char *)dst)) == 0) ! 397: physSeg.location = (IOPhysicalAddress)pmap_extract(kernel_pmap, dst); ! 398: if (!physSeg.location) ! 399: return 0; ! 400: physSeg.length = out->m_len; ! 401: (*outSeg)(physSeg, vector, 0); ! 402: ! 403: m = packet->m_next; ! 404: while (m != 0) ! 405: { ! 406: mnext = m->m_next; ! 407: m_free(m); ! 408: m = mnext; ! 409: } ! 410: ! 411: // The initial header mbuf is preserved, its length set to zero, and ! 412: // linked to the new packet chain. ! 413: ! 414: packet->m_len = 0; ! 415: packet->m_next = out; ! 416: out->m_next = 0; ! 417: ! 418: return 1; ! 419: } ! 420: ! 421: ! 422: // ! 423: // Iterate over the mbuf, translating segments were allowed. When we ! 424: // are not allowed to translate segments then accumulate segment ! 425: // statistics up to kMBufDataCacheSize of mbufs. Finally ! 426: // if we overflow our cache just count how many segments this ! 427: // packet represents. ! 428: // ! 429: UInt segsPerMBuf[kMBufDataCacheSize]; ! 430: ! 431: tryAgain: ! 432: UInt curMBufIndex = 0; ! 433: UInt curSegIndex = 0; ! 434: UInt lastSegCount = 0; ! 435: struct mbuf *m = packet; ! 436: ! 437: // For each mbuf in incoming packet. ! 438: do { ! 439: vm_size_t mbufLen, thisLen = 0; ! 440: vm_offset_t src; ! 441: ! 442: // Step through each segment in the current mbuf ! 443: for (mbufLen = m->m_len, src = mtod(m, vm_offset_t); ! 444: mbufLen; ! 445: src += thisLen, mbufLen -= thisLen) ! 446: { ! 447: // If maxSegmentSize is atleast PAGE_SIZE, then ! 448: // thisLen = MIN(next_page(src), src + mbufLen) - src; ! 449: ! 450: thisLen = MIN(mbufLen, maxSegmentSize); ! 451: thisLen = MIN(next_page(src), src + thisLen) - src; ! 452: ! 453: // If room left then find the current segment addr and output ! 454: if (curSegIndex < maxSegs) { ! 455: struct IOPhysicalSegment physSeg; ! 456: ! 457: if ((physSeg.location = ! 458: (IOPhysicalAddress)mcl_to_paddr((char *)src)) == 0) ! 459: physSeg.location = (IOPhysicalAddress)pmap_extract(kernel_pmap, src); ! 460: if (!physSeg.location) ! 461: return 0; ! 462: physSeg.length = thisLen; ! 463: (*outSeg)(physSeg, vector, curSegIndex); ! 464: } ! 465: // Count segments if we are coalescing. ! 466: curSegIndex++; ! 467: } ! 468: ! 469: // Cache the segment count data if room is available. ! 470: if (curMBufIndex < kMBufDataCacheSize) { ! 471: segsPerMBuf[curMBufIndex] = curSegIndex - lastSegCount; ! 472: lastSegCount = curSegIndex; ! 473: } ! 474: ! 475: // Move on to next imcoming mbuf ! 476: curMBufIndex++; ! 477: m = m->m_next; ! 478: } while (m); ! 479: ! 480: // If we finished cleanly return number of segments found ! 481: if (curSegIndex <= maxSegs) ! 482: return curSegIndex; ! 483: if (!doCoalesce) ! 484: return 0; // if !coalescing we've got a problem. ! 485: ! 486: ! 487: // If we are coalescing and it is possible then attempt coalesce, ! 488: if (!doneCoalesce ! 489: && (UInt) packet->m_pkthdr.len <= maxSegs * maxSegmentSize) { ! 490: // Hmm, we have to do some coalescing. ! 491: bool analysisRet; ! 492: ! 493: analysisRet = analyseSegments(packet, ! 494: MIN(curMBufIndex, kMBufDataCacheSize), ! 495: segsPerMBuf, ! 496: curSegIndex, maxSegs); ! 497: if (analysisRet) { ! 498: doneCoalesce = true; ! 499: coalesceCount++; ! 500: goto tryAgain; ! 501: } ! 502: } ! 503: ! 504: assert(!doneCoalesce); // Problem in Coalesce code. ! 505: packetTooBigErrors++; ! 506: return 0; ! 507: } ! 508: ! 509: /********************* class IOMBufBigMemoryCursor **********************/ ! 510: IOMBufBigMemoryCursor * ! 511: IOMBufBigMemoryCursor::withSpecification(UInt maxSegSize, UInt maxNumSegs) ! 512: { ! 513: IOMBufBigMemoryCursor *me = new IOMBufBigMemoryCursor; ! 514: ! 515: if (me && !me->initWithSpecification(&bigOutputSegment, ! 516: maxSegSize, maxNumSegs)) { ! 517: me->release(); ! 518: return 0; ! 519: } ! 520: ! 521: return me; ! 522: } ! 523: ! 524: ! 525: /******************* class IOMBufNaturalMemoryCursor ********************/ ! 526: IOMBufNaturalMemoryCursor * ! 527: IOMBufNaturalMemoryCursor::withSpecification(UInt maxSegSize, UInt maxNumSegs) ! 528: { ! 529: IOMBufNaturalMemoryCursor *me = new IOMBufNaturalMemoryCursor; ! 530: ! 531: if (me && !me->initWithSpecification(&naturalOutputSegment, ! 532: maxSegSize, maxNumSegs)) { ! 533: me->release(); ! 534: return 0; ! 535: } ! 536: ! 537: return me; ! 538: } ! 539: ! 540: ! 541: /******************** class IOMBufLittleMemoryCursor ********************/ ! 542: IOMBufLittleMemoryCursor * ! 543: IOMBufLittleMemoryCursor::withSpecification(UInt maxSegSize, UInt maxNumSegs) ! 544: { ! 545: IOMBufLittleMemoryCursor *me = new IOMBufLittleMemoryCursor; ! 546: ! 547: if (me && !me->initWithSpecification(&littleOutputSegment, ! 548: maxSegSize, maxNumSegs)) { ! 549: me->release(); ! 550: return 0; ! 551: } ! 552: ! 553: return me; ! 554: } ! 555: ! 556: ! 557: /******************** class IOMBufDBDMAMemoryCursor *********************/ ! 558: #ifdef __ppc__ ! 559: ! 560: IOMBufDBDMAMemoryCursor * ! 561: IOMBufDBDMAMemoryCursor::withSpecification(UInt maxSegSize, UInt maxNumSegs) ! 562: { ! 563: IOMBufDBDMAMemoryCursor *me = new IOMBufDBDMAMemoryCursor; ! 564: ! 565: if (me && !me->initWithSpecification(&dbdmaOutputSegment, ! 566: maxSegSize, maxNumSegs)) { ! 567: me->release(); ! 568: return 0; ! 569: } ! 570: ! 571: return me; ! 572: } ! 573: #endif /* __ppc__ */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.