1/*
2 * This is a tiny driver that attaches to a PCI device and logs information
3 * about it. It doesn't alter the device in any way. It also supports a
4 * generic IOUserClient subclass that allows driver specific client code to
5 * make various kinds of calls into the driver, and map shared memory
6 * or portions of hardware memory.
7 */
8
9#include "AppleSamplePCI.h"
10#include <IOKit/IOLib.h>
11#include <IOKit/assert.h>
12
13/*
14 * Define the metaclass information that is used for runtime
15 * typechecking of IOKit objects. We're a subclass of IOService,
16 * but usually we would subclass from a family class.
17 */
18
19#define super IOService
20OSDefineMetaClassAndStructors( AppleSamplePCI, IOService );
21
22bool AppleSamplePCI::start( IOService * provider )
23{
24    IOMemoryDescriptor *        mem;
25    IOMemoryMap *               map;
26
27    IOLog("AppleSamplePCI::start\n");
28
29    if( !super::start( provider ))
30        return( false );
31
32    /*
33     * Our provider class is specified in the driver property table
34     * as IOPCIDevice, so the provider must be of that class.
35     * The assert is just to make absolutely sure for debugging.
36     */
37
38    assert( OSDynamicCast( IOPCIDevice, provider ));
39    fPCIDevice = (IOPCIDevice *) provider;
40
41    /*
42     * Enable memory response from the card
43     */
44    fPCIDevice->setMemoryEnable( true );
45
46
47    /*
48     * Log some info about the device
49     */
50
51    /* print all the device's memory ranges */
52    for( UInt32 index = 0;
53         index < fPCIDevice->getDeviceMemoryCount();
54         index++ ) {
55
56        mem = fPCIDevice->getDeviceMemoryWithIndex( index );
57        assert( mem );
58        IOLog("Range[%ld] %08lx:%08lx\n", index,
59              mem->getPhysicalAddress(), mem->getLength());
60    }
61
62    /* look up a range based on its config space base address register */
63    mem = fPCIDevice->getDeviceMemoryWithRegister(
64                                  kIOPCIConfigBaseAddress0 );
65    if( mem )
66        IOLog("Range@0x%x %08lx:%08lx\n", kIOPCIConfigBaseAddress0,
67                mem->getPhysicalAddress(), mem->getLength());
68
69    /* map a range based on its config space base address register,
70     * this is how the driver gets access to its memory mapped registers
71     * the getVirtualAddress() method returns a kernel virtual address
72     * for the register mapping */
73
74    map = fPCIDevice->mapDeviceMemoryWithRegister(
75                                  kIOPCIConfigBaseAddress0 );
76    if( map ) {
77        IOLog("Range@0x%x (%08lx) mapped to kernel virtual address %08x\n",
78                kIOPCIConfigBaseAddress0,
79                map->getPhysicalAddress(),
80                map->getVirtualAddress());
81        /* release the map object, and the mapping itself */
82        map->release();
83    }
84
85    /* read a config space register */
86    IOLog("Config register@0x%x = %08lx\n", kIOPCIConfigCommand,
87          fPCIDevice->configRead32(kIOPCIConfigCommand) );
88
89    // construct a memory descriptor for a buffer below the 4Gb line &
90    // so addressable by 32 bit DMA. This could be used for a
91    // DMA program buffer for example
92
93    IOBufferMemoryDescriptor * bmd =
94        IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
95                                // task to hold the memory
96                                kernel_task,
97                                // options
98                                kIOMemoryPhysicallyContiguous,
99                                // size
100                                64*1024,
101                                // physicalMask - 32 bit addressable and page aligned
102                                0x00000000FFFFF000ULL);
103
104    if (bmd) {
105        generateDMAAddresses(bmd);
106    } else {
107        IOLog("IOBufferMemoryDescriptor::inTaskWithPhysicalMask failed\n");
108    }
109    fLowMemory = bmd;
110
111    /* publish ourselves so clients can find us */
112    registerService();
113
114    return( true );
115}
116
117/*
118 * We'll come here when the device goes away, or the driver is unloaded.
119 */
120
121void AppleSamplePCI::stop( IOService * provider )
122{
123    IOLog("AppleSamplePCI::stop\n");
124    super::stop( provider );
125}
126
127/*
128 * Method to supply an IOMemoryDescriptor for the user client to map into
129 * the client process. This sample just supplies all of the hardware memory
130 * associated with the PCI device's Base Address Register 0.
131 * In a real driver mapping hardware memory would only ever be used in some
132 * limited high performance scenarios where the device range can be safely
133 * accessed by client code with compromising system stability.
134 */
135
136IOMemoryDescriptor * AppleSamplePCI::copyGlobalMemory( void )
137{
138    IOMemoryDescriptor * memory;
139
140    memory = fPCIDevice->getDeviceMemoryWithRegister( kIOPCIConfigBaseAddress0 );
141    if( memory)
142        memory->retain();
143
144    return( memory );
145}
146
147IOReturn AppleSamplePCI::generateDMAAddresses( IOMemoryDescriptor * memDesc )
148{
149    // Get the physical segment list. These could be used to generate a scatter gather
150    // list for hardware.
151
152    // This is the old getPhysicalSegment() loop calling IOMemoryDescriptor,
153    // it will fail (panic) on new machines with memory above the 4Gb line
154
155    IODMACommand *      cmd;
156    IOReturn            err = kIOReturnSuccess;
157    IOByteCount         offset = 0;
158    IOPhysicalAddress   physicalAddr;
159    IOPhysicalLength    segmentLength;
160    UInt32              index = 0;
161
162    while( (physicalAddr = memDesc->getPhysicalSegment( offset, &segmentLength ))) {
163        IOLog("Physical segment(%ld) %08lx:%08lx\n", index, physicalAddr, segmentLength);
164        offset += segmentLength;
165        index++;
166    }
167
168    // 64 bit physical address generation using IODMACommand
169    do
170    {
171        cmd = IODMACommand::withSpecification(
172            // outSegFunc - Host endian since we read the address data with the cpu
173            // and 64 bit wide quantities
174            kIODMACommandOutputHost64,
175            // numAddressBits
176            64,
177            // maxSegmentSize - zero for unrestricted physically contiguous chunks
178            0,
179            // mappingOptions - kMapped for DMA addresses
180            IODMACommand::kMapped,
181            // maxTransferSize - no restriction
182            0,
183            // alignment - no restriction
184            1 );
185        if (!cmd)
186        {
187            IOLog("IODMACommand::withSpecification failed\n");
188            break;
189        }
190
191        // point at the memory descriptor and use the auto prepare option
192        // to prepare the entire range
193        err = cmd->setMemoryDescriptor(memDesc);
194        if (kIOReturnSuccess != err)
195        {
196            IOLog("setMemoryDescriptor failed (0x%x)\n", err);
197            break;
198        }
199
200        UInt64 offset = 0;
201        while ((kIOReturnSuccess == err) && (offset < memDesc->getLength()))
202        {
203            // use the 64 bit variant to match outSegFunc
204            IODMACommand::Segment64 segments[1];
205            UInt32 numSeg = 1;
206
207            // use the 64 bit variant to match outSegFunc
208            err = cmd->gen64IOVMSegments(&offset, &segments[0], &numSeg);
209            IOLog("gen64IOVMSegments(%x) addr 0x%qx, len 0x%qx, nsegs %ld\n",
210                    err, segments[0].fIOVMAddr, segments[0].fLength, numSeg);
211        }
212
213        // if we had a DMA controller, kick off the DMA here
214
215        // when the DMA has completed,
216
217        // clear the memory descriptor and use the auto complete option
218        // to complete the transaction
219        err = cmd->clearMemoryDescriptor();
220        if (kIOReturnSuccess != err)
221        {
222            IOLog("clearMemoryDescriptor failed (0x%x)\n", err);
223        }
224    }
225    while (false);
226    if (cmd)
227        cmd->release();
228    // end 64 bit loop
229
230
231    // 32 bit physical address generation using IODMACommand
232    // any memory above 4Gb in the memory descriptor will be buffered
233    // to memory below the 4G line, on machines without remapping HW support
234    do
235    {
236        cmd = IODMACommand::withSpecification(
237            // outSegFunc - Host endian since we read the address data with the cpu
238            // and 32 bit wide quantities
239            kIODMACommandOutputHost32,
240            // numAddressBits
241            32,
242            // maxSegmentSize - zero for unrestricted physically contiguous chunks
243            0,
244            // mappingOptions - kMapped for DMA addresses
245            IODMACommand::kMapped,
246            // maxTransferSize - no restriction
247            0,
248            // alignment - no restriction
249            1 );
250        if (!cmd)
251        {
252            IOLog("IODMACommand::withSpecification failed\n");
253            break;
254        }
255
256        // point at the memory descriptor and use the auto prepare option
257        // to prepare the entire range
258        err = cmd->setMemoryDescriptor(memDesc);
259        if (kIOReturnSuccess != err)
260        {
261            IOLog("setMemoryDescriptor failed (0x%x)\n", err);
262            break;
263        }
264
265        UInt64 offset = 0;
266        while ((kIOReturnSuccess == err) && (offset < memDesc->getLength()))
267        {
268            // use the 32 bit variant to match outSegFunc
269            IODMACommand::Segment32 segments[1];
270            UInt32 numSeg = 1;
271
272            // use the 32 bit variant to match outSegFunc
273            err = cmd->gen32IOVMSegments(&offset, &segments[0], &numSeg);
274            IOLog("gen32IOVMSegments(%x) addr 0x%lx, len 0x%lx, nsegs %ld\n",
275                    err, segments[0].fIOVMAddr, segments[0].fLength, numSeg);
276        }
277
278        // if we had a DMA controller, kick off the DMA here
279
280        // when the DMA has completed,
281
282        // clear the memory descriptor and use the auto complete option
283        // to complete the transaction
284        err = cmd->clearMemoryDescriptor();
285        if (kIOReturnSuccess != err)
286        {
287            IOLog("clearMemoryDescriptor failed (0x%x)\n", err);
288        }
289    }
290    while (false);
291    if (cmd)
292        cmd->release();
293    // end 32 bit loop
294
295    return (err);
296}
297