[SeaBIOS] [PATCH 01/14] pci: Add helper functions for internal driver BAR handling
Kevin O'Connor
kevin at koconnor.net
Wed Feb 3 05:18:44 CET 2016
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 at koconnor.net>
---
src/hw/pci.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/hw/pci.h | 3 +++
2 files changed, 61 insertions(+)
diff --git a/src/hw/pci.c b/src/hw/pci.c
index a241d06..86b7d54 100644
--- a/src/hw/pci.c
+++ b/src/hw/pci.c
@@ -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)
{
diff --git a/src/hw/pci.h b/src/hw/pci.h
index fc5e7b9..8e39753 100644
--- a/src/hw/pci.h
+++ b/src/hw/pci.h
@@ -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
--
2.5.0
More information about the SeaBIOS
mailing list