Use more care when implementing the PCI BIOS functions.

The READ_CONF and WRITE_CONF functions would both do the wrong thing
if the passed in BDF was not found.  We should return and error to the
caller, but not stop running the option ROM.

Signed-off-by: Mark Marshall <mark.marshall@csr.com>

I slightly reworked the patch:

The 'CHECK' function seemed to be both wrong code and the wrong
number. 

In fact the CHECK function was given the function number of
the "Microsoft Real-Time Compression Interface". Since this is definitely wrong 
I removed the code.

Dropped some unneeded scopes, too, to make the code easier to read.

Acked-by: Stefan Reinauer <stepan@coresystems.de>




git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4910 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
Mark Marshall 2009-11-05 09:03:04 +00:00 committed by Stefan Reinauer
parent 2fa7c2e210
commit d08e69dd5e
1 changed files with 37 additions and 38 deletions

View File

@ -34,19 +34,22 @@
#endif #endif
enum { enum {
CHECK = 0xb001, PCIBIOS_CHECK = 0xb101,
FINDDEV = 0xb102, PCIBIOS_FINDDEV = 0xb102,
READCONFBYTE = 0xb108, PCIBIOS_READCONFBYTE = 0xb108,
READCONFWORD = 0xb109, PCIBIOS_READCONFWORD = 0xb109,
READCONFDWORD = 0xb10a, PCIBIOS_READCONFDWORD = 0xb10a,
WRITECONFBYTE = 0xb10b, PCIBIOS_WRITECONFBYTE = 0xb10b,
WRITECONFWORD = 0xb10c, PCIBIOS_WRITECONFWORD = 0xb10c,
WRITECONFDWORD = 0xb10d PCIBIOS_WRITECONFDWORD = 0xb10d
}; };
// errors go in AH. Just set these up so that word assigns // errors go in AH. Just set these up so that word assigns
// will work. KISS. // will work. KISS.
enum { enum {
PCIBIOS_SUCCESSFUL = 0x0000,
PCIBIOS_UNSUPPORTED = 0x8100,
PCIBIOS_BADVENDOR = 0x8300,
PCIBIOS_NODEV = 0x8600, PCIBIOS_NODEV = 0x8600,
PCIBIOS_BADREG = 0x8700 PCIBIOS_BADREG = 0x8700
}; };
@ -63,7 +66,7 @@ int int12_handler(struct eregs *regs)
int int1a_handler(struct eregs *regs) int int1a_handler(struct eregs *regs)
{ {
unsigned short func = (unsigned short) regs->eax; unsigned short func = (unsigned short)regs->eax;
int retval = 0; int retval = 0;
unsigned short devid, vendorid, devfn; unsigned short devid, vendorid, devfn;
/* Use short to get rid of gabage in upper half of 32-bit register */ /* Use short to get rid of gabage in upper half of 32-bit register */
@ -71,14 +74,13 @@ int int1a_handler(struct eregs *regs)
unsigned char bus; unsigned char bus;
struct device *dev; struct device *dev;
switch(func) { switch (func) {
case CHECK: case PCIBIOS_CHECK:
regs->edx = 0x4350; regs->edx = 0x20494350; /* ' ICP' */
regs->ecx = 0x2049; regs->edi = 0x00000000; /* protected mode entry */
retval = 0; retval = 0;
break; break;
case FINDDEV: case PCIBIOS_FINDDEV:
{
devid = regs->ecx; devid = regs->ecx;
vendorid = regs->edx; vendorid = regs->edx;
devindex = regs->esi; devindex = regs->esi;
@ -98,7 +100,7 @@ int int1a_handler(struct eregs *regs)
// busnum is an unsigned char; // busnum is an unsigned char;
// devfn is an int, so we mask it off. // devfn is an int, so we mask it off.
busdevfn = (dev->bus->secondary << 8) busdevfn = (dev->bus->secondary << 8)
| (dev->path.pci.devfn & 0xff); | (dev->path.pci.devfn & 0xff);
printk(BIOS_DEBUG, "0x%x: return 0x%x\n", func, busdevfn); printk(BIOS_DEBUG, "0x%x: return 0x%x\n", func, busdevfn);
regs->ebx = busdevfn; regs->ebx = busdevfn;
retval = 0; retval = 0;
@ -106,15 +108,13 @@ int int1a_handler(struct eregs *regs)
regs->eax = PCIBIOS_NODEV; regs->eax = PCIBIOS_NODEV;
retval = -1; retval = -1;
} }
} break;
break; case PCIBIOS_READCONFDWORD:
case READCONFDWORD: case PCIBIOS_READCONFWORD:
case READCONFWORD: case PCIBIOS_READCONFBYTE:
case READCONFBYTE: case PCIBIOS_WRITECONFDWORD:
case WRITECONFDWORD: case PCIBIOS_WRITECONFWORD:
case WRITECONFWORD: case PCIBIOS_WRITECONFBYTE:
case WRITECONFBYTE:
{
unsigned long dword; unsigned long dword;
unsigned short word; unsigned short word;
unsigned char byte; unsigned char byte;
@ -124,49 +124,48 @@ int int1a_handler(struct eregs *regs)
bus = regs->ebx >> 8; bus = regs->ebx >> 8;
reg = regs->edi; reg = regs->edi;
dev = dev_find_slot(bus, devfn); dev = dev_find_slot(bus, devfn);
if (! dev) { if (!dev) {
printk(BIOS_DEBUG, "0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn); printk(BIOS_DEBUG, "0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn);
// idiots. the pcibios guys assumed you'd never pass a bad bus/devfn! // idiots. the pcibios guys assumed you'd never pass a bad bus/devfn!
regs->eax = PCIBIOS_BADREG; regs->eax = PCIBIOS_BADREG;
retval = -1; retval = -1;
return retval;
} }
switch(func) { switch (func) {
case READCONFBYTE: case PCIBIOS_READCONFBYTE:
byte = pci_read_config8(dev, reg); byte = pci_read_config8(dev, reg);
regs->ecx = byte; regs->ecx = byte;
break; break;
case READCONFWORD: case PCIBIOS_READCONFWORD:
word = pci_read_config16(dev, reg); word = pci_read_config16(dev, reg);
regs->ecx = word; regs->ecx = word;
break; break;
case READCONFDWORD: case PCIBIOS_READCONFDWORD:
dword = pci_read_config32(dev, reg); dword = pci_read_config32(dev, reg);
regs->ecx = dword; regs->ecx = dword;
break; break;
case WRITECONFBYTE: case PCIBIOS_WRITECONFBYTE:
byte = regs->ecx; byte = regs->ecx;
pci_write_config8(dev, reg, byte); pci_write_config8(dev, reg, byte);
break; break;
case WRITECONFWORD: case PCIBIOS_WRITECONFWORD:
word = regs->ecx; word = regs->ecx;
pci_write_config16(dev, reg, word); pci_write_config16(dev, reg, word);
break; break;
case WRITECONFDWORD: case PCIBIOS_WRITECONFDWORD:
dword = regs->ecx; dword = regs->ecx;
pci_write_config32(dev, reg, dword); pci_write_config32(dev, reg, dword);
break; break;
} }
if (retval)
retval = PCIBIOS_BADREG;
printk(BIOS_DEBUG, "0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n", printk(BIOS_DEBUG, "0x%x: bus %d devfn 0x%x reg 0x%x val 0x%x\n",
func, bus, devfn, reg, regs->ecx); func, bus, devfn, reg, regs->ecx);
regs->eax = 0; regs->eax = 0;
retval = 0; retval = 0;
} break;
break;
default: default:
printk(BIOS_ERR, "UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func); printk(BIOS_ERR, "UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
retval = -1;
break; break;
} }