/root/src/xen/xen/drivers/pci/pci.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * pci.c |
3 | | * |
4 | | * Architecture-independent PCI access functions. |
5 | | */ |
6 | | |
7 | | #include <xen/init.h> |
8 | | #include <xen/pci.h> |
9 | | #include <xen/pci_regs.h> |
10 | | |
11 | | int pci_find_cap_offset(u16 seg, u8 bus, u8 dev, u8 func, u8 cap) |
12 | 349 | { |
13 | 349 | u8 id; |
14 | 349 | int max_cap = 48; |
15 | 349 | u8 pos = PCI_CAPABILITY_LIST; |
16 | 349 | u16 status; |
17 | 349 | |
18 | 349 | status = pci_conf_read16(seg, bus, dev, func, PCI_STATUS); |
19 | 349 | if ( (status & PCI_STATUS_CAP_LIST) == 0 ) |
20 | 96 | return 0; |
21 | 349 | |
22 | 650 | while ( max_cap-- ) |
23 | 650 | { |
24 | 650 | pos = pci_conf_read8(seg, bus, dev, func, pos); |
25 | 650 | if ( pos < 0x40 ) |
26 | 110 | break; |
27 | 650 | |
28 | 540 | pos &= ~3; |
29 | 540 | id = pci_conf_read8(seg, bus, dev, func, pos + PCI_CAP_LIST_ID); |
30 | 540 | |
31 | 540 | if ( id == 0xff ) |
32 | 0 | break; |
33 | 540 | else if ( id == cap ) |
34 | 143 | return pos; |
35 | 540 | |
36 | 397 | pos += PCI_CAP_LIST_NEXT; |
37 | 397 | } |
38 | 253 | |
39 | 110 | return 0; |
40 | 253 | } |
41 | | |
42 | | int pci_find_next_cap(u16 seg, u8 bus, unsigned int devfn, u8 pos, int cap) |
43 | 0 | { |
44 | 0 | u8 id; |
45 | 0 | int ttl = 48; |
46 | 0 |
|
47 | 0 | while ( ttl-- ) |
48 | 0 | { |
49 | 0 | pos = pci_conf_read8(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos); |
50 | 0 | if ( pos < 0x40 ) |
51 | 0 | break; |
52 | 0 |
|
53 | 0 | pos &= ~3; |
54 | 0 | id = pci_conf_read8(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), |
55 | 0 | pos + PCI_CAP_LIST_ID); |
56 | 0 |
|
57 | 0 | if ( id == 0xff ) |
58 | 0 | break; |
59 | 0 | if ( id == cap ) |
60 | 0 | return pos; |
61 | 0 |
|
62 | 0 | pos += PCI_CAP_LIST_NEXT; |
63 | 0 | } |
64 | 0 | return 0; |
65 | 0 | } |
66 | | |
67 | | /** |
68 | | * pci_find_ext_capability - Find an extended capability |
69 | | * @seg/@bus/@devfn: PCI device to query |
70 | | * @cap: capability code |
71 | | * |
72 | | * Returns the address of the requested extended capability structure |
73 | | * within the device's PCI configuration space or 0 if the device does |
74 | | * not support it. |
75 | | */ |
76 | | int pci_find_ext_capability(int seg, int bus, int devfn, int cap) |
77 | 0 | { |
78 | 0 | return pci_find_next_ext_capability(seg, bus, devfn, 0, cap); |
79 | 0 | } |
80 | | |
81 | | /** |
82 | | * pci_find_next_ext_capability - Find another extended capability |
83 | | * @seg/@bus/@devfn: PCI device to query |
84 | | * @pos: starting position |
85 | | * @cap: capability code |
86 | | * |
87 | | * Returns the address of the requested extended capability structure |
88 | | * within the device's PCI configuration space or 0 if the device does |
89 | | * not support it. |
90 | | */ |
91 | | int pci_find_next_ext_capability(int seg, int bus, int devfn, int start, int cap) |
92 | 0 | { |
93 | 0 | u32 header; |
94 | 0 | int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */ |
95 | 0 | int pos = max(start, 0x100); |
96 | 0 |
|
97 | 0 | header = pci_conf_read32(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos); |
98 | 0 |
|
99 | 0 | /* |
100 | 0 | * If we have no capabilities, this is indicated by cap ID, |
101 | 0 | * cap version and next pointer all being 0. |
102 | 0 | */ |
103 | 0 | if ( (header == 0) || (header == -1) ) |
104 | 0 | return 0; |
105 | 0 | ASSERT(start != pos || PCI_EXT_CAP_ID(header) == cap); |
106 | 0 |
|
107 | 0 | while ( ttl-- > 0 ) { |
108 | 0 | if ( PCI_EXT_CAP_ID(header) == cap && pos != start ) |
109 | 0 | return pos; |
110 | 0 | pos = PCI_EXT_CAP_NEXT(header); |
111 | 0 | if ( pos < 0x100 ) |
112 | 0 | break; |
113 | 0 | header = pci_conf_read32(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos); |
114 | 0 | } |
115 | 0 | return 0; |
116 | 0 | } |
117 | | |
118 | | const char *__init parse_pci(const char *s, unsigned int *seg_p, |
119 | | unsigned int *bus_p, unsigned int *dev_p, |
120 | | unsigned int *func_p) |
121 | 0 | { |
122 | 0 | bool def_seg; |
123 | 0 |
|
124 | 0 | return parse_pci_seg(s, seg_p, bus_p, dev_p, func_p, &def_seg); |
125 | 0 | } |
126 | | |
127 | | const char *__init parse_pci_seg(const char *s, unsigned int *seg_p, |
128 | | unsigned int *bus_p, unsigned int *dev_p, |
129 | | unsigned int *func_p, bool *def_seg) |
130 | 0 | { |
131 | 0 | unsigned long seg = simple_strtoul(s, &s, 16), bus, dev, func; |
132 | 0 |
|
133 | 0 | if ( *s != ':' ) |
134 | 0 | return NULL; |
135 | 0 | bus = simple_strtoul(s + 1, &s, 16); |
136 | 0 | *def_seg = false; |
137 | 0 | if ( *s == ':' ) |
138 | 0 | dev = simple_strtoul(s + 1, &s, 16); |
139 | 0 | else |
140 | 0 | { |
141 | 0 | dev = bus; |
142 | 0 | bus = seg; |
143 | 0 | seg = 0; |
144 | 0 | *def_seg = true; |
145 | 0 | } |
146 | 0 | if ( func_p ) |
147 | 0 | { |
148 | 0 | if ( *s != '.' ) |
149 | 0 | return NULL; |
150 | 0 | func = simple_strtoul(s + 1, &s, 0); |
151 | 0 | } |
152 | 0 | else |
153 | 0 | func = 0; |
154 | 0 | if ( seg != (seg_p ? (u16)seg : 0) || |
155 | 0 | bus != PCI_BUS(PCI_BDF2(bus, 0)) || |
156 | 0 | dev != PCI_SLOT(PCI_DEVFN(dev, 0)) || |
157 | 0 | func != PCI_FUNC(PCI_DEVFN(0, func)) ) |
158 | 0 | return NULL; |
159 | 0 |
|
160 | 0 | if ( seg_p ) |
161 | 0 | *seg_p = seg; |
162 | 0 | *bus_p = bus; |
163 | 0 | *dev_p = dev; |
164 | 0 | if ( func_p ) |
165 | 0 | *func_p = func; |
166 | 0 |
|
167 | 0 | return s; |
168 | 0 | } |