~ubuntu-branches/ubuntu/intrepid/xserver-xgl/intrepid

« back to all changes in this revision

Viewing changes to hw/xfree86/os-support/bus/linuxPci.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthew Garrett
  • Date: 2006-02-13 14:21:43 UTC
  • Revision ID: james.westby@ubuntu.com-20060213142143-mad6z9xzem7hzxz9
Tags: upstream-7.0.0
ImportĀ upstreamĀ versionĀ 7.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/bus/linuxPci.c,v 1.9 2002/09/24 16:14:16 tsi Exp $ */
 
2
/*
 
3
 * Copyright 1998 by Concurrent Computer Corporation
 
4
 *
 
5
 * Permission to use, copy, modify, distribute, and sell this software
 
6
 * and its documentation for any purpose is hereby granted without fee,
 
7
 * provided that the above copyright notice appear in all copies and that
 
8
 * both that copyright notice and this permission notice appear in
 
9
 * supporting documentation, and that the name of Concurrent Computer
 
10
 * Corporation not be used in advertising or publicity pertaining to
 
11
 * distribution of the software without specific, written prior
 
12
 * permission.  Concurrent Computer Corporation makes no representations
 
13
 * about the suitability of this software for any purpose.  It is
 
14
 * provided "as is" without express or implied warranty.
 
15
 *
 
16
 * CONCURRENT COMPUTER CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD
 
17
 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
18
 * AND FITNESS, IN NO EVENT SHALL CONCURRENT COMPUTER CORPORATION BE
 
19
 * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
 
20
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 
21
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 
22
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 
23
 * SOFTWARE.
 
24
 *
 
25
 * Copyright 1998 by Metro Link Incorporated
 
26
 *
 
27
 * Permission to use, copy, modify, distribute, and sell this software
 
28
 * and its documentation for any purpose is hereby granted without fee,
 
29
 * provided that the above copyright notice appear in all copies and that
 
30
 * both that copyright notice and this permission notice appear in
 
31
 * supporting documentation, and that the name of Metro Link
 
32
 * Incorporated not be used in advertising or publicity pertaining to
 
33
 * distribution of the software without specific, written prior
 
34
 * permission.  Metro Link Incorporated makes no representations
 
35
 * about the suitability of this software for any purpose.  It is
 
36
 * provided "as is" without express or implied warranty.
 
37
 *
 
38
 * METRO LINK INCORPORATED DISCLAIMS ALL WARRANTIES WITH REGARD
 
39
 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
40
 * AND FITNESS, IN NO EVENT SHALL METRO LINK INCORPORATED BE
 
41
 * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
 
42
 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 
43
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 
44
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 
45
 * SOFTWARE.
 
46
 */
 
47
 
 
48
#ifdef HAVE_XORG_CONFIG_H
 
49
#include <xorg-config.h>
 
50
#endif
 
51
 
 
52
#include <stdio.h>
 
53
#include "compiler.h"
 
54
#include "xf86.h"
 
55
#include "xf86Priv.h"
 
56
#include "xf86_OSlib.h"
 
57
#include "Pci.h"
 
58
 
 
59
/*
 
60
 * linux platform specific PCI access functions -- using /proc/bus/pci
 
61
 * needs kernel version 2.2.x
 
62
 */
 
63
static CARD32 linuxPciCfgRead(PCITAG tag, int off);
 
64
static void linuxPciCfgWrite(PCITAG, int off, CARD32 val);
 
65
static void linuxPciCfgSetBits(PCITAG tag, int off, CARD32 mask, CARD32 bits);
 
66
static ADDRESS linuxTransAddrBusToHost(PCITAG tag, PciAddrType type, ADDRESS addr);
 
67
#if defined(__powerpc__)
 
68
static ADDRESS linuxPpcBusAddrToHostAddr(PCITAG, PciAddrType, ADDRESS);
 
69
static ADDRESS linuxPpcHostAddrToBusAddr(PCITAG, PciAddrType, ADDRESS);
 
70
#endif
 
71
 
 
72
static CARD8 linuxPciCfgReadByte(PCITAG tag, int off);
 
73
static void linuxPciCfgWriteByte(PCITAG tag, int off, CARD8 val);
 
74
static CARD16 linuxPciCfgReadWord(PCITAG tag, int off);
 
75
static void linuxPciCfgWriteWord(PCITAG tag, int off, CARD16 val);
 
76
 
 
77
static pciBusFuncs_t linuxFuncs0 = {
 
78
/* pciReadLong      */  linuxPciCfgRead,
 
79
/* pciWriteLong     */  linuxPciCfgWrite,
 
80
/* pciSetBitsLong   */  linuxPciCfgSetBits,
 
81
#if defined(__powerpc__)
 
82
/* pciAddrHostToBus */  linuxPpcHostAddrToBusAddr,
 
83
/* pciAddrBusToHost */  linuxPpcBusAddrToHostAddr,
 
84
#else
 
85
/* pciAddrHostToBus */  pciAddrNOOP,
 
86
/* pciAddrBusToHost */  linuxTransAddrBusToHost,
 
87
#endif
 
88
 
 
89
/* pciControlBridge */          NULL,
 
90
/* pciGetBridgeBuses */         NULL,
 
91
/* pciGetBridgeResources */     NULL,
 
92
 
 
93
/* pciReadByte */       linuxPciCfgReadByte,
 
94
/* pciWriteByte */      linuxPciCfgWriteByte,
 
95
 
 
96
/* pciReadWord */       linuxPciCfgReadWord,
 
97
/* pciWriteWord */      linuxPciCfgWriteWord,
 
98
};
 
