|
|
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.