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