[gPXE-devel] [PATCH 29/33] [linux] Add PCI API

Piotr Jaroszyński p.jaroszynski at gmail.com
Sun Aug 15 18:59:34 EDT 2010


Add PCI API using the lpci devices to access the config space.

Signed-off-by: Piotr Jaroszyński <p.jaroszynski at gmail.com>
---
 src/arch/x86/core/linux/linux_api.c |    5 ++
 src/config/defaults/linux.h         |    2 +
 src/include/gpxe/linux/linux_pci.h  |  125 +++++++++++++++++++++++++++++++++++
 src/include/gpxe/pci_io.h           |    1 +
 src/include/linux_api.h             |    2 +
 src/interface/linux/linux_pci.c     |   97 +++++++++++++++++++++++++++
 6 files changed, 232 insertions(+), 0 deletions(-)
 create mode 100644 src/include/gpxe/linux/linux_pci.h
 create mode 100644 src/interface/linux/linux_pci.c

diff --git a/src/arch/x86/core/linux/linux_api.c b/src/arch/x86/core/linux/linux_api.c
index c557bb1..dbd4479 100644
--- a/src/arch/x86/core/linux/linux_api.c
+++ b/src/arch/x86/core/linux/linux_api.c
@@ -54,6 +54,11 @@ ssize_t linux_write(int fd, const void *buf, size_t count)
 	return linux_syscall(__NR_write, fd, buf, count);
 }
 
