Browse Source

[linux] Add support for accessing PCI configuration space via /proc/bus/pci

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 10 years ago
parent
commit
d8392851d2

+ 4
- 0
src/arch/x86/core/linux/linux_api.c View File

@@ -37,6 +37,10 @@ int linux_close ( int fd ) {
37 37
 	return linux_syscall ( __NR_close, fd );
38 38
 }
39 39
 
40
+off_t linux_lseek ( int fd, off_t offset, int whence ) {
41
+	return linux_syscall ( __NR_lseek, fd, offset, whence );
42
+}
43
+
40 44
 __kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count ) {
41 45
 	return linux_syscall ( __NR_read, fd, buf, count );
42 46
 }

+ 1
- 0
src/config/defaults/linux.h View File

@@ -17,6 +17,7 @@
17 17
 #define ENTROPY_LINUX
18 18
 #define TIME_LINUX
19 19
 #define REBOOT_NULL
20
+#define PCIAPI_LINUX
20 21
 
21 22
 #define DRIVERS_LINUX
22 23
 

+ 1
- 0
src/include/ipxe/errfile.h View File

@@ -275,6 +275,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
275 275
 #define ERRFILE_efi_init	      ( ERRFILE_OTHER | 0x00390000 )
276 276
 #define ERRFILE_efi_timer	      ( ERRFILE_OTHER | 0x003a0000 )
277 277
 #define ERRFILE_efi_umalloc	      ( ERRFILE_OTHER | 0x003b0000 )
278
+#define ERRFILE_linux_pci	      ( ERRFILE_OTHER | 0x003c0000 )
278 279
 
279 280
 /** @} */
280 281
 

+ 8
- 0
src/include/ipxe/linux.h View File

@@ -30,6 +30,14 @@ FILE_LICENCE(GPL2_OR_LATER);
30 30
 #include <ipxe/device.h>
31 31
 #include <ipxe/settings.h>
32 32
 
33
+/**
34
+ * Convert a Linux error number to an iPXE status code
35
+ *
36
+ * @v errno		Linux error number
37
+ * @ret rc		iPXE status code (before negation)
38
+ */
39
+#define ELINUX( errno ) EPLATFORM ( EINFO_EPLATFORM, errno )
40
+
33 41
 /** A linux device */
