pci_module.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include <arch/io.h> 4 #include <pci.h> 5 #include <libpayload.h> 6 #include "coreinfo.h" 7 8 #if CONFIG(MODULE_PCI) 9 10 struct pci_devices { 11 pcidev_t device; 12 unsigned int id; 13 }; 14 15 #define MAX_PCI_DEVICES 64 16 static struct pci_devices devices[MAX_PCI_DEVICES]; 17 static int devices_index; 18 19 /* Number of entries to show in the list */ 20 #define MENU_VISIBLE 16 21 22 static int menu_selected = 0; 23 static int menu_first = 0; 24 25 static 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 39 static int partition(struct pci_devices *list, int len) 40 { 41 pcidev_t val = list[len / 2].device; 42 int index = 0; 43 int i; 44 45 swap(&list[len / 2], &list[len - 1]); 46 47 for (i = 0; i < len - 1; i++) { 48 if (list[i].device < val) { 49 swap(&list[i], &list[index]); 50 index++; 51 } 52 } 53 54 swap(&list[index], &list[len - 1]); 55 56 return index; 57 } 58 59 static 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 72 static void show_config_space(WINDOW *win, int row, int col, int index) 73 { 74 unsigned char cspace[256]; 75 pcidev_t dev; 76 int i, x, y; 77 78 dev = devices[index].device; 79 80 for (i = 0; i < 256; i ++) 81 cspace[i] = pci_read_config8(dev, i); 82 83 for (y = 0; y < 16; y++) { 84 for (x = 0; x < 16; x++) 85 mvwprintw(win, row + y, col + (x * 3), "%2.2X ", 86 cspace[(y * 16) + x]); 87 } 88 } 89 90 static int pci_module_redraw(WINDOW *win) 91 { 92 unsigned int bus, slot, func; 93 int i; 94 95 print_module_title(win, "PCI Device List"); 96 97 for (i = 0; i < MENU_VISIBLE; i++) { 98 int item = menu_first + i; 99 100 /* Draw a blank space. */ 101 if (item >= devices_index) { 102 wattrset(win, COLOR_PAIR(2)); 103 mvwprintw(win, 2 + i, 1, " "); 104 continue; 105 } 106 107 bus = PCI_BUS(devices[item].device); 108 slot = PCI_SLOT(devices[item].device); 109 func = PCI_FUNC(devices[item].device); 110 111 if (item == menu_selected) 112 wattrset(win, COLOR_PAIR(3) | A_BOLD); 113 else 114 wattrset(win, COLOR_PAIR(2)); 115 116 mvwprintw(win, 2 + i, 1, "%X:%2.2X.%2.2X %04X:%04X ", 117 bus, slot, func, 118 devices[item].id & 0xffff, 119 (devices[item].id >> 16) & 0xffff); 120 121 wattrset(win, COLOR_PAIR(2)); 122 123 if (i == 0) { 124 if (item != 0) 125 mvwaddch(win, 2 + i, 19, ACS_UARROW); 126 } 127 if (i == MENU_VISIBLE - 1) { 128 if ((item + 1) < devices_index) 129 mvwaddch(win, 2 + i, 19, ACS_DARROW); 130 } 131 } 132 133 wattrset(win, COLOR_PAIR(2)); 134 135 for (i = 0; i < 16; i++) 136 mvwprintw(win, 2, 26 + (i * 3), "%2.2X ", i); 137 138 wmove(win, 3, 25); 139 140 for (i = 0; i < 48; i++) 141 waddch(win, (i == 0) ? ACS_ULCORNER : ACS_HLINE); 142 143 for (i = 0; i < 16; i++) { 144 mvwprintw(win, 4 + i, 23, "%2.2X", i * 16); 145 wmove(win, 4 + i, 25); 146 waddch(win, ACS_VLINE); 147 } 148 149 show_config_space(win, 4, 26, menu_selected); 150 151 return 0; 152 } 153 154 static void ci_pci_scan_bus(int bus) 155 { 156 int slot, func; 157 unsigned int val; 158 unsigned char hdr; 159 160 for (slot = 0; slot < 0x20; slot++) { 161 for (func = 0; func < 8; func++) { 162 pcidev_t dev = PCI_DEV(bus, slot, func); 163 164 val = pci_read_config32(dev, REG_VENDOR_ID); 165 166 /* Nobody home. */ 167 if (val == 0xffffffff || val == 0x00000000 || 168 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; 174 continue; 175 } 176 177 /* FIXME: Remove this arbitrary limitation. */ 178 if (devices_index >= MAX_PCI_DEVICES) 179 return; 180 181 devices[devices_index].device = 182 PCI_DEV(bus, slot, func); 183 184 devices[devices_index++].id = val; 185 186 /* If this is a bridge, then follow it. */ 187 hdr = pci_read_config8(dev, REG_HEADER_TYPE); 188 189 if ((func == 0) && !(hdr & HEADER_TYPE_MULTIFUNCTION)) 190 func = 8; 191 192 hdr &= ~HEADER_TYPE_MULTIFUNCTION; 193 if (hdr == HEADER_TYPE_BRIDGE || 194 hdr == HEADER_TYPE_CARDBUS) { 195 unsigned int busses; 196 197 busses = pci_read_config32(dev, REG_PRIMARY_BUS); 198 199 ci_pci_scan_bus((busses >> 8) & 0xff); 200 201 } 202 } 203 } 204 205 quicksort(devices, devices_index); 206 } 207 208 static int pci_module_handle(int key) 209 { 210 int ret = 0; 211 212 switch (key) { 213 case KEY_DOWN: 214 if (menu_selected + 1 < devices_index) { 215 menu_selected++; 216 ret = 1; 217 } 218 break; 219 case KEY_UP: 220 if (menu_selected > 0) { 221 menu_selected--; 222 ret = 1; 223 } 224 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 238 return ret; 239 } 240 241 static int pci_module_init(void) 242 { 243 ci_pci_scan_bus(0); 244 return 0; 245 } 246 247 struct coreinfo_module pci_module = { 248 .name = "PCI", 249 .init = pci_module_init, 250 .redraw = pci_module_redraw, 251 .handle = pci_module_handle, 252 }; 253 254 #else 255 256 struct coreinfo_module pci_module = { 257 }; 258 259 #endif