linux设备模型之pci设备的I/O和内存(二)

本文深入探讨了Linux内核如何处理PCI总线设备的I/O和内存资源冲突。从`pci_bus_size_bridges()`开始,分析`pbus_size_io()`和`pbus_size_mem()`函数,这两个函数用于计算和调整资源长度以避免冲突。接着,介绍了`pci_assign_resource()`在资源冲突修正中的关键作用,以及`pci_bus_alloc_resource()`和`allocate_resource()`如何分配资源。文章还提到了`pci_enable_bridges()`在启用PCI桥接设备中的角色,确保总线和设备准备就绪。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

回到pci_bus_size_bridges()中,经过pci_bridge_check_ranges()的处理过后,流程会转向pbus_size_io().
从字面意思看这个函数是用来计算i/o的大小.主要是用来处理有待修正的pci bus.我们来思考一下,为什么pci bus的资源会有冲突呢?可能有两个原因:
1:pci bus的起始地址冲突.在上层pci bus中,该区间已经被其它设备占用了.这种情况只需要在上层设备中偏移到特定位置就可以了.
2:pci bus的长度过长.这可能是bios在处理PCI的时候出现了错误,我们需要重新计算pci bus的长度.
而pbus_size_io()就是用来处理第二种情况的,处理资源的类型为I/O.代码如下:
static void pbus_size_io(struct pci_bus *bus)
{
         struct pci_dev *dev;
         struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
         unsigned long size = 0, size1 = 0;

         if (!b_res)
                  return;

         list_for_each_entry(dev, &bus->devices, bus_list) {
                  int i;

                   for (i = 0; i
                            struct resource *r = &dev->resource;
                            unsigned long r_size;

                            if (r->parent || !(r->flags & IORESOURCE_IO))
                                     continue;
                            r_size = r->end - r->start + 1;

                            if (r_size
                                     /* Might be re-aligned for ISA */
                                     size += r_size;
                            else
                                     size1 += r_size;
                   }
         }
/* To be fixed in 2.5: we should have sort of HAVE_ISA
   flag in the struct pci_bus. */
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
         size = (size & 0xff) + ((size & ~0xffUL)
#endif
         size = ALIGN(size + size1, 4096);
         if (!size) {
                   b_res->flags = 0;
                   return;
         }
         /* Alignment of the IO window is always 4K */
         b_res->start = 4096;
         b_res->end = b_res->start + size - 1;
}
首先,它查看对应类型(I/O)的总线资源是否有冲突的情况.如果有冲突,则计算下层需要该资源的总数.冲突资源的长度就是下层设备所需该资源的总数.只不过,对于pci bus 的I/O资源是4K对齐的.因此总长度也是4K对齐.

find_free_bus_resource()就是用来检查冲突资源项的.代码如下:
static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type)
{
         int i;
         struct resource *r;
         unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
                                       IORESOURCE_PREFETCH;

         for (i = 0; i
                   r = bus->resource;
                   if (r == &ioport_resource || r == &iomem_resource)
                            continue;
                   if (r && (r->flags & type_mask) == type && !r->parent)
                            return r;
         }
         return NULL;
}
对于资源是ioport_resource, iomem_resource的情况.表示该总线是根总线,不需要处理.注意这一句:
if (r && (r->flags & type_mask) == type && !r->parent)
不仅要求类型匹配,而且要父节点为空.父节点为空.说明之前在分配资源的时候失败,也即资源冲突.

因为pci_bus_size_bridges()使用的是深度优先搜索算法,它是先处理最底层的总线,然后再逐层上处理.而下层总线又是上层总线的一个设备(通过pci-pci bridge相连)所以,下层所需的资源长度就可以从下往上反应到上层总线中.最后,到最上层资源冲突的pci bus就可以知道下层需要多少长度的资源了.

pbus_size_mem()类似于pbus_size_io(),只是它是用来查找memory类型资源的长度.在代码中,以不同的参数两次调用了这个函数,分别是用来查找带预读的存储区间和一般的存储区间.
pbus_size_mem()和pbus_size_io()相比只是对齐因子不一样,其它大部份的处理都是一样,所以在这里不分析这个函数的代码了.请自行查阅.

回到pci_assign_unassigned_resources()函数中.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值