1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker * The PCI Library -- Configuration Access via /sys/bus/pci
3*c2e0c6b5SAndroid Build Coastguard Worker *
4*c2e0c6b5SAndroid Build Coastguard Worker * Copyright (c) 2003 Matthew Wilcox <[email protected]>
5*c2e0c6b5SAndroid Build Coastguard Worker * Copyright (c) 1997--2024 Martin Mares <[email protected]>
6*c2e0c6b5SAndroid Build Coastguard Worker *
7*c2e0c6b5SAndroid Build Coastguard Worker * Can be freely distributed and used under the terms of the GNU GPL v2+.
8*c2e0c6b5SAndroid Build Coastguard Worker *
9*c2e0c6b5SAndroid Build Coastguard Worker * SPDX-License-Identifier: GPL-2.0-or-later
10*c2e0c6b5SAndroid Build Coastguard Worker */
11*c2e0c6b5SAndroid Build Coastguard Worker
12*c2e0c6b5SAndroid Build Coastguard Worker #define _GNU_SOURCE
13*c2e0c6b5SAndroid Build Coastguard Worker
14*c2e0c6b5SAndroid Build Coastguard Worker #include <stdio.h>
15*c2e0c6b5SAndroid Build Coastguard Worker #include <stdlib.h>
16*c2e0c6b5SAndroid Build Coastguard Worker #include <string.h>
17*c2e0c6b5SAndroid Build Coastguard Worker #include <stdarg.h>
18*c2e0c6b5SAndroid Build Coastguard Worker #include <unistd.h>
19*c2e0c6b5SAndroid Build Coastguard Worker #include <errno.h>
20*c2e0c6b5SAndroid Build Coastguard Worker #include <dirent.h>
21*c2e0c6b5SAndroid Build Coastguard Worker #include <fcntl.h>
22*c2e0c6b5SAndroid Build Coastguard Worker #include <libgen.h>
23*c2e0c6b5SAndroid Build Coastguard Worker #include <sys/types.h>
24*c2e0c6b5SAndroid Build Coastguard Worker
25*c2e0c6b5SAndroid Build Coastguard Worker #include "internal.h"
26*c2e0c6b5SAndroid Build Coastguard Worker
27*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_config(struct pci_access * a)28*c2e0c6b5SAndroid Build Coastguard Worker sysfs_config(struct pci_access *a)
29*c2e0c6b5SAndroid Build Coastguard Worker {
30*c2e0c6b5SAndroid Build Coastguard Worker pci_define_param(a, "sysfs.path", PCI_PATH_SYS_BUS_PCI, "Path to the sysfs device tree");
31*c2e0c6b5SAndroid Build Coastguard Worker }
32*c2e0c6b5SAndroid Build Coastguard Worker
33*c2e0c6b5SAndroid Build Coastguard Worker static inline char *
sysfs_name(struct pci_access * a)34*c2e0c6b5SAndroid Build Coastguard Worker sysfs_name(struct pci_access *a)
35*c2e0c6b5SAndroid Build Coastguard Worker {
36*c2e0c6b5SAndroid Build Coastguard Worker return pci_get_param(a, "sysfs.path");
37*c2e0c6b5SAndroid Build Coastguard Worker }
38*c2e0c6b5SAndroid Build Coastguard Worker
39*c2e0c6b5SAndroid Build Coastguard Worker static int
sysfs_detect(struct pci_access * a)40*c2e0c6b5SAndroid Build Coastguard Worker sysfs_detect(struct pci_access *a)
41*c2e0c6b5SAndroid Build Coastguard Worker {
42*c2e0c6b5SAndroid Build Coastguard Worker if (access(sysfs_name(a), R_OK))
43*c2e0c6b5SAndroid Build Coastguard Worker {
44*c2e0c6b5SAndroid Build Coastguard Worker a->debug("...cannot open %s", sysfs_name(a));
45*c2e0c6b5SAndroid Build Coastguard Worker return 0;
46*c2e0c6b5SAndroid Build Coastguard Worker }
47*c2e0c6b5SAndroid Build Coastguard Worker a->debug("...using %s", sysfs_name(a));
48*c2e0c6b5SAndroid Build Coastguard Worker return 1;
49*c2e0c6b5SAndroid Build Coastguard Worker }
50*c2e0c6b5SAndroid Build Coastguard Worker
51*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_init(struct pci_access * a)52*c2e0c6b5SAndroid Build Coastguard Worker sysfs_init(struct pci_access *a)
53*c2e0c6b5SAndroid Build Coastguard Worker {
54*c2e0c6b5SAndroid Build Coastguard Worker a->fd = -1;
55*c2e0c6b5SAndroid Build Coastguard Worker a->fd_vpd = -1;
56*c2e0c6b5SAndroid Build Coastguard Worker }
57*c2e0c6b5SAndroid Build Coastguard Worker
58*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_flush_cache(struct pci_access * a)59*c2e0c6b5SAndroid Build Coastguard Worker sysfs_flush_cache(struct pci_access *a)
60*c2e0c6b5SAndroid Build Coastguard Worker {
61*c2e0c6b5SAndroid Build Coastguard Worker if (a->fd >= 0)
62*c2e0c6b5SAndroid Build Coastguard Worker {
63*c2e0c6b5SAndroid Build Coastguard Worker close(a->fd);
64*c2e0c6b5SAndroid Build Coastguard Worker a->fd = -1;
65*c2e0c6b5SAndroid Build Coastguard Worker }
66*c2e0c6b5SAndroid Build Coastguard Worker if (a->fd_vpd >= 0)
67*c2e0c6b5SAndroid Build Coastguard Worker {
68*c2e0c6b5SAndroid Build Coastguard Worker close(a->fd_vpd);
69*c2e0c6b5SAndroid Build Coastguard Worker a->fd_vpd = -1;
70*c2e0c6b5SAndroid Build Coastguard Worker }
71*c2e0c6b5SAndroid Build Coastguard Worker a->cached_dev = NULL;
72*c2e0c6b5SAndroid Build Coastguard Worker }
73*c2e0c6b5SAndroid Build Coastguard Worker
74*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_cleanup(struct pci_access * a)75*c2e0c6b5SAndroid Build Coastguard Worker sysfs_cleanup(struct pci_access *a)
76*c2e0c6b5SAndroid Build Coastguard Worker {
77*c2e0c6b5SAndroid Build Coastguard Worker sysfs_flush_cache(a);
78*c2e0c6b5SAndroid Build Coastguard Worker }
79*c2e0c6b5SAndroid Build Coastguard Worker
80*c2e0c6b5SAndroid Build Coastguard Worker #define OBJNAMELEN 1024
81*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_obj_name(struct pci_dev * d,char * object,char * buf)82*c2e0c6b5SAndroid Build Coastguard Worker sysfs_obj_name(struct pci_dev *d, char *object, char *buf)
83*c2e0c6b5SAndroid Build Coastguard Worker {
84*c2e0c6b5SAndroid Build Coastguard Worker int n = snprintf(buf, OBJNAMELEN, "%s/devices/%04x:%02x:%02x.%d/%s",
85*c2e0c6b5SAndroid Build Coastguard Worker sysfs_name(d->access), d->domain, d->bus, d->dev, d->func, object);
86*c2e0c6b5SAndroid Build Coastguard Worker if (n < 0 || n >= OBJNAMELEN)
87*c2e0c6b5SAndroid Build Coastguard Worker d->access->error("File name too long");
88*c2e0c6b5SAndroid Build Coastguard Worker }
89*c2e0c6b5SAndroid Build Coastguard Worker
90*c2e0c6b5SAndroid Build Coastguard Worker #define OBJBUFSIZE 1024
91*c2e0c6b5SAndroid Build Coastguard Worker
92*c2e0c6b5SAndroid Build Coastguard Worker static int
sysfs_get_string(struct pci_dev * d,char * object,char * buf,int mandatory)93*c2e0c6b5SAndroid Build Coastguard Worker sysfs_get_string(struct pci_dev *d, char *object, char *buf, int mandatory)
94*c2e0c6b5SAndroid Build Coastguard Worker {
95*c2e0c6b5SAndroid Build Coastguard Worker struct pci_access *a = d->access;
96*c2e0c6b5SAndroid Build Coastguard Worker int fd, n;
97*c2e0c6b5SAndroid Build Coastguard Worker char namebuf[OBJNAMELEN];
98*c2e0c6b5SAndroid Build Coastguard Worker void (*warn)(char *msg, ...) = (mandatory ? a->error : a->warning);
99*c2e0c6b5SAndroid Build Coastguard Worker
100*c2e0c6b5SAndroid Build Coastguard Worker sysfs_obj_name(d, object, namebuf);
101*c2e0c6b5SAndroid Build Coastguard Worker fd = open(namebuf, O_RDONLY);
102*c2e0c6b5SAndroid Build Coastguard Worker if (fd < 0)
103*c2e0c6b5SAndroid Build Coastguard Worker {
104*c2e0c6b5SAndroid Build Coastguard Worker if (mandatory || errno != ENOENT)
105*c2e0c6b5SAndroid Build Coastguard Worker warn("Cannot open %s: %s", namebuf, strerror(errno));
106*c2e0c6b5SAndroid Build Coastguard Worker return 0;
107*c2e0c6b5SAndroid Build Coastguard Worker }
108*c2e0c6b5SAndroid Build Coastguard Worker n = read(fd, buf, OBJBUFSIZE);
109*c2e0c6b5SAndroid Build Coastguard Worker int read_errno = errno;
110*c2e0c6b5SAndroid Build Coastguard Worker close(fd);
111*c2e0c6b5SAndroid Build Coastguard Worker if (n < 0)
112*c2e0c6b5SAndroid Build Coastguard Worker {
113*c2e0c6b5SAndroid Build Coastguard Worker warn("Error reading %s: %s", namebuf, strerror(read_errno));
114*c2e0c6b5SAndroid Build Coastguard Worker return 0;
115*c2e0c6b5SAndroid Build Coastguard Worker }
116*c2e0c6b5SAndroid Build Coastguard Worker if (n >= OBJBUFSIZE)
117*c2e0c6b5SAndroid Build Coastguard Worker {
118*c2e0c6b5SAndroid Build Coastguard Worker warn("Value in %s too long", namebuf);
119*c2e0c6b5SAndroid Build Coastguard Worker return 0;
120*c2e0c6b5SAndroid Build Coastguard Worker }
121*c2e0c6b5SAndroid Build Coastguard Worker buf[n] = 0;
122*c2e0c6b5SAndroid Build Coastguard Worker return 1;
123*c2e0c6b5SAndroid Build Coastguard Worker }
124*c2e0c6b5SAndroid Build Coastguard Worker
125*c2e0c6b5SAndroid Build Coastguard Worker static char *
sysfs_deref_link(struct pci_dev * d,char * link_name)126*c2e0c6b5SAndroid Build Coastguard Worker sysfs_deref_link(struct pci_dev *d, char *link_name)
127*c2e0c6b5SAndroid Build Coastguard Worker {
128*c2e0c6b5SAndroid Build Coastguard Worker char path[2*OBJNAMELEN], rel_path[OBJNAMELEN];
129*c2e0c6b5SAndroid Build Coastguard Worker
130*c2e0c6b5SAndroid Build Coastguard Worker sysfs_obj_name(d, link_name, path);
131*c2e0c6b5SAndroid Build Coastguard Worker memset(rel_path, 0, sizeof(rel_path));
132*c2e0c6b5SAndroid Build Coastguard Worker
133*c2e0c6b5SAndroid Build Coastguard Worker if (readlink(path, rel_path, sizeof(rel_path)) < 0)
134*c2e0c6b5SAndroid Build Coastguard Worker return NULL;
135*c2e0c6b5SAndroid Build Coastguard Worker
136*c2e0c6b5SAndroid Build Coastguard Worker sysfs_obj_name(d, "", path);
137*c2e0c6b5SAndroid Build Coastguard Worker strcat(path, rel_path);
138*c2e0c6b5SAndroid Build Coastguard Worker
139*c2e0c6b5SAndroid Build Coastguard Worker // Returns a pointer to malloc'ed memory
140*c2e0c6b5SAndroid Build Coastguard Worker return realpath(path, NULL);
141*c2e0c6b5SAndroid Build Coastguard Worker }
142*c2e0c6b5SAndroid Build Coastguard Worker
143*c2e0c6b5SAndroid Build Coastguard Worker static int
sysfs_get_value(struct pci_dev * d,char * object,int mandatory)144*c2e0c6b5SAndroid Build Coastguard Worker sysfs_get_value(struct pci_dev *d, char *object, int mandatory)
145*c2e0c6b5SAndroid Build Coastguard Worker {
146*c2e0c6b5SAndroid Build Coastguard Worker char buf[OBJBUFSIZE];
147*c2e0c6b5SAndroid Build Coastguard Worker
148*c2e0c6b5SAndroid Build Coastguard Worker if (sysfs_get_string(d, object, buf, mandatory))
149*c2e0c6b5SAndroid Build Coastguard Worker return strtol(buf, NULL, 0);
150*c2e0c6b5SAndroid Build Coastguard Worker else
151*c2e0c6b5SAndroid Build Coastguard Worker return -1;
152*c2e0c6b5SAndroid Build Coastguard Worker }
153*c2e0c6b5SAndroid Build Coastguard Worker
154*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_get_resources(struct pci_dev * d)155*c2e0c6b5SAndroid Build Coastguard Worker sysfs_get_resources(struct pci_dev *d)
156*c2e0c6b5SAndroid Build Coastguard Worker {
157*c2e0c6b5SAndroid Build Coastguard Worker struct pci_access *a = d->access;
158*c2e0c6b5SAndroid Build Coastguard Worker char namebuf[OBJNAMELEN], buf[256];
159*c2e0c6b5SAndroid Build Coastguard Worker struct { pciaddr_t flags, base_addr, size; } lines[10];
160*c2e0c6b5SAndroid Build Coastguard Worker int have_bar_bases, have_rom_base, have_bridge_bases;
161*c2e0c6b5SAndroid Build Coastguard Worker FILE *file;
162*c2e0c6b5SAndroid Build Coastguard Worker int i;
163*c2e0c6b5SAndroid Build Coastguard Worker
164*c2e0c6b5SAndroid Build Coastguard Worker have_bar_bases = have_rom_base = have_bridge_bases = 0;
165*c2e0c6b5SAndroid Build Coastguard Worker sysfs_obj_name(d, "resource", namebuf);
166*c2e0c6b5SAndroid Build Coastguard Worker file = fopen(namebuf, "r");
167*c2e0c6b5SAndroid Build Coastguard Worker if (!file)
168*c2e0c6b5SAndroid Build Coastguard Worker a->error("Cannot open %s: %s", namebuf, strerror(errno));
169*c2e0c6b5SAndroid Build Coastguard Worker for (i = 0; i < 7+6+4+1; i++)
170*c2e0c6b5SAndroid Build Coastguard Worker {
171*c2e0c6b5SAndroid Build Coastguard Worker unsigned long long start, end, size, flags;
172*c2e0c6b5SAndroid Build Coastguard Worker if (!fgets(buf, sizeof(buf), file))
173*c2e0c6b5SAndroid Build Coastguard Worker break;
174*c2e0c6b5SAndroid Build Coastguard Worker if (sscanf(buf, "%llx %llx %llx", &start, &end, &flags) != 3)
175*c2e0c6b5SAndroid Build Coastguard Worker a->error("Syntax error in %s", namebuf);
176*c2e0c6b5SAndroid Build Coastguard Worker if (end > start)
177*c2e0c6b5SAndroid Build Coastguard Worker size = end - start + 1;
178*c2e0c6b5SAndroid Build Coastguard Worker else
179*c2e0c6b5SAndroid Build Coastguard Worker size = 0;
180*c2e0c6b5SAndroid Build Coastguard Worker if (i < 6)
181*c2e0c6b5SAndroid Build Coastguard Worker {
182*c2e0c6b5SAndroid Build Coastguard Worker d->flags[i] = flags;
183*c2e0c6b5SAndroid Build Coastguard Worker flags &= PCI_ADDR_FLAG_MASK;
184*c2e0c6b5SAndroid Build Coastguard Worker d->base_addr[i] = start | flags;
185*c2e0c6b5SAndroid Build Coastguard Worker d->size[i] = size;
186*c2e0c6b5SAndroid Build Coastguard Worker have_bar_bases = 1;
187*c2e0c6b5SAndroid Build Coastguard Worker }
188*c2e0c6b5SAndroid Build Coastguard Worker else if (i == 6)
189*c2e0c6b5SAndroid Build Coastguard Worker {
190*c2e0c6b5SAndroid Build Coastguard Worker d->rom_flags = flags;
191*c2e0c6b5SAndroid Build Coastguard Worker flags &= PCI_ADDR_FLAG_MASK;
192*c2e0c6b5SAndroid Build Coastguard Worker d->rom_base_addr = start | flags;
193*c2e0c6b5SAndroid Build Coastguard Worker d->rom_size = size;
194*c2e0c6b5SAndroid Build Coastguard Worker have_rom_base = 1;
195*c2e0c6b5SAndroid Build Coastguard Worker }
196*c2e0c6b5SAndroid Build Coastguard Worker else if (i < 7+6+4)
197*c2e0c6b5SAndroid Build Coastguard Worker {
198*c2e0c6b5SAndroid Build Coastguard Worker /*
199*c2e0c6b5SAndroid Build Coastguard Worker * If kernel was compiled without CONFIG_PCI_IOV option then after
200*c2e0c6b5SAndroid Build Coastguard Worker * the ROM line for configured bridge device (that which had set
201*c2e0c6b5SAndroid Build Coastguard Worker * subordinary bus number to non-zero value) are four additional lines
202*c2e0c6b5SAndroid Build Coastguard Worker * which describe resources behind bridge. For PCI-to-PCI bridges they
203*c2e0c6b5SAndroid Build Coastguard Worker * are: IO, MEM, PREFMEM and empty. For CardBus bridges they are: IO0,
204*c2e0c6b5SAndroid Build Coastguard Worker * IO1, MEM0 and MEM1. For unconfigured bridges and other devices
205*c2e0c6b5SAndroid Build Coastguard Worker * there is no additional line after the ROM line. If kernel was
206*c2e0c6b5SAndroid Build Coastguard Worker * compiled with CONFIG_PCI_IOV option then after the ROM line and
207*c2e0c6b5SAndroid Build Coastguard Worker * before the first bridge resource line are six additional lines
208*c2e0c6b5SAndroid Build Coastguard Worker * which describe IOV resources. Read all remaining lines in resource
209*c2e0c6b5SAndroid Build Coastguard Worker * file and based on the number of remaining lines (0, 4, 6, 10) parse
210*c2e0c6b5SAndroid Build Coastguard Worker * resources behind bridge.
211*c2e0c6b5SAndroid Build Coastguard Worker */
212*c2e0c6b5SAndroid Build Coastguard Worker lines[i-7].flags = flags;
213*c2e0c6b5SAndroid Build Coastguard Worker lines[i-7].base_addr = start;
214*c2e0c6b5SAndroid Build Coastguard Worker lines[i-7].size = size;
215*c2e0c6b5SAndroid Build Coastguard Worker }
216*c2e0c6b5SAndroid Build Coastguard Worker }
217*c2e0c6b5SAndroid Build Coastguard Worker if (i == 7+4 || i == 7+6+4)
218*c2e0c6b5SAndroid Build Coastguard Worker {
219*c2e0c6b5SAndroid Build Coastguard Worker int offset = (i == 7+6+4) ? 6 : 0;
220*c2e0c6b5SAndroid Build Coastguard Worker for (i = 0; i < 4; i++)
221*c2e0c6b5SAndroid Build Coastguard Worker {
222*c2e0c6b5SAndroid Build Coastguard Worker d->bridge_flags[i] = lines[offset+i].flags;
223*c2e0c6b5SAndroid Build Coastguard Worker d->bridge_base_addr[i] = lines[offset+i].base_addr;
224*c2e0c6b5SAndroid Build Coastguard Worker d->bridge_size[i] = lines[offset+i].size;
225*c2e0c6b5SAndroid Build Coastguard Worker }
226*c2e0c6b5SAndroid Build Coastguard Worker have_bridge_bases = 1;
227*c2e0c6b5SAndroid Build Coastguard Worker }
228*c2e0c6b5SAndroid Build Coastguard Worker fclose(file);
229*c2e0c6b5SAndroid Build Coastguard Worker if (!have_bar_bases)
230*c2e0c6b5SAndroid Build Coastguard Worker clear_fill(d, PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS);
231*c2e0c6b5SAndroid Build Coastguard Worker if (!have_rom_base)
232*c2e0c6b5SAndroid Build Coastguard Worker clear_fill(d, PCI_FILL_ROM_BASE);
233*c2e0c6b5SAndroid Build Coastguard Worker if (!have_bridge_bases)
234*c2e0c6b5SAndroid Build Coastguard Worker clear_fill(d, PCI_FILL_BRIDGE_BASES);
235*c2e0c6b5SAndroid Build Coastguard Worker }
236*c2e0c6b5SAndroid Build Coastguard Worker
sysfs_scan(struct pci_access * a)237*c2e0c6b5SAndroid Build Coastguard Worker static void sysfs_scan(struct pci_access *a)
238*c2e0c6b5SAndroid Build Coastguard Worker {
239*c2e0c6b5SAndroid Build Coastguard Worker char dirname[1024];
240*c2e0c6b5SAndroid Build Coastguard Worker DIR *dir;
241*c2e0c6b5SAndroid Build Coastguard Worker struct dirent *entry;
242*c2e0c6b5SAndroid Build Coastguard Worker int n;
243*c2e0c6b5SAndroid Build Coastguard Worker
244*c2e0c6b5SAndroid Build Coastguard Worker n = snprintf(dirname, sizeof(dirname), "%s/devices", sysfs_name(a));
245*c2e0c6b5SAndroid Build Coastguard Worker if (n < 0 || n >= (int) sizeof(dirname))
246*c2e0c6b5SAndroid Build Coastguard Worker a->error("Directory name too long");
247*c2e0c6b5SAndroid Build Coastguard Worker dir = opendir(dirname);
248*c2e0c6b5SAndroid Build Coastguard Worker if (!dir)
249*c2e0c6b5SAndroid Build Coastguard Worker a->error("Cannot open %s", dirname);
250*c2e0c6b5SAndroid Build Coastguard Worker while ((entry = readdir(dir)))
251*c2e0c6b5SAndroid Build Coastguard Worker {
252*c2e0c6b5SAndroid Build Coastguard Worker struct pci_dev *d;
253*c2e0c6b5SAndroid Build Coastguard Worker unsigned int dom, bus, dev, func;
254*c2e0c6b5SAndroid Build Coastguard Worker
255*c2e0c6b5SAndroid Build Coastguard Worker /* ".", ".." or a special non-device perhaps */
256*c2e0c6b5SAndroid Build Coastguard Worker if (entry->d_name[0] == '.')
257*c2e0c6b5SAndroid Build Coastguard Worker continue;
258*c2e0c6b5SAndroid Build Coastguard Worker
259*c2e0c6b5SAndroid Build Coastguard Worker d = pci_alloc_dev(a);
260*c2e0c6b5SAndroid Build Coastguard Worker if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4)
261*c2e0c6b5SAndroid Build Coastguard Worker a->error("sysfs_scan: Couldn't parse entry name %s", entry->d_name);
262*c2e0c6b5SAndroid Build Coastguard Worker
263*c2e0c6b5SAndroid Build Coastguard Worker /* Ensure kernel provided domain that fits in a signed integer */
264*c2e0c6b5SAndroid Build Coastguard Worker if (dom > 0x7fffffff)
265*c2e0c6b5SAndroid Build Coastguard Worker a->error("sysfs_scan: Invalid domain %x", dom);
266*c2e0c6b5SAndroid Build Coastguard Worker
267*c2e0c6b5SAndroid Build Coastguard Worker d->domain = dom;
268*c2e0c6b5SAndroid Build Coastguard Worker d->bus = bus;
269*c2e0c6b5SAndroid Build Coastguard Worker d->dev = dev;
270*c2e0c6b5SAndroid Build Coastguard Worker d->func = func;
271*c2e0c6b5SAndroid Build Coastguard Worker pci_link_dev(a, d);
272*c2e0c6b5SAndroid Build Coastguard Worker }
273*c2e0c6b5SAndroid Build Coastguard Worker closedir(dir);
274*c2e0c6b5SAndroid Build Coastguard Worker }
275*c2e0c6b5SAndroid Build Coastguard Worker
276*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_fill_slots(struct pci_access * a)277*c2e0c6b5SAndroid Build Coastguard Worker sysfs_fill_slots(struct pci_access *a)
278*c2e0c6b5SAndroid Build Coastguard Worker {
279*c2e0c6b5SAndroid Build Coastguard Worker char dirname[1024];
280*c2e0c6b5SAndroid Build Coastguard Worker DIR *dir;
281*c2e0c6b5SAndroid Build Coastguard Worker struct dirent *entry;
282*c2e0c6b5SAndroid Build Coastguard Worker int n;
283*c2e0c6b5SAndroid Build Coastguard Worker
284*c2e0c6b5SAndroid Build Coastguard Worker n = snprintf(dirname, sizeof(dirname), "%s/slots", sysfs_name(a));
285*c2e0c6b5SAndroid Build Coastguard Worker if (n < 0 || n >= (int) sizeof(dirname))
286*c2e0c6b5SAndroid Build Coastguard Worker a->error("Directory name too long");
287*c2e0c6b5SAndroid Build Coastguard Worker dir = opendir(dirname);
288*c2e0c6b5SAndroid Build Coastguard Worker if (!dir)
289*c2e0c6b5SAndroid Build Coastguard Worker return;
290*c2e0c6b5SAndroid Build Coastguard Worker
291*c2e0c6b5SAndroid Build Coastguard Worker while (entry = readdir(dir))
292*c2e0c6b5SAndroid Build Coastguard Worker {
293*c2e0c6b5SAndroid Build Coastguard Worker char namebuf[OBJNAMELEN], buf[16];
294*c2e0c6b5SAndroid Build Coastguard Worker FILE *file;
295*c2e0c6b5SAndroid Build Coastguard Worker unsigned int dom, bus, dev;
296*c2e0c6b5SAndroid Build Coastguard Worker int res = 0;
297*c2e0c6b5SAndroid Build Coastguard Worker struct pci_dev *d;
298*c2e0c6b5SAndroid Build Coastguard Worker
299*c2e0c6b5SAndroid Build Coastguard Worker /* ".", ".." or a special non-device perhaps */
300*c2e0c6b5SAndroid Build Coastguard Worker if (entry->d_name[0] == '.')
301*c2e0c6b5SAndroid Build Coastguard Worker continue;
302*c2e0c6b5SAndroid Build Coastguard Worker
303*c2e0c6b5SAndroid Build Coastguard Worker n = snprintf(namebuf, OBJNAMELEN, "%s/%s/%s", dirname, entry->d_name, "address");
304*c2e0c6b5SAndroid Build Coastguard Worker if (n < 0 || n >= OBJNAMELEN)
305*c2e0c6b5SAndroid Build Coastguard Worker a->error("File name too long");
306*c2e0c6b5SAndroid Build Coastguard Worker file = fopen(namebuf, "r");
307*c2e0c6b5SAndroid Build Coastguard Worker /*
308*c2e0c6b5SAndroid Build Coastguard Worker * Old versions of Linux had a fakephp which didn't have an 'address'
309*c2e0c6b5SAndroid Build Coastguard Worker * file. There's no useful information to be gleaned from these
310*c2e0c6b5SAndroid Build Coastguard Worker * devices, pretend they're not there.
311*c2e0c6b5SAndroid Build Coastguard Worker */
312*c2e0c6b5SAndroid Build Coastguard Worker if (!file)
313*c2e0c6b5SAndroid Build Coastguard Worker continue;
314*c2e0c6b5SAndroid Build Coastguard Worker
315*c2e0c6b5SAndroid Build Coastguard Worker if (!fgets(buf, sizeof(buf), file) || (res = sscanf(buf, "%x:%x:%x", &dom, &bus, &dev)) < 3)
316*c2e0c6b5SAndroid Build Coastguard Worker {
317*c2e0c6b5SAndroid Build Coastguard Worker /*
318*c2e0c6b5SAndroid Build Coastguard Worker * In some cases, the slot is not tied to a specific device before
319*c2e0c6b5SAndroid Build Coastguard Worker * a card gets inserted. This happens for example on IBM pSeries
320*c2e0c6b5SAndroid Build Coastguard Worker * and we need not warn about it.
321*c2e0c6b5SAndroid Build Coastguard Worker */
322*c2e0c6b5SAndroid Build Coastguard Worker if (res != 2)
323*c2e0c6b5SAndroid Build Coastguard Worker a->warning("sysfs_fill_slots: Couldn't parse entry address %s", buf);
324*c2e0c6b5SAndroid Build Coastguard Worker }
325*c2e0c6b5SAndroid Build Coastguard Worker else
326*c2e0c6b5SAndroid Build Coastguard Worker {
327*c2e0c6b5SAndroid Build Coastguard Worker for (d = a->devices; d; d = d->next)
328*c2e0c6b5SAndroid Build Coastguard Worker if (dom == (unsigned)d->domain && bus == d->bus && dev == d->dev && !d->phy_slot)
329*c2e0c6b5SAndroid Build Coastguard Worker d->phy_slot = pci_set_property(d, PCI_FILL_PHYS_SLOT, entry->d_name);
330*c2e0c6b5SAndroid Build Coastguard Worker }
331*c2e0c6b5SAndroid Build Coastguard Worker fclose(file);
332*c2e0c6b5SAndroid Build Coastguard Worker }
333*c2e0c6b5SAndroid Build Coastguard Worker closedir(dir);
334*c2e0c6b5SAndroid Build Coastguard Worker }
335*c2e0c6b5SAndroid Build Coastguard Worker
336*c2e0c6b5SAndroid Build Coastguard Worker static void
sysfs_fill_info(struct pci_dev * d,unsigned int flags)337*c2e0c6b5SAndroid Build Coastguard Worker sysfs_fill_info(struct pci_dev *d, unsigned int flags)
338*c2e0c6b5SAndroid Build Coastguard Worker {
339*c2e0c6b5SAndroid Build Coastguard Worker int value, want_class, want_class_ext;
340*c2e0c6b5SAndroid Build Coastguard Worker
341*c2e0c6b5SAndroid Build Coastguard Worker if (!d->access->buscentric)
342*c2e0c6b5SAndroid Build Coastguard Worker {
343*c2e0c6b5SAndroid Build Coastguard Worker /*
344*c2e0c6b5SAndroid Build Coastguard Worker * These fields can be read from the config registers, but we want to show
345*c2e0c6b5SAndroid Build Coastguard Worker * the kernel's view, which has regions and IRQs remapped and other fields
346*c2e0c6b5SAndroid Build Coastguard Worker * (most importantly classes) possibly fixed if the device is known broken.
347*c2e0c6b5SAndroid Build Coastguard Worker */
348*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_IDENT))
349*c2e0c6b5SAndroid Build Coastguard Worker {
350*c2e0c6b5SAndroid Build Coastguard Worker d->vendor_id = sysfs_get_value(d, "vendor", 1);
351*c2e0c6b5SAndroid Build Coastguard Worker d->device_id = sysfs_get_value(d, "device", 1);
352*c2e0c6b5SAndroid Build Coastguard Worker }
353*c2e0c6b5SAndroid Build Coastguard Worker want_class = want_fill(d, flags, PCI_FILL_CLASS);
354*c2e0c6b5SAndroid Build Coastguard Worker want_class_ext = want_fill(d, flags, PCI_FILL_CLASS_EXT);
355*c2e0c6b5SAndroid Build Coastguard Worker if (want_class || want_class_ext)
356*c2e0c6b5SAndroid Build Coastguard Worker {
357*c2e0c6b5SAndroid Build Coastguard Worker value = sysfs_get_value(d, "class", 1);
358*c2e0c6b5SAndroid Build Coastguard Worker if (want_class)
359*c2e0c6b5SAndroid Build Coastguard Worker d->device_class = value >> 8;
360*c2e0c6b5SAndroid Build Coastguard Worker if (want_class_ext)
361*c2e0c6b5SAndroid Build Coastguard Worker {
362*c2e0c6b5SAndroid Build Coastguard Worker d->prog_if = value & 0xff;
363*c2e0c6b5SAndroid Build Coastguard Worker value = sysfs_get_value(d, "revision", 0);
364*c2e0c6b5SAndroid Build Coastguard Worker if (value < 0)
365*c2e0c6b5SAndroid Build Coastguard Worker value = pci_read_byte(d, PCI_REVISION_ID);
366*c2e0c6b5SAndroid Build Coastguard Worker if (value >= 0)
367*c2e0c6b5SAndroid Build Coastguard Worker d->rev_id = value;
368*c2e0c6b5SAndroid Build Coastguard Worker }
369*c2e0c6b5SAndroid Build Coastguard Worker }
370*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_SUBSYS))
371*c2e0c6b5SAndroid Build Coastguard Worker {
372*c2e0c6b5SAndroid Build Coastguard Worker value = sysfs_get_value(d, "subsystem_vendor", 0);
373*c2e0c6b5SAndroid Build Coastguard Worker if (value >= 0)
374*c2e0c6b5SAndroid Build Coastguard Worker {
375*c2e0c6b5SAndroid Build Coastguard Worker d->subsys_vendor_id = value;
376*c2e0c6b5SAndroid Build Coastguard Worker value = sysfs_get_value(d, "subsystem_device", 0);
377*c2e0c6b5SAndroid Build Coastguard Worker if (value >= 0)
378*c2e0c6b5SAndroid Build Coastguard Worker d->subsys_id = value;
379*c2e0c6b5SAndroid Build Coastguard Worker }
380*c2e0c6b5SAndroid Build Coastguard Worker else
381*c2e0c6b5SAndroid Build Coastguard Worker clear_fill(d, PCI_FILL_SUBSYS);
382*c2e0c6b5SAndroid Build Coastguard Worker }
383*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_IRQ))
384*c2e0c6b5SAndroid Build Coastguard Worker d->irq = sysfs_get_value(d, "irq", 1);
385*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS | PCI_FILL_BRIDGE_BASES))
386*c2e0c6b5SAndroid Build Coastguard Worker sysfs_get_resources(d);
387*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_PARENT))
388*c2e0c6b5SAndroid Build Coastguard Worker {
389*c2e0c6b5SAndroid Build Coastguard Worker unsigned int domain, bus, dev, func;
390*c2e0c6b5SAndroid Build Coastguard Worker char *path_abs, *path_canon, *name;
391*c2e0c6b5SAndroid Build Coastguard Worker char path_rel[OBJNAMELEN];
392*c2e0c6b5SAndroid Build Coastguard Worker struct pci_dev *parent;
393*c2e0c6b5SAndroid Build Coastguard Worker
394*c2e0c6b5SAndroid Build Coastguard Worker /* Construct sysfs path for parent device */
395*c2e0c6b5SAndroid Build Coastguard Worker sysfs_obj_name(d, "..", path_rel);
396*c2e0c6b5SAndroid Build Coastguard Worker path_abs = realpath(path_rel, NULL);
397*c2e0c6b5SAndroid Build Coastguard Worker name = path_abs ? strrchr(path_abs, '/') : NULL;
398*c2e0c6b5SAndroid Build Coastguard Worker name = name ? name+1 : name;
399*c2e0c6b5SAndroid Build Coastguard Worker parent = NULL;
400*c2e0c6b5SAndroid Build Coastguard Worker
401*c2e0c6b5SAndroid Build Coastguard Worker if (name && sscanf(name, "%x:%x:%x.%d", &domain, &bus, &dev, &func) == 4 && domain <= 0x7fffffff)
402*c2e0c6b5SAndroid Build Coastguard Worker for (parent = d->access->devices; parent; parent = parent->next)
403*c2e0c6b5SAndroid Build Coastguard Worker if (parent->domain == (int)domain && parent->bus == bus && parent->dev == dev && parent->func == func)
404*c2e0c6b5SAndroid Build Coastguard Worker break;
405*c2e0c6b5SAndroid Build Coastguard Worker
406*c2e0c6b5SAndroid Build Coastguard Worker if (parent)
407*c2e0c6b5SAndroid Build Coastguard Worker {
408*c2e0c6b5SAndroid Build Coastguard Worker /* Check if parsed BDF address from parent sysfs device is really expected PCI device */
409*c2e0c6b5SAndroid Build Coastguard Worker sysfs_obj_name(parent, ".", path_rel);
410*c2e0c6b5SAndroid Build Coastguard Worker path_canon = realpath(path_rel, NULL);
411*c2e0c6b5SAndroid Build Coastguard Worker if (!path_canon || strcmp(path_canon, path_abs) != 0)
412*c2e0c6b5SAndroid Build Coastguard Worker parent = NULL;
413*c2e0c6b5SAndroid Build Coastguard Worker
414*c2e0c6b5SAndroid Build Coastguard Worker if (path_canon)
415*c2e0c6b5SAndroid Build Coastguard Worker free(path_canon);
416*c2e0c6b5SAndroid Build Coastguard Worker }
417*c2e0c6b5SAndroid Build Coastguard Worker
418*c2e0c6b5SAndroid Build Coastguard Worker if (parent)
419*c2e0c6b5SAndroid Build Coastguard Worker d->parent = parent;
420*c2e0c6b5SAndroid Build Coastguard Worker else
421*c2e0c6b5SAndroid Build Coastguard Worker clear_fill(d, PCI_FILL_PARENT);
422*c2e0c6b5SAndroid Build Coastguard Worker
423*c2e0c6b5SAndroid Build Coastguard Worker if (path_abs)
424*c2e0c6b5SAndroid Build Coastguard Worker free(path_abs);
425*c2e0c6b5SAndroid Build Coastguard Worker }
426*c2e0c6b5SAndroid Build Coastguard Worker }
427*c2e0c6b5SAndroid Build Coastguard Worker
428*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_PHYS_SLOT))
429*c2e0c6b5SAndroid Build Coastguard Worker {
430*c2e0c6b5SAndroid Build Coastguard Worker struct pci_dev *pd;
431*c2e0c6b5SAndroid Build Coastguard Worker sysfs_fill_slots(d->access);
432*c2e0c6b5SAndroid Build Coastguard Worker for (pd = d->access->devices; pd; pd = pd->next)
433*c2e0c6b5SAndroid Build Coastguard Worker pd->known_fields |= PCI_FILL_PHYS_SLOT;
434*c2e0c6b5SAndroid Build Coastguard Worker }
435*c2e0c6b5SAndroid Build Coastguard Worker
436*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_MODULE_ALIAS))
437*c2e0c6b5SAndroid Build Coastguard Worker {
438*c2e0c6b5SAndroid Build Coastguard Worker char buf[OBJBUFSIZE];
439*c2e0c6b5SAndroid Build Coastguard Worker if (sysfs_get_string(d, "modalias", buf, 0))
440*c2e0c6b5SAndroid Build Coastguard Worker d->module_alias = pci_set_property(d, PCI_FILL_MODULE_ALIAS, buf);
441*c2e0c6b5SAndroid Build Coastguard Worker }
442*c2e0c6b5SAndroid Build Coastguard Worker
443*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_LABEL))
444*c2e0c6b5SAndroid Build Coastguard Worker {
445*c2e0c6b5SAndroid Build Coastguard Worker char buf[OBJBUFSIZE];
446*c2e0c6b5SAndroid Build Coastguard Worker if (sysfs_get_string(d, "label", buf, 0))
447*c2e0c6b5SAndroid Build Coastguard Worker d->label = pci_set_property(d, PCI_FILL_LABEL, buf);
448*c2e0c6b5SAndroid Build Coastguard Worker }
449*c2e0c6b5SAndroid Build Coastguard Worker
450*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_NUMA_NODE))
451*c2e0c6b5SAndroid Build Coastguard Worker d->numa_node = sysfs_get_value(d, "numa_node", 0);
452*c2e0c6b5SAndroid Build Coastguard Worker
453*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_IOMMU_GROUP))
454*c2e0c6b5SAndroid Build Coastguard Worker {
455*c2e0c6b5SAndroid Build Coastguard Worker char *group_link = sysfs_deref_link(d, "iommu_group");
456*c2e0c6b5SAndroid Build Coastguard Worker if (group_link)
457*c2e0c6b5SAndroid Build Coastguard Worker {
458*c2e0c6b5SAndroid Build Coastguard Worker pci_set_property(d, PCI_FILL_IOMMU_GROUP, basename(group_link));
459*c2e0c6b5SAndroid Build Coastguard Worker free(group_link);
460*c2e0c6b5SAndroid Build Coastguard Worker }
461*c2e0c6b5SAndroid Build Coastguard Worker }
462*c2e0c6b5SAndroid Build Coastguard Worker
463*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_DT_NODE))
464*c2e0c6b5SAndroid Build Coastguard Worker {
465*c2e0c6b5SAndroid Build Coastguard Worker char *node = sysfs_deref_link(d, "of_node");
466*c2e0c6b5SAndroid Build Coastguard Worker if (node)
467*c2e0c6b5SAndroid Build Coastguard Worker {
468*c2e0c6b5SAndroid Build Coastguard Worker pci_set_property(d, PCI_FILL_DT_NODE, node);
469*c2e0c6b5SAndroid Build Coastguard Worker free(node);
470*c2e0c6b5SAndroid Build Coastguard Worker }
471*c2e0c6b5SAndroid Build Coastguard Worker }
472*c2e0c6b5SAndroid Build Coastguard Worker
473*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_DRIVER))
474*c2e0c6b5SAndroid Build Coastguard Worker {
475*c2e0c6b5SAndroid Build Coastguard Worker char *driver_path = sysfs_deref_link(d, "driver");
476*c2e0c6b5SAndroid Build Coastguard Worker if (driver_path)
477*c2e0c6b5SAndroid Build Coastguard Worker {
478*c2e0c6b5SAndroid Build Coastguard Worker char *driver = strrchr(driver_path, '/');
479*c2e0c6b5SAndroid Build Coastguard Worker driver = driver ? driver+1 : driver_path;
480*c2e0c6b5SAndroid Build Coastguard Worker pci_set_property(d, PCI_FILL_DRIVER, driver);
481*c2e0c6b5SAndroid Build Coastguard Worker free(driver_path);
482*c2e0c6b5SAndroid Build Coastguard Worker }
483*c2e0c6b5SAndroid Build Coastguard Worker else
484*c2e0c6b5SAndroid Build Coastguard Worker clear_fill(d, PCI_FILL_DRIVER);
485*c2e0c6b5SAndroid Build Coastguard Worker }
486*c2e0c6b5SAndroid Build Coastguard Worker
487*c2e0c6b5SAndroid Build Coastguard Worker if (want_fill(d, flags, PCI_FILL_RCD_LNK))
488*c2e0c6b5SAndroid Build Coastguard Worker {
489*c2e0c6b5SAndroid Build Coastguard Worker char buf[OBJBUFSIZE];
490*c2e0c6b5SAndroid Build Coastguard Worker if (sysfs_get_string(d, "rcd_link_cap", buf, 0))
491*c2e0c6b5SAndroid Build Coastguard Worker d->rcd_link_cap = strtoul(buf, NULL, 16);
492*c2e0c6b5SAndroid Build Coastguard Worker if (sysfs_get_string(d, "rcd_link_ctrl", buf, 0))
493*c2e0c6b5SAndroid Build Coastguard Worker d->rcd_link_ctrl = strtoul(buf, NULL, 16);
494*c2e0c6b5SAndroid Build Coastguard Worker if (sysfs_get_string(d, "rcd_link_status", buf, 0))
495*c2e0c6b5SAndroid Build Coastguard Worker d->rcd_link_status = strtoul(buf, NULL, 16);
496*c2e0c6b5SAndroid Build Coastguard Worker }
497*c2e0c6b5SAndroid Build Coastguard Worker
498*c2e0c6b5SAndroid Build Coastguard Worker pci_generic_fill_info(d, flags);
499*c2e0c6b5SAndroid Build Coastguard Worker }
500*c2e0c6b5SAndroid Build Coastguard Worker
501*c2e0c6b5SAndroid Build Coastguard Worker /* Intent of the sysfs_setup() caller */
502*c2e0c6b5SAndroid Build Coastguard Worker enum
503*c2e0c6b5SAndroid Build Coastguard Worker {
504*c2e0c6b5SAndroid Build Coastguard Worker SETUP_READ_CONFIG = 0,
505*c2e0c6b5SAndroid Build Coastguard Worker SETUP_WRITE_CONFIG = 1,
506*c2e0c6b5SAndroid Build Coastguard Worker SETUP_READ_VPD = 2
507*c2e0c6b5SAndroid Build Coastguard Worker };
508*c2e0c6b5SAndroid Build Coastguard Worker
509*c2e0c6b5SAndroid Build Coastguard Worker static int
sysfs_setup(struct pci_dev * d,int intent)510*c2e0c6b5SAndroid Build Coastguard Worker sysfs_setup(struct pci_dev *d, int intent)
511*c2e0c6b5SAndroid Build Coastguard Worker {
512*c2e0c6b5SAndroid Build Coastguard Worker struct pci_access *a = d->access;
513*c2e0c6b5SAndroid Build Coastguard Worker char namebuf[OBJNAMELEN];
514*c2e0c6b5SAndroid Build Coastguard Worker
515*c2e0c6b5SAndroid Build Coastguard Worker if (a->cached_dev != d || (intent == SETUP_WRITE_CONFIG && !a->fd_rw))
516*c2e0c6b5SAndroid Build Coastguard Worker {
517*c2e0c6b5SAndroid Build Coastguard Worker sysfs_flush_cache(a);
518*c2e0c6b5SAndroid Build Coastguard Worker a->cached_dev = d;
519*c2e0c6b5SAndroid Build Coastguard Worker }
520*c2e0c6b5SAndroid Build Coastguard Worker
521*c2e0c6b5SAndroid Build Coastguard Worker if (intent == SETUP_READ_VPD)
522*c2e0c6b5SAndroid Build Coastguard Worker {
523*c2e0c6b5SAndroid Build Coastguard Worker if (a->fd_vpd < 0)
524*c2e0c6b5SAndroid Build Coastguard Worker {
525*c2e0c6b5SAndroid Build Coastguard Worker sysfs_obj_name(d, "vpd", namebuf);
526*c2e0c6b5SAndroid Build Coastguard Worker a->fd_vpd = open(namebuf, O_RDONLY);
527*c2e0c6b5SAndroid Build Coastguard Worker /* No warning on error; vpd may be absent or accessible only to root */
528*c2e0c6b5SAndroid Build Coastguard Worker }
529*c2e0c6b5SAndroid Build Coastguard Worker return a->fd_vpd;
530*c2e0c6b5SAndroid Build Coastguard Worker }
531*c2e0c6b5SAndroid Build Coastguard Worker
532*c2e0c6b5SAndroid Build Coastguard Worker if (a->fd < 0)
533*c2e0c6b5SAndroid Build Coastguard Worker {
534*c2e0c6b5SAndroid Build Coastguard Worker sysfs_obj_name(d, "config", namebuf);
535*c2e0c6b5SAndroid Build Coastguard Worker a->fd_rw = a->writeable || intent == SETUP_WRITE_CONFIG;
536*c2e0c6b5SAndroid Build Coastguard Worker a->fd = open(namebuf, a->fd_rw ? O_RDWR : O_RDONLY);
537*c2e0c6b5SAndroid Build Coastguard Worker if (a->fd < 0)
538*c2e0c6b5SAndroid Build Coastguard Worker a->warning("Cannot open %s", namebuf);
539*c2e0c6b5SAndroid Build Coastguard Worker }
540*c2e0c6b5SAndroid Build Coastguard Worker return a->fd;
541*c2e0c6b5SAndroid Build Coastguard Worker }
542*c2e0c6b5SAndroid Build Coastguard Worker
sysfs_read(struct pci_dev * d,int pos,byte * buf,int len)543*c2e0c6b5SAndroid Build Coastguard Worker static int sysfs_read(struct pci_dev *d, int pos, byte *buf, int len)
544*c2e0c6b5SAndroid Build Coastguard Worker {
545*c2e0c6b5SAndroid Build Coastguard Worker int fd = sysfs_setup(d, SETUP_READ_CONFIG);
546*c2e0c6b5SAndroid Build Coastguard Worker int res;
547*c2e0c6b5SAndroid Build Coastguard Worker
548*c2e0c6b5SAndroid Build Coastguard Worker if (fd < 0)
549*c2e0c6b5SAndroid Build Coastguard Worker return 0;
550*c2e0c6b5SAndroid Build Coastguard Worker res = pread(fd, buf, len, pos);
551*c2e0c6b5SAndroid Build Coastguard Worker if (res < 0)
552*c2e0c6b5SAndroid Build Coastguard Worker {
553*c2e0c6b5SAndroid Build Coastguard Worker d->access->warning("sysfs_read: read failed: %s", strerror(errno));
554*c2e0c6b5SAndroid Build Coastguard Worker return 0;
555*c2e0c6b5SAndroid Build Coastguard Worker }
556*c2e0c6b5SAndroid Build Coastguard Worker else if (res != len)
557*c2e0c6b5SAndroid Build Coastguard Worker return 0;
558*c2e0c6b5SAndroid Build Coastguard Worker return 1;
559*c2e0c6b5SAndroid Build Coastguard Worker }
560*c2e0c6b5SAndroid Build Coastguard Worker
sysfs_write(struct pci_dev * d,int pos,byte * buf,int len)561*c2e0c6b5SAndroid Build Coastguard Worker static int sysfs_write(struct pci_dev *d, int pos, byte *buf, int len)
562*c2e0c6b5SAndroid Build Coastguard Worker {
563*c2e0c6b5SAndroid Build Coastguard Worker int fd = sysfs_setup(d, SETUP_WRITE_CONFIG);
564*c2e0c6b5SAndroid Build Coastguard Worker int res;
565*c2e0c6b5SAndroid Build Coastguard Worker
566*c2e0c6b5SAndroid Build Coastguard Worker if (fd < 0)
567*c2e0c6b5SAndroid Build Coastguard Worker return 0;
568*c2e0c6b5SAndroid Build Coastguard Worker res = pwrite(fd, buf, len, pos);
569*c2e0c6b5SAndroid Build Coastguard Worker if (res < 0)
570*c2e0c6b5SAndroid Build Coastguard Worker {
571*c2e0c6b5SAndroid Build Coastguard Worker d->access->warning("sysfs_write: write failed: %s", strerror(errno));
572*c2e0c6b5SAndroid Build Coastguard Worker return 0;
573*c2e0c6b5SAndroid Build Coastguard Worker }
574*c2e0c6b5SAndroid Build Coastguard Worker else if (res != len)
575*c2e0c6b5SAndroid Build Coastguard Worker {
576*c2e0c6b5SAndroid Build Coastguard Worker d->access->warning("sysfs_write: tried to write %d bytes at %d, but only %d succeeded", len, pos, res);
577*c2e0c6b5SAndroid Build Coastguard Worker return 0;
578*c2e0c6b5SAndroid Build Coastguard Worker }
579*c2e0c6b5SAndroid Build Coastguard Worker return 1;
580*c2e0c6b5SAndroid Build Coastguard Worker }
581*c2e0c6b5SAndroid Build Coastguard Worker
sysfs_read_vpd(struct pci_dev * d,int pos,byte * buf,int len)582*c2e0c6b5SAndroid Build Coastguard Worker static int sysfs_read_vpd(struct pci_dev *d, int pos, byte *buf, int len)
583*c2e0c6b5SAndroid Build Coastguard Worker {
584*c2e0c6b5SAndroid Build Coastguard Worker int fd = sysfs_setup(d, SETUP_READ_VPD);
585*c2e0c6b5SAndroid Build Coastguard Worker int res;
586*c2e0c6b5SAndroid Build Coastguard Worker
587*c2e0c6b5SAndroid Build Coastguard Worker if (fd < 0)
588*c2e0c6b5SAndroid Build Coastguard Worker return 0;
589*c2e0c6b5SAndroid Build Coastguard Worker res = pread(fd, buf, len, pos);
590*c2e0c6b5SAndroid Build Coastguard Worker if (res < 0)
591*c2e0c6b5SAndroid Build Coastguard Worker {
592*c2e0c6b5SAndroid Build Coastguard Worker d->access->warning("sysfs_read_vpd: read failed: %s", strerror(errno));
593*c2e0c6b5SAndroid Build Coastguard Worker return 0;
594*c2e0c6b5SAndroid Build Coastguard Worker }
595*c2e0c6b5SAndroid Build Coastguard Worker else if (res != len)
596*c2e0c6b5SAndroid Build Coastguard Worker return 0;
597*c2e0c6b5SAndroid Build Coastguard Worker return 1;
598*c2e0c6b5SAndroid Build Coastguard Worker }
599*c2e0c6b5SAndroid Build Coastguard Worker
sysfs_cleanup_dev(struct pci_dev * d)600*c2e0c6b5SAndroid Build Coastguard Worker static void sysfs_cleanup_dev(struct pci_dev *d)
601*c2e0c6b5SAndroid Build Coastguard Worker {
602*c2e0c6b5SAndroid Build Coastguard Worker struct pci_access *a = d->access;
603*c2e0c6b5SAndroid Build Coastguard Worker
604*c2e0c6b5SAndroid Build Coastguard Worker if (a->cached_dev == d)
605*c2e0c6b5SAndroid Build Coastguard Worker sysfs_flush_cache(a);
606*c2e0c6b5SAndroid Build Coastguard Worker }
607*c2e0c6b5SAndroid Build Coastguard Worker
608*c2e0c6b5SAndroid Build Coastguard Worker struct pci_methods pm_linux_sysfs = {
609*c2e0c6b5SAndroid Build Coastguard Worker .name = "linux-sysfs",
610*c2e0c6b5SAndroid Build Coastguard Worker .help = "The sys filesystem on Linux",
611*c2e0c6b5SAndroid Build Coastguard Worker .config = sysfs_config,
612*c2e0c6b5SAndroid Build Coastguard Worker .detect = sysfs_detect,
613*c2e0c6b5SAndroid Build Coastguard Worker .init = sysfs_init,
614*c2e0c6b5SAndroid Build Coastguard Worker .cleanup = sysfs_cleanup,
615*c2e0c6b5SAndroid Build Coastguard Worker .scan = sysfs_scan,
616*c2e0c6b5SAndroid Build Coastguard Worker .fill_info = sysfs_fill_info,
617*c2e0c6b5SAndroid Build Coastguard Worker .read = sysfs_read,
618*c2e0c6b5SAndroid Build Coastguard Worker .write = sysfs_write,
619*c2e0c6b5SAndroid Build Coastguard Worker .read_vpd = sysfs_read_vpd,
620*c2e0c6b5SAndroid Build Coastguard Worker .cleanup_dev = sysfs_cleanup_dev,
621*c2e0c6b5SAndroid Build Coastguard Worker };
622