免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12345下一页
最近访问板块 发新帖
查看: 16261 | 回复: 46
打印 上一主题 下一主题

PCI规范里BAR寄存器的一段话看不懂 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-08-31 01:22 |只看该作者 |倒序浏览
我看的是3.0, 在S 6.2.5.1中,将MMIO方式的region,其BAR寄存器的最低4bit是这样的:

31                   4|3|2|1|0

bit 0 : 为1代表是IO区间,为0代表MMIO区间
bit [1:2] :  00表示是32位的, 10表示是64位的, 11和01这两种编码被reserve
bit 3: 代表该区间是否是prefetable

这都没问题,但是接下来它说:

The number of upper bits that a device actually implements depends on how much of the
address space the device will respond to. A 32-bit register can be implemented to support a
single memory size that is a power of 2 from 16 bytes to 2 GB. A device that wants a 1 MB
memory address space (using a 32-bit base address register) would build the top 12 bits of
the address register, hardwiring the other bits to 0.


BAR本身是32位的,除去这4位,还剩下28位, 为什么最大能表示到2G? 应该是2^8MB才对啊。
如果想实现1MB的区间,那么就实现12比特,可是2^12 == 4K,为什么是1MB呢?


琢磨了好几天还没想明白,请教一下。

论坛徽章:
0
2 [报告]
发表于 2008-08-31 11:38 |只看该作者
原帖由 albcamus 于 2008-8-31 01:22 发表
我看的是3.0, 在S 6.2.5.1中,将MMIO方式的region,其BAR寄存器的最低4bit是这样的:

31                   4|3|2|1|0

bit 0 : 为1代表是IO区间,为0代表MMIO区间
bit [1:2] :  00表示是32位的, 10表 ...

没细读过PCI的spec,不过我想可能是这样的:
1~4bit虽然不用,但只是说MMIO地址是16byte对齐的,所以BAR地址范围应该可以从0x0000 0000 ~ 0xFFFF FFF0,所以size的最大长度应该是0xFFFF FFF0接近4G,不知道为什么说这里是2G。
对于第二个问题也是一样的,1M是(1<<20),即地址线低20bit为0,故设备需要1M以上地址空间时只需要20bit~31bit高12bit中有1bit为1就可以了。这里want 1M address space我觉得应该理解为希望map到1M以上地址空间,而不是说1M长度

论坛徽章:
0
3 [报告]
发表于 2008-08-31 15:28 |只看该作者
#define  PCI_BASE_ADDRESS_MEM_MASK    (~0x0fUL)

1<<4(16byte)  --> 1<<31(2G)

static u32 pci_size(u32 base, u32 maxbase, u32 mask)
{
    u32 size = mask & maxbase;    /* Find the significant bits */
    if (!size)
        return 0;

    /* Get the lowest of them to find the decode size, and
       from that the extent.  */

    size = (size & ~(size-1)) - 1;

        ...
}


至于说1M,应该是zx_wing说的那样,译码的时候只需要上面12bit,后面的就认为是0了,
比如 00000000,0001写进去,就等价于告诉是00000000,00010000,00000000,00000000
后面的20就总为0

论坛徽章:
0
4 [报告]
发表于 2008-08-31 15:45 |只看该作者
话说回来, zx_wing大侠还有篇 iommu的论文,不知道是否放出来可以给大家学习下。

论坛徽章:
0
5 [报告]
发表于 2008-08-31 16:01 |只看该作者
原帖由 flw2 于 2008-8-31 15:28 发表
#define  PCI_BASE_ADDRESS_MEM_MASK    (~0x0fUL)

1

1<<31虽然是2G,但后面的bit还可以是1啊,所以最大应该是可以到接近4G。
cat /proc/iomem就可以看到,实际上MMIO空间肯定是在2G以上的

论坛徽章:
0
6 [报告]
发表于 2008-08-31 16:06 |只看该作者
原帖由 epegasus 于 2008-8-31 15:45 发表
话说回来, zx_wing大侠还有篇 iommu的论文,不知道是否放出来可以给大家学习下。

