xref: /aosp_15_r20/external/pciutils/lib/mmio-ports.c (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
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