blob: ff01770868d58ea4d829d70e903f1cd4f0f9109a [file] [log] [blame]
Jacob Garber07201d72020-09-08 12:25:44 -06001/* SPDX-License-Identifier: GPL-2.0-only */
Jordan Crouse7249f792008-03-20 00:11:05 +00002
3#include <arch/io.h>
Stefan Reinauer28dff392008-08-13 08:23:06 +00004#include <pci.h>
Uwe Hermann754edf72008-08-04 21:02:07 +00005#include <libpayload.h>
Jordan Crouse7249f792008-03-20 00:11:05 +00006#include "coreinfo.h"
7
Julius Wernereab2a292019-03-05 16:55:15 -08008#if CONFIG(MODULE_PCI)
Uwe Hermannab5b3e02008-03-31 20:30:18 +00009
Jordan Crouse7249f792008-03-20 00:11:05 +000010struct pci_devices {
Stefan Reinauer28dff392008-08-13 08:23:06 +000011 pcidev_t device;
Jordan Crouse7249f792008-03-20 00:11:05 +000012 unsigned int id;
13};
14
Stefan Reinauer10d0a812008-09-05 15:18:15 +000015#define MAX_PCI_DEVICES 64
16static struct pci_devices devices[MAX_PCI_DEVICES];
Jordan Crouse7249f792008-03-20 00:11:05 +000017static int devices_index;
18
Jordan Crouse7249f792008-03-20 00:11:05 +000019/* Number of entries to show in the list */
20#define MENU_VISIBLE 16
21
22static int menu_selected = 0;
23static int menu_first = 0;
24
25static void swap(struct pci_devices *a, struct pci_devices *b)
26{
27 struct pci_devices tmp;
28
29 tmp.device = a->device;
30 tmp.id = a->id;
31
32 a->device = b->device;
33 a->id = b->id;
34
35 b->device = tmp.device;
36 b->id = tmp.id;
37}
38
39static int partition(struct pci_devices *list, int len)
40{
Jacob Garbera711e9c2019-06-28 10:58:56 -060041 pcidev_t val = list[len / 2].device;
Jordan Crouse7249f792008-03-20 00:11:05 +000042 int index = 0;
43 int i;
44
45 swap(&list[len / 2], &list[len - 1]);
46
Uwe Hermann3a406fe2008-03-20 01:11:28 +000047 for (i = 0; i < len - 1; i++) {
Jordan Crouse7249f792008-03-20 00:11:05 +000048 if (list[i].device < val) {
49 swap(&list[i], &list[index]);
50 index++;
51 }
52 }
53
54 swap(&list[index], &list[len - 1]);
Uwe Hermann3a406fe2008-03-20 01:11:28 +000055
Jordan Crouse7249f792008-03-20 00:11:05 +000056 return index;
57}
58
59static void quicksort(struct pci_devices *list, int len)
60{
61 int index;
62
63 if (len <= 1)
64 return;
65
66 index = partition(list, len);
67
68 quicksort(list, index);
69 quicksort(&(list[index]), len - index);
70}
71
Uwe Hermann35845a22008-03-20 20:05:22 +000072static void show_config_space(WINDOW *win, int row, int col, int index)
Jordan Crouse7249f792008-03-20 00:11:05 +000073{
Stefan Reinauer28dff392008-08-13 08:23:06 +000074 unsigned char cspace[256];
75 pcidev_t dev;
Jordan Crouse7249f792008-03-20 00:11:05 +000076 int i, x, y;
77
Stefan Reinauer28dff392008-08-13 08:23:06 +000078 dev = devices[index].device;
Jordan Crouse7249f792008-03-20 00:11:05 +000079
Stefan Reinauer28dff392008-08-13 08:23:06 +000080 for (i = 0; i < 256; i ++)
81 cspace[i] = pci_read_config8(dev, i);
Jordan Crouse7249f792008-03-20 00:11:05 +000082
Stefan Reinauer28dff392008-08-13 08:23:06 +000083 for (y = 0; y < 16; y++) {
Uwe Hermann3a406fe2008-03-20 01:11:28 +000084 for (x = 0; x < 16; x++)
85 mvwprintw(win, row + y, col + (x * 3), "%2.2X ",
86 cspace[(y * 16) + x]);
Jordan Crouse7249f792008-03-20 00:11:05 +000087 }
88}
89
Uwe Hermann0bfb5c42008-03-23 15:34:04 +000090static int pci_module_redraw(WINDOW *win)
Jordan Crouse7249f792008-03-20 00:11:05 +000091{
Stefan Reinauer28dff392008-08-13 08:23:06 +000092 unsigned int bus, slot, func;
Jacob Garberdce10f82019-04-06 16:10:36 -060093 int i;
Jordan Crouse7249f792008-03-20 00:11:05 +000094
95 print_module_title(win, "PCI Device List");
96
Uwe Hermann3a406fe2008-03-20 01:11:28 +000097 for (i = 0; i < MENU_VISIBLE; i++) {
Jordan Crouse7249f792008-03-20 00:11:05 +000098 int item = menu_first + i;
99
Uwe Hermann3a406fe2008-03-20 01:11:28 +0000100 /* Draw a blank space. */
Jordan Crouse7249f792008-03-20 00:11:05 +0000101 if (item >= devices_index) {
102 wattrset(win, COLOR_PAIR(2));
103 mvwprintw(win, 2 + i, 1, " ");
104 continue;
105 }
106
Stefan Reinauer28dff392008-08-13 08:23:06 +0000107 bus = PCI_BUS(devices[item].device);
108 slot = PCI_SLOT(devices[item].device);
109 func = PCI_FUNC(devices[item].device);
Jordan Crouse7249f792008-03-20 00:11:05 +0000110
111 if (item == menu_selected)
112 wattrset(win, COLOR_PAIR(3) | A_BOLD);
113 else
114 wattrset(win, COLOR_PAIR(2));
115
Uwe Hermanna0c00932008-03-27 20:46:49 +0000116 mvwprintw(win, 2 + i, 1, "%X:%2.2X.%2.2X %04X:%04X ",
Stefan Reinauer28dff392008-08-13 08:23:06 +0000117 bus, slot, func,
Uwe Hermann3a406fe2008-03-20 01:11:28 +0000118 devices[item].id & 0xffff,
119 (devices[item].id >> 16) & 0xffff);
Jordan Crouse7249f792008-03-20 00:11:05 +0000120
121 wattrset(win, COLOR_PAIR(2));
122
123 if (i == 0) {
124 if (item != 0)
Ulf Jordand133d9a2008-08-11 20:35:32 +0000125 mvwaddch(win, 2 + i, 19, ACS_UARROW);
Jordan Crouse7249f792008-03-20 00:11:05 +0000126 }
127 if (i == MENU_VISIBLE - 1) {
128 if ((item + 1) < devices_index)
Ulf Jordand133d9a2008-08-11 20:35:32 +0000129 mvwaddch(win, 2 + i, 19, ACS_DARROW);
Jordan Crouse7249f792008-03-20 00:11:05 +0000130 }
131 }
132
133 wattrset(win, COLOR_PAIR(2));
134
Uwe Hermann3a406fe2008-03-20 01:11:28 +0000135 for (i = 0; i < 16; i++)
Jordan Crouse7249f792008-03-20 00:11:05 +0000136 mvwprintw(win, 2, 26 + (i * 3), "%2.2X ", i);
137
138 wmove(win, 3, 25);
139
Uwe Hermann3a406fe2008-03-20 01:11:28 +0000140 for (i = 0; i < 48; i++)
Ulf Jordand133d9a2008-08-11 20:35:32 +0000141 waddch(win, (i == 0) ? ACS_ULCORNER : ACS_HLINE);
Jordan Crouse7249f792008-03-20 00:11:05 +0000142
Stefan Reinauer28dff392008-08-13 08:23:06 +0000143 for (i = 0; i < 16; i++) {
Jordan Crouse7249f792008-03-20 00:11:05 +0000144 mvwprintw(win, 4 + i, 23, "%2.2X", i * 16);
145 wmove(win, 4 + i, 25);
Ulf Jordand133d9a2008-08-11 20:35:32 +0000146 waddch(win, ACS_VLINE);
Jordan Crouse7249f792008-03-20 00:11:05 +0000147 }
148
149 show_config_space(win, 4, 26, menu_selected);
150
151 return 0;
152}
153
Felix Singer6034b0f2020-10-19 17:42:59 +0200154static void ci_pci_scan_bus(int bus)
Jordan Crouse7249f792008-03-20 00:11:05 +0000155{
Stefan Reinauer28dff392008-08-13 08:23:06 +0000156 int slot, func;
Jordan Crouse7249f792008-03-20 00:11:05 +0000157 unsigned int val;
158 unsigned char hdr;
159
Stefan Reinauerbc5379a2008-08-13 09:38:12 +0000160 for (slot = 0; slot < 0x20; slot++) {
Stefan Reinauer28dff392008-08-13 08:23:06 +0000161 for (func = 0; func < 8; func++) {
162 pcidev_t dev = PCI_DEV(bus, slot, func);
Stefan Reinauer88ad6b02008-08-07 19:09:17 +0000163
164 val = pci_read_config32(dev, REG_VENDOR_ID);
Jordan Crouse7249f792008-03-20 00:11:05 +0000165
Uwe Hermann3a406fe2008-03-20 01:11:28 +0000166 /* Nobody home. */
Jordan Crouse7249f792008-03-20 00:11:05 +0000167 if (val == 0xffffffff || val == 0x00000000 ||
Kyösti Mälkki1dc5ce32018-06-09 08:25:03 +0300168 val == 0x0000ffff || val == 0xffff0000) {
169
170 /* If function 0 is not present, no need
171 * to test other functions. */
172 if (func == 0)
173 func = 8;
Jordan Crouse7249f792008-03-20 00:11:05 +0000174 continue;
Kyösti Mälkki1dc5ce32018-06-09 08:25:03 +0300175 }
Jordan Crouse7249f792008-03-20 00:11:05 +0000176
Uwe Hermann3a406fe2008-03-20 01:11:28 +0000177 /* FIXME: Remove this arbitrary limitation. */
Stefan Reinauer10d0a812008-09-05 15:18:15 +0000178 if (devices_index >= MAX_PCI_DEVICES)
Jordan Crouse7249f792008-03-20 00:11:05 +0000179 return;
180
Stefan Reinauer14e22772010-04-27 06:56:47 +0000181 devices[devices_index].device =
Stefan Reinauer28dff392008-08-13 08:23:06 +0000182 PCI_DEV(bus, slot, func);
Jordan Crouse7249f792008-03-20 00:11:05 +0000183
184 devices[devices_index++].id = val;
185
Uwe Hermann3a406fe2008-03-20 01:11:28 +0000186 /* If this is a bridge, then follow it. */
Stefan Reinauer88ad6b02008-08-07 19:09:17 +0000187 hdr = pci_read_config8(dev, REG_HEADER_TYPE);
Kyösti Mälkki1dc5ce32018-06-09 08:25:03 +0300188
189 if ((func == 0) && !(hdr & HEADER_TYPE_MULTIFUNCTION))
190 func = 8;
191
192 hdr &= ~HEADER_TYPE_MULTIFUNCTION;
Jordan Crouse7249f792008-03-20 00:11:05 +0000193 if (hdr == HEADER_TYPE_BRIDGE ||
194 hdr == HEADER_TYPE_CARDBUS) {
195 unsigned int busses;
196
Stefan Reinauer88ad6b02008-08-07 19:09:17 +0000197 busses = pci_read_config32(dev, REG_PRIMARY_BUS);
Jordan Crouse7249f792008-03-20 00:11:05 +0000198
Felix Singer6034b0f2020-10-19 17:42:59 +0200199 ci_pci_scan_bus((busses >> 8) & 0xff);
Jordan Crouse7249f792008-03-20 00:11:05 +0000200
201 }
202 }
203 }
204
205 quicksort(devices, devices_index);
206}
207
Uwe Hermann0bfb5c42008-03-23 15:34:04 +0000208static int pci_module_handle(int key)
Jordan Crouse7249f792008-03-20 00:11:05 +0000209{
210 int ret = 0;
211
Uwe Hermann3a406fe2008-03-20 01:11:28 +0000212 switch (key) {
Jordan Crouse7249f792008-03-20 00:11:05 +0000213 case KEY_DOWN:
214 if (menu_selected + 1 < devices_index) {
215 menu_selected++;
216 ret = 1;
217 }
Jordan Crouse7249f792008-03-20 00:11:05 +0000218 break;
Jordan Crouse7249f792008-03-20 00:11:05 +0000219 case KEY_UP:
220 if (menu_selected > 0) {
221 menu_selected--;
222 ret = 1;
223 }
Jordan Crouse7249f792008-03-20 00:11:05 +0000224 break;
225 }
226
227 if (!ret)
228 return ret;
229
230 if (menu_selected < menu_first)
231 menu_first = menu_selected;
232 else if (menu_selected >= menu_first + MENU_VISIBLE) {
233 menu_first = menu_selected - (MENU_VISIBLE - 1);
234 if (menu_first < 0)
235 menu_first = 0;
236 }
237
Jordan Crouse7249f792008-03-20 00:11:05 +0000238 return ret;
239}
240
Uwe Hermann0bfb5c42008-03-23 15:34:04 +0000241static int pci_module_init(void)
Jordan Crouse7249f792008-03-20 00:11:05 +0000242{
Felix Singer6034b0f2020-10-19 17:42:59 +0200243 ci_pci_scan_bus(0);
Jordan Crouse7249f792008-03-20 00:11:05 +0000244 return 0;
245}
246
247struct coreinfo_module pci_module = {
248 .name = "PCI",
249 .init = pci_module_init,
250 .redraw = pci_module_redraw,
251 .handle = pci_module_handle,
252};
Uwe Hermannab5b3e02008-03-31 20:30:18 +0000253
254#else
255
256struct coreinfo_module pci_module = {
257};
258
259#endif