| /* |
| * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation; either version 2 of the |
| * License, or any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| * 02110-1301, USA. |
| * |
| * You can also choose to distribute this program under the terms of |
| * the Unmodified Binary Distribution Licence (as given in the file |
| * COPYING.UBDL), provided that you have satisfied its requirements. |
| */ |
| |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); |
| |
| #include <stdint.h> |
| #include <ipxe/pci.h> |
| #include <realmode.h> |
| |
| /** @file |
| * |
| * PCI configuration space access via PCI BIOS |
| * |
| */ |
| |
| /** |
| * Find next PCI bus:dev.fn address range in system |
| * |
| * @v busdevfn Starting PCI bus:dev.fn address |
| * @v range PCI bus:dev.fn address range to fill in |
| */ |
| static void pcibios_discover ( uint32_t busdevfn __unused, |
| struct pci_range *range ) { |
| int discard_a, discard_D; |
| uint16_t num_bus; |
| |
| /* We issue this call using flat real mode, to work around a |
| * bug in some HP BIOSes. |
| */ |
| __asm__ __volatile__ ( REAL_CODE ( "call flatten_real_mode\n\t" |
| "stc\n\t" |
| "int $0x1a\n\t" |
| "movzbw %%cl, %%cx\n\t" |
| "incw %%cx\n\t" |
| "jnc 1f\n\t" |
| "xorw %%cx, %%cx\n\t" |
| "\n1:\n\t" ) |
| : "=c" ( num_bus ), "=a" ( discard_a ), |
| "=D" ( discard_D ) |
| : "a" ( PCIBIOS_INSTALLATION_CHECK >> 16 ), |
| "D" ( 0 ) |
| : "ebx", "edx" ); |
| |
| /* Populate range */ |
| range->start = PCI_BUSDEVFN ( 0, 0, 0, 0 ); |
| range->count = PCI_BUSDEVFN ( 0, num_bus, 0, 0 ); |
| } |
| |
| /** |
| * Read configuration space via PCI BIOS |
| * |
| * @v pci PCI device |
| * @v command PCI BIOS command |
| * @v value Value read |
| * @ret rc Return status code |
| */ |
| int pcibios_read ( struct pci_device *pci, uint32_t command, uint32_t *value ){ |
| int discard_b, discard_D; |
| uint16_t status; |
| |
| __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" |
| "int $0x1a\n\t" |
| "jnc 1f\n\t" |
| "xorl %%eax, %%eax\n\t" |
| "decl %%eax\n\t" |
| "movl %%eax, %%ecx\n\t" |
| "\n1:\n\t" ) |
| : "=a" ( status ), "=b" ( discard_b ), |
| "=c" ( *value ), "=D" ( discard_D ) |
| : "a" ( command >> 16 ), "D" ( command ), |
| "b" ( pci->busdevfn ) |
| : "edx" ); |
| |
| return ( status >> 8 ); |
| } |
| |
| /** |
| * Write configuration space via PCI BIOS |
| * |
| * @v pci PCI device |
| * @v command PCI BIOS command |
| * @v value Value to be written |
| * @ret rc Return status code |
| */ |
| int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){ |
| int discard_b, discard_c, discard_D; |
| uint16_t status; |
| |
| __asm__ __volatile__ ( REAL_CODE ( "stc\n\t" |
| "int $0x1a\n\t" |
| "jnc 1f\n\t" |
| "movb $0xff, %%ah\n\t" |
| "\n1:\n\t" ) |
| : "=a" ( status ), "=b" ( discard_b ), |
| "=c" ( discard_c ), "=D" ( discard_D ) |
| : "a" ( command >> 16 ), "D" ( command ), |
| "b" ( pci->busdevfn ), "c" ( value ) |
| : "edx" ); |
| |
| return ( status >> 8 ); |
| } |
| |
| PROVIDE_PCIAPI ( pcbios, pci_discover, pcibios_discover ); |
| PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_byte ); |
| PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word ); |
| PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword ); |
| PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_byte ); |
| PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_word ); |
| PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_dword ); |
| PROVIDE_PCIAPI_INLINE ( pcbios, pci_ioremap ); |
| |
| struct pci_api pcibios_api = PCIAPI_RUNTIME ( pcbios ); |