Cyberman.Wu 发表于 2009-02-20 14:59

pci_request_regions是干啥的,在驱动中需要调用吗?

今天看Linux内核中自带的e1000网卡驱动,发现它在probe中有如下操作:
    if ((err = pci_request_regions(pdev, e1000_driver_name)))
      return err;


但看代码好像这里主要是把BAR0~BAR5分配到的几个物理地址根据类似挂到iomem_resource或ioport_resource里面,从实现看感觉就是一个单向排序的链表。这个是用来干啥的?里面还检查了地址范围是否冲突,但这些地址范围不是BIOS或系统初始化时PCI设备枚举时映射的吗,难道还会冲突?
也见过许多实际应用的PCI设备驱动不调用这一操作的,这样有啥区别?

关于这个函数用途Manual Page中讲得很少,就几句话,和源代码中的注释差不多;内核Documentation/pci.txt中没有提到这一函数。

[ 本帖最后由 Cyberman.Wu 于 2009-2-20 16:20 编辑 ]

Cyberman.Wu 发表于 2009-02-27 18:18

自己踢一下,没人知道?在内核自带的驱动中发现许多地方做了这个操作。

Godbach 发表于 2009-02-27 19:13

建议LZ先看看LDD3中PCI的那一章啊。里面应该讲得比较清楚

Cyberman.Wu 发表于 2009-02-27 19:57

回复 #3 Godbach 的帖子

1. LDD3中提都没提到这个函数,我是在看e1000网上驱动时看到的。从代码知道它做了什么操作,但它的作用不怎么清楚,因为我也见过许多驱动不做这一操作的。
2. 说句实话,LDD3对于PCI驱动很是走马观花,不怎么样,我是看了一本PCI Express System Architecture和一些实际驱动的代码,然后再看标准规范才逐渐理解了的。

albcamus 发表于 2009-03-02 12:21

原帖由 Cyberman.Wu 于 2009-2-27 19:57 发表 http://linux.chinaunix.net/bbs/images/common/back.gif
1. LDD3中提都没提到这个函数,我是在看e1000网上驱动时看到的。从代码知道它做了什么操作,但它的作用不怎么清楚,因为我也见过许多驱动不做这一操作的。
2. 说句实话,LDD3对于PCI驱动很是走马观花,不怎么样 ...

我记得ldd3是讲了的, 你确信没有?

Cyberman.Wu 发表于 2009-03-02 13:03

回复 #5 albcamus 的帖子

我在PDF格式的电子中搜索过的但没找到,另外后面的索引中也没找到。

Cyberman.Wu 发表于 2009-03-09 16:21

自己踢一脚。真的没人知道?

Godbach 发表于 2009-03-09 23:04

驱动板置顶的电子书中就有LDD3的英文和中文版,LZ确实查找了吗。我看LDD3的时候,PCI那一章是讲过这个函数的。

scutan 发表于 2009-03-10 02:14

原帖由 Cyberman.Wu 于 2009-2-20 14:59 发表 http://linux.chinaunix.net/bbs/images/common/back.gif
今天看Linux内核中自带的e1000网卡驱动,发现它在probe中有如下操作:
    if ((err = pci_request_regions(pdev, e1000_driver_name)))
      return err;


但看代码好像这里主要是把BAR0~BAR5分配到的 ...
Essential Linux Device Drivers 这本书对这个函数有讲解,而且我觉得讲得也很不错。我把那一章都拷贝出来:

Accessing PCI Regions
PCI devices contain three addressable regions: configuration space, I/O ports, and device memory. Let's learn how to access these memory regions from a device driver.

Configuration Space
The kernel offers a set of six functions that your driver can use to operate on PCI configuration space:

pci_read_config_(struct pci_dev *pdev,
                                  int offset, int *value);
and
pci_write_config_(struct pci_dev *pdev,
                                 int offset, int value);


In the argument list, struct pci_dev is the PCI device structure, and offset is the byte position in the configuration space that you want to access. For read functions, value is a pointer to a supplied data buffer, and for write routines, it contains the data to be written.

Let's consider some examples:

To decipher the IRQ number assigned to a card function, use the following:

