/*
** Support for NE2000 PCI clones added David Monro June 1997
** Generalised to other NICs by Ken Yap July 1997
**
** Most of this is taken from:
**
*/
#define PCBIOS
#include "grub.h"
#include "pci.h"
#ifdef CONFIG_PCI_DIRECT
#define DEBUG 0
/*
* Functions for accessing PCI configuration space with type 1 accesses
*/
#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
{
return PCIBIOS_SUCCESSFUL;
}
{
return PCIBIOS_SUCCESSFUL;
}
{
return PCIBIOS_SUCCESSFUL;
}
{
return PCIBIOS_SUCCESSFUL;
}
{
return PCIBIOS_SUCCESSFUL;
}
int pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, uint32_t value)
{
return PCIBIOS_SUCCESSFUL;
}
#else /* CONFIG_PCI_DIRECT not defined */
#if !defined(PCBIOS)
#error "The pcibios can only be used when the PCBIOS support is compiled in"
#endif
/* Stuff for asm */
#define save_flags(x) \
#define restore_flags(x) \
static struct {
unsigned long address;
unsigned short segment;
static long pcibios_entry = 0;
static struct {
unsigned long address;
unsigned short segment;
{
unsigned long flags;
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%edi)"
#else
"lcall *(%%edi)"
#endif
: "=a" (return_code),
"=b" (address),
"=c" (length),
"=d" (entry)
: "0" (service),
"1" (0),
"D" (&bios32_indirect));
switch (return_code) {
case 0:
case 0x80: /* Not present */
return 0;
default: /* Shouldn't happen */
printf("bios32_service(%d) : returned %#X, mail drew@colorado.edu\n",
return 0;
}
}
{
unsigned long ret;
unsigned long flags;
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (ret)
: "1" (PCIBIOS_READ_CONFIG_BYTE),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
}
{
unsigned long ret;
unsigned long flags;
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (ret)
: "1" (PCIBIOS_READ_CONFIG_WORD),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
}
{
unsigned long ret;
unsigned long flags;
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=c" (*value),
"=a" (ret)
: "1" (PCIBIOS_READ_CONFIG_DWORD),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
}
{
unsigned long ret;
unsigned long flags;
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (ret)
: "0" (PCIBIOS_WRITE_CONFIG_BYTE),
"c" (value),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
}
{
unsigned long ret;
unsigned long flags;
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (ret)
: "0" (PCIBIOS_WRITE_CONFIG_WORD),
"c" (value),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
}
{
unsigned long ret;
unsigned long flags;
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%esi)\n\t"
#else
"lcall *(%%esi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:"
: "=a" (ret)
: "0" (PCIBIOS_WRITE_CONFIG_DWORD),
"c" (value),
"b" (bx),
"D" ((long) where),
"S" (&pci_indirect));
}
static void check_pcibios(void)
{
unsigned long signature;
unsigned char present_status;
unsigned char major_revision;
unsigned char minor_revision;
unsigned long flags;
int pack;
#ifdef ABSOLUTE_WITHOUT_ASTERISK
"lcall (%%edi)\n\t"
#else
"lcall *(%%edi)\n\t"
#endif
"jc 1f\n\t"
"xor %%ah, %%ah\n"
"1:\tshl $8, %%eax\n\t"
"movw %%bx, %%ax"
: "=d" (signature),
"=a" (pack)
: "1" (PCIBIOS_PCI_BIOS_PRESENT),
"D" (&pci_indirect)
: "bx", "cx");
printf("ERROR: BIOS32 says PCI BIOS, but no PCI "
"BIOS????\n");
pcibios_entry = 0;
}
#if DEBUG
if (pcibios_entry) {
printf ("pcibios_init : PCI BIOS revision %hhX.%hhX"
" entry at %#X\n", major_revision,
}
#endif
}
}
static void pcibios_init(void)
{
unsigned char sum;
int i, length;
unsigned long bios32_entry = 0;
EnterFunction("pcibios_init");
/*
* Follow the standard procedure for locating the BIOS32 Service
* directory by scanning the permissible address range from
* 0xe0000 through 0xfffff for a valid BIOS32 structure.
*
*/
continue;
if (!length)
continue;
sum = 0;
for (i = 0; i < length ; ++i)
if (sum != 0)
continue;
printf("pcibios_init : unsupported revision %d at %#X, mail drew@colorado.edu\n",
continue;
}
#if DEBUG
printf("pcibios_init : BIOS32 Service Directory "
"structure at %#X\n", check);
#endif
if (!bios32_entry) {
printf("pcibios_init: entry in high "
"memory, giving up\n");
return;
} else {
#if DEBUG
printf("pcibios_init : BIOS32 Service Directory"
" entry at %#X\n", bios32_entry);
#endif
}
}
}
if (bios32_entry)
LeaveFunction("pcibios_init");
}
#endif /* CONFIG_PCI_DIRECT not defined*/
{
/* architecturally this must be 0 */
return 0;
}
{
EnterFunction("find_pci");
#ifndef CONFIG_PCI_DIRECT
if (!pcibios_entry) {
pcibios_init();
}
if (!pcibios_entry) {
printf("pci_init: no BIOS32 detected\n");
return;
}
#endif
LeaveFunction("find_pci");
}