mirror of https://github.com/ipxe/ipxe.git
[pci] Add minimal PCI bridge driver
Add a minimal driver for PCI bridges that can be used to locate the bridge to which a PCI device is attached. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/583/merge
parent
649176cd60
commit
3aa6b79c8d
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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 (at your option) 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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/pci.h>
|
||||
#include <ipxe/pcibridge.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* PCI-to-PCI bridge
|
||||
*
|
||||
*/
|
||||
|
||||
/** List of all PCI bridges */
|
||||
static LIST_HEAD ( pcibridges );
|
||||
|
||||
/**
|
||||
* Find bridge attached to a PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
* @ret bridge PCI bridge, or NULL
|
||||
*/
|
||||
struct pci_bridge * pcibridge_find ( struct pci_device *pci ) {
|
||||
unsigned int bus = PCI_BUS ( pci->busdevfn );
|
||||
struct pci_bridge *bridge;
|
||||
|
||||
/* Find matching bridge */
|
||||
list_for_each_entry ( bridge, &pcibridges, list ) {
|
||||
if ( bus == bridge->secondary )
|
||||
return bridge;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int pcibridge_probe ( struct pci_device *pci ) {
|
||||
struct pci_bridge *bridge;
|
||||
uint16_t base;
|
||||
uint16_t limit;
|
||||
int rc;
|
||||
|
||||
/* Allocate and initialise structure */
|
||||
bridge = zalloc ( sizeof ( *bridge ) );
|
||||
if ( ! bridge ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
bridge->pci = pci;
|
||||
|
||||
/* Read configuration */
|
||||
pci_read_config_dword ( pci, PCI_PRIMARY, &bridge->buses );
|
||||
cpu_to_le32s ( &buses );
|
||||
pci_read_config_word ( pci, PCI_MEM_BASE, &base );
|
||||
bridge->membase = ( ( base & ~PCI_MEM_MASK ) << 16 );
|
||||
pci_read_config_word ( pci, PCI_MEM_LIMIT, &limit );
|
||||
bridge->memlimit = ( ( ( ( limit | PCI_MEM_MASK ) + 1 ) << 16 ) - 1 );
|
||||
DBGC ( bridge, "BRIDGE " PCI_FMT " bus %02x to [%02x,%02x) mem "
|
||||
"[%08x,%08x)\n", PCI_ARGS ( pci ), bridge->primary,
|
||||
bridge->secondary, bridge->subordinate, bridge->membase,
|
||||
bridge->memlimit );
|
||||
|
||||
/* Add to list of PCI bridges */
|
||||
list_add ( &bridge->list, &pcibridges );
|
||||
|
||||
pci_set_drvdata ( pci, bridge );
|
||||
return 0;
|
||||
|
||||
free ( bridge );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
*/
|
||||
static void pcibridge_remove ( struct pci_device *pci ) {
|
||||
struct pci_bridge *bridge = pci_get_drvdata ( pci );
|
||||
|
||||
/* Remove from list of bridges */
|
||||
list_del ( &bridge->list );
|
||||
|
||||
/* Free device */
|
||||
free ( bridge );
|
||||
}
|
||||
|
||||
/** Bridge PCI device IDs */
|
||||
static struct pci_device_id pcibridge_ids[] = {
|
||||
PCI_ROM ( 0xffff, 0xffff, "bridge", "Bridge", 0 ),
|
||||
};
|
||||
|
||||
/** Bridge PCI driver */
|
||||
struct pci_driver pcibridge_driver __pci_driver = {
|
||||
.ids = pcibridge_ids,
|
||||
.id_count = ( sizeof ( pcibridge_ids ) / sizeof ( pcibridge_ids[0] ) ),
|
||||
.class = PCI_CLASS_ID ( PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_PCI,
|
||||
PCI_ANY_ID ),
|
||||
.probe = pcibridge_probe,
|
||||
.remove = pcibridge_remove,
|
||||
};
|
|
@ -217,6 +217,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
#define ERRFILE_rdc ( ERRFILE_DRIVER | 0x00d10000 )
|
||||
#define ERRFILE_ice ( ERRFILE_DRIVER | 0x00d20000 )
|
||||
#define ERRFILE_ecam ( ERRFILE_DRIVER | 0x00d30000 )
|
||||
#define ERRFILE_pcibridge ( ERRFILE_DRIVER | 0x00d40000 )
|
||||
|
||||
#define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 )
|
||||
#define ERRFILE_arp ( ERRFILE_NET | 0x00010000 )
|
||||
|
|
|
@ -127,6 +127,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
/** Network controller */
|
||||
#define PCI_CLASS_NETWORK 0x02
|
||||
|
||||
/** Bridge device */
|
||||
#define PCI_CLASS_BRIDGE 0x06
|
||||
#define PCI_CLASS_BRIDGE_PCI 0x04 /**< PCI-to-PCI bridge */
|
||||
|
||||
/** Serial bus controller */
|
||||
#define PCI_CLASS_SERIAL 0x0c
|
||||
#define PCI_CLASS_SERIAL_USB 0x03 /**< USB controller */
|
||||
|
@ -135,9 +139,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
#define PCI_CLASS_SERIAL_USB_EHCI 0x20 /**< ECHI USB controller */
|
||||
#define PCI_CLASS_SERIAL_USB_XHCI 0x30 /**< xHCI USB controller */
|
||||
|
||||
/** Primary bus number */
|
||||
#define PCI_PRIMARY 0x18
|
||||
|
||||
/** Secondary bus number */
|
||||
#define PCI_SECONDARY 0x19
|
||||
|
||||
/** Subordinate bus number */
|
||||
#define PCI_SUBORDINATE 0x1a
|
||||
|
||||
/** Memory base and limit */
|
||||
#define PCI_MEM_BASE 0x20
|
||||
#define PCI_MEM_LIMIT 0x22
|
||||
#define PCI_MEM_MASK 0x000f
|
||||
|
||||
/** Construct PCI class
|
||||
*
|
||||
* @v base Base class (or PCI_ANY_ID)
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
#ifndef _IPXE_PCIBRIDGE_H
|
||||
#define _IPXE_PCIBRIDGE_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* PCI-to-PCI bridge
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/list.h>
|
||||
#include <ipxe/pci.h>
|
||||
|
||||
/** A PCI-to-PCI bridge */
|
||||
struct pci_bridge {
|
||||
/** PCI device */
|
||||
struct pci_device *pci;
|
||||
/** Bridge numbers */
|
||||
union {
|
||||
/** Raw dword */
|
||||
uint32_t buses;
|
||||
struct {
|
||||
/** Primary bus */
|
||||
uint8_t primary;
|
||||
/** Secondary bus */
|
||||
uint8_t secondary;
|
||||
/** Subordinate bus */
|
||||
uint8_t subordinate;
|
||||
} __attribute__ (( packed ));
|
||||
};
|
||||
/** Memory base */
|
||||
uint32_t membase;
|
||||
/** Memory limit */
|
||||
uint32_t memlimit;
|
||||
/** List of bridges */
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
extern struct pci_bridge * pcibridge_find ( struct pci_device *pci );
|
||||
|
||||
#endif /* _IPXE_PCIBRIDGE_H */
|
Loading…
Reference in New Issue