source: trunk/pcidev.c @ 1397

Revision 1397, 8.9 KB checked in by uwe, 10 months ago (diff)

Random whitespace and coding-style fixes.

Also, indentation fixes, e.g. due to conversion to msg_*, use ARRAY_SIZE
where possible, wrap overly long line, etc.

Compile-tested. There should be no functional changes.

Signed-off-by: Uwe Hermann <uwe@…>
Acked-by: Uwe Hermann <uwe@…>

Line 
1/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
5 * Copyright (C) 2010, 2011 Carl-Daniel Hailfinger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
20 */
21
22#include <stdlib.h>
23#include <string.h>
24#include "flash.h"
25#include "programmer.h"
26
27uint32_t io_base_addr;
28struct pci_access *pacc;
29struct pci_dev *pcidev_dev = NULL;
30
31enum pci_bartype {
32        TYPE_MEMBAR,
33        TYPE_IOBAR,
34        TYPE_ROMBAR,
35        TYPE_UNKNOWN
36};
37
38uintptr_t pcidev_validate(struct pci_dev *dev, int bar,
39                         const struct pcidev_status *devs)
40{
41        int i;
42        uint64_t addr;
43        uint32_t upperaddr;
44        uint8_t headertype;
45        uint16_t supported_cycles;
46        enum pci_bartype bartype = TYPE_UNKNOWN;
47
48        for (i = 0; devs[i].device_name != NULL; i++) {
49                if (dev->device_id != devs[i].device_id)
50                        continue;
51
52                msg_pinfo("Found \"%s %s\" (%04x:%04x, BDF %02x:%02x.%x).\n",
53                       devs[i].vendor_name, devs[i].device_name,
54                       dev->vendor_id, dev->device_id, dev->bus, dev->dev,
55                       dev->func);
56
57                headertype = pci_read_byte(dev, PCI_HEADER_TYPE) & 0x7f;
58                msg_pspew("PCI header type 0x%02x\n", headertype);
59
60                /*
61                 * Don't use dev->base_addr[x] (as value for 'bar'), won't
62                 * work on older libpci.
63                 */
64                addr = pci_read_long(dev, bar);
65
66                /* Sanity checks. */
67                switch (headertype) {
68                case PCI_HEADER_TYPE_NORMAL:
69                        switch (bar) {
70                        case PCI_BASE_ADDRESS_0:
71                        case PCI_BASE_ADDRESS_1:
72                        case PCI_BASE_ADDRESS_2:
73                        case PCI_BASE_ADDRESS_3:
74                        case PCI_BASE_ADDRESS_4:
75                        case PCI_BASE_ADDRESS_5:
76                                if ((addr & PCI_BASE_ADDRESS_SPACE) ==
77                                    PCI_BASE_ADDRESS_SPACE_IO)
78                                        bartype = TYPE_IOBAR;
79                                else
80                                        bartype = TYPE_MEMBAR;
81                                break;
82                        case PCI_ROM_ADDRESS:
83                                bartype = TYPE_ROMBAR;
84                                break;
85                        }
86                        break;
87                case PCI_HEADER_TYPE_BRIDGE:
88                        switch (bar) {
89                        case PCI_BASE_ADDRESS_0:
90                        case PCI_BASE_ADDRESS_1:
91                                if ((addr & PCI_BASE_ADDRESS_SPACE) ==
92                                    PCI_BASE_ADDRESS_SPACE_IO)
93                                        bartype = TYPE_IOBAR;
94                                else
95                                        bartype = TYPE_MEMBAR;
96                                break;
97                        case PCI_ROM_ADDRESS1:
98                                bartype = TYPE_ROMBAR;
99                                break;
100                        }
101                        break;
102                case PCI_HEADER_TYPE_CARDBUS:
103                        break;
104                default:
105                        msg_perr("Unknown PCI header type 0x%02x, BAR type "
106                                 "cannot be determined reliably.\n", headertype);
107                        break;
108                }
109
110                supported_cycles = pci_read_word(dev, PCI_COMMAND);
111
112                msg_pdbg("Requested BAR is ");
113                switch (bartype) {
114                case TYPE_MEMBAR:
115                        msg_pdbg("MEM");
116                        if (!(supported_cycles & PCI_COMMAND_MEMORY)) {
117                                msg_perr("MEM BAR access requested, but device "
118                                         "has MEM space accesses disabled.\n");
119                                /* TODO: Abort here? */
120                        }
121                        msg_pdbg(", %sbit, %sprefetchable\n",
122                                 ((addr & 0x6) == 0x0) ? "32" :
123                                 (((addr & 0x6) == 0x4) ? "64" : "reserved"),
124                                 (addr & 0x8) ? "" : "not ");
125                        if ((addr & 0x6) == 0x4) {
126                                /* The spec says that a 64-bit register consumes
127                                 * two subsequent dword locations.
128                                 */
129                                upperaddr = pci_read_long(dev, bar + 4);
130                                if (upperaddr != 0x00000000) {
131                                        /* Fun! A real 64-bit resource. */
132                                        if (sizeof(uintptr_t) != sizeof(uint64_t)) {
133                                                msg_perr("BAR unreachable!");
134                                                /* TODO: Really abort here? If
135                                                 * multiple PCI devices match,
136                                                 * we might never tell the user
137                                                 * about the other devices.
138                                                 */
139                                                return 0;
140                                        }
141                                        addr |= (uint64_t)upperaddr << 32;
142                                }
143                        }
144                        addr &= PCI_BASE_ADDRESS_MEM_MASK;
145                        break;
146                case TYPE_IOBAR:
147                        msg_pdbg("I/O\n");
148#if __FLASHROM_HAVE_OUTB__
149                        if (!(supported_cycles & PCI_COMMAND_IO)) {
150                                msg_perr("I/O BAR access requested, but device "
151                                         "has I/O space accesses disabled.\n");
152                                /* TODO: Abort here? */
153                        }
154#else
155                        msg_perr("I/O BAR access requested, but flashrom does "
156                                 "not support I/O BAR access on this platform "
157                                 "(yet).\n");
158#endif
159                        addr &= PCI_BASE_ADDRESS_IO_MASK;
160                        break;
161                case TYPE_ROMBAR:
162                        msg_pdbg("ROM\n");
163                        /* Not sure if this check is needed. */
164                        if (!(supported_cycles & PCI_COMMAND_MEMORY)) {
165                                msg_perr("MEM BAR access requested, but device "
166                                         "has MEM space accesses disabled.\n");
167                                /* TODO: Abort here? */
168                        }
169                        addr &= PCI_ROM_ADDRESS_MASK;
170                        break;
171                case TYPE_UNKNOWN:
172                        msg_perr("BAR type unknown, please report a bug at "
173                                 "flashrom@flashrom.org\n");
174                }
175               
176                if (devs[i].status == NT) {
177                        msg_pinfo("===\nThis PCI device is UNTESTED. Please "
178                                  "report the 'flashrom -p xxxx' output \n"
179                                  "to flashrom@flashrom.org if it works "
180                                  "for you. Please add the name of your\n"
181                                  "PCI device to the subject. Thank you for "
182                                  "your help!\n===\n");
183                }
184
185                return (uintptr_t)addr;
186        }
187
188        return 0;
189}
190
191uintptr_t pcidev_init(int bar, const struct pcidev_status *devs)
192{
193        struct pci_dev *dev;
194        struct pci_filter filter;
195        char *pcidev_bdf;
196        char *msg = NULL;
197        int found = 0;
198        uintptr_t addr = 0, curaddr = 0;
199
200        pacc = pci_alloc();     /* Get the pci_access structure */
201        pci_init(pacc);         /* Initialize the PCI library */
202        pci_scan_bus(pacc);     /* We want to get the list of devices */
203        pci_filter_init(pacc, &filter);
204
205        /* Filter by bb:dd.f (if supplied by the user). */
206        pcidev_bdf = extract_programmer_param("pci");
207        if (pcidev_bdf != NULL) {
208                if ((msg = pci_filter_parse_slot(&filter, pcidev_bdf))) {
209                        msg_perr("Error: %s\n", msg);
210                        exit(1);
211                }
212        }
213        free(pcidev_bdf);
214
215        for (dev = pacc->devices; dev; dev = dev->next) {
216                if (pci_filter_match(&filter, dev)) {
217                        /* FIXME: We should count all matching devices, not
218                         * just those with a valid BAR.
219                         */
220                        if ((addr = pcidev_validate(dev, bar, devs)) != 0) {
221                                curaddr = addr;
222                                pcidev_dev = dev;
223                                found++;
224                        }
225                }
226        }
227
228        /* Only continue if exactly one supported PCI dev has been found. */
229        if (found == 0) {
230                msg_perr("Error: No supported PCI device found.\n");
231                exit(1);
232        } else if (found > 1) {
233                msg_perr("Error: Multiple supported PCI devices found. "
234                        "Use 'flashrom -p xxxx:pci=bb:dd.f' \n"
235                        "to explicitly select the card with the given BDF "
236                        "(PCI bus, device, function).\n");
237                exit(1);
238        }
239
240        return curaddr;
241}
242
243void print_supported_pcidevs(const struct pcidev_status *devs)
244{
245        int i;
246
247        msg_pinfo("PCI devices:\n");
248        for (i = 0; devs[i].vendor_name != NULL; i++) {
249                msg_pinfo("%s %s [%04x:%04x]%s\n", devs[i].vendor_name,
250                          devs[i].device_name, devs[i].vendor_id,
251                          devs[i].device_id,
252                          (devs[i].status == NT) ? " (untested)" : "");
253        }
254}
255
256enum pci_write_type {
257        pci_write_type_byte,
258        pci_write_type_word,
259        pci_write_type_long,
260};
261
262struct undo_pci_write_data {
263        struct pci_dev dev;
264        int reg;
265        enum pci_write_type type;
266        union {
267                uint8_t bytedata;
268                uint16_t worddata;
269                uint32_t longdata;
270        };
271};
272
273int undo_pci_write(void *p)
274{
275        struct undo_pci_write_data *data = p;
276        msg_pdbg("Restoring PCI config space for %02x:%02x:%01x reg 0x%02x\n",
277                 data->dev.bus, data->dev.dev, data->dev.func, data->reg);
278        switch (data->type) {
279        case pci_write_type_byte:
280                pci_write_byte(&data->dev, data->reg, data->bytedata);
281                break;
282        case pci_write_type_word:
283                pci_write_word(&data->dev, data->reg, data->worddata);
284                break;
285        case pci_write_type_long:
286                pci_write_long(&data->dev, data->reg, data->longdata);
287                break;
288        }
289        /* p was allocated in register_undo_pci_write. */
290        free(p);
291        return 0;
292}
293
294#define register_undo_pci_write(a, b, c)                                \
295{                                                                       \
296        struct undo_pci_write_data *undo_pci_write_data;                \
297        undo_pci_write_data = malloc(sizeof(struct undo_pci_write_data)); \
298        if (!undo_pci_write_data) {                                     \
299                msg_gerr("Out of memory!\n");                           \
300                exit(1);                                                \
301        }                                                               \
302        undo_pci_write_data->dev = *a;                                  \
303        undo_pci_write_data->reg = b;                                   \
304        undo_pci_write_data->type = pci_write_type_##c;                 \
305        undo_pci_write_data->c##data = pci_read_##c(dev, reg);          \
306        register_shutdown(undo_pci_write, undo_pci_write_data);         \
307}
308
309#define register_undo_pci_write_byte(a, b) register_undo_pci_write(a, b, byte)
310#define register_undo_pci_write_word(a, b) register_undo_pci_write(a, b, word)
311#define register_undo_pci_write_long(a, b) register_undo_pci_write(a, b, long)
312
313int rpci_write_byte(struct pci_dev *dev, int reg, uint8_t data)
314{
315        register_undo_pci_write_byte(dev, reg);
316        return pci_write_byte(dev, reg, data);
317}
318 
319int rpci_write_word(struct pci_dev *dev, int reg, uint16_t data)
320{
321        register_undo_pci_write_word(dev, reg);
322        return pci_write_word(dev, reg, data);
323}
324 
325int rpci_write_long(struct pci_dev *dev, int reg, uint32_t data)
326{
327        register_undo_pci_write_long(dev, reg);
328        return pci_write_long(dev, reg, data);
329}
Note: See TracBrowser for help on using the repository browser.