Linux Driver---Access PCI bus device configuration space with I/O commands

Source: Internet
Author: User

Since the introduction of PCI bus, its unique characteristics have been favored by many vendors, which has become the mainstream of computer extension bus. At present, many domestic technical personnel have the ability to develop PCI bus interface equipment. However, the PCI bus programming technology, that is, the operation of the PCI bus device technology, has been a technical staff to feel the headache of things. The core technology of PCI bus programming is to understand and access the corresponding board configuration space. General software programmers based on the principle of hardware equipment unfamiliar, it is difficult to understand and operate the configuration space, I hope that the hardware developers directly tell them how to operate, and the PCI bus hardware developers have a deep understanding of its significance, in the absence of too much programming experience, it is difficult to easily operate the PCI board card. The result is that the hardware technician spends a lot of time and effort to learn DDK, Windrver and other driver development software.

In the development of PCI bus interface equipment, the author, through the Deep research of PCI bus protocol, from the point of view of protocol itself, find a kind of efficient PCI configuration space operation method, use simple I/o command to find specific PCI bus device and read and write to all of its configuration space. Once the content of its configuration space is read, the resource allocation of the PCI bus device can be obtained as the system.

1 PCI bus configuration space and configuration mechanism

In order to avoid the collision of each PCI device in resource occupancy, PCI bus adopts Plug and Play protocol. That is, when the system is established by the operating system according to the requirements of each device uniform allocation of resources, resource allocation information is written by the system to each PCI device configuration space register, and internal operating system backup. Each PCI device has its own configuration space, and the designer differentiates the configuration space of different devices by driving the isdel pin of the backlog device (or slot). The first 64 bytes of the configuration space, called the scheduled self-zone of the configuration space, have the same definition and must be supported for each device, and the total space is called the device affinity area, which is defined by the device manufacturer as needed. Programming-related configuration space information mainly includes:

(1) Device ID and sales name (Vendor ID), configuration space offset of 00h, for each PCI device to distinguish and find. To ensure its uniqueness, the Vendor ID should be applied to the PCI Special Interest Group (PCI SIG).

(2) PCI base address (PCI base address), the configuration space offset is 10~24h, the device by setting a read-write high value to the operating system to indicate the size of the required resource space. For example, a device needs 64K bytes of memory space, you can set the configuration space of a base address register high 16 bits to read and write, and the low 16 bits to 0 (readable only). When the operating system is established, write to all bits 1, in fact only the high 16 bits are received and are set to 1, the lower 16 bits are still 0. When the operating system reads the register, the return value is ffff0000h, whereby the operating system can determine the size of the space it needs to be 64K bytes, and then Allocate an idle memory space and fill in its address with a height of 16 bits to the register.

Other possible programming-related configuration space definitions and addresses can be found in the references [1].

Due to the Pc-at compatible system CPU with only memory and I/O two space, there is no dedicated configuration space, the PCI protocol specifies that a specific I/O space operation is used to drive the PCI bridge into the configuration space. At present, there are two kinds of transformation mechanism, namely configuration mechanism # and configuration mechanism. The configuration mechanism will no longer be adopted in the new design, and the new design should use a configuration mechanism of # to generate the physical operation of the configuration space. This mechanism uses two specific 32-bit I/O spaces, namely cf8h and CFCH. These two spaces correspond to the two registers of the PCI bridge, and when the bridge sees that the CPU is doing double-word operation on the two I/O space on the local bus, it turns the I/O operation into the configuration operation of the PCI bus. The register cf8h is used to generate the address of the configuration space (config-address), and the register cfch is used to hold the read-write data (config-data) of the configuration space.

Configure the format of the spatial address register 1.


cf8h (Local bus):

When the CPU issues an I/O space cfch operation, the PCI bridge checks the 31 bits of the configuration space address register cf8h. If 1, a corresponding configuration space read or write operation is generated on the PCI bus, and its address is converted by the PCI bridge as shown in the contents of the Configuration Space address register as 2.

CFCH (Local bus):

The device number is encoded by PCI bridge to generate the high address of the PCI bus address, which is used by the designer as the Idsel signal to differentiate the PCI device. The 6-bit register number is used to address the configuration register (256 bytes) of the PCI device configuration space with 62 double words. The function number is used to differentiate the configuration space for a particular function of a multifunction device, which is 000 for a commonly used single-function device. The bus number of a PCI slot varies slightly with the system (motherboard), most PCs are 1 and the IPC may be 2 or 3. In order to find a device, it should be located on each bus number of the system until it is positioned. If the device cannot be found on the 0~5 bus, it can be considered that the device does not exist.

After understanding the configuration mechanism in the above PCI protocol, we can operate the cf8h and cfch two double-word I/O space directly, find a PCI device and access its configuration space, thus obtaining the resource allocation of the PCI device by the operating system.

2 Accessing the PCI bus configuration space with the I/o command



