|
|
1.1 root 1: /******************************************************************************
2: * Copyright (c) 2004, 2008 IBM Corporation
3: * All rights reserved.
4: * This program and the accompanying materials
5: * are made available under the terms of the BSD License
6: * which accompanies this distribution, and is available at
7: * http://www.opensource.org/licenses/bsd-license.php
8: *
9: * Contributors:
10: * IBM Corporation - initial implementation
11: *****************************************************************************/
12:
13:
14: #include "device.h"
15: #include "rtas.h"
16: #include <stdio.h>
17: #include <string.h>
18: #include "debug.h"
19:
20: typedef struct {
21: uint8_t info;
22: uint8_t bus;
23: uint8_t devfn;
24: uint8_t cfg_space_offset;
25: uint64_t address;
26: uint64_t size;
27: } __attribute__ ((__packed__)) assigned_address_t;
28:
29: // use translate_address_dev and get_puid from net-snk's net_support.c
30: void translate_address_dev(uint64_t *, phandle_t);
31: uint64_t get_puid(phandle_t node);
32:
33:
34: // scan all adresses assigned to the device ("assigned-addresses" and "reg")
35: // store in translate_address_array for faster translation using dev_translate_address
36: void
37: dev_get_addr_info()
38: {
39: // get bus/dev/fn from assigned-addresses
40: int32_t len;
41: //max. 6 BARs and 1 Exp.ROM plus CfgSpace and 3 legacy ranges
42: assigned_address_t buf[11];
43: len =
44: of_getprop(bios_device.phandle, "assigned-addresses", buf,
45: sizeof(buf));
46: bios_device.bus = buf[0].bus;
47: bios_device.devfn = buf[0].devfn;
48: DEBUG_PRINTF("bus: %x, devfn: %x\n", bios_device.bus,
49: bios_device.devfn);
50: //store address translations for all assigned-addresses and regs in
51: //translate_address_array for faster translation later on...
52: int i = 0;
53: // index to insert data into translate_address_array
54: int taa_index = 0;
55: uint64_t address_offset;
56: for (i = 0; i < (len / sizeof(assigned_address_t)); i++, taa_index++) {
57: //copy all info stored in assigned-addresses
58: translate_address_array[taa_index].info = buf[i].info;
59: translate_address_array[taa_index].bus = buf[i].bus;
60: translate_address_array[taa_index].devfn = buf[i].devfn;
61: translate_address_array[taa_index].cfg_space_offset =
62: buf[i].cfg_space_offset;
63: translate_address_array[taa_index].address = buf[i].address;
64: translate_address_array[taa_index].size = buf[i].size;
65: // translate first address and store it as address_offset
66: address_offset = buf[i].address;
67: translate_address_dev(&address_offset, bios_device.phandle);
68: translate_address_array[taa_index].address_offset =
69: address_offset - buf[i].address;
70: }
71: //get "reg" property
72: len = of_getprop(bios_device.phandle, "reg", buf, sizeof(buf));
73: for (i = 0; i < (len / sizeof(assigned_address_t)); i++) {
74: if ((buf[i].size == 0) || (buf[i].cfg_space_offset != 0)) {
75: // we dont care for ranges with size 0 and
76: // BARs and Expansion ROM must be in assigned-addresses... so in reg
77: // we only look for those without config space offset set...
78: // i.e. the legacy ranges
79: continue;
80: }
81: //copy all info stored in assigned-addresses
82: translate_address_array[taa_index].info = buf[i].info;
83: translate_address_array[taa_index].bus = buf[i].bus;
84: translate_address_array[taa_index].devfn = buf[i].devfn;
85: translate_address_array[taa_index].cfg_space_offset =
86: buf[i].cfg_space_offset;
87: translate_address_array[taa_index].address = buf[i].address;
88: translate_address_array[taa_index].size = buf[i].size;
89: // translate first address and store it as address_offset
90: address_offset = buf[i].address;
91: translate_address_dev(&address_offset, bios_device.phandle);
92: translate_address_array[taa_index].address_offset =
93: address_offset - buf[i].address;
94: taa_index++;
95: }
96: // store last entry index of translate_address_array
97: taa_last_entry = taa_index - 1;
98: #ifdef DEBUG
99: //dump translate_address_array
100: printf("translate_address_array: \n");
101: translate_address_t ta;
102: for (i = 0; i <= taa_last_entry; i++) {
103: ta = translate_address_array[i];
104: printf
105: ("%d: %02x%02x%02x%02x\n\taddr: %016llx\n\toffs: %016llx\n\tsize: %016llx\n",
106: i, ta.info, ta.bus, ta.devfn, ta.cfg_space_offset,
107: ta.address, ta.address_offset, ta.size);
108: }
109: #endif
110: }
111:
112: // to simulate accesses to legacy VGA Memory (0xA0000-0xBFFFF)
113: // we look for the first prefetchable memory BAR, if no prefetchable BAR found,
114: // we use the first memory BAR
115: // dev_translate_addr will translate accesses to the legacy VGA Memory into the found vmem BAR
116: void
117: dev_find_vmem_addr()
118: {
119: int i = 0;
120: translate_address_t ta;
121: int8_t tai_np = -1, tai_p = -1; // translate_address_array index for non-prefetchable and prefetchable memory
122: //search backwards to find first entry
123: for (i = taa_last_entry; i >= 0; i--) {
124: ta = translate_address_array[i];
125: if ((ta.cfg_space_offset >= 0x10)
126: && (ta.cfg_space_offset <= 0x24)) {
127: //only BARs
128: if ((ta.info & 0x03) >= 0x02) {
129: //32/64bit memory
130: tai_np = i;
131: if ((ta.info & 0x40) != 0) {
132: // prefetchable
133: tai_p = i;
134: }
135: }
136: }
137: }
138: if (tai_p != -1) {
139: ta = translate_address_array[tai_p];
140: bios_device.vmem_addr = ta.address;
141: bios_device.vmem_size = ta.size;
142: DEBUG_PRINTF
143: ("%s: Found prefetchable Virtual Legacy Memory BAR: %llx, size: %llx\n",
144: __FUNCTION__, bios_device.vmem_addr,
145: bios_device.vmem_size);
146: } else if (tai_np != -1) {
147: ta = translate_address_array[tai_np];
148: bios_device.vmem_addr = ta.address;
149: bios_device.vmem_size = ta.size;
150: DEBUG_PRINTF
151: ("%s: Found non-prefetchable Virtual Legacy Memory BAR: %llx, size: %llx",
152: __FUNCTION__, bios_device.vmem_addr,
153: bios_device.vmem_size);
154: }
155: // disable vmem
156: //bios_device.vmem_size = 0;
157: }
158:
159: void
160: dev_get_puid()
161: {
162: // get puid
163: bios_device.puid = get_puid(bios_device.phandle);
164: DEBUG_PRINTF("puid: 0x%llx\n", bios_device.puid);
165: }
166:
167: void
168: dev_get_device_vendor_id()
169: {
170: uint32_t pci_config_0 =
171: rtas_pci_config_read(bios_device.puid, 4, bios_device.bus,
172: bios_device.devfn, 0x0);
173: bios_device.pci_device_id =
174: (uint16_t) ((pci_config_0 & 0xFFFF0000) >> 16);
175: bios_device.pci_vendor_id = (uint16_t) (pci_config_0 & 0x0000FFFF);
176: DEBUG_PRINTF("PCI Device ID: %04x, PCI Vendor ID: %x\n",
177: bios_device.pci_device_id, bios_device.pci_vendor_id);
178: }
179:
180: /* check, wether the device has a valid Expansion ROM, also search the PCI Data Structure and
181: * any Expansion ROM Header (using dev_scan_exp_header()) for needed information */
182: uint8_t
183: dev_check_exprom()
184: {
185: int i = 0;
186: translate_address_t ta;
187: uint64_t rom_base_addr = 0;
188: uint16_t pci_ds_offset;
189: pci_data_struct_t pci_ds;
190: // check for ExpROM Address (Offset 30) in taa
191: for (i = 0; i <= taa_last_entry; i++) {
192: ta = translate_address_array[i];
193: if (ta.cfg_space_offset == 0x30) {
194: rom_base_addr = ta.address + ta.address_offset; //translated address
195: break;
196: }
197: }
198: // in the ROM there could be multiple Expansion ROM Images... start searching
199: // them for a x86 image
200: do {
201: if (rom_base_addr == 0) {
202: printf("Error: no Expansion ROM address found!\n");
203: return -1;
204: }
205: set_ci();
206: uint16_t rom_signature = *((uint16_t *) rom_base_addr);
207: clr_ci();
208: if (rom_signature != 0x55aa) {
209: printf
210: ("Error: invalid Expansion ROM signature: %02x!\n",
211: *((uint16_t *) rom_base_addr));
212: return -1;
213: }
214: set_ci();
215: // at offset 0x18 is the (16bit little-endian) pointer to the PCI Data Structure
216: pci_ds_offset = in16le((void *) (rom_base_addr + 0x18));
217: //copy the PCI Data Structure
218: memcpy(&pci_ds, (void *) (rom_base_addr + pci_ds_offset),
219: sizeof(pci_ds));
220: clr_ci();
221: #ifdef DEBUG
222: DEBUG_PRINTF("PCI Data Structure @%llx:\n",
223: rom_base_addr + pci_ds_offset);
224: dump((void *) &pci_ds, sizeof(pci_ds));
225: #endif
226: if (strncmp((const char *) pci_ds.signature, "PCIR", 4) != 0) {
227: printf("Invalid PCI Data Structure found!\n");
228: break;
229: }
230: //little-endian conversion
231: pci_ds.vendor_id = in16le(&pci_ds.vendor_id);
232: pci_ds.device_id = in16le(&pci_ds.device_id);
233: pci_ds.img_length = in16le(&pci_ds.img_length);
234: pci_ds.pci_ds_length = in16le(&pci_ds.pci_ds_length);
235: if (pci_ds.vendor_id != bios_device.pci_vendor_id) {
236: printf
237: ("Image has invalid Vendor ID: %04x, expected: %04x\n",
238: pci_ds.vendor_id, bios_device.pci_vendor_id);
239: break;
240: }
241: if (pci_ds.device_id != bios_device.pci_device_id) {
242: printf
243: ("Image has invalid Device ID: %04x, expected: %04x\n",
244: pci_ds.device_id, bios_device.pci_device_id);
245: break;
246: }
247: //DEBUG_PRINTF("Image Length: %d\n", pci_ds.img_length * 512);
248: //DEBUG_PRINTF("Image Code Type: %d\n", pci_ds.code_type);
249: if (pci_ds.code_type == 0) {
250: //x86 image
251: //store image address and image length in bios_device struct
252: bios_device.img_addr = rom_base_addr;
253: bios_device.img_size = pci_ds.img_length * 512;
254: // we found the image, exit the loop
255: break;
256: } else {
257: // no x86 image, check next image (if any)
258: rom_base_addr += pci_ds.img_length * 512;
259: }
260: if ((pci_ds.indicator & 0x80) == 0x80) {
261: //last image found, exit the loop
262: DEBUG_PRINTF("Last PCI Expansion ROM Image found.\n");
263: break;
264: }
265: }
266: while (bios_device.img_addr == 0);
267: // in case we did not find a valid x86 Expansion ROM Image
268: if (bios_device.img_addr == 0) {
269: printf("Error: no valid x86 Expansion ROM Image found!\n");
270: return -1;
271: }
272: return 0;
273: }
274:
275: uint8_t
276: dev_init(char *device_name)
277: {
278: uint8_t rval = 0;
279: //init bios_device struct
280: DEBUG_PRINTF("%s(%s)\n", __FUNCTION__, device_name);
281: memset(&bios_device, 0, sizeof(bios_device));
282: bios_device.ihandle = of_open(device_name);
283: if (bios_device.ihandle == 0) {
284: DEBUG_PRINTF("%s is no valid device!\n", device_name);
285: return -1;
286: }
287: bios_device.phandle = of_finddevice(device_name);
288: dev_get_addr_info();
289: dev_find_vmem_addr();
290: dev_get_puid();
291: dev_get_device_vendor_id();
292: return rval;
293: }
294:
295: // translate address function using translate_address_array assembled
296: // by dev_get_addr_info... MUCH faster than calling translate_address_dev
297: // and accessing client interface for every translation...
298: // returns: 0 if addr not found in translate_address_array, 1 if found.
299: uint8_t
300: dev_translate_address(uint64_t * addr)
301: {
302: int i = 0;
303: translate_address_t ta;
304: //check if it is an access to legacy VGA Mem... if it is, map the address
305: //to the vmem BAR and then translate it...
306: // (translation info provided by Ben Herrenschmidt)
307: // NOTE: the translation seems to only work for NVIDIA cards... but it is needed
308: // to make some NVIDIA cards work at all...
309: if ((bios_device.vmem_size > 0)
310: && ((*addr >= 0xA0000) && (*addr < 0xB8000))) {
311: *addr = (*addr - 0xA0000) * 4 + 2 + bios_device.vmem_addr;
312: }
313: if ((bios_device.vmem_size > 0)
314: && ((*addr >= 0xB8000) && (*addr < 0xC0000))) {
315: uint8_t shift = *addr & 1;
316: *addr &= 0xfffffffe;
317: *addr = (*addr - 0xB8000) * 4 + shift + bios_device.vmem_addr;
318: }
319: for (i = 0; i <= taa_last_entry; i++) {
320: ta = translate_address_array[i];
321: if ((*addr >= ta.address) && (*addr <= (ta.address + ta.size))) {
322: *addr += ta.address_offset;
323: return 1;
324: }
325: }
326: return 0;
327: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.