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(PCI_SBDF(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(PCI_SBDF(seg, bus, dev, func), pos);
25 if ( pos < 0x40 )
26 break;
27
28 pos &= ~3;
29 id = pci_conf_read8(PCI_SBDF(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(PCI_SBDF3(seg, bus, devfn), pos);
50 if ( pos < 0x40 )
51 break;
52
53 pos &= ~3;
54 id = pci_conf_read8(PCI_SBDF3(seg, bus, devfn), pos + PCI_CAP_LIST_ID);
55
56 if ( id == 0xff )
57 break;
58 if ( id == cap )
59 return pos;
60
61 pos += PCI_CAP_LIST_NEXT;
62 }
63 return 0;
64 }
65
66 /**
67 * pci_find_ext_capability - Find an extended capability
68 * @seg/@bus/@devfn: PCI device to query
69 * @cap: capability code
70 *
71 * Returns the address of the requested extended capability structure
72 * within the device's PCI configuration space or 0 if the device does
73 * not support it.
74 */
pci_find_ext_capability(int seg,int bus,int devfn,int cap)75 int pci_find_ext_capability(int seg, int bus, int devfn, int cap)
76 {
77 return pci_find_next_ext_capability(seg, bus, devfn, 0, cap);
78 }
79
80 /**
81 * pci_find_next_ext_capability - Find another extended capability
82 * @seg/@bus/@devfn: PCI device to query
83 * @pos: starting position
84 * @cap: capability code
85 *
86 * Returns the address of the requested extended capability structure
87 * within the device's PCI configuration space or 0 if the device does
88 * not support it.
89 */
pci_find_next_ext_capability(int seg,int bus,int devfn,int start,int cap)90 int pci_find_next_ext_capability(int seg, int bus, int devfn, int start, int cap)
91 {
92 u32 header;
93 int ttl = 480; /* 3840 bytes, minimum 8 bytes per capability */
94 int pos = max(start, 0x100);
95
96 header = pci_conf_read32(PCI_SBDF3(seg, bus, devfn), pos);
97
98 /*
99 * If we have no capabilities, this is indicated by cap ID,
100 * cap version and next pointer all being 0.
101 */
102 if ( (header == 0) || (header == -1) )
103 return 0;
104 ASSERT(start != pos || PCI_EXT_CAP_ID(header) == cap);
105
106 while ( ttl-- > 0 ) {
107 if ( PCI_EXT_CAP_ID(header) == cap && pos != start )
108 return pos;
109 pos = PCI_EXT_CAP_NEXT(header);
110 if ( pos < 0x100 )
111 break;
112 header = pci_conf_read32(PCI_SBDF3(seg, bus, devfn), pos);
113 }
114 return 0;
115 }
116
pci_intx(const struct pci_dev * pdev,bool enable)117 void pci_intx(const struct pci_dev *pdev, bool enable)
118 {
119 uint16_t cmd = pci_conf_read16(pdev->sbdf, PCI_COMMAND);
120
121 if ( enable )
122 cmd &= ~PCI_COMMAND_INTX_DISABLE;
123 else
124 cmd |= PCI_COMMAND_INTX_DISABLE;
125 pci_conf_write16(pdev->sbdf, PCI_COMMAND, cmd);
126 }
127
parse_pci(const char * s,unsigned int * seg_p,unsigned int * bus_p,unsigned int * dev_p,unsigned int * func_p)128 const char *__init parse_pci(const char *s, unsigned int *seg_p,
129 unsigned int *bus_p, unsigned int *dev_p,
130 unsigned int *func_p)
131 {
132 bool def_seg;
133
134 return parse_pci_seg(s, seg_p, bus_p, dev_p, func_p, &def_seg);
135 }
136
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)137 const char *__init parse_pci_seg(const char *s, unsigned int *seg_p,
138 unsigned int *bus_p, unsigned int *dev_p,
139 unsigned int *func_p, bool *def_seg)
140 {
141 unsigned long seg = simple_strtoul(s, &s, 16), bus, dev, func;
142
143 if ( *s != ':' )
144 return NULL;
145 bus = simple_strtoul(s + 1, &s, 16);
146 *def_seg = false;
147 if ( *s == ':' )
148 dev = simple_strtoul(s + 1, &s, 16);
149 else
150 {
151 dev = bus;
152 bus = seg;
153 seg = 0;
154 *def_seg = true;
155 }
156 if ( func_p )
157 {
158 if ( *s != '.' )
159 return NULL;
160 func = simple_strtoul(s + 1, &s, 0);
161 }
162 else
163 func = 0;
164 if ( seg != (seg_p ? (u16)seg : 0) ||
165 bus != PCI_BUS(PCI_BDF2(bus, 0)) ||
166 dev != PCI_SLOT(PCI_DEVFN(dev, 0)) ||
167 func != PCI_FUNC(PCI_DEVFN(0, func)) )
168 return NULL;
169
170 if ( seg_p )
171 *seg_p = seg;
172 *bus_p = bus;
173 *dev_p = dev;
174 if ( func_p )
175 *func_p = func;
176
177 return s;
178 }
179