惭愧,我的毕业论文纯粹是为了忽悠老师好毕业的,没有实用价值。
我找时间写一篇介绍Intel IOMMU的文章吧。

论坛徽章:
0
7 [报告]
发表于 2008-08-31 16:41 |只看该作者
原帖由 zx_wing 于 2008-8-31 16:01 发表

1


一个mem bar的大小就是通过pci_size函数得来的,也是PCI标准规定的,怎么算也最多是2G,最少是16字节
而地址安排在2G以上和最大2G没任何关系,我猜应该不是PCI的标准所规定的
在x86上是这样的,在离4G比较近的地方

比如对一个1M的空间,我们写11111111,11010000,00000000,00000000,那就意味把这个1M的起始安排在0xffc00000了,也就是/proc/iomem看到的吧

论坛徽章:
0
8 [报告]
发表于 2008-08-31 17:41 |只看该作者
原帖由 flw2 于 2008-8-31 16:41 发表


一个mem bar的大小就是通过pci_size函数得来的,也是PCI标准规定的,怎么算也最多是2G,最少是16字节
而地址安排在2G以上和最大2G没任何关系,我猜应该不是PCI的标准所规定的
在x86上是这样的,在离4G比较 ...

实际上我觉得PCI spec对size的问题讲的不清楚,也可能是我读的不清楚。
flw2你指的PCI spec规定最大是2G是指al贴的那段文字吗?那么根据PCI spec规定如何获取size的方法得到的size最多就不是2G.
Sizing a 32-bit Base Address Register Example
Decode (I/O or memory) of a register is disabled via the command register before sizing a  
Base Address register.  Software saves the original value of the Base Address register, writes
0 FFFF FFFFh to the register, then reads it back.  Size calculation can be done from the
32-bit value read by first clearing encoding information bits (bit 0 for I/O, bits 0-3 for
memory), inverting all 32 bits (logical NOT), then incrementing by 1.
  The resultant 32-bit
value is the memory/I/O range size decoded by the register.  Note that the upper 16 bits of
the result is ignored if the Base Address register is for I/O and bits 16-31 returned zero
upon read.  The original value in the Base Address register is restored before re-enabling
decode in the command register of the device.   
64-bit (memory) Base Address registers can be handled the same, except that the second
32-bit register is considered an extension of the first; i.e., bits 32-63.  Software writes
0FFFFFFFFh to both registers, reads them back, and combines the result into a 64-bit value.  
Size calculation is done on the 64-bit value.

我不知道这里first clearing encoding information bits是什么意思,我的理解是低4bit都不算,这样最多只有28bit可以表示长度(就算读回来全1,再加1长度也是(1<<29)),到不了2G

论坛徽章:
0
9 [报告]
发表于 2008-08-31 18:47 |只看该作者
zzzzzzzzzs
原帖由 zx_wing 于 2008-8-31 17:41 发表

实际上我觉得PCI spec对size的问题讲的不清楚,也可能是我读的不清楚。
flw2你指的PCI spec规定最大是2G是指al贴的那段文字吗?那么根据PCI spec规定如何获取size的方法得到的size最多就不是2G.
Sizing a 3 ...

first clearing encoding information bits
应该就是指 & ~0x0f

比如0xfff00004 & ~0x0f == 0xfff00000
~0xfff00000 == 0x000fffff
0x000fffff + 1 == 1M

这是按照你贴的那段话来计算的
但是不知道是不是因为标准版本的不同还是怎样
我看的例子都是找到最低的位置为1的位(0xfff00000中的最低位), 所以这么计算的话0x00100000计算出来的大小和0xfff00000应该是一样的,而如果按照你贴的方法计算就不对了,而代码做的也是前者的方法

/* Get the lowest of them to find the decode size, and
       from that the extent.  */
    size = (size & ~(size-1)) - 1;

下面这个函数是2.6.26.3的

