[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