pci_request_selected_regions功能:为设备内存分配物理地址空间。
ioremap功能:将设备物理地址空间映射成虚拟地址空间,从而驱动可以访问。
static int nvme_dev_map(struct nvme_dev *dev)
{
int bars, result = -ENOMEM;
struct pci_dev *pdev = dev->pci_dev;
if (pci_enable_device_mem(pdev))
return result;
dev->entry[0].vector = pdev->irq;
pci_set_master(pdev);
bars = pci_select_bars(pdev, IORESOURCE_MEM);
// request iomem for the selected bars, means alloc physical addrs for the mem in pci device.
/* 1.PCI设备的256字节配置的header中包含6个bar,每个bar制定一个io port地址空间,或者io mem地址
空间,实际使用中,可能一个bar就够用了。
2.pci_request_selected_regions函数的工作就是按照bar要求的起始地址和长度分配物理地址空间。
3.分配地址的目的就是希望驱动可以直接通过这些地址访问PCI设备的内存,但是该函数返回的是物理地址
在基于分页的虚拟内存管理系统中,驱动无法直接访问物理地址,要调用ioremap函数将物理地址映射到
虚拟地址,从而达到驱动可以访问PCI设备中内存的目的。
*/
if (pci_request_selected_regions(pdev, bars, "nvme"))
goto disable_pci;
if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)))
dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)))
dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
else
goto disable_pci;
pci_set_drvdata(pdev, dev);
// the driver can't access the physical addrs allocatd for pci bars memory, must call ioremap to map
// the physical addrs to virtual addrs so that driver can access them.
// Map the physical addrs to virtual addrs.
dev->bar = ioremap(pci_resource_start(pdev, 0), 8192); // PCIE device have 8k bar memory.
if (!dev->bar)
goto disable;
dev->db_stride = NVME_CAP_STRIDE(readq(&dev->bar->cap));
dev->dbs = ((void __iomem *)dev->bar) + 4096;
return 0;
disable:
pci_release_regions(pdev);
disable_pci:
pci_disable_device(pdev);
return result;
}