xref: /aosp_15_r20/external/pciutils/lib/generic.c (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1 /*
2  *	The PCI Library -- Generic Direct Access Functions
3  *
4  *	Copyright (c) 1997--2022 Martin Mares <[email protected]>
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
pci_generic_scan_bus(struct pci_access * a,byte * busmap,int domain,int bus)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
pci_generic_scan_domain(struct pci_access * a,int domain)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
pci_generic_scan(struct pci_access * a)82 pci_generic_scan(struct pci_access *a)
83 {
84   pci_generic_scan_domain(a, 0);
85 }
86 
87 static int
get_hdr_type(struct pci_dev * d)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
pci_generic_fill_info(struct pci_dev * d,unsigned int flags)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
pci_generic_block_op(struct pci_dev * d,int pos,byte * buf,int len,int (* r)(struct pci_dev * d,int pos,byte * buf,int len))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
pci_generic_block_read(struct pci_dev * d,int pos,byte * buf,int len)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
pci_generic_block_write(struct pci_dev * d,int pos,byte * buf,int len)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 }
260