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