From 614ffa927eb7acb1c1fb31f5186f5e3d4b1bca74 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 2 Jun 2024 23:06:29 -0400 Subject: kernel: pci: Add PCI BAR mapping routine Signed-off-by: Ian Moffett --- sys/dev/pci/pci.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'sys/dev') diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 006b428..3be61d9 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -33,7 +33,9 @@ #include #include #include +#include #include +#include #if defined(__x86_64__) #include #endif @@ -182,6 +184,62 @@ pci_scan_bus(uint8_t bus) } } +/* + * Convert a BAR number to BAR register offset. + * + * @dev: Device of BAR to check. + * @bar: Bar number. + */ +static uint8_t +pci_get_barreg(struct pci_device *dev, uint8_t bar) +{ + switch (bar) { + case 0: return PCIREG_BAR0; + case 1: return PCIREG_BAR1; + case 2: return PCIREG_BAR2; + case 3: return PCIREG_BAR3; + case 4: return PCIREG_BAR4; + case 5: return PCIREG_BAR5; + default: return 0; + } +} + +/* + * Map a PCI(e) BAR into kernel memory. + * + * @dev: Device of BAR to map. + * @bar: BAR number to map. + * @vap: Resulting virtual address. + */ +int +pci_map_bar(struct pci_device *dev, uint8_t bar, void **vap) +{ + uint8_t bar_reg = pci_get_barreg(dev, bar); + uintptr_t tmp; + uint32_t size; + + if (bar_reg == 0) { + return -EINVAL; + } + + /* + * Get the length of the region this BAR covers by writing a + * mask of 32 bits into the BAR register and seeing how many + * bits are unset. We can use this to compute the size of the + * region. We know that log2(len) bits must be unset. + */ + tmp = pci_readl(dev, bar_reg); + pci_writel(dev, bar_reg, __MASK(32)); + size = pci_readl(dev, bar_reg); + size = ~size + 1; + + /* Now we need to restore the previous value */ + pci_writel(dev, bar_reg, tmp); + + /* Now do the actual mapping work */ + return bus_map(dev->bar[bar], size, 0, vap); +} + /* * Read PCI(e) configuration space. * -- cgit v1.2.3