3052a90eea05bc70b5128d41d96f90682ea6c218
[lunaix-os.git] / lunaix-os / hal / bus / pci.c
1 /**
2  * @file pci.c
3  * @author Lunaixsky (zelong56@gmail.com)
4  * @brief A software implementation of PCI Local Bus Specification Revision 3.0
5  * @version 0.1
6  * @date 2022-06-28
7  *
8  * @copyright Copyright (c) 2022
9  *
10  */
11 #include <hal/pci.h>
12
13 #include <klibc/string.h>
14 #include <lunaix/fs/twifs.h>
15 #include <lunaix/mm/valloc.h>
16 #include <lunaix/spike.h>
17 #include <lunaix/syslog.h>
18
19 LOG_MODULE("PCI")
20
21 /*
22     device instance for pci bridge, 
23     currently, lunaix only support one bridge controller.
24 */
25 static struct device* pci_bridge;
26
27 static morph_t* pci_probers;
28 static DECLARE_HASHTABLE(pci_drivers, 8);
29
30 static inline void
31 pci_log_device(struct pci_probe* probe)
32 {
33     pciaddr_t loc = probe->loc;
34
35     kprintf("pci.%03d:%02d:%02d, class=%p, vendor:dev=%04x:%04x",
36             PCILOC_BUS(loc),
37             PCILOC_DEV(loc),
38             PCILOC_FN(loc),
39             probe->class_info,
40             PCI_DEV_VENDOR(probe->device_info),
41             PCI_DEV_DEVID(probe->device_info));
42 }
43
44 static void
45 __pci_probe_msi_info(struct pci_probe* probe)
46 {
47     // Note that Virtualbox have to use ICH9 chipset for MSI support.
48     // Qemu seems ok with default PIIX3, Bochs is pending to test...
49     //    See https://www.virtualbox.org/manual/ch03.html (section 3.5.1)
50     pci_reg_t status =
51       pci_read_cspace(probe->cspace_base, PCI_REG_STATUS_CMD) >> 16;
52
53     if (!(status & 0x10)) {
54         probe->msi_loc = 0;
55         return;
56     }
57
58     pci_reg_t cap_ptr = pci_read_cspace(probe->cspace_base, 0x34) & 0xff;
59     u32_t cap_hdr;
60
61     while (cap_ptr) {
62         cap_hdr = pci_read_cspace(probe->cspace_base, cap_ptr);
63         if ((cap_hdr & 0xff) == 0x5) {
64             // MSI
65             probe->msi_loc = cap_ptr;
66             return;
67         }
68         cap_ptr = (cap_hdr >> 8) & 0xff;
69     }
70 }
71
72
73 static void
74 __pci_probe_bar_info(struct pci_probe* probe)
75 {
76     u32_t bar;
77     struct pci_base_addr* ba;
78     for (size_t i = 0; i < PCI_BAR_COUNT; i++) {
79         ba = &probe->bar[i];
80         ba->size = pci_bar_sizing(probe, &bar, i + 1);
81         if (PCI_BAR_MMIO(bar)) {
82             ba->start = PCI_BAR_ADDR_MM(bar);
83             ba->type |= PCI_BAR_CACHEABLE(bar) ? BAR_TYPE_CACHABLE : 0;
84             ba->type |= BAR_TYPE_MMIO;
85         } else {
86             ba->start = PCI_BAR_ADDR_IO(bar);
87         }
88     }
89 }
90
91 static void
92 __pci_add_prober(pciaddr_t loc, ptr_t pci_base, int devinfo)
93 {
94     struct pci_probe* prober;
95     morph_t* probe_morph;
96
97     pci_reg_t class = pci_read_cspace(pci_base, 0x8);
98
99     u32_t devid = PCI_DEV_DEVID(devinfo);
100     u32_t vendor = PCI_DEV_VENDOR(devinfo);
101     pci_reg_t intr = pci_read_cspace(pci_base, 0x3c);
102
103     prober = vzalloc(sizeof(*prober));
104
105     prober->class_info = class;
106     prober->device_info = devinfo;
107     prober->cspace_base = pci_base;
108     prober->intr_info = intr;
109     prober->loc = loc;
110
111     changeling_morph_anon(pci_probers, prober->mobj, pci_probe_morpher);
112
113     __pci_probe_msi_info(prober);
114     __pci_probe_bar_info(prober);
115
116     pci_log_device(prober);
117 }
118
119 static int
120 __pci_bind(struct pci_registry* reg, struct pci_probe* probe)
121 {
122     int errno;
123     struct device_def* devdef;
124
125     if (probe->bind) {
126         return EEXIST;
127     }
128
129     if (!reg->check_compact(probe)) {
130         return EINVAL;
131     }
132
133     devdef = reg->definition;
134     errno = devdef->create(devdef, &probe->mobj);
135
136     if (errno) {
137         ERROR("pci_loc:%x, bind (%xh:%xh.%d) failed, e=%d",
138                 probe->loc,
139                 devdef->class.fn_grp,
140                 devdef->class.device,
141                 devdef->class.variant,
142                 errno);
143     }
144
145     return errno;
146 }
147
148 int
149 pci_bind_driver(struct pci_registry* reg)
150 {
151     struct pci_probe* probe;
152     int errno = 0;
153     
154     morph_t *pos, *n;
155     changeling_for_each(pos, n, pci_probers)
156     {
157         probe = changeling_reveal(pos, pci_probe_morpher);
158
159         errno = __pci_bind(reg, probe);
160         if (errno) {
161             continue;
162         }
163     }
164
165     return errno;
166 }
167
168 void
169 pci_probe_device(pciaddr_t pci_loc)
170 {
171     u32_t base = PCI_CFGADDR(pci_loc);
172     pci_reg_t reg1 = pci_read_cspace(base, 0);
173
174     // Vendor=0xffff则表示设备不存在
175     if (PCI_DEV_VENDOR(reg1) == PCI_VENDOR_INVLD) {
176         return;
177     }
178
179     pci_reg_t hdr_type = pci_read_cspace(base, 0xc);
180     hdr_type = (hdr_type >> 16) & 0xff;
181
182     // 防止堆栈溢出
183     // QEMU的ICH9/Q35实现似乎有点问题,对于多功能设备的每一个功能的header type
184     //  都将第七位置位。而virtualbox 就没有这个毛病。
185     if ((hdr_type & 0x80) && PCILOC_FN(pci_loc) == 0) {
186         hdr_type = hdr_type & ~0x80;
187         // 探测多用途设备(multi-function device)
188         for (int i = 1; i < 7; i++) {
189             pci_probe_device(pci_loc + i);
190         }
191     }
192
193     struct pci_probe* prober;
194     morph_t *pos, *n;
195     changeling_for_each(pos, n, pci_probers) 
196     {
197         prober = changeling_reveal(pos, pci_probe_morpher);
198         if (prober->loc == pci_loc) {
199             pci_log_device(prober);
200             return;
201         }
202     }
203
204     __pci_add_prober(pci_loc, base, reg1);
205 }
206
207 static struct pci_registry*
208 __pci_registry_get(struct device_def* def)
209 {
210     struct pci_registry *pos, *n;
211     unsigned int hash;
212
213     hash = hash_32(__ptr(def), HSTR_FULL_HASH);
214     hashtable_hash_foreach(pci_drivers, hash, pos, n, entries)
215     {
216         if (pos->definition == def) {
217             return pos;
218         }
219     }
220
221     return NULL;
222 }
223
224 static int
225 __pci_proxied_devdef_load(struct device_def* def)
226 {
227     struct pci_registry* reg;
228     int errno = 0;
229
230     reg = __pci_registry_get(def);
231     assert(reg);
232
233     return pci_bind_driver(reg);
234 }
235
236 bool
237 pci_register_driver(struct device_def* def, pci_id_checker_t checker)
238 {
239     struct pci_registry* reg;
240     unsigned int hash;
241
242     if (!checker) {
243         return false;
244     }
245
246     if (__pci_registry_get(def)) {
247         return false;
248     }
249
250     reg = valloc(sizeof(*reg));
251     
252     *reg = (struct pci_registry) {
253         .check_compact = checker,
254         .definition = def,
255     };
256
257     device_chain_loader(def, __pci_proxied_devdef_load);
258
259     hash = hash_32(__ptr(def), HSTR_FULL_HASH);
260     hashtable_hash_in(pci_drivers, &reg->entries, hash);
261
262     return true;
263 }
264
265 void
266 pci_scan()
267 {
268     for (u32_t loc = 0; loc < (pciaddr_t)-1; loc += 8) {
269         pci_probe_device((pciaddr_t)loc);
270     }
271 }
272
273 static void
274 __pci_config_msi(struct pci_probe* probe, msi_vector_t msiv)
275 {
276     // PCI LB Spec. (Rev 3) Section 6.8 & 6.8.1
277
278     ptr_t msi_addr = msi_addr(msiv);
279     u32_t msi_data = msi_data(msiv);
280
281     pci_reg_t reg1 = pci_read_cspace(probe->cspace_base, probe->msi_loc);
282     pci_reg_t msg_ctl = reg1 >> 16;
283     int offset_cap64 = !!(msg_ctl & MSI_CAP_64BIT) * 4;
284
285     pci_write_cspace(probe->cspace_base, 
286                      PCI_MSI_ADDR_LO(probe->msi_loc), 
287                      msi_addr);
288     
289     if (offset_cap64) {
290         pci_write_cspace(probe->cspace_base, 
291                          PCI_MSI_ADDR_HI(probe->msi_loc), 
292                          (u64_t)msi_addr >> 32);
293     }
294
295     pci_write_cspace(probe->cspace_base,
296                      PCI_MSI_DATA(probe->msi_loc, offset_cap64),
297                      msi_data & 0xffff);
298
299     if ((msg_ctl & MSI_CAP_MASK)) {
300         pci_write_cspace(
301           probe->cspace_base, PCI_MSI_MASK(probe->msi_loc, offset_cap64), 0);
302     }
303
304     // manipulate the MSI_CTRL to allow device using MSI to request service.
305     reg1 = (reg1 & 0xff8fffff) | 0x10000;
306     pci_write_cspace(probe->cspace_base, probe->msi_loc, reg1);
307 }
308
309 msienv_t
310 pci_msi_start(struct pci_probe* probe)
311 {
312     /*
313         As a PCI bridge/root complex can be initialised from device tree node,
314         in that case, general information such as routing, rid remapping, 
315         are vital to all msi setup of all peripherals under it.
316
317         Therefore, a wrapper around isrm_msi_* is needed in order to
318         improve overall readability and usability, where the bridge
319         device instance that contain these information will be 
320         automatically passed to the underlay as credential to perform
321         configuration.
322     */
323
324     msienv_t env;
325     
326     env = isrm_msi_start(pci_bridge);
327     isrm_msi_set_sideband(env, pci_requester_id(probe));
328
329     return env;
330 }
331
332 msi_vector_t
333 pci_msi_setup_at(msienv_t msienv, struct pci_probe* probe, 
334                  int i, isr_cb handler)
335 {
336     msi_vector_t msiv;
337
338     msiv = isrm_msi_alloc(msienv, 0, i, handler);
339     __pci_config_msi(probe, msiv);
340
341     return msiv;
342 }
343
344 size_t
345 pci_bar_sizing(struct pci_probe* probe, u32_t* bar_out, u32_t bar_num)
346 {
347     pci_reg_t sized, bar;
348     
349     bar = pci_read_cspace(probe->cspace_base, PCI_REG_BAR(bar_num));
350     if (!bar) {
351         *bar_out = 0;
352         return 0;
353     }
354
355     pci_write_cspace(probe->cspace_base, PCI_REG_BAR(bar_num), 0xffffffff);
356     
357     sized =
358       pci_read_cspace(probe->cspace_base, PCI_REG_BAR(bar_num)) & ~0x1;
359     
360     if (PCI_BAR_MMIO(bar)) {
361         sized = PCI_BAR_ADDR_MM(sized);
362     }
363     
364     *bar_out = bar;
365     pci_write_cspace(probe->cspace_base, PCI_REG_BAR(bar_num), bar);
366     
367     return ~sized + 1;
368 }
369
370 void
371 pci_apply_command(struct pci_probe* probe, pci_reg_t cmd)
372 {
373     pci_reg_t rcmd;
374     ptr_t base;
375
376     base = probe->cspace_base;
377     rcmd = pci_read_cspace(base, PCI_REG_STATUS_CMD);
378
379     cmd  = cmd & 0xffff;
380     rcmd = (rcmd & 0xffff0000) | cmd;
381
382     pci_write_cspace(base, PCI_REG_STATUS_CMD, rcmd);
383 }
384
385 static void
386 __pci_read_cspace(struct twimap* map)
387 {
388     struct pci_probe* probe;
389
390     probe = twimap_data(map, struct pci_probe*);
391
392     for (size_t i = 0; i < 256; i += sizeof(pci_reg_t)) {
393         *(pci_reg_t*)(map->buffer + i) =
394           pci_read_cspace(probe->cspace_base, i);
395     }
396
397     map->size_acc = 256;
398 }
399
400 /*---------- TwiFS interface definition ----------*/
401
402 static void
403 __pci_read_revid(struct twimap* map)
404 {
405     struct pci_probe* probe;
406
407     probe = twimap_data(map, struct pci_probe*);
408     twimap_printf(map, "0x%x", PCI_DEV_REV(probe->class_info));
409 }
410
411 static void
412 __pci_read_class(struct twimap* map)
413 {
414     struct pci_probe* probe;
415
416     probe = twimap_data(map, struct pci_probe*);
417     twimap_printf(map, "0x%x", PCI_DEV_CLASS(probe->class_info));
418 }
419
420 static void
421 __pci_read_devinfo(struct twimap* map)
422 {
423     struct pci_probe* probe;
424
425     probe = twimap_data(map, struct pci_probe*);
426     twimap_printf(map, "%x:%x", 
427             PCI_DEV_VENDOR(probe->device_info), 
428             PCI_DEV_DEVID(probe->device_info));
429 }
430
431 static void
432 __pci_bar_read(struct twimap* map)
433 {
434     struct pci_probe* probe;
435     int bar_index;
436
437     probe = twimap_data(map, struct pci_probe*);
438     bar_index = twimap_index(map, int);
439
440     struct pci_base_addr* bar = &probe->bar[bar_index];
441
442     if (!bar->start && !bar->size) {
443         twimap_printf(map, "[%d] not present \n", bar_index);
444         return;
445     }
446
447     twimap_printf(
448       map, "[%d] base=%.8p, size=%.8p, ", bar_index, bar->start, bar->size);
449
450     if ((bar->type & BAR_TYPE_MMIO)) {
451         twimap_printf(map, "mmio");
452         if ((bar->type & BAR_TYPE_CACHABLE)) {
453             twimap_printf(map, ", prefetchable");
454         }
455     } else {
456         twimap_printf(map, "io");
457     }
458
459     twimap_printf(map, "\n");
460 }
461
462 static int
463 __pci_bar_gonext(struct twimap* map)
464 {
465     if (twimap_index(map, int) >= 5) {
466         return 0;
467     }
468     map->index += 1;
469     return 1;
470 }
471
472 static void
473 __pci_read_binding(struct twimap* map)
474 {
475     struct pci_probe* probe;
476     struct devident* devid;
477
478     probe = twimap_data(map, struct pci_probe*);
479     if (!probe->bind) {
480         return;
481     }
482
483     devid = &probe->bind->ident;
484
485     twimap_printf(map, "%xh:%xh.%d",
486                   devid->fn_grp,
487                   DEV_KIND_FROM(devid->unique),
488                   DEV_VAR_FROM(devid->unique));
489 }
490
491 static void
492 __pci_trigger_bus_rescan(struct twimap* map)
493 {
494     pci_scan();
495 }
496
497 void
498 pci_build_fsmapping()
499 {
500     struct twifs_node *pci_class = twifs_dir_node(NULL, "pci"), *pci_dev;
501     struct twimap* map;
502     struct pci_probe* probe;
503     morph_t *pos, *n;
504
505     // TODO bus rescan is not ready yet
506     // map = twifs_mapping(pci_class, NULL, "rescan");
507     // map->read = __pci_trigger_bus_rescan;
508
509     changeling_for_each(pos, n, pci_probers)
510     {
511         probe = changeling_reveal(pos, pci_probe_morpher);
512         pci_dev = twifs_dir_node(pci_class, "%x", probe->loc);
513
514         map = twifs_mapping(pci_dev, probe, "config");
515         map->read = __pci_read_cspace;
516
517         map = twifs_mapping(pci_dev, probe, "revision");
518         map->read = __pci_read_revid;
519
520         map = twifs_mapping(pci_dev, probe, "class");
521         map->read = __pci_read_class;
522
523         map = twifs_mapping(pci_dev, probe, "binding");
524         map->read = __pci_read_binding;
525
526         map = twifs_mapping(pci_dev, probe, "io_bases");
527         map->read = __pci_bar_read;
528         map->go_next = __pci_bar_gonext;
529     }
530 }
531 EXPORT_TWIFS_PLUGIN(pci_devs, pci_build_fsmapping);
532
533 /*---------- PCI 3.0 HBA device definition ----------*/
534
535 static int
536 pci_register(struct device_def* def)
537 {
538     pci_probers = changeling_spawn(NULL, "pci_realm");
539
540     return 0;
541 }
542
543 static int
544 pci_create(struct device_def* def, morph_t* obj)
545 {
546     devtree_link_t devtree_node;
547
548     devtree_node = changeling_try_reveal(obj, dt_node_morpher);
549
550     pci_bridge = device_allocsys(NULL, NULL);
551     device_set_devtree_node(pci_bridge, devtree_node);
552
553     register_device(pci_bridge, &def->class, "pci_bridge");
554
555     pci_scan();
556
557     return 0;
558 }
559
560 static struct device_def pci_def = {
561     def_device_name("Generic PCI"),
562     def_device_class(GENERIC, BUSIF, PCI),
563
564     def_on_register(pci_register),
565     def_on_create(pci_create)
566 };
567 EXPORT_DEVICE(pci3hba, &pci_def, load_sysconf);