Post

host-bridge is pci device BUT NOT pci bridge

查看host-bridge配置空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@A06-R08-I134-73-919XB72 openEuler-2403]# lspci -xxx -s 00:00.0
00: [86 80]  [00 2f]  [40 05]   [10 00]     02        [00 00 06]    00 00 [00] 00
    [vendor] [device] [command] [status][revision id] [class_code]         |
                                                                           |
                                                                          header type  [ type 0]
10: [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00](bar) [00 00 00 00]     [86 80]  [00 00]
                                  [cardbus CIS ptr] [subsys  [subsystem id]
                                                    vendor id]
30: 00 00 00 00 [90] 00 00 00 00 00 00 00 00 [01] 00 00
                 cap pointor                 interrupt pin
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 01 e0 ff c7 00 00 00 00 00 00 00 00 00 00 00 00
60: 05 90 02 01 00 00 00 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 10 e0 42 00 00 80 00 00 00 00 00 00 41 38 79 00
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
b0: 00 00 00 00 9e 13 00 00 00 00 00 00 06 00 00 00
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
e0: 01 00 03 00 08 00 00 00 00 00 00 00 00 00 00 00
f0: 04 00 00 00 00 00 00 00 09 00 00 00 00 00 00 00

传统方式读取pci配置空间

host bridge的提供了两个io端口0xcf8(config address), 0xcfc(config_data)

相关代码:

1
2
3
4
pci_bus_read_config_##size
  pci_read
    raw_pci_read
      pci_conf1_read
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn,
                                                int reg, int len, u32 *val)
{
        if (domain == 0 && reg < 256 && raw_pci_ops)
                return raw_pci_ops->read(domain, bus, devfn, reg, len, val);
        if (raw_pci_ext_ops)
                return raw_pci_ext_ops->read(domain, bus, devfn, reg, len, val);
        return -EINVAL;
}

//对于pci type 0/1来说
static int pci_conf1_read(unsigned int seg, unsigned int bus,
                          unsigned int devfn, int reg, int len, u32 *value)
{
        unsigned long flags;

        if (seg || (bus > 255) || (devfn > 255) || (reg > 4095)) {
                *value = -1;
                return -EINVAL;
        }

        raw_spin_lock_irqsave(&pci_config_lock, flags);
        //将 config address写入 CF8
        outl(PCI_CONF1_ADDRESS(bus, devfn, reg), 0xCF8);
        //从CFC中读取
        switch (len) {
        case 1:
                *value = inb(0xCFC + (reg & 3));
                break;
        case 2:
                *value = inw(0xCFC + (reg & 2));
                break;
        case 4:
                *value = inl(0xCFC);
                break;
        }

        raw_spin_unlock_irqrestore(&pci_config_lock, flags);

        return 0;
}

通过下面bpftrace命令抓取lspci -xxx -s 00:00.0是否会调用该函数:

1
bpftrace -e 'kfunc:vmlinux:pci_conf1_read { printf("Device: %x:%x \n", args->bus, args->devfn); }'

输出如下:

1
2
3
4
5
6
7
8
9
Device: 0:0 0
Device: 0:0 4
Device: 0:0 8
Device: 0:0 c
...
Device: 0:0 f0
Device: 0:0 f4
Device: 0:0 f8
Device: 0:0 fc

可以看到其一共读取了256 byte

参考链接

  1. Intel® Platform Innovation Framework for EFI PCI Host Bridge Resource Allocation Protocol Specification
This post is licensed under CC BY 4.0 by the author.