xref: /aosp_15_r20/external/pciutils/ls-map.c (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1 /*
2  *	The PCI Utilities -- Bus Mapping Mode
3  *
4  *	Copyright (c) 1997--2008 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 <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 
15 #include "lspci.h"
16 
17 struct bus_bridge {
18   struct bus_bridge *next;
19   byte this, dev, func, first, last, bug;
20 };
21 
22 struct bus_info {
23   byte exists;
24   byte guestbook;
25   struct bus_bridge *bridges, *via;
26 };
27 
28 static struct bus_info *bus_info;
29 
30 static void
map_bridge(struct bus_info * bi,struct device * d,int np,int ns,int nl)31 map_bridge(struct bus_info *bi, struct device *d, int np, int ns, int nl)
32 {
33   struct bus_bridge *b = xmalloc(sizeof(struct bus_bridge));
34   struct pci_dev *p = d->dev;
35 
36   b->next = bi->bridges;
37   bi->bridges = b;
38   b->this = get_conf_byte(d, np);
39   b->dev = p->dev;
40   b->func = p->func;
41   b->first = get_conf_byte(d, ns);
42   b->last = get_conf_byte(d, nl);
43   printf("## %02x:%02x.%d is a bridge from %02x to %02x-%02x\n",
44 	 p->bus, p->dev, p->func, b->this, b->first, b->last);
45   if (b->this != p->bus)
46     printf("!!! Bridge points to invalid primary bus.\n");
47   if (b->first > b->last)
48     {
49       printf("!!! Bridge points to invalid bus range.\n");
50       b->last = b->first;
51     }
52 }
53 
54 static void
do_map_bus(int bus)55 do_map_bus(int bus)
56 {
57   int domain = (filter.domain >= 0 ? filter.domain : 0);
58   int dev, func;
59   int verbose = pacc->debugging;
60   struct bus_info *bi = bus_info + bus;
61   struct device *d;
62 
63   if (verbose)
64     printf("Mapping bus %04x:%02x\n", domain, bus);
65   for (dev = 0; dev < 32; dev++)
66     if (filter.slot < 0 || filter.slot == dev)
67       {
68 	int func_limit = 1;
69 	for (func = 0; func < func_limit; func++)
70 	  if (filter.func < 0 || filter.func == func)
71 	    {
72 	      struct pci_dev *p = pci_get_dev(pacc, domain, bus, dev, func);
73 	      u16 vendor = pci_read_word(p, PCI_VENDOR_ID);
74 	      if (vendor && vendor != 0xffff)
75 		{
76 		  if (!func && (pci_read_byte(p, PCI_HEADER_TYPE) & 0x80))
77 		    func_limit = 8;
78 		  if (verbose)
79 		    printf("Discovered device %04x:%02x:%02x.%d\n", domain, bus, dev, func);
80 		  bi->exists = 1;
81 		  if (d = scan_device(p))
82 		    {
83 		      show_device(d);
84 		      switch (get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f)
85 			{
86 			case PCI_HEADER_TYPE_BRIDGE:
87 			  map_bridge(bi, d, PCI_PRIMARY_BUS, PCI_SECONDARY_BUS, PCI_SUBORDINATE_BUS);
88 			  break;
89 			case PCI_HEADER_TYPE_CARDBUS:
90 			  map_bridge(bi, d, PCI_CB_PRIMARY_BUS, PCI_CB_CARD_BUS, PCI_CB_SUBORDINATE_BUS);
91 			  break;
92 			}
93 		      free(d);
94 		    }
95 		  else if (verbose)
96 		    printf("But it was filtered out.\n");
97 		}
98 	      pci_free_dev(p);
99 	    }
100       }
101 }
102 
103 static void
do_map_bridges(int bus,int min,int max)104 do_map_bridges(int bus, int min, int max)
105 {
106   struct bus_info *bi = bus_info + bus;
107   struct bus_bridge *b;
108 
109   bi->guestbook = 1;
110   for (b=bi->bridges; b; b=b->next)
111     {
112       if (bus_info[b->first].guestbook)
113 	b->bug = 1;
114       else if (b->first < min || b->last > max)
115 	b->bug = 2;
116       else
117 	{
118 	  bus_info[b->first].via = b;
119 	  do_map_bridges(b->first, b->first, b->last);
120 	}
121     }
122 }
123 
124 static void
map_bridges(void)125 map_bridges(void)
126 {
127   int i;
128 
129   printf("\nSummary of buses:\n\n");
130   for (i=0; i<256; i++)
131     if (bus_info[i].exists && !bus_info[i].guestbook)
132       do_map_bridges(i, 0, 255);
133   for (i=0; i<256; i++)
134     {
135       struct bus_info *bi = bus_info + i;
136       struct bus_bridge *b = bi->via;
137 
138       if (bi->exists)
139 	{
140 	  printf("%02x: ", i);
141 	  if (b)
142 	    printf("Entered via %02x:%02x.%d\n", b->this, b->dev, b->func);
143 	  else if (!i)
144 	    printf("Primary host bus\n");
145 	  else
146 	    printf("Secondary host bus (?)\n");
147 	}
148       for (b=bi->bridges; b; b=b->next)
149 	{
150 	  printf("\t%02x.%d Bridge to %02x-%02x", b->dev, b->func, b->first, b->last);
151 	  switch (b->bug)
152 	    {
153 	    case 1:
154 	      printf(" <overlap bug>");
155 	      break;
156 	    case 2:
157 	      printf(" <crossing bug>");
158 	      break;
159 	    }
160 	  putchar('\n');
161 	}
162     }
163 }
164 
165 void
map_the_bus(void)166 map_the_bus(void)
167 {
168   if (pacc->method == PCI_ACCESS_PROC_BUS_PCI ||
169       pacc->method == PCI_ACCESS_SYS_BUS_PCI ||
170       pacc->method == PCI_ACCESS_WIN32_CFGMGR32 ||
171       pacc->method == PCI_ACCESS_DUMP)
172     printf("WARNING: Bus mapping can be reliable only with direct hardware access enabled.\n\n");
173   bus_info = xmalloc(sizeof(struct bus_info) * 256);
174   memset(bus_info, 0, sizeof(struct bus_info) * 256);
175   if (filter.bus >= 0)
176     do_map_bus(filter.bus);
177   else
178     {
179       int bus;
180       for (bus=0; bus<256; bus++)
181 	do_map_bus(bus);
182     }
183   map_bridges();
184 }
185