aboutsummaryrefslogtreecommitdiffstats
path: root/pcidev.c
blob: add1fce4c05b02adb24aa45824f76910e5f2f626 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * This file is part of the flashrom project.
 *
 * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
 *
 * 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
 * (at your option) 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
 */

#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "flash.h"

uint32_t io_base_addr;
struct pci_access *pacc;
struct pci_filter filter;
struct pci_dev *pcidev_dev = NULL;

uint32_t pcidev_validate(struct pci_dev *dev, uint32_t bar,
			 struct pcidev_status *devs)
{
	int i;
	/* FIXME: 64 bit memory BARs need a 64 bit addr. */
	uint32_t addr;

	for (i = 0; devs[i].device_name != NULL; i++) {
		if (dev->device_id != devs[i].device_id)
			continue;

		/*
		 * Don't use dev->base_addr[x] (as value for 'bar'), won't
		 * work on older libpci.
		 */
		addr = pci_read_long(dev, bar);
		
		msg_pinfo("Found \"%s %s\" (%04x:%04x, BDF %02x:%02x.%x).\n",
		       devs[i].vendor_name, devs[i].device_name,
		       dev->vendor_id, dev->device_id, dev->bus, dev->dev,
		       dev->func);
		msg_pdbg("Requested BAR is %s", (addr & 0x1) ? "IO" : "MEM");
		if (addr & 0x1) {
			/* Mask off IO space indicator and reserved bit. */
			msg_pdbg("\n");
			addr &= ~0x3;
		} else {
			msg_pdbg(", %sbit, %sprefetchable\n",
				 ((addr & 0x6) == 0x0) ? "32" :
				 (((addr & 0x6) == 0x4) ? "64" : "reserved"),
				 (addr & 0x8) ? "" : "not ");
			/* Mask off Mem space indicator, 32/64bit type indicator
			 * and Prefetchable indicator.
			 */
			addr &= ~0xf;
		}

		if (devs[i].status == NT) {
			msg_pinfo("===\nThis PCI device is UNTESTED. Please "
			       "report the 'flashrom -p xxxx' output \n"
			       "to flashrom@flashrom.org if it works "
			       "for you. Thank you for your help!\n===\n");
		}

		return addr;
	}

	return 0;
}

uint32_t pcidev_init(uint16_t vendor_id, uint32_t bar,
		     struct pcidev_status *devs, char *pcidev_bdf)
{
	struct pci_dev *dev;
	char *msg = NULL;
	int found = 0;
	uint32_t addr = 0, curaddr = 0;

	pacc = pci_alloc();     /* Get the pci_access structure */
	pci_init(pacc);         /* Initialize the PCI library */
	pci_scan_bus(pacc);     /* We want to get the list of devices */
	pci_filter_init(pacc, &filter);

	/* Filter by vendor and also bb:dd.f (if supplied by the user). */
	filter.vendor = vendor_id;
	if (pcidev_bdf != NULL) {
		if ((msg = pci_filter_parse_slot(&filter, pcidev_bdf))) {
			msg_perr("Error: %s\n", msg);
			exit(1);
		}
	}

	for (dev = pacc->devices; dev; dev = dev->next) {
		if (pci_filter_match(&filter, dev)) {
			if ((addr = pcidev_validate(dev, bar, devs)) != 0) {
				curaddr = addr;
				pcidev_dev = dev;
				found++;
			}
		}
	}

	/* Only continue if exactly one supported PCI dev has been found. */
	if (found == 0) {
		msg_perr("Error: No supported PCI device found.\n");
		exit(1);
	} else if (found > 1) {
		msg_perr("Error: Multiple supported PCI devices found. "
			"Use 'flashrom -p xxxx:bb:dd.f' \n"
			"to explicitly select the card with the given BDF "
			"(PCI bus, device, function).\n");
		exit(1);
	}

	return curaddr;
}

void print_supported_pcidevs(struct pcidev_status *devs)
{
	int i;

	for (i = 0; devs[i].vendor_name != NULL; i++) {
		msg_pinfo("%s %s [%02x:%02x]%s\n", devs[i].vendor_name,
		       devs[i].device_name, devs[i].vendor_id,
		       devs[i].device_id,
		       (devs[i].status == NT) ? " (untested)" : "");
	}
}