#define pr_fmt(fmt) "pci: " fmt #include #include #include #include #include #include #include #include #include struct pci_ecam { struct pci_access access; void* base; }; static void* ecam_ptr(struct pci_access* self, const struct pci_address* addr, uint16_t offset) { struct pci_ecam* ecam = containerof(self, struct pci_ecam, access); size_t index = (size_t)(addr->bus - self->start_bus) << 20 | (size_t)(addr->device & 0x1f) << 15 | (size_t)(addr->function & 0x7) << 12 | (offset & 0xffc); return (uint8_t*)ecam->base + index; } static uint32_t ecam_read32(struct pci_access* self, const struct pci_address* addr, uint16_t offset) { return mmio_read32(ecam_ptr(self, addr, offset)); } static void ecam_write32(struct pci_access* self, const struct pci_address* addr, uint16_t offset, uint32_t value) { mmio_write32(ecam_ptr(self, addr, offset), value); } errno_t pci_ecam_register(phys_t base, uint16_t domain, uint8_t start_bus, uint8_t end_bus) { if (end_bus < start_bus) return EINVAL; size_t length = ((size_t)(end_bus - start_bus) + 1) << 20; phys_t phys = base + ((phys_t)start_bus << 20); uintptr_t vaddr = vm_alloc(length); if (!vaddr) return ENOMEM; for (size_t i = 0; i < length; i += arch_mem_page_size()) { errno_t status = pmap_map(&kernel_vma.pmap, vaddr + i, phys + i, PTE_READ | PTE_WRITE, CACHE_MMIO); if (status != 0) return status; } struct pci_ecam* ecam = mem_alloc(sizeof(*ecam), 0); if (ecam == nullptr) return ENOMEM; *ecam = (struct pci_ecam){ .access = { .name = "ecam", .domain = domain, .start_bus = start_bus, .end_bus = end_bus, .priority = PCI_ACCESS_PRIO_ECAM, .read32 = ecam_read32, .write32 = ecam_write32, }, .base = (void*)vaddr, }; errno_t status = pci_access_register(&ecam->access); if (status != 0) { mem_free(ecam); return status; } log("ECAM for %.4hx:%.2hhx - %.4hx:%.2hhx at %p\n", domain, start_bus, domain, end_bus, (void*)phys); return 0; }