Sorry if I am alittle confused.
But
No, you just read the 0xcfc io port 256 times (reading 32bit dwords), after selecting 256 different register numbers via the 0xcf8 port. You have to select each configuration space "register" individually.
So if for example from osdev wiki they have a configuration space table
like this
Code: Select all
register bits 31-24 bits 23-16 bits 15-8 bits 7-0
00 Device ID Vendor ID
04 Status Command
08 Class code Subclass Prog IF Revision ID
0C BIST Header type Latency Timer Cache Line Size
10 Base address #0 (BAR0)
14 Base address #1 (BAR1)
18 Base address #2 (BAR2)
1C Base address #3 (BAR3)
20 Base address #4 (BAR4)
24 Base address #5 (BAR5)
28 Cardbus CIS Pointer
2C Subsystem ID Subsystem Vendor ID
30 Expansion ROM base address
34 Reserved Capabilities Pointer
38 Reserved
3C Max latency Min Grant Interrupt PIN Interrupt Line
Does that mean calling indword(0xCFC); for the first time brings back
Device ID Vendor ID
and if so another indword(0xCFC) read after that will bring back the next 32bit register
04 Status Command
...and so on
so too get the complete table I would have to read from 0xCFC 64 times in a row?
If that is true then the functions on the wiki
i.e
Code: Select all
unsigned short pciConfigReadWord (unsigned short bus, unsigned short slot,
unsigned short func, unsigned short offset)
{
unsigned long address;
unsigned long lbus = (unsigned long)bus;
unsigned long lslot = (unsigned long)slot;
unsigned long lfunc = (unsigned long)func;
unsigned short tmp = 0;
/* create configuration address as per Figure 1 */
address = (unsigned long)((lbus << 16) | (lslot << 11) |
(lfunc << 8) | (offset & 0xfc) | ((UINT32)0x80000000));
/* write out the address */
sysOutLong (0xCF8, address);
/* read in the data */
tmp = (unsigned short)((sysInLong (0xCFC) >> ((offset & 2) * 8)) & 0xffff);
return (tmp);
}
only ever returns halve of the first register 00 Device ID Vendor ID
If I am correct with my understanding
then to read the second 32bit register by modifying this function to read the second register line 04 Status Command
All I would have to do is skip the first read.
like this
Code: Select all
unsigned long pciConfigReadDWord (unsigned short bus, unsigned short slot,
unsigned short func, unsigned short offset)
{
unsigned long address;
unsigned long lbus = (unsigned long)bus;
unsigned long lslot = (unsigned long)slot;
unsigned long lfunc = (unsigned long)func;
unsigned long tmp = 0;
/* create configuration address as per Figure 1 */
address = (unsigned long)((lbus << 16) | (lslot << 11) |
(lfunc << 8) | (offset & 0xfc) | ((UINT32)0x80000000));
/* write out the address */
sysOutLong (0xCF8, address);
/* read in the data */
sysInLong (0xCFC) ; // skip the first 32 bit register
tmp = sysInLong (0xCFC) ;
return (tmp);
}
Thanks
Add *****
I thought about it and maybe you meant you do it this way
from this header static u64 read_pci(u64 bus, u64 dev, u64 func, u64 offset)
if you have a device on bus= 0, dev=1, func=2 the 256 byte configuration space table entries would be access by the offset
if offset = 0x00 your going to read the first register in the configuration space
which is 00 Device ID Vendor ID
if offset = 0x01
you would read the second 32 bit register in the configuration space
which is 04 Status Command
and so on
offset = 64 would read the last 32bit register in the table.
Let me know if this is the way it works.
If so to probe all the PCI bus completely for devices and function you would run thur a triple for loop
for( int i = 0 ; i < bus_size ; i++)
for( int j = 0 ; j < dev_size ; j++)
for( int k = 0 ; k < func_size ; k++)
{
if( isvaildPCIBUSDEVICE( i , j , k) != 0xFFFF )
{
//read the configuration table with the offset incremented 0 , 1 , 2,...,64
//to get the whole table into an array ....etc
}
}
return 0 ;