⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 csbpci.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      pci.c
//
//      PCI probing routine
//
// Author(s):    Michael Kelly, Cogent Computer Systems, Inc.
// Contributors: 
// Date:         02/05/2002
// Description:  This file contains the generic PCI probe routine
//				 and configuration accesses as well as a simple test		
//
//--------------------------------------------------------------------------

#include "config.h"
#include "cpuio.h"
#include "stddefs.h"
#include "genlib.h"
#include "pci.h"
#include "cpu_pci.h"	// bring in CPU specific defines for PCI

//--------------------------------------------------------------------------
// Function Prototypes
//
int pci_probe_bus(void);
int pci_tst(int argc,char *argv[]);

// external functions
extern ulong pci_cfg_read_dword (ulong bus, ulong dev_func, ulong offset);
extern ushort pci_cfg_read_word (ulong bus, ulong dev_func, ulong offset);
extern uchar pci_cfg_read_byte (ulong bus, ulong dev_func, ulong offset);
extern void pci_cfg_write_dword (ulong bus, ulong dev_func, ulong offset, ulong data);
extern void pci_cfg_write_word (ulong bus, ulong dev_func, ulong offset, ushort data);
extern void pci_cfg_write_byte (ulong bus, ulong dev_func, ulong offset, uchar  data);

extern void set_cfg_type_id(ulong bus, ulong dev_func);
extern int pci_master_abort(void);
extern void udelay(int), pci_init(void);

// globals to keep track of the pci devices we find
pci_device_structure pci_dev_info[PCI_DEV_MAX];
ulong next_bus, mem_base, io_base, pci_dev;
// global shared memory base address for all PCI devices
ulong sh_mem_base;

//--------------------------------------------------------------------------
// pci_probe_bus()
// 
// The following function scans the PCI bus and fills in a static structure
// with the various ID's and the BAR's.  This function is reentrant to 
// handle bus bridges.  It returns 0 if no error.  
//
// NOTES:
// 1. This function does not enable the devices it finds.  It merely assigns
//    address space to them and stores the information in the pci_dev_info 
//    structure.  It is up to the respective driver to fully setup each
//    device.  
// 2. The one exception to note 2. above is that the code will setup and
//    enable any bridges it finds.
// 3. All Memory space across bridges will be assigned as non-prefetchable.
//    We do not have enough memory space to consider true memory type devices
//    versus memory mapped I/O registers.  For simplicity and safety, we 
//    assume that all MEM space is not prefetchable.
// 4. We do not support bridges with only 64KB IO windows.  This does not seem
//    to be a limitation of most modern bridges.
// 5. This function will assign space to devices as it finds them without
//    regard to fragmentation.  That means if we find a 1Mbyte device (the
//    minimum we assign for memory) and then find a 16Mbyte device, the 1M
//    device will start at mem_base while the 16M device will start at
//    mem_base + 16M.  The space from 1M to 16M will be lost.
// 5. This function is reentrant to handle pci-pci bridges.

int pci_probe_bus(void){

	uchar temp8;
	ushort temp16;
	ulong temp32;
	ulong bus, dev, func;
	ulong bar_size, bar_type, bar_boundry, bar;
	ulong old_bus, old_mem_base, old_io_base;

	bus = next_bus++;

	// scan the chosen bus for devices
	for (dev = DEV_START; dev < DEV_START + 7; dev++){
		for (func = 0; func < 7; func++){

			// read the vendor ID.  A 0xFFFF means no device
			temp16 = pci_cfg_read_word (bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_VEN_ID_REG);
#ifdef PCI_DBG
			printf("PCI Probe Read %04x\n", temp16);
#endif
			if (temp16 != 0xFFFF){

				// got a live one! Now see if it's a bridge
				temp8 = pci_cfg_read_byte (bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_CLASS_REG);
				if (temp8 == PCI_CLASS_BRIDGE){

#ifdef PCI_DBG
				printf("PCI Probe Found Bridge\n");
#endif
					// if it's not a pci to pci bridge bail out.
					if (pci_cfg_read_byte (bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_SUBCLASS_REG) != PCI_SUBCLASS_BRIDGE_PCI_PCI) 
						return PCI_BRIDGE_TYPE_ERR;
					 
					else { // probe it

						// save the info for the bus we are on - we'll need this when we return
						old_bus = bus;
						old_mem_base = mem_base;
						old_io_base = io_base;

						// setup the bridge's bus registers so we can probe the other side
						pci_cfg_write_byte(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_PRI_BUS_REG, bus);
						pci_cfg_write_byte(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_SEC_BUS_REG, next_bus);

						// reenter pci_probe_bus to scan the next bus
						temp32 = pci_probe_bus();
						if (temp32) return temp32;	// non-zero means something went wrong

						bus = old_bus;

						// after returning from a bridge probe, we need to set the subordinate bus number to
						// the highest bus found on the other side of this bridge.  That will be next_bus -1.
						pci_cfg_write_byte(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_SUB_BUS_REG, (next_bus - 1));

						// fill in the bridge registers
						// round up the final mem_base if necessary
						if (mem_base & 0x000fffff) mem_base = (mem_base + 0x00100000) & 0xfff00000;

						// disable prefetch bys setting the base higher than the limit
						pci_cfg_write_word(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_PREFETCH_BASE_REG, 0xFFFF);
						pci_cfg_write_word(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_PREFETCH_LIMIT_REG, 0x0000);

						// rounded mem_base is the beginning of the bridge's MEM window, mem_base is the end
						pci_cfg_write_word(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_MEM_BASE_REG, ((old_mem_base >> 16) & 0xFFFF));
						pci_cfg_write_word(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_MEM_LIMIT_REG, ((mem_base  >> 16) & 0xFFFF));

						// enable the bridge to handle memory accesses and mastering
						temp16 = pci_cfg_read_word (bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_CMD_REG);
						temp16 = temp16 | PCI_CFG_CMD_MEM | PCI_CFG_CMD_MASTER;
						pci_cfg_write_word (bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_CMD_REG, temp16);

						// fill in the bridge registers
						// round up the final io_base if necessary
						if (io_base & 0x00000fff) io_base = (io_base + 0x00001000) & 0xfffff000;

						// make sure this bridge supports 32-bit IO addressing
						if ((pci_cfg_read_byte(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_IO_BASE_LO_REG) & 0x0f) != 0x01)
							return PCI_BRIDGE_TYPE_ERR;

						// rounded io_base is the beginning of the bridge's IO window, io_base is the end
						pci_cfg_write_word(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_IO_BASE_HI_REG, ((old_io_base >> 16) & 0xFFFF));
						pci_cfg_write_word(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_IO_LIMIT_HI_REG, ((io_base  >> 16) & 0xFFFF));

						// enable the bridge to handle io accesses and mastering
						temp16 = pci_cfg_read_word (bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_CMD_REG);
						temp16 = temp16 | PCI_CFG_CMD_IO | PCI_CFG_CMD_MASTER;
						pci_cfg_write_word (bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_CMD_REG, temp16);

					} // else - pci to pci bridge
				} // if bridge
				else { // not a bridge
#ifdef PCI_DBG
					printf("PCI Probe Found Non-Bridge\n");
#endif
					pci_dev_info[pci_dev].ven_id = pci_cfg_read_word(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_VEN_ID_REG);
					pci_dev_info[pci_dev].dev_id = pci_cfg_read_word(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_DEV_ID_REG);
					pci_dev_info[pci_dev].class = pci_cfg_read_byte(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_CLASS_REG);
					pci_dev_info[pci_dev].subclass = pci_cfg_read_byte(bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_SUBCLASS_REG);

#ifdef PCI_DBG
					printf("PCI Probe Vendor ID = %08x\n", pci_dev_info[pci_dev].ven_id);
					printf("PCI Probe Device ID = %08x\n", pci_dev_info[pci_dev].dev_id);
					printf("PCI Probe Class 	= %08x\n", pci_dev_info[pci_dev].class);
					printf("PCI Probe Subclass 	= %08x\n", pci_dev_info[pci_dev].subclass);
#endif
					// scan each BAR and assign memory or io as appropriate
					for (bar = 0; bar < 6; bar++){
						// Write all 1's to the BAR and then read back to get size, type
						pci_cfg_write_dword(bus, PCI_MAKE_DEV_FUNC(dev, func), ((bar << 2) + PCI_CFG_BAR0_REG), 0xffffffff);
						bar_size = pci_cfg_read_dword(bus, PCI_MAKE_DEV_FUNC(dev, func), ((bar << 2) + PCI_CFG_BAR0_REG));

						if (bar_size != 0) {
							// is it IO or MEM?
							if (bar_size & 0x01){

								// assign a minimum of 4K for I/O
								if(bar_size < 0x00001000) bar_size = 0xfffff000;

								// save the boundry as a mask for use later
								bar_boundry = ~(bar_size & 0xfffffffc);

								// IO - convert raw bar size to final size
								bar_size = bar_boundry + 1;

								// sanity check it against maximum size IO we allow
								if (bar_size > PCI_IO_BAR_MAX) return PCI_IO_BAR_MAX_ERR;

								// All allocation must occur on the boundry specificed by the size
								if (io_base & ~bar_boundry){
									io_base = io_base + bar_size;
									io_base = io_base & ~bar_boundry;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -