Annotation of XNU/iokit/Families/IONetworking/IOMBufMemoryCursor.cpp, revision 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.