]> mj.ucw.cz Git - pciutils.git/blob - lib/generic.c
libpci: ecam: Fix big address range mappings
[pciutils.git] / lib / generic.c
1 /*
2  *      The PCI Library -- Generic Direct Access Functions
3  *
4  *      Copyright (c) 1997--2022 Martin Mares <mj@ucw.cz>
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 <string.h>
12
13 #include "internal.h"
14
15 void
16 pci_generic_scan_bus(struct pci_access *a, byte *busmap, int domain, int bus)
17 {
18   int dev, multi, ht;
19   struct pci_dev *t;
20
21   a->debug("Scanning bus %02x for devices...\n", bus);
22   if (busmap[bus])
23     {
24       a->warning("Bus %02x seen twice (firmware bug). Ignored.", bus);
25       return;
26     }
27   busmap[bus] = 1;
28   t = pci_alloc_dev(a);
29   t->domain = domain;
30   t->bus = bus;
31   for (dev=0; dev<32; dev++)
32     {
33       t->dev = dev;
34       multi = 0;
35       for (t->func=0; !t->func || multi && t->func<8; t->func++)
36         {
37           u32 vd = pci_read_long(t, PCI_VENDOR_ID);
38           struct pci_dev *d;
39
40           if (!vd || vd == 0xffffffff)
41             continue;
42           ht = pci_read_byte(t, PCI_HEADER_TYPE);
43           if (!t->func)
44             multi = ht & 0x80;
45           ht &= 0x7f;
46           d = pci_alloc_dev(a);
47           d->domain = t->domain;
48           d->bus = t->bus;
49           d->dev = t->dev;
50           d->func = t->func;
51           d->vendor_id = vd & 0xffff;
52           d->device_id = vd >> 16U;
53           d->known_fields = PCI_FILL_IDENT;
54           d->hdrtype = ht;
55           pci_link_dev(a, d);
56           switch (ht)
57             {
58             case PCI_HEADER_TYPE_NORMAL:
59               break;
60             case PCI_HEADER_TYPE_BRIDGE:
61             case PCI_HEADER_TYPE_CARDBUS:
62               pci_generic_scan_bus(a, busmap, domain, pci_read_byte(t, PCI_SECONDARY_BUS));
63               break;
64             default:
65               a->debug("Device %04x:%02x:%02x.%d has unknown header type %02x.\n", d->domain, d->bus, d->dev, d->func, ht);
66             }
67         }
68     }
69   pci_free_dev(t);
70 }
71
72 void
73 pci_generic_scan_domain(struct pci_access *a, int domain)
74 {
75   byte busmap[256];
76
77   memset(busmap, 0, sizeof(busmap));
78   pci_generic_scan_bus(a, busmap, domain, 0);
79 }
80
81 void
82 pci_generic_scan(struct pci_access *a)
83 {
84   pci_generic_scan_domain(a, 0);
85 }
86
87 static int
88 get_hdr_type(struct pci_dev *d)
89 {
90   if (d->hdrtype < 0)
91     d->hdrtype = pci_read_byte(d, PCI_HEADER_TYPE) & 0x7f;
92   return d->hdrtype;
93 }
94
95 void
96 pci_generic_fill_info(struct pci_dev *d, unsigned int flags)
97 {
98   struct pci_access *a = d->access;
99   struct pci_cap *cap;
100
101   if (want_fill(d, flags, PCI_FILL_IDENT))
102     {
103       d->vendor_id = pci_read_word(d, PCI_VENDOR_ID);
104       d->device_id = pci_read_word(d, PCI_DEVICE_ID);
105     }
106
107   if (want_fill(d, flags, PCI_FILL_CLASS))
108     d->device_class = pci_read_word(d, PCI_CLASS_DEVICE);
109
110   if (want_fill(d, flags, PCI_FILL_CLASS_EXT))
111     {
112       d->prog_if = pci_read_byte(d, PCI_CLASS_PROG);
113       d->rev_id = pci_read_byte(d, PCI_REVISION_ID);
114     }
115
116   if (want_fill(d, flags, PCI_FILL_SUBSYS))
117     {
118       switch (get_hdr_type(d))
119         {
120         case PCI_HEADER_TYPE_NORMAL:
121           d->subsys_vendor_id = pci_read_word(d, PCI_SUBSYSTEM_VENDOR_ID);
122           d->subsys_id = pci_read_word(d, PCI_SUBSYSTEM_ID);
123           break;
124         case PCI_HEADER_TYPE_BRIDGE:
125           cap = pci_find_cap(d, PCI_CAP_ID_SSVID, PCI_CAP_NORMAL);
126           if (cap)
127             {
128               d->subsys_vendor_id = pci_read_word(d, cap->addr + PCI_SSVID_VENDOR);
129               d->subsys_id = pci_read_word(d, cap->addr + PCI_SSVID_DEVICE);
130             }
131           break;
132         case PCI_HEADER_TYPE_CARDBUS:
133           d->subsys_vendor_id = pci_read_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID);
134           d->subsys_id = pci_read_word(d, PCI_CB_SUBSYSTEM_ID);
135           break;
136         default:
137           clear_fill(d, PCI_FILL_SUBSYS);
138         }
139     }
140
141   if (want_fill(d, flags, PCI_FILL_IRQ))
142     d->irq = pci_read_byte(d, PCI_INTERRUPT_LINE);
143
144   if (want_fill(d, flags, PCI_FILL_BASES))
145     {
146       int cnt = 0, i;
147       memset(d->base_addr, 0, sizeof(d->base_addr));
148       switch (get_hdr_type(d))
149         {
150         case PCI_HEADER_TYPE_NORMAL:
151           cnt = 6;
152           break;
153         case PCI_HEADER_TYPE_BRIDGE:
154           cnt = 2;
155           break;
156         case PCI_HEADER_TYPE_CARDBUS:
157           cnt = 1;
158           break;
159         }
160       if (cnt)
161         {
162           for (i=0; i<cnt; i++)
163             {
164               u32 x = pci_read_long(d, PCI_BASE_ADDRESS_0 + i*4);
165               if (!x || x == (u32) ~0)
166                 continue;
167               if ((x & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
168                 d->base_addr[i] = x;
169               else
170                 {
171                   if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) != PCI_BASE_ADDRESS_MEM_TYPE_64)
172                     d->base_addr[i] = x;
173                   else if (i >= cnt-1)
174                     a->warning("%04x:%02x:%02x.%d: Invalid 64-bit address seen for BAR %d.", d->domain, d->bus, d->dev, d->func, i);
175                   else
176                     {
177                       u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i)*4);
178 #ifdef PCI_HAVE_64BIT_ADDRESS
179                       d->base_addr[i-1] = x | (((pciaddr_t) y) << 32);
180 #else
181                       if (y)
182                         a->warning("%04x:%02x:%02x.%d 64-bit device address ignored.", d->domain, d->bus, d->dev, d->func);
183                       else
184                         d->base_addr[i-1] = x;
185 #endif
186                     }
187                 }
188             }
189         }
190     }
191
192   if (want_fill(d, flags, PCI_FILL_ROM_BASE))
193     {
194       int reg = 0;
195       d->rom_base_addr = 0;
196       switch (get_hdr_type(d))
197         {
198         case PCI_HEADER_TYPE_NORMAL:
199           reg = PCI_ROM_ADDRESS;
200           break;
201         case PCI_HEADER_TYPE_BRIDGE:
202           reg = PCI_ROM_ADDRESS1;
203           break;
204         }
205       if (reg)
206         {
207           u32 u = pci_read_long(d, reg);
208           if (u != 0xffffffff)
209             d->rom_base_addr = u;
210         }
211     }
212
213   pci_scan_caps(d, flags);
214 }
215
216 static int
217 pci_generic_block_op(struct pci_dev *d, int pos, byte *buf, int len,
218                  int (*r)(struct pci_dev *d, int pos, byte *buf, int len))
219 {
220   if ((pos & 1) && len >= 1)
221     {
222       if (!r(d, pos, buf, 1))
223         return 0;
224       pos++; buf++; len--;
225     }
226   if ((pos & 3) && len >= 2)
227     {
228       if (!r(d, pos, buf, 2))
229         return 0;
230       pos += 2; buf += 2; len -= 2;
231     }
232   while (len >= 4)
233     {
234       if (!r(d, pos, buf, 4))
235         return 0;
236       pos += 4; buf += 4; len -= 4;
237     }
238   if (len >= 2)
239     {
240       if (!r(d, pos, buf, 2))
241         return 0;
242       pos += 2; buf += 2; len -= 2;
243     }
244   if (len && !r(d, pos, buf, 1))
245     return 0;
246   return 1;
247 }
248
249 int
250 pci_generic_block_read(struct pci_dev *d, int pos, byte *buf, int len)
251 {
252   return pci_generic_block_op(d, pos, buf, len, d->access->methods->read);
253 }
254
255 int
256 pci_generic_block_write(struct pci_dev *d, int pos, byte *buf, int len)
257 {
258   return pci_generic_block_op(d, pos, buf, len, d->access->methods->write);
259 }