1/*
2 * Copyright (c) 1998-2008 Apple 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>
31struct mbuf * m_getpackets(int num_needed, int num_with_pkthdrs, int how);
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#if 0
44#define ERROR_LOG(args...)  IOLog(args)
45#else
46#define ERROR_LOG(args...)
47#endif
48
49/* Define the meta class stuff for the entire file here */
50OSDefineMetaClassAndStructors(IOMbufMemoryCursor, IOMemoryCursor)
51OSMetaClassDefineReservedUnused( IOMbufMemoryCursor,  0);
52OSMetaClassDefineReservedUnused( IOMbufMemoryCursor,  1);
53OSMetaClassDefineReservedUnused( IOMbufMemoryCursor,  2);
54OSMetaClassDefineReservedUnused( IOMbufMemoryCursor,  3);
55
56OSDefineMetaClassAndStructors(IOMbufNaturalMemoryCursor, IOMbufMemoryCursor)
57OSDefineMetaClassAndStructors(IOMbufBigMemoryCursor, IOMbufMemoryCursor)
58OSDefineMetaClassAndStructors(IOMbufLittleMemoryCursor, IOMbufMemoryCursor)
59
60#ifdef __ppc__
61OSDefineMetaClassAndStructors(IOMbufDBDMAMemoryCursor, IOMbufMemoryCursor)
62#endif /* __ppc__ */
63
64/*********************** class IOMbufMemoryCursor ***********************/
65#define super IOMemoryCursor
66
67bool IOMbufMemoryCursor::initWithSpecification(OutputSegmentFunc outSeg,
68                                               UInt32 maxSegmentSize,
69                                               UInt32 maxTransferSize,
70                                               UInt32 align)
71{
72    return false;
73}
74
75bool IOMbufMemoryCursor::initWithSpecification(OutputSegmentFunc inOutSeg,
76                                               UInt32 inMaxSegmentSize,
77                                               UInt32 inMaxNumSegments)
78{
79    if (!super::initWithSpecification(inOutSeg, inMaxSegmentSize, 0, 1))
80        return false;
81
82#if 0
83    // It is too confusing to force the max segment size to be at least
84    // as large as a page. Most Enet devices only have 11-12 bit fields,
85    // enough for a full size frame, and also the PAGE_SIZE parameter
86    // may be architecture dependent.
87
88    assert(inMaxSegmentSize >= PAGE_SIZE);
89    if (inMaxSegmentSize < PAGE_SIZE)
90        return false;
91#else
92    if (!inMaxSegmentSize)
93        return false;
94#endif
95
96    maxSegmentSize = MIN(maxSegmentSize, PAGE_SIZE);
97    maxNumSegments = inMaxNumSegments;
98    coalesceCount = 0;
99
100    return true;
101}
102
103//
104// Copy the src packet into the destination packet. The amount to copy is
105// determined by the dstm->m_len, which is setup by analyseSegments, see below.
106// Mbufs(except for the head) from the source are freed as they are copied and the
107// remaining uncopied mbufs are attached to the end of the dest chain.
108#define BCOPY(s, d, l) do { bcopy((void *) s, (void *) d, l); } while(0)
109
110static inline void coalesceSegments(mbuf_t srcm, mbuf_t dstm)
111{
112    uintptr_t src, dst;
113    SInt32 srcLen, dstLen;
114    mbuf_t temp;
115    mbuf_t head = srcm;
116
117    srcLen = mbuf_len( srcm );
118    src = (uintptr_t) mbuf_data(srcm);
119
120    dstLen = mbuf_len( dstm );
121    dst = (uintptr_t) mbuf_data( dstm );
122
123    for (;;) {
124        if (srcLen < dstLen) {
125
126            // Copy remainder of src mbuf to current dst.
127            BCOPY(src, dst, srcLen);
128            dst += srcLen;
129            dstLen -= srcLen;
130
131            // Move on to the next source mbuf.
132            temp = mbuf_next( srcm ); assert(temp);
133			if(srcm != head)
134				mbuf_free(srcm);
135            srcm = temp;
136
137            srcLen = mbuf_len( srcm );
138            src = (uintptr_t)mbuf_data(srcm);
139        }
140        else if (srcLen > dstLen) {
141
142            // Copy some of src mbuf to remaining space in dst mbuf.
143            BCOPY(src, dst, dstLen);
144            src += dstLen;
145            srcLen -= dstLen;
146
147            // Move on to the next destination mbuf.
148            temp = mbuf_next( dstm ); assert(temp);
149            dstm = temp;
150
151            dstLen = mbuf_len( dstm );
152            dst = (uintptr_t)mbuf_data( dstm );
153        }
154        else {  /* (srcLen == dstLen) */
155
156            // copy remainder of src into remaining space of current dst
157            BCOPY(src, dst, srcLen);
158
159            // Free current mbuf and move the current onto the next
160            temp = mbuf_next( srcm );
161			if(srcm != head)
162				mbuf_free(srcm);
163			srcm = temp;
164
165            // Do we have any more dest buffers to copy to?
166            if (! mbuf_next ( dstm ))
167			{
168				// nope- hook the remainder of source chain to end of dest chain
169				mbuf_setnext(dstm, srcm);
170                break;
171			}
172            dstm = mbuf_next ( dstm );
173
174            assert(srcm);
175            dstLen = mbuf_len ( dstm );
176            dst = (uintptr_t)mbuf_data( dstm );
177            srcLen = mbuf_len( srcm );
178            src = (uintptr_t)mbuf_data( srcm );
179        }
180    }
181}
182
183static const UInt32 kMBufDataCacheSize = 16;
184
185static inline bool analyseSegments(
186    mbuf_t packet,        /* input packet mbuf */
187    const UInt32 mbufsInCache,  /* number of entries in segsPerMBuf[] */
188    const UInt32 segsPerMBuf[], /* segments required per mbuf */
189    SInt32 numSegs,               /* total number of segments */
190    const UInt32 maxSegs)       /* max controller segments per mbuf */
191{
192    mbuf_t newPacket;     // output mbuf chain.
193    mbuf_t out;           // current output mbuf link.
194    SInt32 outSize;               // size of current output mbuf link.
195    SInt32 outSegs;               // segments for current output mbuf link.
196    SInt32 doneSegs;              // segments for output mbuf chain.
197    SInt32 outLen;                // remaining length of input buffer.
198
199    mbuf_t in = packet;   // save the original input packet pointer.
200    UInt32 inIndex = 0;
201    const uint32_t c_mlen = mbuf_get_mlen();
202
203    // Allocate a mbuf (non header mbuf) to begin the output mbuf chain.
204
205    if(mbuf_get(MBUF_DONTWAIT, MT_DATA, &newPacket))
206    {
207        ERROR_LOG("analyseSegments: MGET() 1 error\n");
208        return false;
209    }
210
211    /* Initialise outgoing packet controls */
212    out = newPacket;
213    outSize = c_mlen;
214    doneSegs = outSegs = outLen = 0;
215
216    // numSegs stores the delta between the total and the max. For each
217    // input mbuf consumed, we decrement numSegs.
218    //
219    numSegs -= maxSegs;
220
221    // Loop through the input packet mbuf 'in' and construct a new mbuf chain
222    // large enough to make (numSegs + doneSegs + outSegs) less than or
223    // equal to zero.
224    //
225    do {
226        uintptr_t vmo;
227
228        outLen += mbuf_len(in);
229
230        while (outLen > outSize) {
231            // Oh dear the current outgoing length is too big.
232            if (outSize != MCLBYTES) {
233                // Current mbuf is not yet a cluster so promote, then
234                // check for error.
235
236                if(mbuf_mclget(MBUF_DONTWAIT, MT_DATA, &out) || !(mbuf_flags(out) & MBUF_EXT) )
237				{
238                    ERROR_LOG("analyseSegments: MCLGET() error\n");
239                    goto bombAnalysis;
240                }
241
242                outSize = MCLBYTES;
243
244                continue;
245            }
246
247            vmo = (uintptr_t)mbuf_data(out);
248            mbuf_setlen(out, MCLBYTES);  /* Fill in target copy size */
249            doneSegs += (round_page(vmo + MCLBYTES) - trunc_page(vmo))
250                     /   PAGE_SIZE;
251
252            // If the number of segments of the output chain, plus
253            // the segment for the mbuf we are about to allocate is greater
254            // than maxSegs, then abort.
255            //
256            if (doneSegs + 1 > (int) maxSegs) {
257                ERROR_LOG("analyseSegments: maxSegs limit 1 reached! %ld %ld\n",
258                          doneSegs, maxSegs);
259                goto bombAnalysis;
260            }
261
262            mbuf_t tempmbuf;
263			if(mbuf_get(MBUF_DONTWAIT, MT_DATA, &tempmbuf))
264            {
265                ERROR_LOG("analyseSegments: MGET() error\n");
266                goto bombAnalysis;
267            }
268            mbuf_setnext(out, tempmbuf);
269            out = tempmbuf;
270            outSize = c_mlen;
271            outLen -= MCLBYTES;
272        }
273
274        // Compute number of segment in current outgoing mbuf.
275        vmo = (uintptr_t)mbuf_data(out);
276        outSegs = (round_page(vmo + outLen) - trunc_page(vmo)) / PAGE_SIZE;
277        if (doneSegs + outSegs > (int) maxSegs) {
278            ERROR_LOG("analyseSegments: maxSegs limit 2 reached! %ld %ld %ld\n",
279                      doneSegs, outSegs, maxSegs);
280            goto bombAnalysis;
281        }
282
283        // Get the number of segments in the current inbuf
284        if (inIndex < mbufsInCache)
285            numSegs -= segsPerMBuf[inIndex];    // Yeah, in cache
286        else {
287            // Hmm, we have to recompute from scratch. Copy code from genPhys.
288            int thisLen = 0, mbufLen;
289
290            vmo = (uintptr_t)mbuf_data(in);
291            for (mbufLen = mbuf_len(in); mbufLen; mbufLen -= thisLen) {
292                thisLen = MIN(next_page(vmo), vmo + mbufLen) - vmo;
293                vmo += thisLen;
294                numSegs--;
295            }
296        }
297
298        // Walk the incoming buffer on one.
299        in = mbuf_next(in);
300        inIndex++;
301
302        // continue looping until the total number of segments has dropped
303        // to an acceptable level, or if we ran out of mbuf links.
304
305    } while (in && ((numSegs + doneSegs + outSegs) > 0));
306
307    if ( (int) (numSegs + doneSegs + outSegs) <= 0) {   // success
308
309        mbuf_setlen(out, outLen);    // Set last mbuf with the remaining length.
310
311        // The amount to copy is determine by the segment length in each
312        // mbuf linked to newPacket. The sum can be smaller than
313        // packet->pkthdr.len;
314        //
315        coalesceSegments(packet, newPacket);
316
317        // The initial header mbuf is preserved, its length set to zero, and
318        // linked to the new packet chain.
319        // coalesceSegments() has already freed the mbufs that it coalesced into the newPacket chain.
320		// It also hooked the remaining chain pointed to by "in" to the end of the newPacket chain.
321		// All that remains is to set packet's len to 0 (to "free" the contents that coalesceSegments copied out)
322		// and make it the head of the new chain.
323
324        mbuf_setlen(packet , 0 );
325        mbuf_setnext(packet, newPacket);
326
327        return true;
328    }
329
330bombAnalysis:
331
332    mbuf_freem(newPacket);
333    return false;
334}
335
336UInt32 IOMbufMemoryCursor::genPhysicalSegments(mbuf_t packet, void *vector,
337                                               UInt32 maxSegs, bool doCoalesce)
338{
339    bool doneCoalesce = false;
340
341    if (!packet || !(mbuf_flags(packet) & MBUF_PKTHDR))
342        return 0;
343
344    if (!maxSegs)
345    {
346        maxSegs = maxNumSegments;
347        if (!maxSegs) return 0;
348    }
349
350    if ( mbuf_next(packet) == 0 )
351    {
352        uintptr_t               src;
353        struct IOPhysicalSegment  physSeg;
354
355        /*
356         * the packet consists of only 1 mbuf
357         * so if the data buffer doesn't span a page boundary
358         * we can take the simple way out
359         */
360        src = (uintptr_t)mbuf_data(packet);
361
362        if ( trunc_page(src) == trunc_page(src + mbuf_len(packet) - 1) )
363        {
364            physSeg.location = (IOPhysicalAddress) mbuf_data_to_physical((char *)src);
365            if ( physSeg.location )
366            {
367                physSeg.length = mbuf_len(packet);
368                (*outSeg)(physSeg, vector, 0);
369                return 1;
370            }
371
372            maxSegs = 1;
373            if ( doCoalesce == false ) return 0;
374        }
375    }
376
377    if ( doCoalesce == true && maxSegs == 1 )
378    {
379        uintptr_t               src;
380        uintptr_t               dst;
381        mbuf_t               m;
382        mbuf_t               mnext;
383        mbuf_t               out;
384        UInt32                    len = 0;
385        struct IOPhysicalSegment  physSeg;
386
387        if ( mbuf_pkthdr_len(packet) > MCLBYTES ) return 0;
388
389        m = packet;
390
391        // Allocate a non-header mbuf + cluster.
392        if (mbuf_getpacket( MBUF_DONTWAIT, &out ))
393			return 0;
394		mbuf_setflags( out, mbuf_flags( out ) & ~MBUF_PKTHDR );
395        dst = (uintptr_t)mbuf_data(out);
396
397        do
398        {
399            src = (uintptr_t)mbuf_data(m);
400            BCOPY( src, dst, mbuf_len(m) );
401            dst += mbuf_len(m);
402            len += mbuf_len(m);
403        } while ( (m = mbuf_next(m)) != 0 );
404
405        mbuf_setlen(out , len);
406
407        dst = (uintptr_t)mbuf_data(out);
408        physSeg.location = (IOPhysicalAddress) mbuf_data_to_physical((char *)dst);
409        if (!physSeg.location)
410        {
411            mbuf_free(out);
412            return 0;
413        }
414        physSeg.length = mbuf_len(out);
415        (*outSeg)(physSeg, vector, 0);
416
417        m = mbuf_next(packet);
418        while (m != 0)
419        {
420            mnext = mbuf_next(m);
421            mbuf_free(m);
422            m = mnext;
423        }
424
425        // The initial header mbuf is preserved, its length set to zero,
426        // and linked to the new packet chain.
427
428        mbuf_setlen(packet , 0);
429        mbuf_setnext(packet , out);
430        mbuf_setnext(out , 0);
431
432        return 1;
433    }
434
435    //
436    // Iterate over the mbuf, translating segments were allowed.  When we
437    // are not allowed to translate segments then accumulate segment
438    // statistics up to kMBufDataCacheSize of mbufs.  Finally
439    // if we overflow our cache just count how many segments this
440    // packet represents.
441    //
442    UInt32 segsPerMBuf[kMBufDataCacheSize];
443
444tryAgain:
445    UInt32 curMBufIndex = 0;
446    UInt32 curSegIndex  = 0;
447    UInt32 lastSegCount = 0;
448    mbuf_t m = packet;
449
450    // For each mbuf in incoming packet.
451    do {
452        vm_size_t   mbufLen, thisLen = 0;
453        uintptr_t src;
454
455        // Step through each segment in the current mbuf
456        for (mbufLen = mbuf_len(m), src = (uintptr_t)mbuf_data(m);
457             mbufLen;
458             src += thisLen, mbufLen -= thisLen)
459        {
460            // If maxSegmentSize is atleast PAGE_SIZE, then
461            // thisLen = MIN(next_page(src), src + mbufLen) - src;
462
463            thisLen = MIN(mbufLen, maxSegmentSize);
464            thisLen = MIN(next_page(src), src + thisLen) - src;
465
466            // If room left then find the current segment addr and output
467            if (curSegIndex < maxSegs) {
468                struct IOPhysicalSegment physSeg;
469
470                physSeg.location = (IOPhysicalAddress) mbuf_data_to_physical((char *)src);
471                if ( physSeg.location == 0 )
472                {
473                    return doCoalesce ?
474                           genPhysicalSegments(packet, vector, 1, true) : 0;
475                }
476                physSeg.length = thisLen;
477                (*outSeg)(physSeg, vector, curSegIndex);
478            }
479
480            // Count segments if we are coalescing.
481            curSegIndex++;
482        }
483
484        // Cache the segment count data if room is available.
485        if (curMBufIndex < kMBufDataCacheSize) {
486            segsPerMBuf[curMBufIndex] = curSegIndex - lastSegCount;
487            lastSegCount = curSegIndex;
488        }
489
490        // Move on to next imcoming mbuf
491        curMBufIndex++;
492        m = mbuf_next(m);
493    } while (m);
494
495    // If we finished cleanly return number of segments found
496    if (curSegIndex <= maxSegs)
497        return curSegIndex;
498    if (!doCoalesce)
499        return 0;   // if !coalescing we've got a problem.
500
501    // If we are coalescing and it is possible then attempt coalesce,
502    if (!doneCoalesce
503    &&  (UInt) mbuf_pkthdr_len(packet) <= maxSegs * maxSegmentSize) {
504        // Hmm, we have to do some coalescing.
505        bool analysisRet;
506
507        analysisRet = analyseSegments(packet,
508                                      MIN(curMBufIndex, kMBufDataCacheSize),
509                                      segsPerMBuf,
510                                      curSegIndex, maxSegs);
511        if (analysisRet) {
512            doneCoalesce = true;
513            coalesceCount++;
514            goto tryAgain;
515        }
516    }
517
518    assert(!doneCoalesce);  // Problem in Coalesce code.
519    packetTooBigErrors++;
520    return 0;
521}
522
523UInt32 IOMbufMemoryCursor::getAndResetCoalesceCount()
524{
525    UInt32 cnt = coalesceCount; coalesceCount = 0; return cnt;
526}
527
528/* the extern "C" wrappers that follow, are used for binary compatability since
529changing the prototypes from "struct mbuf *" to "mbuf_t" causes the symbol name to change. */
530
531/********************* class IOMbufBigMemoryCursor **********************/
532IOMbufBigMemoryCursor *
533IOMbufBigMemoryCursor::withSpecification(UInt32 maxSegSize, UInt32 maxNumSegs)
534{
535    IOMbufBigMemoryCursor *me = new IOMbufBigMemoryCursor;
536
537    if (me && !me->initWithSpecification(&bigOutputSegment,
538                                         maxSegSize, maxNumSegs)) {
539        me->release();
540        return 0;
541    }
542
543    return me;
544}
545
546extern "C" UInt32 _ZN21IOMbufBigMemoryCursor19getPhysicalSegmentsEP4mbufPN14IOMemoryCursor15PhysicalSegmentEm(
547      IOMbufBigMemoryCursor *self, void *packet, struct IOPhysicalSegment *vector, UInt32 numVectorSegments)
548{
549	return self->getPhysicalSegments((mbuf_t)packet, vector,numVectorSegments);
550}
551
552UInt32
553IOMbufBigMemoryCursor::getPhysicalSegments(mbuf_t packet,
554                       struct IOPhysicalSegment *vector,
555                       UInt32 numVectorSegments)
556{
557    return genPhysicalSegments(packet, vector, numVectorSegments, false);
558}
559
560extern "C" UInt32 _ZN21IOMbufBigMemoryCursor31getPhysicalSegmentsWithCoalesceEP4mbufPN14IOMemoryCursor15PhysicalSegmentEm(
561 IOMbufBigMemoryCursor *self, void *packet, struct IOPhysicalSegment *vector, UInt32 numVectorSegments)
562{
563	return self->getPhysicalSegmentsWithCoalesce((mbuf_t)packet, vector,numVectorSegments);
564}
565
566UInt32
567IOMbufBigMemoryCursor::getPhysicalSegmentsWithCoalesce(mbuf_t packet,
568                                   struct IOPhysicalSegment *vector,
569                                   UInt32 numVectorSegments)
570{
571    return genPhysicalSegments(packet, vector, numVectorSegments, true);
572}
573
574
575/******************* class IOMbufNaturalMemoryCursor ********************/
576IOMbufNaturalMemoryCursor *
577IOMbufNaturalMemoryCursor::withSpecification(UInt32 maxSegSize, UInt32 maxNumSegs)
578{
579    IOMbufNaturalMemoryCursor *me = new IOMbufNaturalMemoryCursor;
580
581    if (me && !me->initWithSpecification(&naturalOutputSegment,
582                                         maxSegSize, maxNumSegs)) {
583        me->release();
584        return 0;
585    }
586
587    return me;
588}
589
590extern "C" UInt32 _ZN25IOMbufNaturalMemoryCursor19getPhysicalSegmentsEP4mbufPN14IOMemoryCursor15PhysicalSegmentEm(
591 IOMbufNaturalMemoryCursor *self, void *packet, struct IOPhysicalSegment *vector, UInt32 numVectorSegments)
592{
593	return self->getPhysicalSegments((mbuf_t)packet, vector,numVectorSegments);
594}
595
596UInt32
597IOMbufNaturalMemoryCursor::getPhysicalSegments(mbuf_t packet,
598                       struct IOPhysicalSegment *vector,
599                       UInt32 numVectorSegments)
600{
601    return genPhysicalSegments(packet, vector, numVectorSegments, false);
602}
603
604extern "C" UInt32 _ZN25IOMbufNaturalMemoryCursor31getPhysicalSegmentsWithCoalesceEP4mbufPN14IOMemoryCursor15PhysicalSegmentEm(
605IOMbufNaturalMemoryCursor *self, void *packet, struct IOPhysicalSegment *vector, UInt32 numVectorSegments)
606{
607	return self->getPhysicalSegmentsWithCoalesce((mbuf_t)packet, vector,numVectorSegments);
608}
609
610
611UInt32
612IOMbufNaturalMemoryCursor::getPhysicalSegmentsWithCoalesce(mbuf_t packet,
613                                   struct IOPhysicalSegment *vector,
614                                   UInt32 numVectorSegments)
615{
616    return genPhysicalSegments(packet, vector, numVectorSegments, true);
617}
618
619
620/******************** class IOMbufLittleMemoryCursor ********************/
621IOMbufLittleMemoryCursor *
622IOMbufLittleMemoryCursor::withSpecification(UInt32 maxSegSize, UInt32 maxNumSegs)
623{
624    IOMbufLittleMemoryCursor *me = new IOMbufLittleMemoryCursor;
625
626    if (me && !me->initWithSpecification(&littleOutputSegment,
627                                         maxSegSize, maxNumSegs)) {
628        me->release();
629        return 0;
630    }
631
632    return me;
633}
634
635extern "C" UInt32 _ZN24IOMbufLittleMemoryCursor19getPhysicalSegmentsEP4mbufPN14IOMemoryCursor15PhysicalSegmentEm(
636 IOMbufLittleMemoryCursor *self, void *packet, struct IOPhysicalSegment *vector, UInt32 numVectorSegments)
637{
638	return self->getPhysicalSegments((mbuf_t)packet, vector,numVectorSegments);
639}
640
641UInt32
642IOMbufLittleMemoryCursor::getPhysicalSegments(mbuf_t packet,
643                       struct IOPhysicalSegment *vector,
644                       UInt32 numVectorSegments)
645{
646    return genPhysicalSegments(packet, vector, numVectorSegments, false);
647}
648
649extern "C" UInt32 _ZN24IOMbufLittleMemoryCursor31getPhysicalSegmentsWithCoalesceEP4mbufPN14IOMemoryCursor15PhysicalSegmentEm(
650  IOMbufLittleMemoryCursor *self, void *packet, struct IOPhysicalSegment *vector, UInt32 numVectorSegments)
651{
652	return self->getPhysicalSegmentsWithCoalesce((mbuf_t)packet, vector,numVectorSegments);
653}
654
655
656UInt32
657IOMbufLittleMemoryCursor::getPhysicalSegmentsWithCoalesce(mbuf_t packet,
658                                   struct IOPhysicalSegment *vector,
659                                   UInt32 numVectorSegments)
660{
661    return genPhysicalSegments(packet, vector, numVectorSegments, true);
662}
663
664
665/******************** class IOMbufDBDMAMemoryCursor *********************/
666#ifdef __ppc__
667
668IOMbufDBDMAMemoryCursor *
669IOMbufDBDMAMemoryCursor::withSpecification(UInt32 maxSegSize, UInt32 maxNumSegs)
670{
671    IOMbufDBDMAMemoryCursor *me = new IOMbufDBDMAMemoryCursor;
672
673    if (me && !me->initWithSpecification(&dbdmaOutputSegment,
674                                         maxSegSize, maxNumSegs)) {
675        me->release();
676        return 0;
677    }
678
679    return me;
680}
681
682extern "C" UInt32 _ZN23IOMbufDBDMAMemoryCursor19getPhysicalSegmentsEP4mbufP17IODBDMADescriptorm(
683IOMbufDBDMAMemoryCursor *self, void *packet, struct IODBDMADescriptor *vector, UInt32 numVectorSegments)
684{
685	return self->getPhysicalSegments((mbuf_t)packet, vector, numVectorSegments);
686}
687
688UInt32
689IOMbufDBDMAMemoryCursor::getPhysicalSegments(mbuf_t packet,
690                                   struct IODBDMADescriptor *vector,
691                                   UInt32 numVectorSegments)
692{
693    return genPhysicalSegments(packet, vector, numVectorSegments, false);
694}
695
696extern "C" UInt32 _ZN23IOMbufDBDMAMemoryCursor31getPhysicalSegmentsWithCoalesceEP4mbufP17IODBDMADescriptorm(
697IOMbufDBDMAMemoryCursor *self, void *packet, struct IODBDMADescriptor *vector, UInt32 numVectorSegments)
698{
699	return self->getPhysicalSegmentsWithCoalesce((mbuf_t)packet, vector, numVectorSegments);
700}
701
702
703UInt32
704IOMbufDBDMAMemoryCursor::getPhysicalSegmentsWithCoalesce(mbuf_t packet,
705                                   struct IODBDMADescriptor *vector,
706                                   UInt32 numVectorSegments)
707{
708    return genPhysicalSegments(packet, vector, numVectorSegments, true);
709}
710
711#endif /* __ppc__ */
712