99
 
 
100
static pciBusInfo_t linuxPci0 = {
 
101
/* configMech  */       PCI_CFG_MECH_OTHER,
 
102
/* numDevices  */       32,
 
103
/* secondary   */       FALSE,
 
104
/* primary_bus */       0,
 
105
/* funcs       */       &linuxFuncs0,
 
106
/* pciBusPriv  */       NULL,
 
107
/* bridge      */       NULL
 
108
};
 
109
 
 
110
void
 
111
linuxPciInit()
 
112
{
 
113
        struct stat st;
 
114
        if ((xf86Info.pciFlags == PCIForceNone) ||
 
115
            (-1 == stat("/proc/bus/pci", &st))) {
 
116
                /* when using this as default for all linux architectures,
 
117
                   we'll need a fallback for 2.0 kernels here */
 
118
                return;
 
119
        }
 
120
        pciNumBuses    = 1;
 
121
        pciBusInfo[0]  = &linuxPci0;
 
122
        pciFindFirstFP = pciGenFindFirst;
 
123
        pciFindNextFP  = pciGenFindNext;
 
124
}
 
125
 
 
126
static int
 
127
linuxPciOpenFile(PCITAG tag, Bool write)
 
128
{
 
129
        static int      lbus,ldev,lfunc,fd = -1,is_write = 0;
 
130
        int             bus, dev, func;
 
131
        char            file[32];
 
132
        struct stat     ignored;
 
133
 
 
134
        bus  = PCI_BUS_FROM_TAG(tag);
 
135
        dev  = PCI_DEV_FROM_TAG(tag);
 
136
        func = PCI_FUNC_FROM_TAG(tag);
 
137
        if (fd == -1 || (write && (!is_write))
 
138
            || bus != lbus || dev != ldev || func != lfunc) {
 
139
                if (fd != -1)
 
140
                        close(fd);
 
141
                if (bus < 256) {
 
142
                        sprintf(file,"/proc/bus/pci/%02x",bus);
 
143
                        if (stat(file, &ignored) < 0)
 
144
                                sprintf(file, "/proc/bus/pci/0000:%02x/%02x.%1x",
 
145
                                        bus, dev, func);
 
146
                        else
 
147
                                sprintf(file, "/proc/bus/pci/%02x/%02x.%1x",
 
148
                                        bus, dev, func);
 
149
                } else {
 
150
                        sprintf(file,"/proc/bus/pci/%04x",bus);
 
151
                        if (stat(file, &ignored) < 0)
 
152
                                sprintf(file, "/proc/bus/pci/0000:%04x/%02x.%1x",
 
153
                                        bus, dev, func);
 
154
                        else
 
155
                                sprintf(file, "/proc/bus/pci/%04x/%02x.%1x",
 
156
                                        bus, dev, func);
 
157
                }
 
158
                if (write) {
 
159
                    fd = open(file,O_RDWR);
 
160
                    if (fd != -1) is_write = TRUE;
 
161
                } else switch (is_write) {
 
162
                        case TRUE:
 
163
                            fd = open(file,O_RDWR);
 
164
                            if (fd > -1)
 
165
                                break;
 
166
                        default:
 
167
                            fd = open(file,O_RDONLY);
 
168
                            is_write = FALSE;
 
169
                }
 
170
                
 
171
                lbus  = bus;
 
172
                ldev  = dev;
 
173
                lfunc = func;
 
174
        }
 
175
        return fd;
 
176
}
 
177
 
 
178
static CARD32
 
179
linuxPciCfgRead(PCITAG tag, int off)
 
180
{
 
181
        int     fd;
 
182
        CARD32  val = 0xffffffff;
 
183
 
 
184
        if (-1 != (fd = linuxPciOpenFile(tag,FALSE))) {
 
185
                lseek(fd,off,SEEK_SET);
 
186
                read(fd,&val,4);
 
187
        }
 
188
        return PCI_CPU(val);
 
189
}
 
190
 
 
191
static void
 
192
linuxPciCfgWrite(PCITAG tag, int off, CARD32 val)
 
193
{
 
194
        int     fd;
 
195
 
 
196
        if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
 
197
                lseek(fd,off,SEEK_SET);
 
198
                val = PCI_CPU(val);
 
199
                write(fd,&val,4);
 
200
        }
 
201
}
 
202
 
 
203
static void
 
204
linuxPciCfgSetBits(PCITAG tag, int off, CARD32 mask, CARD32 bits)
 
