From: Minep Date: Thu, 26 Oct 2023 11:29:58 +0000 (+0100) Subject: feat: support user-spcae pci rescan X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/0f73e6cc9945f9b4a074bb62b9708d1751fa3723 feat: support user-spcae pci rescan refactor: allow lazy driver binding for pci devices --- diff --git a/lunaix-os/hal/ahci/ahci.c b/lunaix-os/hal/ahci/ahci.c index 2aa37e5..61ea95b 100644 --- a/lunaix-os/hal/ahci/ahci.c +++ b/lunaix-os/hal/ahci/ahci.c @@ -200,7 +200,7 @@ ahci_driver_init(struct device_def* def, struct device* dev) ahci_register_device(hbadev); } - dev->underlay = ahci_drv; + pci_bind_instance(ahci_dev, ahci_drv); return 0; } @@ -447,6 +447,6 @@ static struct pci_device_def ahcidef = { .ident_mask = PCI_MATCH_ANY, .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_STORAGE, DEV_SATA), .name = "Serial ATA Controller", - .init_for = ahci_driver_init } + .bind = ahci_driver_init } }; EXPORT_PCI_DEVICE(ahci, &ahcidef); \ No newline at end of file diff --git a/lunaix-os/hal/gfxa/vga/vga_pci.c b/lunaix-os/hal/gfxa/vga/vga_pci.c index 5d4ed8d..fe77652 100644 --- a/lunaix-os/hal/gfxa/vga/vga_pci.c +++ b/lunaix-os/hal/gfxa/vga/vga_pci.c @@ -105,6 +105,6 @@ static struct pci_device_def vga_pci_devdef = { .ident_mask = PCI_MATCH_EXACT, .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_DISP, DEV_VGA), .name = "Generic VGA", - .init_for = vga_pci_init } + .bind = vga_pci_init } }; EXPORT_PCI_DEVICE(vga_pci, &vga_pci_devdef); \ No newline at end of file diff --git a/lunaix-os/hal/pci.c b/lunaix-os/hal/pci.c index bc1e7cc..1f6cc3d 100644 --- a/lunaix-os/hal/pci.c +++ b/lunaix-os/hal/pci.c @@ -20,22 +20,64 @@ LOG_MODULE("PCI") static DEFINE_LLIST(pci_devices); +static DECLARE_HASHTABLE(pci_devcache, 8); static struct device* 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; + + if (!binddef) { + kprintf("pci.%d:%d:%d, no binding\n", + PCILOC_BUS(loc), + PCILOC_DEV(loc), + PCILOC_FN(loc)); + return; + } + + kprintf("pci.%d:%d:%d, dev.%xh:%xh.%d, %s\n", + PCILOC_BUS(loc), + PCILOC_DEV(loc), + PCILOC_FN(loc), + binddef->class.fn_grp, + binddef->class.device, + binddef->class.variant, + binddef->name); +} + 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); + pci_reg_t intr = pci_read_cspace(pci_base, 0x3c); + + struct pci_device* device = vzalloc(sizeof(struct pci_device)); + device->class_info = class; + device->device_info = devinfo; + device->cspace_base = pci_base; + device->intr_info = intr; + + device_create(&device->dev, pcidev_cat, DEV_IFSYS, NULL); + + pci_probe_msi_info(device); + pci_probe_bar_info(device); + + llist_append(&pci_devices, &device->dev_chain); + device_register(&device->dev, &pci_def.class, "%x", loc); + pci_def.class.variant++; - kappendf(".%x:%x, ", vendor, devid); + // find a suitable binding struct pci_device_def *pos, *n; hashtable_bucket_foreach(bucket, pos, n, devdef.hlist_if) @@ -52,55 +94,39 @@ pci_create_device(ptr_t pci_base, int devinfo) } } - kappendf(KWARN "unknown device\n"); - - return NULL; + goto done; found: - pci_reg_t intr = pci_read_cspace(pci_base, 0x3c); - - struct pci_device* device = vzalloc(sizeof(struct pci_device)); - device->class_info = class; - device->device_info = devinfo; - device->cspace_base = pci_base; - device->intr_info = intr; - - device_create(&device->dev, 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.fn_grp, - pos->devdef.class.device, - pos->devdef.class.variant); - - if (!pos->devdef.init_for) { - kappendf(KERROR "bad def\n"); - goto fail; + if (!pos->devdef.bind) { + kprintf(KERROR "pci_loc:%x, (%xh:%xh.%d) unbindable\n", + loc, + pos->devdef.class.fn_grp, + pos->devdef.class.device, + pos->devdef.class.variant); + goto done; } - int errno = pos->devdef.init_for(&pos->devdef, &device->dev); + int errno = pos->devdef.bind(&pos->devdef, &device->dev); if (errno) { - kappendf(KERROR "failed (e=%d)\n", errno); - goto fail; + kprintf(KERROR "pci_loc:%x, (%xh:%xh.%d) failed, e=%d\n", + loc, + pos->devdef.class.fn_grp, + pos->devdef.class.device, + pos->devdef.class.variant, + errno); + goto done; } - llist_append(&pci_devices, &device->dev_chain); - device_register(&device->dev, &pos->devdef.class, "%x:%x", vendor, devid); + device->binding.def = &pos->devdef; +done: return device; - -fail: - vfree(device); - return NULL; } 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则表示设备不存在 @@ -114,31 +140,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); } } @@ -266,6 +297,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) { @@ -308,13 +347,22 @@ static void __pci_read_binding(struct twimap* map) { struct pci_device* pcidev = twimap_data(map, struct pci_device*); - // check if device binding has been initialized - struct device* dev = device_cast(&pcidev->dev); - if (!dev) { + struct device_def* devdef = pcidev->binding.def; + if (!devdef) { return; } - twimap_printf(map, "0x%x:0x%x", dev->ident.fn_grp, dev->ident.unique); + 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 @@ -323,15 +371,13 @@ 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; @@ -364,6 +410,13 @@ pci_load_devices(struct device_def* def) 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_PCI), diff --git a/lunaix-os/includes/hal/pci.h b/lunaix-os/includes/hal/pci.h index 8c18997..e5bbd45 100644 --- a/lunaix-os/includes/hal/pci.h +++ b/lunaix-os/includes/hal/pci.h @@ -53,13 +53,18 @@ #define PCI_RCMD_MM_ACCESS (1 << 1) #define PCI_RCMD_IO_ACCESS 1 -#define PCI_ADDRESS(bus, dev, funct) \ - (((bus) & 0xff) << 16) | (((dev) & 0xff) << 11) | \ - (((funct) & 0xff) << 8) | 0x80000000 +#define PCI_CFGADDR(pciloc) ((u32_t)(pciloc) << 8) | 0x80000000UL + +#define PCILOC(bus, dev, funct) \ + (((bus) & 0xff) << 8) | (((dev) & 0x1f) << 3) | ((funct) & 0x7) +#define PCILOC_BUS(loc) (((loc) >> 8) & 0xff) +#define PCILOC_DEV(loc) (((loc) >> 3) & 0x1f) +#define PCILOC_FN(loc) ((loc) & 0x7) #define PCI_ID_ANY (-1) typedef unsigned int pci_reg_t; +typedef u16_t pciaddr_t; // PCI device header format // Ref: "PCI Local Bus Specification, Rev.3, Section 6.1" @@ -79,11 +84,20 @@ struct pci_device { struct device dev; struct llist_header dev_chain; + struct hlist_node dev_cache; + + struct + { + struct device* dev; + struct device_def* def; + } binding; + + pciaddr_t loc; + u16_t intr_info; u32_t device_info; u32_t class_info; u32_t cspace_base; u32_t msi_loc; - u16_t intr_info; struct pci_base_addr bar[6]; }; #define PCI_DEVICE(devbase) (container_of((devbase), struct pci_device, dev)) @@ -132,15 +146,14 @@ pci_get_device_by_id(u16_t vendorId, u16_t deviceId); size_t pci_bar_sizing(struct pci_device* dev, u32_t* bar_out, u32_t bar_num); +/** + * @brief Bind an abstract device instance to the pci device + * + * @param pcidev pci device + * @param devobj abstract device instance + */ void -pci_add_driver(const char* name, - u32_t class, - u32_t vendor, - u32_t devid, - pci_drv_init init); - -int -pci_bind_driver(struct pci_device* pci_dev); +pci_bind_instance(struct pci_device* pcidev, void* devobj); void pci_probe_bar_info(struct pci_device* device); diff --git a/lunaix-os/includes/lunaix/device.h b/lunaix-os/includes/lunaix/device.h index 2d9f82b..fac62a9 100644 --- a/lunaix-os/includes/lunaix/device.h +++ b/lunaix-os/includes/lunaix/device.h @@ -116,7 +116,8 @@ struct device_def struct devclass class; int (*init)(struct device_def*); - int (*init_for)(struct device_def*, struct device*); + int (*bind)(struct device_def*, struct device*); + int (*free)(struct device_def*, void* instance); }; static inline u32_t @@ -226,4 +227,6 @@ device_locked(struct device* dev) return mutex_on_hold(&dev->lock); } +#define devprintf_expand(devident) (devident)->fn_grp, (devident)->unique + #endif /* __LUNAIX_DEVICE_H */