To access the configuration space of a PCI bus device, you must first locate the device. The basic basis of the search is that each PCI device has a specific unit number (device ID) and a sales firm (Vendor ID) in the configuration space, which occupy the 00h address of the configuration space. The purpose of the lookup is to obtain the bus number and the device number of the device. The basic process of finding is as follows: Write the address register cf8h of the configuration space with I/o command, make it the highest bit is 1, bus number and device is 0, function number and register number is 0, namely go to I/O port cf8h80000000h, then use I/o command to read the configuration space data register CFCH. If the register value does not match the device ID and vendor ID of the PCI devices, increment the device number/bus number, and repeat until the device is found. If you still cannot find the device after checking all the device numbers/bus numbers, you should consider the hardware problem. For multifunction devices, the remaining steps are the same as for a single-function device as long as the device configuration register corresponds to the function number value.

If you find the device number 9054h, the sales firm is 10b5 's single-function PCI device, the program is written as follows:

Code:char Bus;char device;

unsigned int ioa0,iod;

int scan ()

{

bus=0;device=0;

for (char i=0;i<5;i++) {

for (char j=0;j<32;j++) {

Bus=i; Device=j;

ioa0=0x80000000+bus*0x10000

+ (device*8) *0x100;

_OUTPD (0XCF8,IOA0);

IOD=_INPD (0XCFC);

if (iod0= =0x905410b5) return 0;

}

}

Retrn-1

}

Call the subroutine scan () and if the return value is-1, the PCI device is not found. If the return value is 0, the PCI device is found. The bus number and device number of the device in the global variable bus and devices, the use of these two variables can easily access the configuration space of the device, resulting in the allocation of resource information. Assume that the PCI device occupies 4 resource space, corresponding to the configuration space 10h~1ch, of which the first two are I/O space, the latter two are memory space, if the base address is defined as IOADDR1,IOADDR2,MEMADDR1,MEMADDR2, the corresponding program is as follows:

code:unsigned short IOADDR1,IOADDR2;

unsigned int memaddr1,memaddr2;

unsigned int iobase,ioa;

void Getbaseaddr (char bus,char device);

{

iobase=0x80000000+bus*0x10000+ (device*8) *0x100;

ioa=iobase+0x10;/* addressing base address register 0*/

_OUTPD (0XCF8,IOA);

ioaddr1= (unsigned short) _inpd (0XCFC) &0xfffc;

/* Shielded low two-bit and high 16-bit */

ioa=iobase+0x14; /* Addressing the base address register 1*/

_OUTPD (0XCF8,IOA);

ioaddr2= (unsigned short) _inpd (0XCFC) &0xfffc;

ioa=iobase+0x18;/* Addressing base Register 2*/

_OUTPD (0XCF8,IOA);

MEMADDR1=_INPD (0XCFC) & 0xfffffff0;

/* Shielded low 4-bit */

ioa=iobase+0x1c; /* Addressing the base address register 3*/

_OUTPD (0XCF8,IOA);

MEMADDR2=_INPD (0XCFC) & 0xfffffff0;

}

For I/O base addresses, a minimum of two bits D0, D1 fixed to 01, is not valid for the address itself and should be masked. For Pc-at compatible machines, the I/O valid address is 16 bits, so the high level should also be masked. For memory addresses, the lowest bit D0 is fixed to 0, and d1~d3 is used to indicate some physical properties of the address [1], so its low 4-bit address should be masked. It should be noted that the memory address is the physical address of the system, and when Windows is running in protected mode, it needs to be converted to the corresponding linear address in order to read and write the memory space directly. The article about the conversion method is more common and is not mentioned here.

The above procedure gives the method of reading the base address in the configuration space. There are quite a number of PCI devices through the configuration space of the device Association area to set the operating state of the device, you can easily use the I/O command to set the corresponding, without the need to write cumbersome drivers. In the process of developing PCI video image Acquisition Card, this method has been applied in practice.

