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
pci_find_cap_offset(u16 seg,u8 bus,u8 dev,u8 func,u8 cap)11 int pci_find_cap_offset(u16 seg, u8 bus, u8 dev, u8 func, u8 cap)
12 {
13 u8 id;
14 int max_cap = 48;
15 u8 pos = PCI_CAPABILITY_LIST;
16 u16 status;
17
18 status = pci_conf_read16(seg, bus, dev, func, PCI_STATUS);
19 if ( (status & PCI_STATUS_CAP_LIST) == 0 )
20 return 0;
21
22 while ( max_cap-- )
23 {
24 pos = pci_conf_read8(seg, bus, dev, func, pos);
25 if ( pos < 0x40 )
26 break;
27
28 pos &= ~3;
29 id = pci_conf_read8(seg, bus, dev, func, pos + PCI_CAP_LIST_ID);
30
31 if ( id == 0xff )
32 break;
33 else if ( id == cap )
34 return pos;
35
36 pos += PCI_CAP_LIST_NEXT;
37 }
38
39 return 0;
40 }
41
pci_find_next_cap(u16 seg,u8 bus,unsigned int devfn,u8 pos,int cap)42 int pci_find_next_cap(u16 seg, u8 bus, unsigned int devfn, u8 pos, int cap)
43 {
44 u8 id;
45 int ttl = 48;
46
47 while ( ttl-- )
48 {
49 pos = pci_conf_read8(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
50 if ( pos < 0x40 )
51 break;
52
53 pos &= ~3;
54 id = pci_conf_read8(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
55 pos + PCI_CAP_LIST_ID);
56
57 if ( id == 0xff )
58 break;
59 if ( id == cap )
60 return pos;
61
62 pos += PCI_CAP_LIST_NEXT;
63 }
64 return 0;
65 }
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 */
pci_find_ext_capability(int seg,int bus,int devfn,int cap)76 int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
77 {
78 return pci_find_next_ext_capability(seg, bus, devfn, 0, cap);
79 }
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 */
pci_find_next_ext_capability(int seg,int bus,int devfn,int start,int cap)91 int pci_find_next_ext_capability(int seg, int bus, int devfn, int start, int cap)
92 {
93 u32 header;
94 int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */
95 int pos = max(start, 0x100);
96
97 header = pci_conf_read32(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
98
99 /*
100 * If we have no capabilities, this is indicated by cap ID,
101 * cap version and next pointer all being 0.
102 */
103 if ( (header == 0) || (header == -1) )
104 return 0;
105 ASSERT(start != pos || PCI_EXT_CAP_ID(header) == cap);
106
107 while ( ttl-- > 0 ) {
108 if ( PCI_EXT_CAP_ID(header) == cap && pos != start )
109 return pos;
110 pos = PCI_EXT_CAP_NEXT(header);
111 if ( pos < 0x100 )
112 break;
113 header = pci_conf_read32(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), pos);
114 }
115 return 0;
116 }
117
parse_pci(const char * s,unsigned int * seg_p,unsigned int * bus_p,unsigned int * dev_p,unsigned int * func_p)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 {
122 bool def_seg;
123
124 return parse_pci_seg(s, seg_p, bus_p, dev_p, func_p, &def_seg);
125 }
126
parse_pci_seg(const char * s,unsigned int * seg_p,unsigned int * bus_p,unsigned int * dev_p,unsigned int * func_p,bool * def_seg)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 {
131 unsigned long seg = simple_strtoul(s, &s, 16), bus, dev, func;
132
133 if ( *s != ':' )
134 return NULL;
135 bus = simple_strtoul(s + 1, &s, 16);
136 *def_seg = false;
137 if ( *s == ':' )
138 dev = simple_strtoul(s + 1, &s, 16);
139 else
140 {
141 dev = bus;
142 bus = seg;
143 seg = 0;
144 *def_seg = true;
145 }
146 if ( func_p )
147 {
148 if ( *s != '.' )
149 return NULL;
150 func = simple_strtoul(s + 1, &s, 0);
151 }
152 else
153 func = 0;
154 if ( seg != (seg_p ? (u16)seg : 0) ||
155 bus != PCI_BUS(PCI_BDF2(bus, 0)) ||
156 dev != PCI_SLOT(PCI_DEVFN(dev, 0)) ||
157 func != PCI_FUNC(PCI_DEVFN(0, func)) )
158 return NULL;
159
160 if ( seg_p )
161 *seg_p = seg;
162 *bus_p = bus;
163 *dev_p = dev;
164 if ( func_p )
165 *func_p = func;
166
167 return s;
168 }
169