unsigned char irq;
pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &irq);
As per the PCI specification, offset 60 inside the PCI configuration space holds the IRQ number assigned to the card. All configuration register offsets are expressively defined in include/linux/pci_regs.h, so use PCI_INTERRUPT_LINE rather than 60 to specify this offset. Similarly, to read the PCI status register (two bytes at offset six in the configuration space), do this:

unsigned short status;
pci_read_config_word(pdev, PCI_STATUS, &status);
Only the first 64 bytes of the configuration space are standardized. The device manufacturer defines desired semantics to the rest. The Xircom card used earlier, assigns four bytes at offset 64 for power management purposes. To disable power management, the Xircom CardBus driver, drivers/net/tulip/xircom_cb.c, does this:

#define PCI_POWERMGMT 0x40
pci_write_config_dword(pdev, PCI_POWERMGMT, 0x0000);
I/O and Memory
PCI cards have up to six I/O or memory regions. I/O regions contain registers, and memory regions hold data. Video cards, for example, have I/O spaces that accommodate control registers and memory regions that map to frame buffers. Not all cards have addressable memory regions, however. The semantics of I/O and memory spaces are hardware-dependent and can be obtained from the device data sheet.

Like for configuration memory, the kernel offers a set of helpers to operate on I/O and memory regions of PCI devices:

Code View:
unsigned long pci_resource_ (struct pci_dev *pdev, int bar);

                                          


To operate on an I/O region such as the device control registers of a PCI video card, the driver needs to do the following:


1.Get the I/O base address from the appropriate base address register (bar) in the configuration space:


unsigned long io_base = pci_resource_start(pdev, bar);

This assumes that the device control registers for this card are mapped to the memory region associated with bar, whose value can range from 0 through 5, as shown in Table 10.2.


2.Mark this region as being spoken for, using the kernel's request_region() regulatory mechanism discussed in Chapter 5, "Character Drivers":


request_region(io_base, length, "my_driver");

Here, length is the size of the control register space and my_driver identifies the region's owner. Look for the entry containing my_driver in /proc/ioports to spot this memory region.

You may instead use the wrapper function pci_request_region(), defined in drivers/pci/pci.c.


3.Add the register's offset obtained from the data-sheet, to the base address gleaned in Step 1. Operate on this address using the inb() and outb() family of functions discussed in Chapter 5:


/* Read */
register_data = inl(io_base + REGISTER_OFFSET);
/* Use */
/* ... */
/* Write */
outl(register_data, iobase + REGISTER_OFFSET);



To operate on a memory region such as the frame buffer on the above PCI video card, follow these steps:

1.Get the base address, length, and flags associated with the memory region:


unsigned long mmio_base   = pci_resource_start(pdev, bar);
unsigned long mmio_length = pci_resource_length(pdev, bar);
unsigned long mmio_flags= pci_resource_flags(pdev, bar);

This assumes that this memory is mapped to the base address register, bar.


2.Mark ownership of this region using the kernel's request_mem_region() regulatory mechanism:


request_mem_region(mmio_base, mmio_length, "my_driver");

You may instead use the wrapper function pci_request_region(), mentioned previously.



3.Obtain CPU access to the device memory obtained in Step 1. Certain memory regions, such as the ones that hold registers, need to guard against side effects, so they are marked as not being prefetchable (or cacheable) by the CPU. Other regions, such as the one used in this example, can be cached. Depending on the access flag, use the appropriate function to obtain kernel virtual addresses corresponding to the mapped region:


void __iomem *buffer;
if (flags & IORESOURCE_CACHEABLE) {
buffer = ioremap(mmio_base, mmio_length);
} else {
buffer = ioremap_nocache(mmio_base, mmio_length);
}



To be safe, and to avoid performing the preceding checks, use the services of pci_iomap() defined in lib/iomap.c instead:

buffer = pci_iomap(pdev, bar, mmio_length);

Cyberman.Wu 发表于 2009-03-10 09:52

回复 #9 scutan 的帖子

Thanks. 这本书我以前下载了,但从来没看过,只看过LDD3,看来要多看一些不同的书及代码才行。

不过在实际的驱动中还是看到过没有调用这一函数处理的,是一个错误,还是不调用关系也不大?
页: [1] 2
查看完整版本: pci_request_regions是干啥的,在驱动中需要调用吗?