首页 > 其他分享 >AMD Xilinx PCIe Host 配置空间访问流程

AMD Xilinx PCIe Host 配置空间访问流程

时间:2024-08-19 13:55:13浏览次数:12  
标签:val int bus AMD dev PCIe Host pci config

AMD Xilinx的Versal器件中的PCIe IP,也可以作为PCIe Host。 AR76647 提供了相关驱动。 Xilinx Linux PL PCIe Root Port 提供了配置和测试过程。

最近研究了Linux下,AMD Xilinx PCIe Host 配置空间访问流程。

pci_read_config_xxx 和 pci_write_config_xxx 函数定义

首先,Linux通用的PCI代码,需要PCI配置空间的访问函数 pci_read_config_xxx 和 pci_write_config_xxx。 文件include\linux\Pci.h中对它们进行了声明。

int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val);
int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val);
int pci_read_config_dword(const struct pci_dev *dev, int where, u32 *val);
int pci_write_config_byte(const struct pci_dev *dev, int where, u8 val);
int pci_write_config_word(const struct pci_dev *dev, int where, u16 val);
int pci_write_config_dword(const struct pci_dev *dev, int where, u32 val);

文件drivers\pci\Access.c中,通过调用pci_bus_read_config_xxx 和 pci_bus_write_config_xxx, 定义了上述函数。


int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val)
{
	if (pci_dev_is_disconnected(dev)) {
		*val = ~0;
		return PCIBIOS_DEVICE_NOT_FOUND;
	}
	return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_read_config_byte);

int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val)
{
	if (pci_dev_is_disconnected(dev)) {
		*val = ~0;
		return PCIBIOS_DEVICE_NOT_FOUND;
	}
	return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_read_config_word);

int pci_read_config_dword(const struct pci_dev *dev, int where,
					u32 *val)
{
	if (pci_dev_is_disconnected(dev)) {
		*val = ~0;
		return PCIBIOS_DEVICE_NOT_FOUND;
	}
	return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_read_config_dword);

int pci_write_config_byte(const struct pci_dev *dev, int where, u8 val)
{
	if (pci_dev_is_disconnected(dev))
		return PCIBIOS_DEVICE_NOT_FOUND;
	return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_write_config_byte);

int pci_write_config_word(const struct pci_dev *dev, int where, u16 val)
{
	if (pci_dev_is_disconnected(dev))
		return PCIBIOS_DEVICE_NOT_FOUND;
	return pci_bus_write_config_word(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_write_config_word);

int pci_write_config_dword(const struct pci_dev *dev, int where,
					 u32 val)
{
	if (pci_dev_is_disconnected(dev))
		return PCIBIOS_DEVICE_NOT_FOUND;
	return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_write_config_dword);

pci_bus_read_config_xxx 和 pci_bus_write_config_xxx 函数定义

pci_bus_read_config_xxx 和 pci_bus_write_config_xxx是更底层的函数。它们也在文件include\linux\Pci.h中被声明。

int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn,
			     int where, u8 *val);
int pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn,
			     int where, u16 *val);
int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn,
			      int where, u32 *val);
int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn,
			      int where, u8 val);
int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn,
			      int where, u16 val);
int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn,
			       int where, u32 val);

pci_bus_read_config_xxx 和 pci_bus_write_config_xxx的代码通过宏“PCI_OP_READ”和宏“PCI_OP_WRITE”实现。

#define PCI_OP_READ(size, type, len) \
int noinline pci_bus_read_config_##size \
	(struct pci_bus *bus, unsigned int devfn, int pos, type *value)	\
{									\
	int res;							\
	unsigned long flags;						\
	u32 data = 0;							\
	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
	pci_lock_config(flags);						\
	res = bus->ops->read(bus, devfn, pos, len, &data);		\
	*value = (type)data;						\
	pci_unlock_config(flags);					\
	return res;							\
}

#define PCI_OP_WRITE(size, type, len) \
int noinline pci_bus_write_config_##size \
	(struct pci_bus *bus, unsigned int devfn, int pos, type value)	\
{									\
	int res;							\
	unsigned long flags;						\
	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
	pci_lock_config(flags);						\
	res = bus->ops->write(bus, devfn, pos, len, value);		\
	pci_unlock_config(flags);					\
	return res;							\
}

