/* * Copyright : (C) 2022 Phytium Information Technology, Inc. * All Rights Reserved. * * This program is OPEN SOURCE software: you can redistribute it and/or modify it * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd, * either version 1.0 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the Phytium Public License for more details. * * * FilePath: fpcie.c * Date: 2022-08-10 14:55:11 * LastEditTime: 2022-08-18 08:59:28 * Description: This file is for the minimum required function implementations for this driver. * * Modify History: * Ver   Who        Date         Changes * ----- ------     --------    -------------------------------------- * 1.0 huanghe 2022/8/18 init commit */ /***************************** Include Files *********************************/ #include "fpcie.h" #include "fpcie_hw.h" #include "fpcie_common.h" #include "fparameters.h" #include "fkernel.h" #include #include #include "fdebug.h" #define CONFIG_SYS_PCI_CACHE_LINE_SIZE 8 #define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) /***************** Macros (Inline Functions) Definitions *********************/ #define FPCIE_DEBUG_TAG "FPCIE" #define FPCIE_ERROR(format, ...) FT_DEBUG_PRINT_E(FPCIE_DEBUG_TAG, format, ##__VA_ARGS__) #define FPCIE_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(FPCIE_DEBUG_TAG, format, ##__VA_ARGS__) #define FPCIE_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(FPCIE_DEBUG_TAG, format, ##__VA_ARGS__) #define FPCIE_DEBUG_E(format, ...) FT_DEBUG_PRINT_E(FPCIE_DEBUG_TAG, format, ##__VA_ARGS__) /************************** Constant Definitions *****************************/ /**************************** Type Definitions *******************************/ /************************** Variable Definitions *****************************/ extern int FPcieEpCleanBar(FPcie *instance_p, u32 peu_num, u32 bar_num) ; static void FPcieShowRegion(const char *name, struct FPcieRegion *region) { FPCIE_DEBUG_I("Pci auto config: bus %s region: [0x%llx-0x%llx],\n" "\t\tphysical memory [0x%llx-0x%llx]", name, (unsigned long long)region->bus_start, (unsigned long long)(region->bus_start + region->size - 1), (unsigned long long)region->phys_start, (unsigned long long)(region->phys_start + region->size - 1)); FPCIE_DEBUG_I("Bus lower is 0x%llx", (unsigned long long)region->bus_lower) ; } /** * @name: FPcieRegionConfigInit * @msg: 初始化PEU 用于分配的地址空间 * @param {FPcie} *instance_p is a pointer to the FPcie instance. * @param {FPcieRegion} *regs 地址空间对应的指针 * @param {u32} regs_num 传入regs 结构体的数量 */ //用于资源初始化到instance_p中 static void FPcieRegionConfigInit(FPcie *instance_p, struct FPcieRegion *regs, u32 regs_num) { u32 i ; for (i = 0; i < regs_num; i++) { switch (regs[i].flags) { case FPCIE_REGION_IO: memset(&instance_p->mem_io, 0, sizeof(struct FPcieRegion)) ; memcpy(&instance_p->mem_io, regs, sizeof(struct FPcieRegion)) ; instance_p->mem_io.exist_flg = FPCIE_REGION_EXIST_FLG ; instance_p->mem_io.bus_lower = instance_p->mem_io.phys_start; FPcieShowRegion("I/O", &instance_p->mem_io); break; case FPCIE_REGION_MEM: memset(&instance_p->mem, 0, sizeof(struct FPcieRegion)) ; memcpy(&instance_p->mem, regs, sizeof(struct FPcieRegion)) ; instance_p->mem.exist_flg = FPCIE_REGION_EXIST_FLG ; instance_p->mem.bus_lower = instance_p->mem.phys_start; FPcieShowRegion("Memory", &instance_p->mem); break; case (PCI_REGION_PREFETCH|FPCIE_REGION_MEM): memset(&instance_p->mem_prefetch, 0, sizeof(struct FPcieRegion)) ; memcpy(&instance_p->mem_prefetch, regs, sizeof(struct FPcieRegion)) ; instance_p->mem_prefetch.exist_flg = FPCIE_REGION_EXIST_FLG ; instance_p->mem_prefetch.bus_lower = instance_p->mem_prefetch.phys_start; FPcieShowRegion("Prefetchable Mem", &instance_p->mem_prefetch); break; default: break; } } } /** * @name: FPcieCfgInitialize * @msg: This function initializes the config space and PCIe bridge. * @param {FPcie} *instance_p is a pointer to the FPcie instance. * @param {FPcieConfig} *config_p pointer to FPcieConfig instrance Pointer. * @return FError */ FError FPcieCfgInitialize(FPcie *instance_p, FPcieConfig *config_p) //用于从全局配置数据中获取数据,初始化instance_p { fsize_t i; struct FPcieRegion mem_region = {0} ; struct FPcieRegion prefetch_region = {0} ; struct FPcieRegion io_region = {0} ; /* Assert arguments */ FASSERT(instance_p != NULL); FASSERT(config_p != NULL); /* Clear instance memory and make copy of configuration */ memset(instance_p, 0, sizeof(FPcie)); memcpy(&instance_p->config, config_p, sizeof(FPcieConfig)); /* 为枚举过程中,涉及的配置空间提供地址划分 */ /* mem32 地址 */ //使用获取到的硬件信息,来初始化mem32 mem_region.phys_start = instance_p->config.npmem_base_addr ; mem_region.bus_start = instance_p->config.npmem_base_addr ; mem_region.size = instance_p->config.npmem_size ; mem_region.flags = FPCIE_REGION_MEM ; /* mem64 地址 */ //使用获取到的硬件信息,来初始化mem64 prefetch_region.phys_start = instance_p->config.pmem_base_addr ; prefetch_region.bus_start = instance_p->config.pmem_base_addr ; prefetch_region.size = instance_p->config.pmem_size ; prefetch_region.flags = (PCI_REGION_PREFETCH | FPCIE_REGION_MEM); /* memio 地址 */ //使用获取到的硬件信息,来初始化io io_region.phys_start = instance_p->config.io_base_addr ; io_region.bus_start = instance_p->config.io_base_addr ; io_region.size = instance_p->config.io_size ; io_region.flags = FPCIE_REGION_IO; /* scaned bdf array clean */ instance_p->scaned_bdf_count = 0; FPcieRegionConfigInit(instance_p, &mem_region, 1) ; #if defined(__aarch64__) FPcieRegionConfigInit(instance_p, &prefetch_region, 1) ; #endif FPcieRegionConfigInit(instance_p, &io_region, 1) ; instance_p->is_ready = FT_COMPONENT_IS_READY; return (FT_SUCCESS); } u32 FPcieFindCapability(FPcie *instance_p, u32 bdf, u32 cid_type, u32 cid, u32 *cid_offset) { u32 reg_value; u32 next_cap_offset; if (cid_type == PCIE_CAP) { /* Serach in PCIe configuration space */ FPcieEcamReadConfig32bit(instance_p->config.ecam, bdf, FPCIE_CAPABILITY_LIST, ®_value); if (reg_value == 0xffffffff) { return -1; } next_cap_offset = (reg_value & 0xff); while (next_cap_offset) { FPcieEcamReadConfig32bit(instance_p->config.ecam, bdf, next_cap_offset, ®_value); if ((reg_value & 0xff) == cid) { *cid_offset = next_cap_offset; return 0; } next_cap_offset = ((reg_value >> 8) & 0xff); } } else if (cid_type == PCIE_ECAP) { /* Serach in PCIe extended configuration space */ next_cap_offset = FPCIE_ECAP_START; while (next_cap_offset) { FPcieEcamReadConfig32bit(instance_p->config.ecam, bdf, next_cap_offset, ®_value); if ((reg_value & 0xffff) == cid) { *cid_offset = next_cap_offset; return 0; } next_cap_offset = ((reg_value >> 20) & 0xfff); } } /* The capability was not found */ return -1; } const char *FPcieClassStr(u8 class) { switch (class) { case FPCI_CLASS_NOT_DEFINED: return "Build before PCI Rev2.0"; break; case FPCI_BASE_CLASS_STORAGE: return "Mass storage controller"; break; case FPCI_BASE_CLASS_NETWORK: return "Network controller"; break; case FPCI_BASE_CLASS_DISPLAY: return "Display controller"; break; case FPCI_BASE_CLASS_MULTIMEDIA: return "Multimedia device"; break; case FPCI_BASE_CLASS_MEMORY: return "Memory controller"; break; case FPCI_BASE_CLASS_BRIDGE: return "Bridge device"; break; case FPCI_BASE_CLASS_COMMUNICATION: return "Simple comm. controller"; break; case FPCI_BASE_CLASS_SYSTEM: return "Base system peripheral"; break; case FPCI_BASE_CLASS_INPUT: return "Input device"; break; case FPCI_BASE_CLASS_DOCKING: return "Docking station"; break; case FPCI_BASE_CLASS_PROCESSOR: return "Processor"; break; case FPCI_BASE_CLASS_SERIAL: return "Serial bus controller"; break; case FPCI_BASE_CLASS_INTELLIGENT: return "Intelligent controller"; break; case FPCI_BASE_CLASS_SATELLITE: return "Satellite controller"; break; case FPCI_BASE_CLASS_CRYPT: return "Cryptographic device"; break; case FPCI_BASE_CLASS_SIGNAL_PROCESSING: return "DSP"; break; case FPCI_CLASS_OTHERS: return "Does not fit any class"; break; default: return "???"; break; }; } void FPcieAutoRegionAlign(struct FPcieRegion *res, pci_size_t size) { res->bus_lower = ((res->bus_lower - 1) | (size - 1)) + 1; } int FPcieAutoRegionAllocate(struct FPcieRegion *res, pci_size_t size, pci_addr_t *bar, bool supports_64bit) { pci_addr_t addr; if (!res) { FPCIE_DEBUG_E("No resource."); goto error; } addr = ((res->bus_lower - 1) | (size - 1)) + 1; if (addr - res->bus_start + size > res->size) { FPCIE_DEBUG_E("No room in resource."); goto error; } if (upper_32_bits(addr) && !supports_64bit) { FPCIE_DEBUG_E("Cannot assign 64-bit address to 32-bit-only resource."); goto error; } res->bus_lower = addr + size; *bar = addr; return 0; error: *bar = (pci_addr_t) -1; return -1; } void FPcieAutoSetupDevice(FPcie *instance_p, u32 bdf, int bars_num, struct FPcieRegion *mem, struct FPcieRegion *prefetch, struct FPcieRegion *io, bool enum_only) { u32 bar_response; pci_size_t bar_size; u16 cmdstat = 0; int bar, bar_nr = 0; u8 header_type; int rom_addr; pci_addr_t bar_value; struct FPcieRegion *bar_res = NULL; int found_mem64 = 0; u16 class; FPcieEcamReadConfig16bit(instance_p->config.ecam, bdf, FPCIE_COMMAND_REG, &cmdstat); cmdstat = (cmdstat & ~(FPCIE_COMMAND_IO | FPCIE_COMMAND_MEMORY)) | FPCIE_COMMAND_MASTER; for (bar = FPCIE_BASE_ADDRESS_0; bar < FPCIE_BASE_ADDRESS_0 + (bars_num * 4); bar += 4) { /* Tickle the BAR and get the response */ if (!enum_only) { FPcieEcamWriteConfig32bit(instance_p->config.ecam, bdf, bar, 0xffffffff); } FPcieEcamReadConfig32bit(instance_p->config.ecam, bdf, bar, &bar_response); /* If BAR is not implemented go to the next BAR */ if (!bar_response) { continue; } found_mem64 = 0; /* Check the BAR type and set our address mask */ if (bar_response & FPCIE_BASE_ADDRESS_SPACE) { bar_size = ((~(bar_response & FPCIE_BASE_ADDRESS_IO_MASK)) & 0xffff) + 1; if (!enum_only) { bar_res = io; } } else { if ((bar_response & FPCIE_BASE_ADDRESS_MEM_TYPE_MASK) == FPCIE_BASE_ADDRESS_MEM_TYPE_64) { u32 bar_response_upper; u64 bar64; if (!enum_only) { FPcieEcamWriteConfig32bit(instance_p->config.ecam, bdf, bar + 4, 0xffffffff); } FPcieEcamReadConfig32bit(instance_p->config.ecam, bdf, bar + 4, &bar_response_upper); bar64 = ((u64)bar_response_upper << 32) | bar_response; bar_size = ~(bar64 & FPCIE_BASE_ADDRESS_MEM_MASK) + 1; if (!enum_only) { found_mem64 = 1; } } else { bar_size = (u32)(~(bar_response & FPCIE_BASE_ADDRESS_MEM_MASK) + 1); } if (!enum_only) { if ((prefetch->exist_flg & FPCIE_REGION_EXIST_FLG) & (bar_response & FPCIE_BASE_ADDRESS_MEM_PREFETCH)) { bar_res = prefetch; } else { bar_res = mem; } } } if (!enum_only && FPcieAutoRegionAllocate(bar_res, bar_size, &bar_value, found_mem64) == 0) { /* Write it out and update our limit */ FPcieEcamWriteConfig32bit(instance_p->config.ecam, bdf, bar, (u32)bar_value); if (found_mem64) { bar += 4; #ifdef CONFIG_SYS_PCI_64BIT FPcieEcamWriteConfig32bit(instance_p->config.ecam, bdf, bar, (u32)(bar_value >> 32)); #else /* * If we are a 64-bit decoder then increment to * the upper 32 bits of the bar and force it to * locate in the lower 4GB of memory. */ FPcieEcamWriteConfig32bit(instance_p->config.ecam, bdf, bar, 0x00000000); #endif } } cmdstat |= (bar_response & FPCIE_BASE_ADDRESS_SPACE) ? FPCIE_COMMAND_IO : FPCIE_COMMAND_MEMORY; bar_nr++; } if (!enum_only) { /* Configure the expansion ROM address */ FPcieEcamReadConfig8bit(instance_p->config.ecam, bdf, FPCIE_HEADER_TYPE_REG, &header_type); header_type &= 0x7f; if (header_type != FPCIE_HEADER_TYPE_CARDBUS) { rom_addr = (header_type == FPCIE_HEADER_TYPE_NORMAL) ? FPCIE_ROM_ADDRESS : FPCIE_ROM_ADDRESS1; FPcieEcamWriteConfig32bit(instance_p->config.ecam, bdf, rom_addr, 0xfffffffe); FPcieEcamReadConfig32bit(instance_p->config.ecam, bdf, rom_addr, &bar_response); if (bar_response) { bar_size = -(bar_response & ~1); if (FPcieAutoRegionAllocate(mem, bar_size, &bar_value, false) == 0) { FPcieEcamWriteConfig32bit(instance_p->config.ecam, bdf, rom_addr, bar_value); } cmdstat |= FPCIE_COMMAND_MEMORY; } } } /* PCI_COMMAND_IO must be set for VGA device */ FPcieEcamReadConfig16bit(instance_p->config.ecam, bdf, FPCI_CLASS_DEVICE_REG, &class); if (class == FPCI_CLASS_DISPLAY_VGA) { cmdstat |= FPCIE_COMMAND_IO; } FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_COMMAND_REG, cmdstat); FPcieEcamWriteConfig8bit(instance_p->config.ecam, bdf, FPCIE_CACHE_LINE_SIZE_REG, CONFIG_SYS_PCI_CACHE_LINE_SIZE); FPcieEcamWriteConfig8bit(instance_p->config.ecam, bdf, FPCIE_LATENCY_TIMER_REG, 0x80); } void FPcieAutoPrescanSetupBridge(FPcie *instance_p, u32 bdf, int sub_bus) { struct FPcieRegion *pci_mem; struct FPcieRegion *pci_prefetch; struct FPcieRegion *pci_io; u16 cmdstat, prefechable_64; pci_mem = &(instance_p->mem); pci_prefetch = &(instance_p->mem_prefetch); pci_io = &(instance_p->mem_io); FPcieEcamReadConfig16bit(instance_p->config.ecam, bdf, FPCIE_COMMAND_REG, &cmdstat) ; FPcieEcamReadConfig16bit(instance_p->config.ecam, bdf, FPCIE_PREF_MEMORY_BASE_REG, &prefechable_64) ; prefechable_64 &= FPCIE_PREF_RANGE_TYPE_MASK; /* Configure bus number registers *///暂时只有一个pcie配置空间的做法,如果多个pci配置空间,则需当前bus减去该配置空间对应设备的起始bus号 FPcieEcamWriteConfig8bit(instance_p->config.ecam, bdf, FPCIE_PRIMARY_BUS_REG, FPCIE_BUS(bdf)); FPcieEcamWriteConfig8bit(instance_p->config.ecam, bdf, FPCIE_SECONDARY_BUS_REG, sub_bus); FPcieEcamWriteConfig8bit(instance_p->config.ecam, bdf, FPCIE_SUBORDINATE_BUS_REG, 0xff); if (pci_mem->exist_flg & FPCIE_REGION_EXIST_FLG) { /* Round memory allocator to 1MB boundary */ FPcieAutoRegionAlign(pci_mem, 0x100000); /* * Set up memory and I/O filter limits, assume 32-bit * I/O space */ FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_MEMORY_BASE_REG, (pci_mem->bus_lower & 0xfff00000) >> 16); cmdstat |= FPCIE_COMMAND_MEMORY; } if (pci_prefetch->exist_flg & FPCIE_REGION_EXIST_FLG) { /* Round memory allocator to 1MB boundary */ FPcieAutoRegionAlign(pci_prefetch, 0x100000); /* * Set up memory and I/O filter limits, assume 32-bit * I/O space */ FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_PREF_MEMORY_BASE_REG, (pci_prefetch->bus_lower & 0xfff00000) >> 16); if (prefechable_64 == FPCIE_PREF_RANGE_TYPE_64) #ifdef CONFIG_SYS_PCI_64BIT FPcieEcamWriteConfig32bit(instance_p->config.ecam, bdf, FPCIE_PREF_BASE_UPPER32_REG, pci_prefetch->bus_lower >> 32); #else FPcieEcamWriteConfig32bit(instance_p->config.ecam, bdf, FPCIE_PREF_BASE_UPPER32_REG, 0x0); #endif cmdstat |= FPCIE_COMMAND_MEMORY; } else { /* We don't support prefetchable memory for now, so disable */ FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_PREF_MEMORY_BASE_REG, 0x1000); FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_PREF_MEMORY_LIMIT_REG, 0x0); if (prefechable_64 == FPCIE_PREF_RANGE_TYPE_64) { FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_PREF_BASE_UPPER32_REG, 0x0); FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_PREF_LIMIT_UPPER32_REG, 0x0); } } if (pci_io->exist_flg & FPCIE_REGION_EXIST_FLG) { /* Round I/O allocator to 4KB boundary */ FPcieAutoRegionAlign(pci_io, 0x1000); FPcieEcamWriteConfig8bit(instance_p->config.ecam, bdf, FPCIE_IO_BASE_REG, (pci_io->bus_lower & 0x0000f000) >> 8); FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_IO_BASE_UPPER16_REG, (pci_io->bus_lower & 0xffff0000) >> 16); cmdstat |= FPCIE_COMMAND_IO; } /* Enable memory and I/O accesses, enable bus master */ FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_COMMAND_REG, cmdstat | FPCIE_COMMAND_MASTER); } void FPcieAutoPostscanSetupBridge(FPcie *instance_p, u32 bdf, int sub_bus) { struct FPcieRegion *pci_mem; struct FPcieRegion *pci_prefetch; struct FPcieRegion *pci_io; pci_mem = &(instance_p->mem); pci_prefetch = &(instance_p->mem_prefetch); pci_io = &(instance_p->mem_io); /* Configure bus number registers */ FPcieEcamWriteConfig8bit(instance_p->config.ecam, bdf, FPCIE_SUBORDINATE_BUS_REG, sub_bus);//配置一下subordinate-bus,可能在固件下不一定必须用 if (pci_mem->exist_flg & FPCIE_REGION_EXIST_FLG) { /* Round memory allocator to 1MB boundary */ FPcieAutoRegionAlign(pci_mem, 0x100000); FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_MEMORY_LIMIT_REG, (pci_mem->bus_lower - 1) >> 16); } if (pci_prefetch->exist_flg & FPCIE_REGION_EXIST_FLG) { u16 prefechable_64; FPcieEcamReadConfig16bit(instance_p->config.ecam, bdf, FPCIE_PREF_MEMORY_LIMIT_REG, &prefechable_64); prefechable_64 &= FPCIE_PREF_RANGE_TYPE_MASK; /* Round memory allocator to 1MB boundary */ FPcieAutoRegionAlign(pci_prefetch, 0x100000); FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_PREF_MEMORY_LIMIT_REG, (pci_prefetch->bus_lower - 1) >> 16); if (prefechable_64 == FPCIE_PREF_RANGE_TYPE_64) #ifdef CONFIG_SYS_PCI_64BIT FPcieEcamWriteConfig32bit(instance_p->config.ecam, bdf, FPCIE_PREF_LIMIT_UPPER32_REG, (pci_prefetch->bus_lower - 1) >> 32); #else FPcieEcamWriteConfig32bit(instance_p->config.ecam, bdf, FPCIE_PREF_LIMIT_UPPER32_REG, 0x0); #endif } if (pci_io->exist_flg & FPCIE_REGION_EXIST_FLG) { /* Round I/O allocator to 4KB boundary */ FPcieAutoRegionAlign(pci_io, 0x1000); FPcieEcamWriteConfig8bit(instance_p->config.ecam, bdf, FPCIE_IO_LIMIT_REG, ((pci_io->bus_lower - 1) & 0x0000f000) >> 8); FPcieEcamWriteConfig16bit(instance_p->config.ecam, bdf, FPCIE_IO_LIMIT_UPPER16_REG, ((pci_io->bus_lower - 1) & 0xffff0000) >> 16); } } int FPcieHoseProbeBus(FPcie *instance_p, u32 bdf) { int sub_bus; int ret; instance_p->bus_max = instance_p->bus_max + 1; sub_bus = instance_p->bus_max; FPcieAutoPrescanSetupBridge(instance_p, bdf, sub_bus); FPcieScanBus(instance_p, sub_bus, bdf); sub_bus = instance_p->bus_max; FPcieAutoPostscanSetupBridge(instance_p, bdf, sub_bus); return sub_bus; } /* * HJF: Changed this to return int. I think this is required * to get the correct result when scanning bridges */ int FPcieAutoConfigDevice(FPcie *instance_p, u32 bdf) { u16 class = 0; struct FPcieRegion *pci_mem; struct FPcieRegion *pci_prefetch; struct FPcieRegion *pci_io; bool enum_only = false; int n; #ifdef CONFIG_PCI_ENUM_ONLY enum_only = true; #endif pci_mem = &(instance_p->mem); pci_prefetch = &(instance_p->mem_prefetch); pci_io = &(instance_p->mem_io); FPcieEcamReadConfig16bit(instance_p->config.ecam, bdf, FPCIE_CLASS_DEVICE_REG, &class) ;//读取classcode编号 switch (class) { case FPCI_CLASS_BRIDGE_PCI: FPcieAutoSetupDevice(instance_p, bdf, 2, pci_mem, pci_prefetch, pci_io, enum_only); n = FPcieHoseProbeBus(instance_p, bdf); if (n < 0) { return n; } break; case FPCI_CLASS_BRIDGE_CARDBUS: /* * just do a minimal setup of the bridge, * let the OS take care of the rest */ FPcieAutoSetupDevice(instance_p, bdf, 0, pci_mem, pci_prefetch, pci_io, enum_only); FPCIE_DEBUG_I("PCI auto config: Found P2CardBus bridge, device %d.", FPCIE_DEV(bdf)); break; case FPCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */ FPCIE_DEBUG_I("PCI auto config: Found PowerPC device."); default: FPcieAutoSetupDevice(instance_p, bdf, 6, pci_mem, pci_prefetch, pci_io, enum_only); break; } return FT_SUCCESS; } FError FPcieBindBusDevices(FPcie *instance_p, u32 bus_num, u32 parent_bdf, struct FPcieBus *bus) { int dev_count = 0; u16 vendor, device; u8 header_type; s32 bdf, end; bool found_multi; FError ret; u8 class_show; u32 dev_exp_cap, bus_exp_cap, dev_ext_ari_cap; u32 data; char buf_bdf_print[20]; found_multi = false; end = FPCIE_BDF(bus_num, FPCIE_CFG_MAX_NUM_OF_DEV - 1, FPCIE_CFG_MAX_NUM_OF_FUN - 1); /* 使用bus的seq成员来进行扫描,其实相当于secondory_bus号 */ for (bdf = FPCIE_BDF(bus_num, 0, 0); bdf <= end; bdf += FPCIE_BDF(0, 0, 1)) { u32 class; /* phytium old pci ip version, need skip in some bus */ if (instance_p->config.need_skip) { if (FPcieSkipDevice(instance_p->config.ecam, parent_bdf) == FPCIE_NEED_SKIP) { continue; } } if (!FPCIE_FUNC(bdf)) { found_multi = false; } if (FPCIE_FUNC(bdf) && !found_multi) { continue; } /* Check only the first access, we don't expect problems */ FPcieEcamReadConfig16bit(instance_p->config.ecam, bdf, FPCIE_VENDOR_REG, &vendor) ; if (vendor == 0xffff || vendor == 0x0000) { continue; } FPcieEcamReadConfig8bit(instance_p->config.ecam, bdf, FPCIE_HEADER_TYPE_REG, &header_type) ; if (!FPCIE_FUNC(bdf)) { found_multi = header_type & 0x80; } /* 读取deviceid, classcode */ FPcieEcamReadConfig16bit(instance_p->config.ecam, bdf, FPCIE_DEVICE_ID_REG, &device) ; FPcieEcamReadConfig32bit(instance_p->config.ecam, bdf, FPCI_CLASS_REVISION, &class) ; class >>= 8; FPcieEcamReadConfig8bit(instance_p->config.ecam, bdf, FPCIE_CLASS_CODE_REG, &class_show) ; if (parent_bdf == 0xffffffff) { strcpy(buf_bdf_print, "root-controller"); } else { sprintf(buf_bdf_print, "pci_%x:%x:%x", FPCIE_BUS(parent_bdf), FPCIE_DEV(parent_bdf), FPCIE_FUNC(parent_bdf)); } printf(" %02x:%02x.%02x - %04lx:%04lx %s", FPCIE_BUS(bdf), FPCIE_DEV(bdf), FPCIE_FUNC(bdf), vendor, device, buf_bdf_print); printf(" 0x%.2x (%s)\n", (int)class_show, FPcieClassStr(class_show)); /* ARI function handle */ /* step 1: detect if PCI Express Device */ ret = FPcieFindCapability(instance_p, bdf, PCIE_CAP, FPCI_CAP_ID_EXP, &dev_exp_cap); if (ret == 0 && dev_exp_cap > 0) { /* step2: check if the device is an ARI device */ ret = FPcieFindCapability(instance_p, bdf, PCIE_ECAP, FPCI_EXT_CAP_ID_ARI, &dev_ext_ari_cap); if (ret == 0 && dev_ext_ari_cap > 0) { /* step3: check if its parent supports ARI forwarding */ ret = FPcieFindCapability(instance_p, parent_bdf, PCIE_CAP, FPCI_CAP_ID_EXP, &bus_exp_cap); /* config bus ARI forwarding */ if (ret == 0 && bus_exp_cap > 0) { FPcieEcamReadConfig32bit(instance_p->config.ecam, parent_bdf, bus_exp_cap + FPCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET, &data); if ((data & FPCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) { /* step4: ARI forwarding support in bridge, so enable it */ FPcieEcamReadConfig32bit(instance_p->config.ecam, parent_bdf, bus_exp_cap + FPCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, &data); if (data & FPCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING == 0) { data |= FPCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING; FPcieEcamWriteConfig32bit(instance_p->config.ecam, parent_bdf, bus_exp_cap + FPCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, data); } } } } } bus->ChildN[dev_count] = bdf; dev_count++; //这里可以将当前的device,保存到全局变量中,供别的驱动来查询。 instance_p->scaned_bdf_array[instance_p->scaned_bdf_count] = bdf; (instance_p->scaned_bdf_count)++; } bus->ChildCount = dev_count; return FT_SUCCESS; } FError FPcieScanBus(FPcie *instance_p, u32 bus_num, u32 parent_bdf) { int i = 0; s32 bdf; struct FPcieBus bus; bus.ChildCount = 0; /* scan bus 0 device */ FPcieBindBusDevices(instance_p, bus_num, parent_bdf, &bus); if (bus.ChildCount > 0) { for (i = 0; i < bus.ChildCount; i++) { bdf = bus.ChildN[i]; FPcieAutoConfigDevice(instance_p, bdf); } } instance_p->is_scaned = 1; //表示已经扫描完成 }