Added pxe_netdev; a slight hack for now, but will need to be done
[people/xl0/gpxe.git] / src / interface / pxe / pxe.c
1 /** @file
2  *
3  * 
4  *
5  */
6
7 /*
8  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of the
13  * License, or any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #include "dev.h"
26 #include "pxe.h"
27
28 struct net_device *pxe_netdev = NULL;
29
30 #if 0
31
32 /* Global pointer to currently installed PXE stack */
33 pxe_stack_t *pxe_stack = NULL;
34
35 /* Various startup/shutdown routines.  The startup/shutdown call
36  * sequence is incredibly badly defined in the Intel PXE spec, for
37  * example:
38  *
39  *   PXENV_UNDI_INITIALIZE says that the parameters used to initialize
40  *   the adaptor should be those supplied to the most recent
41  *   PXENV_UNDI_STARTUP call.  PXENV_UNDI_STARTUP takes no parameters.
42  *
43  *   PXENV_UNDI_CLEANUP says that the rest of the API will not be
44  *   available after making this call.  Figure 3-3 ("Early UNDI API
45  *   usage") shows a call to PXENV_UNDI_CLEANUP being followed by a
46  *   call to the supposedly now unavailable PXENV_STOP_UNDI.
47  *
48  *   PXENV_UNLOAD_BASE_STACK talks about freeing up the memory
49  *   occupied by the PXE stack.  Figure 4-3 ("PXE IPL") shows a call
50  *   to PXENV_STOP_UNDI being made after the call to
51  *   PXENV_UNLOAD_BASE_STACK, by which time the entire PXE stack
52  *   should have been freed (and, potentially, zeroed).
53  *
54  *   Nothing, anywhere, seems to mention who's responsible for freeing
55  *   up the base memory allocated for the stack segment.  It's not
56  *   even clear whether or not this is expected to be in free base
57  *   memory rather than claimed base memory.
58  *
59  * Consequently, we adopt a rather defensive strategy, designed to
60  * work with any conceivable sequence of initialisation or shutdown
61  * calls.  We have only two things that we care about:
62  *
63  *   1. Have we hooked INT 1A and INT 15,E820(etc.)?
64  *   2. Is the NIC initialised?
65  *
66  * The NIC should never be initialised without the vectors being
67  * hooked, similarly the vectors should never be unhooked with the NIC
68  * still initialised.  We do, however, want to be able to have the
69  * vectors hooked with the NIC shutdown.  We therefore have three
70  * possible states:
71  *
72  *   1. Ready to unload: interrupts unhooked, NIC shutdown.
73  *   2. Midway: interrupts hooked, NIC shutdown.
74  *   3. Fully ready: interrupts hooked, NIC initialised.
75  *
76  * We provide the three states CAN_UNLOAD, MIDWAY and READY to define
77  * these, and the call pxe_ensure_state() to ensure that the stack is
78  * in the specified state.  All our PXE API call implementations
79  * should use this call to ensure that the state is as required for
80  * that PXE API call.  This enables us to cope with whatever the
81  * end-user's interpretation of the PXE spec may be.  It even allows
82  * for someone calling e.g. PXENV_START_UNDI followed by
83  * PXENV_UDP_WRITE, without bothering with any of the intervening
84  * calls.
85  *
86  * pxe_ensure_state() returns 1 for success, 0 for failure.  In the
87  * event of failure (which can arise from e.g. asking for state READY
88  * when we don't know where our NIC is), the error code
89  * PXENV_STATUS_UNDI_INVALID_STATE should be returned to the user.
90  * The macros ENSURE_XXX() can be used to achieve this without lots of
91  * duplicated code.
92  */
93
94 /* pxe_[un]hook_stack are architecture-specific and provided in
95  * pxe_callbacks.c
96  */
97
98 int pxe_initialise_nic ( void ) {
99         if ( pxe_stack->state >= READY ) return 1;
100
101 #warning "device probing mechanism has completely changed"
102 #if 0
103
104         /* Check if NIC is initialised.  dev.disable is set to 0
105          * when disable() is called, so we use this.
106          */
107         if ( dev.disable ) {
108                 /* NIC may have been initialised independently
109                  * (e.g. when we set up the stack prior to calling the
110                  * NBP).
111                  */
112                 pxe_stack->state = READY;
113                 return 1;
114         }
115
116         /* If we already have a NIC defined, reuse that one with
117          * PROBE_AWAKE.  If one was specifed via PXENV_START_UNDI, try
118          * that one first.  Otherwise, set PROBE_FIRST.
119          */
120
121         if ( dev.state.pci.dev.use_specified == 1 ) {
122                 dev.how_probe = PROBE_NEXT;
123                 DBG ( " initialising NIC specified via START_UNDI" );
124         } else if ( dev.state.pci.dev.driver ) {
125                 DBG ( " reinitialising NIC" );
126                 dev.how_probe = PROBE_AWAKE;
127         } else {
128                 DBG ( " probing for any NIC" );
129                 dev.how_probe = PROBE_FIRST;
130         }
131
132         /* Call probe routine to bring up the NIC */
133         if ( eth_probe ( &dev ) != PROBE_WORKED ) {
134                 DBG ( " failed" );
135                 return 0;
136         }
137 #endif
138         
139
140         pxe_stack->state = READY;
141         return 1;
142 }
143
144 int pxe_shutdown_nic ( void ) {
145         if ( pxe_stack->state <= MIDWAY ) return 1;
146
147         eth_irq ( DISABLE );
148         disable ( &dev );
149         pxe_stack->state = MIDWAY;
150         return 1;
151 }
152
153 int ensure_pxe_state ( pxe_stack_state_t wanted ) {
154         int success = 1;
155
156         if ( ! pxe_stack ) return 0;
157         if ( wanted >= MIDWAY )
158                 success = success & hook_pxe_stack();
159         if ( wanted > MIDWAY ) {
160                 success = success & pxe_initialise_nic();
161         } else {
162                 success = success & pxe_shutdown_nic();
163         }
164         if ( wanted < MIDWAY )
165                 success = success & unhook_pxe_stack();
166         return success;
167 }
168
169 #endif