]> mj.ucw.cz Git - pciutils.git/blob - lib/ecam.c
7c688169548f0742dbca607025b6a969a60dc29c
[pciutils.git] / lib / ecam.c
1 /*
2  *      The PCI Library -- Direct Configuration access via PCIe ECAM
3  *
4  *      Copyright (c) 2023 Pali Rohár <pali@kernel.org>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL v2+.
7  *
8  *      SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include "internal.h"
12 #include "physmem.h"
13 #include "physmem-access.h"
14
15 #include <ctype.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <limits.h>
21
22 #include <glob.h>
23 #include <unistd.h>
24
25 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
26 #include <sys/sysctl.h>
27 #endif
28
29 #if defined (__FreeBSD__) || defined (__DragonFly__)
30 #include <kenv.h>
31 #endif
32
33 struct acpi_rsdp {
34   char signature[8];
35   u8 checksum;
36   char oem_id[6];
37   u8 revision;
38   u32 rsdt_address;
39   struct {
40     u32 length;
41     u64 xsdt_address;
42     u8 ext_checksum;
43     u8 reserved[3];
44   } rsdp20[0];
45 } PCI_PACKED;
46
47 struct acpi_sdt {
48   char signature[4];
49   u32 length;
50   u8 revision;
51   u8 checksum;
52   char oem_id[6];
53   char oem_table_id[8];
54   u32 oem_revision;
55   char asl_compiler_id[4];
56   u32 asl_compiler_revision;
57 } PCI_PACKED;
58
59 struct acpi_rsdt {
60   struct acpi_sdt sdt;
61   u32 sdt_addresses[0];
62 } PCI_PACKED;
63
64 struct acpi_xsdt {
65   struct acpi_sdt sdt;
66   u64 sdt_addresses[0];
67 } PCI_PACKED;
68
69 struct acpi_mcfg {
70   struct acpi_sdt sdt;
71   u64 reserved;
72   struct {
73     u64 address;
74     u16 pci_segment;
75     u8 start_bus_number;
76     u8 end_bus_number;
77     u32 reserved;
78   } allocations[0];
79 } PCI_PACKED;
80
81 struct mmap_cache {
82   void *map;
83   u64 addr;
84   u32 length;
85   int domain;
86   u8 bus;
87   int w;
88 };
89
90 // Back-end data linked to struct pci_access
91 struct ecam_access {
92   struct acpi_mcfg *mcfg;
93   struct mmap_cache *cache;
94   struct physmem *physmem;
95   long pagesize;
96 };
97
98 static unsigned int
99 get_rsdt_addresses_count(struct acpi_rsdt *rsdt)
100 {
101   return (rsdt->sdt.length - ((unsigned char*)&rsdt->sdt_addresses - (unsigned char *)rsdt)) / sizeof(rsdt->sdt_addresses[0]);
102 }
103
104 static unsigned int
105 get_xsdt_addresses_count(struct acpi_xsdt *xsdt)
106 {
107   return (xsdt->sdt.length - ((unsigned char*)&xsdt->sdt_addresses - (unsigned char *)xsdt)) / sizeof(xsdt->sdt_addresses[0]);
108 }
109
110 static unsigned int
111 get_mcfg_allocations_count(struct acpi_mcfg *mcfg)
112 {
113   return (mcfg->sdt.length - ((unsigned char *)&mcfg->allocations - (unsigned char *)mcfg)) / sizeof(mcfg->allocations[0]);
114 }
115
116 static u8
117 calculate_checksum(const u8 *bytes, int len)
118 {
119   u8 checksum = 0;
120
121   while (len-- > 0)
122     checksum -= *(bytes++);
123   return checksum;
124 }
125
126 static struct acpi_sdt *
127 check_and_map_sdt(struct physmem *physmem, long pagesize, u64 addr, const char *signature, void **map_addr, u32 *map_length)
128 {
129   struct acpi_sdt *sdt;
130   char sdt_signature[sizeof(sdt->signature)];
131   u32 length;
132   void *map;
133
134   if (addr + sizeof(*sdt) < addr)
135     return NULL;
136
137   map = physmem_map(physmem, addr & ~(pagesize-1), sizeof(*sdt) + (addr & (pagesize-1)), 0);
138   if (map == (void *)-1)
139     return NULL;
140
141   sdt = (struct acpi_sdt *)((unsigned char *)map + (addr & (pagesize-1)));
142   length = sdt->length;
143   memcpy(sdt_signature, sdt->signature, sizeof(sdt->signature));
144
145   physmem_unmap(physmem, map, sizeof(*sdt) + (addr & (pagesize-1)));
146
147   if (memcmp(sdt_signature, signature, sizeof(sdt_signature)) != 0)
148     return NULL;
149   if (length < sizeof(*sdt))
150     return NULL;
151
152   map = physmem_map(physmem, addr & ~(pagesize-1), length + (addr & (pagesize-1)), 0);
153   if (map == (void *)-1)
154     return NULL;
155
156   sdt = (struct acpi_sdt *)((unsigned char *)map + (addr & (pagesize-1)));
157
158   if (calculate_checksum((u8 *)sdt, sdt->length) != 0)
159     {
160       physmem_unmap(physmem, map, length + (addr & (pagesize-1)));
161       return NULL;
162     }
163
164   *map_addr = map;
165   *map_length = length + (addr & (pagesize-1));
166   return sdt;
167 }
168
169 static int
170 check_rsdp(struct acpi_rsdp *rsdp)
171 {
172   if (memcmp(rsdp->signature, "RSD PTR ", sizeof(rsdp->signature)) != 0)
173     return 0;
174   if (calculate_checksum((u8 *)rsdp, sizeof(*rsdp)) != 0)
175     return 0;
176   return 1;
177 }
178
179 static int
180 check_and_parse_rsdp(struct physmem *physmem, long pagesize, u64 addr, u32 *rsdt_address, u64 *xsdt_address)
181 {
182   struct acpi_rsdp *rsdp;
183   unsigned char buf[sizeof(*rsdp) + sizeof(*rsdp->rsdp20)];
184   void *map;
185
186   map = physmem_map(physmem, addr & ~(pagesize-1), sizeof(buf) + (addr & (pagesize-1)), 0);
187   if (map == (void *)-1)
188     return 0;
189
190   rsdp = (struct acpi_rsdp *)buf;
191   memcpy(rsdp, (unsigned char *)map + (addr & (pagesize-1)), sizeof(buf));
192
193   physmem_unmap(physmem, map, sizeof(buf));
194
195   if (!check_rsdp(rsdp))
196     return 0;
197
198   *rsdt_address = rsdp->rsdt_address;
199
200   if (rsdp->revision != 0 &&
201       (*rsdp->rsdp20).length == sizeof(*rsdp) + sizeof(*rsdp->rsdp20) &&
202       calculate_checksum((u8 *)rsdp, (*rsdp->rsdp20).length) == 0)
203     *xsdt_address = (*rsdp->rsdp20).xsdt_address;
204   else
205     *xsdt_address = 0;
206
207   return 1;
208 }
209
210 static u64
211 find_rsdp_address(struct pci_access *a, const char *efisystab, int use_bsd UNUSED, int use_x86bios UNUSED)
212 {
213   u64 ullnum;
214 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
215   unsigned long ulnum;
216 #endif
217   char buf[1024];
218   char *endptr;
219   u64 acpi20;
220   u64 acpi;
221 #if defined(__amd64__) || defined(__i386__)
222   struct ecam_access *eacc = a->backend_data;
223   struct physmem *physmem = eacc->physmem;
224   u64 rsdp_addr;
225   u64 addr;
226   void *map;
227 #endif
228   size_t len;
229   FILE *f;
230
231   if (efisystab[0])
232     {
233       acpi = 0;
234       acpi20 = 0;
235       a->debug("reading EFI system table: %s...", efisystab);
236       f = fopen(efisystab, "r");
237       if (f)
238         {
239           while (fgets(buf, sizeof(buf), f))
240             {
241               len = strlen(buf);
242               while (len > 0 && buf[len-1] == '\n')
243                 buf[--len] = '\0';
244               if (strncmp(buf, "ACPI20=", 7) == 0 && isxdigit(buf[7]))
245                 {
246                   errno = 0;
247                   ullnum = strtoull(buf+7, &endptr, 16);
248                   if (!errno && !*endptr)
249                     acpi20 = ullnum;
250                 }
251               else if (strncmp(buf, "ACPI=", 5) == 0 && isxdigit(buf[5]))
252                 {
253                   errno = 0;
254                   ullnum = strtoull(buf+5, &endptr, 16);
255                   if (!errno && !*endptr)
256                     acpi = ullnum;
257                 }
258             }
259           fclose(f);
260         }
261       else
262         a->debug("opening failed: %s...", strerror(errno));
263
264       if (acpi20)
265         return acpi20;
266       else if (acpi)
267         return acpi;
268     }
269
270 #if defined (__FreeBSD__) || defined (__DragonFly__)
271   if (use_bsd)
272     {
273       /* First try FreeBSD kenv hint.acpi.0.rsdp */
274       a->debug("calling kenv hint.acpi.0.rsdp...");
275       if (kenv(KENV_GET, "hint.acpi.0.rsdp", buf, sizeof(buf)) > 0)
276         {
277           errno = 0;
278           ullnum = strtoull(buf, &endptr, 16);
279           if (!errno && !*endptr)
280             return ullnum;
281         }
282
283       /* Then try FreeBSD sysctl machdep.acpi_root */
284       a->debug("calling sysctl machdep.acpi_root...");
285       len = sizeof(ulnum);
286       if (sysctlbyname("machdep.acpi_root", &ulnum, &len, NULL, 0) == 0)
287         return ulnum;
288     }
289 #endif
290
291 #if defined(__NetBSD__)
292   if (use_bsd)
293     {
294       /* Try NetBSD sysctl hw.acpi.root */
295       a->debug("calling sysctl hw.acpi.root...");
296       len = sizeof(ulnum);
297       if (sysctlbyname("hw.acpi.root", &ulnum, &len, NULL, 0) == 0)
298         return ulnum;
299     }
300 #endif
301
302 #if defined(__amd64__) || defined(__i386__)
303   if (use_x86bios)
304     {
305       rsdp_addr = 0;
306
307       /* Scan first kB of Extended BIOS Data Area */
308       a->debug("scanning first kB of EBDA...");
309       map = physmem_map(physmem, 0, 0x40E + 1024, 0);
310       if (map != (void *)-1)
311         {
312           for (addr = 0x40E; addr < 0x40E + 1024; addr += 16)
313             {
314               if (check_rsdp((struct acpi_rsdp *)((unsigned char *)map + addr)))
315                 {
316                   rsdp_addr = addr;
317                   break;
318                 }
319             }
320           if (physmem_unmap(physmem, map, 0x40E + 1024) != 0)
321             a->debug("unmapping of EBDA failed: %s...", strerror(errno));
322         }
323       else
324         a->debug("mapping of EBDA failed: %s...", strerror(errno));
325
326       if (rsdp_addr)
327         return rsdp_addr;
328
329       /* Scan the main BIOS area below 1 MB */
330       a->debug("scanning BIOS below 1 MB...");
331       map = physmem_map(physmem, 0xE0000, 0x20000, 0);
332       if (map != (void *)-1)
333         {
334           for (addr = 0x0; addr < 0x20000; addr += 16)
335             {
336               if (check_rsdp((struct acpi_rsdp *)((unsigned char *)map + addr)))
337                 {
338                   rsdp_addr = 0xE0000 + addr;
339                   break;
340                 }
341             }
342           if (physmem_unmap(physmem, map, 0x20000) != 0)
343             a->debug("unmapping of BIOS failed: %s...", strerror(errno));
344         }
345       else
346         a->debug("mapping of BIOS failed: %s...", strerror(errno));
347
348       if (rsdp_addr)
349         return rsdp_addr;
350     }
351 #endif
352
353   return 0;
354 }
355
356 static struct acpi_mcfg *
357 find_mcfg(struct pci_access *a, const char *acpimcfg, const char *efisystab, int use_bsd, int use_x86bios)
358 {
359   struct ecam_access *eacc = a->backend_data;
360   struct physmem *physmem = eacc->physmem;
361   long pagesize = eacc->pagesize;
362   struct acpi_xsdt *xsdt;
363   struct acpi_rsdt *rsdt;
364   struct acpi_mcfg *mcfg;
365   struct acpi_sdt *sdt;
366   unsigned int i, count;
367   u64 rsdp_address;
368   u64 xsdt_address;
369   u32 rsdt_address;
370   void *map_addr;
371   u32 map_length;
372   void *map2_addr;
373   u32 map2_length;
374   long length;
375   FILE *mcfg_file;
376   const char *path;
377   glob_t mcfg_glob;
378   int ret;
379
380   if (acpimcfg[0])
381     {
382       ret = glob(acpimcfg, GLOB_NOCHECK, NULL, &mcfg_glob);
383       if (ret == 0)
384         {
385           path = mcfg_glob.gl_pathv[0];
386           a->debug("reading acpi mcfg file: %s...", path);
387           mcfg_file = fopen(path, "rb");
388           globfree(&mcfg_glob);
389           if (mcfg_file)
390             {
391               if (fseek(mcfg_file, 0, SEEK_END) == 0)
392                 length = ftell(mcfg_file);
393               else
394                 length = -1;
395               if (length > 0 && (size_t)length > sizeof(*mcfg))
396                 {
397                   rewind(mcfg_file);
398                   mcfg = pci_malloc(a, length);
399                   if (fread(mcfg, 1, length, mcfg_file) == (size_t)length &&
400                       memcmp(mcfg->sdt.signature, "MCFG", 4) == 0 &&
401                       mcfg->sdt.length <= (size_t)length &&
402                       calculate_checksum((u8 *)mcfg, mcfg->sdt.length) == 0)
403                     {
404                       fclose(mcfg_file);
405                       return mcfg;
406                     }
407                 }
408               fclose(mcfg_file);
409             }
410           a->debug("failed...");
411         }
412       else
413         a->debug("glob(%s) failed: %d...", acpimcfg, ret);
414     }
415
416   a->debug("searching for ACPI RSDP...");
417   rsdp_address = find_rsdp_address(a, efisystab, use_bsd, use_x86bios);
418   if (!rsdp_address)
419     {
420       a->debug("not found...");
421       return NULL;
422     }
423   a->debug("found at 0x%" PCI_U64_FMT_X "...", rsdp_address);
424
425   if (!check_and_parse_rsdp(physmem, pagesize, rsdp_address, &rsdt_address, &xsdt_address))
426     {
427       a->debug("invalid...");
428       return NULL;
429     }
430
431   mcfg = NULL;
432   a->debug("searching for ACPI MCFG (XSDT=0x%" PCI_U64_FMT_X ", RSDT=0x%lx)...", xsdt_address, (unsigned long)rsdt_address);
433
434   xsdt = xsdt_address ? (struct acpi_xsdt *)check_and_map_sdt(physmem, pagesize, xsdt_address, "XSDT", &map_addr, &map_length) : NULL;
435   if (xsdt)
436     {
437       a->debug("via XSDT...");
438       count = get_xsdt_addresses_count(xsdt);
439       for (i = 0; i < count; i++)
440         {
441           sdt = check_and_map_sdt(physmem, pagesize, xsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length);
442           if (sdt)
443             {
444               mcfg = pci_malloc(a, sdt->length);
445               memcpy(mcfg, sdt, sdt->length);
446               physmem_unmap(physmem, map2_addr, map2_length);
447               break;
448             }
449         }
450       physmem_unmap(physmem, map_addr, map_length);
451       if (mcfg)
452         {
453           a->debug("found...");
454           return mcfg;
455         }
456     }
457
458   rsdt = (struct acpi_rsdt *)check_and_map_sdt(physmem, pagesize, rsdt_address, "RSDT", &map_addr, &map_length);
459   if (rsdt)
460     {
461       a->debug("via RSDT...");
462       count = get_rsdt_addresses_count(rsdt);
463       for (i = 0; i < count; i++)
464         {
465           sdt = check_and_map_sdt(physmem, pagesize, rsdt->sdt_addresses[i], "MCFG", &map2_addr, &map2_length);
466           if (sdt)
467             {
468               mcfg = pci_malloc(a, sdt->length);
469               memcpy(mcfg, sdt, sdt->length);
470               physmem_unmap(physmem, map2_addr, map2_length);
471               break;
472             }
473         }
474       physmem_unmap(physmem, map_addr, map_length);
475       if (mcfg)
476         {
477           a->debug("found...");
478           return mcfg;
479         }
480     }
481
482   a->debug("not found...");
483   return NULL;
484 }
485
486 static void
487 get_mcfg_allocation(struct acpi_mcfg *mcfg, unsigned int i, int *domain, u8 *start_bus, u8 *end_bus, u64 *addr, u32 *length)
488 {
489   int buses = (int)mcfg->allocations[i].end_bus_number - (int)mcfg->allocations[i].start_bus_number + 1;
490
491   if (domain)
492     *domain = mcfg->allocations[i].pci_segment;
493   if (start_bus)
494     *start_bus = mcfg->allocations[i].start_bus_number;
495   if (end_bus)
496     *end_bus = mcfg->allocations[i].end_bus_number;
497   if (addr)
498     *addr = mcfg->allocations[i].address;
499   if (length)
500     *length = (buses > 0) ? (buses * 32 * 8 * 4096) : 0;
501 }
502
503 static int
504 parse_next_addrs(const char *addrs, const char **next, int *domain, u8 *start_bus, u8 *end_bus, u64 *addr, u32 *length)
505 {
506   u64 ullnum;
507   const char *sep1, *sep2;
508   int addr_len;
509   char *endptr;
510   long num;
511   int buses;
512   u64 start_addr;
513
514   if (!*addrs)
515     {
516       if (next)
517         *next = NULL;
518       return 0;
519     }
520
521   endptr = strchr(addrs, ',');
522   if (endptr)
523     addr_len = endptr - addrs;
524   else
525     addr_len = strlen(addrs);
526
527   if (next)
528     *next = endptr ? (endptr+1) : NULL;
529
530   sep1 = memchr(addrs, ':', addr_len);
531   if (!sep1)
532     return 0;
533
534   sep2 = memchr(sep1+1, ':', addr_len - (sep1+1 - addrs));
535   if (!sep2)
536     {
537       sep2 = sep1;
538       sep1 = NULL;
539     }
540
541   if (!sep1)
542     {
543       if (domain)
544         *domain = 0;
545     }
546   else
547     {
548       if (!isxdigit(*addrs))
549         return 0;
550       errno = 0;
551       num = strtol(addrs, &endptr, 16);
552       if (errno || endptr != sep1 || num < 0 || num > INT_MAX)
553         return 0;
554       if (domain)
555         *domain = num;
556     }
557
558   errno = 0;
559   num = strtol(sep1 ? (sep1+1) : addrs, &endptr, 16);
560   if (errno || num < 0 || num > 0xff)
561     return 0;
562   if (start_bus)
563     *start_bus = num;
564
565   buses = -num;
566
567   if (endptr != sep2)
568     {
569       if (*endptr != '-')
570         return 0;
571       errno = 0;
572       num = strtol(endptr+1, &endptr, 16);
573       if (errno || endptr != sep2 || num < 0 || num > 0xff)
574         return 0;
575       buses = num - -buses + 1;
576       if (buses <= 0)
577         return 0;
578       if (end_bus)
579         *end_bus = num;
580     }
581
582   if (!isxdigit(*(sep2+1)))
583     return 0;
584
585   errno = 0;
586   ullnum = strtoull(sep2+1, &endptr, 16);
587   if (errno || (ullnum & 3))
588     return 0;
589   if (addr)
590     *addr = ullnum;
591   start_addr = ullnum;
592
593   if (endptr == addrs + addr_len)
594     {
595       if (buses <= 0)
596         {
597           buses = 0xff - -buses + 1;
598           if (end_bus)
599             *end_bus = 0xff;
600         }
601       if (start_addr + (unsigned)buses * 32 * 8 * 4096 < start_addr)
602         return 0;
603       if (length)
604         *length = buses * 32 * 8 * 4096;
605     }
606   else
607     {
608       if (*endptr != '+' || !isxdigit(*(endptr+1)))
609         return 0;
610       errno = 0;
611       ullnum = strtoull(endptr+1, &endptr, 16);
612       if (errno || endptr != addrs + addr_len || (ullnum & 3) || ullnum > 256 * 32 * 8 * 4096)
613         return 0;
614       if (start_addr + ullnum < start_addr)
615         return 0;
616       if (buses > 0 && ullnum > (unsigned)buses * 32 * 8 * 4096)
617         return 0;
618       if (buses <= 0 && ullnum > (0xff - (unsigned)-buses + 1) * 32 * 8 * 4096)
619         return 0;
620       if (length)
621         *length = ullnum;
622       if (buses <= 0 && end_bus)
623         *end_bus = -buses + (ullnum + 32 * 8 * 4096 - 1) / (32 * 8 * 4096);
624     }
625
626   return 1;
627 }
628
629 static int
630 validate_addrs(const char *addrs)
631 {
632   if (!*addrs)
633     return 1;
634
635   while (addrs)
636     if (!parse_next_addrs(addrs, &addrs, NULL, NULL, NULL, NULL, NULL))
637       return 0;
638
639   return 1;
640 }
641
642 static int
643 calculate_bus_addr(u8 start_bus, u64 start_addr, u32 total_length, u8 bus, u64 *addr, u32 *length)
644 {
645   u32 offset;
646
647   offset = 32*8*4096 * (bus - start_bus);
648   if (offset >= total_length)
649     return 0;
650
651   *addr = start_addr + offset;
652   *length = total_length - offset;
653
654   if (*length > 32*8*4096)
655     *length = 32*8*4096;
656
657   return 1;
658 }
659
660 static int
661 get_bus_addr(struct acpi_mcfg *mcfg, const char *addrs, int domain, u8 bus, u64 *addr, u32 *length)
662 {
663   int cur_domain;
664   u8 start_bus;
665   u8 end_bus;
666   u64 start_addr;
667   u32 total_length;
668   int i, count;
669
670   if (mcfg)
671     {
672       count = get_mcfg_allocations_count(mcfg);
673       for (i = 0; i < count; i++)
674         {
675           get_mcfg_allocation(mcfg, i, &cur_domain, &start_bus, &end_bus, &start_addr, &total_length);
676           if (domain == cur_domain && bus >= start_bus && bus <= end_bus)
677             return calculate_bus_addr(start_bus, start_addr, total_length, bus, addr, length);
678         }
679       return 0;
680     }
681   else
682     {
683       while (addrs)
684         {
685           if (!parse_next_addrs(addrs, &addrs, &cur_domain, &start_bus, &end_bus, &start_addr, &total_length))
686             return 0;
687           if (domain == cur_domain && bus >= start_bus && bus <= end_bus)
688             return calculate_bus_addr(start_bus, start_addr, total_length, bus, addr, length);
689         }
690       return 0;
691     }
692 }
693
694 static void
695 munmap_reg(struct pci_access *a)
696 {
697   struct ecam_access *eacc = a->backend_data;
698   struct mmap_cache *cache = eacc->cache;
699   struct physmem *physmem = eacc->physmem;
700   long pagesize = eacc->pagesize;
701
702   if (!cache)
703     return;
704
705   physmem_unmap(physmem, cache->map, cache->length + (cache->addr & (pagesize-1)));
706   pci_mfree(cache);
707   eacc->cache = NULL;
708 }
709
710 static int
711 mmap_reg(struct pci_access *a, int w, int domain, u8 bus, u8 dev, u8 func, int pos, volatile void **reg)
712 {
713   struct ecam_access *eacc = a->backend_data;
714   struct mmap_cache *cache = eacc->cache;
715   struct physmem *physmem = eacc->physmem;
716   long pagesize = eacc->pagesize;
717   const char *addrs;
718   void *map;
719   u64 addr;
720   u32 length;
721   u32 offset;
722
723   if (cache && cache->domain == domain && cache->bus == bus && !!cache->w == !!w)
724     {
725       map = cache->map;
726       addr = cache->addr;
727       length = cache->length;
728     }
729   else
730     {
731       addrs = pci_get_param(a, "ecam.addrs");
732       if (!get_bus_addr(eacc->mcfg, addrs, domain, bus, &addr, &length))
733         return 0;
734
735       map = physmem_map(physmem, addr & ~(pagesize-1), length + (addr & (pagesize-1)), w);
736       if (map == (void *)-1)
737         return 0;
738
739       if (cache)
740         physmem_unmap(physmem, cache->map, cache->length + (cache->addr & (pagesize-1)));
741       else
742         cache = eacc->cache = pci_malloc(a, sizeof(*cache));
743
744       cache->map = map;
745       cache->addr = addr;
746       cache->length = length;
747       cache->domain = domain;
748       cache->bus = bus;
749       cache->w = w;
750     }
751
752   /*
753    * Enhanced Configuration Access Mechanism (ECAM) offset according to:
754    * PCI Express Base Specification, Revision 5.0, Version 1.0, Section 7.2.2, Table 7-1, p. 677
755    */
756   offset = ((dev & 0x1f) << 15) | ((func & 0x7) << 12) | (pos & 0xfff);
757
758   if (offset + 4 > length)
759     return 0;
760
761   *reg = (unsigned char *)map + (addr & (pagesize-1)) + offset;
762   return 1;
763 }
764
765 static void
766 ecam_config(struct pci_access *a)
767 {
768   physmem_init_config(a);
769   pci_define_param(a, "ecam.acpimcfg", PCI_PATH_ACPI_MCFG, "Path to the ACPI MCFG table");
770   pci_define_param(a, "ecam.efisystab", PCI_PATH_EFI_SYSTAB, "Path to the EFI system table");
771 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
772   pci_define_param(a, "ecam.bsd", "1", "Use BSD kenv or sysctl to find ACPI MCFG table");
773 #endif
774 #if defined(__amd64__) || defined(__i386__)
775   pci_define_param(a, "ecam.x86bios", "1", "Scan x86 BIOS memory for ACPI MCFG table");
776 #endif
777   pci_define_param(a, "ecam.addrs", "", "Physical addresses of memory mapped PCIe ECAM interface"); /* format: [domain:]start_bus[-end_bus]:start_addr[+length],... */
778 }
779
780 static int
781 ecam_detect(struct pci_access *a)
782 {
783   int use_addrs = 1, use_acpimcfg = 1, use_efisystab = 1, use_bsd = 1, use_x86bios = 1;
784   const char *acpimcfg = pci_get_param(a, "ecam.acpimcfg");
785   const char *efisystab = pci_get_param(a, "ecam.efisystab");
786 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
787   const char *bsd = pci_get_param(a, "ecam.bsd");
788 #endif
789 #if defined(__amd64__) || defined(__i386__)
790   const char *x86bios = pci_get_param(a, "ecam.x86bios");
791 #endif
792   const char *addrs = pci_get_param(a, "ecam.addrs");
793   struct ecam_access *eacc;
794   glob_t mcfg_glob;
795   int ret;
796
797   if (!*addrs)
798     {
799       a->debug("ecam.addrs was not specified...");
800       use_addrs = 0;
801     }
802
803   if (acpimcfg[0])
804     {
805       ret = glob(acpimcfg, GLOB_NOCHECK, NULL, &mcfg_glob);
806       if (ret == 0)
807         {
808           if (access(mcfg_glob.gl_pathv[0], R_OK))
809             {
810               a->debug("cannot access acpimcfg: %s: %s...", mcfg_glob.gl_pathv[0], strerror(errno));
811               use_acpimcfg = 0;
812             }
813           globfree(&mcfg_glob);
814         }
815       else
816         {
817           a->debug("glob(%s) failed: %d...", acpimcfg, ret);
818           use_acpimcfg = 0;
819         }
820     }
821   else
822     use_acpimcfg = 0;
823
824   if (!efisystab[0] || access(efisystab, R_OK))
825     {
826       if (efisystab[0])
827         a->debug("cannot access efisystab: %s: %s...", efisystab, strerror(errno));
828       use_efisystab = 0;
829     }
830
831 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
832   if (strcmp(bsd, "0") == 0)
833     {
834       a->debug("not using BSD kenv/sysctl...");
835       use_bsd = 0;
836     }
837 #else
838   use_bsd = 0;
839 #endif
840
841 #if defined(__amd64__) || defined(__i386__)
842   if (strcmp(x86bios, "0") == 0)
843     {
844       a->debug("not using x86 BIOS...");
845       use_x86bios = 0;
846     }
847 #else
848   use_x86bios = 0;
849 #endif
850
851   if (!use_addrs && !use_acpimcfg && !use_efisystab && !use_bsd && !use_x86bios)
852     {
853       a->debug("no ecam source provided");
854       return 0;
855     }
856
857   if (!validate_addrs(addrs))
858     {
859       a->debug("ecam.addrs has invalid format %s", addrs);
860       return 0;
861     }
862
863   if (physmem_access(a, 0))
864     {
865       a->debug("cannot access physical memory: %s", strerror(errno));
866       return 0;
867     }
868
869   if (!use_addrs)
870     {
871       eacc = pci_malloc(a, sizeof(*eacc));
872
873       eacc->physmem = physmem_open(a, a->writeable);
874       if (!eacc->physmem)
875         {
876           a->debug("cannot open physcal memory: %s.", strerror(errno));
877           pci_mfree(eacc);
878           return 0;
879         }
880
881       eacc->pagesize = physmem_get_pagesize(eacc->physmem);
882       if (eacc->pagesize <= 0)
883         {
884           a->debug("Cannot get page size: %s.", strerror(errno));
885           physmem_close(eacc->physmem);
886           pci_mfree(eacc);
887           return 0;
888         }
889
890       eacc->mcfg = NULL;
891       eacc->cache = NULL;
892       a->backend_data = eacc;
893       eacc->mcfg = find_mcfg(a, acpimcfg, efisystab, use_bsd, use_x86bios);
894       if (!eacc->mcfg)
895         {
896           physmem_close(eacc->physmem);
897           pci_mfree(eacc);
898           a->backend_data = NULL;
899           return 0;
900         }
901       pci_mfree(eacc->mcfg);
902       physmem_close(eacc->physmem);
903       pci_mfree(eacc);
904       a->backend_data = NULL;
905     }
906
907   if (use_addrs)
908     a->debug("using with ecam addresses %s", addrs);
909   else
910     a->debug("using with%s%s%s%s%s%s", use_acpimcfg ? " acpimcfg=" : "", use_acpimcfg ? acpimcfg : "", use_efisystab ? " efisystab=" : "", use_efisystab ? efisystab : "", use_bsd ? " bsd" : "", use_x86bios ? " x86bios" : "");
911
912   return 1;
913 }
914
915 static void
916 ecam_init(struct pci_access *a)
917 {
918   const char *acpimcfg = pci_get_param(a, "ecam.acpimcfg");
919   const char *efisystab = pci_get_param(a, "ecam.efisystab");
920 #if defined (__FreeBSD__) || defined (__DragonFly__) || defined(__NetBSD__)
921   const char *bsd = pci_get_param(a, "ecam.bsd");
922 #endif
923 #if defined(__amd64__) || defined(__i386__)
924   const char *x86bios = pci_get_param(a, "ecam.x86bios");
925 #endif
926   const char *addrs = pci_get_param(a, "ecam.addrs");
927   struct physmem *physmem = NULL;
928   struct ecam_access *eacc = NULL;
929   long pagesize = 0;
930   int use_bsd = 0;
931   int use_x86bios = 0;
932   int test_domain = 0;
933   u8 test_bus = 0;
934   volatile void *test_reg;
935
936   if (!validate_addrs(addrs))
937     a->error("Option ecam.addrs has invalid address format \"%s\".", addrs);
938
939   physmem = physmem_open(a, a->writeable);
940   if (!physmem)
941     a->error("Cannot open physcal memory: %s.", strerror(errno));
942
943   pagesize = physmem_get_pagesize(physmem);
944   if (pagesize <= 0)
945     a->error("Cannot get page size: %s.", strerror(errno));
946
947   eacc = pci_malloc(a, sizeof(*eacc));
948   eacc->mcfg = NULL;
949   eacc->cache = NULL;
950   eacc->physmem = physmem;
951   eacc->pagesize = pagesize;
952   a->backend_data = eacc;
953
954   if (!*addrs)
955     {
956 #if defined (__FreeBSD__) || defined (__DragonFly__)
957       if (strcmp(bsd, "0") != 0)
958         use_bsd = 1;
959 #endif
960 #if defined(__amd64__) || defined(__i386__)
961       if (strcmp(x86bios, "0") != 0)
962         use_x86bios = 1;
963 #endif
964       eacc->mcfg = find_mcfg(a, acpimcfg, efisystab, use_bsd, use_x86bios);
965       if (!eacc->mcfg)
966         a->error("Option ecam.addrs was not specified and ACPI MCFG table cannot be found.");
967     }
968
969   if (eacc->mcfg)
970     get_mcfg_allocation(eacc->mcfg, 0, &test_domain, &test_bus, NULL, NULL, NULL);
971   else
972     parse_next_addrs(addrs, NULL, &test_domain, &test_bus, NULL, NULL, NULL);
973
974   errno = 0;
975   if (!mmap_reg(a, 0, test_domain, test_bus, 0, 0, 0, &test_reg))
976     a->error("Cannot map ecam region: %s.", errno ? strerror(errno) : "Unknown error");
977 }
978
979 static void
980 ecam_cleanup(struct pci_access *a)
981 {
982   struct ecam_access *eacc = a->backend_data;
983
984   munmap_reg(a);
985   physmem_close(eacc->physmem);
986   pci_mfree(eacc->mcfg);
987   pci_mfree(eacc);
988   a->backend_data = NULL;
989 }
990
991 static void
992 ecam_scan(struct pci_access *a)
993 {
994   const char *addrs = pci_get_param(a, "ecam.addrs");
995   struct ecam_access *eacc = a->backend_data;
996   u32 *segments;
997   int i, j, count;
998   int domain;
999
1000   segments = pci_malloc(a, 0xFFFF/8);
1001   memset(segments, 0, 0xFFFF/8);
1002
1003   if (eacc->mcfg)
1004     {
1005       count = get_mcfg_allocations_count(eacc->mcfg);
1006       for (i = 0; i < count; i++)
1007         segments[eacc->mcfg->allocations[i].pci_segment / 32] |= 1 << (eacc->mcfg->allocations[i].pci_segment % 32);
1008     }
1009   else
1010     {
1011       while (addrs)
1012         {
1013           if (parse_next_addrs(addrs, &addrs, &domain, NULL, NULL, NULL, NULL))
1014             segments[domain / 32] |= 1 << (domain % 32);
1015         }
1016     }
1017
1018   for (i = 0; i < 0xFFFF/32; i++)
1019     {
1020       if (!segments[i])
1021         continue;
1022       for (j = 0; j < 32; j++)
1023         if (segments[i] & (1 << j))
1024           pci_generic_scan_domain(a, 32*i + j);
1025     }
1026
1027   pci_mfree(segments);
1028 }
1029
1030 static int
1031 ecam_read(struct pci_dev *d, int pos, byte *buf, int len)
1032 {
1033   volatile void *reg;
1034
1035   if (pos >= 4096)
1036     return 0;
1037
1038   if (len != 1 && len != 2 && len != 4)
1039     return pci_generic_block_read(d, pos, buf, len);
1040
1041   if (!mmap_reg(d->access, 0, d->domain, d->bus, d->dev, d->func, pos, &reg))
1042     return 0;
1043
1044   switch (len)
1045     {
1046     case 1:
1047       buf[0] = physmem_readb(reg);
1048       break;
1049     case 2:
1050       ((u16 *) buf)[0] = physmem_readw(reg);
1051       break;
1052     case 4:
1053       ((u32 *) buf)[0] = physmem_readl(reg);
1054       break;
1055     }
1056
1057   return 1;
1058 }
1059
1060 static int
1061 ecam_write(struct pci_dev *d, int pos, byte *buf, int len)
1062 {
1063   volatile void *reg;
1064
1065   if (pos >= 4096)
1066     return 0;
1067
1068   if (len != 1 && len != 2 && len != 4)
1069     return pci_generic_block_read(d, pos, buf, len);
1070
1071   if (!mmap_reg(d->access, 1, d->domain, d->bus, d->dev, d->func, pos, &reg))
1072     return 0;
1073
1074   switch (len)
1075     {
1076     case 1:
1077       physmem_writeb(buf[0], reg);
1078       break;
1079     case 2:
1080       physmem_writew(((u16 *) buf)[0], reg);
1081       break;
1082     case 4:
1083       physmem_writel(((u32 *) buf)[0], reg);
1084       break;
1085     }
1086
1087   return 1;
1088 }
1089
1090 struct pci_methods pm_ecam = {
1091   "ecam",
1092   "Raw memory mapped access using PCIe ECAM interface",
1093   ecam_config,
1094   ecam_detect,
1095   ecam_init,
1096   ecam_cleanup,
1097   ecam_scan,
1098   pci_generic_fill_info,
1099   ecam_read,
1100   ecam_write,
1101   NULL,                                 /* read_vpd */
1102   NULL,                                 /* init_dev */
1103   NULL                                  /* cleanup_dev */
1104 };