X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/6f6da1abb22dff69dbb710bd2fd9d95f083f2b43..7b8a1bcad75628f9add4590db2bb9b8e418ee8eb:/lunaix-os/hal/pci.c diff --git a/lunaix-os/hal/pci.c b/lunaix-os/hal/pci.c index 3859e0c..8a5048b 100644 --- a/lunaix-os/hal/pci.c +++ b/lunaix-os/hal/pci.c @@ -20,41 +20,36 @@ LOG_MODULE("PCI") static DEFINE_LLIST(pci_devices); +static DECLARE_HASHTABLE(pci_devcache, 8); + +static struct device_cat* pcidev_cat; +static struct device_def pci_def; void pci_probe_msi_info(struct pci_device* device); +static inline void +pci_log_device(struct pci_device* pcidev) +{ + pciaddr_t loc = pcidev->loc; + struct device_def* binddef = pcidev->binding.def; + + kprintf("pci.%03d:%02d:%02d, class=%p, vendor:dev=%04x:%04x", + PCILOC_BUS(loc), + PCILOC_DEV(loc), + PCILOC_FN(loc), + pcidev->class_info, + PCI_DEV_VENDOR(pcidev->device_info), + PCI_DEV_DEVID(pcidev->device_info)); +} + static struct pci_device* -pci_create_device(ptr_t pci_base, int devinfo) +pci_create_device(pciaddr_t loc, ptr_t pci_base, int devinfo) { pci_reg_t class = pci_read_cspace(pci_base, 0x8); - struct hbucket* bucket = device_definitions_byif(DEVIF_PCI); u32_t devid = PCI_DEV_DEVID(devinfo); u32_t vendor = PCI_DEV_VENDOR(devinfo); - - kappendf(".%x:%x, ", vendor, devid); - - struct pci_device_def *pos, *n; - hashtable_bucket_foreach(bucket, pos, n, devdef.hlist_if) - { - if (pos->dev_class != PCI_DEV_CLASS(class)) { - continue; - } - - int result = (pos->dev_vendor & vendor) == vendor && - (pos->dev_id & devid) == devid; - - if (result) { - goto found; - } - } - - kappendf(KWARN "unknown device\n"); - - return NULL; - -found: pci_reg_t intr = pci_read_cspace(pci_base, 0x3c); struct pci_device* device = vzalloc(sizeof(struct pci_device)); @@ -63,41 +58,98 @@ found: device->cspace_base = pci_base; device->intr_info = intr; - device_prepare(&device->dev, &pos->devdef.class); + device_create(&device->dev, dev_meta(pcidev_cat), DEV_IFSYS, NULL); pci_probe_msi_info(device); pci_probe_bar_info(device); - kappendf("%s (dev.%x:%x:%x) \n", - pos->devdef.name, - pos->devdef.class.meta, - pos->devdef.class.device, - pos->devdef.class.variant); + llist_append(&pci_devices, &device->dev_chain); + register_device(&device->dev, &pci_def.class, "%x", loc); + pci_def.class.variant++; + + return device; +} - if (!pos->devdef.init_for) { - kappendf(KERROR "bad def\n"); - goto fail; +int +pci_bind_definition(struct pci_device_def* pcidev_def, int* more) +{ + u32_t class = pcidev_def->dev_class; + u32_t devid_mask = pcidev_def->ident_mask; + u32_t devid = pcidev_def->dev_ident & devid_mask; + + if (!pcidev_def->devdef.bind) { + ERROR("pcidev %xh:%xh.%d is unbindable", + pcidev_def->devdef.class.fn_grp, + pcidev_def->devdef.class.device, + pcidev_def->devdef.class.variant); + return EINVAL; } - int errno = pos->devdef.init_for(&pos->devdef, &device->dev); - if (errno) { - kappendf(KERROR "failed (e=%d)\n", errno); - goto fail; + *more = 0; + + int bind_attempted = 0; + int errno = 0; + + struct device_def* devdef; + struct pci_device *pos, *n; + llist_for_each(pos, n, &pci_devices, dev_chain) + { + if (binded_pcidev(pos)) { + continue; + } + + if (class != PCI_DEV_CLASS(pos->class_info)) { + continue; + } + + int matched = (pos->device_info & devid_mask) == devid; + + if (!matched) { + continue; + } + + if (bind_attempted) { + *more = 1; + break; + } + + bind_attempted = 1; + devdef = &pcidev_def->devdef; + errno = devdef->bind(devdef, &pos->dev); + + if (errno) { + ERROR("pci_loc:%x, bind (%xh:%xh.%d) failed, e=%d", + pos->loc, + devdef->class.fn_grp, + devdef->class.device, + devdef->class.variant, + errno); + continue; + } + + pos->binding.def = &pcidev_def->devdef; } - llist_append(&pci_devices, &device->dev_chain); + return errno; +} - return device; +int +pci_bind_definition_all(struct pci_device_def* pcidef) +{ + int more = 0, e = 0; + do { + if (!(e = pci_bind_definition(pcidef, &more))) { + break; + } + } while (more); -fail: - vfree(device); - return NULL; + return e; } void -pci_probe_device(int bus, int dev, int funct) +pci_probe_device(pciaddr_t pci_loc) { - u32_t base = PCI_ADDRESS(bus, dev, funct); + u32_t base = PCI_CFGADDR(pci_loc); pci_reg_t reg1 = pci_read_cspace(base, 0); // Vendor=0xffff则表示设备不存在 @@ -111,31 +163,36 @@ pci_probe_device(int bus, int dev, int funct) // 防止堆栈溢出 // QEMU的ICH9/Q35实现似乎有点问题,对于多功能设备的每一个功能的header type // 都将第七位置位。而virtualbox 就没有这个毛病。 - if ((hdr_type & 0x80) && funct == 0) { + if ((hdr_type & 0x80) && PCILOC_FN(pci_loc) == 0) { hdr_type = hdr_type & ~0x80; // 探测多用途设备(multi-function device) for (int i = 1; i < 7; i++) { - pci_probe_device(bus, dev, i); + pci_probe_device(pci_loc + i); } } - if (hdr_type != PCI_TDEV) { - // XXX: 目前忽略所有桥接设备,比如PCI-PCI桥接器,或者是CardBus桥接器 - return; + struct pci_device *pos, *n; + hashtable_hash_foreach(pci_devcache, pci_loc, pos, n, dev_cache) + { + if (pos->loc == pci_loc) { + pci_log_device(pos); + return; + } } - kprintf("pci.%d:%d:%d", bus, dev, funct); - - pci_create_device(base, reg1); + struct pci_device* pcidev = pci_create_device(pci_loc, base, reg1); + if (pcidev) { + pcidev->loc = pci_loc; + hashtable_hash_in(pci_devcache, &pcidev->dev_cache, pci_loc); + pci_log_device(pcidev); + } } void pci_scan() { - for (int bus = 0; bus < 256; bus++) { - for (int dev = 0; dev < 32; dev++) { - pci_probe_device(bus, dev, 0); - } + for (u32_t loc = 0; loc < (pciaddr_t)-1; loc += 8) { + pci_probe_device((pciaddr_t)loc); } } @@ -263,6 +320,14 @@ __pci_read_class(struct twimap* map) twimap_printf(map, "0x%x", PCI_DEV_CLASS(class)); } +static void +__pci_read_devinfo(struct twimap* map) +{ + int devinfo = twimap_data(map, struct pci_device*)->device_info; + twimap_printf( + map, "%x:%x", PCI_DEV_VENDOR(devinfo), PCI_DEV_DEVID(devinfo)); +} + static void __pci_bar_read(struct twimap* map) { @@ -301,21 +366,41 @@ __pci_bar_gonext(struct twimap* map) return 1; } +static void +__pci_read_binding(struct twimap* map) +{ + struct pci_device* pcidev = twimap_data(map, struct pci_device*); + struct device_def* devdef = pcidev->binding.def; + if (!devdef) { + return; + } + + twimap_printf(map, + "%xh:%xh.%d", + devdef->class.fn_grp, + devdef->class.device, + devdef->class.variant); +} + +static void +__pci_trigger_bus_rescan(struct twimap* map) +{ + pci_scan(); +} + void pci_build_fsmapping() { struct twifs_node *pci_class = twifs_dir_node(NULL, "pci"), *pci_dev; struct pci_device *pos, *n; struct twimap* map; + + map = twifs_mapping(pci_class, NULL, "rescan"); + map->read = __pci_trigger_bus_rescan; + llist_for_each(pos, n, &pci_devices, dev_chain) { - pci_dev = twifs_dir_node(pci_class, - "%.2d:%.2d:%.2d.%.4x:%.4x", - PCI_BUS_NUM(pos->cspace_base), - PCI_SLOT_NUM(pos->cspace_base), - PCI_FUNCT_NUM(pos->cspace_base), - PCI_DEV_VENDOR(pos->device_info), - PCI_DEV_DEVID(pos->device_info)); + pci_dev = twifs_dir_node(pci_class, "%x", pos->loc); map = twifs_mapping(pci_dev, pos, "config"); map->read = __pci_read_cspace; @@ -326,6 +411,9 @@ pci_build_fsmapping() map = twifs_mapping(pci_dev, pos, "class"); map->read = __pci_read_class; + map = twifs_mapping(pci_dev, pos, "binding"); + map->read = __pci_read_binding; + map = twifs_mapping(pci_dev, pos, "io_bases"); map->read = __pci_bar_read; map->go_next = __pci_bar_gonext; @@ -338,14 +426,23 @@ EXPORT_TWIFS_PLUGIN(pci_devs, pci_build_fsmapping); static int pci_load_devices(struct device_def* def) { + pcidev_cat = device_addcat(NULL, "pci"); + pci_scan(); return 0; } +void +pci_bind_instance(struct pci_device* pcidev, void* devobj) +{ + pcidev->dev.underlay = devobj; + pcidev->binding.dev = devobj; +} + static struct device_def pci_def = { - .name = "pci3.0-hba", - .class = DEVCLASS(DEVIF_SOC, DEVFN_BUSIF, DEV_BUS, 0), + .name = "Generic PCI", + .class = DEVCLASS(DEVIF_SOC, DEVFN_BUSIF, DEV_PCI), .init = pci_load_devices }; -EXPORT_DEVICE(pci3hba, &pci_def, load_poststage); +EXPORT_DEVICE(pci3hba, &pci_def, load_sysconf);