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

发布于 2022-09-23 15:30:48 字数 623 浏览 18 评论 0

今天看Linux内核中自带的e1000网卡驱动,发现它在probe中有如下操作:

    if ((err = pci_request_regions(pdev, e1000_driver_name)))
        return err;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

月野兔 2022-09-30 15:30:48

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

草莓味的萝莉 2022-09-30 15:30:48

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

黑白记忆 2022-09-30 15:30:48

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

多情出卖 2022-09-30 15:30:48

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

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

热情消退 2022-09-30 15:30:48

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

请持续率性 2022-09-30 15:30:48

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

天暗了我发光 2022-09-30 15:30:48

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

月隐月明月朦胧 2022-09-30 15:30:48

原帖由 Cyberman.Wu 于 2009-2-20 14:59 发表
今天看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_[byte|word|dword](struct pci_dev *pdev,
                                  int offset, int *value);
and
pci_write_config_[byte|word|dword](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_[start|len|end|flags] (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);

绻影浮沉 2022-09-30 15:30:48

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

不过在实际的驱动中还是看到过没有调用这一函数处理的,是一个错误,还是不调用关系也不大?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文