通过调用宏“PCI_OP_READ”和宏“PCI_OP_WRITE”,定义了pci_bus_read_config_xxx 和 pci_bus_write_config_xxx。

PCI_OP_READ(byte, u8, 1)
PCI_OP_READ(word, u16, 2)
PCI_OP_READ(dword, u32, 4)
PCI_OP_WRITE(byte, u8, 1)
PCI_OP_WRITE(word, u16, 2)
PCI_OP_WRITE(dword, u32, 4)

EXPORT_SYMBOL(pci_bus_read_config_byte);
EXPORT_SYMBOL(pci_bus_read_config_word);
EXPORT_SYMBOL(pci_bus_read_config_dword);
EXPORT_SYMBOL(pci_bus_write_config_byte);
EXPORT_SYMBOL(pci_bus_write_config_word);
EXPORT_SYMBOL(pci_bus_write_config_dword);

通过宏“PCI_OP_READ”和宏“PCI_OP_WRITE”,也可以看出,实现pci_bus_read_config_xxx 和 pci_bus_write_config_xxx,需要数据结构“struct pci_bus”中嵌套的数据结构“struct pci_ops”中的函数read和write函数。

/* Low-level architecture-dependent routines */
struct pci_ops {
	int (*add_bus)(struct pci_bus *bus);
	void (*remove_bus)(struct pci_bus *bus);
	void __iomem *(*map_bus)(struct pci_bus *bus, unsigned int devfn, int where);
	int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val);
	int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val);
};

pcie-xdma-pl.c 中的pci_ops

pcie-xdma-pl.c定义了pci_ops。

/* PCIe operations */
static struct pci_ops xilinx_pcie_ops = {
	.map_bus = xilinx_pcie_map_bus,
	.read	= pci_generic_config_read,
	.write	= pci_generic_config_write,
};

pci_generic_config_read和pci_generic_config_write在drivers\pci\access.c中定义。

int pci_generic_config_read(struct pci_bus *bus, unsigned int devfn,
			    int where, int size, u32 *val)
{
	void __iomem *addr;

	addr = bus->ops->map_bus(bus, devfn, where);
	if (!addr) {
		*val = ~0;
		return PCIBIOS_DEVICE_NOT_FOUND;
	}

	if (size == 1)
		*val = readb(addr);
	else if (size == 2)
		*val = readw(addr);
	else
		*val = readl(addr);

	return PCIBIOS_SUCCESSFUL;
}
EXPORT_SYMBOL_GPL(pci_generic_config_read);

int pci_generic_config_write(struct pci_bus *bus, unsigned int devfn,
			     int where, int size, u32 val)
{
	void __iomem *addr;

	addr = bus->ops->map_bus(bus, devfn, where);
	if (!addr)
		return PCIBIOS_DEVICE_NOT_FOUND;

	if (size == 1)
		writeb(val, addr);
	else if (size == 2)
		writew(val, addr);
	else
		writel(val, addr);

	return PCIBIOS_SUCCESSFUL;
}
EXPORT_SYMBOL_GPL(pci_generic_config_write);

可以看到,它们调用了“struct pci_bus *bus”中的map_bus()函数。

pcie-xdma-pl.c 也实现了 map_bus()函数。它根据总线号、设备号,得到一个寄存器地址。通过这个寄存器地址操作,就能对设备的发起配置寄存器的读写操作。

static void __iomem *xilinx_pcie_map_bus(struct pci_bus *bus,
					 unsigned int devfn, int where)
{
	struct xilinx_pcie_port *port = bus->sysdata;
	int relbus;

	if (!xilinx_pcie_valid_device(bus, devfn))
		return NULL;

	relbus = (bus->number << ECAM_BUS_NUM_SHIFT) |
		 (devfn << ECAM_DEV_NUM_SHIFT);

	return port->reg_base + relbus + where;
}

这样,PCIe Host 配置空间访问流程中,与设备相关的代码就齐全了。

总结

从上到下,PCIe Host 配置空间访问过程中,相关的函数如下:

  1. pci_read_config_xxx 和 pci_write_config_xxx 函数定义
  2. pci_bus_read_config_xxx 和 pci_bus_write_config_xxx 函数定义
  3. static struct pci_ops xilinx_pcie_ops
  4. xilinx_pcie_map_bus

标签:val,int,bus,AMD,dev,PCIe,Host,pci,config
From: https://www.cnblogs.com/hankfu/p/18367067

