]> xenbits.xensource.com Git - seabios.git/commitdiff
pci: Add helper functions for internal driver BAR handling
authorKevin O'Connor <kevin@koconnor.net>
Wed, 3 Feb 2016 03:09:57 +0000 (22:09 -0500)
committerKevin O'Connor <kevin@koconnor.net>
Wed, 3 Feb 2016 04:16:40 +0000 (23:16 -0500)
Add functions to verify and obtain PCI BARs (Base Address Registers).
These new functions check that the requested BAR is of the right type
and appears valid.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
src/hw/pci.c
src/hw/pci.h

index a241d067548cf919e89cb29f034bd009026b825c..86b7d546bad839b5663ed73b0a509d53821e7473 100644 (file)
@@ -10,6 +10,7 @@
 #include "pci.h" // pci_config_writel
 #include "pci_regs.h" // PCI_VENDOR_ID
 #include "romfile.h" // romfile_loadint
+#include "stacks.h" // wait_preempt
 #include "string.h" // memset
 #include "util.h" // udelay
 #include "x86.h" // outl
@@ -271,6 +272,63 @@ int pci_bridge_has_region(struct pci_device *pci,
     return pci_config_readb(pci->bdf, base) != 0;
 }
 
+// Enable PCI bus-mastering (ie, DMA) support on a pci device
+void
+pci_enable_busmaster(struct pci_device *pci)
+{
+    ASSERT32FLAT();
+    wait_preempt();
+    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER);
+}
+
+// Verify an IO bar and return it to the caller
+u16
+pci_enable_iobar(struct pci_device *pci, u32 addr)
+{
+    ASSERT32FLAT();
+    wait_preempt();
+    u32 bar = pci_config_readl(pci->bdf, addr);
+    if (!(bar & PCI_BASE_ADDRESS_SPACE_IO)) {
+        warn_internalerror();
+        return 0;
+    }
+    bar &= PCI_BASE_ADDRESS_IO_MASK;
+    if (bar == 0 || bar > 0xffff) {
+        warn_internalerror();
+        return 0;
+    }
+    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_IO);
+    return bar;
+}
+
+// Verify a memory bar and return it to the caller
+void *
+pci_enable_membar(struct pci_device *pci, u32 addr)
+{
+    ASSERT32FLAT();
+    wait_preempt();
+    u32 bar = pci_config_readl(pci->bdf, addr);
+    if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
+        warn_internalerror();
+        return NULL;
+    }
+    if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+        u32 high = pci_config_readl(pci->bdf, addr+4);
+        if (high) {
+            dprintf(1, "Can not map memory bar over 4Gig\n");
+            return NULL;
+        }
+    }
+    bar &= PCI_BASE_ADDRESS_MEM_MASK;
+    if (bar + 4*1024*1024 < 20*1024*1024) {
+        // Bar doesn't look valid (it is in last 4M or first 16M)
+        warn_internalerror();
+        return NULL;
+    }
+    pci_config_maskw(pci->bdf, PCI_COMMAND, 0, PCI_COMMAND_MEMORY);
+    return (void*)bar;
+}
+
 void
 pci_reboot(void)
 {
index fc5e7b9bf8068da4201d3e73797a43adad2da187..8e397539284a9e82aaa79e918165c1c61569c3e2 100644 (file)
@@ -126,6 +126,9 @@ struct pci_device *pci_find_init_device(const struct pci_device_id *ids
 u8 pci_find_capability(struct pci_device *pci, u8 cap_id, u8 cap);
 int pci_bridge_has_region(struct pci_device *pci,
                           enum pci_region_type region_type);
+void pci_enable_busmaster(struct pci_device *pci);
+u16 pci_enable_iobar(struct pci_device *pci, u32 addr);
+void *pci_enable_membar(struct pci_device *pci, u32 addr);
 void pci_reboot(void);
 
 #endif