Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/xtensa/lib/pci-auto.c
10817 views
1
/*
2
* arch/xtensa/lib/pci-auto.c
3
*
4
* PCI autoconfiguration library
5
*
6
* Copyright (C) 2001 - 2005 Tensilica Inc.
7
*
8
* Chris Zankel <[email protected], [email protected]>
9
*
10
* Based on work from Matt Porter <[email protected]>
11
*
12
* This program is free software; you can redistribute it and/or modify it
13
* under the terms of the GNU General Public License as published by the
14
* Free Software Foundation; either version 2 of the License, or (at your
15
* option) any later version.
16
*/
17
18
#include <linux/kernel.h>
19
#include <linux/init.h>
20
#include <linux/pci.h>
21
22
#include <asm/pci-bridge.h>
23
24
25
/*
26
*
27
* Setting up a PCI
28
*
29
* pci_ctrl->first_busno = <first bus number (0)>
30
* pci_ctrl->last_busno = <last bus number (0xff)>
31
* pci_ctrl->ops = <PCI config operations>
32
* pci_ctrl->map_irq = <function to return the interrupt number for a device>
33
*
34
* pci_ctrl->io_space.start = <IO space start address (PCI view)>
35
* pci_ctrl->io_space.end = <IO space end address (PCI view)>
36
* pci_ctrl->io_space.base = <IO space offset: address 0 from CPU space>
37
* pci_ctrl->mem_space.start = <MEM space start address (PCI view)>
38
* pci_ctrl->mem_space.end = <MEM space end address (PCI view)>
39
* pci_ctrl->mem_space.base = <MEM space offset: address 0 from CPU space>
40
*
41
* pcibios_init_resource(&pci_ctrl->io_resource, <IO space start>,
42
* <IO space end>, IORESOURCE_IO, "PCI host bridge");
43
* pcibios_init_resource(&pci_ctrl->mem_resources[0], <MEM space start>,
44
* <MEM space end>, IORESOURCE_MEM, "PCI host bridge");
45
*
46
* pci_ctrl->last_busno = pciauto_bus_scan(pci_ctrl,pci_ctrl->first_busno);
47
*
48
* int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
49
*
50
*/
51
52
53
/* define DEBUG to print some debugging messages. */
54
55
#undef DEBUG
56
57
#ifdef DEBUG
58
# define DBG(x...) printk(x)
59
#else
60
# define DBG(x...)
61
#endif
62
63
static int pciauto_upper_iospc;
64
static int pciauto_upper_memspc;
65
66
static struct pci_dev pciauto_dev;
67
static struct pci_bus pciauto_bus;
68
69
/*
70
* Helper functions
71
*/
72
73
/* Initialize the bars of a PCI device. */
74
75
static void __init
76
pciauto_setup_bars(struct pci_dev *dev, int bar_limit)
77
{
78
int bar_size;
79
int bar, bar_nr;
80
int *upper_limit;
81
int found_mem64 = 0;
82
83
for (bar = PCI_BASE_ADDRESS_0, bar_nr = 0;
84
bar <= bar_limit;
85
bar+=4, bar_nr++)
86
{
87
/* Tickle the BAR and get the size */
88
pci_write_config_dword(dev, bar, 0xffffffff);
89
pci_read_config_dword(dev, bar, &bar_size);
90
91
/* If BAR is not implemented go to the next BAR */
92
if (!bar_size)
93
continue;
94
95
/* Check the BAR type and set our address mask */
96
if (bar_size & PCI_BASE_ADDRESS_SPACE_IO)
97
{
98
bar_size &= PCI_BASE_ADDRESS_IO_MASK;
99
upper_limit = &pciauto_upper_iospc;
100
DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr);
101
}
102
else
103
{
104
if ((bar_size & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
105
PCI_BASE_ADDRESS_MEM_TYPE_64)
106
found_mem64 = 1;
107
108
bar_size &= PCI_BASE_ADDRESS_MEM_MASK;
109
upper_limit = &pciauto_upper_memspc;
110
DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr);
111
}
112
113
/* Allocate a base address (bar_size is negative!) */
114
*upper_limit = (*upper_limit + bar_size) & bar_size;
115
116
/* Write it out and update our limit */
117
pci_write_config_dword(dev, bar, *upper_limit);
118
119
/*
120
* If we are a 64-bit decoder then increment to the
121
* upper 32 bits of the bar and force it to locate
122
* in the lower 4GB of memory.
123
*/
124
125
if (found_mem64)
126
pci_write_config_dword(dev, (bar+=4), 0x00000000);
127
128
DBG("size=0x%x, address=0x%x\n", ~bar_size + 1, *upper_limit);
129
}
130
}
131
132
/* Initialize the interrupt number. */
133
134
static void __init
135
pciauto_setup_irq(struct pci_controller* pci_ctrl,struct pci_dev *dev,int devfn)
136
{
137
u8 pin;
138
int irq = 0;
139
140
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
141
142
/* Fix illegal pin numbers. */
143
144
if (pin == 0 || pin > 4)
145
pin = 1;
146
147
if (pci_ctrl->map_irq)
148
irq = pci_ctrl->map_irq(dev, PCI_SLOT(devfn), pin);
149
150
if (irq == -1)
151
irq = 0;
152
153
DBG("PCI Autoconfig: Interrupt %d, pin %d\n", irq, pin);
154
155
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
156
}
157
158
159
static void __init
160
pciauto_prescan_setup_bridge(struct pci_dev *dev, int current_bus,
161
int sub_bus, int *iosave, int *memsave)
162
{
163
/* Configure bus number registers */
164
pci_write_config_byte(dev, PCI_PRIMARY_BUS, current_bus);
165
pci_write_config_byte(dev, PCI_SECONDARY_BUS, sub_bus + 1);
166
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, 0xff);
167
168
/* Round memory allocator to 1MB boundary */
169
pciauto_upper_memspc &= ~(0x100000 - 1);
170
*memsave = pciauto_upper_memspc;
171
172
/* Round I/O allocator to 4KB boundary */
173
pciauto_upper_iospc &= ~(0x1000 - 1);
174
*iosave = pciauto_upper_iospc;
175
176
/* Set up memory and I/O filter limits, assume 32-bit I/O space */
177
pci_write_config_word(dev, PCI_MEMORY_LIMIT,
178
((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
179
pci_write_config_byte(dev, PCI_IO_LIMIT,
180
((pciauto_upper_iospc - 1) & 0x0000f000) >> 8);
181
pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16,
182
((pciauto_upper_iospc - 1) & 0xffff0000) >> 16);
183
}
184
185
static void __init
186
pciauto_postscan_setup_bridge(struct pci_dev *dev, int current_bus, int sub_bus,
187
int *iosave, int *memsave)
188
{
189
int cmdstat;
190
191
/* Configure bus number registers */
192
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, sub_bus);
193
194
/*
195
* Round memory allocator to 1MB boundary.
196
* If no space used, allocate minimum.
197
*/
198
pciauto_upper_memspc &= ~(0x100000 - 1);
199
if (*memsave == pciauto_upper_memspc)
200
pciauto_upper_memspc -= 0x00100000;
201
202
pci_write_config_word(dev, PCI_MEMORY_BASE, pciauto_upper_memspc >> 16);
203
204
/* Allocate 1MB for pre-fretch */
205
pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT,
206
((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
207
208
pciauto_upper_memspc -= 0x100000;
209
210
pci_write_config_word(dev, PCI_PREF_MEMORY_BASE,
211
pciauto_upper_memspc >> 16);
212
213
/* Round I/O allocator to 4KB boundary */
214
pciauto_upper_iospc &= ~(0x1000 - 1);
215
if (*iosave == pciauto_upper_iospc)
216
pciauto_upper_iospc -= 0x1000;
217
218
pci_write_config_byte(dev, PCI_IO_BASE,
219
(pciauto_upper_iospc & 0x0000f000) >> 8);
220
pci_write_config_word(dev, PCI_IO_BASE_UPPER16,
221
pciauto_upper_iospc >> 16);
222
223
/* Enable memory and I/O accesses, enable bus master */
224
pci_read_config_dword(dev, PCI_COMMAND, &cmdstat);
225
pci_write_config_dword(dev, PCI_COMMAND,
226
cmdstat |
227
PCI_COMMAND_IO |
228
PCI_COMMAND_MEMORY |
229
PCI_COMMAND_MASTER);
230
}
231
232
/*
233
* Scan the current PCI bus.
234
*/
235
236
237
int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
238
{
239
int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0;
240
unsigned short vid;
241
unsigned char header_type;
242
struct pci_dev *dev = &pciauto_dev;
243
244
pciauto_dev.bus = &pciauto_bus;
245
pciauto_dev.sysdata = pci_ctrl;
246
pciauto_bus.ops = pci_ctrl->ops;
247
248
/*
249
* Fetch our I/O and memory space upper boundaries used
250
* to allocated base addresses on this pci_controller.
251
*/
252
253
if (current_bus == pci_ctrl->first_busno)
254
{
255
pciauto_upper_iospc = pci_ctrl->io_resource.end + 1;
256
pciauto_upper_memspc = pci_ctrl->mem_resources[0].end + 1;
257
}
258
259
sub_bus = current_bus;
260
261
for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++)
262
{
263
/* Skip our host bridge */
264
if ((current_bus == pci_ctrl->first_busno) && (pci_devfn == 0))
265
continue;
266
267
if (PCI_FUNC(pci_devfn) && !found_multi)
268
continue;
269
270
pciauto_bus.number = current_bus;
271
pciauto_dev.devfn = pci_devfn;
272
273
/* If config space read fails from this device, move on */
274
if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type))
275
continue;
276
277
if (!PCI_FUNC(pci_devfn))
278
found_multi = header_type & 0x80;
279
pci_read_config_word(dev, PCI_VENDOR_ID, &vid);
280
281
if (vid == 0xffff || vid == 0x0000) {
282
found_multi = 0;
283
continue;
284
}
285
286
pci_read_config_dword(dev, PCI_CLASS_REVISION, &pci_class);
287
288
if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) {
289
290
int iosave, memsave;
291
292
DBG("PCI Autoconfig: Found P2P bridge, device %d\n",
293
PCI_SLOT(pci_devfn));
294
295
/* Allocate PCI I/O and/or memory space */
296
pciauto_setup_bars(dev, PCI_BASE_ADDRESS_1);
297
298
pciauto_prescan_setup_bridge(dev, current_bus, sub_bus,
299
&iosave, &memsave);
300
sub_bus = pciauto_bus_scan(pci_ctrl, sub_bus+1);
301
pciauto_postscan_setup_bridge(dev, current_bus, sub_bus,
302
&iosave, &memsave);
303
pciauto_bus.number = current_bus;
304
305
continue;
306
307
}
308
309
310
#if 0
311
/* Skip legacy mode IDE controller */
312
313
if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
314
315
unsigned char prg_iface;
316
pci_read_config_byte(dev, PCI_CLASS_PROG, &prg_iface);
317
318
if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
319
DBG("PCI Autoconfig: Skipping legacy mode "
320
"IDE controller\n");
321
continue;
322
}
323
}
324
#endif
325
326
/*
327
* Found a peripheral, enable some standard
328
* settings
329
*/
330
331
pci_read_config_dword(dev, PCI_COMMAND, &cmdstat);
332
pci_write_config_dword(dev, PCI_COMMAND,
333
cmdstat |
334
PCI_COMMAND_IO |
335
PCI_COMMAND_MEMORY |
336
PCI_COMMAND_MASTER);
337
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
338
339
/* Allocate PCI I/O and/or memory space */
340
DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n",
341
current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) );
342
343
pciauto_setup_bars(dev, PCI_BASE_ADDRESS_5);
344
pciauto_setup_irq(pci_ctrl, dev, pci_devfn);
345
}
346
return sub_bus;
347
}
348
349
350
351
352
353
354