+off_t linux_lseek(int fd, off_t offset, int whence)
+{
+	return linux_syscall(__NR_lseek, fd, offset, whence);
+}
+
 int linux_fcntl(int fd, int cmd, ...)
 {
 	long arg;
diff --git a/src/config/defaults/linux.h b/src/config/defaults/linux.h
index a678aa4..a917c23 100644
--- a/src/config/defaults/linux.h
+++ b/src/config/defaults/linux.h
@@ -14,6 +14,8 @@
 #define NAP_LINUX
 #define SMBIOS_LINUX
 
+#define PCIAPI_LINUX
+
 #define IMAGE_SCRIPT
 
 #endif /* CONFIG_DEFAULTS_LINUX_H */
diff --git a/src/include/gpxe/linux/linux_pci.h b/src/include/gpxe/linux/linux_pci.h
new file mode 100644
index 0000000..0f78d7f
--- /dev/null
+++ b/src/include/gpxe/linux/linux_pci.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _GPXE_LINUX_PCI_H
+#define _GPXE_LINUX_PCI_H
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+/** @file
+ *
+ * gPXE PCI I/O API for Linux
+ *
+ */
+
+#ifdef PCIAPI_LINUX
+#define PCIAPI_PREFIX_linux
+#else
+#define PCIAPI_PREFIX_linux __linux_
+#endif
+
+struct pci_device;
+
+extern int lpci_read(struct pci_device *pci, unsigned int where, void *value, size_t size);
+extern int lpci_write(struct pci_device *pci, unsigned int where, unsigned long value, size_t size);
+
+/**
+ * Read byte from PCI configuration space via linux
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE(linux, pci_read_config_byte)(struct pci_device *pci, unsigned int where, uint8_t *value)
+{
+	return lpci_read(pci, where, value, sizeof(*value));
+}
+
+/**
+ * Read word from PCI configuration space via linux
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE(linux, pci_read_config_word)(struct pci_device *pci, unsigned int where, uint16_t *value)
+{
+	return lpci_read(pci, where, value, sizeof(*value));
+}
+
+/**
+ * Read dword from PCI configuration space via linux
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value read
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE(linux, pci_read_config_dword)(struct pci_device *pci, unsigned int where, uint32_t *value)
+{
+	return lpci_read(pci, where, value, sizeof(*value));
+}
+
+/**
+ * Write byte to PCI configuration space via linux
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE(linux, pci_write_config_byte)(struct pci_device *pci, unsigned int where, uint8_t value)
+{
+	return lpci_write(pci, where, value, sizeof(value));
+}
+
+/**
+ * Write word to PCI configuration space via linux
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE(linux, pci_write_config_word)(struct pci_device *pci, unsigned int where, uint16_t value)
+{
+	return lpci_write(pci, where, value, sizeof(value));
+}
+
+/**
+ * Write dword to PCI configuration space via linux
+ *
+ * @v pci	PCI device
+ * @v where	Location within PCI configuration space
+ * @v value	Value to be written
+ * @ret rc	Return status code
+ */
+static inline __always_inline int
+PCIAPI_INLINE(linux, pci_write_config_dword)(struct pci_device *pci, unsigned int where, uint32_t value)
+{
+	return lpci_write(pci, where, value, sizeof(value));
+}
+
+#endif /* _GPXE_LINUX_PCI_H */
diff --git a/src/include/gpxe/pci_io.h b/src/include/gpxe/pci_io.h
index 8b2729a..a9f0d73 100644
--- a/src/include/gpxe/pci_io.h
+++ b/src/include/gpxe/pci_io.h
@@ -44,6 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 
 /* Include all architecture-independent I/O API headers */
 #include <gpxe/efi/efi_pci.h>
+#include <gpxe/linux/linux_pci.h>
 
 /* Include all architecture-dependent I/O API headers */
 #include <bits/pci_io.h>
diff --git a/src/include/linux_api.h b/src/include/linux_api.h
index 1bc1f73..3021db7 100644
--- a/src/include/linux_api.h
+++ b/src/include/linux_api.h
@@ -42,6 +42,7 @@ typedef int pid_t;
 #include <linux/fcntl.h>
 #include <linux/ioctl.h>
 #include <linux/poll.h>
+#include <linux/fs.h>
 
 typedef uint32_t useconds_t;
 
@@ -52,6 +53,7 @@ extern int linux_open(const char *pathname, int flags);
 extern int linux_close(int fd);
 extern ssize_t linux_read(int fd, void *buf, size_t count);
 extern ssize_t linux_write(int fd, const void *buf, size_t count);
+extern off_t linux_lseek(int fd, off_t offset, int whence);
 extern int linux_fcntl(int fd, int cmd, ...);
 extern int linux_ioctl(int fd, int request, ...);
 
diff --git a/src/interface/linux/linux_pci.c b/src/interface/linux/linux_pci.c
new file mode 100644
index 0000000..4c066c6
--- /dev/null
+++ b/src/interface/linux/linux_pci.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE(GPL2_OR_LATER);
+
+#include <errno.h>
+#include <linux_api.h>
+#include <gpxe/pci.h>
+#include <gpxe/lpci.h>
+
+/** @file
+ *
+ * gPXE PCI I/O API for linux
+ *
+ */
+
+/** Find a corresponding lpci device and get its PCI config fd */
+static int pci_to_config_fd(struct pci_device *pci)
+{
+	struct lpci_device *lpci;
+	
+	for_each_lpci(lpci) {
+		if (pci->bus == lpci->bus && pci->devfn == lpci->devfn)
+			return lpci->pci_config_fd;
+	}
+
+	return -1;
+}
+
+/** Read from the PCI config space */
+int lpci_read(struct pci_device *pci, unsigned int where, void *value, size_t size)
+{
+	int config_fd = pci_to_config_fd(pci);
+
+	if (linux_lseek(config_fd, where, SEEK_SET) == -1)
+		return -1;
+
+	if (linux_read(config_fd, value, size) != (ssize_t)size)
+		return -1;
+
+	return 0;
+}
+
+/** Write to the PCI config space */
+int lpci_write(struct pci_device *pci, unsigned int where, unsigned long value, size_t size)
+{
+	int config_fd = pci_to_config_fd(pci);
+
+	if (linux_lseek(config_fd, where, SEEK_SET) == -1)
+		return -1;
+
+	if (linux_write(config_fd, &value, size) != (ssize_t)size)
+		return -1;
+
+	return 0;
+}
+
+/**
+ * Determine maximum PCI bus number within system
+ *
+ * @ret max_bus  Maximum bus number
+ */
+static int lpci_pci_max_bus(void)
+{
+	struct lpci_device *lpci;
+	int max_bus = 0;
+
+	for_each_lpci(lpci) {
+		if (lpci->bus > max_bus)
+			max_bus = lpci->bus;
+	}
+
+	return max_bus;
+}
+
+PROVIDE_PCIAPI(linux, pci_max_bus, lpci_pci_max_bus);
+PROVIDE_PCIAPI_INLINE(linux, pci_read_config_byte);
+PROVIDE_PCIAPI_INLINE(linux, pci_read_config_word);
+PROVIDE_PCIAPI_INLINE(linux, pci_read_config_dword);
+PROVIDE_PCIAPI_INLINE(linux, pci_write_config_byte);
+PROVIDE_PCIAPI_INLINE(linux, pci_write_config_word);
+PROVIDE_PCIAPI_INLINE(linux, pci_write_config_dword);
-- 
1.7.1



More information about the gPXE-devel mailing list