继续来分析PCI设备的搜索过程,下面就是通过调用搜索程序来实现的。
for(i = 0, pb = _pci_head; i < pci_roots; i++, pb = pb->next) {
_pci_scan_dev(pb, i, 0, init);
}
接着去看看函数_pci_scan_dev的实现:
static void
_pci_scan_dev(struct pci_device *dev, int bus, int device, int initialise)
{
for(; device < 32; device++) {
_pci_query_dev (dev, bus, device, initialise);
}
}
上面是根据PCI的总线定义,可以知道它最多有32个设备,因此就需要把这32个设备进行枚举。下面的搜索过程是通过PCI的标识来进行的,因为每个PCI插槽存在设备时,它的ID不为0xFFFF FFFF,根据这样的特征,就可以知道是否存在PCI设备了。
static void
_pci_query_dev (struct pci_device *dev, int bus, int device, int initialise)
{
pcitag_t tag;
pcireg_t id;
pcireg_t misc;
tag = _pci_make_tag(bus, device, 0);
if (!_pci_canscan (tag))
return;
上面组成PCI标识地址。
if (_pciverbose >= 2)
_pci_bdfprintf (bus, device, -1, "probe...");
id = _pci_conf_read(tag, PCI_ID_REG);
上面读取PCI的ID标识。
if (_pciverbose >= 2) {
PRINTF ("completed\n");
}
if (id == 0 || id == 0xffffffff) {
return;
}
上面判断是否存在PCI设备,如果不存在就返回。
misc = _pci_conf_read(tag, PCI_BHLC_REG);
if (PCI_HDRTYPE_MULTIFN(misc)) {
int function;
for (function = 0; function < 8; function++) {
tag = _pci_make_tag(bus, device, function);
id = _pci_conf_read(tag, PCI_ID_REG);
if (id == 0 || id == 0xffffffff) {
return;
}
_pci_query_dev_func (dev, tag, initialise);
}
}
else {
_pci_query_dev_func (dev, tag, initialise);
}
上面读取PCI信息,并分类PCI设备,然后保存到PCI设备列表里。
}
找到所有设备之后,就需要把PCI的总线带宽分配,并分别分配设备的内存映射空间。通过下面的程序实现的:
static void
_setup_pcibuses(int initialise)
{
struct pci_bus *pb;
struct pci_device *pd;
unsigned int def_ltim, max_ltim;
int i;
SBD_DISPLAY ("PCIS", CHKPNT_PCIS);
for(pb = _pci_bushead; pb != NULL; pb = pb->next) {
if (pb->ndev == 0)
return;
if (initialise) {
/* convert largest minimum grant time to cycle count */
/*XXX 66/33 Mhz */ max_ltim = pb->min_gnt * 33 / 4;
/* now see how much bandwidth is left to distribute */
if (pb->bandwidth <= 0) {
if (_pciverbose) {
_pci_bdfprintf (pb->bus, -1, -1,
"WARN: total bandwidth exceeded\n");
}
def_ltim = 1;
}
else {
/* calculate a fair share for each device */
def_ltim = pb->bandwidth / pb->ndev;
if (def_ltim > pb->max_lat) {
/* would exceed critical time for some device */
def_ltim = pb->max_lat;
}
/* convert to cycle count */
def_ltim = def_ltim * 33 / 4;
}
/* most devices don't implement bottom three bits */
def_ltim = (def_ltim + 7) & ~7;
max_ltim = (max_ltim + 7) & ~7;
pb->def_ltim = MIN (def_ltim, 255);
pb->max_ltim = MIN (MAX (max_ltim, def_ltim), 255);
}
}
SBD_DISPLAY ("PCIR", CHKPNT_PCIR);
_pci_hwreinit ();
/* setup the individual device windows */
SBD_DISPLAY ("PCIW", CHKPNT_PCIW);
for(i = 0, pd = _pci_head; i < pci_roots; i++, pd = pd->next) {
_pci_setup_windows (pd);
}
}
到这里,就已经把PCI局部总线上的设备配置完成。PCI总线配置是非常复杂的,不但有众多的设备,还有内存空间的分配,还有设备的DMA选择,还有桥设备在上面的转换等等。 查看本文来源