#define Pci_cfg_data 0xcfc#define Pci_cfg_ctrl 0xcf8 void pci_read_config_byte (unsigned char bus, unsigned char Dev,       unsigned char offset, unsigned char *val) {unsigned char fun = 0; Outl ((0x80000000 | (bus) <<16) | (dev) <<11) | ((Fun) <<8) |    (Offset & ~0x3), Pci_cfg_ctrl); *val = INL (Pci_cfg_data) >> ((offset & 3) * 8);} void Pci_read_config_word (unsigned char bus, unsigned char dev, unsigned char offset, unsigned short *val) {unsigned ch       AR fun = 0; Outl ((0x80000000 | (bus) <<16) | (dev) <<11) | ((Fun) <<8) |    (Offset & ~0x3), Pci_cfg_ctrl); *val = INL (Pci_cfg_data) >> ((offset & 3) * 8);} void Pci_read_config_dword (unsigned char bus, unsigned char dev, unsigned char offset, unsigned int *val) {unsigned cha       R fun = 0; Outl ((0x80000000 | (bus) <<16) | (dev) <<11) | ((Fun) <<8) |    (offset)), Pci_cfg_ctrl); *val = INL (pci_cfg_data);} It is obvious that the control register is written to the integrated address, the format mentioned earlier, compared to the exact same.Then read the data from the data register, because the data register is 32 bits, if not read double word, need to do shift operation. In addition, you must pay attention to the size of the problem, if necessary to carry out the size of the end of the conversion, the following writing program. 5. Write program void Pci_write_config_dword (unsigned char bus, unsigned char dev, unsigned char offset, unsigned int val) {unsign       ed char fun = 0; Outl ((0x80000000 | (bus) <<16) | (dev) <<11) | ((Fun) <<8) |    (offset)), Pci_cfg_ctrl); Outl (Val, pci_cfg_data);} void Pci_write_config_word (unsigned char bus, unsigned char dev, unsigned char offset, unsigned short val) {unsigned lo    NG tmp;     unsigned char fun = 0; Outl ((0x80000000 | (bus) <<16) | (dev) <<11) | ((Fun) <<8) |    (Offset & ~0x3), Pci_cfg_ctrl);    TMP = INL (pci_cfg_data);    TMP &= ~ (0xFFFF << ((offset & 0x3) * 8));    TMP |= (Val << ((Offset & 0x3) * 8)); OUTL (TMP, pci_cfg_data);} void Pci_write_config_byte (unsigned char bus, unsigned char dev, unsigned char offset, unsigned short val) {unsigned lo    NG tmp;       unsigned char fun = 0; Outl ((0x80000000 | (bus) <<16) | ((dev) <<11) | ((Fun) <<8) |    (Offset & ~0x3), Pci_cfg_ctrl);    TMP = INL (pci_cfg_data);    TMP &= ~ (0xFF << ((offset & 0x3) * 8));    TMP |= (Val << ((Offset & 0x3) * 8)); OUTL (TMP, pci_cfg_data);} The writer writes to the control register and writes the data to the data register, just as the program reads. 6. The above procedure is written in reference to the Linux kernel's read-write program for PCI space. However, it is quite different to read and write PCI space in the application and read and write PCI space in the kernel. In the Linux source code can be seen, in the PCI space read and write operations are in the case of closed interrupts, and in the user program space does not have this means. Therefore, reading and writing can be error-prone. After I test, read basically no error, and write a certain error probability, use with caution! Interested, can write an application to try. 7. Source code is attached to a source code, can be directly compiled to run. #include <stdio.h> #include <stdlib.h> #include <sys/io.h>static unsigned int read_pci_config_32 ( unsigned char bus, unsigned char slot, unsigned char func, unsigned char offset) {unsigned int v; outl (0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | Offset, 0xcf8); v = INL (0XCFC); return v;}  unsigned char read_pci_config_8 (unsigned char bus, unsigned char slot, unsigned char func, unsigned char offset) {unsigned Char v; Outl (0x80000000 | (bus<<16) | (SLOT&LT;&LT;11)| (func<<8) | Offset, 0xcf8); v = inb (0XCFC + (offset&3)); return v;} unsigned short read_pci_config_16 (unsigned char bus, unsigned char slot, unsigned char func, unsigned char offset) {unsign Ed Short V; Outl (0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | Offset, 0xcf8); v = inw (0XCFC + (offset&2)); return v;} void write_pci_config_32 (unsigned char bus, unsigned char slot, unsigned char func, unsigned char offset, unsigned int val ) {Outl (0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | Offset, 0xcf8); Outl (Val, 0XCFC);} void Write_pci_config_8 (unsigned char bus,unsigned char slot, unsigned char func, unsigned char offset, unsigned char val) {Outl (0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | Offset, 0xcf8); Outb (Val, 0XCFC + (offset&3));} void write_pci_config_16 (unsigned char bus,unsigned char slot, unsigned char func, unsigned char offset, unsigned char val ) {Outl (0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | Offset, 0xcf8); OUTW (Val, 0XCFC + (OFFSET&AMP;2));}  int main (void) {IOPL (3); printf ("0 0 0 0 =%x\n", read_pci_config_16 (0, 0, 0, 0)); printf ("0 0 0 2 =%x\n", read_pci_config_16 (0, 0, 0, 2)); printf ("0 1 0 0 =%x\n", read_pci_config_16 (0, 1, 0, 0));  printf ("0 1 0 2 =%x\n", read_pci_config_16 (0, 1, 0, 2)); printf ("0 7 1 0 =%x\n", read_pci_config_16 (0, 7, 1, 0)); printf ("0 7 1 2 =%x\n", read_pci_config_16 (0, 7, 1, 2)); return 0;}


Linux Driver---Access PCI bus device configuration space with I/O commands

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.