3 * @author Lunaixsky (zelong56@gmail.com)
4 * @brief A software implementation of PCI Local Bus Specification Revision 3.0
8 * @copyright Copyright (c) 2022
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>
22 device instance for pci bridge,
23 currently, lunaix only support one bridge controller.
25 static struct device* pci_bridge;
27 static morph_t* pci_probers;
28 static DECLARE_HASHTABLE(pci_drivers, 8);
31 pci_log_device(struct pci_probe* probe)
33 pciaddr_t loc = probe->loc;
35 kprintf("pci.%03d:%02d:%02d, class=%p, vendor:dev=%04x:%04x",
40 PCI_DEV_VENDOR(probe->device_info),
41 PCI_DEV_DEVID(probe->device_info));
45 __pci_probe_msi_info(struct pci_probe* probe)
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)
51 pci_read_cspace(probe->cspace_base, PCI_REG_STATUS_CMD) >> 16;
53 if (!(status & 0x10)) {
58 pci_reg_t cap_ptr = pci_read_cspace(probe->cspace_base, 0x34) & 0xff;
62 cap_hdr = pci_read_cspace(probe->cspace_base, cap_ptr);
63 if ((cap_hdr & 0xff) == 0x5) {
65 probe->msi_loc = cap_ptr;
68 cap_ptr = (cap_hdr >> 8) & 0xff;
74 __pci_probe_bar_info(struct pci_probe* probe)
77 struct pci_base_addr* ba;
78 for (size_t i = 0; i < PCI_BAR_COUNT; 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;
86 ba->start = PCI_BAR_ADDR_IO(bar);
92 __pci_add_prober(pciaddr_t loc, ptr_t pci_base, int devinfo)
94 struct pci_probe* prober;
97 pci_reg_t class = pci_read_cspace(pci_base, 0x8);
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);
103 prober = vzalloc(sizeof(*prober));
105 prober->class_info = class;
106 prober->device_info = devinfo;
107 prober->cspace_base = pci_base;
108 prober->intr_info = intr;
111 changeling_morph_anon(pci_probers, prober->mobj, pci_probe_morpher);
113 __pci_probe_msi_info(prober);
114 __pci_probe_bar_info(prober);
116 pci_log_device(prober);
120 __pci_bind(struct pci_registry* reg, struct pci_probe* probe)
123 struct device_def* devdef;
129 if (!reg->check_compact(probe)) {
133 devdef = reg->definition;
134 errno = devdef->create(devdef, &probe->mobj);
137 ERROR("pci_loc:%x, bind (%xh:%xh.%d) failed, e=%d",
139 devdef->class.fn_grp,
140 devdef->class.device,
141 devdef->class.variant,
149 pci_bind_driver(struct pci_registry* reg)
151 struct pci_probe* probe;
155 changeling_for_each(pos, n, pci_probers)
157 probe = changeling_reveal(pos, pci_probe_morpher);
159 errno = __pci_bind(reg, probe);
169 pci_probe_device(pciaddr_t pci_loc)
171 u32_t base = PCI_CFGADDR(pci_loc);
172 pci_reg_t reg1 = pci_read_cspace(base, 0);
174 // Vendor=0xffff则表示设备不存在
175 if (PCI_DEV_VENDOR(reg1) == PCI_VENDOR_INVLD) {
179 pci_reg_t hdr_type = pci_read_cspace(base, 0xc);
180 hdr_type = (hdr_type >> 16) & 0xff;
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);
193 struct pci_probe* prober;
195 changeling_for_each(pos, n, pci_probers)
197 prober = changeling_reveal(pos, pci_probe_morpher);
198 if (prober->loc == pci_loc) {
199 pci_log_device(prober);
204 __pci_add_prober(pci_loc, base, reg1);
207 static struct pci_registry*
208 __pci_registry_get(struct device_def* def)
210 struct pci_registry *pos, *n;
213 hash = hash_32(__ptr(def), HSTR_FULL_HASH);
214 hashtable_hash_foreach(pci_drivers, hash, pos, n, entries)
216 if (pos->definition == def) {
225 __pci_proxied_devdef_load(struct device_def* def)
227 struct pci_registry* reg;
230 reg = __pci_registry_get(def);
233 return pci_bind_driver(reg);
237 pci_register_driver(struct device_def* def, pci_id_checker_t checker)
239 struct pci_registry* reg;
246 if (__pci_registry_get(def)) {
250 reg = valloc(sizeof(*reg));
252 *reg = (struct pci_registry) {
253 .check_compact = checker,
257 device_chain_loader(def, __pci_proxied_devdef_load);
259 hash = hash_32(__ptr(def), HSTR_FULL_HASH);
260 hashtable_hash_in(pci_drivers, ®->entries, hash);
268 for (u32_t loc = 0; loc < (pciaddr_t)-1; loc += 8) {
269 pci_probe_device((pciaddr_t)loc);
274 __pci_config_msi(struct pci_probe* probe, msi_vector_t msiv)
276 // PCI LB Spec. (Rev 3) Section 6.8 & 6.8.1
278 ptr_t msi_addr = msi_addr(msiv);
279 u32_t msi_data = msi_data(msiv);
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;
285 pci_write_cspace(probe->cspace_base,
286 PCI_MSI_ADDR_LO(probe->msi_loc),
290 pci_write_cspace(probe->cspace_base,
291 PCI_MSI_ADDR_HI(probe->msi_loc),
292 (u64_t)msi_addr >> 32);
295 pci_write_cspace(probe->cspace_base,
296 PCI_MSI_DATA(probe->msi_loc, offset_cap64),
299 if ((msg_ctl & MSI_CAP_MASK)) {
301 probe->cspace_base, PCI_MSI_MASK(probe->msi_loc, offset_cap64), 0);
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);
310 pci_msi_start(struct pci_probe* probe)
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.
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
326 env = isrm_msi_start(pci_bridge);
327 isrm_msi_set_sideband(env, pci_requester_id(probe));
333 pci_msi_setup_at(msienv_t msienv, struct pci_probe* probe,
334 int i, isr_cb handler)
338 msiv = isrm_msi_alloc(msienv, 0, i, handler);
339 __pci_config_msi(probe, msiv);
345 pci_bar_sizing(struct pci_probe* probe, u32_t* bar_out, u32_t bar_num)
347 pci_reg_t sized, bar;
349 bar = pci_read_cspace(probe->cspace_base, PCI_REG_BAR(bar_num));
355 pci_write_cspace(probe->cspace_base, PCI_REG_BAR(bar_num), 0xffffffff);
358 pci_read_cspace(probe->cspace_base, PCI_REG_BAR(bar_num)) & ~0x1;
360 if (PCI_BAR_MMIO(bar)) {
361 sized = PCI_BAR_ADDR_MM(sized);
365 pci_write_cspace(probe->cspace_base, PCI_REG_BAR(bar_num), bar);
371 pci_apply_command(struct pci_probe* probe, pci_reg_t cmd)
376 base = probe->cspace_base;
377 rcmd = pci_read_cspace(base, PCI_REG_STATUS_CMD);
380 rcmd = (rcmd & 0xffff0000) | cmd;
382 pci_write_cspace(base, PCI_REG_STATUS_CMD, rcmd);
386 __pci_read_cspace(struct twimap* map)
388 struct pci_probe* probe;
390 probe = twimap_data(map, struct pci_probe*);
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);
400 /*---------- TwiFS interface definition ----------*/
403 __pci_read_revid(struct twimap* map)
405 struct pci_probe* probe;
407 probe = twimap_data(map, struct pci_probe*);
408 twimap_printf(map, "0x%x", PCI_DEV_REV(probe->class_info));
412 __pci_read_class(struct twimap* map)
414 struct pci_probe* probe;
416 probe = twimap_data(map, struct pci_probe*);
417 twimap_printf(map, "0x%x", PCI_DEV_CLASS(probe->class_info));
421 __pci_read_devinfo(struct twimap* map)
423 struct pci_probe* probe;
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));
432 __pci_bar_read(struct twimap* map)
434 struct pci_probe* probe;
437 probe = twimap_data(map, struct pci_probe*);
438 bar_index = twimap_index(map, int);
440 struct pci_base_addr* bar = &probe->bar[bar_index];
442 if (!bar->start && !bar->size) {
443 twimap_printf(map, "[%d] not present \n", bar_index);
448 map, "[%d] base=%.8p, size=%.8p, ", bar_index, bar->start, bar->size);
450 if ((bar->type & BAR_TYPE_MMIO)) {
451 twimap_printf(map, "mmio");
452 if ((bar->type & BAR_TYPE_CACHABLE)) {
453 twimap_printf(map, ", prefetchable");
456 twimap_printf(map, "io");
459 twimap_printf(map, "\n");
463 __pci_bar_gonext(struct twimap* map)
465 if (twimap_index(map, int) >= 5) {
473 __pci_read_binding(struct twimap* map)
475 struct pci_probe* probe;
476 struct devident* devid;
478 probe = twimap_data(map, struct pci_probe*);
483 devid = &probe->bind->ident;
485 twimap_printf(map, "%xh:%xh.%d",
487 DEV_KIND_FROM(devid->unique),
488 DEV_VAR_FROM(devid->unique));
492 __pci_trigger_bus_rescan(struct twimap* map)
498 pci_build_fsmapping()
500 struct twifs_node *pci_class = twifs_dir_node(NULL, "pci"), *pci_dev;
502 struct pci_probe* probe;
505 // TODO bus rescan is not ready yet
506 // map = twifs_mapping(pci_class, NULL, "rescan");
507 // map->read = __pci_trigger_bus_rescan;
509 changeling_for_each(pos, n, pci_probers)
511 probe = changeling_reveal(pos, pci_probe_morpher);
512 pci_dev = twifs_dir_node(pci_class, "%x", probe->loc);
514 map = twifs_mapping(pci_dev, probe, "config");
515 map->read = __pci_read_cspace;
517 map = twifs_mapping(pci_dev, probe, "revision");
518 map->read = __pci_read_revid;
520 map = twifs_mapping(pci_dev, probe, "class");
521 map->read = __pci_read_class;
523 map = twifs_mapping(pci_dev, probe, "binding");
524 map->read = __pci_read_binding;
526 map = twifs_mapping(pci_dev, probe, "io_bases");
527 map->read = __pci_bar_read;
528 map->go_next = __pci_bar_gonext;
531 EXPORT_TWIFS_PLUGIN(pci_devs, pci_build_fsmapping);
533 /*---------- PCI 3.0 HBA device definition ----------*/
536 pci_register(struct device_def* def)
538 pci_probers = changeling_spawn(NULL, "pci_realm");
544 pci_create(struct device_def* def, morph_t* obj)
546 devtree_link_t devtree_node;
548 devtree_node = changeling_try_reveal(obj, dt_node_morpher);
550 pci_bridge = device_allocsys(NULL, NULL);
551 device_set_devtree_node(pci_bridge, devtree_node);
553 register_device(pci_bridge, &def->class, "pci_bridge");
560 static struct device_def pci_def = {
561 def_device_name("Generic PCI"),
562 def_device_class(GENERIC, BUSIF, PCI),
564 def_on_register(pci_register),
565 def_on_create(pci_create)
567 EXPORT_DEVICE(pci3hba, &pci_def, load_sysconf);