205
{
 
206
        int     fd;
 
207
        CARD32  val = 0xffffffff;
 
208
 
 
209
        if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
 
210
                lseek(fd,off,SEEK_SET);
 
211
                read(fd,&val,4);
 
212
                val = PCI_CPU(val);
 
213
                val = (val & ~mask) | (bits & mask);
 
214
                val = PCI_CPU(val);
 
215
                lseek(fd,off,SEEK_SET);
 
216
                write(fd,&val,4);
 
217
        }
 
218
}
 
219
 
 
220
/*
 
221
 * This function will convert a BAR address into a host address
 
222
 * suitable for passing into the mmap function of a /proc/bus
 
223
 * device.
 
224
 */
 
225
ADDRESS linuxTransAddrBusToHost(PCITAG tag, PciAddrType type, ADDRESS addr)
 
226
{
 
227
    ADDRESS ret = xf86GetOSOffsetFromPCI(tag, PCI_MEM|PCI_IO, addr);
 
228
 
 
229
    if (ret)
 
230
        return ret;
 
231
 
 
232
    /*
 
233
     * if it is not a BAR address, it must be legacy, (or wrong)
 
234
     * return it as is..
 
235
     */
 
236
    return addr;
 
237
}
 
238
 
 
239
 
 
240
#if defined(__powerpc__)
 
241
 
 
242
#ifndef __NR_pciconfig_iobase
 
243
#define __NR_pciconfig_iobase   200
 
244
#endif
 
245
 
 
246
static ADDRESS
 
247
linuxPpcBusAddrToHostAddr(PCITAG tag, PciAddrType type, ADDRESS addr)
 