相关文章

  • UsbHostManager解析
    UsbHostManager和UsbDeviceManager的区别在于,UsbDeviceManager是将手机作为一个设备,比如手机连上电脑,使用adb、mtp等;而UsbHostManager,是将手机作为一个host,比如手机连接usb鼠标、usb摄像头等,就会new出一个UsbDevice出来。UsbHostManager初始化UsbHostManager和UsbDeviceManager......
  • PCIe信号详解
    PCIe信号详解PCIe简介PCIe(peripheralcomponentinterconnectexpress)是一种高速串行计算机扩展总线标准,是用于连接高速组件的接口标准。每台台式电脑主板有许多PCIe插槽,可用于添加通用显卡,各种外设卡,无线网卡或固态硬盘等等,PC中可用的PCIe插槽类型将取决于你购买的主板。P......
  • PCIe扫盲:Memory & IO 地址空间/基地址寄存器详解/Base & Limit寄存器详解
    转载:PCIe扫盲:Memory&IO地址空间/基地址寄存器详解/Base&Limit寄存器详解-极术社区-连接开发者与智能计算生态(aijishu.com)Memory&IO地址空间早期的PC中,所有的IO设备(除了存储设备之外的设备)的内部存储或者寄存器都只能通过IO地址空间进行访问。但是这种方式局限性......
  • 光纤PCIe 卡设计资料第383篇: 基于kintex UltraScale XCKU060的双路QSFP+光纤PCIe 卡
    基于kintexUltraScaleXCKU060的双路QSFP+光纤PCIe卡一、板卡概述    本板卡系我司自主研发,基于Xilinx UltraScale Kintex系列FPGA  XCKU060-FFVA1156-2-I架构,支持PCIE Gen3 x8模式的高速信号处理板卡,搭配两路40G QSFP+接口,两组64-bit DDR4,每组容量2Gbyte,可稳定......
  • SMHC Three SD/MMC host controller (SMHC) interfaces
    SMHCThreeSD/MMChostcontroller(SMHC)interfaces1TheSMHC0controlsthedevicesthatcomplywiththeprotocolSecureDigitalMemory(SDmem-version3.0)2TheSMHC1controlsthedevicethatcomplieswiththeprotocolSecureDigitalI/O(SDIO-version......
  • Windows:hosts文件作用,程序员开发需要掌握哪些内容
    一、hosts文件的基本概念和作用1.1、基本概念:hosts文件是一个没有扩展名的系统文件,位于:Windows系统的:C:\Windows\System32\drivers\etc\hostsMacOSX和Linux操作系统:Hosts文件位于/etc/hosts。1.2、主要作用:hosts文件用于将网址域名与其对应的IP地址建立一个关联“数据库......
  • Dllhost.exe 是 Windows 操作系统中的一个进程,通常与 COM+ 服务相关。它的主要作用是
    Dllhost.exe是Windows操作系统中的一个进程,通常与COM+服务相关。它的主要作用是运行COM组件和处理进程间的通信。Dllhost.exe的起源可以追溯到MicrosoftWindows2000和WindowsXP的早期版本。它是Windows操作系统的一部分,主要用于支持COM+(ComponentObjectMode......
  • Flannel HOST-GW 模式
    FlannelUDP模式一、环境信息主机IPubuntu172.16.94.141软件版本docker26.1.4helmv3.15.0-rc.2kind0.18.0clab0.54.2kubernetes1.23.4ubuntuosUbuntu20.04.6LTSkernel5.11.5内核升级文档二、安装服务kind配置文件信......
  • 安装local-path-provisioner基于HostPath动态制备PV
    目录一、背景二、安装local-path-provisioner1、地址2、更改local-path-provisioner使用的默认存储路径3、创建文件并提权4、创建NameSpace5、应用local-path-storage6、验证相关资源状态三、设置local-path为defaultSC四、使用StorageClass动态制备PV1、创建PVC2、创建......
  • CommonJS、AMD、CMD、UMD、ES6
    一、commonJs1、CommonJS的发扬光大和nodejs相关,CommonJS用同步的方式加载模块。在服务器端,读取快。限于网络原因,不适合在浏览器端使用;2、输出module.exports,加载require;//model1.jsvarage=11functionsay(){console.log(age);}module.exports={say}/......