Annotation of XNU/iokit/Families/IONetworking/IOMBufMemoryCursor.cpp, revision 1.1.1.1

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__ */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.