248
{
 
249
    if (type == PCI_MEM)
 
250
    {
 
251
        ADDRESS membase = syscall(__NR_pciconfig_iobase, 1,
 
252
                    PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
 
253
        return (addr + membase);
 
254
    }
 
255
    else if (type == PCI_IO)
 
256
    {
 
257
        ADDRESS iobase = syscall(__NR_pciconfig_iobase, 2,
 
258
                    PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
 
259
        return (addr + iobase);
 
260
    }
 
261
    else return addr;
 
262
}
 
263
 
 
264
static ADDRESS
 
265
linuxPpcHostAddrToBusAddr(PCITAG tag, PciAddrType type, ADDRESS addr)
 
266
{
 
267
    if (type == PCI_MEM)
 
268
    {
 
269
        ADDRESS membase = syscall(__NR_pciconfig_iobase, 1,
 
270
                    PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
 
271
        return (addr - membase);
 
272
    }
 
273
    else if (type == PCI_IO)
 
274
    {
 
275
        ADDRESS iobase = syscall(__NR_pciconfig_iobase, 2,
 
276
                    PCI_BUS_FROM_TAG(tag), PCI_DFN_FROM_TAG(tag));
 
277
        return (addr - iobase);
 
278
    }
 
279
    else return addr;
 
280
}
 
281
 
 
282
#endif /* __powerpc__ */
 
283
 
 
284
static CARD8
 
285
linuxPciCfgReadByte(PCITAG tag, int off)
 
286
{
 
287
        int     fd;
 
288
        CARD8   val = 0xff;
 
289
 
 
290
        if (-1 != (fd = linuxPciOpenFile(tag,FALSE))) {
 
291
                lseek(fd,off,SEEK_SET);
 
292
                read(fd,&val,1);
 
293
        }
 
294
 
 
295
        return val;
 
296
}
 
297
 
 
298
static void
 
299
linuxPciCfgWriteByte(PCITAG tag, int off, CARD8 val)
 
300
{
 
301
        int     fd;
 
302
 
 
303
        if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
 
304
                lseek(fd,off,SEEK_SET);
 
305
                write(fd, &val, 1);
 
306
        }
 
307
}
 
308
 
 
309
static CARD16
 
310
linuxPciCfgReadWord(PCITAG tag, int off)
 
311
{
 
312
        int     fd;
 
313
        CARD16  val = 0xff;
 
314
 
 
315
        if (-1 != (fd = linuxPciOpenFile(tag,FALSE))) {
 
316
                lseek(fd, off, SEEK_SET);
 
317
                read(fd, &val, 2);
 
318
        }
 
319
 
 
320
        return PCI_CPU16(val);
 
321
}
 
322
 
 
323
static void
 
324
linuxPciCfgWriteWord(PCITAG tag, int off, CARD16 val)
 
325
{
 
326
        int     fd;
 
327
 
 
328
        if (-1 != (fd = linuxPciOpenFile(tag,TRUE))) {
 
329
                lseek(fd, off, SEEK_SET);
 
330
                val = PCI_CPU16(val);
 
331
                write(fd, &val, 2);
 
332
        }
 
333
}
 
334
 
 
335
#ifndef INCLUDE_XF86_NO_DOMAIN
 
336
 
 
337
/*
 
338
 * Compiling the following simply requires the presence of <linux/pci.c>.
 
339
 * Actually running this is another matter altogether...
 
340
 *
 
341
 * This scheme requires that the kernel allow mmap()'ing of a host bridge's I/O
 
342
 * and memory spaces through its /proc/bus/pci/BUS/DFN entry.  Which one is
 
343
 * determined by a prior ioctl().
 
344
 *
 
345
 * For the sparc64 port, this means 2.4.12 or later.  For ppc, this
 
346
 * functionality is almost, but not quite there yet.  Alpha and other kernel
 
347
 * ports to multi-domain architectures still need to implement this.
 
348
 *
 
349
 * This scheme is also predicated on the use of an IOADDRESS compatible type to
 
350
 * designate I/O addresses.  Although IOADDRESS is defined as an unsigned
 
351
 * integral type, it is actually the virtual address of, i.e. a pointer to, the
 
352
 * I/O port to access.  And so, the inX/outX macros in "compiler.h" need to be
 
353
 * #define'd appropriately (as is done on SPARC's).
 
354
 *
 
355
 * Another requirement to port this scheme to another multi-domain architecture
 
356
 * is to add the appropriate entries in the pciControllerSizes array below.
 
357
 *
 
358
 * TO DO:  Address the deleterious reaction some host bridges have to master
 
359
 *         aborts.  This is already done for secondary PCI buses, but not yet
 
360
 *         for accesses to primary buses (except for the SPARC port, where
 
361
 *         master aborts are avoided during PCI scans).
 
362
 */
 
363
 
 
364
#include <linux/pci.h>
 
365
 
 
366
#ifndef PCIIOC_BASE             /* Ioctls for /proc/bus/pci/X/Y nodes. */
 
367
#define PCIIOC_BASE             ('P' << 24 | 'C' << 16 | 'I' << 8)
 
368
 
 
369
/* Get controller for PCI device. */
 
370
#define PCIIOC_CONTROLLER       (PCIIOC_BASE | 0x00)
 
371
/* Set mmap state to I/O space. */
 
372
#define PCIIOC_MMAP_IS_IO       (PCIIOC_BASE | 0x01)
 
373
/* Set mmap state to MEM space. */
 
374
#define PCIIOC_MMAP_IS_MEM      (PCIIOC_BASE | 0x02)
 
375
/* Enable/disable write-combining. */
 
376
#define PCIIOC_WRITE_COMBINE    (PCIIOC_BASE | 0x03)
 
377
 
 
378
#endif
 
379
 
 
380
/* This probably shouldn't be Linux-specific */
 
381
static pciConfigPtr
 
382
xf86GetPciHostConfigFromTag(PCITAG Tag)
 
383
{
 
384
    int bus = PCI_BUS_FROM_TAG(Tag);
 
385
    pciBusInfo_t *pBusInfo;
 
386
 
 
387
    while ((bus < pciNumBuses) && (pBusInfo = pciBusInfo[bus])) {
 
388
        if (bus == pBusInfo->primary_bus)
 
389
            return pBusInfo->bridge;
 
390
        bus = pBusInfo->primary_bus;
 
391
    }
 
392
 
 
393
    return NULL;        /* Bad data */
 
394
}
 
395
 
 
396
/*
 
397
 * This is ugly, but until I can extract this information from the kernel,
 
398
 * it'll have to do.  The default I/O space size is 64K, and 4G for memory.
 
399
 * Anything else needs to go in this table.  (PowerPC folk take note.)
 
400
 *
 
401
 * Note that Linux/SPARC userland is 32-bit, so 4G overflows to zero here.
 
402
 *
 
403
 * Please keep this table in ascending vendor/device order.
 
404
 */
 
405
static struct pciSizes {
 
406
    unsigned short vendor, device;
 
407
    unsigned long io_size, mem_size;
 
408
} pciControllerSizes[] = {
 
409
    {
 
410
        PCI_VENDOR_SUN, PCI_CHIP_PSYCHO,
 
411
        1U << 16, 1U << 31
 
412
    },
 
413
    {
 
414
        PCI_VENDOR_SUN, PCI_CHIP_SCHIZO,
 
415
        1U << 24, 1U << 31      /* ??? */
 
416
    },
 
417
    {
 
418
        PCI_VENDOR_SUN, PCI_CHIP_SABRE,
 
419
        1U << 24, (unsigned long)(1ULL << 32)
 
420
    },
 
421
    {
 
422
        PCI_VENDOR_SUN, PCI_CHIP_HUMMINGBIRD,
 
423
        1U << 24, (unsigned long)(1ULL << 32)
 
424
    }
 
425
};
 
426
#define NUM_SIZES (sizeof(pciControllerSizes) / sizeof(pciControllerSizes[0]))
 
427
 
 
428
static unsigned long
 
429
linuxGetIOSize(PCITAG Tag)
 
430
{
 
431
    pciConfigPtr pPCI;
 
432
    int          i;
 
433
 
 
434
    /* Find host bridge */
 
435
    if ((pPCI = xf86GetPciHostConfigFromTag(Tag))) {
 
436
        /* Look up vendor/device */
 
437
        for (i = 0;  i < NUM_SIZES;  i++) {
 
438
            if (pPCI->pci_vendor > pciControllerSizes[i].vendor)
 
439
                continue;
 
440
            if (pPCI->pci_vendor < pciControllerSizes[i].vendor)
 
441
                break;
 
442
            if (pPCI->pci_device > pciControllerSizes[i].device)
 
443
                continue;
 
444
            if (pPCI->pci_device < pciControllerSizes[i].device)
 
445
                break;
 
446
            return pciControllerSizes[i].io_size;
 
447
        }
 
448
    }
 
449
 
 
450
    return 1U << 16;                    /* Default to 64K */
 
451
}
 
452
 
 
453
static void
 
454
linuxGetSizes(PCITAG Tag, unsigned long *io_size, unsigned long *mem_size)
 
455
{
 
456
    pciConfigPtr pPCI;
 
457
    int          i;
 
458
 
 
459
    *io_size  = (1U << 16);                     /* Default to 64K */
 
460
    *mem_size = (unsigned long)(1ULL << 32);    /* Default to 4G */
 
461
 
 
462
    /* Find host bridge */
 
463
    if ((pPCI = xf86GetPciHostConfigFromTag(Tag))) {
 
464
        /* Look up vendor/device */
 
465
        for (i = 0;  i < NUM_SIZES;  i++) {
 
466
            if (pPCI->pci_vendor > pciControllerSizes[i].vendor)
 
467
                continue;
 
468
            if (pPCI->pci_vendor < pciControllerSizes[i].vendor)
 
469
                break;
 
470
            if (pPCI->pci_device > pciControllerSizes[i].device)
 
471
                continue;
 
472
            if (pPCI->pci_device < pciControllerSizes[i].device)
 
473
                break;
 
474
            *io_size  = pciControllerSizes[i].io_size;
 
475
            *mem_size = pciControllerSizes[i].mem_size;
 
476
            break;
 
477
        }
 
478
    }
 
479
}
 
480
 
 
481
int
 
482
xf86GetPciDomain(PCITAG Tag)
 
483
{
 
484
    pciConfigPtr pPCI;
 
485
    int fd, result;
 
486
 
 
487
    pPCI = xf86GetPciHostConfigFromTag(Tag);
 
488
 
 
489
    if (pPCI && (result = PCI_DOM_FROM_BUS(pPCI->busnum)))
 
490
        return result;
 
491
 
 
492
    if (!pPCI || pPCI->fakeDevice)
 
493
        return 1;               /* Domain 0 is reserved */
 
494
 
 
495
    if ((fd = linuxPciOpenFile(pPCI ? pPCI->tag : 0,FALSE)) < 0)
 
496
        return 0;
 
497
 
 
498
    if ((result = ioctl(fd, PCIIOC_CONTROLLER, 0)) < 0)
 
499
        return 0;
 
500
 
 
501
    return result + 1;          /* Domain 0 is reserved */
 
502
}
 
503
 
 
504
static pointer
 
505
linuxMapPci(int ScreenNum, int Flags, PCITAG Tag,
 
506
            ADDRESS Base, unsigned long Size, int mmap_ioctl)
 
507
{
 
508
    do {
 
509
        pciConfigPtr pPCI;
 
510
        unsigned char *result;
 
511
        ADDRESS realBase, Offset;
 
512
        int fd, mmapflags, prot;
 
513
 
 
514
        xf86InitVidMem();
 
515
 
 
516
        pPCI = xf86GetPciHostConfigFromTag(Tag);
 
517
 
 
518
        if (((fd = linuxPciOpenFile(pPCI ? pPCI->tag : 0,FALSE)) < 0) ||
 
519
            (ioctl(fd, mmap_ioctl, 0) < 0))
 
520
            break;
 
521
 
 
522
/* Note:  IA-64 doesn't compile this and doesn't need to */
 
523
#ifdef __ia64__
 
524
 
 
525
# ifndef  MAP_WRITECOMBINED
 
526
#  define MAP_WRITECOMBINED 0x00010000
 
527
# endif
 
528
# ifndef  MAP_NONCACHED
 
529
#  define MAP_NONCACHED     0x00020000
 
530
# endif
 
531
 
 
532
        if (Flags & VIDMEM_FRAMEBUFFER)
 
533
            mmapflags = MAP_SHARED | MAP_WRITECOMBINED;
 
534
        else
 
535
            mmapflags = MAP_SHARED | MAP_NONCACHED;
 
536
 
 
537
#else /* !__ia64__ */
 
538
 
 
539
        mmapflags = (Flags & VIDMEM_FRAMEBUFFER) / VIDMEM_FRAMEBUFFER;
 
540
 
 
541
        if (ioctl(fd, PCIIOC_WRITE_COMBINE, mmapflags) < 0)
 
542
            break;
 
543
 
 
544
        mmapflags = MAP_SHARED;
 
545
 
 
546
#endif /* ?__ia64__ */
 
547
 
 
548
        /* Align to page boundary */
 
549
        realBase = Base & ~(getpagesize() - 1);
 
550
        Offset = Base - realBase;
 
551
 
 
552
        if (Flags & VIDMEM_READONLY)
 
553
            prot = PROT_READ;
 
554
        else
 
555
            prot = PROT_READ | PROT_WRITE;
 
556
 
 
557
        result = mmap(NULL, Size + Offset, prot, mmapflags, fd, realBase);
 
558
 
 
559
        if (!result || ((pointer)result == MAP_FAILED))
 
560
            return NULL;
 
561
 
 
562
        xf86MakeNewMapping(ScreenNum, Flags, realBase, Size + Offset, result);
 
563
 
 
564
        return result + Offset;
 
565
    } while (0);
 
566
 
 
567
    if (mmap_ioctl == PCIIOC_MMAP_IS_MEM)
 
568
        return xf86MapVidMem(ScreenNum, Flags, Base, Size);
 
569
 
 
570
    return NULL;
 
571
}
 
572
 
 
573
#define MAX_DOMAINS 257
 
574
static pointer DomainMmappedIO[MAX_DOMAINS];
 
575
static pointer DomainMmappedMem[MAX_DOMAINS];
 
576
 
 
577
static int
 
578
linuxOpenLegacy(PCITAG Tag, char *name)
 
579
{
 
580
#define PREFIX "/sys/class/pci_bus/%04x:%02x/%s"
 
581
    char *path;
 
582
    int domain, bus;
 
583
    pciBusInfo_t *pBusInfo;
 
584
    pciConfigPtr bridge = NULL;
 
585
    int fd;
 
586
 
 
587
    path = xalloc(strlen(PREFIX) + strlen(name));
 
588
    if (!path)
 
589
        return -1;
 
590
 
 
591
    for (;;) {
 
592
        domain = xf86GetPciDomain(Tag);
 
593
        bus = PCI_BUS_NO_DOMAIN(PCI_BUS_FROM_TAG(Tag));
 
594
 
 
595
        /* Domain 0 is reserved -- see xf86GetPciDomain() */
 
596
        if ((domain <= 0) || (domain >= MAX_DOMAINS))
 
597
            FatalError("linuxOpenLegacy():  domain out of range\n");
 
598
 
 
599
        sprintf(path, PREFIX, domain - 1, bus, name);
 
600
        fd = open(path, O_RDWR);
 
601
        if (fd >= 0) {
 
602
            xfree(path);
 
603
            return fd;
 
604
        }
 
605
 
 
606
        pBusInfo = pciBusInfo[bus];
 
607
        if (!pBusInfo || (bridge == pBusInfo->bridge) ||
 
608
                !(bridge = pBusInfo->bridge)) {
 
609
            xfree(path);
 
610
            return -1;
 
611
        }
 
612
 
 
613
        Tag = bridge->tag;
 
614
    }
 
615
 
 
616
    xfree(path);
 
617
    return fd;
 
618
}
 
619
 
 
620
/*
 
621
 * xf86MapDomainMemory - memory map PCI domain memory
 
622
 *
 
623
 * This routine maps the memory region in the domain specified by Tag and
 
624
 * returns a pointer to it.  The pointer is saved for future use if it's in
 
625
 * the legacy ISA memory space (memory in a domain between 0 and 1MB).
 
626
 */
 
627
pointer
 
628
xf86MapDomainMemory(int ScreenNum, int Flags, PCITAG Tag,
 
629
                    ADDRESS Base, unsigned long Size)
 
630
{
 
631
    int domain = xf86GetPciDomain(Tag);
 
632
    int fd;
 
633
 
 
634
    /*
 
635
     * We use /proc/bus/pci on non-legacy addresses or if the Linux sysfs
 
636
     * legacy_mem interface is unavailable.
 
637
     */
 
638
    if (Base > 1024*1024)
 
639
        return linuxMapPci(ScreenNum, Flags, Tag, Base, Size,
 
640
                           PCIIOC_MMAP_IS_MEM);
 
641
 
 
642
    if ((fd = linuxOpenLegacy(Tag, "legacy_mem")) < 0)
 
643
        return linuxMapPci(ScreenNum, Flags, Tag, Base, Size,
 
644
                           PCIIOC_MMAP_IS_MEM);
 
645
 
 
646
 
 
647
    /* If we haven't already mapped this legacy space, try to. */
 
648
    if (!DomainMmappedMem[domain]) {
 
649
        DomainMmappedMem[domain] = mmap(NULL, 1024*1024, PROT_READ|PROT_WRITE,
 
650
                                        MAP_SHARED, fd, 0);
 
651
        if (DomainMmappedMem[domain] == MAP_FAILED) {
 
652
            close(fd);
 
653
            perror("mmap failure");
 
654
            FatalError("xf86MapDomainMem():  mmap() failure\n");
 
655
        }
 
656
    }
 
657
 
 
658
    close(fd);
 
659
    return (pointer)((char *)DomainMmappedMem[domain] + Base);
 
660
}
 
661
 
 
662
/*
 
663
 * xf86MapDomainIO - map I/O space in this domain
 
664
 *
 
665
 * Each domain has a legacy ISA I/O space.  This routine will try to
 
666
 * map it using the Linux sysfs legacy_io interface.  If that fails,
 
667
 * it'll fall back to using /proc/bus/pci.
 
668
 *
 
669
 * If the legacy_io interface *does* exist, the file descriptor (fd below)
 
670
 * will be saved in the DomainMmappedIO array in the upper bits of the
 
671
 * pointer.  Callers will do I/O with small port numbers (<64k values), so
 
672
 * the platform I/O code can extract the port number and the fd, lseek to
 
673
 * the port number in the legacy_io file, and issue the read or write.
 
674
 *
 
675
 * This has no means of returning failure, so all errors are fatal
 
676
 */
 
677
IOADDRESS
 
678
xf86MapDomainIO(int ScreenNum, int Flags, PCITAG Tag,
 
679
                IOADDRESS Base, unsigned long Size)
 
680
{
 
681
    int domain = xf86GetPciDomain(Tag);
 
682
    int fd;
 
683
 
 
684
    if ((domain <= 0) || (domain >= MAX_DOMAINS))
 
685
        FatalError("xf86MapDomainIO():  domain out of range\n");
 
686
 
 
687
    if (DomainMmappedIO[domain])
 
688
        return (IOADDRESS)DomainMmappedIO[domain] + Base;
 
689
 
 
690
    /* Permanently map all of I/O space */
 
691
    if ((fd = linuxOpenLegacy(Tag, "legacy_io")) < 0) {
 
692
            DomainMmappedIO[domain] = linuxMapPci(ScreenNum, Flags, Tag,
 
693
                                                  0, linuxGetIOSize(Tag),
 
694
                                                  PCIIOC_MMAP_IS_IO);
 
695
            /* ia64 can't mmap legacy IO port space */
 
696
            if (!DomainMmappedIO[domain])
 
697
                return Base;
 
698
    }
 
699
    else { /* legacy_io file exists, encode fd */
 
700
        DomainMmappedIO[domain] = (pointer)(fd << 24);
 
701
    }
 
702
 
 
703
    return (IOADDRESS)DomainMmappedIO[domain] + Base;
 
704
}
 
705
 
 
706
/*
 
707
 * xf86ReadDomainMemory - copy from domain memory into a caller supplied buffer
 
708
 */
 
709
int
 
710
xf86ReadDomainMemory(PCITAG Tag, ADDRESS Base, int Len, unsigned char *Buf)
 
711
{
 
712
    unsigned char *ptr, *src;
 
713
    ADDRESS offset;
 
714
    unsigned long size;
 
715
    int len, pagemask = getpagesize() - 1;
 
716
 
 
717
    unsigned int i, dom, bus, dev, func;
 
718
    unsigned int fd;
 
719
    char file[256];
 
720
    struct stat st;
 
721
 
 
722
    dom  = PCI_DOM_FROM_TAG(Tag);
 
723
    bus  = PCI_BUS_FROM_TAG(Tag);
 
724
    dev  = PCI_DEV_FROM_TAG(Tag);
 
725
    func = PCI_FUNC_FROM_TAG(Tag);
 
726
    sprintf(file, "/sys/devices/pci%04x:%02x/%04x:%02x:%02x.%1x/rom",
 
727
            dom, bus, dom, bus, dev, func);
 
728
 
 
729
    /*
 
730
     * If the caller wants the ROM and the sysfs rom interface exists,
 
731
     * try to use it instead of reading it from /proc/bus/pci.
 
732
     */
 
733
    if (((Base & 0xfffff) == 0xC0000) && (stat(file, &st) == 0)) {
 
734
        if ((fd = open(file, O_RDWR)))
 
735
            Base = 0x0;
 
736
 
 
737
        /* enable the ROM first */
 
738
        write(fd, "1", 2);
 
739
        lseek(fd, 0, SEEK_SET);
 
740
 
 
741
        /* copy the ROM until we hit Len, EOF or read error */
 
742
        for (i = 0; i < Len && read(fd, Buf, 1) > 0; Buf++, i++)
 
743
            ;
 
744
 
 
745
        write(fd, "0", 2);
 
746
        close(fd);
 
747
 
 
748
        return Len;
 
749
    }
 
750
 
 
751
    /* Ensure page boundaries */
 
752
    offset = Base & ~pagemask;
 
753
    size = ((Base + Len + pagemask) & ~pagemask) - offset;
 
754
 
 
755
    ptr = xf86MapDomainMemory(-1, VIDMEM_READONLY, Tag, offset, size);
 
756
 
 
757
    if (!ptr)
 
758
        return -1;
 
759
 
 
760
    /* Using memcpy() here can hang the system */
 
761
    src = ptr + (Base - offset);
 
762
    for (len = Len;  len-- > 0;)
 
763
        *Buf++ = *src++;
 
764
 
 
765
    xf86UnMapVidMem(-1, ptr, size);
 
766
 
 
767
    return Len;
 
768
}
 
769
 
 
770
resPtr
 
771
xf86BusAccWindowsFromOS(void)
 
772
{
 
773
    pciConfigPtr  *ppPCI, pPCI;
 
774
    resPtr        pRes = NULL;
 
775
    resRange      range;
 
776
    unsigned long io_size, mem_size;
 
777
    int           domain;
 
778
 
 
779
    if ((ppPCI = xf86scanpci(0))) {
 
780
        for (;  (pPCI = *ppPCI);  ppPCI++) {
 
781
            if ((pPCI->pci_base_class != PCI_CLASS_BRIDGE) ||
 
782
                (pPCI->pci_sub_class  != PCI_SUBCLASS_BRIDGE_HOST))
 
783
                continue;
 
784
 
 
785
            domain = xf86GetPciDomain(pPCI->tag);
 
786
            linuxGetSizes(pPCI->tag, &io_size, &mem_size);
 
787
 
 
788
            RANGE(range, 0, (ADDRESS)(mem_size - 1),
 
789
                  RANGE_TYPE(ResExcMemBlock, domain));
 
790
            pRes = xf86AddResToList(pRes, &range, -1);
 
791
 
 
792
            RANGE(range, 0, (IOADDRESS)(io_size - 1),
 
793
                  RANGE_TYPE(ResExcIoBlock, domain));
 
794
            pRes = xf86AddResToList(pRes, &range, -1);
 
795
 
 
796
            if (domain <= 0)
 
797
                break;
 
798
        }
 
799
    }
 
800
 
 
801
    return pRes;
 
802
}
 
803
 
 
804
resPtr
 
805
xf86PciBusAccWindowsFromOS(void)
 
806
{
 
807
    pciConfigPtr  *ppPCI, pPCI;
 
808
    resPtr        pRes = NULL;
 
809
    resRange      range;
 
810
    unsigned long io_size, mem_size;
 
811
    int           domain;
 
812
 
 
813
    if ((ppPCI = xf86scanpci(0))) {
 
814
        for (;  (pPCI = *ppPCI);  ppPCI++) {
 
815
            if ((pPCI->pci_base_class != PCI_CLASS_BRIDGE) ||
 
816
                (pPCI->pci_sub_class  != PCI_SUBCLASS_BRIDGE_HOST))
 
817
                continue;
 
818
 
 
819
            domain = xf86GetPciDomain(pPCI->tag);
 
820
            linuxGetSizes(pPCI->tag, &io_size, &mem_size);
 
821
 
 
822
            RANGE(range, 0, (ADDRESS)(mem_size - 1),
 
823
                  RANGE_TYPE(ResExcMemBlock, domain));
 
824
            pRes = xf86AddResToList(pRes, &range, -1);
 
825
 
 
826
            RANGE(range, 0, (IOADDRESS)(io_size - 1),
 
827
                  RANGE_TYPE(ResExcIoBlock, domain));
 
828
            pRes = xf86AddResToList(pRes, &range, -1);
 
829
 
 
830
            if (domain <= 0)
 
831
                break;
 
832
        }
 
833
    }
 
834
 
 
835
    return pRes;
 
836
}
 
837
 
 
838
 
 
839
resPtr
 
840
xf86AccResFromOS(resPtr pRes)
 
841
{
 
842
    pciConfigPtr  *ppPCI, pPCI;
 
843
    resRange      range;
 
844
    unsigned long io_size, mem_size;
 
845
    int           domain;
 
846
 
 
847
    if ((ppPCI = xf86scanpci(0))) {
 
848
        for (;  (pPCI = *ppPCI);  ppPCI++) {
 
849
            if ((pPCI->pci_base_class != PCI_CLASS_BRIDGE) ||
 
850
                (pPCI->pci_sub_class  != PCI_SUBCLASS_BRIDGE_HOST))
 
851
                continue;
 
852
 
 
853
            domain = xf86GetPciDomain(pPCI->tag);
 
854
            linuxGetSizes(pPCI->tag, &io_size, &mem_size);
 
855
 
 
856
            /*
 
857
             * At minimum, the top and bottom resources must be claimed, so
 
858
             * that resources that are (or appear to be) unallocated can be
 
859
             * relocated.
 
860
             */
 
861
            RANGE(range, 0x00000000u, 0x0009ffffu,
 
862
                  RANGE_TYPE(ResExcMemBlock, domain));
 
863
            pRes = xf86AddResToList(pRes, &range, -1);
 
864
            RANGE(range, 0x000c0000u, 0x000effffu,
 
865
                  RANGE_TYPE(ResExcMemBlock, domain));
 
866
            pRes = xf86AddResToList(pRes, &range, -1);
 
867
            RANGE(range, 0x000f0000u, 0x000fffffu,
 
868
                  RANGE_TYPE(ResExcMemBlock, domain));
 
869
            pRes = xf86AddResToList(pRes, &range, -1);
 
870
 
 
871
            RANGE(range, (ADDRESS)(mem_size - 1), (ADDRESS)(mem_size - 1),
 
872
                  RANGE_TYPE(ResExcMemBlock, domain));
 
873
            pRes = xf86AddResToList(pRes, &range, -1);
 
874
 
 
875
            RANGE(range, 0x00000000u, 0x00000000u,
 
876
                  RANGE_TYPE(ResExcIoBlock, domain));
 
877
            pRes = xf86AddResToList(pRes, &range, -1);
 
878
            RANGE(range, (IOADDRESS)(io_size - 1), (IOADDRESS)(io_size - 1),
 
879
                  RANGE_TYPE(ResExcIoBlock, domain));
 
880
            pRes = xf86AddResToList(pRes, &range, -1);
 
881
 
 
882
            if (domain <= 0)
 
883
                break;
 
884
        }
 
885
    }
 
886
 
 
887
    return pRes;
 
888
}
 
889
 
 
890
#endif /* !INCLUDE_XF86_NO_DOMAIN */