static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
    unsigned int pos, reg, next;
    u32 l, sz;
    struct resource *res;

    for(pos=0; pos<howmany; pos = next) {
        u64 l64;
        u64 sz64;
        u32 raw_sz;

        next = pos+1;
        res = &dev->resource[pos];
        res->name = pci_name(dev);
        reg = PCI_BASE_ADDRESS_0 + (pos << 2);
        pci_read_config_dword(dev, reg, &l);
        pci_write_config_dword(dev, reg, ~0);
        pci_read_config_dword(dev, reg, &sz);
        pci_write_config_dword(dev, reg, l);//write orig value

        if (!sz || sz == 0xffffffff)
            continue;
        if (l == 0xffffffff)
            l = 0;
        raw_sz = sz;
        if ((l & PCI_BASE_ADDRESS_SPACE) ==
                PCI_BASE_ADDRESS_SPACE_MEMORY) {
            sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
            /*
             * For 64bit prefetchable memory sz could be 0, if the
             * real size is bigger than 4G, so we need to check
             * szhi for that.
             */

            if (!is_64bit_memory(l) && !sz)
                continue;
            res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
            res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
        } else {
            sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
            if (!sz)
                continue;
            res->start = l & PCI_BASE_ADDRESS_IO_MASK;
            res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK;
        }
        res->end = res->start + (unsigned long) sz;
        res->flags |= pci_calc_resource_flags(l) | IORESOURCE_SIZEALIGN;
        if (is_64bit_memory(l)) {
            u32 szhi, lhi;

            pci_read_config_dword(dev, reg+4, &lhi);
            pci_write_config_dword(dev, reg+4, ~0);
            pci_read_config_dword(dev, reg+4, &szhi);
            pci_write_config_dword(dev, reg+4, lhi);
            sz64 = ((u64)szhi << 32) | raw_sz;
            l64 = ((u64)lhi << 32) | l;
            sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK);
            next++;
#if BITS_PER_LONG == 64
            if (!sz64) {
                res->start = 0;
                res->end = 0;
                res->flags = 0;
                continue;
            }
            res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK;
            res->end = res->start + sz64;
#else
            if (sz64 > 0x100000000ULL) {
                printk(KERN_ERR "PCI: Unable to handle 64-bit "
                    "BAR for device %s\n", pci_name(dev));
                res->start = 0;
                res->flags = 0;
            } else if (lhi) {
                /* 64-bit wide address, treat as disabled */
                pci_write_config_dword(dev, reg,
                    l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
                pci_write_config_dword(dev, reg+4, 0);
                res->start = 0;
                res->end = sz;
            }
#endif
        }
    }
    if (rom) {
        dev->rom_base_reg = rom;
        res = &dev->resource[PCI_ROM_RESOURCE];
        res->name = pci_name(dev);
        pci_read_config_dword(dev, rom, &l);
        pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
        pci_read_config_dword(dev, rom, &sz);
        pci_write_config_dword(dev, rom, l);
        if (l == 0xffffffff)
            l = 0;
        if (sz && sz != 0xffffffff) {
            sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK);
            if (sz) {
                res->flags = (l & IORESOURCE_ROM_ENABLE) |
                  IORESOURCE_MEM | IORESOURCE_PREFETCH |
                  IORESOURCE_READONLY | IORESOURCE_CACHEABLE |
                  IORESOURCE_SIZEALIGN;
                res->start = l & PCI_ROM_ADDRESS_MASK;
                res->end = res->start + (unsigned long) sz;
            }
        }
    }
}

论坛徽章:
0
10 [报告]
发表于 2008-08-31 20:18 |只看该作者
原帖由 flw2 于 2008-8-31 18:47 发表
zzzzzzzzzs
first clearing encoding information bits
应该就是指 & ~0x0f

比如0xfff00004 & ~0x0f == 0xfff00000
~0xfff00000 == 0x000fffff
0x000fffff + 1 == 1M

这是按照你贴的那段话来计算的
...

我明天看看代码,我看的也是3.0的PCI spec,应该是我们什么地方理解错了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP