| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 | 
							- /** @file
 -  *
 -  * 
 -  *
 -  */
 - 
 - /*
 -  * Copyright (C) 2004 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 -  */
 - 
 - #include "pxe.h"
 - 
 - /* Global pointer to currently installed PXE stack */
 - pxe_stack_t *pxe_stack = NULL;
 - 
 - /* Various startup/shutdown routines.  The startup/shutdown call
 -  * sequence is incredibly badly defined in the Intel PXE spec, for
 -  * example:
 -  *
 -  *   PXENV_UNDI_INITIALIZE says that the parameters used to initialize
 -  *   the adaptor should be those supplied to the most recent
 -  *   PXENV_UNDI_STARTUP call.  PXENV_UNDI_STARTUP takes no parameters.
 -  *
 -  *   PXENV_UNDI_CLEANUP says that the rest of the API will not be
 -  *   available after making this call.  Figure 3-3 ("Early UNDI API
 -  *   usage") shows a call to PXENV_UNDI_CLEANUP being followed by a
 -  *   call to the supposedly now unavailable PXENV_STOP_UNDI.
 -  *
 -  *   PXENV_UNLOAD_BASE_STACK talks about freeing up the memory
 -  *   occupied by the PXE stack.  Figure 4-3 ("PXE IPL") shows a call
 -  *   to PXENV_STOP_UNDI being made after the call to
 -  *   PXENV_UNLOAD_BASE_STACK, by which time the entire PXE stack
 -  *   should have been freed (and, potentially, zeroed).
 -  *
 -  *   Nothing, anywhere, seems to mention who's responsible for freeing
 -  *   up the base memory allocated for the stack segment.  It's not
 -  *   even clear whether or not this is expected to be in free base
 -  *   memory rather than claimed base memory.
 -  *
 -  * Consequently, we adopt a rather defensive strategy, designed to
 -  * work with any conceivable sequence of initialisation or shutdown
 -  * calls.  We have only two things that we care about:
 -  *
 -  *   1. Have we hooked INT 1A and INT 15,E820(etc.)?
 -  *   2. Is the NIC initialised?
 -  *
 -  * The NIC should never be initialised without the vectors being
 -  * hooked, similarly the vectors should never be unhooked with the NIC
 -  * still initialised.  We do, however, want to be able to have the
 -  * vectors hooked with the NIC shutdown.  We therefore have three
 -  * possible states:
 -  *
 -  *   1. Ready to unload: interrupts unhooked, NIC shutdown.
 -  *   2. Midway: interrupts hooked, NIC shutdown.
 -  *   3. Fully ready: interrupts hooked, NIC initialised.
 -  *
 -  * We provide the three states CAN_UNLOAD, MIDWAY and READY to define
 -  * these, and the call pxe_ensure_state() to ensure that the stack is
 -  * in the specified state.  All our PXE API call implementations
 -  * should use this call to ensure that the state is as required for
 -  * that PXE API call.  This enables us to cope with whatever the
 -  * end-user's interpretation of the PXE spec may be.  It even allows
 -  * for someone calling e.g. PXENV_START_UNDI followed by
 -  * PXENV_UDP_WRITE, without bothering with any of the intervening
 -  * calls.
 -  *
 -  * pxe_ensure_state() returns 1 for success, 0 for failure.  In the
 -  * event of failure (which can arise from e.g. asking for state READY
 -  * when we don't know where our NIC is), the error code
 -  * PXENV_STATUS_UNDI_INVALID_STATE should be returned to the user.
 -  * The macros ENSURE_XXX() can be used to achieve this without lots of
 -  * duplicated code.
 -  */
 - 
 - /* pxe_[un]hook_stack are architecture-specific and provided in
 -  * pxe_callbacks.c
 -  */
 - 
 - int pxe_initialise_nic ( void ) {
 - 	if ( pxe_stack->state >= READY ) return 1;
 - 
 - #warning "device probing mechanism has completely changed"
 - #if 0
 - 
 - 	/* Check if NIC is initialised.  dev.disable is set to 0
 - 	 * when disable() is called, so we use this.
 - 	 */
 - 	if ( dev.disable ) {
 - 		/* NIC may have been initialised independently
 - 		 * (e.g. when we set up the stack prior to calling the
 - 		 * NBP).
 - 		 */
 - 		pxe_stack->state = READY;
 - 		return 1;
 - 	}
 - 
 - 	/* If we already have a NIC defined, reuse that one with
 - 	 * PROBE_AWAKE.  If one was specifed via PXENV_START_UNDI, try
 - 	 * that one first.  Otherwise, set PROBE_FIRST.
 - 	 */
 - 
 - 	if ( dev.state.pci.dev.use_specified == 1 ) {
 - 		dev.how_probe = PROBE_NEXT;
 - 		DBG ( " initialising NIC specified via START_UNDI" );
 - 	} else if ( dev.state.pci.dev.driver ) {
 - 		DBG ( " reinitialising NIC" );
 - 		dev.how_probe = PROBE_AWAKE;
 - 	} else {
 - 		DBG ( " probing for any NIC" );
 - 		dev.how_probe = PROBE_FIRST;
 - 	}
 - 
 - 	/* Call probe routine to bring up the NIC */
 - 	if ( eth_probe ( &dev ) != PROBE_WORKED ) {
 - 		DBG ( " failed" );
 - 		return 0;
 - 	}
 - #endif
 - 	
 - 
 - 	pxe_stack->state = READY;
 - 	return 1;
 - }
 - 
 - int pxe_shutdown_nic ( void ) {
 - 	if ( pxe_stack->state <= MIDWAY ) return 1;
 - 
 - 	eth_irq ( DISABLE );
 - 	disable ( &dev );
 - 	pxe_stack->state = MIDWAY;
 - 	return 1;
 - }
 - 
 - int ensure_pxe_state ( pxe_stack_state_t wanted ) {
 - 	int success = 1;
 - 
 - 	if ( ! pxe_stack ) return 0;
 - 	if ( wanted >= MIDWAY )
 - 		success = success & hook_pxe_stack();
 - 	if ( wanted > MIDWAY ) {
 - 		success = success & pxe_initialise_nic();
 - 	} else {
 - 		success = success & pxe_shutdown_nic();
 - 	}
 - 	if ( wanted < MIDWAY )
 - 		success = success & unhook_pxe_stack();
 - 	return success;
 - }
 - 
 - /* API call dispatcher
 -  *
 -  * Status: complete
 -  */
 - PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any ) {
 - 	PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
 - 
 - 	/* Set default status in case child routine fails to do so */
 - 	any->Status = PXENV_STATUS_FAILURE;
 - 
 - 	DBG ( "[" );
 - 
 - 	/* Hand off to relevant API routine */
 - 	switch ( opcode ) {
 - 	case PXENV_START_UNDI:
 - 		ret = pxenv_start_undi ( &any->start_undi );
 - 		break;
 - 	case PXENV_UNDI_STARTUP:
 - 		ret = pxenv_undi_startup ( &any->undi_startup );
 - 		break;
 - 	case PXENV_UNDI_CLEANUP:
 - 		ret = pxenv_undi_cleanup ( &any->undi_cleanup );
 - 		break;
 - 	case PXENV_UNDI_INITIALIZE:
 - 		ret = pxenv_undi_initialize ( &any->undi_initialize );
 - 		break;
 - 	case PXENV_UNDI_RESET_ADAPTER:
 - 		ret = pxenv_undi_reset_adapter ( &any->undi_reset_adapter );
 - 		break;
 - 	case PXENV_UNDI_SHUTDOWN:
 - 		ret = pxenv_undi_shutdown ( &any->undi_shutdown );
 - 		break;
 - 	case PXENV_UNDI_OPEN:
 - 		ret = pxenv_undi_open ( &any->undi_open );
 - 		break;
 - 	case PXENV_UNDI_CLOSE:
 - 		ret = pxenv_undi_close ( &any->undi_close );
 - 		break;
 - 	case PXENV_UNDI_TRANSMIT:
 - 		ret = pxenv_undi_transmit ( &any->undi_transmit );
 - 		break;
 - 	case PXENV_UNDI_SET_MCAST_ADDRESS:
 - 		ret = pxenv_undi_set_mcast_address (
 - 						&any->undi_set_mcast_address );
 - 		break;
 - 	case PXENV_UNDI_SET_STATION_ADDRESS:
 - 		ret = pxenv_undi_set_station_address (
 - 					      &any->undi_set_station_address );
 - 		break;
 - 	case PXENV_UNDI_SET_PACKET_FILTER:
 - 		ret = pxenv_undi_set_packet_filter (
 - 						&any->undi_set_packet_filter );
 - 		break;
 - 	case PXENV_UNDI_GET_INFORMATION:
 - 		ret = pxenv_undi_get_information (
 - 					       &any->undi_get_information );
 - 		break;
 - 	case PXENV_UNDI_GET_STATISTICS:
 - 		ret = pxenv_undi_get_statistics ( &any->undi_get_statistics );
 - 		break;
 - 	case PXENV_UNDI_CLEAR_STATISTICS:
 - 		ret = pxenv_undi_clear_statistics (
 - 						 &any->undi_clear_statistics );
 - 		break;
 - 	case PXENV_UNDI_INITIATE_DIAGS:
 - 		ret = pxenv_undi_initiate_diags ( &any->undi_initiate_diags );
 - 						 
 - 		break;
 - 	case PXENV_UNDI_FORCE_INTERRUPT:
 - 		ret = pxenv_undi_force_interrupt (
 - 					       &any->undi_force_interrupt );
 - 		break;
 - 	case PXENV_UNDI_GET_MCAST_ADDRESS:
 - 		ret = pxenv_undi_get_mcast_address (
 - 					     &any->undi_get_mcast_address );
 - 		break;
 - 	case PXENV_UNDI_GET_NIC_TYPE:
 - 		ret = pxenv_undi_get_nic_type ( &any->undi_get_nic_type );
 - 		break;
 - 	case PXENV_UNDI_GET_IFACE_INFO:
 - 		ret = pxenv_undi_get_iface_info ( &any->undi_get_iface_info );
 - 		break;
 - 	case PXENV_UNDI_ISR:
 - 		ret = pxenv_undi_isr ( &any->undi_isr );
 - 		break;
 - 	case PXENV_STOP_UNDI:
 - 		ret = pxenv_stop_undi ( &any->stop_undi );
 - 		break;
 - 	case PXENV_TFTP_OPEN:
 - 		ret = pxenv_tftp_open ( &any->tftp_open );
 - 		break;
 - 	case PXENV_TFTP_CLOSE:
 - 		ret = pxenv_tftp_close ( &any->tftp_close );
 - 		break;
 - 	case PXENV_TFTP_READ:
 - 		ret = pxenv_tftp_read ( &any->tftp_read );
 - 		break;
 - 	case PXENV_TFTP_READ_FILE:
 - 		ret = pxenv_tftp_read_file ( &any->tftp_read_file );
 - 		break;
 - 	case PXENV_TFTP_GET_FSIZE:
 - 		ret = pxenv_tftp_get_fsize ( &any->tftp_get_fsize );
 - 		break;
 - 	case PXENV_UDP_OPEN:
 - 		ret = pxenv_udp_open ( &any->udp_open );
 - 		break;
 - 	case PXENV_UDP_CLOSE:
 - 		ret = pxenv_udp_close ( &any->udp_close );
 - 		break;
 - 	case PXENV_UDP_READ:
 - 		ret = pxenv_udp_read ( &any->udp_read );
 - 		break;
 - 	case PXENV_UDP_WRITE:
 - 		ret = pxenv_udp_write ( &any->udp_write );
 - 		break;
 - 	case PXENV_UNLOAD_STACK:
 - 		ret = pxenv_unload_stack ( &any->unload_stack );
 - 		break;
 - 	case PXENV_GET_CACHED_INFO:
 - 		ret = pxenv_get_cached_info ( &any->get_cached_info );
 - 		break;
 - 	case PXENV_RESTART_TFTP:
 - 		ret = pxenv_restart_tftp ( &any->restart_tftp );
 - 		break;
 - 	case PXENV_START_BASE:
 - 		ret = pxenv_start_base ( &any->start_base );
 - 		break;
 - 	case PXENV_STOP_BASE:
 - 		ret = pxenv_stop_base ( &any->stop_base );
 - 		break;
 - 		
 - 	default:
 - 		DBG ( "PXENV_UNKNOWN_%hx", opcode );
 - 		any->Status = PXENV_STATUS_UNSUPPORTED;
 - 		ret = PXENV_EXIT_FAILURE;
 - 		break;
 - 	}
 - 
 - 	if ( any->Status != PXENV_STATUS_SUCCESS ) {
 - 		DBG ( " %hx", any->Status );
 - 	}
 - 	if ( ret != PXENV_EXIT_SUCCESS ) {
 - 		DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
 - 	}
 - 	DBG ( "]" );
 - 
 - 	return ret;
 - }
 
 
  |