Browse Source

[pci] Add support for PCI Enhanced Allocation

Some embedded devices have immovable BARs, which are described via a
PCI Enhanced Allocation capability.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 years ago
parent
commit
6d2bdc4ea3
4 changed files with 221 additions and 0 deletions
  1. 149
    0
      src/drivers/bus/pciea.c
  2. 1
    0
      src/include/ipxe/errfile.h
  3. 1
    0
      src/include/ipxe/pci.h
  4. 70
    0
      src/include/ipxe/pciea.h

+ 149
- 0
src/drivers/bus/pciea.c View File

@@ -0,0 +1,149 @@
1
+/*
2
+ * Copyright (C) 2016 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
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+#include <stdint.h>
27
+#include <errno.h>
28
+#include <ipxe/pci.h>
29
+#include <ipxe/pciea.h>
30
+
31
+/** @file
32
+ *
33
+ * PCI Enhanced Allocation
34
+ *
35
+ */
36
+
37
+/**
38
+ * Locate PCI Enhanced Allocation BAR equivalent entry
39
+ *
40
+ * @v pci		PCI device
41
+ * @v bei		BAR equivalent indicator
42
+ * @ret offset		PCI Enhanced Allocation entry offset, or negative error
43
+ */
44
+static int pciea_offset ( struct pci_device *pci, unsigned int bei ) {
45
+	uint8_t entries;
46
+	uint32_t desc;
47
+	unsigned int i;
48
+	int offset;
49
+
50
+	/* Locate Enhanced Allocation capability */
51
+	offset = pci_find_capability ( pci, PCI_CAP_ID_EA );
52
+	if ( offset < 0 )
53
+		return offset;
54
+
55
+	/* Get number of entries */
56
+	pci_read_config_byte ( pci, ( offset + PCIEA_ENTRIES ), &entries );
57
+	entries &= PCIEA_ENTRIES_MASK;
58
+
59
+	/* Locate first entry */
60
+	offset += PCIEA_FIRST;
61
+
62
+	/* Search for a matching entry */
63
+	for ( i = 0 ; i < entries ; i++ ) {
64
+
65
+		/* Read entry descriptor */
66
+		pci_read_config_dword ( pci, offset, &desc );
67
+
68
+		/* Check for a matching entry */
69
+		if ( ( desc & PCIEA_DESC_ENABLED ) &&
70
+		     ( bei == PCIEA_DESC_BEI ( desc ) ) )
71
+			return offset;
72
+
73
+		/* Move to next entry */
74
+		offset += ( ( PCIEA_DESC_SIZE ( desc ) + 1 ) << 2 );
75
+	}
76
+
77
+	return -ENOENT;
78
+}
79
+
80
+/**
81
+ * Read PCI Enhanced Allocation BAR equivalent value
82
+ *
83
+ * @v pci		PCI device
84
+ * @v bei		BAR equivalent indicator
85
+ * @v low_offset	Offset to low dword of value
86
+ * @ret value		BAR equivalent value
87
+ */
88
+static unsigned long pciea_bar_value ( struct pci_device *pci, unsigned int bei,
89
+				       unsigned int low_offset ) {
90
+	uint32_t low;
91
+	uint32_t high;
92
+	int offset;
93
+
94
+	/* Locate Enhanced Allocation offset for this BEI */
95
+	offset = pciea_offset ( pci, bei );
96
+	if ( offset < 0 )
97
+		return 0;
98
+
99
+	/* Read BAR equivalent */
100
+	offset += low_offset;
101
+	pci_read_config_dword ( pci, offset, &low );
102
+	if ( low & PCIEA_LOW_ATTR_64BIT ) {
103
+		offset += PCIEA_LOW_HIGH;
104
+		pci_read_config_dword ( pci, offset, &high );
105
+		if ( high ) {
106
+			if ( sizeof ( unsigned long ) > sizeof ( uint32_t ) ) {
107
+				return ( ( ( uint64_t ) high << 32 ) | low );
108
+			} else {
109
+				DBGC ( pci, PCI_FMT " unhandled 64-bit EA BAR "
110
+				       "%08x%08x\n",
111
+				       PCI_ARGS ( pci ), high, low );
112
+				return 0;
113
+			}
114
+		}
115
+	}
116
+	return low;
117
+}
118
+
119
+/**
120
+ * Find the start of a PCI Enhanced Allocation BAR equivalent
121
+ *
122
+ * @v pci		PCI device
123
+ * @v bei		BAR equivalent indicator
124
+ * @ret start		BAR start address
125
+ *
126
+ * If the address exceeds the size of an unsigned long (i.e. if a
127
+ * 64-bit BAR has a non-zero high dword on a 32-bit machine), the
128
+ * return value will be zero.
129
+ */
130
+unsigned long pciea_bar_start ( struct pci_device *pci, unsigned int bei ) {
131
+	unsigned long base;
132
+
133
+	base = pciea_bar_value ( pci, bei, PCIEA_LOW_BASE );
134
+	return ( base & ~PCIEA_LOW_ATTR_MASK );
135
+}
136
+
137
+/**
138
+ * Find the size of a PCI Enhanced Allocation BAR equivalent
139
+ *
140
+ * @v pci		PCI device
141
+ * @v bei		BAR equivalent indicator
142
+ * @ret size		BAR size
143
+ */
144
+unsigned long pciea_bar_size ( struct pci_device *pci, unsigned int bei ) {
145
+	unsigned long limit;
146
+
147
+	limit = pciea_bar_value ( pci, bei, PCIEA_LOW_LIMIT );
148
+	return ( limit ? ( ( limit | PCIEA_LOW_ATTR_MASK ) + 1 ) : 0 );
149
+}

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

