1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker * The PCI Library -- Direct Configuration access via memory mapped ports
3*c2e0c6b5SAndroid Build Coastguard Worker *
4*c2e0c6b5SAndroid Build Coastguard Worker * Copyright (c) 2022 Pali Rohár <[email protected]>
5*c2e0c6b5SAndroid Build Coastguard Worker *
6*c2e0c6b5SAndroid Build Coastguard Worker * Can be freely distributed and used under the terms of the GNU GPL v2+.
7*c2e0c6b5SAndroid Build Coastguard Worker *
8*c2e0c6b5SAndroid Build Coastguard Worker * SPDX-License-Identifier: GPL-2.0-or-later
9*c2e0c6b5SAndroid Build Coastguard Worker */
10*c2e0c6b5SAndroid Build Coastguard Worker
11*c2e0c6b5SAndroid Build Coastguard Worker #include "internal.h"
12*c2e0c6b5SAndroid Build Coastguard Worker #include "physmem.h"
13*c2e0c6b5SAndroid Build Coastguard Worker #include "physmem-access.h"
14*c2e0c6b5SAndroid Build Coastguard Worker
15*c2e0c6b5SAndroid Build Coastguard Worker #include <ctype.h>
16*c2e0c6b5SAndroid Build Coastguard Worker #include <errno.h>
17*c2e0c6b5SAndroid Build Coastguard Worker #include <stdlib.h>
18*c2e0c6b5SAndroid Build Coastguard Worker #include <string.h>
19*c2e0c6b5SAndroid Build Coastguard Worker
20*c2e0c6b5SAndroid Build Coastguard Worker struct mmio_cache {
21*c2e0c6b5SAndroid Build Coastguard Worker u64 addr_page;
22*c2e0c6b5SAndroid Build Coastguard Worker u64 data_page;
23*c2e0c6b5SAndroid Build Coastguard Worker void *addr_map;
24*c2e0c6b5SAndroid Build Coastguard Worker void *data_map;
25*c2e0c6b5SAndroid Build Coastguard Worker };
26*c2e0c6b5SAndroid Build Coastguard Worker
27*c2e0c6b5SAndroid Build Coastguard Worker struct mmio_access {
28*c2e0c6b5SAndroid Build Coastguard Worker struct mmio_cache *cache;
29*c2e0c6b5SAndroid Build Coastguard Worker struct physmem *physmem;
30*c2e0c6b5SAndroid Build Coastguard Worker long pagesize;
31*c2e0c6b5SAndroid Build Coastguard Worker };
32*c2e0c6b5SAndroid Build Coastguard Worker
33*c2e0c6b5SAndroid Build Coastguard Worker static void
munmap_regs(struct pci_access * a)34*c2e0c6b5SAndroid Build Coastguard Worker munmap_regs(struct pci_access *a)
35*c2e0c6b5SAndroid Build Coastguard Worker {
36*c2e0c6b5SAndroid Build Coastguard Worker struct mmio_access *macc = a->backend_data;
37*c2e0c6b5SAndroid Build Coastguard Worker struct mmio_cache *cache = macc->cache;
38*c2e0c6b5SAndroid Build Coastguard Worker struct physmem *physmem = macc->physmem;
39*c2e0c6b5SAndroid Build Coastguard Worker long pagesize = macc->pagesize;
40*c2e0c6b5SAndroid Build Coastguard Worker
41*c2e0c6b5SAndroid Build Coastguard Worker if (!cache)
42*c2e0c6b5SAndroid Build Coastguard Worker return;
43*c2e0c6b5SAndroid Build Coastguard Worker
44*c2e0c6b5SAndroid Build Coastguard Worker physmem_unmap(physmem, cache->addr_map, pagesize);
45*c2e0c6b5SAndroid Build Coastguard Worker if (cache->addr_page != cache->data_page)
46*c2e0c6b5SAndroid Build Coastguard Worker physmem_unmap(physmem, cache->data_map, pagesize);
47*c2e0c6b5SAndroid Build Coastguard Worker
48*c2e0c6b5SAndroid Build Coastguard Worker pci_mfree(macc->cache);
49*c2e0c6b5SAndroid Build Coastguard Worker macc->cache = NULL;
50*c2e0c6b5SAndroid Build Coastguard Worker }
51*c2e0c6b5SAndroid Build Coastguard Worker
52*c2e0c6b5SAndroid Build Coastguard Worker static int
mmap_regs(struct pci_access * a,u64 addr_reg,u64 data_reg,int data_off,volatile void ** addr,volatile void ** data)53*c2e0c6b5SAndroid Build Coastguard Worker mmap_regs(struct pci_access *a, u64 addr_reg, u64 data_reg, int data_off, volatile void **addr, volatile void **data)
54*c2e0c6b5SAndroid Build Coastguard Worker {
55*c2e0c6b5SAndroid Build Coastguard Worker struct mmio_access *macc = a->backend_data;
56*c2e0c6b5SAndroid Build Coastguard Worker struct mmio_cache *cache = macc->cache;
57*c2e0c6b5SAndroid Build Coastguard Worker struct physmem *physmem = macc->physmem;
58*c2e0c6b5SAndroid Build Coastguard Worker long pagesize = macc->pagesize;
59*c2e0c6b5SAndroid Build Coastguard Worker u64 addr_page = addr_reg & ~(pagesize-1);
60*c2e0c6b5SAndroid Build Coastguard Worker u64 data_page = data_reg & ~(pagesize-1);
61*c2e0c6b5SAndroid Build Coastguard Worker void *addr_map = (void *)-1;
62*c2e0c6b5SAndroid Build Coastguard Worker void *data_map = (void *)-1;
63*c2e0c6b5SAndroid Build Coastguard Worker
64*c2e0c6b5SAndroid Build Coastguard Worker if (cache && cache->addr_page == addr_page)
65*c2e0c6b5SAndroid Build Coastguard Worker addr_map = cache->addr_map;
66*c2e0c6b5SAndroid Build Coastguard Worker
67*c2e0c6b5SAndroid Build Coastguard Worker if (cache && cache->data_page == data_page)
68*c2e0c6b5SAndroid Build Coastguard Worker data_map = cache->data_map;
69*c2e0c6b5SAndroid Build Coastguard Worker
70*c2e0c6b5SAndroid Build Coastguard Worker if (addr_map == (void *)-1)
71*c2e0c6b5SAndroid Build Coastguard Worker addr_map = physmem_map(physmem, addr_page, pagesize, 1);
72*c2e0c6b5SAndroid Build Coastguard Worker
73*c2e0c6b5SAndroid Build Coastguard Worker if (addr_map == (void *)-1)
74*c2e0c6b5SAndroid Build Coastguard Worker return 0;
75*c2e0c6b5SAndroid Build Coastguard Worker
76*c2e0c6b5SAndroid Build Coastguard Worker if (data_map == (void *)-1)
77*c2e0c6b5SAndroid Build Coastguard Worker {
78*c2e0c6b5SAndroid Build Coastguard Worker if (data_page == addr_page)
79*c2e0c6b5SAndroid Build Coastguard Worker data_map = addr_map;
80*c2e0c6b5SAndroid Build Coastguard Worker else
81*c2e0c6b5SAndroid Build Coastguard Worker data_map = physmem_map(physmem, data_page, pagesize, 1);
82*c2e0c6b5SAndroid Build Coastguard Worker }
83*c2e0c6b5SAndroid Build Coastguard Worker
84*c2e0c6b5SAndroid Build Coastguard Worker if (data_map == (void *)-1)
85*c2e0c6b5SAndroid Build Coastguard Worker {
86*c2e0c6b5SAndroid Build Coastguard Worker if (!cache || cache->addr_map != addr_map)
87*c2e0c6b5SAndroid Build Coastguard Worker physmem_unmap(physmem, addr_map, pagesize);
88*c2e0c6b5SAndroid Build Coastguard Worker return 0;
89*c2e0c6b5SAndroid Build Coastguard Worker }
90*c2e0c6b5SAndroid Build Coastguard Worker
91*c2e0c6b5SAndroid Build Coastguard Worker if (cache && cache->addr_page != addr_page)
92*c2e0c6b5SAndroid Build Coastguard Worker physmem_unmap(physmem, cache->addr_map, pagesize);
93*c2e0c6b5SAndroid Build Coastguard Worker
94*c2e0c6b5SAndroid Build Coastguard Worker if (cache && cache->data_page != data_page && cache->data_page != cache->addr_page)
95*c2e0c6b5SAndroid Build Coastguard Worker physmem_unmap(physmem, cache->data_map, pagesize);
96*c2e0c6b5SAndroid Build Coastguard Worker
97*c2e0c6b5SAndroid Build Coastguard Worker if (!cache)
98*c2e0c6b5SAndroid Build Coastguard Worker cache = macc->cache = pci_malloc(a, sizeof(*cache));
99*c2e0c6b5SAndroid Build Coastguard Worker
100*c2e0c6b5SAndroid Build Coastguard Worker cache->addr_page = addr_page;
101*c2e0c6b5SAndroid Build Coastguard Worker cache->data_page = data_page;
102*c2e0c6b5SAndroid Build Coastguard Worker cache->addr_map = addr_map;
103*c2e0c6b5SAndroid Build Coastguard Worker cache->data_map = data_map;
104*c2e0c6b5SAndroid Build Coastguard Worker
105*c2e0c6b5SAndroid Build Coastguard Worker *addr = (unsigned char *)addr_map + (addr_reg & (pagesize-1));
106*c2e0c6b5SAndroid Build Coastguard Worker *data = (unsigned char *)data_map + (data_reg & (pagesize-1)) + data_off;
107*c2e0c6b5SAndroid Build Coastguard Worker return 1;
108*c2e0c6b5SAndroid Build Coastguard Worker }
109*c2e0c6b5SAndroid Build Coastguard Worker
110*c2e0c6b5SAndroid Build Coastguard Worker static int
validate_addrs(const char * addrs)111*c2e0c6b5SAndroid Build Coastguard Worker validate_addrs(const char *addrs)
112*c2e0c6b5SAndroid Build Coastguard Worker {
113*c2e0c6b5SAndroid Build Coastguard Worker const char *sep, *next;
114*c2e0c6b5SAndroid Build Coastguard Worker u64 num;
115*c2e0c6b5SAndroid Build Coastguard Worker char *endptr;
116*c2e0c6b5SAndroid Build Coastguard Worker
117*c2e0c6b5SAndroid Build Coastguard Worker if (!*addrs)
118*c2e0c6b5SAndroid Build Coastguard Worker return 0;
119*c2e0c6b5SAndroid Build Coastguard Worker
120*c2e0c6b5SAndroid Build Coastguard Worker while (1)
121*c2e0c6b5SAndroid Build Coastguard Worker {
122*c2e0c6b5SAndroid Build Coastguard Worker next = strchr(addrs, ',');
123*c2e0c6b5SAndroid Build Coastguard Worker if (!next)
124*c2e0c6b5SAndroid Build Coastguard Worker next = addrs + strlen(addrs);
125*c2e0c6b5SAndroid Build Coastguard Worker
126*c2e0c6b5SAndroid Build Coastguard Worker sep = strchr(addrs, '/');
127*c2e0c6b5SAndroid Build Coastguard Worker if (!sep)
128*c2e0c6b5SAndroid Build Coastguard Worker return 0;
129*c2e0c6b5SAndroid Build Coastguard Worker
130*c2e0c6b5SAndroid Build Coastguard Worker if (!isxdigit(*addrs) || !isxdigit(*(sep+1)))
131*c2e0c6b5SAndroid Build Coastguard Worker return 0;
132*c2e0c6b5SAndroid Build Coastguard Worker
133*c2e0c6b5SAndroid Build Coastguard Worker errno = 0;
134*c2e0c6b5SAndroid Build Coastguard Worker num = strtoull(addrs, &endptr, 16);
135*c2e0c6b5SAndroid Build Coastguard Worker if (errno || endptr != sep || (num & 3))
136*c2e0c6b5SAndroid Build Coastguard Worker return 0;
137*c2e0c6b5SAndroid Build Coastguard Worker
138*c2e0c6b5SAndroid Build Coastguard Worker errno = 0;
139*c2e0c6b5SAndroid Build Coastguard Worker num = strtoull(sep+1, &endptr, 16);
140*c2e0c6b5SAndroid Build Coastguard Worker if (errno || endptr != next || (num & 3))
141*c2e0c6b5SAndroid Build Coastguard Worker return 0;
142*c2e0c6b5SAndroid Build Coastguard Worker
143*c2e0c6b5SAndroid Build Coastguard Worker if (!*next)
144*c2e0c6b5SAndroid Build Coastguard Worker return 1;
145*c2e0c6b5SAndroid Build Coastguard Worker
146*c2e0c6b5SAndroid Build Coastguard Worker addrs = next + 1;
147*c2e0c6b5SAndroid Build Coastguard Worker }
148*c2e0c6b5SAndroid Build Coastguard Worker }
149*c2e0c6b5SAndroid Build Coastguard Worker
150*c2e0c6b5SAndroid Build Coastguard Worker static int
get_domain_count(const char * addrs)151*c2e0c6b5SAndroid Build Coastguard Worker get_domain_count(const char *addrs)
152*c2e0c6b5SAndroid Build Coastguard Worker {
153*c2e0c6b5SAndroid Build Coastguard Worker int count = 1;
154*c2e0c6b5SAndroid Build Coastguard Worker while (addrs = strchr(addrs, ','))
155*c2e0c6b5SAndroid Build Coastguard Worker {
156*c2e0c6b5SAndroid Build Coastguard Worker addrs++;
157*c2e0c6b5SAndroid Build Coastguard Worker count++;
158*c2e0c6b5SAndroid Build Coastguard Worker }
159*c2e0c6b5SAndroid Build Coastguard Worker return count;
160*c2e0c6b5SAndroid Build Coastguard Worker }
161*c2e0c6b5SAndroid Build Coastguard Worker
162*c2e0c6b5SAndroid Build Coastguard Worker static int
get_domain_addr(const char * addrs,int domain,u64 * addr_reg,u64 * data_reg)163*c2e0c6b5SAndroid Build Coastguard Worker get_domain_addr(const char *addrs, int domain, u64 *addr_reg, u64 *data_reg)
164*c2e0c6b5SAndroid Build Coastguard Worker {
165*c2e0c6b5SAndroid Build Coastguard Worker char *endptr;
166*c2e0c6b5SAndroid Build Coastguard Worker
167*c2e0c6b5SAndroid Build Coastguard Worker while (domain-- > 0)
168*c2e0c6b5SAndroid Build Coastguard Worker {
169*c2e0c6b5SAndroid Build Coastguard Worker addrs = strchr(addrs, ',');
170*c2e0c6b5SAndroid Build Coastguard Worker if (!addrs)
171*c2e0c6b5SAndroid Build Coastguard Worker return 0;
172*c2e0c6b5SAndroid Build Coastguard Worker addrs++;
173*c2e0c6b5SAndroid Build Coastguard Worker }
174*c2e0c6b5SAndroid Build Coastguard Worker
175*c2e0c6b5SAndroid Build Coastguard Worker *addr_reg = strtoull(addrs, &endptr, 16);
176*c2e0c6b5SAndroid Build Coastguard Worker *data_reg = strtoull(endptr+1, NULL, 16);
177*c2e0c6b5SAndroid Build Coastguard Worker
178*c2e0c6b5SAndroid Build Coastguard Worker return 1;
179*c2e0c6b5SAndroid Build Coastguard Worker }
180*c2e0c6b5SAndroid Build Coastguard Worker
181*c2e0c6b5SAndroid Build Coastguard Worker static void
conf1_config(struct pci_access * a)182*c2e0c6b5SAndroid Build Coastguard Worker conf1_config(struct pci_access *a)
183*c2e0c6b5SAndroid Build Coastguard Worker {
184*c2e0c6b5SAndroid Build Coastguard Worker physmem_init_config(a);
185*c2e0c6b5SAndroid Build Coastguard Worker pci_define_param(a, "mmio-conf1.addrs", "", "Physical addresses of memory mapped Intel conf1 interface"); /* format: 0xaddr1/0xdata1,0xaddr2/0xdata2,... */
186*c2e0c6b5SAndroid Build Coastguard Worker }
187*c2e0c6b5SAndroid Build Coastguard Worker
188*c2e0c6b5SAndroid Build Coastguard Worker static void
conf1_ext_config(struct pci_access * a)189*c2e0c6b5SAndroid Build Coastguard Worker conf1_ext_config(struct pci_access *a)
190*c2e0c6b5SAndroid Build Coastguard Worker {
191*c2e0c6b5SAndroid Build Coastguard Worker physmem_init_config(a);
192*c2e0c6b5SAndroid Build Coastguard Worker pci_define_param(a, "mmio-conf1-ext.addrs", "", "Physical addresses of memory mapped Intel conf1 extended interface"); /* format: 0xaddr1/0xdata1,0xaddr2/0xdata2,... */
193*c2e0c6b5SAndroid Build Coastguard Worker }
194*c2e0c6b5SAndroid Build Coastguard Worker
195*c2e0c6b5SAndroid Build Coastguard Worker static int
detect(struct pci_access * a,char * addrs_param_name)196*c2e0c6b5SAndroid Build Coastguard Worker detect(struct pci_access *a, char *addrs_param_name)
197*c2e0c6b5SAndroid Build Coastguard Worker {
198*c2e0c6b5SAndroid Build Coastguard Worker char *addrs = pci_get_param(a, addrs_param_name);
199*c2e0c6b5SAndroid Build Coastguard Worker
200*c2e0c6b5SAndroid Build Coastguard Worker if (!*addrs)
201*c2e0c6b5SAndroid Build Coastguard Worker {
202*c2e0c6b5SAndroid Build Coastguard Worker a->debug("%s was not specified", addrs_param_name);
203*c2e0c6b5SAndroid Build Coastguard Worker return 0;
204*c2e0c6b5SAndroid Build Coastguard Worker }
205*c2e0c6b5SAndroid Build Coastguard Worker
206*c2e0c6b5SAndroid Build Coastguard Worker if (!validate_addrs(addrs))
207*c2e0c6b5SAndroid Build Coastguard Worker {
208*c2e0c6b5SAndroid Build Coastguard Worker a->debug("%s has invalid address format %s", addrs_param_name, addrs);
209*c2e0c6b5SAndroid Build Coastguard Worker return 0;
210*c2e0c6b5SAndroid Build Coastguard Worker }
211*c2e0c6b5SAndroid Build Coastguard Worker
212*c2e0c6b5SAndroid Build Coastguard Worker if (physmem_access(a, 1))
213*c2e0c6b5SAndroid Build Coastguard Worker {
214*c2e0c6b5SAndroid Build Coastguard Worker a->debug("cannot access physical memory: %s", strerror(errno));
215*c2e0c6b5SAndroid Build Coastguard Worker return 0;
216*c2e0c6b5SAndroid Build Coastguard Worker }
217*c2e0c6b5SAndroid Build Coastguard Worker
218*c2e0c6b5SAndroid Build Coastguard Worker a->debug("using with %s", addrs);
219*c2e0c6b5SAndroid Build Coastguard Worker return 1;
220*c2e0c6b5SAndroid Build Coastguard Worker }
221*c2e0c6b5SAndroid Build Coastguard Worker
222*c2e0c6b5SAndroid Build Coastguard Worker static int
conf1_detect(struct pci_access * a)223*c2e0c6b5SAndroid Build Coastguard Worker conf1_detect(struct pci_access *a)
224*c2e0c6b5SAndroid Build Coastguard Worker {
225*c2e0c6b5SAndroid Build Coastguard Worker return detect(a, "mmio-conf1.addrs");
226*c2e0c6b5SAndroid Build Coastguard Worker }
227*c2e0c6b5SAndroid Build Coastguard Worker
228*c2e0c6b5SAndroid Build Coastguard Worker static int
conf1_ext_detect(struct pci_access * a)229*c2e0c6b5SAndroid Build Coastguard Worker conf1_ext_detect(struct pci_access *a)
230*c2e0c6b5SAndroid Build Coastguard Worker {
231*c2e0c6b5SAndroid Build Coastguard Worker return detect(a, "mmio-conf1-ext.addrs");
232*c2e0c6b5SAndroid Build Coastguard Worker }
233*c2e0c6b5SAndroid Build Coastguard Worker
234*c2e0c6b5SAndroid Build Coastguard Worker static char*
get_addrs_param_name(struct pci_access * a)235*c2e0c6b5SAndroid Build Coastguard Worker get_addrs_param_name(struct pci_access *a)
236*c2e0c6b5SAndroid Build Coastguard Worker {
237*c2e0c6b5SAndroid Build Coastguard Worker if (a->methods->config == conf1_ext_config)
238*c2e0c6b5SAndroid Build Coastguard Worker return "mmio-conf1-ext.addrs";
239*c2e0c6b5SAndroid Build Coastguard Worker else
240*c2e0c6b5SAndroid Build Coastguard Worker return "mmio-conf1.addrs";
241*c2e0c6b5SAndroid Build Coastguard Worker }
242*c2e0c6b5SAndroid Build Coastguard Worker
243*c2e0c6b5SAndroid Build Coastguard Worker static void
conf1_init(struct pci_access * a)244*c2e0c6b5SAndroid Build Coastguard Worker conf1_init(struct pci_access *a)
245*c2e0c6b5SAndroid Build Coastguard Worker {
246*c2e0c6b5SAndroid Build Coastguard Worker char *addrs_param_name = get_addrs_param_name(a);
247*c2e0c6b5SAndroid Build Coastguard Worker char *addrs = pci_get_param(a, addrs_param_name);
248*c2e0c6b5SAndroid Build Coastguard Worker struct mmio_access *macc;
249*c2e0c6b5SAndroid Build Coastguard Worker struct physmem *physmem;
250*c2e0c6b5SAndroid Build Coastguard Worker long pagesize;
251*c2e0c6b5SAndroid Build Coastguard Worker
252*c2e0c6b5SAndroid Build Coastguard Worker if (!*addrs)
253*c2e0c6b5SAndroid Build Coastguard Worker a->error("Option %s was not specified.", addrs_param_name);
254*c2e0c6b5SAndroid Build Coastguard Worker
255*c2e0c6b5SAndroid Build Coastguard Worker if (!validate_addrs(addrs))
256*c2e0c6b5SAndroid Build Coastguard Worker a->error("Option %s has invalid address format \"%s\".", addrs_param_name, addrs);
257*c2e0c6b5SAndroid Build Coastguard Worker
258*c2e0c6b5SAndroid Build Coastguard Worker physmem = physmem_open(a, 1);
259*c2e0c6b5SAndroid Build Coastguard Worker if (!physmem)
260*c2e0c6b5SAndroid Build Coastguard Worker a->error("Cannot open physcal memory: %s.", strerror(errno));
261*c2e0c6b5SAndroid Build Coastguard Worker
262*c2e0c6b5SAndroid Build Coastguard Worker pagesize = physmem_get_pagesize(physmem);
263*c2e0c6b5SAndroid Build Coastguard Worker if (pagesize <= 0)
264*c2e0c6b5SAndroid Build Coastguard Worker a->error("Cannot get page size: %s.", strerror(errno));
265*c2e0c6b5SAndroid Build Coastguard Worker
266*c2e0c6b5SAndroid Build Coastguard Worker macc = pci_malloc(a, sizeof(*macc));
267*c2e0c6b5SAndroid Build Coastguard Worker macc->cache = NULL;
268*c2e0c6b5SAndroid Build Coastguard Worker macc->physmem = physmem;
269*c2e0c6b5SAndroid Build Coastguard Worker macc->pagesize = pagesize;
270*c2e0c6b5SAndroid Build Coastguard Worker a->backend_data = macc;
271*c2e0c6b5SAndroid Build Coastguard Worker }
272*c2e0c6b5SAndroid Build Coastguard Worker
273*c2e0c6b5SAndroid Build Coastguard Worker static void
conf1_cleanup(struct pci_access * a)274*c2e0c6b5SAndroid Build Coastguard Worker conf1_cleanup(struct pci_access *a)
275*c2e0c6b5SAndroid Build Coastguard Worker {
276*c2e0c6b5SAndroid Build Coastguard Worker struct mmio_access *macc = a->backend_data;
277*c2e0c6b5SAndroid Build Coastguard Worker
278*c2e0c6b5SAndroid Build Coastguard Worker munmap_regs(a);
279*c2e0c6b5SAndroid Build Coastguard Worker physmem_close(macc->physmem);
280*c2e0c6b5SAndroid Build Coastguard Worker pci_mfree(macc);
281*c2e0c6b5SAndroid Build Coastguard Worker }
282*c2e0c6b5SAndroid Build Coastguard Worker
283*c2e0c6b5SAndroid Build Coastguard Worker static void
conf1_scan(struct pci_access * a)284*c2e0c6b5SAndroid Build Coastguard Worker conf1_scan(struct pci_access *a)
285*c2e0c6b5SAndroid Build Coastguard Worker {
286*c2e0c6b5SAndroid Build Coastguard Worker char *addrs_param_name = get_addrs_param_name(a);
287*c2e0c6b5SAndroid Build Coastguard Worker char *addrs = pci_get_param(a, addrs_param_name);
288*c2e0c6b5SAndroid Build Coastguard Worker int domain_count = get_domain_count(addrs);
289*c2e0c6b5SAndroid Build Coastguard Worker int domain;
290*c2e0c6b5SAndroid Build Coastguard Worker
291*c2e0c6b5SAndroid Build Coastguard Worker for (domain = 0; domain < domain_count; domain++)
292*c2e0c6b5SAndroid Build Coastguard Worker pci_generic_scan_domain(a, domain);
293*c2e0c6b5SAndroid Build Coastguard Worker }
294*c2e0c6b5SAndroid Build Coastguard Worker
295*c2e0c6b5SAndroid Build Coastguard Worker static int
conf1_ext_read(struct pci_dev * d,int pos,byte * buf,int len)296*c2e0c6b5SAndroid Build Coastguard Worker conf1_ext_read(struct pci_dev *d, int pos, byte *buf, int len)
297*c2e0c6b5SAndroid Build Coastguard Worker {
298*c2e0c6b5SAndroid Build Coastguard Worker char *addrs_param_name = get_addrs_param_name(d->access);
299*c2e0c6b5SAndroid Build Coastguard Worker char *addrs = pci_get_param(d->access, addrs_param_name);
300*c2e0c6b5SAndroid Build Coastguard Worker volatile void *addr, *data;
301*c2e0c6b5SAndroid Build Coastguard Worker u64 addr_reg, data_reg;
302*c2e0c6b5SAndroid Build Coastguard Worker
303*c2e0c6b5SAndroid Build Coastguard Worker if (pos >= 4096)
304*c2e0c6b5SAndroid Build Coastguard Worker return 0;
305*c2e0c6b5SAndroid Build Coastguard Worker
306*c2e0c6b5SAndroid Build Coastguard Worker if (len != 1 && len != 2 && len != 4)
307*c2e0c6b5SAndroid Build Coastguard Worker return pci_generic_block_read(d, pos, buf, len);
308*c2e0c6b5SAndroid Build Coastguard Worker
309*c2e0c6b5SAndroid Build Coastguard Worker if (!get_domain_addr(addrs, d->domain, &addr_reg, &data_reg))
310*c2e0c6b5SAndroid Build Coastguard Worker return 0;
311*c2e0c6b5SAndroid Build Coastguard Worker
312*c2e0c6b5SAndroid Build Coastguard Worker if (!mmap_regs(d->access, addr_reg, data_reg, pos&3, &addr, &data))
313*c2e0c6b5SAndroid Build Coastguard Worker return 0;
314*c2e0c6b5SAndroid Build Coastguard Worker
315*c2e0c6b5SAndroid Build Coastguard Worker physmem_writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr);
316*c2e0c6b5SAndroid Build Coastguard Worker physmem_readl(addr); /* write barrier for address */
317*c2e0c6b5SAndroid Build Coastguard Worker
318*c2e0c6b5SAndroid Build Coastguard Worker switch (len)
319*c2e0c6b5SAndroid Build Coastguard Worker {
320*c2e0c6b5SAndroid Build Coastguard Worker case 1:
321*c2e0c6b5SAndroid Build Coastguard Worker buf[0] = physmem_readb(data);
322*c2e0c6b5SAndroid Build Coastguard Worker break;
323*c2e0c6b5SAndroid Build Coastguard Worker case 2:
324*c2e0c6b5SAndroid Build Coastguard Worker ((u16 *) buf)[0] = physmem_readw(data);
325*c2e0c6b5SAndroid Build Coastguard Worker break;
326*c2e0c6b5SAndroid Build Coastguard Worker case 4:
327*c2e0c6b5SAndroid Build Coastguard Worker ((u32 *) buf)[0] = physmem_readl(data);
328*c2e0c6b5SAndroid Build Coastguard Worker break;
329*c2e0c6b5SAndroid Build Coastguard Worker }
330*c2e0c6b5SAndroid Build Coastguard Worker
331*c2e0c6b5SAndroid Build Coastguard Worker return 1;
332*c2e0c6b5SAndroid Build Coastguard Worker }
333*c2e0c6b5SAndroid Build Coastguard Worker
334*c2e0c6b5SAndroid Build Coastguard Worker static int
conf1_read(struct pci_dev * d,int pos,byte * buf,int len)335*c2e0c6b5SAndroid Build Coastguard Worker conf1_read(struct pci_dev *d, int pos, byte *buf, int len)
336*c2e0c6b5SAndroid Build Coastguard Worker {
337*c2e0c6b5SAndroid Build Coastguard Worker if (pos >= 256)
338*c2e0c6b5SAndroid Build Coastguard Worker return 0;
339*c2e0c6b5SAndroid Build Coastguard Worker
340*c2e0c6b5SAndroid Build Coastguard Worker return conf1_ext_read(d, pos, buf, len);
341*c2e0c6b5SAndroid Build Coastguard Worker }
342*c2e0c6b5SAndroid Build Coastguard Worker
343*c2e0c6b5SAndroid Build Coastguard Worker static int
conf1_ext_write(struct pci_dev * d,int pos,byte * buf,int len)344*c2e0c6b5SAndroid Build Coastguard Worker conf1_ext_write(struct pci_dev *d, int pos, byte *buf, int len)
345*c2e0c6b5SAndroid Build Coastguard Worker {
346*c2e0c6b5SAndroid Build Coastguard Worker char *addrs_param_name = get_addrs_param_name(d->access);
347*c2e0c6b5SAndroid Build Coastguard Worker char *addrs = pci_get_param(d->access, addrs_param_name);
348*c2e0c6b5SAndroid Build Coastguard Worker volatile void *addr, *data;
349*c2e0c6b5SAndroid Build Coastguard Worker u64 addr_reg, data_reg;
350*c2e0c6b5SAndroid Build Coastguard Worker
351*c2e0c6b5SAndroid Build Coastguard Worker if (pos >= 4096)
352*c2e0c6b5SAndroid Build Coastguard Worker return 0;
353*c2e0c6b5SAndroid Build Coastguard Worker
354*c2e0c6b5SAndroid Build Coastguard Worker if (len != 1 && len != 2 && len != 4)
355*c2e0c6b5SAndroid Build Coastguard Worker return pci_generic_block_write(d, pos, buf, len);
356*c2e0c6b5SAndroid Build Coastguard Worker
357*c2e0c6b5SAndroid Build Coastguard Worker if (!get_domain_addr(addrs, d->domain, &addr_reg, &data_reg))
358*c2e0c6b5SAndroid Build Coastguard Worker return 0;
359*c2e0c6b5SAndroid Build Coastguard Worker
360*c2e0c6b5SAndroid Build Coastguard Worker if (!mmap_regs(d->access, addr_reg, data_reg, pos&3, &addr, &data))
361*c2e0c6b5SAndroid Build Coastguard Worker return 0;
362*c2e0c6b5SAndroid Build Coastguard Worker
363*c2e0c6b5SAndroid Build Coastguard Worker physmem_writel(0x80000000 | ((pos & 0xf00) << 16) | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & 0xfc), addr);
364*c2e0c6b5SAndroid Build Coastguard Worker physmem_readl(addr); /* write barrier for address */
365*c2e0c6b5SAndroid Build Coastguard Worker
366*c2e0c6b5SAndroid Build Coastguard Worker switch (len)
367*c2e0c6b5SAndroid Build Coastguard Worker {
368*c2e0c6b5SAndroid Build Coastguard Worker case 1:
369*c2e0c6b5SAndroid Build Coastguard Worker physmem_writeb(buf[0], data);
370*c2e0c6b5SAndroid Build Coastguard Worker break;
371*c2e0c6b5SAndroid Build Coastguard Worker case 2:
372*c2e0c6b5SAndroid Build Coastguard Worker physmem_writew(((u16 *) buf)[0], data);
373*c2e0c6b5SAndroid Build Coastguard Worker break;
374*c2e0c6b5SAndroid Build Coastguard Worker case 4:
375*c2e0c6b5SAndroid Build Coastguard Worker physmem_writel(((u32 *) buf)[0], data);
376*c2e0c6b5SAndroid Build Coastguard Worker break;
377*c2e0c6b5SAndroid Build Coastguard Worker }
378*c2e0c6b5SAndroid Build Coastguard Worker
379*c2e0c6b5SAndroid Build Coastguard Worker /*
380*c2e0c6b5SAndroid Build Coastguard Worker * write barrier for data
381*c2e0c6b5SAndroid Build Coastguard Worker * Note that we cannot read from data port because it may have side effect.
382*c2e0c6b5SAndroid Build Coastguard Worker * Instead we read from address port (which should not have side effect) to
383*c2e0c6b5SAndroid Build Coastguard Worker * create a barrier between two conf1_write() calls. But this does not have
384*c2e0c6b5SAndroid Build Coastguard Worker * to be 100% correct as it does not ensure barrier on data port itself.
385*c2e0c6b5SAndroid Build Coastguard Worker * Correct way is to issue CPU instruction for full hw sync barrier but gcc
386*c2e0c6b5SAndroid Build Coastguard Worker * does not provide any (builtin) function yet.
387*c2e0c6b5SAndroid Build Coastguard Worker */
388*c2e0c6b5SAndroid Build Coastguard Worker physmem_readl(addr);
389*c2e0c6b5SAndroid Build Coastguard Worker
390*c2e0c6b5SAndroid Build Coastguard Worker return 1;
391*c2e0c6b5SAndroid Build Coastguard Worker }
392*c2e0c6b5SAndroid Build Coastguard Worker
393*c2e0c6b5SAndroid Build Coastguard Worker static int
conf1_write(struct pci_dev * d,int pos,byte * buf,int len)394*c2e0c6b5SAndroid Build Coastguard Worker conf1_write(struct pci_dev *d, int pos, byte *buf, int len)
395*c2e0c6b5SAndroid Build Coastguard Worker {
396*c2e0c6b5SAndroid Build Coastguard Worker if (pos >= 256)
397*c2e0c6b5SAndroid Build Coastguard Worker return 0;
398*c2e0c6b5SAndroid Build Coastguard Worker
399*c2e0c6b5SAndroid Build Coastguard Worker return conf1_ext_write(d, pos, buf, len);
400*c2e0c6b5SAndroid Build Coastguard Worker }
401*c2e0c6b5SAndroid Build Coastguard Worker
402*c2e0c6b5SAndroid Build Coastguard Worker struct pci_methods pm_mmio_conf1 = {
403*c2e0c6b5SAndroid Build Coastguard Worker .name = "mmio-conf1",
404*c2e0c6b5SAndroid Build Coastguard Worker .help = "Raw memory mapped I/O port access using Intel conf1 interface",
405*c2e0c6b5SAndroid Build Coastguard Worker .config = conf1_config,
406*c2e0c6b5SAndroid Build Coastguard Worker .detect = conf1_detect,
407*c2e0c6b5SAndroid Build Coastguard Worker .init = conf1_init,
408*c2e0c6b5SAndroid Build Coastguard Worker .cleanup = conf1_cleanup,
409*c2e0c6b5SAndroid Build Coastguard Worker .scan = conf1_scan,
410*c2e0c6b5SAndroid Build Coastguard Worker .fill_info = pci_generic_fill_info,
411*c2e0c6b5SAndroid Build Coastguard Worker .read = conf1_read,
412*c2e0c6b5SAndroid Build Coastguard Worker .write = conf1_write,
413*c2e0c6b5SAndroid Build Coastguard Worker };
414*c2e0c6b5SAndroid Build Coastguard Worker
415*c2e0c6b5SAndroid Build Coastguard Worker struct pci_methods pm_mmio_conf1_ext = {
416*c2e0c6b5SAndroid Build Coastguard Worker .name = "mmio-conf1-ext",
417*c2e0c6b5SAndroid Build Coastguard Worker .help = "Raw memory mapped I/O port access using Intel conf1 extended interface",
418*c2e0c6b5SAndroid Build Coastguard Worker .config = conf1_ext_config,
419*c2e0c6b5SAndroid Build Coastguard Worker .detect = conf1_ext_detect,
420*c2e0c6b5SAndroid Build Coastguard Worker .init = conf1_init,
421*c2e0c6b5SAndroid Build Coastguard Worker .cleanup = conf1_cleanup,
422*c2e0c6b5SAndroid Build Coastguard Worker .scan = conf1_scan,
423*c2e0c6b5SAndroid Build Coastguard Worker .fill_info = pci_generic_fill_info,
424*c2e0c6b5SAndroid Build Coastguard Worker .read = conf1_ext_read,
425*c2e0c6b5SAndroid Build Coastguard Worker .write = conf1_ext_write,
426*c2e0c6b5SAndroid Build Coastguard Worker };
427