?? pciiomaplib.c
字號:
/* pciIomapLib.c - Support for PCI drivers *//* Copyright 1984-2002 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------01g,25apr02,to use more appropriate macro.01f,03dec01,rec fix compiler warnings01e,10sep01,jb Fix PCI memory mapping01d,17may00,jgn fix pciFindDevice.01c,08mar00,jpd changed include of pciIomapLib.h to be from local directory.01b,17feb00,jpd made more style-guide-conformant.01a,13jan00,pr adapted from cma220.*//*DESCRIPTIONThis library is PCI Revision 2.1 compliant.This module contains routines to support PCI bus mapped on IO address spacefor x86 and PowerPC architecture. Functions in this library should not becalled from the interrupt level, except pciInt(), since it uses a mutualexclusion semaphore for consecutive register access.The functions addressed here include: - Initialize the library. - Locate the device by deviceID and vendorID. - Locate the device by classCode. - Generate the special cycle. - Access its configuration registers. - Connect a shared interrupt handler. - Disconnect a shared interrupt handler. - Master shared interrupt handler.There are functions to access the IO address space. In x86 architecture,they are sysInXXX() and sysOutXXX(). Macro PCI_IN_XXX() and PCI_OUT_XXX()are provided to use other IO address space functions.The PCI IO base address is defined by the static variable pciIoBase.Each new IO space will increment this variable (see functionpciAllocateIOSpace().The V3 chip provides three windows through which accesses can be made bysystem bus masters to the PCI bus. We use overlaping windows so to accessthe IO space the mapping needs to be changed otherwise accesses will result ina data error. For this window 1 is re-used and remapped to CPU_PCI_CNFG_ADRS.However, before that window 0 must be remapped to ensure that applicationsoftware can access the address space normally assigned to window 1 whilewindow 1 is re-used for configuration cycles (cf. v3OpenConfigWindow())Shared PCI interrupt are supported by three functions: pciInt(),pciIntConnect(), pciIntDisconnect(). pciIntConnect() adds the specifiedinterrupt handler to the link list and pciIntDisconnect() removes it fromthe link list. Master interrupt handler pciInt() executes these interrupthandlers in the link list for a PCI interrupt. Each interrupt handler mustcheck the device dependent interrupt status bit to determine the source ofthe interrupt, since it simply execute all interrupt handlers in the linklist. pciInt() should be attached by intConnect() function in the BSPinitialization with its parameter. The parameter is an IRQ associatedto the PCI interrupt.The maximum number of Type-1 Configuration Space buses supported in the 2.1Specifications is 256 (0x00 - 0xFF), far greater than most systems currentlysupport. Most buses are numbered sequentially from 0. An optional definecalled PCI_MAX_BUS may be declared in config.h to override the defaultdefinition of 256. Similarly, the default number of devices and functionsmay be overriden by defining PCI_MAX_DEV and/or PCI_MAX_FUNC. Note thatthe number of devices applies only to bus zero, all others being restrictedto 16 by the 2.1 spec.*/#if defined(INCLUDE_PCI)#include "vxWorks.h"#include "config.h"#include "dllLib.h"#include "sysLib.h"#include "stdio.h"#include "stdlib.h"#include "string.h"#include "intLib.h"/* * We currently wish to include this from locally rather than from * there as that version is out-dated. However, as it has been included * in sysLib.c already, this will do no harm. */#include "pciIomapLib.h"/* defines *//* * The following defines specify, by default, the maximum number of busses, * devices and functions allowed by the PCI 2.1 Specification. * * Any or all may be overriden by defining them in config.h. */#ifndef PCI_MAX_BUS# define PCI_MAX_BUS 256#endif /* PCI_MAX_BUS */#ifndef PCI_MAX_DEV# define PCI_MAX_DEV 21#endif /* PCI_MAX_DEV */#ifndef PCI_MAX_FUNC# define PCI_MAX_FUNC 8#endif /* PCI_MAX_FUNC *//* globals */STATUS pciLibInitStatus = NONE; /* initialization done */DL_LIST pciIntList[PCI_IRQ_LINES]; /* link list of int handlers */int pciConfigMech = NONE; /* 1=mechanism-1, 2=mechanism-2 */static UINT32 pciIoBase = PCI_IO_ADRS; /* value for start of PCI IO */static UINT32 pciMemBase = PCI_MEM_ADRS;/* value for start of PCI memory */#define MAX(val1, val2) ( ((val1) > (val2)) ? val1 : val2 )#define DEFAULT_MEMORY_ALIGNMENT 0x1000#define DEFAULT_IO_ALIGNMENT 0x800/* locals */LOCAL int pciConfigAddr0; /* config-addr-reg, CSE-reg*/LOCAL int pciConfigAddr1; /* config-data-reg, forward-reg */LOCAL int pciConfigAddr2; /* not-used, base-addr *//* V3 access macros */#define V3_WRITE16(o,v) (*(volatile UINT16 *)(V3_BASE + (UINT32)(o)) = \ (UINT16)(v))#define V3_READ16(o) (*(volatile UINT16 *)(V3_BASE + (UINT32)(o)))#define V3_WRITE32(o,v) (*(volatile UINT32 *)(V3_BASE + (UINT32)(o)) = \ (UINT32)(v))#define V3_READ32(o) (*(volatile UINT32 *)(V3_BASE + (UINT32)(o)))/********************************************************************************* align - returns an aligned value** RETURNS: aligned value*/static unsigned int align ( unsigned int val, /* value to align */ unsigned int align ) { /* * Some heuristics: * if the value is zero, it is aligned, no matter what the size is. */ if (val == 0) return val; /* if the value is less than the alignment, return the alignment */ if (val < align) return align; /* finally, if there is need to move the value upwards, do so... */ if ((val & ~(align - 1)) != 0) return (((val) + ((align) - 1)) & ~((align) - 1)); else return val; }/********************************************************************************* v3OpenConfigWindow - open V3 configuration window** RETURNS: N/A*/void v3OpenConfigWindow(void) { /* * Set up base0 to see all 512Mbytes of memory space (not * prefetchable), this frees up base1 for re-use by configuration * memory */ V3_WRITE32 (V3_LB_BASE0, ((INTEGRATOR_PCI_BASE & 0xFFF00000) | 0x90 | V3_LB_BASE_M_ENABLE)); /* * Set up base1 to point into configuration space, note that MAP1 * register is set up by pciMakeConfigAddress(). */ V3_WRITE32 (V3_LB_BASE1, ((CPU_PCI_CNFG_ADRS & 0xFFF00000) | 0x40 | V3_LB_BASE_M_ENABLE)); }/********************************************************************************* v3CloseConfigWindow - close V3 configuration window** RETURNS: N/A*/void v3CloseConfigWindow(void) { /* Reassign base1 for use by prefetchable PCI memory */ V3_WRITE32 (V3_LB_BASE1, (((INTEGRATOR_PCI_BASE + SZ_256M) & 0xFFF00000) | 0x84 | V3_LB_BASE_M_ENABLE)); V3_WRITE16 (V3_LB_MAP1, (((INTEGRATOR_PCI_BASE + SZ_256M) & 0xFFF00000) >> 16) | 0x0006); /* And shrink base0 back to a 256M window (NOTE: MAP0 already correct) */ V3_WRITE32 (V3_LB_BASE0, ((INTEGRATOR_PCI_BASE & 0xFFF00000) | 0x80 | V3_LB_BASE_M_ENABLE)); }/********************************************************************************* pciMapInterrupt - map a PCI interrupt** This routine caclculates the interrupt number that this slot/pin* combination will use.** RETURNS: board-specific interrupt number*/UINT8 pciMapInterrupt ( UINT8 pin, /* pin number (A=1, B=2, C=3, D=4) */ UINT8 slot /* slot number (IDSEL = slot + 11) */ ) {#define INTA INT_LVL_PCI_0#define INTB INT_LVL_PCI_1#define INTC INT_LVL_PCI_2#define INTD INT_LVL_PCI_3 /* * DANGER! For now this is the SDM interrupt table... */ char irq_tab[12][4] = { /* INTA INTB INTC INTD */ {INTA, INTB, INTC, INTD}, /* idsel 20, slot 9 */ {INTB, INTC, INTD, INTA}, /* idsel 21, slot 10 */ {INTC, INTD, INTA, INTB}, /* idsel 22, slot 11 */ {INTD, INTA, INTB, INTC}, /* idsel 23, slot 12 */ {INTA, INTB, INTC, INTD}, /* idsel 24, slot 13 */ {INTB, INTC, INTD, INTA}, /* idsel 25, slot 14 */ {INTC, INTD, INTA, INTB}, /* idsel 26, slot 15 */ {INTD, INTA, INTB, INTC}, /* idsel 27, slot 16 */ {INTA, INTB, INTC, INTD}, /* idsel 28, slot 17 */ {INTB, INTC, INTD, INTA}, /* idsel 29, slot 18 */ {INTC, INTD, INTA, INTB}, /* idsel 30, slot 19 */ {INTD, INTA, INTB, INTC} /* idsel 31, slot 20 */ }; /* if PIN = 0, default to A */ if (pin == 0) pin = 1; /* return the magic number */ return irq_tab[slot - 9][pin - 1]; }/********************************************************************************* pciAllocateMemSpace - allocate space in PCI memory** This routine allocates space within PCI memory space.** RETURNS: Where in PCI memory allocated** NOTE: Calling this code has a side effect of moving the global* Memory base on.*/static unsigned int pciAllocateMemSpace ( unsigned int size ) { unsigned int alignto; unsigned int base; /* align in minimum sized chunks of DEFAULT_MEMORY_ALIGNMENT */ alignto = MAX (size, DEFAULT_MEMORY_ALIGNMENT); base = align (pciMemBase, alignto); pciMemBase = base + size; return base; }/********************************************************************************* pciAllocateIOSpace - allocate space in PCI I/O memory** This routine allocates space requested within the PCI I/O space.** RETURNS: where in PCI memory allocated** NOTE: Calling this code has a side effect of moving the global* I/O base on.*/static unsigned int pciAllocateIOSpace ( unsigned int size ) { unsigned int alignto; unsigned int base; /* align in minimum sized chunks of DEFAULT_IO_ALIGNMENT */ alignto = MAX (size, DEFAULT_IO_ALIGNMENT); base = align (pciIoBase, alignto); pciIoBase = base + size; return base; }/********************************************************************************* pciAllocateInterrupt - allocate an interrupt number** This routine allocates an interrupt number.** RETURNS: N/A*/void pciAllocateInterrupt ( int bus, /* bus number */ int slot, /* device number */ int func /* function number */ ) { char pin; unsigned char interrupt; /* read the interrupt pin from the device */ pciConfigInByte (bus, slot, func, PCI_CFG_DEV_INT_PIN, &pin); /* work out the interrupt number from the slot/pin */ interrupt = pciMapInterrupt (pin, slot); /* write it to the device (this will be read later by a device driver) */ pciConfigOutByte (bus, slot, func, PCI_CFG_DEV_INT_LINE, interrupt); }/********************************************************************************* pciAssignResources - assign PCI resources** This routine will attempt to glean resource requirements from the* device specified.** RETURNS: N/A*/void pciAssignResources ( int bus, /* bus number */ int slot, /* device number */ int func /* function number */ ) { unsigned int offset = PCI_MEM_BAR; unsigned int base, mask, size; int i, barFlag = 0; /* * set up the bus, slot and func * * Disable PCI I/O and memory accesses */ pciConfigOutWord (bus, slot, func, PCI_CFG_COMMAND, 0); /* allocate an irq number */ pciAllocateInterrupt (bus, slot, func); /* Scan each of the BARS for this device */ for (i = 0; i < PCI_MAX_BAR; i++) { /* write PCI_INVALID to BAR to get size, then read it back */ pciConfigOutLong (bus, slot, func, offset, PCI_INVALID); pciConfigInLong (bus, slot, func, offset, (int *) &base); /* check if this is an implemented BAR (size != 0) */ if (base != 0) { /* Assign some PCI memory (IO or Memory) space to this BAR */ if (base & PCI_CMD_IO_ENABLE) { /* -- IO space BAR -- * * The bottom 2 bits of the BAR for PCI IO look like this: * 0 must be 1 (0 = memory, 1 = IO) * 1 reserved * * figure out how much memory is wanted */ base &= (~0x3); mask = (~base << 1) | 0x1; size = (mask & base) & 0xFFFFFFFF; /* allocate (aligned) space in IO */ base = pciAllocateIOSpace (size); pciConfigOutLong(bus, slot, func, offset, base | 0x1); barFlag |= PCI_CMD_IO_ENABLE; } else { /* -- MEM space BAR -- * * WARNING: we assume only one type of memory - dangerous! */ unsigned int type; /* * The bottom 4 bits of the BAR for PCI memory look like this: * 0 must be zero (0 = memory, 1 = IO) * 1:2 type of space needed * (00 = 32 bit, 01 = below 1M, 10 = 64 bit address) * 3 prefetchable */ type = base & 0x6; base &= (~0xf); mask = (~base << 1) | 0x1; size = (mask & base) & 0xFFFFFFFF; /* cope (or rather don't) with different flavours of memory */ switch (type) { case 0x00: /* 32 bit */ break; case 0x02: /* below 1M */ continue; case 0x04: /* 64 bit */ offset += 4; continue; default: continue; } /* allocate some (aligned) space in PCI memory */ base = pciAllocateMemSpace (size); pciConfigOutLong(bus, slot, func, offset, base); barFlag |= PCI_CMD_MEM_ENABLE; } } /* increment the BAR offset value */ offset += 4; } /* now do the ROM stuff */ pciConfigOutLong (bus, slot, func, PCI_ROM_BAR, PCI_INVALID); pciConfigInLong (bus, slot, func, PCI_ROM_BAR, (int *) &base); if (base & 0x1) { /* valid ROM space, figure out how much it wants/needs */ base &= ~0x1;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -