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