blob: 87aac3b6fc01746962be25bf24ffa50b950b1e27 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2009 Corey Tabaka
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23#include <debug.h>
24#include <err.h>
25#include <stdlib.h>
26#include <string.h>
27#include <kernel/thread.h>
28#include <kernel/spinlock.h>
29#include <arch/x86/descriptor.h>
30#include <dev/pci.h>
31
32static int last_bus = 0;
33static spin_lock_t lock;
34
35typedef struct {
36 uint16_t size;
37 void *offset;
38 uint16_t selector;
39} __PACKED irq_routing_options_t;
40
41static int pci_type1_detect(void);
42static int pci_bios_detect(void);
43
44int pci_get_last_bus(void)
45{
46 return last_bus;
47}
48
49/*
50 * pointers to installed PCI routines
51 */
52int (*g_pci_find_pci_device)(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index);
53int (*g_pci_find_pci_class_code)(pci_location_t *state, uint32_t class_code, uint16_t index);
54
55int (*g_pci_read_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t *value);
56int (*g_pci_read_config_half)(const pci_location_t *state, uint32_t reg, uint16_t *value);
57int (*g_pci_read_config_word)(const pci_location_t *state, uint32_t reg, uint32_t *value);
58
59int (*g_pci_write_config_byte)(const pci_location_t *state, uint32_t reg, uint8_t value);
60int (*g_pci_write_config_half)(const pci_location_t *state, uint32_t reg, uint16_t value);
61int (*g_pci_write_config_word)(const pci_location_t *state, uint32_t reg, uint32_t value);
62
63int (*g_pci_get_irq_routing_options)(irq_routing_options_t *options, uint16_t *pci_irqs);
64int (*g_pci_set_irq_hw_int)(const pci_location_t *state, uint8_t int_pin, uint8_t irq);
65
66
67int pci_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index)
68{
69 spin_lock_saved_state_t irqstate;
70 spin_lock_irqsave(&lock, irqstate);
71
72 int res = g_pci_find_pci_device(state, device_id, vendor_id, index);
73
74 spin_unlock_irqrestore(&lock, irqstate);
75
76 return res;
77}
78
79int pci_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index)
80{
81 spin_lock_saved_state_t irqstate;
82 spin_lock_irqsave(&lock, irqstate);
83
84 int res = g_pci_find_pci_class_code(state, class_code, index);
85
86 spin_unlock_irqrestore(&lock, irqstate);
87
88 return res;
89}
90
91int pci_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value)
92{
93 spin_lock_saved_state_t irqstate;
94 spin_lock_irqsave(&lock, irqstate);
95
96 int res = g_pci_read_config_byte(state, reg, value);
97
98 spin_unlock_irqrestore(&lock, irqstate);
99
100 return res;
101}
102int pci_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value)
103{
104 spin_lock_saved_state_t irqstate;
105 spin_lock_irqsave(&lock, irqstate);
106
107 int res = g_pci_read_config_half(state, reg, value);
108
109 spin_unlock_irqrestore(&lock, irqstate);
110
111 return res;
112}
113
114int pci_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value)
115{
116 spin_lock_saved_state_t irqstate;
117 spin_lock_irqsave(&lock, irqstate);
118
119 int res = g_pci_read_config_word(state, reg, value);
120
121 spin_unlock_irqrestore(&lock, irqstate);
122
123 return res;
124}
125
126int pci_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value)
127{
128 spin_lock_saved_state_t irqstate;
129 spin_lock_irqsave(&lock, irqstate);
130
131 int res = g_pci_write_config_byte(state, reg, value);
132
133 spin_unlock_irqrestore(&lock, irqstate);
134
135 return res;
136}
137
138int pci_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value)
139{
140 spin_lock_saved_state_t irqstate;
141 spin_lock_irqsave(&lock, irqstate);
142
143 int res = g_pci_write_config_half(state, reg, value);
144
145 spin_unlock_irqrestore(&lock, irqstate);
146
147 return res;
148}
149
150int pci_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value)
151{
152 spin_lock_saved_state_t irqstate;
153 spin_lock_irqsave(&lock, irqstate);
154
155 int res = g_pci_write_config_word(state, reg, value);
156
157 spin_unlock_irqrestore(&lock, irqstate);
158
159 return res;
160}
161
162
163int pci_get_irq_routing_options(irq_routing_entry *entries, uint16_t *count, uint16_t *pci_irqs)
164{
165 irq_routing_options_t options;
166 options.size = sizeof(irq_routing_entry) **count;
167 options.selector = DATA_SELECTOR;
168 options.offset = entries;
169
170 spin_lock_saved_state_t irqstate;
171 spin_lock_irqsave(&lock, irqstate);
172
173 int res = g_pci_get_irq_routing_options(&options, pci_irqs);
174
175 spin_unlock_irqrestore(&lock, irqstate);
176
177 *count = options.size / sizeof(irq_routing_entry);
178
179 return res;
180}
181
182int pci_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq)
183{
184 spin_lock_saved_state_t irqstate;
185 spin_lock_irqsave(&lock, irqstate);
186
187 int res = g_pci_set_irq_hw_int(state, int_pin, irq);
188
189 spin_unlock_irqrestore(&lock, irqstate);
190
191 return res;
192}
193
194void pci_init(void)
195{
196 if (!pci_bios_detect()) {
197 dprintf(INFO, "pci bios functions installed\n");
198 dprintf(INFO, "last pci bus is %d\n", last_bus);
199 }
200}
201
202#define PCIBIOS_PRESENT 0xB101
203#define PCIBIOS_FIND_PCI_DEVICE 0xB102
204#define PCIBIOS_FIND_PCI_CLASS_CODE 0xB103
205#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xB106
206#define PCIBIOS_READ_CONFIG_BYTE 0xB108
207#define PCIBIOS_READ_CONFIG_WORD 0xB109
208#define PCIBIOS_READ_CONFIG_DWORD 0xB10A
209#define PCIBIOS_WRITE_CONFIG_BYTE 0xB10B
210#define PCIBIOS_WRITE_CONFIG_WORD 0xB10C
211#define PCIBIOS_WRITE_CONFIG_DWORD 0xB10D
212#define PCIBIOS_GET_IRQ_ROUTING_OPTIONS 0xB10E
213#define PCIBIOS_PCI_SET_IRQ_HW_INT 0xB10F
214
215#define PCIBIOS_SUCCESSFUL 0x00
216#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81
217#define PCIBIOS_BAD_VENDOR_ID 0x83
218#define PCIBIOS_DEVICE_NOT_FOUND 0x86
219#define PCIBIOS_BAD_REGISTER_NUMBER 0x87
220#define PCIBIOS_SET_FAILED 0x88
221#define PCIBIOS_BUFFER_TOO_SMALL 0x89
222
223/*
224 * far call structure used by BIOS32 routines
225 */
226static struct {
227 uint32_t offset;
228 uint16_t selector;
229} __PACKED bios32_entry;
230
231/*
232 * BIOS32 entry header
233 */
234typedef struct {
235 uint8_t magic[4]; // "_32_"
236 void * entry; // entry point
237 uint8_t revision;
238 uint8_t length;
239 uint8_t checksum;
240 uint8_t reserved[5];
241} __PACKED pci_bios_info;
242
243/*
244 * scan for pci bios
245 */
246static const char * pci_bios_magic = "_32_";
247static pci_bios_info *find_pci_bios_info(void)
248{
249 uint32_t *head = (uint32_t *) 0x000e0000;
250 int8_t sum, *b;
251 uint i;
252
253 while (head < (uint32_t *) 0x000ffff0) {
254 if (*head == *(uint32_t *) pci_bios_magic) {
255 // perform the checksum
256 sum = 0;
257 b = (int8_t *) head;
258 for (i=0; i < sizeof(pci_bios_info); i++) {
259 sum += b[i];
260 }
261
262 if (sum == 0) {
263 return (pci_bios_info *) head;
264 }
265 }
266
267 head += 4;
268 }
269
270 return NULL;
271}
272
273/*
274 * local BIOS32 PCI routines
275 */
276static int bios_find_pci_device(pci_location_t *state, uint16_t device_id, uint16_t vendor_id, uint16_t index)
277{
278 uint32_t bx, ret;
279
280 __asm__(
281 "lcall *(%%edi) \n\t"
282 "jc 1f \n\t"
283 "xor %%ah,%%ah \n"
284 "1:"
285 : "=b"(bx),
286 "=a"(ret)
287 : "1"(PCIBIOS_FIND_PCI_DEVICE),
288 "c"(device_id),
289 "d"(vendor_id),
290 "S"(index),
291 "D"(&bios32_entry));
292
293 state->bus = bx >> 8;
294 state->dev_fn = bx & 0xFF;
295
296 ret >>= 8;
297 return ret & 0xFF;
298}
299
300static int bios_find_pci_class_code(pci_location_t *state, uint32_t class_code, uint16_t index)
301{
302 uint32_t bx, ret;
303
304 __asm__(
305 "lcall *(%%edi) \n\t"
306 "jc 1f \n\t"
307 "xor %%ah,%%ah \n"
308 "1:"
309 : "=b"(bx),
310 "=a"(ret)
311 : "1"(PCIBIOS_FIND_PCI_CLASS_CODE),
312 "c"(class_code),
313 "S"(index),
314 "D"(&bios32_entry));
315
316 state->bus = bx >> 8;
317 state->dev_fn = bx & 0xFF;
318
319 ret >>= 8;
320 return ret & 0xFF;
321}
322
323
324static int bios_read_config_byte(const pci_location_t *state, uint32_t reg, uint8_t *value)
325{
326 uint32_t bx, ret;
327
328 bx = state->bus;
329 bx <<= 8;
330 bx |= state->dev_fn;
331 __asm__(
332 "lcall *(%%esi) \n\t"
333 "jc 1f \n\t"
334 "xor %%ah,%%ah \n"
335 "1:"
336 : "=c"(*value),
337 "=a"(ret)
338 : "1"(PCIBIOS_READ_CONFIG_BYTE),
339 "b"(bx),
340 "D"(reg),
341 "S"(&bios32_entry));
342 ret >>= 8;
343 return ret & 0xFF;
344}
345
346static int bios_read_config_half(const pci_location_t *state, uint32_t reg, uint16_t *value)
347{
348 uint32_t bx, ret;
349
350 bx = state->bus;
351 bx <<= 8;
352 bx |= state->dev_fn;
353 __asm__(
354 "lcall *(%%esi) \n\t"
355 "jc 1f \n\t"
356 "xor %%ah,%%ah \n"
357 "1:"
358 : "=c"(*value),
359 "=a"(ret)
360 : "1"(PCIBIOS_READ_CONFIG_WORD),
361 "b"(bx),
362 "D"(reg),
363 "S"(&bios32_entry));
364 ret >>= 8;
365 return ret & 0xFF;
366}
367
368static int bios_read_config_word(const pci_location_t *state, uint32_t reg, uint32_t *value)
369{
370 uint32_t bx, ret;
371
372 bx = state->bus;
373 bx <<= 8;
374 bx |= state->dev_fn;
375 __asm__(
376 "lcall *(%%esi) \n\t"
377 "jc 1f \n\t"
378 "xor %%ah,%%ah \n"
379 "1:"
380 : "=c"(*value),
381 "=a"(ret)
382 : "1"(PCIBIOS_READ_CONFIG_DWORD),
383 "b"(bx),
384 "D"(reg),
385 "S"(&bios32_entry));
386 ret >>= 8;
387 return ret & 0xFF;
388}
389
390static int bios_write_config_byte(const pci_location_t *state, uint32_t reg, uint8_t value)
391{
392 uint32_t bx, ret;
393
394 bx = state->bus;
395 bx <<= 8;
396 bx |= state->dev_fn;
397 __asm__(
398 "lcall *(%%esi) \n\t"
399 "jc 1f \n\t"
400 "xor %%ah,%%ah \n"
401 "1:"
402 : "=a"(ret)
403 : "0"(PCIBIOS_WRITE_CONFIG_BYTE),
404 "c"(value),
405 "b"(bx),
406 "D"(reg),
407 "S"(&bios32_entry));
408 ret >>= 8;
409 return ret & 0xFF;
410}
411
412static int bios_write_config_half(const pci_location_t *state, uint32_t reg, uint16_t value)
413{
414 uint32_t bx, ret;
415
416 bx = state->bus;
417 bx <<= 8;
418 bx |= state->dev_fn;
419 __asm__(
420 "lcall *(%%esi) \n\t"
421 "jc 1f \n\t"
422 "xor %%ah,%%ah \n"
423 "1:"
424 : "=a"(ret)
425 : "0"(PCIBIOS_WRITE_CONFIG_WORD),
426 "c"(value),
427 "b"(bx),
428 "D"(reg),
429 "S"(&bios32_entry));
430 ret >>= 8;
431 return ret & 0xFF;
432}
433
434static int bios_write_config_word(const pci_location_t *state, uint32_t reg, uint32_t value)
435{
436 uint32_t bx, ret;
437
438 bx = state->bus;
439 bx <<= 8;
440 bx |= state->dev_fn;
441 __asm__(
442 "lcall *(%%esi) \n\t"
443 "jc 1f \n\t"
444 "xor %%ah,%%ah \n"
445 "1:"
446 : "=a"(ret)
447 : "0"(PCIBIOS_WRITE_CONFIG_DWORD),
448 "c"(value),
449 "b"(bx),
450 "D"(reg),
451 "S"(&bios32_entry));
452 ret >>= 8;
453 return ret & 0xFF;
454}
455
456static int bios_get_irq_routing_options(irq_routing_options_t *route_buffer, uint16_t *pciIrqs)
457{
458 uint32_t ret;
459
460 __asm__(
461 "lcall *(%%esi) \n\t"
462 "jc 1f \n\t"
463 "xor %%ah,%%ah \n"
464 "1:"
465 : "=b"(*pciIrqs),
466 "=a"(ret)
467 : "1"(PCIBIOS_GET_IRQ_ROUTING_OPTIONS),
468 "b"(0),
469 "D"(route_buffer),
470 "S"(&bios32_entry));
471 ret >>= 8;
472 return ret & 0xff;
473}
474
475static int bios_set_irq_hw_int(const pci_location_t *state, uint8_t int_pin, uint8_t irq)
476{
477 uint32_t bx, cx, ret;
478
479 bx = state->bus;
480 bx <<= 8;
481 bx |= state->dev_fn;
482 cx = irq;
483 cx <<= 8;
484 cx |= int_pin;
485 __asm__(
486 "lcall *(%%esi) \n\t"
487 "jc 1f \n\t"
488 "xor %%ah,%%ah \n"
489 "1:"
490 : "=a"(ret)
491 : "0"(PCIBIOS_PCI_SET_IRQ_HW_INT),
492 "b"(bx),
493 "c"(cx),
494 "S"(&bios32_entry));
495 ret >>= 8;
496 return ret & 0xFF;
497}
498
499static const char *pci_signature = "PCI ";
500static int pci_bios_detect(void)
501{
502 pci_bios_info * pci = find_pci_bios_info();
503
504 if (pci != NULL) {
505 /*printf("Found PCI structure at %08x\n", (uint32_t) pci);
506
507 printf("\nPCI header info:\n");
508 printf("%c%c%c%c\n", pci->magic[0], pci->magic[1], pci->magic[2],
509 pci->magic[3]);
510 printf("%08x\n", (uint32_t) pci->entry);
511 printf("%d\n", pci->length * 16);
512 printf("%d\n", pci->checksum);*/
513
514 uint32_t adr, temp, len;
515 uint8_t err;
516
517 bios32_entry.offset = (uint32_t) pci->entry;
518 bios32_entry.selector = CODE_SELECTOR;
519
520 __asm__(
521 "lcall *(%%edi)"
522 : "=a"(err), /* AL out=status */
523 "=b"(adr), /* EBX out=code segment base adr */
524 "=c"(len), /* ECX out=code segment size */
525 "=d"(temp) /* EDX out=entry pt offset in code */
526 : "0"(0x49435024),/* EAX in=service="$PCI" */
527 "1"(0), /* EBX in=0=get service entry pt */
528 "D"(&bios32_entry)
529 );
530
531 if (err == 0x80) {
532 dprintf(INFO, "BIOS32 found, but no PCI BIOS\n");
533 return -1;
534 }
535
536 if (err != 0) {
537 dprintf(INFO, "BIOS32 call to locate PCI BIOS returned %x\n", err);
538 return -1;
539 }
540
541 bios32_entry.offset = adr + temp;
542
543 // now call PCI_BIOS_PRESENT to get version, hw mechanism, and last bus
544 uint16_t present, version, busses;
545 uint32_t signature;
546 __asm__(
547 "lcall *(%%edi) \n\t"
548 "jc 1f \n\t"
549 "xor %%ah,%%ah \n"
550 "1:"
551 : "=a"(present),
552 "=b"(version),
553 "=c"(busses),
554 "=d"(signature)
555 : "0"(PCIBIOS_PRESENT),
556 "D"(&bios32_entry)
557 );
558
559 if (present & 0xff00) {
560 dprintf(INFO, "PCI_BIOS_PRESENT call returned ah=%02x\n", present >> 8);
561 return -1;
562 }
563
564 if (signature != *(uint32_t *)pci_signature) {
565 dprintf(INFO, "PCI_BIOS_PRESENT call returned edx=%08x\n", signature);
566 return -1;
567 }
568
569 //dprintf(DEBUG, "busses=%04x\n", busses);
570 last_bus = busses & 0xff;
571
572 g_pci_find_pci_device = bios_find_pci_device;
573 g_pci_find_pci_class_code = bios_find_pci_class_code;
574
575 g_pci_read_config_word = bios_read_config_word;
576 g_pci_read_config_half = bios_read_config_half;
577 g_pci_read_config_byte = bios_read_config_byte;
578
579 g_pci_write_config_word = bios_write_config_word;
580 g_pci_write_config_half = bios_write_config_half;
581 g_pci_write_config_byte = bios_write_config_byte;
582
583 g_pci_get_irq_routing_options = bios_get_irq_routing_options;
584 g_pci_set_irq_hw_int = bios_set_irq_hw_int;
585
586 return 0;
587 }
588
589 return -1;
590}