当前位置:首页 > PMON的pci设备初始化
nextpciioaddr开始往下分配。分配的时候要注意不能超过最低可用的地址。 1. 北桥初始化
北桥提供了CPU和PCI设备相互访问的通道,实现了CPU空间和PCI空间的映射。_pci_hwinit() 具体地完成了这个工作。
所有的pci设备通过总线和pci桥联成一个树状结构。北桥Bonito是这棵树的根,与北桥直接相连的总线就是pcibus0。_pci_hwinit()的工作就是建立北桥和pcibus0的数据结构,同时进行CPU和PCI的地址映射。
int
_pci_hwinit(initialise, iot, memt) int initialise;
bus_space_tag_t iot; bus_space_tag_t memt; {
/*pcireg_t stat;*/
struct pci_device *pd; struct pci_bus *pb;
if (!initialise) { return(0); }
pci_local_mem_pci_base = PCI_LOCAL_MEM_PCI_BASE; /*
* Allocate and initialize PCI bus heads. */
/*
* PCI Bus 0 */
pd = pmalloc(sizeof(struct pci_device)); pb = pmalloc(sizeof(struct pci_bus)); if(pd == NULL || pb == NULL) { printf(\ return(-1); }
pd->pa.pa_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
pd->pa.pa_iot = pmalloc(sizeof(bus_space_tag_t)); pd->pa.pa_iot->bus_reverse = 1;
pd->pa.pa_iot->bus_base = BONITO_PCIIO_BASE_VA;
//printf(\>bus_base);
pd->pa.pa_memt = pmalloc(sizeof(bus_space_tag_t)); pd->pa.pa_memt->bus_reverse = 1;
pd->pa.pa_memt->bus_base = PCI_LOCAL_MEM_PCI_BASE; pd->pa.pa_dmat = &bus_dmamap_tag; pd->bridge.secbus = pb; _pci_head = pd;
从上面可以看到,北桥的pa.pa_flags被设置成IO_ENABLED和MEM_ENABLED,这就表示可以进行IO和内存访问。
Pa.pa_iot->bus_base被设置成BONITO_PCI_IO_BASE_VA,这个值被定义为0xbfd0.0000,它在CPU的Kseg1区间,因此是不经过TLB转换的。它的物理地址是0x1fd0.0000。Bontio规范中规定这个地址开始的1M空间是PCI的IO空间。
一个pci桥的配置体内有三个域和总线相关。分别是上游总线(Primary bus),下游总线(Secondary bus)和下级总线(Subordinate bus)。上游总线是和PCI桥相连的离CPU较近的总线。下游总线是离CPU较远的总线。下级总线则是和PCI相连的总线号最大的总线。
对于北桥来说,是没有上游总线的,而他的下游总线就是pcibus0,因此pd->bridge.secbus赋值为pb。
pb->minpcimemaddr = PCI_MEM_SPACE_PCI_BASE+0x01000000; pb->nextpcimemaddr=
PCI_MEM_SPACE_PCI_BASE+BONITO_PCILO_SIZE;
pb->minpciioaddr = PCI_IO_SPACE_BASE+0x000a000;
pb->nextpciioaddr =PCI_IO_SPACE_BASE+ BONITO_PCIIO_SIZE; pb->pci_mem_base = BONITO_PCILO_BASE_VA; //对应256M pb->pci_io_base = BONITO_PCIIO_BASE_VA; pb->max_lat = 255; pb->fast_b2b = 1; pb->prefetch = 1;
pb->bandwidth = 4000000; pb->ndev = 1;
_pci_bushead = pb;
_pci_bus[_max_pci_bus++] = pd;
Pcibus的minimemaddr被设置PCI_MEM_SPACE_PCI_BASE+0x01000000。而PCI_MEM_SPACE_PCI_BASE被定义成0,因此这个值就是16M.之所以这样做,是因为ISA设备只能使用最低16M内存空间。为了保持兼容性,这里预留最低16M的空间给ISA。
PCIbus0的nextpcimemadr被设置PCI_MEM_SPACE_PCI_BASE +
BONITO_PCILO_SIZE。这个值是192M。因此pci设备可用的空间就是16M到192M。
Pciioaddr的值是PCI_IO_SPACE_BASE+0XA000, Nextioaddr的值是
PCI_IO_SPACE_BASE+ BONITO_PCIIO_SIZE,也就是64k。因此pci设备可用的IO空间就是从地址40k到64k。
bus_dmamap_tag._dmamap_offs = 0;
/*set Bonito register*/ BONITO_PCIMAP =
BONITO_PCIMAP_WIN(0,
PCI_MEM_SPACE_PCI_BASE+0x00000000) |
BONITO_PCIMAP_WIN(1,
PCI_MEM_SPACE_PCI_BASE+0x04000000) |
BONITO_PCIMAP_WIN(2,
PCI_MEM_SPACE_PCI_BASE+0x08000000) |
BONITO_PCIMAP_PCIMAP_2;
BONITO_PCIBASE0 = PCI_LOCAL_MEM_PCI_BASE; BONITO_PCIBASE1 = PCI_LOCAL_MEM_ISA_BASE;
BONITO_PCIBASE2 = PCI_LOCAL_MEM_PCI_BASE + 0x10000000;
return(1); }
为了说明上面代码,先要讲一下Bonito中几个寄存器的含义。 为了让CPU访问PCI空间,需要将CPU空间映射到PCI空间。在内存空间256M上方有三个连续的大小均为64M的区间,分别称为PCI_Lo0, PCI_Lo1,PCI_Lo2。这三个区间可以被北桥映射到PCI以64M对齐的任意位置。映射的关系通过设置Bonito的PCIMAP寄存器。该寄存器的格式如下图。
17 12 11 6 5 0
Pci_map2 Pci_lo2 Pci_lo1 Pci_lo0 PCIMAP寄存器
Pci_lo0,pci_lo1,Pci_lo2分别是上面所说三个区间的高6位地址(bit31-26),而Pci_map2是说明映射到2G以上的空间还是2G以下的空间。因此上面给BONITO_PCIMAP赋值就将PCI_lo0,PCI_lo1,PCI_lo2分别映射到了PCI 空间的从0,64M,128M开始的地址。
另外设备进行DMA时,还要提供一种机制将PCI地址转换成CPU地址。这是通过设置Base Address Register。Bonito中一共有三个这样的寄存器pcibas0-2。Pcibas0,pcibase1都可以映射多达256M的空间。具体映射的大小还取决于pcimembasecfg的设置。Pcibase2是映射Bonito的内部寄存器,映射区间为64k大小。
寄存器pcimembasecfg在start.S中设置。我们先看它各个域的含义。
Pcimembasecfg寄存器中的各个域
各个域的含义解释如下:
a) Io:说明示映射到IO空间还是内存空间。IO=0,则是映射到内存空间,
IO=1,则映射的是IO空间。
b) Cached:如果设置成1则使用IOBC,这样可以提高性能
c) Trans/mask各5位。用于决定pci地址的27-23位。一个pci地址,先要
拿掉高三位,然后mask取反后和27-23位相与,再或上trans。
在start.S中,pcimembasecfg的io位都为0,cached为都为1,因此pcibase寄存器映射的是内存空间,并且启用高速缓存。对于pcibase1,它的trans=00000b,mask=00000b,这样pcibase0映射的空间是256M,而pcibase0,它的trans=00000b,mask=11111b,这样pcibase0映射的空间是8M,以节省PCI空间。
现在再来看上面给PCIBASE寄存器赋值的三个语句。PCIBASE0被赋值为PCI_LOCAL_MEM_PCI_BASE(被定义为0x8000.0000),PCIBASE1被赋值PCI_LOCAL_MEM_ISA_BASE(定义为0x00800000)。这样当PCI设备访问地址在0x8000.0000-0x8FFF.FFFF时这个地址会先减掉0x80000000变成要访问的内存地址。如果设备访问地址在0x0080.0000-0x008F.FFFF,经过地址转换后,会变成内存的低8M地址。PCIBASE2被赋值为PCI_LOCAL_MEM_PCI_BASE + 0x10000000(值为0x9000.0000)。因此根据pci地址值,能正确的决定要访问的空间。
完成基本的地址映射后,就是初始化pci设备了:这包括设备的搜索和资源的分配。具体的工作在_pci_scan_dev和_setup_pcibuses完成的。
_pci_scan_dev在_pci_businit中调用。下面是它的调用方式。 for(i = 0, pb = _pci_head; i < pci_roots; i++, pb = pb->next) { //_pci_scan_dev(pb, i, 0, init); _pci_scan_dev(pb, i, 8, init);//from 8+11, hu mingchang }
前面已经说过_pci_head是指向北桥的。Pci_roots在初始化北桥后被置成1,因此_pci_scan_dev在_pci_businit中只调用一次。
再来看_pci_scan_dev static void
_pci_scan_dev(struct pci_device *dev, int bus, int device, int initialise) {
for(; device < 19; device++) //to 19+11, hu mingchang { _pci_query_dev (dev, bus, device, initialise); } }
共分享92篇相关文档