PCI configuration space read/write of 32bit never worked. Fixed.

PCI configuration space read/write of 16bit at offset 1 never worked. Fixed.
Added warnings for unsupported PCI configuration space read/write offsets.
Fixed numerous bugs in PCI Capabilites detection code.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@468 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper
2002-07-26 23:27:40 +00:00
parent 448187a8c3
commit b055a362cb
+45 -10
View File
@@ -317,10 +317,20 @@ static uint32 read_pci_config(uchar bus, uchar device, uchar function, uchar reg
val = in8 (CONFIG_DATA_PORT + (reg & 3));
break;
case 2:
val = in16(CONFIG_DATA_PORT + (reg & 2));
if ((reg & 3) != 3)
val = in16(CONFIG_DATA_PORT + (reg & 3));
else {
val = EINVAL;
dprintf("ERROR: read_pci_config: can't read 2 bytes at reg %d (offset 3)!\n",reg);
}
break;
case 4:
val = in32(CONFIG_DATA_PORT + reg);
if ((reg & 3) == 0)
val = in32(CONFIG_DATA_PORT);
else {
val = EINVAL;
dprintf("ERROR: read_pci_config: can't read 4 bytes at reg %d (offset != 0)!\n",reg);
}
break;
default:
dprintf("ERROR: mech #1: read_pci_config: called for %d bytes!!\n", size);
@@ -372,10 +382,16 @@ static void write_pci_config(uchar bus, uchar device, uchar function, uchar reg,
out8 (value, CONFIG_DATA_PORT + (reg & 3));
break;
case 2:
out16(value, CONFIG_DATA_PORT + (reg & 2));
if ((reg & 3) != 3)
out16(value, CONFIG_DATA_PORT + (reg & 3));
else
dprintf("ERROR: write_pci_config: can't write 2 bytes at reg %d (offset 3)!\n",reg);
break;
case 4:
out32(value, CONFIG_DATA_PORT + reg);
if ((reg & 3) == 0)
out32(value, CONFIG_DATA_PORT);
else
dprintf("ERROR: write_pci_config: can't write 4 bytes at reg %d (offset != 0)!\n",reg);
break;
default:
dprintf("ERROR: write_pci_config: called for %d bytes!!\n", size);
@@ -416,33 +432,52 @@ static void write_pci_config(uchar bus, uchar device, uchar function, uchar reg,
static int pci_get_capability(uint8 bus, uint8 dev, uint8 func, uint8 cap,
uint8 *offs)
{
uint16 status = read_pci_config(bus, dev, func, PCI_status, 2);
uint8 hdr_type, reg_data;
uint16 status;
uint32 reg_data;
uint8 hdr_type;
uint8 ofs;
int maxcount;
status = read_pci_config(bus, dev, func, PCI_status, 2);
if (!(status & PCI_status_capabilities))
return 0;
hdr_type = read_pci_config(bus, dev, func, PCI_header_type, 1);
switch(hdr_type) {
switch (hdr_type & 0x7f) { /* mask off multi function device indicator bit */
case PCI_header_type_generic:
ofs = PCI_capabilities_ptr;
break;
case PCI_header_type_PCI_to_PCI_bridge:
dprintf("ERROR: pci_get_capability: PCItoPCI bridge header type has no capabilities pointer???\n");
return 0;
case PCI_header_type_cardbus:
ofs = PCI_capabilities_ptr_2;
break;
default:
dprintf("ERROR: pci_get_capability: unknown PCI header type\n");
return 0;
}
/* the 192 bytes vendor defined configuration space
* can hold as maximum 48 times a 32 bit capability
*/
maxcount = 48;
ofs = read_pci_config(bus, dev, func, ofs, 1);
while (ofs != 0) {
reg_data = read_pci_config(bus, dev, func, ofs, 2);
while (maxcount-- != 0 && ofs != 0) {
/* mask off potentially wrong bits */
ofs &= ~3;
/* capabilities must be read as 32bit access */
reg_data = read_pci_config(bus, dev, func, ofs, 4);
/* lower 8 bit (0 to 7) contain the capability */
if ((reg_data & 0xff) == cap) {
if (offs)
*offs = ofs;
return 1;
}
/* bit 8 to 15 contain next capability position */
ofs = (reg_data >> 8) & 0xff;
}
return 0;