diff options
author | RajithaY <rajithax.yerrumsetty@intel.com> | 2017-04-25 03:31:15 -0700 |
---|---|---|
committer | Rajitha Yerrumchetty <rajithax.yerrumsetty@intel.com> | 2017-05-22 06:48:08 +0000 |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/roms/ipxe/src/drivers/bus | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/roms/ipxe/src/drivers/bus')
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/cdc.c | 54 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/eisa.c | 182 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/isa.c | 173 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/isa_ids.c | 26 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/isapnp.c | 756 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/mca.c | 177 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/pci.c | 399 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/pci_settings.c | 128 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/pcibackup.c | 95 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/pciextra.c | 86 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/pcivpd.c | 560 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/usb.c | 2128 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/virtio-pci.c | 64 | ||||
-rw-r--r-- | qemu/roms/ipxe/src/drivers/bus/virtio-ring.c | 136 |
14 files changed, 0 insertions, 4964 deletions
diff --git a/qemu/roms/ipxe/src/drivers/bus/cdc.c b/qemu/roms/ipxe/src/drivers/bus/cdc.c deleted file mode 100644 index 373a03072..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/cdc.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2015 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 <ipxe/usb.h> -#include <ipxe/cdc.h> - -/** @file - * - * USB Communications Device Class (CDC) - * - */ - -/** - * Locate CDC union functional descriptor - * - * @v config Configuration descriptor - * @v interface Interface descriptor - * @ret desc Union functional descriptor, or NULL if not found - */ -struct cdc_union_descriptor * -cdc_union_descriptor ( struct usb_configuration_descriptor *config, - struct usb_interface_descriptor *interface ) { - struct cdc_union_descriptor *desc; - - for_each_interface_descriptor ( desc, config, interface ) { - if ( ( desc->header.type == USB_CS_INTERFACE_DESCRIPTOR ) && - ( desc->subtype == CDC_SUBTYPE_UNION ) ) - return desc; - } - return NULL; -} diff --git a/qemu/roms/ipxe/src/drivers/bus/eisa.c b/qemu/roms/ipxe/src/drivers/bus/eisa.c deleted file mode 100644 index a4efe2621..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/eisa.c +++ /dev/null @@ -1,182 +0,0 @@ -#include <stdint.h> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <ipxe/io.h> -#include <unistd.h> -#include <ipxe/eisa.h> - -FILE_LICENCE ( GPL2_OR_LATER ); - -static void eisabus_remove ( struct root_device *rootdev ); - -/** - * Reset and enable/disable an EISA device - * - * @v eisa EISA device - * @v enabled 1=enable, 0=disable - */ -void eisa_device_enabled ( struct eisa_device *eisa, int enabled ) { - /* Set reset line high for 1000 µs. Spec says 500 µs, but - * this doesn't work for all cards, so we are conservative. - */ - outb ( EISA_CMD_RESET, eisa->ioaddr + EISA_GLOBAL_CONFIG ); - udelay ( 1000 ); /* Must wait 800 */ - - /* Set reset low and write a 1 to ENABLE. Delay again, in - * case the card takes a while to wake up. - */ - outb ( enabled ? EISA_CMD_ENABLE : 0, - eisa->ioaddr + EISA_GLOBAL_CONFIG ); - udelay ( 1000 ); /* Must wait 800 */ - - DBG ( "EISA %s device %02x\n", ( enabled ? "enabled" : "disabled" ), - eisa->slot ); -} - -/** - * Probe an EISA device - * - * @v eisa EISA device - * @ret rc Return status code - * - * Searches for a driver for the EISA device. If a driver is found, - * its probe() routine is called. - */ -static int eisa_probe ( struct eisa_device *eisa ) { - struct eisa_driver *driver; - struct eisa_device_id *id; - unsigned int i; - int rc; - - DBG ( "Adding EISA device %02x (%04x:%04x (\"%s\") io %x)\n", - eisa->slot, eisa->vendor_id, eisa->prod_id, - isa_id_string ( eisa->vendor_id, eisa->prod_id ), eisa->ioaddr ); - - for_each_table_entry ( driver, EISA_DRIVERS ) { - for ( i = 0 ; i < driver->id_count ; i++ ) { - id = &driver->ids[i]; - if ( id->vendor_id != eisa->vendor_id ) - continue; - if ( ISA_PROD_ID ( id->prod_id ) != - ISA_PROD_ID ( eisa->prod_id ) ) - continue; - eisa->driver = driver; - eisa->dev.driver_name = id->name; - DBG ( "...using driver %s\n", eisa->dev.driver_name ); - if ( ( rc = driver->probe ( eisa, id ) ) != 0 ) { - DBG ( "......probe failed\n" ); - continue; - } - return 0; - } - } - - DBG ( "...no driver found\n" ); - return -ENOTTY; -} - -/** - * Remove an EISA device - * - * @v eisa EISA device - */ -static void eisa_remove ( struct eisa_device *eisa ) { - eisa->driver->remove ( eisa ); - DBG ( "Removed EISA device %02x\n", eisa->slot ); -} - -/** - * Probe EISA root bus - * - * @v rootdev EISA bus root device - * - * Scans the EISA bus for devices and registers all devices it can - * find. - */ -static int eisabus_probe ( struct root_device *rootdev ) { - struct eisa_device *eisa = NULL; - unsigned int slot; - int rc; - - for ( slot = EISA_MIN_SLOT ; slot <= EISA_MAX_SLOT ; slot++ ) { - /* Allocate struct eisa_device */ - if ( ! eisa ) - eisa = malloc ( sizeof ( *eisa ) ); - if ( ! eisa ) { - rc = -ENOMEM; - goto err; - } - memset ( eisa, 0, sizeof ( *eisa ) ); - eisa->slot = slot; - eisa->ioaddr = EISA_SLOT_BASE ( eisa->slot ); - - /* Test for board present */ - outb ( 0xff, eisa->ioaddr + EISA_VENDOR_ID ); - eisa->vendor_id = - le16_to_cpu ( inw ( eisa->ioaddr + EISA_VENDOR_ID ) ); - eisa->prod_id = - le16_to_cpu ( inw ( eisa->ioaddr + EISA_PROD_ID ) ); - if ( eisa->vendor_id & 0x80 ) { - /* No board present */ - continue; - } - - /* Add to device hierarchy */ - snprintf ( eisa->dev.name, sizeof ( eisa->dev.name ), - "EISA%02x", slot ); - eisa->dev.desc.bus_type = BUS_TYPE_EISA; - eisa->dev.desc.vendor = eisa->vendor_id; - eisa->dev.desc.device = eisa->prod_id; - eisa->dev.parent = &rootdev->dev; - list_add ( &eisa->dev.siblings, &rootdev->dev.children ); - INIT_LIST_HEAD ( &eisa->dev.children ); - - /* Look for a driver */ - if ( eisa_probe ( eisa ) == 0 ) { - /* eisadev registered, we can drop our ref */ - eisa = NULL; - } else { - /* Not registered; re-use struct */ - list_del ( &eisa->dev.siblings ); - } - } - - free ( eisa ); - return 0; - - err: - free ( eisa ); - eisabus_remove ( rootdev ); - return rc; -} - -/** - * Remove EISA root bus - * - * @v rootdev EISA bus root device - */ -static void eisabus_remove ( struct root_device *rootdev ) { - struct eisa_device *eisa; - struct eisa_device *tmp; - - list_for_each_entry_safe ( eisa, tmp, &rootdev->dev.children, - dev.siblings ) { - eisa_remove ( eisa ); - list_del ( &eisa->dev.siblings ); - free ( eisa ); - } -} - -/** EISA bus root device driver */ -static struct root_driver eisa_root_driver = { - .probe = eisabus_probe, - .remove = eisabus_remove, -}; - -/** EISA bus root device */ -struct root_device eisa_root_device __root_device = { - .dev = { .name = "EISA" }, - .driver = &eisa_root_driver, -}; diff --git a/qemu/roms/ipxe/src/drivers/bus/isa.c b/qemu/roms/ipxe/src/drivers/bus/isa.c deleted file mode 100644 index da0c43c60..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/isa.c +++ /dev/null @@ -1,173 +0,0 @@ -#include <stdint.h> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <ipxe/io.h> -#include <ipxe/isa.h> - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* - * isa.c implements a "classical" port-scanning method of ISA device - * detection. The driver must provide a list of probe addresses - * (probe_addrs), together with a function (probe_addr) that can be - * used to test for the physical presence of a device at any given - * address. - * - * Note that this should probably be considered the "last resort" for - * device probing. If the card supports ISAPnP or EISA, use that - * instead. Some cards (e.g. the 3c509) implement a proprietary - * ISAPnP-like mechanism. - * - * The ISA probe address list can be overridden by config.h; if the - * user specifies ISA_PROBE_ADDRS then that list will be used first. - * (If ISA_PROBE_ONLY is defined, the driver's own list will never be - * used). - */ - -/* - * User-supplied probe address list - * - */ -static isa_probe_addr_t isa_extra_probe_addrs[] = { -#ifdef ISA_PROBE_ADDRS - ISA_PROBE_ADDRS -#endif -}; -#define ISA_EXTRA_PROBE_ADDR_COUNT \ - ( sizeof ( isa_extra_probe_addrs ) / sizeof ( isa_extra_probe_addrs[0] ) ) - -#define ISA_IOIDX_MIN( driver ) ( -ISA_EXTRA_PROBE_ADDR_COUNT ) -#ifdef ISA_PROBE_ONLY -#define ISA_IOIDX_MAX( driver ) ( -1 ) -#else -#define ISA_IOIDX_MAX( driver ) ( (int) (driver)->addr_count - 1 ) -#endif - -#define ISA_IOADDR( driver, ioidx ) \ - ( ( (ioidx) >= 0 ) ? \ - (driver)->probe_addrs[(ioidx)] : \ - *( isa_extra_probe_addrs + (ioidx) + ISA_EXTRA_PROBE_ADDR_COUNT ) ) - -static void isabus_remove ( struct root_device *rootdev ); - -/** - * Probe an ISA device - * - * @v isa ISA device - * @ret rc Return status code - */ -static int isa_probe ( struct isa_device *isa ) { - int rc; - - DBG ( "Trying ISA driver %s at I/O %04x\n", - isa->driver->name, isa->ioaddr ); - - if ( ( rc = isa->driver->probe ( isa ) ) != 0 ) { - DBG ( "...probe failed\n" ); - return rc; - } - - DBG ( "...device found\n" ); - return 0; -} - -/** - * Remove an ISA device - * - * @v isa ISA device - */ -static void isa_remove ( struct isa_device *isa ) { - isa->driver->remove ( isa ); - DBG ( "Removed ISA%04x\n", isa->ioaddr ); -} - -/** - * Probe ISA root bus - * - * @v rootdev ISA bus root device - * - * Scans the ISA bus for devices and registers all devices it can - * find. - */ -static int isabus_probe ( struct root_device *rootdev ) { - struct isa_device *isa = NULL; - struct isa_driver *driver; - int ioidx; - int rc; - - for_each_table_entry ( driver, ISA_DRIVERS ) { - for ( ioidx = ISA_IOIDX_MIN ( driver ) ; - ioidx <= ISA_IOIDX_MAX ( driver ) ; ioidx++ ) { - /* Allocate struct isa_device */ - if ( ! isa ) - isa = malloc ( sizeof ( *isa ) ); - if ( ! isa ) { - rc = -ENOMEM; - goto err; - } - memset ( isa, 0, sizeof ( *isa ) ); - isa->driver = driver; - isa->ioaddr = ISA_IOADDR ( driver, ioidx ); - - /* Add to device hierarchy */ - snprintf ( isa->dev.name, sizeof ( isa->dev.name ), - "ISA%04x", isa->ioaddr ); - isa->dev.driver_name = driver->name; - isa->dev.desc.bus_type = BUS_TYPE_ISA; - isa->dev.desc.vendor = driver->vendor_id; - isa->dev.desc.device = driver->prod_id; - isa->dev.parent = &rootdev->dev; - list_add ( &isa->dev.siblings, - &rootdev->dev.children ); - INIT_LIST_HEAD ( &isa->dev.children ); - - /* Try probing at this I/O address */ - if ( isa_probe ( isa ) == 0 ) { - /* isadev registered, we can drop our ref */ - isa = NULL; - } else { - /* Not registered; re-use struct */ - list_del ( &isa->dev.siblings ); - } - } - } - - free ( isa ); - return 0; - - err: - free ( isa ); - isabus_remove ( rootdev ); - return rc; -} - -/** - * Remove ISA root bus - * - * @v rootdev ISA bus root device - */ -static void isabus_remove ( struct root_device *rootdev ) { - struct isa_device *isa; - struct isa_device *tmp; - - list_for_each_entry_safe ( isa, tmp, &rootdev->dev.children, - dev.siblings ) { - isa_remove ( isa ); - list_del ( &isa->dev.siblings ); - free ( isa ); - } -} - -/** ISA bus root device driver */ -static struct root_driver isa_root_driver = { - .probe = isabus_probe, - .remove = isabus_remove, -}; - -/** ISA bus root device */ -struct root_device isa_root_device __root_device = { - .dev = { .name = "ISA" }, - .driver = &isa_root_driver, -}; diff --git a/qemu/roms/ipxe/src/drivers/bus/isa_ids.c b/qemu/roms/ipxe/src/drivers/bus/isa_ids.c deleted file mode 100644 index e72b233f3..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/isa_ids.c +++ /dev/null @@ -1,26 +0,0 @@ -#include <stdint.h> -#include <stdio.h> -#include <byteswap.h> -#include <ipxe/isa_ids.h> - -/* - * EISA and ISAPnP IDs are actually mildly human readable, though in a - * somewhat brain-damaged way. - * - */ -char * isa_id_string ( unsigned int vendor, unsigned int product ) { - static char buf[7]; - int i; - - /* Vendor ID is a compressed ASCII string */ - vendor = bswap_16 ( vendor ); - for ( i = 2 ; i >= 0 ; i-- ) { - buf[i] = ( 'A' - 1 + ( vendor & 0x1f ) ); - vendor >>= 5; - } - - /* Product ID is a 4-digit hex string */ - sprintf ( &buf[3], "%04x", bswap_16 ( product ) ); - - return buf; -} diff --git a/qemu/roms/ipxe/src/drivers/bus/isapnp.c b/qemu/roms/ipxe/src/drivers/bus/isapnp.c deleted file mode 100644 index 6417c74a6..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/isapnp.c +++ /dev/null @@ -1,756 +0,0 @@ -/************************************************************************** -* -* isapnp.c -- Etherboot isapnp support for the 3Com 3c515 -* Written 2002-2003 by Timothy Legge <tlegge@rogers.com> -* -* 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. -* -* Portions of this code: -* Copyright (C) 2001 P.J.H.Fox (fox@roestock.demon.co.uk) -* -* -* REVISION HISTORY: -* ================ -* Version 0.1 April 26, 2002 TJL -* Version 0.2 01/08/2003 TJL Moved outside the 3c515.c driver file -* Version 0.3 Sept 23, 2003 timlegge Change delay to currticks -* -* -* Generalised into an ISAPnP bus that can be used by more than just -* the 3c515 by Michael Brown <mbrown@fensystems.co.uk> -* -***************************************************************************/ - -/** @file - * - * ISAPnP bus support - * - * Etherboot orignally gained ISAPnP support in a very limited way for - * the 3c515 NIC. The current implementation is almost a complete - * rewrite based on the ISAPnP specification, with passing reference - * to the Linux ISAPnP code. - * - * There can be only one ISAPnP bus in a system. Once the read port - * is known and all cards have been allocated CSNs, there's nothing to - * be gained by re-scanning for cards. - * - * External code (e.g. the ISAPnP ROM prefix) may already know the - * read port address, in which case it can store it in - * #isapnp_read_port. Note that setting the read port address in this - * way will prevent further isolation from taking place; you should - * set the read port address only if you know that devices have - * already been allocated CSNs. - * - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <errno.h> -#include <ipxe/io.h> -#include <unistd.h> -#include <ipxe/isapnp.h> - -/** - * ISAPnP Read Port address. - * - * ROM prefix may be able to set this address, which is why this is - * non-static. - */ -uint16_t isapnp_read_port; - -static void isapnpbus_remove ( struct root_device *rootdev ); - -/* - * ISAPnP utility functions - * - */ - -#define ISAPNP_CARD_ID_FMT "ID %04x:%04x (\"%s\") serial %x" -#define ISAPNP_CARD_ID_DATA(identifier) \ - (identifier)->vendor_id, (identifier)->prod_id, \ - isa_id_string ( (identifier)->vendor_id, (identifier)->prod_id ), \ - (identifier)->serial -#define ISAPNP_DEV_ID_FMT "ID %04x:%04x (\"%s\")" -#define ISAPNP_DEV_ID_DATA(isapnp) \ - (isapnp)->vendor_id, (isapnp)->prod_id, \ - isa_id_string ( (isapnp)->vendor_id, (isapnp)->prod_id ) - -static inline void isapnp_write_address ( unsigned int address ) { - outb ( address, ISAPNP_ADDRESS ); -} - -static inline void isapnp_write_data ( unsigned int data ) { - outb ( data, ISAPNP_WRITE_DATA ); -} - -static inline unsigned int isapnp_read_data ( void ) { - return inb ( isapnp_read_port ); -} - -static inline void isapnp_write_byte ( unsigned int address, - unsigned int value ) { - isapnp_write_address ( address ); - isapnp_write_data ( value ); -} - -static inline unsigned int isapnp_read_byte ( unsigned int address ) { - isapnp_write_address ( address ); - return isapnp_read_data (); -} - -static inline unsigned int isapnp_read_word ( unsigned int address ) { - /* Yes, they're in big-endian order */ - return ( ( isapnp_read_byte ( address ) << 8 ) - | isapnp_read_byte ( address + 1 ) ); -} - -/** Inform cards of a new read port address */ -static inline void isapnp_set_read_port ( void ) { - isapnp_write_byte ( ISAPNP_READPORT, ( isapnp_read_port >> 2 ) ); -} - -/** - * Enter the Isolation state. - * - * Only cards currently in the Sleep state will respond to this - * command. - */ -static inline void isapnp_serialisolation ( void ) { - isapnp_write_address ( ISAPNP_SERIALISOLATION ); -} - -/** - * Enter the Wait for Key state. - * - * All cards will respond to this command, regardless of their current - * state. - */ -static inline void isapnp_wait_for_key ( void ) { - isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_WAIT_FOR_KEY ); -} - -/** - * Reset (i.e. remove) Card Select Number. - * - * Only cards currently in the Sleep state will respond to this - * command. - */ -static inline void isapnp_reset_csn ( void ) { - isapnp_write_byte ( ISAPNP_CONFIGCONTROL, ISAPNP_CONFIG_RESET_CSN ); -} - -/** - * Place a specified card into the Config state. - * - * @v csn Card Select Number - * @ret None - - * @err None - - * - * Only cards currently in the Sleep, Isolation, or Config states will - * respond to this command. The card that has the specified CSN will - * enter the Config state, all other cards will enter the Sleep state. - */ -static inline void isapnp_wake ( uint8_t csn ) { - isapnp_write_byte ( ISAPNP_WAKE, csn ); -} - -static inline unsigned int isapnp_read_resourcedata ( void ) { - return isapnp_read_byte ( ISAPNP_RESOURCEDATA ); -} - -static inline unsigned int isapnp_read_status ( void ) { - return isapnp_read_byte ( ISAPNP_STATUS ); -} - -/** - * Assign a Card Select Number to a card, and enter the Config state. - * - * @v csn Card Select Number - * - * Only cards in the Isolation state will respond to this command. - * The isolation protocol is designed so that only one card will - * remain in the Isolation state by the time the isolation protocol - * completes. - */ -static inline void isapnp_write_csn ( unsigned int csn ) { - isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn ); -} - -static inline void isapnp_logicaldevice ( unsigned int logdev ) { - isapnp_write_byte ( ISAPNP_LOGICALDEVICENUMBER, logdev ); -} - -static inline void isapnp_activate ( unsigned int logdev ) { - isapnp_logicaldevice ( logdev ); - isapnp_write_byte ( ISAPNP_ACTIVATE, 1 ); -} - -static inline void isapnp_deactivate ( unsigned int logdev ) { - isapnp_logicaldevice ( logdev ); - isapnp_write_byte ( ISAPNP_ACTIVATE, 0 ); -} - -static inline unsigned int isapnp_read_iobase ( unsigned int index ) { - return isapnp_read_word ( ISAPNP_IOBASE ( index ) ); -} - -static inline unsigned int isapnp_read_irqno ( unsigned int index ) { - return isapnp_read_byte ( ISAPNP_IRQNO ( index ) ); -} - -static void isapnp_delay ( void ) { - udelay ( 1000 ); -} - -/** - * Linear feedback shift register. - * - * @v lfsr Current value of the LFSR - * @v input_bit Current input bit to the LFSR - * @ret lfsr Next value of the LFSR - * - * This routine implements the linear feedback shift register as - * described in Appendix B of the PnP ISA spec. The hardware - * implementation uses eight D-type latches and two XOR gates. I - * think this is probably the smallest possible implementation in - * software. Six instructions when input_bit is a constant 0 (for - * isapnp_send_key). :) - */ -static inline unsigned int isapnp_lfsr_next ( unsigned int lfsr, - unsigned int input_bit ) { - register uint8_t lfsr_next; - - lfsr_next = lfsr >> 1; - lfsr_next |= ( ( ( lfsr ^ lfsr_next ) ^ input_bit ) ) << 7; - return lfsr_next; -} - -/** - * Send the ISAPnP initiation key. - * - * Sending the key causes all ISAPnP cards that are currently in the - * Wait for Key state to transition into the Sleep state. - */ -static void isapnp_send_key ( void ) { - unsigned int i; - unsigned int lfsr; - - isapnp_delay(); - isapnp_write_address ( 0x00 ); - isapnp_write_address ( 0x00 ); - - lfsr = ISAPNP_LFSR_SEED; - for ( i = 0 ; i < 32 ; i++ ) { - isapnp_write_address ( lfsr ); - lfsr = isapnp_lfsr_next ( lfsr, 0 ); - } -} - -/** - * Compute ISAPnP identifier checksum - * - * @v identifier ISAPnP identifier - * @ret checksum Expected checksum value - */ -static unsigned int isapnp_checksum ( struct isapnp_identifier *identifier ) { - unsigned int i, j; - unsigned int lfsr; - unsigned int byte; - - lfsr = ISAPNP_LFSR_SEED; - for ( i = 0 ; i < 8 ; i++ ) { - byte = * ( ( ( uint8_t * ) identifier ) + i ); - for ( j = 0 ; j < 8 ; j++ ) { - lfsr = isapnp_lfsr_next ( lfsr, byte ); - byte >>= 1; - } - } - return lfsr; -} - -/* - * Read a byte of resource data from the current location - * - * @ret byte Byte of resource data - */ -static inline unsigned int isapnp_peek_byte ( void ) { - unsigned int i; - - /* Wait for data to be ready */ - for ( i = 0 ; i < 20 ; i++ ) { - if ( isapnp_read_status() & 0x01 ) { - /* Byte ready - read it */ - return isapnp_read_resourcedata(); - } - isapnp_delay(); - } - /* Data never became ready - return 0xff */ - return 0xff; -} - -/** - * Read resource data. - * - * @v buf Buffer in which to store data, or NULL - * @v bytes Number of bytes to read - * - * Resource data is read from the current location. If #buf is NULL, - * the data is discarded. - */ -static void isapnp_peek ( void *buf, size_t len ) { - unsigned int i; - unsigned int byte; - - for ( i = 0 ; i < len ; i++) { - byte = isapnp_peek_byte(); - if ( buf ) - * ( ( uint8_t * ) buf + i ) = byte; - } -} - -/** - * Find a tag within the resource data. - * - * @v wanted_tag The tag that we're looking for - * @v buf Buffer in which to store the tag's contents - * @v len Length of buffer - * @ret rc Return status code - * - * Scan through the resource data until we find a particular tag, and - * read its contents into a buffer. - */ -static int isapnp_find_tag ( unsigned int wanted_tag, void *buf, size_t len ) { - unsigned int tag; - unsigned int tag_len; - - DBG2 ( "ISAPnP read tag" ); - do { - tag = isapnp_peek_byte(); - if ( ISAPNP_IS_SMALL_TAG ( tag ) ) { - tag_len = ISAPNP_SMALL_TAG_LEN ( tag ); - tag = ISAPNP_SMALL_TAG_NAME ( tag ); - } else { - tag_len = ( isapnp_peek_byte() + - ( isapnp_peek_byte() << 8 ) ); - tag = ISAPNP_LARGE_TAG_NAME ( tag ); - } - DBG2 ( " %02x (%02x)", tag, tag_len ); - if ( tag == wanted_tag ) { - if ( len > tag_len ) - len = tag_len; - isapnp_peek ( buf, len ); - DBG2 ( "\n" ); - return 0; - } else { - isapnp_peek ( NULL, tag_len ); - } - } while ( tag != ISAPNP_TAG_END ); - DBG2 ( "\n" ); - return -ENOENT; -} - -/** - * Find specified Logical Device ID tag - * - * @v logdev Logical device ID - * @v logdevid Logical device ID structure to fill in - * @ret rc Return status code - */ -static int isapnp_find_logdevid ( unsigned int logdev, - struct isapnp_logdevid *logdevid ) { - unsigned int i; - int rc; - - for ( i = 0 ; i <= logdev ; i++ ) { - if ( ( rc = isapnp_find_tag ( ISAPNP_TAG_LOGDEVID, logdevid, - sizeof ( *logdevid ) ) ) != 0 ) - return rc; - } - return 0; -} - -/** - * Try isolating ISAPnP cards at the current read port. - * - * @ret \>0 Number of ISAPnP cards found - * @ret 0 There are no ISAPnP cards in the system - * @ret \<0 A conflict was detected; try a new read port - * @err None - - * - * The state diagram on page 18 (PDF page 24) of the PnP ISA spec - * gives the best overview of what happens here. - */ -static int isapnp_try_isolate ( void ) { - struct isapnp_identifier identifier; - unsigned int i, j; - unsigned int seen_55aa, seen_life; - unsigned int csn = 0; - unsigned int data; - unsigned int byte; - - DBG ( "ISAPnP attempting isolation at read port %04x\n", - isapnp_read_port ); - - /* Place all cards into the Sleep state, whatever state - * they're currently in. - */ - isapnp_wait_for_key(); - isapnp_send_key(); - - /* Reset all assigned CSNs */ - isapnp_reset_csn(); - isapnp_delay(); - isapnp_delay(); - - /* Place all cards into the Isolation state */ - isapnp_wait_for_key (); - isapnp_send_key(); - isapnp_wake ( 0x00 ); - - /* Set the read port */ - isapnp_set_read_port(); - isapnp_delay(); - - while ( 1 ) { - - /* All cards that do not have assigned CSNs are - * currently in the Isolation state, each time we go - * through this loop. - */ - - /* Initiate serial isolation */ - isapnp_serialisolation(); - isapnp_delay(); - - /* Read identifier serially via the ISAPnP read port. */ - memset ( &identifier, 0, sizeof ( identifier ) ); - seen_55aa = seen_life = 0; - for ( i = 0 ; i < 9 ; i++ ) { - byte = 0; - for ( j = 0 ; j < 8 ; j++ ) { - data = isapnp_read_data(); - isapnp_delay(); - data = ( ( data << 8 ) | isapnp_read_data() ); - isapnp_delay(); - byte >>= 1; - if ( data != 0xffff ) { - seen_life++; - if ( data == 0x55aa ) { - byte |= 0x80; - seen_55aa++; - } - } - } - *( ( ( uint8_t * ) &identifier ) + i ) = byte; - } - - /* If we didn't see any 55aa patterns, stop here */ - if ( ! seen_55aa ) { - if ( csn ) { - DBG ( "ISAPnP found no more cards\n" ); - } else { - if ( seen_life ) { - DBG ( "ISAPnP saw life but no cards, " - "trying new read port\n" ); - csn = -1; - } else { - DBG ( "ISAPnP saw no signs of life, " - "abandoning isolation\n" ); - } - } - break; - } - - /* If the checksum was invalid stop here */ - if ( identifier.checksum != isapnp_checksum ( &identifier) ) { - DBG ( "ISAPnP found malformed card " - ISAPNP_CARD_ID_FMT "\n with checksum %02x " - "(should be %02x), trying new read port\n", - ISAPNP_CARD_ID_DATA ( &identifier ), - identifier.checksum, - isapnp_checksum ( &identifier) ); - csn = -1; - break; - } - - /* Give the device a CSN */ - csn++; - DBG ( "ISAPnP found card " ISAPNP_CARD_ID_FMT - ", assigning CSN %02x\n", - ISAPNP_CARD_ID_DATA ( &identifier ), csn ); - - isapnp_write_csn ( csn ); - isapnp_delay(); - - /* Send this card back to Sleep and force all cards - * without a CSN into Isolation state - */ - isapnp_wake ( 0x00 ); - isapnp_delay(); - } - - /* Place all cards in Wait for Key state */ - isapnp_wait_for_key(); - - /* Return number of cards found */ - if ( csn > 0 ) { - DBG ( "ISAPnP found %d cards at read port %04x\n", - csn, isapnp_read_port ); - } - return csn; -} - -/** - * Find a valid read port and isolate all ISAPnP cards. - * - */ -static void isapnp_isolate ( void ) { - for ( isapnp_read_port = ISAPNP_READ_PORT_START ; - isapnp_read_port <= ISAPNP_READ_PORT_MAX ; - isapnp_read_port += ISAPNP_READ_PORT_STEP ) { - /* Avoid problematic locations such as the NE2000 - * probe space - */ - if ( ( isapnp_read_port >= 0x280 ) && - ( isapnp_read_port <= 0x380 ) ) - continue; - - /* If we detect any ISAPnP cards at this location, stop */ - if ( isapnp_try_isolate() >= 0 ) - return; - } -} - -/** - * Activate or deactivate an ISAPnP device. - * - * @v isapnp ISAPnP device - * @v activation True to enable, False to disable the device - * @ret None - - * @err None - - * - * This routine simply activates the device in its current - * configuration, or deactivates the device. It does not attempt any - * kind of resource arbitration. - * - */ -void isapnp_device_activation ( struct isapnp_device *isapnp, - int activation ) { - /* Wake the card and select the logical device */ - isapnp_wait_for_key (); - isapnp_send_key (); - isapnp_wake ( isapnp->csn ); - isapnp_logicaldevice ( isapnp->logdev ); - - /* Activate/deactivate the logical device */ - isapnp_activate ( activation ); - isapnp_delay(); - - /* Return all cards to Wait for Key state */ - isapnp_wait_for_key (); - - DBG ( "ISAPnP %s device %02x:%02x\n", - ( activation ? "activated" : "deactivated" ), - isapnp->csn, isapnp->logdev ); -} - -/** - * Probe an ISAPnP device - * - * @v isapnp ISAPnP device - * @ret rc Return status code - * - * Searches for a driver for the ISAPnP device. If a driver is found, - * its probe() routine is called. - */ -static int isapnp_probe ( struct isapnp_device *isapnp ) { - struct isapnp_driver *driver; - struct isapnp_device_id *id; - unsigned int i; - int rc; - - DBG ( "Adding ISAPnP device %02x:%02x (%04x:%04x (\"%s\") " - "io %x irq %d)\n", isapnp->csn, isapnp->logdev, - isapnp->vendor_id, isapnp->prod_id, - isa_id_string ( isapnp->vendor_id, isapnp->prod_id ), - isapnp->ioaddr, isapnp->irqno ); - - for_each_table_entry ( driver, ISAPNP_DRIVERS ) { - for ( i = 0 ; i < driver->id_count ; i++ ) { - id = &driver->ids[i]; - if ( id->vendor_id != isapnp->vendor_id ) - continue; - if ( ISA_PROD_ID ( id->prod_id ) != - ISA_PROD_ID ( isapnp->prod_id ) ) - continue; - isapnp->driver = driver; - isapnp->dev.driver_name = id->name; - DBG ( "...using driver %s\n", isapnp->dev.driver_name ); - if ( ( rc = driver->probe ( isapnp, id ) ) != 0 ) { - DBG ( "......probe failed\n" ); - continue; - } - return 0; - } - } - - DBG ( "...no driver found\n" ); - return -ENOTTY; -} - -/** - * Remove an ISAPnP device - * - * @v isapnp ISAPnP device - */ -static void isapnp_remove ( struct isapnp_device *isapnp ) { - isapnp->driver->remove ( isapnp ); - DBG ( "Removed ISAPnP device %02x:%02x\n", - isapnp->csn, isapnp->logdev ); -} - -/** - * Probe ISAPnP root bus - * - * @v rootdev ISAPnP bus root device - * - * Scans the ISAPnP bus for devices and registers all devices it can - * find. - */ -static int isapnpbus_probe ( struct root_device *rootdev ) { - struct isapnp_device *isapnp = NULL; - struct isapnp_identifier identifier; - struct isapnp_logdevid logdevid; - unsigned int csn; - unsigned int logdev; - int rc; - - /* Perform isolation if it hasn't yet been done */ - if ( ! isapnp_read_port ) - isapnp_isolate(); - - for ( csn = 1 ; csn <= 0xff ; csn++ ) { - for ( logdev = 0 ; logdev <= 0xff ; logdev++ ) { - - /* Allocate struct isapnp_device */ - if ( ! isapnp ) - isapnp = malloc ( sizeof ( *isapnp ) ); - if ( ! isapnp ) { - rc = -ENOMEM; - goto err; - } - memset ( isapnp, 0, sizeof ( *isapnp ) ); - isapnp->csn = csn; - isapnp->logdev = logdev; - - /* Wake the card */ - isapnp_wait_for_key(); - isapnp_send_key(); - isapnp_wake ( csn ); - - /* Read the card identifier */ - isapnp_peek ( &identifier, sizeof ( identifier ) ); - - /* No card with this CSN; stop here */ - if ( identifier.vendor_id & 0x80 ) - goto done; - - /* Find the Logical Device ID tag */ - if ( ( rc = isapnp_find_logdevid ( logdev, - &logdevid ) ) != 0){ - /* No more logical devices; go to next CSN */ - break; - } - - /* Select the logical device */ - isapnp_logicaldevice ( logdev ); - - /* Populate struct isapnp_device */ - isapnp->vendor_id = logdevid.vendor_id; - isapnp->prod_id = logdevid.prod_id; - isapnp->ioaddr = isapnp_read_iobase ( 0 ); - isapnp->irqno = isapnp_read_irqno ( 0 ); - - /* Return all cards to Wait for Key state */ - isapnp_wait_for_key(); - - /* Add to device hierarchy */ - snprintf ( isapnp->dev.name, - sizeof ( isapnp->dev.name ), - "ISAPnP%02x:%02x", csn, logdev ); - isapnp->dev.desc.bus_type = BUS_TYPE_ISAPNP; - isapnp->dev.desc.vendor = isapnp->vendor_id; - isapnp->dev.desc.device = isapnp->prod_id; - isapnp->dev.desc.ioaddr = isapnp->ioaddr; - isapnp->dev.desc.irq = isapnp->irqno; - isapnp->dev.parent = &rootdev->dev; - list_add ( &isapnp->dev.siblings, - &rootdev->dev.children ); - INIT_LIST_HEAD ( &isapnp->dev.children ); - - /* Look for a driver */ - if ( isapnp_probe ( isapnp ) == 0 ) { - /* isapnpdev registered, we can drop our ref */ - isapnp = NULL; - } else { - /* Not registered; re-use struct */ - list_del ( &isapnp->dev.siblings ); - } - } - } - - done: - free ( isapnp ); - return 0; - - err: - free ( isapnp ); - isapnpbus_remove ( rootdev ); - return rc; -} - -/** - * Remove ISAPnP root bus - * - * @v rootdev ISAPnP bus root device - */ -static void isapnpbus_remove ( struct root_device *rootdev ) { - struct isapnp_device *isapnp; - struct isapnp_device *tmp; - - list_for_each_entry_safe ( isapnp, tmp, &rootdev->dev.children, - dev.siblings ) { - isapnp_remove ( isapnp ); - list_del ( &isapnp->dev.siblings ); - free ( isapnp ); - } -} - -/** ISAPnP bus root device driver */ -static struct root_driver isapnp_root_driver = { - .probe = isapnpbus_probe, - .remove = isapnpbus_remove, -}; - -/** ISAPnP bus root device */ -struct root_device isapnp_root_device __root_device = { - .dev = { .name = "ISAPnP" }, - .driver = &isapnp_root_driver, -}; diff --git a/qemu/roms/ipxe/src/drivers/bus/mca.c b/qemu/roms/ipxe/src/drivers/bus/mca.c deleted file mode 100644 index 0405c3b88..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/mca.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * MCA bus driver code - * - * Abstracted from 3c509.c. - * - */ - -FILE_LICENCE ( BSD2 ); - -#include <stdint.h> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <ipxe/io.h> -#include <ipxe/mca.h> - -static void mcabus_remove ( struct root_device *rootdev ); - -/** - * Probe an MCA device - * - * @v mca MCA device - * @ret rc Return status code - * - * Searches for a driver for the MCA device. If a driver is found, - * its probe() routine is called. - */ -static int mca_probe ( struct mca_device *mca ) { - struct mca_driver *driver; - struct mca_device_id *id; - unsigned int i; - int rc; - - DBG ( "Adding MCA slot %02x (ID %04x POS " - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)\n", - mca->slot, MCA_ID ( mca ), - mca->pos[0], mca->pos[1], mca->pos[2], mca->pos[3], - mca->pos[4], mca->pos[5], mca->pos[6], mca->pos[7] ); - - for_each_table_entry ( driver, MCA_DRIVERS ) { - for ( i = 0 ; i < driver->id_count ; i++ ) { - id = &driver->ids[i]; - if ( id->id != MCA_ID ( mca ) ) - continue; - mca->driver = driver; - mca->dev.driver_name = id->name; - DBG ( "...using driver %s\n", mca->dev.driver_name ); - if ( ( rc = driver->probe ( mca, id ) ) != 0 ) { - DBG ( "......probe failed\n" ); - continue; - } - return 0; - } - } - - DBG ( "...no driver found\n" ); - return -ENOTTY; -} - -/** - * Remove an MCA device - * - * @v mca MCA device - */ -static void mca_remove ( struct mca_device *mca ) { - mca->driver->remove ( mca ); - DBG ( "Removed MCA device %02x\n", mca->slot ); -} - -/** - * Probe MCA root bus - * - * @v rootdev MCA bus root device - * - * Scans the MCA bus for devices and registers all devices it can - * find. - */ -static int mcabus_probe ( struct root_device *rootdev ) { - struct mca_device *mca = NULL; - unsigned int slot; - int seen_non_ff; - unsigned int i; - int rc; - - for ( slot = 0 ; slot <= MCA_MAX_SLOT_NR ; slot++ ) { - /* Allocate struct mca_device */ - if ( ! mca ) - mca = malloc ( sizeof ( *mca ) ); - if ( ! mca ) { - rc = -ENOMEM; - goto err; - } - memset ( mca, 0, sizeof ( *mca ) ); - mca->slot = slot; - - /* Make sure motherboard setup is off */ - outb_p ( 0xff, MCA_MOTHERBOARD_SETUP_REG ); - - /* Select the slot */ - outb_p ( 0x8 | ( mca->slot & 0xf ), MCA_ADAPTER_SETUP_REG ); - - /* Read the POS registers */ - seen_non_ff = 0; - for ( i = 0 ; i < ( sizeof ( mca->pos ) / - sizeof ( mca->pos[0] ) ) ; i++ ) { - mca->pos[i] = inb_p ( MCA_POS_REG ( i ) ); - if ( mca->pos[i] != 0xff ) - seen_non_ff = 1; - } - - /* Kill all setup modes */ - outb_p ( 0, MCA_ADAPTER_SETUP_REG ); - - /* If all POS registers are 0xff, this means there's no device - * present - */ - if ( ! seen_non_ff ) - continue; - - /* Add to device hierarchy */ - snprintf ( mca->dev.name, sizeof ( mca->dev.name ), - "MCA%02x", slot ); - mca->dev.desc.bus_type = BUS_TYPE_MCA; - mca->dev.desc.vendor = GENERIC_MCA_VENDOR; - mca->dev.desc.device = MCA_ID ( mca ); - mca->dev.parent = &rootdev->dev; - list_add ( &mca->dev.siblings, &rootdev->dev.children ); - INIT_LIST_HEAD ( &mca->dev.children ); - - /* Look for a driver */ - if ( mca_probe ( mca ) == 0 ) { - /* mcadev registered, we can drop our ref */ - mca = NULL; - } else { - /* Not registered; re-use struct */ - list_del ( &mca->dev.siblings ); - } - } - - free ( mca ); - return 0; - - err: - free ( mca ); - mcabus_remove ( rootdev ); - return rc; -} - -/** - * Remove MCA root bus - * - * @v rootdev MCA bus root device - */ -static void mcabus_remove ( struct root_device *rootdev ) { - struct mca_device *mca; - struct mca_device *tmp; - - list_for_each_entry_safe ( mca, tmp, &rootdev->dev.children, - dev.siblings ) { - mca_remove ( mca ); - list_del ( &mca->dev.siblings ); - free ( mca ); - } -} - -/** MCA bus root device driver */ -static struct root_driver mca_root_driver = { - .probe = mcabus_probe, - .remove = mcabus_remove, -}; - -/** MCA bus root device */ -struct root_device mca_root_device __root_device = { - .dev = { .name = "MCA" }, - .driver = &mca_root_driver, -}; diff --git a/qemu/roms/ipxe/src/drivers/bus/pci.c b/qemu/roms/ipxe/src/drivers/bus/pci.c deleted file mode 100644 index 6fbedd940..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/pci.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>. - * - * Based in part on pci.c from Etherboot 5.4, by Ken Yap and David - * Munro, in turn based on the Linux kernel's PCI implementation. - * - * 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 <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <ipxe/tables.h> -#include <ipxe/device.h> -#include <ipxe/pci.h> - -/** @file - * - * PCI bus - * - */ - -static void pcibus_remove ( struct root_device *rootdev ); - -/** - * Read PCI BAR - * - * @v pci PCI device - * @v reg PCI register number - * @ret bar Base address register - * - * Reads the specified PCI base address register, including the flags - * portion. 64-bit BARs will be handled automatically. If the value - * of the 64-bit BAR exceeds the size of an unsigned long (i.e. if the - * high dword is non-zero on a 32-bit platform), then the value - * returned will be zero plus the flags for a 64-bit BAR. Unreachable - * 64-bit BARs are therefore returned as uninitialised 64-bit BARs. - */ -static unsigned long pci_bar ( struct pci_device *pci, unsigned int reg ) { - uint32_t low; - uint32_t high; - - pci_read_config_dword ( pci, reg, &low ); - if ( ( low & (PCI_BASE_ADDRESS_SPACE_IO|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) - == PCI_BASE_ADDRESS_MEM_TYPE_64 ) { - pci_read_config_dword ( pci, reg + 4, &high ); - if ( high ) { - if ( sizeof ( unsigned long ) > sizeof ( uint32_t ) ) { - return ( ( ( uint64_t ) high << 32 ) | low ); - } else { - DBGC ( pci, PCI_FMT " unhandled 64-bit BAR " - "%08x%08x\n", - PCI_ARGS ( pci ), high, low ); - return PCI_BASE_ADDRESS_MEM_TYPE_64; - } - } - } - return low; -} - -/** - * Find the start of a PCI BAR - * - * @v pci PCI device - * @v reg PCI register number - * @ret start BAR start address - * - * Reads the specified PCI base address register, and returns the - * address portion of the BAR (i.e. without the flags). - * - * If the address exceeds the size of an unsigned long (i.e. if a - * 64-bit BAR has a non-zero high dword on a 32-bit machine), the - * return value will be zero. - */ -unsigned long pci_bar_start ( struct pci_device *pci, unsigned int reg ) { - unsigned long bar; - - bar = pci_bar ( pci, reg ); - if ( bar & PCI_BASE_ADDRESS_SPACE_IO ) { - return ( bar & ~PCI_BASE_ADDRESS_IO_MASK ); - } else { - return ( bar & ~PCI_BASE_ADDRESS_MEM_MASK ); - } -} - -/** - * Read membase and ioaddr for a PCI device - * - * @v pci PCI device - * - * This scans through all PCI BARs on the specified device. The first - * valid memory BAR is recorded as pci_device::membase, and the first - * valid IO BAR is recorded as pci_device::ioaddr. - * - * 64-bit BARs are handled automatically. On a 32-bit platform, if a - * 64-bit BAR has a non-zero high dword, it will be regarded as - * invalid. - */ -static void pci_read_bases ( struct pci_device *pci ) { - unsigned long bar; - int reg; - - for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4 ) { - bar = pci_bar ( pci, reg ); - if ( bar & PCI_BASE_ADDRESS_SPACE_IO ) { - if ( ! pci->ioaddr ) - pci->ioaddr = - ( bar & ~PCI_BASE_ADDRESS_IO_MASK ); - } else { - if ( ! pci->membase ) - pci->membase = - ( bar & ~PCI_BASE_ADDRESS_MEM_MASK ); - /* Skip next BAR if 64-bit */ - if ( bar & PCI_BASE_ADDRESS_MEM_TYPE_64 ) - reg += 4; - } - } -} - -/** - * Enable PCI device - * - * @v pci PCI device - * - * Set device to be a busmaster in case BIOS neglected to do so. Also - * adjust PCI latency timer to a reasonable value, 32. - */ -void adjust_pci_device ( struct pci_device *pci ) { - unsigned short new_command, pci_command; - unsigned char pci_latency; - - pci_read_config_word ( pci, PCI_COMMAND, &pci_command ); - new_command = ( pci_command | PCI_COMMAND_MASTER | - PCI_COMMAND_MEM | PCI_COMMAND_IO ); - if ( pci_command != new_command ) { - DBGC ( pci, PCI_FMT " device not enabled by BIOS! Updating " - "PCI command %04x->%04x\n", - PCI_ARGS ( pci ), pci_command, new_command ); - pci_write_config_word ( pci, PCI_COMMAND, new_command ); - } - - pci_read_config_byte ( pci, PCI_LATENCY_TIMER, &pci_latency); - if ( pci_latency < 32 ) { - DBGC ( pci, PCI_FMT " latency timer is unreasonably low at " - "%d. Setting to 32.\n", PCI_ARGS ( pci ), pci_latency ); - pci_write_config_byte ( pci, PCI_LATENCY_TIMER, 32); - } -} - -/** - * Read PCI device configuration - * - * @v pci PCI device - * @ret rc Return status code - */ -int pci_read_config ( struct pci_device *pci ) { - uint16_t busdevfn; - uint8_t hdrtype; - uint32_t tmp; - - /* Ignore all but the first function on non-multifunction devices */ - if ( PCI_FUNC ( pci->busdevfn ) != 0 ) { - busdevfn = pci->busdevfn; - pci->busdevfn = PCI_FIRST_FUNC ( pci->busdevfn ); - pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype ); - pci->busdevfn = busdevfn; - if ( ! ( hdrtype & PCI_HEADER_TYPE_MULTI ) ) - return -ENODEV; - } - - /* Check for physical device presence */ - pci_read_config_dword ( pci, PCI_VENDOR_ID, &tmp ); - if ( ( tmp == 0xffffffff ) || ( tmp == 0 ) ) - return -ENODEV; - - /* Populate struct pci_device */ - pci->vendor = ( tmp & 0xffff ); - pci->device = ( tmp >> 16 ); - pci_read_config_dword ( pci, PCI_REVISION, &tmp ); - pci->class = ( tmp >> 8 ); - pci_read_config_byte ( pci, PCI_INTERRUPT_LINE, &pci->irq ); - pci_read_bases ( pci ); - - /* Initialise generic device component */ - snprintf ( pci->dev.name, sizeof ( pci->dev.name ), - "PCI%02x:%02x.%x", PCI_BUS ( pci->busdevfn ), - PCI_SLOT ( pci->busdevfn ), PCI_FUNC ( pci->busdevfn ) ); - pci->dev.desc.bus_type = BUS_TYPE_PCI; - pci->dev.desc.location = pci->busdevfn; - pci->dev.desc.vendor = pci->vendor; - pci->dev.desc.device = pci->device; - pci->dev.desc.class = pci->class; - pci->dev.desc.ioaddr = pci->ioaddr; - pci->dev.desc.irq = pci->irq; - INIT_LIST_HEAD ( &pci->dev.siblings ); - INIT_LIST_HEAD ( &pci->dev.children ); - - return 0; -} - -/** - * Find next device on PCI bus - * - * @v pci PCI device to fill in - * @v busdevfn Starting bus:dev.fn address - * @ret busdevfn Bus:dev.fn address of next PCI device, or negative error - */ -int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) { - static unsigned int end; - int rc; - - /* Determine number of PCI buses */ - if ( ! end ) - end = PCI_BUSDEVFN ( pci_num_bus(), 0, 0 ); - - /* Find next PCI device, if any */ - for ( ; busdevfn < end ; busdevfn++ ) { - memset ( pci, 0, sizeof ( *pci ) ); - pci_init ( pci, busdevfn ); - if ( ( rc = pci_read_config ( pci ) ) == 0 ) - return busdevfn; - } - - return -ENODEV; -} - -/** - * Find driver for PCI device - * - * @v pci PCI device - * @ret rc Return status code - */ -int pci_find_driver ( struct pci_device *pci ) { - struct pci_driver *driver; - struct pci_device_id *id; - unsigned int i; - - for_each_table_entry ( driver, PCI_DRIVERS ) { - if ( ( driver->class.class ^ pci->class ) & driver->class.mask ) - continue; - for ( i = 0 ; i < driver->id_count ; i++ ) { - id = &driver->ids[i]; - if ( ( id->vendor != PCI_ANY_ID ) && - ( id->vendor != pci->vendor ) ) - continue; - if ( ( id->device != PCI_ANY_ID ) && - ( id->device != pci->device ) ) - continue; - pci_set_driver ( pci, driver, id ); - return 0; - } - } - return -ENOENT; -} - -/** - * Probe a PCI device - * - * @v pci PCI device - * @ret rc Return status code - * - * Searches for a driver for the PCI device. If a driver is found, - * its probe() routine is called. - */ -int pci_probe ( struct pci_device *pci ) { - int rc; - - DBGC ( pci, PCI_FMT " (%04x:%04x) has driver \"%s\"\n", - PCI_ARGS ( pci ), pci->vendor, pci->device, pci->id->name ); - DBGC ( pci, PCI_FMT " has mem %lx io %lx irq %d\n", - PCI_ARGS ( pci ), pci->membase, pci->ioaddr, pci->irq ); - - if ( ( rc = pci->driver->probe ( pci ) ) != 0 ) { - DBGC ( pci, PCI_FMT " probe failed: %s\n", - PCI_ARGS ( pci ), strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Remove a PCI device - * - * @v pci PCI device - */ -void pci_remove ( struct pci_device *pci ) { - pci->driver->remove ( pci ); - DBGC ( pci, PCI_FMT " removed\n", PCI_ARGS ( pci ) ); -} - -/** - * Probe PCI root bus - * - * @v rootdev PCI bus root device - * - * Scans the PCI bus for devices and registers all devices it can - * find. - */ -static int pcibus_probe ( struct root_device *rootdev ) { - struct pci_device *pci = NULL; - int busdevfn = 0; - int rc; - - for ( busdevfn = 0 ; 1 ; busdevfn++ ) { - - /* Allocate struct pci_device */ - if ( ! pci ) - pci = malloc ( sizeof ( *pci ) ); - if ( ! pci ) { - rc = -ENOMEM; - goto err; - } - - /* Find next PCI device, if any */ - busdevfn = pci_find_next ( pci, busdevfn ); - if ( busdevfn < 0 ) - break; - - /* Look for a driver */ - if ( ( rc = pci_find_driver ( pci ) ) != 0 ) { - DBGC ( pci, PCI_FMT " (%04x:%04x class %06x) has no " - "driver\n", PCI_ARGS ( pci ), pci->vendor, - pci->device, pci->class ); - continue; - } - - /* Add to device hierarchy */ - pci->dev.parent = &rootdev->dev; - list_add ( &pci->dev.siblings, &rootdev->dev.children ); - - /* Look for a driver */ - if ( ( rc = pci_probe ( pci ) ) == 0 ) { - /* pcidev registered, we can drop our ref */ - pci = NULL; - } else { - /* Not registered; re-use struct pci_device */ - list_del ( &pci->dev.siblings ); - } - } - - free ( pci ); - return 0; - - err: - free ( pci ); - pcibus_remove ( rootdev ); - return rc; -} - -/** - * Remove PCI root bus - * - * @v rootdev PCI bus root device - */ -static void pcibus_remove ( struct root_device *rootdev ) { - struct pci_device *pci; - struct pci_device *tmp; - - list_for_each_entry_safe ( pci, tmp, &rootdev->dev.children, - dev.siblings ) { - pci_remove ( pci ); - list_del ( &pci->dev.siblings ); - free ( pci ); - } -} - -/** PCI bus root device driver */ -static struct root_driver pci_root_driver = { - .probe = pcibus_probe, - .remove = pcibus_remove, -}; - -/** PCI bus root device */ -struct root_device pci_root_device __root_device = { - .dev = { .name = "PCI" }, - .driver = &pci_root_driver, -}; diff --git a/qemu/roms/ipxe/src/drivers/bus/pci_settings.c b/qemu/roms/ipxe/src/drivers/bus/pci_settings.c deleted file mode 100644 index 1cb9fa5a3..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/pci_settings.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2013 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 <stdio.h> -#include <errno.h> -#include <ipxe/pci.h> -#include <ipxe/settings.h> -#include <ipxe/init.h> - -/** @file - * - * PCI device settings - * - */ - -/** PCI device settings scope */ -static const struct settings_scope pci_settings_scope; - -/** - * Check applicability of PCI device setting - * - * @v settings Settings block - * @v setting Setting - * @ret applies Setting applies within this settings block - */ -static int pci_settings_applies ( struct settings *settings __unused, - const struct setting *setting ) { - - return ( setting->scope == &pci_settings_scope ); -} - -/** - * Fetch value of PCI device setting - * - * @v settings Settings block - * @v setting Setting to fetch - * @v data Buffer to fill with setting data - * @v len Length of buffer - * @ret len Length of setting data, or negative error - */ -static int pci_settings_fetch ( struct settings *settings __unused, - struct setting *setting, - void *data, size_t len ) { - struct pci_device pci; - unsigned int tag_busdevfn; - unsigned int tag_offset; - unsigned int tag_len; - unsigned int i; - - /* Extract busdevfn, offset, and length from tag */ - tag_busdevfn = ( ( setting->tag >> 16 ) & 0xffff ); - tag_offset = ( ( setting->tag >> 8 ) & 0xff ); - tag_len = ( ( setting->tag >> 0 ) & 0xff ); - - /* Locate PCI device */ - memset ( &pci, 0, sizeof ( pci ) ); - pci_init ( &pci, tag_busdevfn ); - DBG ( PCI_FMT " reading %#02x+%#x\n", PCI_ARGS ( &pci ), - tag_offset, tag_len ); - - /* Read data one byte at a time, in reverse order (since PCI - * is little-endian and iPXE settings are essentially - * big-endian). - */ - tag_offset += tag_len; - for ( i = 0 ; ( ( i < tag_len ) && ( i < len ) ); i++ ) { - pci_read_config_byte ( &pci, --tag_offset, data++ ); - } - - /* Set type to ":hexraw" if not already specified */ - if ( ! setting->type ) - setting->type = &setting_type_hexraw; - - return tag_len; -} - -/** PCI device settings operations */ -static struct settings_operations pci_settings_operations = { - .applies = pci_settings_applies, - .fetch = pci_settings_fetch, -}; - -/** PCI device settings */ -static struct settings pci_settings = { - .refcnt = NULL, - .siblings = LIST_HEAD_INIT ( pci_settings.siblings ), - .children = LIST_HEAD_INIT ( pci_settings.children ), - .op = &pci_settings_operations, - .default_scope = &pci_settings_scope, -}; - -/** Initialise PCI device settings */ -static void pci_settings_init ( void ) { - int rc; - - if ( ( rc = register_settings ( &pci_settings, NULL, "pci" ) ) != 0 ) { - DBG ( "PCI could not register settings: %s\n", - strerror ( rc ) ); - return; - } -} - -/** PCI device settings initialiser */ -struct init_fn pci_settings_init_fn __init_fn ( INIT_NORMAL ) = { - .initialise = pci_settings_init, -}; diff --git a/qemu/roms/ipxe/src/drivers/bus/pcibackup.c b/qemu/roms/ipxe/src/drivers/bus/pcibackup.c deleted file mode 100644 index fecad8192..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/pcibackup.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2009 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 <ipxe/pcibackup.h> - -/** @file - * - * PCI configuration space backup and restoration - * - */ - -/** - * Check PCI configuration space offset against exclusion list - * - * @v pci PCI device - * @v offset Offset within PCI configuration space - * @v exclude PCI configuration space backup exclusion list, or NULL - */ -static int -pci_backup_excluded ( struct pci_device *pci, unsigned int offset, - const uint8_t *exclude ) { - - if ( ! exclude ) - return 0; - for ( ; *exclude != PCI_CONFIG_BACKUP_EXCLUDE_END ; exclude++ ) { - if ( offset == *exclude ) { - DBGC ( pci, "PCI %p skipping configuration offset " - "%02x\n", pci, offset ); - return 1; - } - } - return 0; -} - -/** - * Back up PCI configuration space - * - * @v pci PCI device - * @v backup PCI configuration space backup - * @v exclude PCI configuration space backup exclusion list, or NULL - */ -void pci_backup ( struct pci_device *pci, struct pci_config_backup *backup, - const uint8_t *exclude ) { - unsigned int offset; - uint32_t *dword; - - for ( offset = 0, dword = backup->dwords ; offset < 0x100 ; - offset += sizeof ( *dword ) , dword++ ) { - if ( ! pci_backup_excluded ( pci, offset, exclude ) ) - pci_read_config_dword ( pci, offset, dword ); - } -} - -/** - * Restore PCI configuration space - * - * @v pci PCI device - * @v backup PCI configuration space backup - * @v exclude PCI configuration space backup exclusion list, or NULL - */ -void pci_restore ( struct pci_device *pci, struct pci_config_backup *backup, - const uint8_t *exclude ) { - unsigned int offset; - uint32_t *dword; - - for ( offset = 0, dword = backup->dwords ; offset < 0x100 ; - offset += sizeof ( *dword ) , dword++ ) { - if ( ! pci_backup_excluded ( pci, offset, exclude ) ) - pci_write_config_dword ( pci, offset, *dword ); - } -} diff --git a/qemu/roms/ipxe/src/drivers/bus/pciextra.c b/qemu/roms/ipxe/src/drivers/bus/pciextra.c deleted file mode 100644 index 82287fb86..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/pciextra.c +++ /dev/null @@ -1,86 +0,0 @@ -FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); - -#include <stdint.h> -#include <ipxe/pci.h> - -/** - * Look for a PCI capability - * - * @v pci PCI device to query - * @v cap Capability code - * @ret address Address of capability, or 0 if not found - * - * Determine whether or not a device supports a given PCI capability. - * Returns the address of the requested capability structure within - * the device's PCI configuration space, or 0 if the device does not - * support it. - */ -int pci_find_capability ( struct pci_device *pci, int cap ) { - uint16_t status; - uint8_t pos, id; - uint8_t hdr_type; - int ttl = 48; - - pci_read_config_word ( pci, PCI_STATUS, &status ); - if ( ! ( status & PCI_STATUS_CAP_LIST ) ) - return 0; - - pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdr_type ); - switch ( hdr_type & PCI_HEADER_TYPE_MASK ) { - case PCI_HEADER_TYPE_NORMAL: - case PCI_HEADER_TYPE_BRIDGE: - default: - pci_read_config_byte ( pci, PCI_CAPABILITY_LIST, &pos ); - break; - case PCI_HEADER_TYPE_CARDBUS: - pci_read_config_byte ( pci, PCI_CB_CAPABILITY_LIST, &pos ); - break; - } - while ( ttl-- && pos >= 0x40 ) { - pos &= ~3; - pci_read_config_byte ( pci, pos + PCI_CAP_ID, &id ); - DBG ( "PCI Capability: %d\n", id ); - if ( id == 0xff ) - break; - if ( id == cap ) - return pos; - pci_read_config_byte ( pci, pos + PCI_CAP_NEXT, &pos ); - } - return 0; -} - -/** - * Find the size of a PCI BAR - * - * @v pci PCI device - * @v reg PCI register number - * @ret size BAR size - * - * It should not be necessary for any Etherboot code to call this - * function. - */ -unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) { - uint16_t cmd; - uint32_t start, size; - - /* Save the original command register */ - pci_read_config_word ( pci, PCI_COMMAND, &cmd ); - /* Save the original bar */ - pci_read_config_dword ( pci, reg, &start ); - /* Compute which bits can be set */ - pci_write_config_dword ( pci, reg, ~0 ); - pci_read_config_dword ( pci, reg, &size ); - /* Restore the original size */ - pci_write_config_dword ( pci, reg, start ); - /* Find the significant bits */ - /* Restore the original command register. This reenables decoding. */ - pci_write_config_word ( pci, PCI_COMMAND, cmd ); - if ( start & PCI_BASE_ADDRESS_SPACE_IO ) { - size &= ~PCI_BASE_ADDRESS_IO_MASK; - } else { - size &= ~PCI_BASE_ADDRESS_MEM_MASK; - } - /* Find the lowest bit set */ - size = size & ~( size - 1 ); - return size; -} diff --git a/qemu/roms/ipxe/src/drivers/bus/pcivpd.c b/qemu/roms/ipxe/src/drivers/bus/pcivpd.c deleted file mode 100644 index 243b1f779..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/pcivpd.c +++ /dev/null @@ -1,560 +0,0 @@ -/* - * Copyright (C) 2010 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 <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <byteswap.h> -#include <ipxe/pci.h> -#include <ipxe/isapnp.h> -#include <ipxe/pcivpd.h> - -/** @file - * - * PCI Vital Product Data - * - */ - -/** - * Initialise PCI Vital Product Data - * - * @v vpd PCI VPD - * @v pci PCI device - * @ret rc Return status code - */ -int pci_vpd_init ( struct pci_vpd *vpd, struct pci_device *pci ) { - - /* Initialise structure */ - vpd->pci = pci; - pci_vpd_invalidate_cache ( vpd ); - - /* Locate VPD capability */ - vpd->cap = pci_find_capability ( pci, PCI_CAP_ID_VPD ); - if ( ! vpd->cap ) { - DBGC ( vpd, PCI_FMT " does not support VPD\n", - PCI_ARGS ( pci ) ); - return -ENOTTY; - } - - DBGC ( vpd, PCI_FMT " VPD is at offset %02x\n", - PCI_ARGS ( pci ), vpd->cap ); - return 0; -} - -/** - * Read one dword of PCI Vital Product Data - * - * @v vpd PCI VPD - * @v address Address to read - * @ret data Read data - * @ret rc Return status code - */ -static int pci_vpd_read_dword ( struct pci_vpd *vpd, int address, - uint32_t *data ) { - struct pci_device *pci = vpd->pci; - unsigned int cap = vpd->cap; - unsigned int retries; - uint16_t flag; - - /* Fail if no VPD present */ - if ( ! cap ) - return -ENOTTY; - - /* Return cached value, if present */ - if ( pci_vpd_cache_is_valid ( vpd ) && - ( vpd->cache.address == address ) ) { - *data = vpd->cache.data; - return 0; - } - - /* Initiate read */ - pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), address ); - - /* Wait for read to complete */ - for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) { - - /* Check if data is ready */ - pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag ); - if ( flag & PCI_VPD_FLAG ) { - - /* Read data */ - pci_read_config_dword ( pci, ( cap + PCI_VPD_DATA ), - data ); - DBGC2 ( vpd, PCI_FMT " VPD %04x => %08x\n", - PCI_ARGS ( pci ), address, htonl ( *data ) ); - - /* Populate cache */ - vpd->cache.address = address; - vpd->cache.data = *data; - - return 0; - } - - /* Wait 1ms before retrying */ - mdelay ( 1 ); - } - - DBGC ( vpd, PCI_FMT " VPD %04x read via %02x timed out\n", - PCI_ARGS ( pci ), address, cap ); - return -ETIMEDOUT; -} - -/** - * Write one dword of PCI Vital Product Data - * - * @v vpd PCI VPD - * @v address Address to write - * @v data Data to write - * @ret rc Return status code - */ -static int pci_vpd_write_dword ( struct pci_vpd *vpd, int address, - uint32_t data ) { - struct pci_device *pci = vpd->pci; - unsigned int cap = vpd->cap; - unsigned int retries; - uint16_t flag; - - /* Fail if no VPD present */ - if ( ! cap ) - return -ENOTTY; - - /* Invalidate cache */ - pci_vpd_invalidate_cache ( vpd ); - - DBGC2 ( vpd, PCI_FMT " VPD %04x <= %08x\n", - PCI_ARGS ( pci ), address, htonl ( data ) ); - - /* Write data */ - pci_write_config_dword ( pci, ( cap + PCI_VPD_DATA ), data ); - - /* Initiate write */ - pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), - ( address | PCI_VPD_FLAG ) ); - - /* Wait for write to complete */ - for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) { - - /* Check if write has completed */ - pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag ); - if ( ! ( flag & PCI_VPD_FLAG ) ) - return 0; - - /* Wait 1ms before retrying */ - mdelay ( 1 ); - } - - DBGC ( vpd, PCI_FMT " VPD %04x write via %02x timed out\n", - PCI_ARGS ( pci ), address, cap ); - return -ETIMEDOUT; -} - -/** - * Read PCI VPD - * - * @v vpd PCI VPD - * @v address Starting address - * @v buf Data buffer - * @v len Length of data buffer - * @ret rc Return status code - */ -int pci_vpd_read ( struct pci_vpd *vpd, unsigned int address, void *buf, - size_t len ) { - uint8_t *bytes = buf; - uint32_t data; - size_t skip_len; - unsigned int i; - int rc; - - /* Calculate length to skip at start of data */ - skip_len = ( address & 0x03 ); - - /* Read data, a dword at a time */ - for ( address &= ~0x03 ; len ; address += 4 ) { - - /* Read whole dword */ - if ( ( rc = pci_vpd_read_dword ( vpd, address, &data ) ) != 0 ) - return rc; - - /* Copy data to buffer */ - for ( i = 4 ; i ; i-- ) { - if ( skip_len ) { - skip_len--; - } else if ( len ) { - *(bytes++) = data; - len--; - } - data = ( ( data << 24 ) | ( data >> 8 ) ); - } - } - - return 0; -} - -/** - * Write PCI VPD - * - * @v vpd PCI VPD - * @v address Starting address - * @v buf Data buffer - * @v len Length of data buffer - * @ret rc Return status code - */ -int pci_vpd_write ( struct pci_vpd *vpd, unsigned int address, const void *buf, - size_t len ) { - const uint8_t *bytes = buf; - uint32_t data; - size_t skip_len; - unsigned int i; - int rc; - - /* Calculate length to skip at start of data */ - skip_len = ( address & 0x03 ); - - /* Write data, a dword at a time */ - for ( address &= ~0x03 ; len ; address += 4 ) { - - /* Read existing dword, if necessary */ - if ( skip_len || ( len <= 0x03 ) ) { - if ( ( rc = pci_vpd_read_dword ( vpd, address, - &data ) ) != 0 ) - return rc; - } - - /* Copy data from buffer */ - for ( i = 4 ; i ; i-- ) { - if ( skip_len ) { - skip_len--; - } else if ( len ) { - data = ( ( data & ~0xff ) | *(bytes++) ); - len--; - } - data = ( ( data << 24 ) | ( data >> 8 ) ); - } - - /* Write whole dword */ - if ( ( rc = pci_vpd_write_dword ( vpd, address, data ) ) != 0 ) - return rc; - } - return 0; -} - -/** - * Dump PCI VPD region (for debugging) - * - * @v vpd PCI VPD - * @v address Starting address - * @v len Length of data - */ -static void pci_vpd_dump ( struct pci_vpd *vpd, unsigned int address, - size_t len ) { - int rc; - - /* Do nothing in non-debug builds */ - if ( ! DBG_LOG ) - return; - - /* Read data */ - { - char buf[len]; - if ( ( rc = pci_vpd_read ( vpd, address, buf, - sizeof ( buf ) ) ) != 0 ) - return; - DBGC_HDA ( vpd, address, buf, sizeof ( buf ) ); - } -} - -/** - * Locate PCI VPD tag - * - * @v vpd PCI VPD - * @v tag ISAPnP tag - * @ret address Address of tag body - * @ret len Length of tag body - * @ret rc Return status code - */ -static int pci_vpd_find_tag ( struct pci_vpd *vpd, unsigned int tag, - unsigned int *address, size_t *len ) { - uint8_t read_tag; - uint16_t read_len; - int rc; - - /* Scan through tags looking for a match */ - *address = 0; - do { - /* Read tag byte */ - if ( ( rc = pci_vpd_read ( vpd, (*address)++, &read_tag, - sizeof ( read_tag ) ) ) != 0 ) - return rc; - - /* Extract tag and length */ - if ( ISAPNP_IS_LARGE_TAG ( read_tag ) ) { - if ( ( rc = pci_vpd_read ( vpd, *address, &read_len, - sizeof ( read_len ) ) ) != 0) - return rc; - *address += sizeof ( read_len ); - read_len = le16_to_cpu ( read_len ); - read_tag = ISAPNP_LARGE_TAG_NAME ( read_tag ); - } else { - read_len = ISAPNP_SMALL_TAG_LEN ( read_tag ); - read_tag = ISAPNP_SMALL_TAG_NAME ( read_tag ); - } - - /* Check for tag match */ - if ( tag == read_tag ) { - *len = read_len; - DBGC ( vpd, PCI_FMT " VPD tag %02x is at " - "[%04x,%04zx)\n", PCI_ARGS ( vpd->pci ), tag, - *address, ( *address + *len ) ); - return 0; - } - - /* Move to next tag */ - *address += read_len; - - } while ( read_tag != ISAPNP_TAG_END ); - - DBGC ( vpd, PCI_FMT " VPD tag %02x not found\n", - PCI_ARGS ( vpd->pci ), tag ); - return -ENOENT; -} - -/** - * Locate PCI VPD field - * - * @v vpd PCI VPD - * @v field VPD field descriptor - * @ret address Address of field body - * @ret len Length of field body - * @ret rc Return status code - */ -int pci_vpd_find ( struct pci_vpd *vpd, unsigned int field, - unsigned int *address, size_t *len ) { - struct pci_vpd_field read_field; - int rc; - - /* Locate containing tag */ - if ( ( rc = pci_vpd_find_tag ( vpd, PCI_VPD_TAG ( field ), - address, len ) ) != 0 ) - return rc; - - /* Return immediately if we are searching for a whole-tag field */ - if ( ! PCI_VPD_KEYWORD ( field ) ) { - pci_vpd_dump ( vpd, *address, *len ); - return 0; - } - - /* Scan through fields looking for a match */ - while ( *len >= sizeof ( read_field ) ) { - - /* Read field header */ - if ( ( rc = pci_vpd_read ( vpd, *address, &read_field, - sizeof ( read_field ) ) ) != 0 ) - return rc; - *address += sizeof ( read_field ); - *len -= sizeof ( read_field ); - - /* Check for keyword match */ - if ( read_field.keyword == PCI_VPD_KEYWORD ( field ) ) { - *len = read_field.len; - DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT - " is at [%04x,%04zx)\n", PCI_ARGS ( vpd->pci ), - PCI_VPD_FIELD_ARGS ( field ), - *address, ( *address + *len ) ); - pci_vpd_dump ( vpd, *address, *len ); - return 0; - } - - /* Move to next field */ - if ( read_field.len > *len ) - break; - *address += read_field.len; - *len -= read_field.len; - } - - DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " not found\n", - PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ) ); - return -ENOENT; -} - -/** - * Resize VPD field - * - * @v vpd PCI VPD - * @v field VPD field descriptor - * @v len New length of field body - * @ret address Address of field body - * @ret rc Return status code - */ -int pci_vpd_resize ( struct pci_vpd *vpd, unsigned int field, size_t len, - unsigned int *address ) { - struct pci_vpd_field rw_field; - struct pci_vpd_field old_field; - struct pci_vpd_field new_field; - unsigned int rw_address; - unsigned int old_address; - unsigned int copy_address; - unsigned int dst_address; - unsigned int dump_address; - size_t rw_len; - size_t old_len; - size_t available_len; - size_t copy_len; - size_t dump_len; - void *copy; - int rc; - - /* Sanity checks */ - assert ( PCI_VPD_TAG ( field ) == PCI_VPD_TAG_RW ); - assert ( PCI_VPD_KEYWORD ( field ) != 0 ); - assert ( field != PCI_VPD_FIELD_RW ); - - /* Locate 'RW' field */ - if ( ( rc = pci_vpd_find ( vpd, PCI_VPD_FIELD_RW, &rw_address, - &rw_len ) ) != 0 ) - goto err_no_rw; - - /* Locate old field, if any */ - if ( ( rc = pci_vpd_find ( vpd, field, &old_address, - &old_len ) ) == 0 ) { - - /* Field already exists */ - if ( old_address > rw_address ) { - DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT - " at [%04x,%04zx) is after field " - PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n", - PCI_ARGS ( vpd->pci ), - PCI_VPD_FIELD_ARGS ( field ), - old_address, ( old_address + old_len ), - PCI_VPD_FIELD_ARGS ( PCI_VPD_FIELD_RW ), - rw_address, ( rw_address + rw_len ) ); - rc = -ENXIO; - goto err_after_rw; - } - dst_address = ( old_address - sizeof ( old_field ) ); - copy_address = ( old_address + old_len ); - copy_len = ( rw_address - sizeof ( rw_field ) - copy_address ); - - /* Calculate available length */ - available_len = ( rw_len + old_len ); - - } else { - - /* Field does not yet exist */ - dst_address = ( rw_address - sizeof ( rw_field ) ); - copy_address = dst_address; - copy_len = 0; - - /* Calculate available length */ - available_len = ( ( rw_len > sizeof ( new_field ) ) ? - ( rw_len - sizeof ( new_field ) ) : 0 ); - } - - /* Dump region before changes */ - dump_address = dst_address; - dump_len = ( rw_address + rw_len - dump_address ); - DBGC ( vpd, PCI_FMT " VPD before resizing field " PCI_VPD_FIELD_FMT - " to %zd bytes:\n", PCI_ARGS ( vpd->pci ), - PCI_VPD_FIELD_ARGS ( field ), len ); - pci_vpd_dump ( vpd, dump_address, dump_len ); - - /* Check available length */ - if ( available_len > PCI_VPD_MAX_LEN ) - available_len = PCI_VPD_MAX_LEN; - if ( len > available_len ) { - DBGC ( vpd, PCI_FMT " VPD no space for field " - PCI_VPD_FIELD_FMT " (need %02zx, have %02zx)\n", - PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ), - len, available_len ); - rc = -ENOSPC; - goto err_no_space; - } - - /* Preserve intermediate fields, if any */ - copy = malloc ( copy_len ); - if ( ! copy ) { - rc = -ENOMEM; - goto err_copy_alloc; - } - if ( ( rc = pci_vpd_read ( vpd, copy_address, copy, copy_len ) ) != 0 ) - goto err_copy_read; - - /* Create new field, if applicable */ - if ( len ) { - new_field.keyword = PCI_VPD_KEYWORD ( field ); - new_field.len = len; - if ( ( rc = pci_vpd_write ( vpd, dst_address, &new_field, - sizeof ( new_field ) ) ) != 0 ) - goto err_new_write; - dst_address += sizeof ( new_field ); - *address = dst_address; - DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now " - "at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ), - PCI_VPD_FIELD_ARGS ( field ), dst_address, - ( dst_address + new_field.len ) ); - dst_address += len; - } else { - DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT - " no longer exists\n", PCI_ARGS ( vpd->pci ), - PCI_VPD_FIELD_ARGS ( field ) ); - } - - /* Restore intermediate fields, if any */ - if ( ( rc = pci_vpd_write ( vpd, dst_address, copy, copy_len ) ) != 0 ) - goto err_copy_write; - dst_address += copy_len; - - /* Create 'RW' field */ - rw_field.keyword = PCI_VPD_KEYWORD ( PCI_VPD_FIELD_RW ); - rw_field.len = ( rw_len + - ( rw_address - sizeof ( rw_field ) ) - dst_address ); - if ( ( rc = pci_vpd_write ( vpd, dst_address, &rw_field, - sizeof ( rw_field ) ) ) != 0 ) - goto err_rw_write; - dst_address += sizeof ( rw_field ); - DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now " - "at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ), - PCI_VPD_FIELD_ARGS ( PCI_VPD_FIELD_RW ), dst_address, - ( dst_address + rw_field.len ) ); - - /* Dump region after changes */ - DBGC ( vpd, PCI_FMT " VPD after resizing field " PCI_VPD_FIELD_FMT - " to %zd bytes:\n", PCI_ARGS ( vpd->pci ), - PCI_VPD_FIELD_ARGS ( field ), len ); - pci_vpd_dump ( vpd, dump_address, dump_len ); - - rc = 0; - - err_rw_write: - err_new_write: - err_copy_write: - err_copy_read: - free ( copy ); - err_copy_alloc: - err_no_space: - err_after_rw: - err_no_rw: - return rc; -} diff --git a/qemu/roms/ipxe/src/drivers/bus/usb.c b/qemu/roms/ipxe/src/drivers/bus/usb.c deleted file mode 100644 index 2019e3341..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/usb.c +++ /dev/null @@ -1,2128 +0,0 @@ -/* - * Copyright (C) 2014 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 <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <strings.h> -#include <unistd.h> -#include <errno.h> -#include <assert.h> -#include <byteswap.h> -#include <ipxe/usb.h> -#include <ipxe/cdc.h> - -/** @file - * - * Universal Serial Bus (USB) - * - */ - -/** List of USB buses */ -struct list_head usb_buses = LIST_HEAD_INIT ( usb_buses ); - -/** List of changed ports */ -static struct list_head usb_changed = LIST_HEAD_INIT ( usb_changed ); - -/** List of halted endpoints */ -static struct list_head usb_halted = LIST_HEAD_INIT ( usb_halted ); - -/****************************************************************************** - * - * Utility functions - * - ****************************************************************************** - */ - -/** - * Get USB speed name (for debugging) - * - * @v speed Speed - * @ret name Speed name - */ -static inline const char * usb_speed_name ( unsigned int speed ) { - static const char *exponents[4] = { "", "k", "M", "G" }; - static char buf[ 10 /* "xxxxxXbps" + NUL */ ]; - unsigned int mantissa; - unsigned int exponent; - - /* Extract mantissa and exponent */ - mantissa = USB_SPEED_MANTISSA ( speed ); - exponent = USB_SPEED_EXPONENT ( speed ); - - /* Name speed */ - switch ( speed ) { - case USB_SPEED_NONE: return "DETACHED"; - case USB_SPEED_LOW: return "low"; - case USB_SPEED_FULL: return "full"; - case USB_SPEED_HIGH: return "high"; - case USB_SPEED_SUPER: return "super"; - default: - snprintf ( buf, sizeof ( buf ), "%d%sbps", - mantissa, exponents[exponent] ); - return buf; - } -} - -/** - * Transcribe USB BCD-coded value (for debugging) - * - * @v bcd BCD-coded value - * @ret string Transcribed value - */ -static inline const char * usb_bcd ( uint16_t bcd ) { - static char buf[ 6 /* "xx.xx" + NUL */ ]; - uint8_t high = ( bcd >> 8 ); - uint8_t low = ( bcd >> 0 ); - - snprintf ( buf, sizeof ( buf ), "%x.%02x", high, low ); - return buf; -} - -/****************************************************************************** - * - * USB descriptors - * - ****************************************************************************** - */ - -/** - * Locate USB interface association descriptor - * - * @v config Configuraton descriptor - * @v first First interface number - * @ret desc Interface association descriptor, or NULL if not found - */ -static struct usb_interface_association_descriptor * -usb_interface_association_descriptor ( struct usb_configuration_descriptor - *config, - unsigned int first ) { - struct usb_interface_association_descriptor *desc; - - /* Find a matching interface association descriptor */ - for_each_config_descriptor ( desc, config ) { - if ( ( desc->header.type == - USB_INTERFACE_ASSOCIATION_DESCRIPTOR ) && - ( desc->first == first ) ) - return desc; - } - return NULL; -} - -/** - * Locate USB interface descriptor - * - * @v config Configuraton descriptor - * @v interface Interface number - * @v alternate Alternate setting - * @ret desc Interface descriptor, or NULL if not found - */ -struct usb_interface_descriptor * -usb_interface_descriptor ( struct usb_configuration_descriptor *config, - unsigned int interface, unsigned int alternate ) { - struct usb_interface_descriptor *desc; - - /* Find a matching interface descriptor */ - for_each_config_descriptor ( desc, config ) { - if ( ( desc->header.type == USB_INTERFACE_DESCRIPTOR ) && - ( desc->interface == interface ) && - ( desc->alternate == alternate ) ) - return desc; - } - return NULL; -} - -/** - * Locate USB endpoint descriptor - * - * @v config Configuration descriptor - * @v interface Interface descriptor - * @v type Endpoint (internal) type - * @v index Endpoint index - * @ret desc Descriptor, or NULL if not found - */ -struct usb_endpoint_descriptor * -usb_endpoint_descriptor ( struct usb_configuration_descriptor *config, - struct usb_interface_descriptor *interface, - unsigned int type, unsigned int index ) { - struct usb_endpoint_descriptor *desc; - unsigned int attributes = ( type & USB_ENDPOINT_ATTR_TYPE_MASK ); - unsigned int direction = ( type & USB_DIR_IN ); - - /* Find a matching endpoint descriptor */ - for_each_interface_descriptor ( desc, config, interface ) { - if ( ( desc->header.type == USB_ENDPOINT_DESCRIPTOR ) && - ( ( desc->attributes & - USB_ENDPOINT_ATTR_TYPE_MASK ) == attributes ) && - ( ( desc->endpoint & USB_DIR_IN ) == direction ) && - ( index-- == 0 ) ) - return desc; - } - return NULL; -} - -/** - * Locate USB endpoint companion descriptor - * - * @v config Configuration descriptor - * @v desc Endpoint descriptor - * @ret descx Companion descriptor, or NULL if not found - */ -struct usb_endpoint_companion_descriptor * -usb_endpoint_companion_descriptor ( struct usb_configuration_descriptor *config, - struct usb_endpoint_descriptor *desc ) { - struct usb_endpoint_companion_descriptor *descx; - - /* Get companion descriptor, if present */ - descx = container_of ( usb_next_descriptor ( &desc->header ), - struct usb_endpoint_companion_descriptor, - header ); - return ( ( usb_is_within_config ( config, &descx->header ) && - descx->header.type == USB_ENDPOINT_COMPANION_DESCRIPTOR ) - ? descx : NULL ); -} - -/****************************************************************************** - * - * USB endpoint - * - ****************************************************************************** - */ - -/** - * Get USB endpoint name (for debugging) - * - * @v ep USB endpoint - * @ret name Endpoint name - */ -const char * usb_endpoint_name ( struct usb_endpoint *ep ) { - static char buf[ 9 /* "EPxx OUT" + NUL */ ]; - unsigned int address = ep->address; - - snprintf ( buf, sizeof ( buf ), "EP%d%s", - ( address & USB_ENDPOINT_MAX ), - ( address ? - ( ( address & USB_ENDPOINT_IN ) ? " IN" : " OUT" ) : "" )); - return buf; -} - -/** - * Describe USB endpoint from device configuration - * - * @v ep USB endpoint - * @v config Configuration descriptor - * @v interface Interface descriptor - * @v type Endpoint (internal) type - * @v index Endpoint index - * @ret rc Return status code - */ -int usb_endpoint_described ( struct usb_endpoint *ep, - struct usb_configuration_descriptor *config, - struct usb_interface_descriptor *interface, - unsigned int type, unsigned int index ) { - struct usb_device *usb = ep->usb; - struct usb_port *port = usb->port; - struct usb_endpoint_descriptor *desc; - struct usb_endpoint_companion_descriptor *descx; - unsigned int sizes; - unsigned int burst; - unsigned int interval; - size_t mtu; - - /* Locate endpoint descriptor */ - desc = usb_endpoint_descriptor ( config, interface, type, index ); - if ( ! desc ) - return -ENOENT; - - /* Locate companion descriptor, if any */ - descx = usb_endpoint_companion_descriptor ( config, desc ); - - /* Calculate MTU and burst size */ - sizes = le16_to_cpu ( desc->sizes ); - mtu = USB_ENDPOINT_MTU ( sizes ); - burst = ( descx ? descx->burst : USB_ENDPOINT_BURST ( sizes ) ); - - /* Calculate interval */ - if ( ( type & USB_ENDPOINT_ATTR_TYPE_MASK ) == - USB_ENDPOINT_ATTR_INTERRUPT ) { - if ( port->speed >= USB_SPEED_HIGH ) { - /* 2^(desc->interval-1) is a microframe count */ - interval = ( 1 << ( desc->interval - 1 ) ); - } else { - /* desc->interval is a (whole) frame count */ - interval = ( desc->interval << 3 ); - } - } else { - /* desc->interval is a microframe count */ - interval = desc->interval; - } - - /* Describe endpoint */ - usb_endpoint_describe ( ep, desc->endpoint, desc->attributes, - mtu, burst, interval ); - return 0; -} - -/** - * Open USB endpoint - * - * @v ep USB endpoint - * @ret rc Return status code - */ -int usb_endpoint_open ( struct usb_endpoint *ep ) { - struct usb_device *usb = ep->usb; - unsigned int idx = USB_ENDPOINT_IDX ( ep->address ); - int rc; - - /* Populate host controller operations */ - ep->host = &usb->port->hub->bus->op->endpoint; - - /* Add to endpoint list */ - if ( usb->ep[idx] != NULL ) { - DBGC ( usb, "USB %s %s is already open\n", - usb->name, usb_endpoint_name ( ep ) ); - rc = -EALREADY; - goto err_already; - } - usb->ep[idx] = ep; - INIT_LIST_HEAD ( &ep->halted ); - - /* Open endpoint */ - if ( ( rc = ep->host->open ( ep ) ) != 0 ) { - DBGC ( usb, "USB %s %s could not open: %s\n", usb->name, - usb_endpoint_name ( ep ), strerror ( rc ) ); - goto err_open; - } - ep->open = 1; - - DBGC2 ( usb, "USB %s %s opened with MTU %zd, burst %d, interval %d\n", - usb->name, usb_endpoint_name ( ep ), ep->mtu, ep->burst, - ep->interval ); - return 0; - - ep->open = 0; - ep->host->close ( ep ); - err_open: - usb->ep[idx] = NULL; - err_already: - if ( ep->max ) - usb_flush ( ep ); - return rc; -} - -/** - * Clear transaction translator (if applicable) - * - * @v ep USB endpoint - * @ret rc Return status code - */ -static int usb_endpoint_clear_tt ( struct usb_endpoint *ep ) { - struct usb_device *usb = ep->usb; - struct usb_port *tt; - int rc; - - /* Do nothing if this is a periodic endpoint */ - if ( ep->attributes & USB_ENDPOINT_ATTR_PERIODIC ) - return 0; - - /* Do nothing if this endpoint is not behind a transaction translator */ - tt = usb_transaction_translator ( usb ); - if ( ! tt ) - return 0; - - /* Clear transaction translator buffer */ - if ( ( rc = tt->hub->driver->clear_tt ( tt->hub, tt, ep ) ) != 0 ) { - DBGC ( usb, "USB %s %s could not clear transaction translator: " - "%s\n", usb->name, usb_endpoint_name ( ep ), - strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Close USB endpoint - * - * @v ep USB endpoint - */ -void usb_endpoint_close ( struct usb_endpoint *ep ) { - struct usb_device *usb = ep->usb; - unsigned int idx = USB_ENDPOINT_IDX ( ep->address ); - - /* Sanity checks */ - assert ( usb->ep[idx] == ep ); - - /* Close endpoint */ - ep->open = 0; - ep->host->close ( ep ); - assert ( ep->fill == 0 ); - - /* Remove from endpoint list */ - usb->ep[idx] = NULL; - list_del ( &ep->halted ); - - /* Discard any recycled buffers, if applicable */ - if ( ep->max ) - usb_flush ( ep ); - - /* Clear transaction translator, if applicable */ - usb_endpoint_clear_tt ( ep ); -} - -/** - * Reset USB endpoint - * - * @v ep USB endpoint - * @ret rc Return status code - */ -static int usb_endpoint_reset ( struct usb_endpoint *ep ) { - struct usb_device *usb = ep->usb; - unsigned int type; - int rc; - - /* Sanity check */ - assert ( ! list_empty ( &ep->halted ) ); - - /* Reset endpoint */ - if ( ( rc = ep->host->reset ( ep ) ) != 0 ) { - DBGC ( usb, "USB %s %s could not reset: %s\n", - usb->name, usb_endpoint_name ( ep ), strerror ( rc ) ); - return rc; - } - - /* Clear transaction translator, if applicable */ - if ( ( rc = usb_endpoint_clear_tt ( ep ) ) != 0 ) - return rc; - - /* Clear endpoint halt, if applicable */ - type = ( ep->attributes & USB_ENDPOINT_ATTR_TYPE_MASK ); - if ( ( type != USB_ENDPOINT_ATTR_CONTROL ) && - ( ( rc = usb_clear_feature ( usb, USB_RECIP_ENDPOINT, - USB_ENDPOINT_HALT, - ep->address ) ) != 0 ) ) { - DBGC ( usb, "USB %s %s could not clear endpoint halt: %s\n", - usb->name, usb_endpoint_name ( ep ), strerror ( rc ) ); - return rc; - } - - /* Remove from list of halted endpoints */ - list_del ( &ep->halted ); - INIT_LIST_HEAD ( &ep->halted ); - - DBGC ( usb, "USB %s %s reset\n", - usb->name, usb_endpoint_name ( ep ) ); - return 0; -} - -/** - * Update endpoint MTU - * - * @v ep USB endpoint - * @v mtu New MTU - * @ret rc Return status code - */ -static int usb_endpoint_mtu ( struct usb_endpoint *ep, size_t mtu ) { - struct usb_device *usb = ep->usb; - int rc; - - /* Update MTU */ - ep->mtu = mtu; - if ( ( rc = ep->host->mtu ( ep ) ) != 0 ) { - DBGC ( usb, "USB %s %s could not update MTU: %s\n", - usb->name, usb_endpoint_name ( ep ), strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Enqueue USB message transfer - * - * @v ep USB endpoint - * @v request Request - * @v value Value parameter - * @v index Index parameter - * @v iobuf I/O buffer - * @ret rc Return status code - * - * The I/O buffer must have sufficient headroom to contain a setup - * packet. - */ -int usb_message ( struct usb_endpoint *ep, unsigned int request, - unsigned int value, unsigned int index, - struct io_buffer *iobuf ) { - struct usb_device *usb = ep->usb; - struct usb_port *port = usb->port; - struct usb_setup_packet *packet; - size_t len = iob_len ( iobuf ); - int rc; - - /* Sanity check */ - assert ( iob_headroom ( iobuf ) >= sizeof ( *packet ) ); - - /* Fail immediately if device has been unplugged */ - if ( port->speed == USB_SPEED_NONE ) - return -ENODEV; - - /* Reset endpoint if required */ - if ( ( ! list_empty ( &ep->halted ) ) && - ( ( rc = usb_endpoint_reset ( ep ) ) != 0 ) ) - return rc; - - /* Zero input data buffer (if applicable) */ - if ( request & USB_DIR_IN ) - memset ( iobuf->data, 0, len ); - - /* Construct setup packet */ - packet = iob_push ( iobuf, sizeof ( *packet ) ); - packet->request = cpu_to_le16 ( request ); - packet->value = cpu_to_le16 ( value ); - packet->index = cpu_to_le16 ( index ); - packet->len = cpu_to_le16 ( len ); - - /* Enqueue message transfer */ - if ( ( rc = ep->host->message ( ep, iobuf ) ) != 0 ) { - DBGC ( usb, "USB %s %s could not enqueue message transfer: " - "%s\n", usb->name, usb_endpoint_name ( ep ), - strerror ( rc ) ); - return rc; - } - - /* Increment fill level */ - ep->fill++; - - return 0; -} - -/** - * Enqueue USB stream transfer - * - * @v ep USB endpoint - * @v iobuf I/O buffer - * @v terminate Terminate using a short packet - * @ret rc Return status code - */ -int usb_stream ( struct usb_endpoint *ep, struct io_buffer *iobuf, - int terminate ) { - struct usb_device *usb = ep->usb; - struct usb_port *port = usb->port; - int rc; - - /* Fail immediately if device has been unplugged */ - if ( port->speed == USB_SPEED_NONE ) - return -ENODEV; - - /* Reset endpoint if required */ - if ( ( ! list_empty ( &ep->halted ) ) && - ( ( rc = usb_endpoint_reset ( ep ) ) != 0 ) ) - return rc; - - /* Enqueue stream transfer */ - if ( ( rc = ep->host->stream ( ep, iobuf, terminate ) ) != 0 ) { - DBGC ( usb, "USB %s %s could not enqueue stream transfer: %s\n", - usb->name, usb_endpoint_name ( ep ), strerror ( rc ) ); - return rc; - } - - /* Increment fill level */ - ep->fill++; - - return 0; -} - -/** - * Complete transfer (possibly with error) - * - * @v ep USB endpoint - * @v iobuf I/O buffer - * @v rc Completion status code - */ -void usb_complete_err ( struct usb_endpoint *ep, struct io_buffer *iobuf, - int rc ) { - struct usb_device *usb = ep->usb; - - /* Decrement fill level */ - assert ( ep->fill > 0 ); - ep->fill--; - - /* Schedule reset, if applicable */ - if ( ( rc != 0 ) && ep->open ) { - DBGC ( usb, "USB %s %s completion failed: %s\n", - usb->name, usb_endpoint_name ( ep ), strerror ( rc ) ); - list_del ( &ep->halted ); - list_add_tail ( &ep->halted, &usb_halted ); - } - - /* Report completion */ - ep->driver->complete ( ep, iobuf, rc ); -} - -/****************************************************************************** - * - * Endpoint refilling - * - ****************************************************************************** - */ - -/** - * Prefill endpoint recycled buffer list - * - * @v ep USB endpoint - * @ret rc Return status code - */ -int usb_prefill ( struct usb_endpoint *ep ) { - struct io_buffer *iobuf; - size_t len = ( ep->len ? ep->len : ep->mtu ); - unsigned int fill; - int rc; - - /* Sanity checks */ - assert ( ep->fill == 0 ); - assert ( ep->max > 0 ); - assert ( list_empty ( &ep->recycled ) ); - - /* Fill recycled buffer list */ - for ( fill = 0 ; fill < ep->max ; fill++ ) { - - /* Allocate I/O buffer */ - iobuf = alloc_iob ( len ); - if ( ! iobuf ) { - rc = -ENOMEM; - goto err_alloc; - } - - /* Add to recycled buffer list */ - list_add_tail ( &iobuf->list, &ep->recycled ); - } - - return 0; - - err_alloc: - usb_flush ( ep ); - return rc; -} - -/** - * Refill endpoint - * - * @v ep USB endpoint - * @ret rc Return status code - */ -int usb_refill ( struct usb_endpoint *ep ) { - struct io_buffer *iobuf; - size_t len = ( ep->len ? ep->len : ep->mtu ); - int rc; - - /* Sanity checks */ - assert ( ep->open ); - assert ( ep->max > 0 ); - - /* Refill endpoint */ - while ( ep->fill < ep->max ) { - - /* Get or allocate buffer */ - if ( list_empty ( &ep->recycled ) ) { - /* Recycled buffer list is empty; allocate new buffer */ - iobuf = alloc_iob ( len ); - if ( ! iobuf ) - return -ENOMEM; - } else { - /* Get buffer from recycled buffer list */ - iobuf = list_first_entry ( &ep->recycled, - struct io_buffer, list ); - assert ( iobuf != NULL ); - list_del ( &iobuf->list ); - } - - /* Reset buffer to maximum size */ - assert ( iob_len ( iobuf ) <= len ); - iob_put ( iobuf, ( len - iob_len ( iobuf ) ) ); - - /* Enqueue buffer */ - if ( ( rc = usb_stream ( ep, iobuf, 0 ) ) != 0 ) { - list_add ( &iobuf->list, &ep->recycled ); - return rc; - } - } - - return 0; -} - -/** - * Discard endpoint recycled buffer list - * - * @v ep USB endpoint - */ -void usb_flush ( struct usb_endpoint *ep ) { - struct io_buffer *iobuf; - struct io_buffer *tmp; - - /* Sanity checks */ - assert ( ! ep->open ); - assert ( ep->max > 0 ); - - /* Free all I/O buffers */ - list_for_each_entry_safe ( iobuf, tmp, &ep->recycled, list ) { - list_del ( &iobuf->list ); - free_iob ( iobuf ); - } -} - -/****************************************************************************** - * - * Control endpoint - * - ****************************************************************************** - */ - -/** USB control transfer pseudo-header */ -struct usb_control_pseudo_header { - /** Completion status */ - int rc; -}; - -/** - * Complete USB control transfer - * - * @v ep USB endpoint - * @v iobuf I/O buffer - * @v rc Completion status code - */ -static void usb_control_complete ( struct usb_endpoint *ep, - struct io_buffer *iobuf, int rc ) { - struct usb_device *usb = ep->usb; - struct usb_control_pseudo_header *pshdr; - - /* Record completion status in buffer */ - pshdr = iob_push ( iobuf, sizeof ( *pshdr ) ); - pshdr->rc = rc; - - /* Add to list of completed I/O buffers */ - list_add_tail ( &iobuf->list, &usb->complete ); -} - -/** USB control endpoint driver operations */ -static struct usb_endpoint_driver_operations usb_control_operations = { - .complete = usb_control_complete, -}; - -/** - * Issue USB control transaction - * - * @v usb USB device - * @v request Request - * @v value Value parameter - * @v index Index parameter - * @v data Data buffer (if any) - * @v len Length of data - * @ret rc Return status code - */ -int usb_control ( struct usb_device *usb, unsigned int request, - unsigned int value, unsigned int index, void *data, - size_t len ) { - struct usb_bus *bus = usb->port->hub->bus; - struct usb_endpoint *ep = &usb->control; - struct io_buffer *iobuf; - struct io_buffer *cmplt; - union { - struct usb_setup_packet setup; - struct usb_control_pseudo_header pshdr; - } *headroom; - struct usb_control_pseudo_header *pshdr; - unsigned int i; - int rc; - - /* Allocate I/O buffer */ - iobuf = alloc_iob ( sizeof ( *headroom ) + len ); - if ( ! iobuf ) { - rc = -ENOMEM; - goto err_alloc; - } - iob_reserve ( iobuf, sizeof ( *headroom ) ); - iob_put ( iobuf, len ); - if ( request & USB_DIR_IN ) { - memset ( data, 0, len ); - } else { - memcpy ( iobuf->data, data, len ); - } - - /* Enqueue message */ - if ( ( rc = usb_message ( ep, request, value, index, iobuf ) ) != 0 ) - goto err_message; - - /* Wait for completion */ - for ( i = 0 ; i < USB_CONTROL_MAX_WAIT_MS ; i++ ) { - - /* Poll bus */ - usb_poll ( bus ); - - /* Check for completion */ - while ( ( cmplt = list_first_entry ( &usb->complete, - struct io_buffer, - list ) ) ) { - - /* Remove from completion list */ - list_del ( &cmplt->list ); - - /* Extract and strip completion status */ - pshdr = cmplt->data; - iob_pull ( cmplt, sizeof ( *pshdr ) ); - rc = pshdr->rc; - - /* Discard stale completions */ - if ( cmplt != iobuf ) { - DBGC ( usb, "USB %s stale control completion: " - "%s\n", usb->name, strerror ( rc ) ); - DBGC_HDA ( usb, 0, cmplt->data, - iob_len ( cmplt ) ); - free_iob ( cmplt ); - continue; - } - - /* Fail immediately if completion was in error */ - if ( rc != 0 ) { - DBGC ( usb, "USB %s control %04x:%04x:%04x " - "failed: %s\n", usb->name, request, - value, index, strerror ( rc ) ); - free_iob ( cmplt ); - return rc; - } - - /* Copy completion to data buffer, if applicable */ - assert ( iob_len ( cmplt ) <= len ); - if ( request & USB_DIR_IN ) - memcpy ( data, cmplt->data, iob_len ( cmplt ) ); - free_iob ( cmplt ); - return 0; - } - - /* Delay */ - mdelay ( 1 ); - } - - DBGC ( usb, "USB %s timed out waiting for control %04x:%04x:%04x\n", - usb->name, request, value, index ); - return -ETIMEDOUT; - - err_message: - free_iob ( iobuf ); - err_alloc: - return rc; -} - -/** - * Get USB string descriptor - * - * @v usb USB device - * @v index String index - * @v language Language ID - * @v buf Data buffer - * @v len Length of buffer - * @ret len String length (excluding NUL), or negative error - */ -int usb_get_string_descriptor ( struct usb_device *usb, unsigned int index, - unsigned int language, char *buf, size_t len ) { - size_t max = ( len ? ( len - 1 /* NUL */ ) : 0 ); - struct { - struct usb_descriptor_header header; - uint16_t character[max]; - } __attribute__ (( packed )) *desc; - unsigned int actual; - unsigned int i; - int rc; - - /* Allocate buffer for string */ - desc = malloc ( sizeof ( *desc ) ); - if ( ! desc ) { - rc = -ENOMEM; - goto err_alloc; - } - - /* Get descriptor */ - if ( ( rc = usb_get_descriptor ( usb, 0, USB_STRING_DESCRIPTOR, index, - language, &desc->header, - sizeof ( *desc ) ) ) != 0 ) - goto err_get_descriptor; - - /* Copy to buffer */ - actual = ( ( desc->header.len - sizeof ( desc->header ) ) / - sizeof ( desc->character[0] ) ); - for ( i = 0 ; ( ( i < actual ) && ( i < max ) ) ; i++ ) - buf[i] = le16_to_cpu ( desc->character[i] ); - if ( len ) - buf[i] = '\0'; - - /* Free buffer */ - free ( desc ); - - return actual; - - err_get_descriptor: - free ( desc ); - err_alloc: - return rc; -} - -/****************************************************************************** - * - * USB device driver - * - ****************************************************************************** - */ - -/** - * Describe USB function - * - * @v func USB function - * @v config Configuration descriptor - * @v first First interface number - * @ret rc Return status code - */ -static int usb_function ( struct usb_function *func, - struct usb_configuration_descriptor *config, - unsigned int first ) { - struct usb_device *usb = func->usb; - struct usb_interface_association_descriptor *association; - struct usb_interface_descriptor *interface; - struct cdc_union_descriptor *cdc_union; - unsigned int i; - - /* First, look for an interface association descriptor */ - association = usb_interface_association_descriptor ( config, first ); - if ( association ) { - - /* Sanity check */ - if ( association->count > config->interfaces ) { - DBGC ( usb, "USB %s has invalid association [%d-%d)\n", - func->name, association->first, - ( association->first + association->count ) ); - return -ERANGE; - } - - /* Describe function */ - memcpy ( &func->class, &association->class, - sizeof ( func->class ) ); - func->count = association->count; - for ( i = 0 ; i < association->count ; i++ ) - func->interface[i] = ( association->first + i ); - return 0; - } - - /* Next, look for an interface descriptor */ - interface = usb_interface_descriptor ( config, first, 0 ); - if ( ! interface ) { - DBGC ( usb, "USB %s has no interface descriptor\n", - func->name ); - return -ENOENT; - } - - /* Describe function */ - memcpy ( &func->class, &interface->class, sizeof ( func->class ) ); - func->count = 1; - func->interface[0] = first; - - /* Look for a CDC union descriptor, if applicable */ - if ( ( func->class.class == USB_CLASS_CDC ) && - ( cdc_union = cdc_union_descriptor ( config, interface ) ) ) { - - /* Determine interface count */ - func->count = ( ( cdc_union->header.len - - offsetof ( typeof ( *cdc_union ), - interface[0] ) ) / - sizeof ( cdc_union->interface[0] ) ); - if ( func->count > config->interfaces ) { - DBGC ( usb, "USB %s has invalid union functional " - "descriptor with %d interfaces\n", - func->name, func->count ); - return -ERANGE; - } - - /* Describe function */ - for ( i = 0 ; i < func->count ; i++ ) - func->interface[i] = cdc_union->interface[i]; - - return 0; - } - - return 0; -} - -/** - * Check for a USB device ID match - * - * @v func USB function - * @v id Device ID - * @ret matches Device ID matches - */ -static int -usb_device_id_matches ( struct usb_function *func, struct usb_device_id *id ) { - - return ( ( ( id->vendor == func->dev.desc.vendor ) || - ( id->vendor == USB_ANY_ID ) ) && - ( ( id->product == func->dev.desc.device ) || - ( id->product == USB_ANY_ID ) ) && - ( id->class.class == func->class.class ) && - ( id->class.subclass == func->class.subclass ) && - ( id->class.protocol == func->class.protocol ) ); -} - -/** - * Probe USB device driver - * - * @v func USB function - * @v config Configuration descriptor - * @ret rc Return status code - */ -static int usb_probe ( struct usb_function *func, - struct usb_configuration_descriptor *config ) { - struct usb_device *usb = func->usb; - struct usb_driver *driver; - struct usb_device_id *id; - unsigned int i; - int rc; - - /* Look for a matching driver */ - for_each_table_entry ( driver, USB_DRIVERS ) { - for ( i = 0 ; i < driver->id_count ; i++ ) { - - /* Check for a matching ID */ - id = &driver->ids[i]; - if ( ! usb_device_id_matches ( func, id ) ) - continue; - - /* Probe driver */ - if ( ( rc = driver->probe ( func, config ) ) != 0 ) { - DBGC ( usb, "USB %s failed to probe driver %s: " - "%s\n", func->name, id->name, - strerror ( rc ) ); - /* Continue trying other drivers */ - continue; - } - - /* Record driver */ - func->driver = driver; - func->dev.driver_name = id->name; - return 0; - } - } - - /* No driver found */ - DBGC ( usb, "USB %s %04x:%04x class %d:%d:%d has no driver\n", - func->name, func->dev.desc.vendor, func->dev.desc.device, - func->class.class, func->class.subclass, func->class.protocol ); - return -ENOENT; -} - -/** - * Remove USB device driver - * - * @v func USB function - */ -static void usb_remove ( struct usb_function *func ) { - - /* Remove driver */ - func->driver->remove ( func ); -} - -/** - * Probe all USB device drivers - * - * @v usb USB device - * @v config Configuration descriptor - */ -static void -usb_probe_all ( struct usb_device *usb, - struct usb_configuration_descriptor *config ) { - struct usb_bus *bus = usb->port->hub->bus; - struct usb_function *func; - uint8_t used[config->interfaces]; - unsigned int first; - unsigned int i; - int rc; - - /* Identify each function in turn */ - memset ( used, 0, sizeof ( used ) ); - for ( first = 0 ; first < config->interfaces ; first++ ) { - - /* Skip interfaces already used */ - if ( used[first] ) - continue; - - /* Allocate and initialise structure */ - func = zalloc ( sizeof ( *func ) + - ( config->interfaces * - sizeof ( func->interface[0] ) ) ); - if ( ! func ) - goto err_alloc; - func->name = func->dev.name; - func->usb = usb; - func->dev.desc.bus_type = BUS_TYPE_USB; - func->dev.desc.location = usb->address; - func->dev.desc.vendor = le16_to_cpu ( usb->device.vendor ); - func->dev.desc.device = le16_to_cpu ( usb->device.product ); - snprintf ( func->dev.name, sizeof ( func->dev.name ), - "%s-%d.%d", usb->name, config->config, first ); - INIT_LIST_HEAD ( &func->dev.children ); - func->dev.parent = bus->dev; - - /* Identify function */ - if ( ( rc = usb_function ( func, config, first ) ) != 0 ) - goto err_function; - assert ( func->count <= config->interfaces ); - - /* Mark interfaces as used */ - for ( i = 0 ; i < func->count ; i++ ) { - if ( func->interface[i] >= config->interfaces ) { - DBGC ( usb, "USB %s has invalid interface %d\n", - func->name, func->interface[i] ); - goto err_interface; - } - used[ func->interface[i] ] = 1; - } - - /* Probe device driver */ - if ( ( rc = usb_probe ( func, config ) ) != 0 ) - goto err_probe; - DBGC ( usb, "USB %s %04x:%04x class %d:%d:%d interfaces ", - func->name, func->dev.desc.vendor, func->dev.desc.device, - func->class.class, func->class.subclass, - func->class.protocol ); - for ( i = 0 ; i < func->count ; i++ ) - DBGC ( usb, "%s%d", ( i ? "," : "" ), - func->interface[i] ); - DBGC ( usb, " using driver %s\n", func->dev.driver_name ); - - /* Add to list of functions */ - list_add ( &func->list, &usb->functions ); - - /* Add to device hierarchy */ - list_add_tail ( &func->dev.siblings, &bus->dev->children ); - - continue; - - list_del ( &func->dev.siblings ); - list_del ( &func->list ); - usb_remove ( func ); - err_probe: - free ( func ); - err_alloc: - err_interface: - err_function: - /* Continue registering other functions */ - continue; - } -} - -/** - * Remove all device drivers - * - * @v usb USB device - */ -static void usb_remove_all ( struct usb_device *usb ) { - struct usb_function *func; - struct usb_function *tmp; - - /* Remove all functions */ - list_for_each_entry_safe ( func, tmp, &usb->functions, list ) { - - /* Remove device driver */ - usb_remove ( func ); - - /* Remove from device hierarchy */ - assert ( list_empty ( &func->dev.children ) ); - list_del ( &func->dev.siblings ); - - /* Remove from list of functions */ - list_del ( &func->list ); - - /* Free function */ - free ( func ); - } -} - -/** - * Select USB device configuration - * - * @v usb USB device - * @v index Configuration index - * @ret rc Return status code - */ -static int usb_configure ( struct usb_device *usb, unsigned int index ) { - struct usb_configuration_descriptor partial; - struct usb_configuration_descriptor *config; - size_t len; - int rc; - - /* Read first part of configuration descriptor to get size */ - if ( ( rc = usb_get_config_descriptor ( usb, index, &partial, - sizeof ( partial ) ) ) != 0 ) { - DBGC ( usb, "USB %s could not get configuration descriptor %d: " - "%s\n", usb->name, index, strerror ( rc ) ); - goto err_get_partial; - } - len = le16_to_cpu ( partial.len ); - if ( len < sizeof ( partial ) ) { - DBGC ( usb, "USB %s underlength configuraton descriptor %d\n", - usb->name, index ); - rc = -EINVAL; - goto err_partial_len; - } - - /* Allocate buffer for whole configuration descriptor */ - config = malloc ( len ); - if ( ! config ) { - rc = -ENOMEM; - goto err_alloc_config; - } - - /* Read whole configuration descriptor */ - if ( ( rc = usb_get_config_descriptor ( usb, index, config, - len ) ) != 0 ) { - DBGC ( usb, "USB %s could not get configuration descriptor %d: " - "%s\n", usb->name, index, strerror ( rc ) ); - goto err_get_config_descriptor; - } - if ( config->len != partial.len ) { - DBGC ( usb, "USB %s bad configuration descriptor %d length\n", - usb->name, index ); - rc = -EINVAL; - goto err_config_len; - } - - /* Set configuration */ - if ( ( rc = usb_set_configuration ( usb, config->config ) ) != 0){ - DBGC ( usb, "USB %s could not set configuration %d: %s\n", - usb->name, config->config, strerror ( rc ) ); - goto err_set_configuration; - } - - /* Probe USB device drivers */ - usb_probe_all ( usb, config ); - - /* Free configuration descriptor */ - free ( config ); - - return 0; - - usb_remove_all ( usb ); - usb_set_configuration ( usb, 0 ); - err_set_configuration: - err_config_len: - err_get_config_descriptor: - free ( config ); - err_alloc_config: - err_partial_len: - err_get_partial: - return rc; -} - -/** - * Clear USB device configuration - * - * @v usb USB device - */ -static void usb_deconfigure ( struct usb_device *usb ) { - unsigned int i; - - /* Remove device drivers */ - usb_remove_all ( usb ); - - /* Sanity checks */ - for ( i = 0 ; i < ( sizeof ( usb->ep ) / sizeof ( usb->ep[0] ) ) ; i++){ - if ( i != USB_ENDPOINT_IDX ( USB_EP0_ADDRESS ) ) - assert ( usb->ep[i] == NULL ); - } - - /* Clear device configuration */ - usb_set_configuration ( usb, 0 ); -} - -/** - * Find and select a supported USB device configuration - * - * @v usb USB device - * @ret rc Return status code - */ -static int usb_configure_any ( struct usb_device *usb ) { - unsigned int index; - int rc = -ENOENT; - - /* Attempt all configuration indexes */ - for ( index = 0 ; index < usb->device.configurations ; index++ ) { - - /* Attempt this configuration index */ - if ( ( rc = usb_configure ( usb, index ) ) != 0 ) - continue; - - /* If we have no drivers, then try the next configuration */ - if ( list_empty ( &usb->functions ) ) { - rc = -ENOTSUP; - usb_deconfigure ( usb ); - continue; - } - - return 0; - } - - return rc; -} - -/****************************************************************************** - * - * USB device - * - ****************************************************************************** - */ - -/** - * Allocate USB device - * - * @v port USB port - * @ret usb USB device, or NULL on allocation failure - */ -static struct usb_device * alloc_usb ( struct usb_port *port ) { - struct usb_hub *hub = port->hub; - struct usb_bus *bus = hub->bus; - struct usb_device *usb; - - /* Allocate and initialise structure */ - usb = zalloc ( sizeof ( *usb ) ); - if ( ! usb ) - return NULL; - snprintf ( usb->name, sizeof ( usb->name ), "%s%c%d", hub->name, - ( hub->usb ? '.' : '-' ), port->address ); - usb->port = port; - INIT_LIST_HEAD ( &usb->functions ); - usb->host = &bus->op->device; - usb_endpoint_init ( &usb->control, usb, &usb_control_operations ); - INIT_LIST_HEAD ( &usb->complete ); - - return usb; -} - -/** - * Register USB device - * - * @v usb USB device - * @ret rc Return status code - */ -static int register_usb ( struct usb_device *usb ) { - struct usb_port *port = usb->port; - struct usb_hub *hub = port->hub; - struct usb_bus *bus = hub->bus; - unsigned int protocol; - size_t mtu; - int rc; - - /* Add to port */ - if ( port->usb != NULL ) { - DBGC ( hub, "USB hub %s port %d is already registered to %s\n", - hub->name, port->address, port->usb->name ); - rc = -EALREADY; - goto err_already; - } - port->usb = usb; - - /* Add to bus device list */ - list_add_tail ( &usb->list, &bus->devices ); - - /* Enable device */ - if ( ( rc = hub->driver->enable ( hub, port ) ) != 0 ) { - DBGC ( hub, "USB hub %s port %d could not enable: %s\n", - hub->name, port->address, strerror ( rc ) ); - goto err_enable; - } - - /* Allow recovery interval since port may have been reset */ - mdelay ( USB_RESET_RECOVER_DELAY_MS ); - - /* Get device speed */ - if ( ( rc = hub->driver->speed ( hub, port ) ) != 0 ) { - DBGC ( hub, "USB hub %s port %d could not get speed: %s\n", - hub->name, port->address, strerror ( rc ) ); - goto err_speed; - } - DBGC2 ( usb, "USB %s attached as %s-speed device\n", - usb->name, usb_speed_name ( port->speed ) ); - - /* Open device */ - if ( ( rc = usb->host->open ( usb ) ) != 0 ) { - DBGC ( usb, "USB %s could not open: %s\n", - usb->name, strerror ( rc ) ); - goto err_open; - } - - /* Describe control endpoint */ - mtu = USB_EP0_DEFAULT_MTU ( port->speed ); - usb_endpoint_describe ( &usb->control, USB_EP0_ADDRESS, - USB_EP0_ATTRIBUTES, mtu, USB_EP0_BURST, - USB_EP0_INTERVAL ); - - /* Open control endpoint */ - if ( ( rc = usb_endpoint_open ( &usb->control ) ) != 0 ) - goto err_open_control; - assert ( usb_endpoint ( usb, USB_EP0_ADDRESS ) == &usb->control ); - - /* Assign device address */ - if ( ( rc = usb->host->address ( usb ) ) != 0 ) { - DBGC ( usb, "USB %s could not set address: %s\n", - usb->name, strerror ( rc ) ); - goto err_address; - } - DBGC2 ( usb, "USB %s assigned address %d\n", usb->name, usb->address ); - - /* Allow recovery interval after Set Address command */ - mdelay ( USB_SET_ADDRESS_RECOVER_DELAY_MS ); - - /* Read first part of device descriptor to get EP0 MTU */ - if ( ( rc = usb_get_mtu ( usb, &usb->device ) ) != 0 ) { - DBGC ( usb, "USB %s could not get MTU: %s\n", - usb->name, strerror ( rc ) ); - goto err_get_mtu; - } - - /* Calculate EP0 MTU */ - protocol = le16_to_cpu ( usb->device.protocol ); - mtu = ( ( protocol < USB_PROTO_3_0 ) ? - usb->device.mtu : ( 1 << usb->device.mtu ) ); - DBGC2 ( usb, "USB %s has control MTU %zd (guessed %zd)\n", - usb->name, mtu, usb->control.mtu ); - - /* Update MTU */ - if ( ( rc = usb_endpoint_mtu ( &usb->control, mtu ) ) != 0 ) - goto err_mtu; - - /* Read whole device descriptor */ - if ( ( rc = usb_get_device_descriptor ( usb, &usb->device ) ) != 0 ) { - DBGC ( usb, "USB %s could not get device descriptor: %s\n", - usb->name, strerror ( rc ) ); - goto err_get_device_descriptor; - } - DBGC ( usb, "USB %s addr %d %04x:%04x class %d:%d:%d (v%s, %s-speed, " - "MTU %zd)\n", usb->name, usb->address, - le16_to_cpu ( usb->device.vendor ), - le16_to_cpu ( usb->device.product ), usb->device.class.class, - usb->device.class.subclass, usb->device.class.protocol, - usb_bcd ( le16_to_cpu ( usb->device.protocol ) ), - usb_speed_name ( port->speed ), usb->control.mtu ); - - /* Configure device */ - if ( ( rc = usb_configure_any ( usb ) ) != 0 ) - goto err_configure_any; - - return 0; - - usb_deconfigure ( usb ); - err_configure_any: - err_get_device_descriptor: - err_mtu: - err_get_mtu: - err_address: - usb_endpoint_close ( &usb->control ); - err_open_control: - usb->host->close ( usb ); - err_open: - err_speed: - hub->driver->disable ( hub, port ); - err_enable: - list_del ( &usb->list ); - port->usb = NULL; - err_already: - return rc; -} - -/** - * Unregister USB device - * - * @v usb USB device - */ -static void unregister_usb ( struct usb_device *usb ) { - struct usb_port *port = usb->port; - struct usb_hub *hub = port->hub; - struct io_buffer *iobuf; - struct io_buffer *tmp; - - /* Sanity checks */ - assert ( port->usb == usb ); - - /* Clear device configuration */ - usb_deconfigure ( usb ); - - /* Close control endpoint */ - usb_endpoint_close ( &usb->control ); - - /* Discard any stale control completions */ - list_for_each_entry_safe ( iobuf, tmp, &usb->complete, list ) { - list_del ( &iobuf->list ); - free_iob ( iobuf ); - } - - /* Close device */ - usb->host->close ( usb ); - - /* Disable port */ - hub->driver->disable ( hub, port ); - - /* Remove from bus device list */ - list_del ( &usb->list ); - - /* Remove from port */ - port->usb = NULL; -} - -/** - * Free USB device - * - * @v usb USB device - */ -static void free_usb ( struct usb_device *usb ) { - unsigned int i; - - /* Sanity checks */ - for ( i = 0 ; i < ( sizeof ( usb->ep ) / sizeof ( usb->ep[0] ) ) ; i++ ) - assert ( usb->ep[i] == NULL ); - assert ( list_empty ( &usb->functions ) ); - assert ( list_empty ( &usb->complete ) ); - - /* Free device */ - free ( usb ); -} - -/****************************************************************************** - * - * USB device hotplug event handling - * - ****************************************************************************** - */ - -/** - * Handle newly attached USB device - * - * @v port USB port - * @ret rc Return status code - */ -static int usb_attached ( struct usb_port *port ) { - struct usb_device *usb; - int rc; - - /* Mark port as attached */ - port->attached = 1; - - /* Sanity checks */ - assert ( port->usb == NULL ); - - /* Allocate USB device */ - usb = alloc_usb ( port ); - if ( ! usb ) { - rc = -ENOMEM; - goto err_alloc; - } - - /* Register USB device */ - if ( ( rc = register_usb ( usb ) ) != 0 ) - goto err_register; - - return 0; - - unregister_usb ( usb ); - err_register: - free_usb ( usb ); - err_alloc: - return rc; -} - -/** - * Handle newly detached USB device - * - * @v port USB port - */ -static void usb_detached ( struct usb_port *port ) { - struct usb_device *usb = port->usb; - - /* Mark port as detached */ - port->attached = 0; - - /* Do nothing if we have no USB device */ - if ( ! usb ) - return; - - /* Unregister USB device */ - unregister_usb ( usb ); - - /* Free USB device */ - free_usb ( usb ); -} - -/** - * Handle newly attached or detached USB device - * - * @v port USB port - * @ret rc Return status code - */ -static int usb_hotplugged ( struct usb_port *port ) { - struct usb_hub *hub = port->hub; - int rc; - - /* Get current port speed */ - if ( ( rc = hub->driver->speed ( hub, port ) ) != 0 ) { - DBGC ( hub, "USB hub %s port %d could not get speed: %s\n", - hub->name, port->address, strerror ( rc ) ); - goto err_speed; - } - - /* Detach device, if applicable */ - if ( port->attached && ( port->disconnected || ! port->speed ) ) - usb_detached ( port ); - - /* Attach device, if applicable */ - if ( port->speed && ( ! port->attached ) && - ( ( rc = usb_attached ( port ) ) != 0 ) ) - goto err_attached; - - err_attached: - err_speed: - /* Clear any recorded disconnections */ - port->disconnected = 0; - return rc; -} - -/****************************************************************************** - * - * USB process - * - ****************************************************************************** - */ - -/** - * Report port status change - * - * @v port USB port - */ -void usb_port_changed ( struct usb_port *port ) { - - /* Record hub port status change */ - list_del ( &port->changed ); - list_add_tail ( &port->changed, &usb_changed ); -} - -/** - * Handle newly attached or detached USB device - * - */ -static void usb_hotplug ( void ) { - struct usb_port *port; - - /* Handle any changed ports, allowing for the fact that the - * port list may change as we perform hotplug actions. - */ - while ( ! list_empty ( &usb_changed ) ) { - - /* Get first changed port */ - port = list_first_entry ( &usb_changed, struct usb_port, - changed ); - assert ( port != NULL ); - - /* Remove from list of changed ports */ - list_del ( &port->changed ); - INIT_LIST_HEAD ( &port->changed ); - - /* Perform appropriate hotplug action */ - usb_hotplugged ( port ); - } -} - -/** - * USB process - * - * @v process USB process - */ -static void usb_step ( struct process *process __unused ) { - struct usb_bus *bus; - struct usb_endpoint *ep; - - /* Poll all buses */ - for_each_usb_bus ( bus ) - usb_poll ( bus ); - - /* Attempt to reset first halted endpoint in list, if any. We - * do not attempt to process the complete list, since this - * would require extra code to allow for the facts that the - * halted endpoint list may change as we do so, and that - * resetting an endpoint may fail. - */ - if ( ( ep = list_first_entry ( &usb_halted, struct usb_endpoint, - halted ) ) != NULL ) - usb_endpoint_reset ( ep ); - - /* Handle any changed ports */ - usb_hotplug(); -} - -/** USB process */ -PERMANENT_PROCESS ( usb_process, usb_step ); - -/****************************************************************************** - * - * USB hub - * - ****************************************************************************** - */ - -/** - * Allocate USB hub - * - * @v bus USB bus - * @v usb Underlying USB device, if any - * @v ports Number of ports - * @v driver Hub driver operations - * @ret hub USB hub, or NULL on allocation failure - */ -struct usb_hub * alloc_usb_hub ( struct usb_bus *bus, struct usb_device *usb, - unsigned int ports, - struct usb_hub_driver_operations *driver ) { - struct usb_hub *hub; - struct usb_port *port; - unsigned int i; - - /* Allocate and initialise structure */ - hub = zalloc ( sizeof ( *hub ) + ( ports * sizeof ( hub->port[0] ) ) ); - if ( ! hub ) - return NULL; - hub->name = ( usb ? usb->name : bus->name ); - hub->bus = bus; - hub->usb = usb; - if ( usb ) - hub->protocol = usb->port->protocol; - hub->ports = ports; - hub->driver = driver; - hub->host = &bus->op->hub; - - /* Initialise port list */ - for ( i = 1 ; i <= hub->ports ; i++ ) { - port = usb_port ( hub, i ); - port->hub = hub; - port->address = i; - if ( usb ) - port->protocol = usb->port->protocol; - INIT_LIST_HEAD ( &port->changed ); - } - - return hub; -} - -/** - * Register USB hub - * - * @v hub USB hub - * @ret rc Return status code - */ -int register_usb_hub ( struct usb_hub *hub ) { - struct usb_bus *bus = hub->bus; - struct usb_port *port; - unsigned int i; - int rc; - - /* Add to hub list */ - list_add_tail ( &hub->list, &bus->hubs ); - - /* Open hub (host controller) */ - if ( ( rc = hub->host->open ( hub ) ) != 0 ) { - DBGC ( hub, "USB hub %s could not open: %s\n", - hub->name, strerror ( rc ) ); - goto err_host_open; - } - - /* Open hub (driver) */ - if ( ( rc = hub->driver->open ( hub ) ) != 0 ) { - DBGC ( hub, "USB hub %s could not open: %s\n", - hub->name, strerror ( rc ) ); - goto err_driver_open; - } - - /* Delay to allow ports to stabilise */ - mdelay ( USB_PORT_DELAY_MS ); - - /* Mark all ports as changed */ - for ( i = 1 ; i <= hub->ports ; i++ ) { - port = usb_port ( hub, i ); - usb_port_changed ( port ); - } - - /* Some hubs seem to defer reporting device connections until - * their interrupt endpoint is polled for the first time. - * Poll the bus once now in order to pick up any such - * connections. - */ - usb_poll ( bus ); - - return 0; - - hub->driver->close ( hub ); - err_driver_open: - hub->host->close ( hub ); - err_host_open: - list_del ( &hub->list ); - return rc; -} - -/** - * Unregister USB hub - * - * @v hub USB hub - */ -void unregister_usb_hub ( struct usb_hub *hub ) { - struct usb_port *port; - unsigned int i; - - /* Detach all devices */ - for ( i = 1 ; i <= hub->ports ; i++ ) { - port = usb_port ( hub, i ); - if ( port->attached ) - usb_detached ( port ); - } - - /* Close hub (driver) */ - hub->driver->close ( hub ); - - /* Close hub (host controller) */ - hub->host->close ( hub ); - - /* Cancel any pending port status changes */ - for ( i = 1 ; i <= hub->ports ; i++ ) { - port = usb_port ( hub, i ); - list_del ( &port->changed ); - INIT_LIST_HEAD ( &port->changed ); - } - - /* Remove from hub list */ - list_del ( &hub->list ); -} - -/** - * Free USB hub - * - * @v hub USB hub - */ -void free_usb_hub ( struct usb_hub *hub ) { - struct usb_port *port; - unsigned int i; - - /* Sanity checks */ - for ( i = 1 ; i <= hub->ports ; i++ ) { - port = usb_port ( hub, i ); - assert ( ! port->attached ); - assert ( port->usb == NULL ); - assert ( list_empty ( &port->changed ) ); - } - - /* Free hub */ - free ( hub ); -} - -/****************************************************************************** - * - * USB bus - * - ****************************************************************************** - */ - -/** - * Allocate USB bus - * - * @v dev Underlying hardware device - * @v ports Number of root hub ports - * @v mtu Largest transfer allowed on the bus - * @v op Host controller operations - * @ret bus USB bus, or NULL on allocation failure - */ -struct usb_bus * alloc_usb_bus ( struct device *dev, unsigned int ports, - size_t mtu, struct usb_host_operations *op ) { - struct usb_bus *bus; - - /* Allocate and initialise structure */ - bus = zalloc ( sizeof ( *bus ) ); - if ( ! bus ) - goto err_alloc_bus; - bus->name = dev->name; - bus->dev = dev; - bus->mtu = mtu; - bus->op = op; - INIT_LIST_HEAD ( &bus->devices ); - INIT_LIST_HEAD ( &bus->hubs ); - bus->host = &bus->op->bus; - - /* Allocate root hub */ - bus->hub = alloc_usb_hub ( bus, NULL, ports, &op->root ); - if ( ! bus->hub ) - goto err_alloc_hub; - - return bus; - - free_usb_hub ( bus->hub ); - err_alloc_hub: - free ( bus ); - err_alloc_bus: - return NULL; -} - -/** - * Register USB bus - * - * @v bus USB bus - * @ret rc Return status code - */ -int register_usb_bus ( struct usb_bus *bus ) { - int rc; - - /* Sanity checks */ - assert ( bus->hub != NULL ); - - /* Open bus */ - if ( ( rc = bus->host->open ( bus ) ) != 0 ) - goto err_open; - - /* Add to list of USB buses */ - list_add_tail ( &bus->list, &usb_buses ); - - /* Register root hub */ - if ( ( rc = register_usb_hub ( bus->hub ) ) != 0 ) - goto err_register_hub; - - /* Attach any devices already present */ - usb_hotplug(); - - return 0; - - unregister_usb_hub ( bus->hub ); - err_register_hub: - list_del ( &bus->list ); - bus->host->close ( bus ); - err_open: - return rc; -} - -/** - * Unregister USB bus - * - * @v bus USB bus - */ -void unregister_usb_bus ( struct usb_bus *bus ) { - - /* Sanity checks */ - assert ( bus->hub != NULL ); - - /* Unregister root hub */ - unregister_usb_hub ( bus->hub ); - - /* Remove from list of USB buses */ - list_del ( &bus->list ); - - /* Close bus */ - bus->host->close ( bus ); - - /* Sanity checks */ - assert ( list_empty ( &bus->devices ) ); - assert ( list_empty ( &bus->hubs ) ); -} - -/** - * Free USB bus - * - * @v bus USB bus - */ -void free_usb_bus ( struct usb_bus *bus ) { - struct usb_endpoint *ep; - struct usb_port *port; - - /* Sanity checks */ - assert ( list_empty ( &bus->devices ) ); - assert ( list_empty ( &bus->hubs ) ); - list_for_each_entry ( ep, &usb_halted, halted ) - assert ( ep->usb->port->hub->bus != bus ); - list_for_each_entry ( port, &usb_changed, changed ) - assert ( port->hub->bus != bus ); - - /* Free root hub */ - free_usb_hub ( bus->hub ); - - /* Free bus */ - free ( bus ); -} - -/** - * Find USB bus by device location - * - * @v bus_type Bus type - * @v location Bus location - * @ret bus USB bus, or NULL - */ -struct usb_bus * find_usb_bus_by_location ( unsigned int bus_type, - unsigned int location ) { - struct usb_bus *bus; - - for_each_usb_bus ( bus ) { - if ( ( bus->dev->desc.bus_type == bus_type ) && - ( bus->dev->desc.location == location ) ) - return bus; - } - - return NULL; -} - -/****************************************************************************** - * - * USB address assignment - * - ****************************************************************************** - */ - -/** - * Allocate device address - * - * @v bus USB bus - * @ret address Device address, or negative error - */ -int usb_alloc_address ( struct usb_bus *bus ) { - unsigned int address; - - /* Find first free device address */ - address = ffsll ( ~bus->addresses ); - if ( ! address ) - return -ENOENT; - - /* Mark address as used */ - bus->addresses |= ( 1ULL << ( address - 1 ) ); - - return address; -} - -/** - * Free device address - * - * @v bus USB bus - * @v address Device address - */ -void usb_free_address ( struct usb_bus *bus, unsigned int address ) { - - /* Sanity check */ - assert ( address > 0 ); - assert ( bus->addresses & ( 1ULL << ( address - 1 ) ) ); - - /* Mark address as free */ - bus->addresses &= ~( 1ULL << ( address - 1 ) ); -} - -/****************************************************************************** - * - * USB bus topology - * - ****************************************************************************** - */ - -/** - * Get USB route string - * - * @v usb USB device - * @ret route USB route string - */ -unsigned int usb_route_string ( struct usb_device *usb ) { - struct usb_device *parent; - unsigned int route; - - /* Navigate up to root hub, constructing route string as we go */ - for ( route = 0 ; ( parent = usb->port->hub->usb ) ; usb = parent ) { - route <<= 4; - route |= ( ( usb->port->address > 0xf ) ? - 0xf : usb->port->address ); - } - - return route; -} - -/** - * Get USB depth - * - * @v usb USB device - * @ret depth Hub depth - */ -unsigned int usb_depth ( struct usb_device *usb ) { - struct usb_device *parent; - unsigned int depth; - - /* Navigate up to root hub, constructing depth as we go */ - for ( depth = 0 ; ( parent = usb->port->hub->usb ) ; usb = parent ) - depth++; - - return depth; -} - -/** - * Get USB root hub port - * - * @v usb USB device - * @ret port Root hub port - */ -struct usb_port * usb_root_hub_port ( struct usb_device *usb ) { - struct usb_device *parent; - - /* Navigate up to root hub */ - while ( ( parent = usb->port->hub->usb ) ) - usb = parent; - - return usb->port; -} - -/** - * Get USB transaction translator - * - * @v usb USB device - * @ret port Transaction translator port, or NULL - */ -struct usb_port * usb_transaction_translator ( struct usb_device *usb ) { - struct usb_device *parent; - - /* Navigate up to root hub. If we find a low-speed or - * full-speed port with a higher-speed parent device, then - * that port is the transaction translator. - */ - for ( ; ( parent = usb->port->hub->usb ) ; usb = parent ) { - if ( ( usb->port->speed <= USB_SPEED_FULL ) && - ( parent->port->speed > USB_SPEED_FULL ) ) - return usb->port; - } - - return NULL; -} - -/* Drag in objects via register_usb_bus() */ -REQUIRING_SYMBOL ( register_usb_bus ); - -/* Drag in USB configuration */ -REQUIRE_OBJECT ( config_usb ); - -/* Drag in hub driver */ -REQUIRE_OBJECT ( usbhub ); diff --git a/qemu/roms/ipxe/src/drivers/bus/virtio-pci.c b/qemu/roms/ipxe/src/drivers/bus/virtio-pci.c deleted file mode 100644 index fbef067bc..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/virtio-pci.c +++ /dev/null @@ -1,64 +0,0 @@ -/* virtio-pci.c - pci interface for virtio interface - * - * (c) Copyright 2008 Bull S.A.S. - * - * Author: Laurent Vivier <Laurent.Vivier@bull.net> - * - * some parts from Linux Virtio PCI driver - * - * Copyright IBM Corp. 2007 - * Authors: Anthony Liguori <aliguori@us.ibm.com> - * - */ - -#include "etherboot.h" -#include "ipxe/io.h" -#include "ipxe/virtio-ring.h" -#include "ipxe/virtio-pci.h" - -int vp_find_vq(unsigned int ioaddr, int queue_index, - struct vring_virtqueue *vq) -{ - struct vring * vr = &vq->vring; - u16 num; - - /* select the queue */ - - outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL); - - /* check if the queue is available */ - - num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM); - if (!num) { - printf("ERROR: queue size is 0\n"); - return -1; - } - - if (num > MAX_QUEUE_NUM) { - printf("ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM); - return -1; - } - - /* check if the queue is already active */ - - if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) { - printf("ERROR: queue already active\n"); - return -1; - } - - vq->queue_index = queue_index; - - /* initialize the queue */ - - vring_init(vr, num, (unsigned char*)&vq->queue); - - /* activate the queue - * - * NOTE: vr->desc is initialized by vring_init() - */ - - outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT, - ioaddr + VIRTIO_PCI_QUEUE_PFN); - - return num; -} diff --git a/qemu/roms/ipxe/src/drivers/bus/virtio-ring.c b/qemu/roms/ipxe/src/drivers/bus/virtio-ring.c deleted file mode 100644 index e55b6d0ed..000000000 --- a/qemu/roms/ipxe/src/drivers/bus/virtio-ring.c +++ /dev/null @@ -1,136 +0,0 @@ -/* virtio-pci.c - virtio ring management - * - * (c) Copyright 2008 Bull S.A.S. - * - * Author: Laurent Vivier <Laurent.Vivier@bull.net> - * - * some parts from Linux Virtio Ring - * - * Copyright Rusty Russell IBM Corporation 2007 - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - * - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include "etherboot.h" -#include "ipxe/io.h" -#include "ipxe/virtio-ring.h" -#include "ipxe/virtio-pci.h" - -#define BUG() do { \ - printf("BUG: failure at %s:%d/%s()!\n", \ - __FILE__, __LINE__, __FUNCTION__); \ - while(1); \ -} while (0) -#define BUG_ON(condition) do { if (condition) BUG(); } while (0) - -/* - * vring_free - * - * put at the begin of the free list the current desc[head] - */ - -void vring_detach(struct vring_virtqueue *vq, unsigned int head) -{ - struct vring *vr = &vq->vring; - unsigned int i; - - /* find end of given descriptor */ - - i = head; - while (vr->desc[i].flags & VRING_DESC_F_NEXT) - i = vr->desc[i].next; - - /* link it with free list and point to it */ - - vr->desc[i].next = vq->free_head; - wmb(); - vq->free_head = head; -} - -/* - * vring_get_buf - * - * get a buffer from the used list - * - */ - -void *vring_get_buf(struct vring_virtqueue *vq, unsigned int *len) -{ - struct vring *vr = &vq->vring; - struct vring_used_elem *elem; - u32 id; - void *opaque; - - BUG_ON(!vring_more_used(vq)); - - elem = &vr->used->ring[vq->last_used_idx % vr->num]; - wmb(); - id = elem->id; - if (len != NULL) - *len = elem->len; - - opaque = vq->vdata[id]; - - vring_detach(vq, id); - - vq->last_used_idx++; - - return opaque; -} - -void vring_add_buf(struct vring_virtqueue *vq, - struct vring_list list[], - unsigned int out, unsigned int in, - void *opaque, int num_added) -{ - struct vring *vr = &vq->vring; - int i, avail, head, prev; - - BUG_ON(out + in == 0); - - prev = 0; - head = vq->free_head; - for (i = head; out; i = vr->desc[i].next, out--) { - - vr->desc[i].flags = VRING_DESC_F_NEXT; - vr->desc[i].addr = (u64)virt_to_phys(list->addr); - vr->desc[i].len = list->length; - prev = i; - list++; - } - for ( ; in; i = vr->desc[i].next, in--) { - - vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE; - vr->desc[i].addr = (u64)virt_to_phys(list->addr); - vr->desc[i].len = list->length; - prev = i; - list++; - } - vr->desc[prev].flags &= ~VRING_DESC_F_NEXT; - - vq->free_head = i; - - vq->vdata[head] = opaque; - - avail = (vr->avail->idx + num_added) % vr->num; - vr->avail->ring[avail] = head; - wmb(); -} - -void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added) -{ - struct vring *vr = &vq->vring; - - wmb(); - vr->avail->idx += num_added; - - mb(); - if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY)) - vp_notify(ioaddr, vq->queue_index); -} - |