34 42
 struct linux_device {
35 43
 	/** Generic device */

+ 130
- 0
src/include/ipxe/linux/linux_pci.h View File

@@ -0,0 +1,130 @@
1
+#ifndef _IPXE_LINUX_PCI_H
2
+#define _IPXE_LINUX_PCI_H
3
+
4
+/** @file
5
+ *
6
+ * iPXE PCI API for Linux
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER );
11
+
12
+#ifdef PCIAPI_LINUX
13
+#define PCIAPI_PREFIX_linux
14
+#else
15
+#define PCIAPI_PREFIX_linux __linux_
16
+#endif
17
+
18
+struct pci_device;
19
+
20
+extern int linux_pci_read ( struct pci_device *pci, unsigned long where,
21
+			    unsigned long *value, size_t len );
22
+extern int linux_pci_write ( struct pci_device *pci, unsigned long where,
23
+			     unsigned long value, size_t len );
24
+
25
+/**
26
+ * Read byte from PCI configuration space
27
+ *
28
+ * @v pci	PCI device
29
+ * @v where	Location within PCI configuration space
30
+ * @v value	Value read
31
+ * @ret rc	Return status code
32
+ */
33
+static inline __always_inline int
34
+PCIAPI_INLINE ( linux, pci_read_config_byte ) ( struct pci_device *pci,
35
+						unsigned int where,
36
+						uint8_t *value ) {
37
+	int rc;
38
+	unsigned long tmp;
39
+
40
+	rc = linux_pci_read ( pci, where, &tmp, sizeof ( *value ) );
41
+	*value = tmp;
42
+	return rc;
43
+}
44
+
45
+/**
46
+ * Read word from PCI configuration space
47
+ *
48
+ * @v pci	PCI device
49
+ * @v where	Location within PCI configuration space
50
+ * @v value	Value read
51
+ * @ret rc	Return status code
52
+ */
53
+static inline __always_inline int
54
+PCIAPI_INLINE ( linux, pci_read_config_word ) ( struct pci_device *pci,
55
+						unsigned int where,
56
+						uint16_t *value ) {
57
+	int rc;
58
+	unsigned long tmp;
59
+
60
+	rc = linux_pci_read ( pci, where, &tmp, sizeof ( *value ) );
61
+	*value = tmp;
62
+	return rc;
63
+}
64
+
65
+/**
66
+ * Read dword from PCI configuration space
67
+ *
68
+ * @v pci	PCI device
69
+ * @v where	Location within PCI configuration space
70
+ * @v value	Value read
71
+ * @ret rc	Return status code
72
+ */
73
+static inline __always_inline int
74
+PCIAPI_INLINE ( linux, pci_read_config_dword ) ( struct pci_device *pci,
75
+						 unsigned int where,
76
+						 uint32_t *value ) {
77
+	int rc;
78
+	unsigned long tmp;
79
+
80
+	rc = linux_pci_read ( pci, where, &tmp, sizeof ( *value ) );
81
+	*value = tmp;
82
+	return rc;
83
+}
84
+
85
+/**
86
+ * Write byte to PCI configuration space
87
+ *
88
+ * @v pci	PCI device
89
+ * @v where	Location within PCI configuration space
90
+ * @v value	Value to be written
91
+ * @ret rc	Return status code
92
+ */
93
+static inline __always_inline int
94
+PCIAPI_INLINE ( linux, pci_write_config_byte ) ( struct pci_device *pci,
95
+						 unsigned int where,
96
+						 uint8_t value ) {
97
+	return linux_pci_write ( pci, where, value, sizeof ( value ) );
98
+}
99
+
100
+/**
101
+ * Write word to PCI configuration space
102
+ *
103
+ * @v pci	PCI device
104
+ * @v where	Location within PCI configuration space
105
+ * @v value	Value to be written
106
+ * @ret rc	Return status code
107
+ */
108
+static inline __always_inline int
109
+PCIAPI_INLINE ( linux, pci_write_config_word ) ( struct pci_device *pci,
110
+						 unsigned int where,
111
+						 uint16_t value ) {
112
+	return linux_pci_write ( pci, where, value, sizeof ( value ) );
113
+}
114
+
115
+/**
116
+ * Write dword to PCI configuration space
117
+ *
118
+ * @v pci	PCI device
119
+ * @v where	Location within PCI configuration space
120
+ * @v value	Value to be written
121
+ * @ret rc	Return status code
122
+ */
123
+static inline __always_inline int
124
+PCIAPI_INLINE ( linux, pci_write_config_dword ) ( struct pci_device *pci,
125
+						  unsigned int where,
126
+						  uint32_t value ) {
127
+	return linux_pci_write ( pci, where, value, sizeof ( value ) );
128
+}
129
+
130
+#endif /* _IPXE_LINUX_PCI_H */

+ 1
- 0
src/include/ipxe/pci_io.h View File

@@ -44,6 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
44 44
 
45 45
 /* Include all architecture-independent I/O API headers */
46 46
 #include <ipxe/efi/efi_pci_api.h>
47
+#include <ipxe/linux/linux_pci.h>
47 48
 
48 49
 /* Include all architecture-dependent I/O API headers */
49 50
 #include <bits/pci_io.h>

+ 2
- 0
src/include/linux_api.h View File

@@ -47,11 +47,13 @@ typedef __kernel_loff_t loff_t;
47 47
 typedef unsigned long nfds_t;
48 48
 typedef uint32_t useconds_t;
49 49
 #define MAP_FAILED ( ( void * ) -1 )
50
+#define SEEK_SET 0
50 51
 
51 52
 extern long linux_syscall ( int number, ... );
52 53
 
53 54
 extern int linux_open ( const char *pathname, int flags );
54 55
 extern int linux_close ( int fd );
56
+extern off_t linux_lseek ( int fd, off_t offset, int whence );
55 57
 extern __kernel_ssize_t linux_read ( int fd, void *buf, __kernel_size_t count );
56 58
 extern __kernel_ssize_t linux_write ( int fd, const void *buf,
57 59
 				      __kernel_size_t count );

+ 185
- 0
src/interface/linux/linux_pci.c View File

@@ -0,0 +1,185 @@
1
+/*
2
+ * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+#include <stdio.h>
23
+#include <errno.h>
24
+#include <byteswap.h>
25
+#include <linux_api.h>
26
+#include <ipxe/linux.h>
27
+#include <ipxe/pci.h>
28
+
29
+/** @file
30
+ *
31
+ * iPXE PCI API for Linux
32
+ *
33
+ */
34
+
35
+/**
36
+ * Open PCI configuration space
37
+ *
38
+ * @v pci		PCI device
39
+ * @v flags		Access mode flags
40
+ * @v where		Address within configuration space
41
+ * @ret fd		File handle, or negative error
42
+ */
43
+static int linux_pci_open ( struct pci_device *pci, int flags,
44
+			    unsigned long where ) {
45
+	char filename[ 22 /* "/proc/bus/pci/xx/xx.x" + NUL */ ];
46
+	int fd;
47
+	int rc;
48
+
49
+	/* Construct filename */
50
+	snprintf ( filename, sizeof ( filename ), "/proc/bus/pci/%02x/%02x.%x",
51
+		   PCI_BUS ( pci->busdevfn ), PCI_SLOT ( pci->busdevfn ),
52
+		   PCI_FUNC ( pci->busdevfn ) );
53
+
54
+	/* Open file */
55
+	fd = linux_open ( filename, flags );
56
+	if ( fd < 0 ) {
57
+		DBGC ( pci, "PCI could not open %s: %s\n", filename,
58
+		       linux_strerror ( linux_errno ) );
59
+		rc = -ELINUX ( linux_errno );
60
+		goto err_open;
61
+	}
62
+
63
+	/* Seek to location */
64
+	if ( linux_lseek ( fd, where, SEEK_SET ) < 0 ) {
65
+		DBGC ( pci, "PCI could not seek to %s offset %#02lx: %s\n",
66
+		       filename, where, linux_strerror ( linux_errno ) );
67
+		rc = -ELINUX ( linux_errno );
68
+		goto err_seek;
69
+	}
70
+
71
+	return fd;
72
+
73
+ err_seek:
74
+	linux_close ( fd );
75
+ err_open:
76
+	return rc;
77
+}
78
+
79
+/**
80
+ * Read from PCI configuration space
81
+ *
82
+ * @v pci		PCI device
83
+ * @v where		Address within configuration space
84
+ * @v value		Data buffer
85
+ * @v len		Length to read
86
+ * @ret rc		Return status code
87
+ */
88
+int linux_pci_read ( struct pci_device *pci, unsigned long where,
89
+		     unsigned long *value, size_t len ) {
90
+	uint32_t tmp = 0;
91
+	int fd;
92
+	int check_len;
93
+	int rc;
94
+
95
+	/* Return "missing device" in case of error */
96
+	*value = -1UL;
97
+
98
+	/* Open configuration space */
99
+	fd = linux_pci_open ( pci, O_RDONLY, where );
100
+	if ( fd < 0 ) {
101
+		rc = fd;
102
+		goto err_open;
103
+	}
104
+
105
+	/* Read value */
106
+	check_len = linux_read ( fd, &tmp, len );
107
+	if ( check_len < 0 ) {
108
+		DBGC ( pci, "PCI could not read from " PCI_FMT " %#02lx+%#zx: "
109
+		       "%s\n", PCI_ARGS ( pci ), where, len,
110
+		       linux_strerror ( linux_errno ) );
111
+		rc = -ELINUX ( linux_errno );
112
+		goto err_read;
113
+	}
114
+	if ( ( size_t ) check_len != len ) {
115
+		DBGC ( pci, "PCI read only %#x bytes from " PCI_FMT
116
+		       " %#02lx+%#zx\n", check_len, PCI_ARGS ( pci ),
117
+		       where, len );
118
+		rc = -EIO;
119
+		goto err_read;
120
+	}
121
+
122
+	/* Return value */
123
+	*value = le32_to_cpu ( tmp );
124
+
125
+	/* Success */
126
+	rc = 0;
127
+
128
+ err_read:
129
+	linux_close ( fd );
130
+ err_open:
131
+	return rc;
132
+}
133
+
134
+/**
135
+ * Write to PCI configuration space
136
+ *
137
+ * @v pci		PCI device
138
+ * @v where		Address within configuration space
139
+ * @v value		Value to write
140
+ * @v len		Length of value
141
+ * @ret rc		Return status code
142
+ */
143
+int linux_pci_write ( struct pci_device *pci, unsigned long where,
144
+		      unsigned long value, size_t len ) {
145
+	uint32_t tmp;
146
+	int fd;
147
+	int check_len;
148
+	int rc;
149
+
150
+	/* Open configuration space */
151
+	fd = linux_pci_open ( pci, O_WRONLY, where );
152
+	if ( fd < 0 ) {
153
+		rc = fd;
154
+		goto err_open;
155
+	}
156
+
157
+	/* Prepare value for writing */
158
+	tmp = cpu_to_le32 ( value );
159
+	assert ( len <= sizeof ( tmp ) );
160
+
161
+	/* Write value */
162
+	check_len = linux_write ( fd, &tmp, len );
163
+	if ( check_len < 0 ) {
164
+		DBGC ( pci, "PCI could not write to " PCI_FMT " %#02lx+%#zx: "
165
+		       "%s\n", PCI_ARGS ( pci ), where, len,
166
+		       linux_strerror ( linux_errno ) );
167
+		rc = -ELINUX ( linux_errno );
168
+		goto err_write;
169
+	}
170
+	if ( ( size_t ) check_len != len ) {
171
+		DBGC ( pci, "PCI wrote only %#x bytes to " PCI_FMT
172
+		       " %#02lx+%#zx\n", check_len, PCI_ARGS ( pci ),
173
+		       where, len );
174
+		rc = -EIO;
175
+		goto err_write;
176
+	}
177
+
178
+	/* Success */
179
+	rc = 0;
180
+
181
+ err_write:
182
+	linux_close ( fd );
183
+ err_open:
184
+	return rc;
185
+}

Loading…
Cancel
Save