📄 pci_serv.c
字号:
/****************************************************************************** sys_pci_device_initialization - initialize PCI I/O devices** This function is responsible for initializing all PCI I/O devices for proper* PCI operation. All I/O devices are mapped into appropriate locations in the* PCI address space (based on size and alignment requirements). This function* must ensure that no bus conflicts exist. This function is also responsible* for initializing cache line size, latency timer, DEVSEL# timing, and parity* error response. This function fills out the data structure which is passed* in to it. This function will return SUCCESSFUL if at least one I/O* controller can be successfully configured. This function will return ERROR* if no I/O controllers can be initialized.**/void sys_pci_device_initialization (PCI_DATA* pci_data){ volatile int i; bus0_lastbus = PRIMARY_BUS_NUM; /* last bus number behind bus 0 (primary bus ) */ bus1_lastbus = SECONDARY_BUS_NUM; /* last bus number behind bus 1 (secondary bus) */ pci_data->num_devices = 0; /* total number of devices configured */ pci_data->num_functions = 0; /* total number of functions configured */ init_312_pci(); /* initialize the ATU, MU and bridge on the 80312 */ if (isHost()) { /* If the IQ80310 board is connected to the backplane it has to initialize the Primary PCI bus */ /* set PCI base addresses for primary bus */ memspace_ptr[PRIMARY_BUS_NUM] = PRIMARY_MEM_BASE; memspace_limit[PRIMARY_BUS_NUM] = PRIMARY_MEM_LIMIT; iospace_ptr[PRIMARY_BUS_NUM] = PRIMARY_IO_BASE; iospace_limit[PRIMARY_BUS_NUM] = PRIMARY_IO_LIMIT; PRINT_OFF(); /* Initialize Primary PCI bus */ sys_pci_bus_init (PRIMARY_BUS_NUM, PRIMARY_BUS_NUM, pci_data); } /* Initialization of the Secondary PCI bus */ /* set PCI base addresses for secondary bus */ memspace_ptr[SECONDARY_BUS_NUM] = SECONDARY_MEM_BASE; memspace_limit[SECONDARY_BUS_NUM] = SECONDARY_MEM_LIMIT; iospace_ptr[SECONDARY_BUS_NUM] = SECONDARY_IO_BASE; iospace_limit[SECONDARY_BUS_NUM] = SECONDARY_IO_LIMIT; PRINT_OFF(); /* Initialize Secondary PCI bus */ sys_pci_bus_init (SECONDARY_BUS_NUM, SECONDARY_BUS_NUM, pci_data); /* Set absolute last secondary bus */ if (bus0_lastbus > bus1_lastbus) lastbus = bus0_lastbus; else lastbus = bus1_lastbus; PRINT_OFF(); /* before exiting, configure and enable FIQ and IRQ interrupts */ _enableFiqIrq(); /* enable FIQ and IRQ interrupts in CP13 */ config_ints(); /* configure interrupts */ /* wait a while to clear out any unwanted NMI interrupts */ for (i = 0; i < 100000; i++) ; PRINT_ON(); /* enable ECC single bit correction and multi-bit reporting - initialization code only enables correction */ *(volatile unsigned long *)ECCR_ADDR = 0x6;}/****************************************************************************** sys_pci_bus_init - initialize PCI I/O devices** This function is responsible for initializing all PCI I/O devices for proper * PCI operation. All I/O devices are mapped into appropriate locations in the* PCI address space (based on size and alignment requirements). This function * must ensure that no bus conflicts exist. This function is also responsible * for initializing cache line size, latency timer, DEVSEL# timing, and parity* error response. This function fills out the data structure which is passed* in to it. This function will return SUCCESSFUL if at least one I/O * controller can be successfully configured. This function will return ERROR * if no I/O controllers can be initialized.*/static void sys_pci_bus_init(UINT bus, UINT root_bus, PCI_DATA* pci_data){ UINT device, function; USHORT vendor, device_id; UINT regno; ULONG regvalue; USHORT regshort; UCHAR regchar; UCHAR intpin, intline; UINT line; UCHAR header_type; ULONG rom_enabled; UINT base_addr_reg_start; UINT base_addr_reg_end; UINT exp_rom_baseaddr; int multifunction;/* bridge initialization variables */ ULONG class_code; UINT secondary_bus_number; UCHAR iospace_type; UCHAR data_byte; USHORT data_word; ULONG membase, iobase; ULONG memlimit, iolimit; int no_memory, no_io;#ifdef DEBUG_PCI printf ("Configuring PCI Bus %d.\n", bus); printf ("PCI Root Bus %d.\n", root_bus); PRINT_OFF();#endiffor (device = 0; device <= MAX_DEVICE_NUMBER; device++){#ifdef DEBUG_PCI printf ("\nConfiguring device %d.\n\n", device);#endif /* assume non-multifunction device at start */ multifunction = FALSE; for (function = 0; function < MAX_FUNCTION_NUMBER; function ++) {#ifdef DEBUG_PCI printf ("Configuring function %d.\n", function);#endif /* To determine whether a device is installed in a particular slot, */ /* we attempt to read the vendor ID from that slot. If there's */ /* nothing there, the bridge should return 0xffff (and signal a */ /* master abort). Otherwise, there is something there and we need */ /* to configure it. */ if ((sys_read_config_word(bus, device, function, VENDOR_ID_OFFSET, &vendor) == ERROR) || (vendor == 0xffff)) { /* This means no device found */#ifdef DEBUG_PCI printf ("\nNo device.\n");#endif break; /* Go on to the next device */ } /* We'll only get here if we got a real device/function */ /* Count the number of devices */ if (function == 0) (pci_data->num_devices)++; /* Count the number of functions */ (pci_data->num_functions)++;#ifdef DEBUG_PCI printf ("Vendor: %x\n", vendor);#endif /* Read the Device ID */ sys_read_config_word (bus,device,function,DEVICE_ID_OFFSET,&device_id);#ifdef DEBUG_PCI printf("\n"); printf("Configuring PCI Bus : %d\n", bus); printf(" PCI Device: %d\n", device); printf(" Vendor Id : 0x%08X\n", vendor); printf(" Device Id : 0x%08X\n", device_id);#endif /* Read the Configuration Header Type to determine configuration */ if (sys_read_config_byte (bus,device,function,HEADER_TYPE_OFFSET,&header_type)== ERROR) continue; /* determine if multifunction device */ if ((header_type & MULTIFUNCTION_DEVICE) && (function == 0)) {#ifdef DEBUG_PCI printf ("Multifunction Device Found...\n");#endif multifunction = TRUE; } /* strip off multifunction device indicator bit */ header_type &= 0x7f; switch (header_type) { case STANDARD_HEADER: base_addr_reg_start = 0x10; /* Base Address Reg. Start Offset */ base_addr_reg_end = 0x24; /* Base Address Reg. End Offset */ exp_rom_baseaddr = 0x30; /* Expansion ROM Base Addr. Reg Offset */ break; case PCITOPCI_HEADER: base_addr_reg_start = 0x10; /* Base Address Reg. Start Offset */ base_addr_reg_end = 0x14; /* Base Address Reg. End Offset */ exp_rom_baseaddr = 0x38; /* Expansion ROM Base Addr. Reg Offset */ break; default: printf ("Header Type Not Supported, 0x%02X\n", header_type); continue; /* skip over device */ break; } /* We cycle through the base registers, first writing out all */ /* ones to the register, then reading it back to determine the */ /* requested size in either I/O or memory space. Then we */ /* align the top of memory or i/o space pointer, write it to */ /* the register, and increment it. I say we so you won't feel */ /* excluded. */ for (regno = base_addr_reg_start; regno <= base_addr_reg_end; regno += 4) { /* Write out all 1's to the base register, then read it back */ regvalue = 0xffffffff; sys_write_config_dword(bus,device,function,regno,(UINT32*)®value); sys_read_config_dword (bus,device,function,regno,(UINT32*)®value); /* Some number of the lower bits of regvalue will be clear */ /* indicating a don't care position. The more clear bits, */ /* the larger the requested mapping space. */ if (regvalue == 0) /* ...this reg not used. */ ; /*---------------------------------------------------------*/ /* I/O space mapping */ /*---------------------------------------------------------*/ else if ((regvalue & 3) == 1) /* ...this is I/O space */ { ULONG requested_size; /* Align iospace_ptr for the requested size. All bit */ /* positions clear in regvalue must be clear in */ /* iospace_ptr. */ requested_size = ~(regvalue & 0xfffffffe);#ifdef DEBUG_PCI printf ("Configuration for I/O space...\n"); printf ("Size request: %x; ", requested_size); printf ("IOspace_ptr: %x\n", iospace_ptr[root_bus]);#endif /* check to make sure that there is enought iospace left to grant */ if ((iospace_ptr[root_bus] + requested_size) > iospace_limit[root_bus]) { printf ("\nPCI Configuration ERROR: Out of I/O Space on Bus %d!\n", bus); printf (" No I/O Space Allocated to Device %d, Function %d.\n", device, function); return; } /* Align the space pointer if necessary */ if (iospace_ptr[root_bus] & requested_size) { iospace_ptr[root_bus] &= ~requested_size; iospace_ptr[root_bus] += requested_size + 1; }#ifdef DEBUG_PCI printf("Adjusted I/O Space Ptr: %x\n", iospace_ptr[root_bus]); printf(" I/O Space Size : 0x%08X\n", requested_size); printf(" I/O Space Base : 0x%08X\n", iospace_ptr[root_bus]);#endif /* Write out the adjusted iospace pointer. */ sys_write_config_dword (bus,device,function,regno,(UINT32*)&iospace_ptr[root_bus]); /* Update space pointer */ iospace_ptr[root_bus] += requested_size + 1; } /*---------------------------------------------------------*/ /* Memory space mapping */ /*---------------------------------------------------------*/ else if ((regvalue & 1) == 0) /* ...this is memory space */ { ULONG requested_size; /* Type is encoded in bits 1 and 2 */ /* 64 bit space (10) is an error for the moment, as is */ /* the reserved value, 11. */ if (regvalue & 0x4) { printf ("Type error in base register.\n"); break; } /* Align memspace_ptr for the requested size. All bit */ /* positions clear in regvalue must be clear in */ /* memspace_ptr. */ requested_size = ~(regvalue & 0xfffffff0);#ifdef DEBUG_PCI printf ("Configuration for memory space.\n"); printf ("Size request: %x; ", requested_size); printf ("Membase_ptr: %x\n", memspace_ptr[root_bus]);#endif /* check to make sure that there is enough memspace left to grant */ if ((memspace_ptr[root_bus] + requested_size) > memspace_limit[root_bus]) { printf ("\nPCI Configuration ERROR: Out of Memory Space on Bus %d!\n", bus); printf (" No Memory Space Allocated to Device %d, Function %d.\n", device, function); printf ("Root Bus = %d, Memory Ptr = 0x%08X, Requested Size = 0x%08X, Memory Limit = 0x%08X\n", root_bus, memspace_ptr[root_bus], requested_size, memspace_limit[root_bus]); return; } if (memspace_ptr[root_bus] & requested_size) { memspace_ptr[root_bus] &= ~requested_size; memspace_ptr[root_bus] += requested_size + 1; }#ifdef DEBUG_PCI printf ("Adjusted Membase_ptr: %x\n", memspace_ptr[root_bus]); printf(" Memory Space Size : 0x%08X\n", requested_size); printf(" Memory Space Base : 0x%08X\n", memspace_ptr[root_bus]);#endif /* Write out the adjusted memory pointer */ sys_write_config_dword (bus,device,function,regno,(UINT32*)&memspace_ptr[root_bus]); memspace_ptr[root_bus] += requested_size + 1; } } /*-------------------------------------------------------------*/ /* Expansion ROM mapping */ /* The expansion ROM is handled in the same way as the other */ /* PCI base registers. If the lowest bit in this register is */ /* set, memory-mapped accesses are not possible, since the ROM */ /* is active. (Only one decoder). */ /*-------------------------------------------------------------*/ /* Store the state of the ROM enabled bit so we can restore it */ sys_read_config_dword (bus,device,function,exp_rom_baseaddr,(UINT32*)®value); rom_enabled = regvalue & 1; /* Write out all 1's to the non-reserved bits of the base register, then read it back */ regvalue = 0xffffffff; sys_write_config_dword(bus,device,function,EXP_ROM_OFFSET,(UINT32*)®value); sys_read_config_dword (bus,device,function,EXP_ROM_OFFSET,(UINT32*)®value); /* Some number of the lower bits of regvalue will be clear */ /* indicating a don't care position. The more clear bits, */ /* the larger the requested mapping space. */ if ((regvalue & 0xffff800) != 0) /* No mapping if it's 0 */ { ULONG requested_size;#ifdef DEBUG_PCI printf ("Expansion ROM detected.\n");#endif /* Expansion ROMs will map into memory space, so... */ /* Align memspace_ptr for the requested size. All bit */ /* positions clear in regvalue must be clear in */ /* memspace_ptr. */ requested_size = ~(regvalue & 0xfffff800);#ifdef DEBUG_PCI printf ("Size request: %x; ", requested_size); printf ("Membase_ptr: %x\n", memspace_ptr[root_bus]);#endif /* check to make sure that there is enought memspace left to grant */ if ((memspace_ptr[root_bus] + requested_size) > memspace_limit[root_bus]) { printf ("\nPCI Configuration ERROR: Out of Memory Space on Bus %d!\n", bus); printf (" No Expansion ROM Space Allocated to Device %d, Function %d.\n", device, function); return; } if (memspace_ptr[root_bus] & requested_size) { memspace_ptr[root_bus] &= ~requested_size; memspace_ptr[root_bus] += requested_size + 1; }#ifdef DEBUG_PCI printf("Adjusted Membase_ptr: %x\n", memspace_ptr[root_bus]); printf(" Exp. ROM Space Size : 0x%08X\n", requested_size); printf(" Exp. ROM Space Base : 0x%08X\n", memspace_ptr[root_bus]);#endif /* Write out the adjusted memory pointer */ regvalue = memspace_ptr[root_bus] | rom_enabled; sys_write_config_dword (bus,device
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -