Explorar el Código

Added PXE bus driver (with support only for using PXE structures found

lying about in memory, not for loading from ROM), and UNDI net driver.
tags/v0.9.3
Michael Brown hace 18 años
padre
commit
7e07dfb2f4
Se han modificado 3 ficheros con 735 adiciones y 27 borrados
  1. 305
    0
      src/arch/i386/drivers/bus/pxebus.c
  2. 385
    0
      src/arch/i386/drivers/net/undi_net.c
  3. 45
    27
      src/include/pxe.h

+ 305
- 0
src/arch/i386/drivers/bus/pxebus.c Ver fichero

@@ -0,0 +1,305 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <stdint.h>
20
+#include <stdlib.h>
21
+#include <string.h>
22
+#include <assert.h>
23
+#include <pxe.h>
24
+#include <realmode.h>
25
+#include <gpxe/device.h>
26
+
27
+/** @file
28
+ *
29
+ * PXE bus
30
+ *
31
+ */
32
+
33
+/**
34
+ * UNDI parameter block
35
+ *
36
+ * Used as the paramter block for all UNDI API calls.  Resides in base
37
+ * memory.
38
+ */
39
+static union u_PXENV_ANY __data16 ( pxe_params );
40
+#define pxe_params __use_data16 ( pxe_params )
41
+
42
+/** UNDI entry point */
43
+static SEGOFF16_t __data16 ( pxe_entry_point );
44
+#define pxe_entry_point __use_data16 ( pxe_entry_point )
45
+
46
+/**
47
+ * Issue PXE API call
48
+ *
49
+ * @v pxe		PXE device
50
+ * @v function		API call number
51
+ * @v params		PXE parameter block
52
+ * @v params_len	Length of PXE parameter block
53
+ * @ret rc		Return status code
54
+ */
55
+int pxe_call ( struct pxe_device *pxe, unsigned int function,
56
+	       void *params, size_t params_len ) {
57
+	union u_PXENV_ANY *pxenv_any = params;
58
+	PXENV_EXIT_t exit;
59
+	int discard_b, discard_D;
60
+	int rc;
61
+
62
+	/* Copy parameter block and entry point */
63
+	assert ( params_len <= sizeof ( pxe_params ) );
64
+	memcpy ( &pxe_params, params, params_len );
65
+	pxe_entry_point = pxe->entry;
66
+
67
+	/* Call real-mode entry point.  This calling convention will
68
+	 * work with both the !PXE and the PXENV+ entry points.
69
+	 */
70
+	__asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
71
+					   "pushw %%di\n\t"
72
+					   "pushw %%bx\n\t"
73
+					   "lcall *%c3\n\t"
74
+					   "addw $6, %%sp\n\t" )
75
+			       : "=a" ( exit ), "=b" ( discard_b ),
76
+			         "=D" ( discard_D )
77
+			       : "p" ( & __from_data16 ( pxe_entry_point ) ),
78
+			         "b" ( function ),
79
+			         "D" ( & __from_data16 ( pxe_params ) ) );
80
+
81
+	/* UNDI API calls may rudely change the status of A20 and not
82
+	 * bother to restore it afterwards.  Intel is known to be
83
+	 * guilty of this.
84
+	 *
85
+	 * Note that we will return to this point even if A20 gets
86
+	 * screwed up by the UNDI driver, because Etherboot always
87
+	 * resides in an even megabyte of RAM.
88
+	 */	
89
+	gateA20_set();
90
+
91
+	/* Copy parameter block back */
92
+	memcpy ( params, &pxe_params, params_len );
93
+
94
+	/* Determine return status code based on PXENV_EXIT and
95
+	 * PXENV_STATUS
96
+	 */
97
+	if ( exit == PXENV_EXIT_SUCCESS ) {
98
+		rc = 0;
99
+	} else {
100
+		rc = -pxenv_any->Status;
101
+		/* Paranoia; don't return success for the combination
102
+		 * of PXENV_EXIT_FAILURE but PXENV_STATUS_SUCCESS
103
+		 */
104
+		if ( rc == 0 )
105
+			rc = -EIO;
106
+	}
107
+
108
+	return rc;
109
+}
110
+
111
+/**
112
+ * Byte checksum
113
+ *
114
+ * @v data		Data to checksum
115
+ * @v len		Length of data
116
+ * @ret sum		Byte checksum
117
+ */
118
+static uint8_t checksum ( void *data, size_t len ) {
119
+	uint8_t *bytes = data;
120
+	unsigned int sum = 0;
121
+
122
+	while ( len-- )
123
+		sum += *(bytes++);
124
+
125
+	return sum;
126
+}
127
+
128
+/**
129
+ * Get PXE device information for an instantiated device
130
+ *
131
+ * @v pxe		PXE device
132
+ * @ret rc		Return status code
133
+ */
134
+static int pxedev_get_instance_info ( struct pxe_device *pxe ) {
135
+	struct s_PXENV pxenv;
136
+	struct s_PXE ppxe;
137
+	struct s_PXENV_UNDI_GET_INFORMATION undi_info;
138
+	int rc;
139
+
140
+	/* Determine entry point from PXENV+ structure */
141
+	DBGC ( pxe, "PXE %p has PXENV+ structure at %04x:%04x\n", pxe,
142
+	      pxe->pxenv.segment, pxe->pxenv.offset );
143
+	copy_from_real ( &pxenv, pxe->pxenv.segment, pxe->pxenv.offset,
144
+			 sizeof ( pxenv ) );
145
+	if ( checksum ( &pxenv, sizeof ( pxenv ) ) != 0 ) {
146
+		DBGC ( pxe, "PXE %p bad PXENV+ checksum\n", pxe );
147
+		return -EINVAL;
148
+	}
149
+	pxe->entry = pxenv.RMEntry;
150
+
151
+	/* If API version is 2.1 or greater, use the !PXE structure instead */
152
+	if ( pxenv.Version >= 0x0201 ) {
153
+		pxe->ppxe = pxenv.PXEPtr;
154
+		DBGC ( pxe, "PXE %p has !PXE structure at %04x:%04x\n", pxe,
155
+		       pxe->ppxe.segment, pxe->ppxe.offset );
156
+		copy_from_real ( &ppxe, pxe->ppxe.segment, pxe->ppxe.offset,
157
+				 sizeof ( ppxe ) );
158
+		if ( checksum ( &pxenv, sizeof ( pxenv ) ) != 0 ) {
159
+			DBGC ( pxe, "PXE %p bad !PXE checksum\n", pxe );
160
+			return -EINVAL;
161
+		}
162
+		pxe->entry = ppxe.EntryPointSP;
163
+	}
164
+
165
+	DBGC ( pxe, "PXE %p using entry point at %04x:%04x\n", pxe,
166
+	       pxe->entry.segment, pxe->entry.offset );
167
+
168
+	/* Get device information */
169
+	memset ( &undi_info, 0, sizeof ( undi_info ) );
170
+	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_GET_INFORMATION, &undi_info,
171
+			       sizeof ( undi_info ) ) ) != 0 ) {
172
+		DBGC ( pxe, "PXE %p could not retrieve UNDI information: %s\n",
173
+		       pxe, strerror ( rc ) );
174
+		return rc;
175
+	}
176
+	memcpy ( pxe->hwaddr, undi_info.PermNodeAddress,
177
+		 sizeof ( pxe->hwaddr ) );
178
+	pxe->irq = undi_info.IntNumber;
179
+	pxe->rom = undi_info.ROMAddress;
180
+
181
+	return 0;
182
+}
183
+
184
+/**
185
+ * Register PXE device
186
+ *
187
+ * @v pxe		PXE device
188
+ * @ret rc		Return status code
189
+ */
190
+static int register_pxedev ( struct pxe_device *pxe ) {
191
+	int rc;
192
+
193
+	DBGC ( pxe, "PXE %p registering\n", pxe );
194
+
195
+	/* Register as an UNDI driver */
196
+	if ( ( rc = undi_probe ( pxe ) ) != 0 )
197
+		return rc;
198
+
199
+	/* Add to device hierarchy and return */
200
+	list_add ( &pxe->dev.siblings, &pxe->dev.parent->children );
201
+	return 0;
202
+}
203
+
204
+/**
205
+ * Unregister a PXE device
206
+ *
207
+ * @v pxe		PXE device
208
+ *
209
+ */
210
+static void unregister_pxedev ( struct pxe_device *pxe ) {
211
+	undi_remove ( pxe );
212
+	list_del ( &pxe->dev.siblings );
213
+	DBGC ( pxe, "PXE %p unregistered\n", pxe );
214
+}
215
+
216
+static void pxebus_remove ( struct root_device *rootdev );
217
+
218
+/**
219
+ * Probe PXE root bus
220
+ *
221
+ * @v rootdev		PXE bus root device
222
+ *
223
+ * Scans the PXE bus for devices and registers all devices it can
224
+ * find.
225
+ */
226
+static int pxebus_probe ( struct root_device *rootdev ) {
227
+	struct pxe_device *pxe;
228
+	uint16_t signature;
229
+	uint16_t pxenv_segment;
230
+	uint16_t pxenv_offset;
231
+	int rc;
232
+
233
+	/* PXE installation check */
234
+	__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
235
+					   "int $0x1a\n\t"
236
+					   "jnc 1f\n\t"
237
+					   "xorw %%ax, %%ax\n\t"
238
+					   "\n1:\n\t"
239
+					   "movw %%es, %%dx\n\t" )
240
+			       : "=a" ( signature ), "=b" ( pxenv_offset ),
241
+			         "=d" ( pxenv_segment )
242
+			       : "a" ( 0x5650 ) );
243
+	if ( signature != 0x564e ) {
244
+		DBG ( "No pixies found\n" );
245
+		return 0;
246
+	}
247
+
248
+	/* Allocate PXE device structure */
249
+	pxe = malloc ( sizeof ( *pxe ) );
250
+	if ( ! pxe ) {
251
+		rc = -ENOMEM;
252
+		goto err;
253
+	}
254
+	memset ( pxe, 0, sizeof ( *pxe ) );
255
+
256
+	/* Populate PXE device structure */
257
+	pxe->pxenv.segment = pxenv_segment;
258
+	pxe->pxenv.offset = pxenv_offset;
259
+	INIT_LIST_HEAD ( &pxe->dev.children );
260
+	pxe->dev.parent = &rootdev->dev;
261
+	if ( ( rc = pxedev_get_instance_info ( pxe ) ) != 0 )
262
+		goto err;
263
+
264
+	/* Register PXE device */
265
+	if ( ( rc = register_pxedev ( pxe ) ) != 0 )
266
+		goto err;
267
+
268
+	return 0;
269
+
270
+ err:
271
+	free ( pxe );
272
+	pxebus_remove ( rootdev );
273
+	return rc;
274
+}
275
+
276
+/**
277
+ * Remove PXE root bus
278
+ *
279
+ * @v rootdev		PXE bus root device
280
+ */
281
+static void pxebus_remove ( struct root_device *rootdev ) {
282
+	struct pxe_device *pxe;
283
+	struct pxe_device *tmp;
284
+
285
+	list_for_each_entry_safe ( pxe, tmp, &rootdev->dev.children,
286
+				   dev.siblings ) {
287
+		unregister_pxedev ( pxe );
288
+		free ( pxe );
289
+	}
290
+}
291
+
292
+/** PXE bus root device driver */
293
+static struct root_driver pxe_root_driver = {
294
+	.probe = pxebus_probe,
295
+	.remove = pxebus_remove,
296
+};
297
+
298
+/** PXE bus root device */
299
+struct root_device pxe_root_device __root_device = {
300
+	.name = "PXE",
301
+	.driver = &pxe_root_driver,
302
+	.dev = {
303
+		.children = LIST_HEAD_INIT ( pxe_root_device.dev.children ),
304
+	},
305
+};

+ 385
- 0
src/arch/i386/drivers/net/undi_net.c Ver fichero

@@ -0,0 +1,385 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#include <string.h>
20
+#include <pxe.h>
21
+#include <realmode.h>
22
+#include <pic8259.h>
23
+#include <biosint.h>
24
+#include <gpxe/pkbuff.h>
25
+#include <gpxe/netdevice.h>
26
+#include <gpxe/if_ether.h>
27
+#include <gpxe/ethernet.h>
28
+
29
+/** @file
30
+ *
31
+ * UNDI network device driver
32
+ *
33
+ */
34
+
35
+/*****************************************************************************
36
+ *
37
+ * UNDI interrupt service routine
38
+ *
39
+ *****************************************************************************
40
+ */
41
+
42
+/**
43
+ * UNDI interrupt service routine
44
+ *
45
+ * The UNDI ISR simply increments a counter (@c trigger_count) and
46
+ * exits.
47
+ */
48
+extern void undi_isr ( void );
49
+
50
+/** Vector for chaining to other interrupts handlers */
51
+static struct segoff __text16 ( undi_isr_chain );
52
+#define undi_isr_chain __use_text16 ( undi_isr_chain )
53
+
54
+/** IRQ trigger count */
55
+static volatile uint16_t __text16 ( trigger_count );
56
+#define trigger_count __use_text16 ( trigger_count )
57
+
58
+/**
59
+ * Hook UNDI interrupt service routine
60
+ *
61
+ * @v irq		IRQ number
62
+ */
63
+static void undi_hook_isr ( unsigned int irq ) {
64
+	__asm__ __volatile__ ( TEXT16_CODE ( "\nundi_isr:\n\t"
65
+					     "incl %%cs:%c0\n\t"
66
+					     "ljmp *%%cs:%c1\n\t" )
67
+			       : : "p" ( & __from_text16 ( trigger_count ) ),
68
+			           "p" ( & __from_text16 ( undi_isr_chain ) ));
69
+
70
+	hook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
71
+			      &undi_isr_chain );
72
+
73
+}
74
+
75
+/**
76
+ * Unhook UNDI interrupt service routine
77
+ *
78
+ * @v irq		IRQ number
79
+ */
80
+static void undi_unhook_isr ( unsigned int irq ) {
81
+	unhook_bios_interrupt ( IRQ_INT ( irq ), ( ( unsigned int ) undi_isr ),
82
+				&undi_isr_chain );
83
+}
84
+
85
+/**
86
+ * Test to see if UNDI ISR has been triggered
87
+ *
88
+ * @ret triggered	ISR has been triggered since last check
89
+ */
90
+static int undi_isr_triggered ( void ) {
91
+	static unsigned int last_trigger_count;
92
+	unsigned int this_trigger_count;
93
+
94
+	/* Read trigger_count.  Do this only once; it is volatile */
95
+	this_trigger_count = trigger_count;
96
+
97
+	if ( this_trigger_count == last_trigger_count ) {
98
+		/* Not triggered */
99
+		return 0;
100
+	} else {
101
+		/* Triggered */
102
+		last_trigger_count = this_trigger_count;
103
+		return 1;
104
+	}
105
+}
106
+
107
+/*****************************************************************************
108
+ *
109
+ * UNDI network device interface
110
+ *
111
+ *****************************************************************************
112
+ */
113
+
114
+/** Maximum length of a packet transmitted via the UNDI API */
115
+#define UNDI_PKB_LEN 1514
116
+
117
+/** A packet transmitted via the UNDI API */
118
+struct undi_packet {
119
+	uint8_t bytes[UNDI_PKB_LEN];
120
+};
121
+
122
+/** UNDI packet buffer */
123
+static struct undi_packet __data16 ( undi_pkb );
124
+#define undi_pkb __use_data16 ( undi_pkb )
125
+
126
+/** UNDI transmit buffer descriptor */
127
+static struct s_PXENV_UNDI_TBD __data16 ( undi_tbd );
128
+#define undi_tbd __use_data16 ( undi_tbd )
129
+
130
+/**
131
+ * Transmit packet
132
+ *
133
+ * @v netdev		Network device
134
+ * @v pkb		Packet buffer
135
+ * @ret rc		Return status code
136
+ */
137
+static int undi_transmit ( struct net_device *netdev, struct pk_buff *pkb ) {
138
+	struct pxe_device *pxe = netdev->priv;
139
+	struct s_PXENV_UNDI_TRANSMIT undi_transmit;
140
+	size_t len = pkb_len ( pkb );
141
+	int rc;
142
+
143
+	/* Copy packet to UNDI packet buffer */
144
+	if ( len > sizeof ( undi_pkb ) )
145
+		len = sizeof ( undi_pkb );
146
+	memcpy ( &undi_pkb, pkb->data, len );
147
+
148
+	/* Create PXENV_UNDI_TRANSMIT data structure */
149
+	memset ( &undi_transmit, 0, sizeof ( undi_transmit ) );
150
+	undi_transmit.DestAddr.segment = rm_ds;
151
+	undi_transmit.DestAddr.offset
152
+		= ( ( unsigned ) & __from_data16 ( undi_tbd ) );
153
+	undi_transmit.TBD.segment = rm_ds;
154
+	undi_transmit.TBD.offset
155
+		= ( ( unsigned ) & __from_data16 ( undi_tbd ) );
156
+
157
+	/* Create PXENV_UNDI_TBD data structure */
158
+	undi_tbd.ImmedLength = len;
159
+	undi_tbd.Xmit.segment = rm_ds;
160
+	undi_tbd.Xmit.offset 
161
+		= ( ( unsigned ) & __from_data16 ( undi_pkb ) );
162
+
163
+	/* Issue PXE API call */
164
+	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_TRANSMIT, &undi_transmit,
165
+			       sizeof ( undi_transmit ) ) ) != 0 ) {
166
+		DBG ( "UNDI_TRANSMIT failed: %s\n", strerror ( rc ) );
167
+	}
168
+
169
+	/* Free packet buffer and return */
170
+	free_pkb ( pkb );
171
+	return rc;
172
+}
173
+
174
+/** 
175
+ * Poll for received packets
176
+ *
177
+ * @v netdev	Network device
178
+ *
179
+ * Fun, fun, fun.  UNDI drivers don't use polling; they use
180
+ * interrupts.  We therefore cheat and pretend that an interrupt has
181
+ * occurred every time undi_poll() is called.  This isn't too much of
182
+ * a hack; PCI devices share IRQs and so the first thing that a proper
183
+ * ISR should do is call PXENV_UNDI_ISR to determine whether or not
184
+ * the UNDI NIC generated the interrupt; there is no harm done by
185
+ * spurious calls to PXENV_UNDI_ISR.  Similarly, we wouldn't be
186
+ * handling them any more rapidly than the usual rate of undi_poll()
187
+ * being called even if we did implement a full ISR.  So it should
188
+ * work.  Ha!
189
+ *
190
+ * Addendum (21/10/03).  Some cards don't play nicely with this trick,
191
+ * so instead of doing it the easy way we have to go to all the hassle
192
+ * of installing a genuine interrupt service routine and dealing with
193
+ * the wonderful 8259 Programmable Interrupt Controller.  Joy.
194
+ */
195
+static void undi_poll ( struct net_device *netdev ) {
196
+	struct pxe_device *pxe = netdev->priv;
197
+	struct s_PXENV_UNDI_ISR undi_isr;
198
+	struct pk_buff *pkb = NULL;
199
+	size_t len;
200
+	size_t frag_len;
201
+	int rc;
202
+
203
+	/* Do nothing unless ISR has been triggered */
204
+	if ( ! undi_isr_triggered() )
205
+		return;
206
+
207
+	/* See if this was our interrupt */
208
+	memset ( &undi_isr, 0, sizeof ( undi_isr ) );
209
+	undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
210
+	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_ISR, &undi_isr,
211
+			       sizeof ( undi_isr ) ) ) != 0 ) {
212
+		DBG ( "UNDI_ISR (START) failed: %s\n", strerror ( rc ) );
213
+		return;
214
+	}
215
+	if ( undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_OURS )
216
+		return;
217
+
218
+	/* Send EOI */
219
+	send_eoi ( pxe->irq );
220
+
221
+	/* Run through the ISR loop */
222
+	undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
223
+	while ( 1 ) {
224
+		if ( ( rc = pxe_call ( pxe, PXENV_UNDI_ISR, &undi_isr,
225
+				       sizeof ( undi_isr ) ) ) != 0 ) {
226
+			DBG ( "UNDI_ISR (PROCESS/GET_NEXT) failed: %s\n",
227
+			      strerror ( rc ) );
228
+			break;
229
+		}
230
+		switch ( undi_isr.FuncFlag ) {
231
+		case PXENV_UNDI_ISR_OUT_TRANSMIT:
232
+			/* We don't care about transmit completions */
233
+			break;
234
+		case PXENV_UNDI_ISR_OUT_RECEIVE:
235
+			/* Packet fragment received */
236
+			len = undi_isr.FrameLength;
237
+			frag_len = undi_isr.BufferLength;
238
+			if ( ! pkb )
239
+				pkb = alloc_pkb ( len );
240
+			if ( ! pkb ) {
241
+				DBG ( "UNDI could not allocate %zd bytes for "
242
+				      "receive buffer\n", len );
243
+				break;
244
+			}
245
+			if ( frag_len > pkb_available ( pkb ) ) {
246
+				DBG ( "UNDI fragment too large\n" );
247
+				frag_len = pkb_available ( pkb );
248
+			}
249
+			copy_from_real ( pkb_put ( pkb, frag_len ),
250
+					 undi_isr.Frame.segment,
251
+					 undi_isr.Frame.offset, frag_len );
252
+			if ( pkb_len ( pkb ) == len ) {
253
+				netdev_rx ( netdev, pkb );
254
+				pkb = NULL;
255
+			}
256
+			break;
257
+		case PXENV_UNDI_ISR_OUT_DONE:
258
+			/* Processing complete */
259
+			goto done;
260
+		default:
261
+			/* Should never happen */
262
+			DBG ( "UNDI ISR returned invalid FuncFlag %04x\n",
263
+			      undi_isr.FuncFlag );
264
+			goto done;
265
+		}
266
+		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
267
+	}
268
+
269
+ done:
270
+	if ( pkb ) {
271
+		DBG ( "UNDI returned incomplete packet\n" );
272
+		netdev_rx ( netdev, pkb );
273
+	}
274
+}
275
+
276
+/**
277
+ * Open NIC
278
+ *
279
+ * @v netdev		Net device
280
+ * @ret rc		Return status code
281
+ */
282
+static int undi_open ( struct net_device *netdev ) {
283
+	struct pxe_device *pxe = netdev->priv;
284
+	struct s_PXENV_UNDI_SET_STATION_ADDRESS set_address;
285
+	struct s_PXENV_UNDI_OPEN open;
286
+	int rc;
287
+
288
+	/* Hook interrupt service routine */
289
+	undi_hook_isr ( pxe->irq );
290
+
291
+	/* Set station address.  Required for some PXE stacks; will
292
+	 * spuriously fail on others.  Ignore failures.  We only ever
293
+	 * use it to set the MAC address to the card's permanent value
294
+	 * anyway.
295
+	 */
296
+	memcpy ( set_address.StationAddress, netdev->ll_addr,
297
+		 sizeof ( set_address.StationAddress ) );
298
+	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_SET_STATION_ADDRESS,
299
+			       &set_address, sizeof ( set_address ) ) ) != 0 ){
300
+		DBG ( "UNDI_SET_STATION_ADDRESS failed: %s\n",
301
+		      strerror ( rc ) );
302
+	}
303
+
304
+	/* Open NIC */
305
+	memset ( &open, 0, sizeof ( open ) );
306
+	open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST );
307
+	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_OPEN, &open,
308
+			       sizeof ( open ) ) ) != 0 ) {
309
+		DBG ( "UNDI_OPEN failed: %s\n", strerror ( rc ) );
310
+		return rc;
311
+	}
312
+
313
+	return 0;
314
+}
315
+
316
+/**
317
+ * Close NIC
318
+ *
319
+ * @v netdev		Net device
320
+ */
321
+static void undi_close ( struct net_device *netdev ) {
322
+	struct pxe_device *pxe = netdev->priv;
323
+	struct s_PXENV_UNDI_CLOSE close;
324
+	int rc;
325
+
326
+	/* Close NIC */
327
+	if ( ( rc = pxe_call ( pxe, PXENV_UNDI_CLOSE, &close,
328
+			       sizeof ( close ) ) ) != 0 ) {
329
+		DBG ( "UNDI_CLOSE failed: %s\n", strerror ( rc ) );
330
+	}
331
+
332
+	/* Unhook ISR */
333
+	undi_unhook_isr ( pxe->irq );
334
+}
335
+
336
+/**
337
+ * Probe PXE device
338
+ *
339
+ * @v pxe		PXE device
340
+ * @ret rc		Return status code
341
+ */
342
+int undi_probe ( struct pxe_device *pxe ) {
343
+	struct net_device *netdev;
344
+	int rc;
345
+
346
+	/* Allocate net device */
347
+	netdev = alloc_etherdev ( 0 );
348
+	if ( ! netdev ) {
349
+		rc = -ENOMEM;
350
+		goto err;
351
+	}
352
+	netdev->priv = pxe;
353
+	pxe_set_drvdata ( pxe, netdev );
354
+
355
+	/* Fill in NIC information */
356
+	memcpy ( netdev->ll_addr, pxe->hwaddr, ETH_ALEN );
357
+
358
+	/* Point to NIC specific routines */
359
+	netdev->open	 = undi_open;
360
+	netdev->close	 = undi_close;
361
+	netdev->transmit = undi_transmit;
362
+	netdev->poll	 = undi_poll;
363
+
364
+	/* Register network device */
365
+	if ( ( rc = register_netdev ( netdev ) ) != 0 )
366
+		goto err;
367
+
368
+	return 0;
369
+
370
+ err:
371
+	free_netdev ( netdev );
372
+	return rc;
373
+}
374
+
375
+/**
376
+ * Remove PXE device
377
+ *
378
+ * @v pxe		PXE device
379
+ */
380
+void undi_remove ( struct pxe_device *pxe ) {
381
+	struct net_device *netdev = pxe_get_drvdata ( pxe );
382
+
383
+	unregister_netdev ( netdev );
384
+	free_netdev ( netdev );
385
+}

+ 45
- 27
src/include/pxe.h Ver fichero

@@ -3,6 +3,7 @@
3 3
 
4 4
 #include "pxe_types.h"
5 5
 #include "pxe_api.h"
6
+#include <gpxe/device.h>
6 7
 
7 8
 /* Parameter block for pxenv_unknown() */
8 9
 struct s_PXENV_UNKNOWN {
@@ -61,38 +62,55 @@ union u_PXENV_ANY {
61 62
 
62 63
 typedef union u_PXENV_ANY PXENV_ANY_t;
63 64
 
64
-/* PXE stack status indicator.  See pxe_export.c for further
65
- * explanation.
66
- */
67
-typedef enum {
68
-	CAN_UNLOAD = 0,
69
-	MIDWAY,
70
-	READY
71
-} pxe_stack_state_t;
65
+/** A PXE device */
66
+struct pxe_device {
67
+	/** Generic device */
68
+	struct device dev;
69
+	/** Driver-private data
70
+	 *
71
+	 * Use pxe_set_drvdata() and pxe_get_drvdata() to access this
72
+	 * field.
73
+	 */
74
+	void *priv;
72 75
 
73
-#define ENSURE_CAN_UNLOAD(structure) if ( ! ensure_pxe_state(CAN_UNLOAD) ) { \
74
-			structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
75
-			return PXENV_EXIT_FAILURE; }
76
-#define ENSURE_MIDWAY(structure) if ( ! ensure_pxe_state(MIDWAY) ) { \
77
-			structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
78
-			return PXENV_EXIT_FAILURE; }
79
-#define ENSURE_READY(structure) if ( ! ensure_pxe_state(READY) ) { \
80
-			structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
81
-			return PXENV_EXIT_FAILURE; }
76
+	/** PXENV+ structure address */
77
+	SEGOFF16_t pxenv;
78
+	/** !PXE structure address */
79
+	SEGOFF16_t ppxe;
80
+	/** Entry point */
81
+	SEGOFF16_t entry;
82
+	/** MAC address */
83
+	MAC_ADDR_t hwaddr;
84
+	/** Assigned IRQ number */
85
+	UINT16_t irq;
86
+	/** ROM address */
87
+	SEGSEL_t rom;
88
+};
82 89
 
83
-/* Data structures installed as part of a PXE stack.  Architectures
84
- * will have extra information to append to the end of this.
90
+/**
91
+ * Set PXE driver-private data
92
+ *
93
+ * @v pxe		PXE device
94
+ * @v priv		Private data
85 95
  */
86
-#define PXE_TFTP_MAGIC_COOKIE ( ( 'P'<<24 ) | ( 'x'<<16 ) | ( 'T'<<8 ) | 'f' )
87
-typedef struct pxe_stack {
88
-	struct s_PXE		pxe	__attribute__ ((aligned(16)));
89
-	struct s_PXENV		pxenv	__attribute__ ((aligned(16)));
90
-	pxe_stack_state_t	state;
91
-} pxe_stack_t;
96
+static inline void pxe_set_drvdata ( struct pxe_device *pxe, void *priv ) {
97
+	pxe->priv = priv;
98
+}
92 99
 
93
-extern int ensure_pxe_state ( pxe_stack_state_t wanted );
100
+/**
101
+ * Get PXE driver-private data
102
+ *
103
+ * @v pxe		PXE device
104
+ * @ret priv		Private data
105
+ */
106
+static inline void * pxe_get_drvdata ( struct pxe_device *pxe ) {
107
+	return pxe->priv;
108
+}
94 109
 
95
-extern pxe_stack_t *pxe_stack;
110
+extern int pxe_call ( struct pxe_device *pxe, unsigned int function,
111
+		      void *params, size_t params_len );
112
+extern int undi_probe ( struct pxe_device *pxe );
113
+extern void undi_remove ( struct pxe_device *pxe );
96 114
 
97 115
 extern struct net_device *pxe_netdev;
98 116
 

Loading…
Cancelar
Guardar