1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
/*
* This file contains the glue necessary for support of SGI's Altix chipset.
*/
#include <stdio.h>
#include <unistd.h>
#include "altixPCI.h"
#include "xf86.h"
#include "Pci.h"
/*
* get_dev_on_bus - Return the first device we find on segnum, busnum
*
* Walk all the PCI devices and return the first one found on segnum, busnum.
* There may be a better way to do this in some xf86* function I don't know
* about.
*/
static pciDevice *get_dev_on_bus(unsigned int segnum, unsigned int busnum)
{
pciDevice **pdev = xf86scanpci(0);
int i;
for (i = 0; pdev[i] != NULL; i++)
if (PCI_DOM_FROM_TAG(pdev[i]->tag) == segnum &&
pdev[i]->busnum == busnum)
return pdev[i];
/* Should never get here... */
ErrorF("No PCI device found on %04x:%02x??", segnum, busnum);
return NULL;
}
/*
* get_bridge_info - fill in the bridge info for bus_info based on pdev
*
* Find the parent bus for pdev if it exists, otherwise assume pdev *is*
* the parent bus. We need this on Altix because our bridges are transparent.
*/
static void get_bridge_info(pciBusInfo_t *bus_info, pciDevice *pdev)
{
unsigned int parent_segnum, segnum = PCI_DOM_FROM_TAG(pdev->tag);
unsigned int parent_busnum, busnum = pdev->busnum;
char bridge_path[] = "/sys/class/pci_bus/0000:00/bridge";
char bridge_target[] = "../../../devices/pci0000:00";
/* Path to this device's bridge */
sprintf(bridge_path, "/sys/class/pci_bus/%04x:%02x/bridge", segnum,
busnum);
if (readlink(bridge_path, bridge_target, strlen(bridge_target)) < 0) {
perror("failed to dereference bridge link");
ErrorF("failed to dereference bridge link, aborting\n");
exit(-1);
}
sscanf(bridge_target, "../../../devices/pci%04x:%02x", &parent_segnum,
&parent_busnum);
/*
* If there's no bridge or the bridge points to the device, use
* pdev as the bridge
*/
if (segnum == parent_segnum && busnum == parent_busnum) {
bus_info->bridge = pdev;
bus_info->secondary = FALSE;
bus_info->primary_bus = busnum;
} else {
bus_info->bridge = get_dev_on_bus(parent_segnum,
parent_busnum);
bus_info->secondary = TRUE;
bus_info->primary_bus = parent_busnum;
}
pdev->businfo = bus_info;
pdev->pci_base_class = PCI_CLASS_DISPLAY;
pdev->pci_sub_class = PCI_SUBCLASS_PREHISTORIC_VGA;
}
void xf86PreScanAltix(void)
{
/* Nothing to see here... */
}
void xf86PostScanAltix(void)
{
pciConfigPtr *pdev;
pciBusInfo_t *bus_info;
int prevBusNum, curBusNum, idx;
/*
* Altix PCI bridges are invisible to userspace, so we make each device
* look like it's its own bridge unless it actually has a parent (as in
* the case of PCI to PCI bridges).
*/
bus_info = pciBusInfo[0];
pdev = xf86scanpci(0);
prevBusNum = curBusNum = pdev[0]->busnum;
bus_info = pciBusInfo[curBusNum];
bus_info->bridge = pdev[0];
bus_info->secondary = FALSE;
bus_info->primary_bus = curBusNum;
/* Walk all the PCI devices, assigning their bridge info */
for (idx = 0; pdev[idx] != NULL; idx++) {
if (pdev[idx]->busnum == prevBusNum)
continue; /* Already fixed up this bus */
curBusNum = pdev[idx]->busnum;
bus_info = pciBusInfo[curBusNum];
/*
* Fill in bus_info for pdev. The bridge field will either
* be pdev[idx] or a device on the parent bus.
*/
get_bridge_info(bus_info, pdev[idx]);
prevBusNum = curBusNum;
}
return;
}
|