@@ -189,6 +189,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
189 189
 #define ERRFILE_golan		     ( ERRFILE_DRIVER | 0x007d0000 )
190 190
 #define ERRFILE_flexboot_nodnic	     ( ERRFILE_DRIVER | 0x007e0000 )
191 191
 #define ERRFILE_virtio_pci	     ( ERRFILE_DRIVER | 0x007f0000 )
192
+#define ERRFILE_pciea		     ( ERRFILE_DRIVER | 0x00c00000 )
192 193
 
193 194
 #define ERRFILE_aoe			( ERRFILE_NET | 0x00000000 )
194 195
 #define ERRFILE_arp			( ERRFILE_NET | 0x00010000 )

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

@@ -94,6 +94,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
94 94
 #define PCI_CAP_ID_VPD			0x03	/**< Vital product data */
95 95
 #define PCI_CAP_ID_VNDR			0x09	/**< Vendor-specific */
96 96
 #define PCI_CAP_ID_EXP			0x10	/**< PCI Express */
97
+#define PCI_CAP_ID_EA			0x14	/**< Enhanced Allocation */
97 98
 
98 99
 /** Next capability */
99 100
 #define PCI_CAP_NEXT		0x01

+ 70
- 0
src/include/ipxe/pciea.h View File

@@ -0,0 +1,70 @@
1
+#ifndef _IPXE_PCIEA_H
2
+#define _IPXE_PCIEA_H
3
+
4
+/** @file
5
+ *
6
+ * PCI Enhanced Allocation
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
+
12
+#include <ipxe/pci.h>
13
+
14
+/** Number of entries */
15
+#define PCIEA_ENTRIES 2
16
+#define PCIEA_ENTRIES_MASK 0x3f
17
+
18
+/** First entry */
19
+#define PCIEA_FIRST 4
20
+
21
+/** Entry descriptor */
22
+#define PCIEA_DESC 0
23
+
24
+/** Entry size */
25
+#define PCIEA_DESC_SIZE(desc) ( ( (desc) >> 0 ) & 0x7 )
26
+
27
+/** BAR equivalent indicator */
28
+#define PCIEA_DESC_BEI(desc) ( ( (desc) >> 4 ) & 0xf )
29
+
30
+/** BAR equivalent indicators */
31
+enum pciea_bei {
32
+	PCIEA_BEI_BAR_0 = 0,		/**< Standard BAR 0 */
33
+	PCIEA_BEI_BAR_1 = 1,		/**< Standard BAR 1 */
34
+	PCIEA_BEI_BAR_2 = 2,		/**< Standard BAR 2 */
35
+	PCIEA_BEI_BAR_3 = 3,		/**< Standard BAR 3 */
36
+	PCIEA_BEI_BAR_4 = 4,		/**< Standard BAR 4 */
37
+	PCIEA_BEI_BAR_5 = 5,		/**< Standard BAR 5 */
38
+	PCIEA_BEI_ROM = 8,		/**< Expansion ROM BAR */
39
+	PCIEA_BEI_VF_BAR_0 = 9,		/**< Virtual function BAR 0 */
40
+	PCIEA_BEI_VF_BAR_1 = 10,	/**< Virtual function BAR 1 */
41
+	PCIEA_BEI_VF_BAR_2 = 11,	/**< Virtual function BAR 2 */
42
+	PCIEA_BEI_VF_BAR_3 = 12,	/**< Virtual function BAR 3 */
43
+	PCIEA_BEI_VF_BAR_4 = 13,	/**< Virtual function BAR 4 */
44
+	PCIEA_BEI_VF_BAR_5 = 14,	/**< Virtual function BAR 5 */
45
+};
46
+
47
+/** Entry is enabled */
48
+#define PCIEA_DESC_ENABLED 0x80000000UL
49
+
50
+/** Base address low dword */
51
+#define PCIEA_LOW_BASE 4
52
+
53
+/** Limit low dword */
54
+#define PCIEA_LOW_LIMIT 8
55
+
56
+/** BAR is 64-bit */
57
+#define PCIEA_LOW_ATTR_64BIT 0x00000002UL
58
+
59
+/** Low dword attribute bit mask */
60
+#define PCIEA_LOW_ATTR_MASK 0x00000003UL
61
+
62
+/** Offset to high dwords */
63
+#define PCIEA_LOW_HIGH 8
64
+
65
+extern unsigned long pciea_bar_start ( struct pci_device *pci,
66
+				       unsigned int bei );
67
+extern unsigned long pciea_bar_size ( struct pci_device *pci,
68
+				      unsigned int bei );
69
+
70
+#endif /* _IPXE_PCIEA_H */

Loading…
Cancel
Save