#include <string.h>
#include <pxe.h>
#include <realmode.h>
#include <pic8259.h>
#include <biosint.h>
#include <pnpbios.h>
#include <basemem_packet.h>
#include <gpxe/io.h>
#include <gpxe/iobuf.h>
#include <gpxe/netdevice.h>
#include <gpxe/if_ether.h>
#include <gpxe/ethernet.h>
#include <undi.h>
#include <undinet.h>
#include <pxeparent.h>
Go to the source code of this file.
Data Structures | |
| struct | undi_nic |
| An UNDI NIC. More... | |
Defines | |
| #define | UNDI_HACK_EB54 0x0001 |
| Work around Etherboot 5.4 bugs. | |
| #define | undiisr_irq __use_data16 ( undiisr_irq ) |
| #define | undiisr_next_handler __use_data16 ( undiisr_next_handler ) |
| #define | undiisr_trigger_count __use_data16 ( undiisr_trigger_count ) |
| #define | undinet_tbd __use_data16 ( undinet_tbd ) |
Functions | |
| FILE_LICENCE (GPL2_OR_LATER) | |
| static void | undinet_close (struct net_device *netdev) |
| Close NIC. | |
| void | undiisr (void) |
| UNDI interrupt service routine. | |
| uint8_t | __data16 (undiisr_irq) |
| IRQ number. | |
| struct segoff | __data16 (undiisr_next_handler) |
| IRQ chain vector. | |
| volatile uint8_t | __data16 (undiisr_trigger_count)=0 |
| IRQ trigger count. | |
| static void | undinet_hook_isr (unsigned int irq) |
| Hook UNDI interrupt service routine. | |
| static void | undinet_unhook_isr (unsigned int irq) |
| Unhook UNDI interrupt service routine. | |
| static int | undinet_isr_triggered (void) |
| Test to see if UNDI ISR has been triggered. | |
| static struct s_PXENV_UNDI_TBD | __data16 (undinet_tbd) |
| UNDI transmit buffer descriptor. | |
| static int | undinet_transmit (struct net_device *netdev, struct io_buffer *iobuf) |
| Transmit packet. | |
| static void | undinet_poll (struct net_device *netdev) |
| Poll for received packets. | |
| static int | undinet_open (struct net_device *netdev) |
| Open NIC. | |
| static void | undinet_irq (struct net_device *netdev, int enable) |
| Enable/disable interrupts. | |
| int | undinet_probe (struct undi_device *undi) |
| Probe UNDI device. | |
| void | undinet_remove (struct undi_device *undi) |
| Remove UNDI device. | |
Variables | |
| static SEGOFF16_t | undinet_entry |
| Address of UNDI entry point. | |
| static unsigned int | last_trigger_count = 0 |
| Last observed trigger count. | |
| static struct net_device_operations | undinet_operations |
| UNDI network device operations. | |
Definition in file undinet.c.
| #define undiisr_irq __use_data16 ( undiisr_irq ) |
Definition at line 85 of file undinet.c.
Referenced by undinet_hook_isr(), and undinet_unhook_isr().
| #define undiisr_next_handler __use_data16 ( undiisr_next_handler ) |
Definition at line 89 of file undinet.c.
Referenced by undinet_hook_isr(), and undinet_unhook_isr().
| #define undiisr_trigger_count __use_data16 ( undiisr_trigger_count ) |
| #define undinet_tbd __use_data16 ( undinet_tbd ) |
| FILE_LICENCE | ( | GPL2_OR_LATER | ) |
| static void undinet_close | ( | struct net_device * | netdev | ) | [static] |
Close NIC.
| netdev | Net device |
Definition at line 399 of file undinet.c.
References DBGC, disable_irq, s_PXENV_UNDI_ISR::FuncFlag, undi_nic::irq, undi_nic::isr_processing, net_device::priv, PXENV_UNDI_CLOSE, PXENV_UNDI_ISR, PXENV_UNDI_ISR_IN_GET_NEXT, PXENV_UNDI_ISR_OUT_RECEIVE, PXENV_UNDI_ISR_OUT_TRANSMIT, pxeparent_call(), and undinet_unhook_isr().
Referenced by undinet_open().
00399 { 00400 struct undi_nic *undinic = netdev->priv; 00401 struct s_PXENV_UNDI_ISR undi_isr; 00402 struct s_PXENV_UNDI_CLOSE undi_close; 00403 int rc; 00404 00405 /* Ensure ISR has exited cleanly */ 00406 while ( undinic->isr_processing ) { 00407 undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; 00408 if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR, 00409 &undi_isr, 00410 sizeof ( undi_isr ) ) ) != 0 ) 00411 break; 00412 switch ( undi_isr.FuncFlag ) { 00413 case PXENV_UNDI_ISR_OUT_TRANSMIT: 00414 case PXENV_UNDI_ISR_OUT_RECEIVE: 00415 /* Continue draining */ 00416 break; 00417 default: 00418 /* Stop processing */ 00419 undinic->isr_processing = 0; 00420 break; 00421 } 00422 } 00423 00424 /* Close NIC */ 00425 pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE, 00426 &undi_close, sizeof ( undi_close ) ); 00427 00428 /* Disable interrupt and unhook ISR */ 00429 disable_irq ( undinic->irq ); 00430 undinet_unhook_isr ( undinic->irq ); 00431 00432 DBGC ( undinic, "UNDINIC %p closed\n", undinic ); 00433 }
| void undiisr | ( | void | ) |
UNDI interrupt service routine.
The UNDI ISR increments a counter (trigger_count) and exits.
Referenced by undinet_hook_isr(), and undinet_unhook_isr().
| uint8_t __data16 | ( | undiisr_irq | ) |
IRQ number.
| struct segoff __data16 | ( | undiisr_next_handler | ) | [read] |
IRQ chain vector.
| volatile uint8_t __data16 | ( | undiisr_trigger_count | ) | [pure virtual] |
IRQ trigger count.
| static void undinet_hook_isr | ( | unsigned int | irq | ) | [static] |
Hook UNDI interrupt service routine.
| irq | IRQ number |
Definition at line 103 of file undinet.c.
References assert, hook_bios_interrupt(), IRQ_INT, IRQ_MAX, undiisr(), undiisr_irq, and undiisr_next_handler.
Referenced by undinet_open().
00103 { 00104 00105 assert ( irq <= IRQ_MAX ); 00106 assert ( undiisr_irq == 0 ); 00107 00108 undiisr_irq = irq; 00109 hook_bios_interrupt ( IRQ_INT ( irq ), 00110 ( ( unsigned int ) undiisr ), 00111 &undiisr_next_handler ); 00112 }
| static void undinet_unhook_isr | ( | unsigned int | irq | ) | [static] |
Unhook UNDI interrupt service routine.
| irq | IRQ number |
Definition at line 119 of file undinet.c.
References assert, IRQ_INT, IRQ_MAX, undiisr(), undiisr_irq, undiisr_next_handler, and unhook_bios_interrupt().
Referenced by undinet_close().
00119 { 00120 00121 assert ( irq <= IRQ_MAX ); 00122 00123 unhook_bios_interrupt ( IRQ_INT ( irq ), 00124 ( ( unsigned int ) undiisr ), 00125 &undiisr_next_handler ); 00126 undiisr_irq = 0; 00127 }
| static int undinet_isr_triggered | ( | void | ) | [static] |
Test to see if UNDI ISR has been triggered.
| triggered | ISR has been triggered since last check |
Definition at line 134 of file undinet.c.
References last_trigger_count, and undiisr_trigger_count.
Referenced by undinet_poll().
00134 { 00135 unsigned int this_trigger_count; 00136 00137 /* Read trigger_count. Do this only once; it is volatile */ 00138 this_trigger_count = undiisr_trigger_count; 00139 00140 if ( this_trigger_count == last_trigger_count ) { 00141 /* Not triggered */ 00142 return 0; 00143 } else { 00144 /* Triggered */ 00145 last_trigger_count = this_trigger_count; 00146 return 1; 00147 } 00148 }
| static struct s_PXENV_UNDI_TBD __data16 | ( | undinet_tbd | ) | [static, read] |
UNDI transmit buffer descriptor.
| static int undinet_transmit | ( | struct net_device * | netdev, | |
| struct io_buffer * | iobuf | |||
| ) | [static] |
Transmit packet.
| netdev | Network device | |
| iobuf | I/O buffer |
| rc | Return status code |
Definition at line 168 of file undinet.c.
References __from_data16, basemem_packet, io_buffer::data, s_PXENV_UNDI_TRANSMIT::DestAddr, iob_len(), memcpy, memset(), netdev_tx_complete(), s_SEGOFF16::offset, PXENV_UNDI_TRANSMIT, pxeparent_call(), rm_ds, s_SEGOFF16::segment, s_PXENV_UNDI_TRANSMIT::TBD, and undinet_tbd.
00169 { 00170 struct s_PXENV_UNDI_TRANSMIT undi_transmit; 00171 size_t len = iob_len ( iobuf ); 00172 int rc; 00173 00174 /* Technically, we ought to make sure that the previous 00175 * transmission has completed before we re-use the buffer. 00176 * However, many PXE stacks (including at least some Intel PXE 00177 * stacks and Etherboot 5.4) fail to generate TX completions. 00178 * In practice this won't be a problem, since our TX datapath 00179 * has a very low packet volume and we can get away with 00180 * assuming that a TX will be complete by the time we want to 00181 * transmit the next packet. 00182 */ 00183 00184 /* Copy packet to UNDI I/O buffer */ 00185 if ( len > sizeof ( basemem_packet ) ) 00186 len = sizeof ( basemem_packet ); 00187 memcpy ( &basemem_packet, iobuf->data, len ); 00188 00189 /* Create PXENV_UNDI_TRANSMIT data structure */ 00190 memset ( &undi_transmit, 0, sizeof ( undi_transmit ) ); 00191 undi_transmit.DestAddr.segment = rm_ds; 00192 undi_transmit.DestAddr.offset = __from_data16 ( &undinet_tbd ); 00193 undi_transmit.TBD.segment = rm_ds; 00194 undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd ); 00195 00196 /* Create PXENV_UNDI_TBD data structure */ 00197 undinet_tbd.ImmedLength = len; 00198 undinet_tbd.Xmit.segment = rm_ds; 00199 undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet ); 00200 00201 /* Issue PXE API call */ 00202 if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_TRANSMIT, 00203 &undi_transmit, 00204 sizeof ( undi_transmit ) ) ) != 0 ) 00205 goto done; 00206 00207 /* Free I/O buffer */ 00208 netdev_tx_complete ( netdev, iobuf ); 00209 00210 done: 00211 return rc; 00212 }
| static void undinet_poll | ( | struct net_device * | netdev | ) | [static] |
Poll for received packets.
| netdev | Network device |
Addendum (21/10/03). Some cards don't play nicely with this trick, so instead of doing it the easy way we have to go to all the hassle of installing a genuine interrupt service routine and dealing with the wonderful 8259 Programmable Interrupt Controller. Joy.
Addendum (10/07/07). When doing things such as iSCSI boot, in which we have to co-operate with a running OS, we can't get away with the "ISR-just-increments-a-counter-and-returns" trick at all, because it involves tying up the PIC for far too long, and other interrupt-dependent components (e.g. local disks) start breaking. We therefore implement a "proper" ISR which calls PXENV_UNDI_ISR from within interrupt context in order to deassert the device interrupt, and sends EOI if applicable.
Definition at line 244 of file undinet.c.
References __asm__(), alloc_iob(), s_PXENV_UNDI_ISR::BufferLength, copy_from_real, DBGC, EINVAL, ENOMEM, s_PXENV_UNDI_ISR::Frame, s_PXENV_UNDI_ISR::FrameLength, s_PXENV_UNDI_ISR::FuncFlag, undi_nic::hacks, iob_disown, iob_len(), iob_put, iob_tailroom(), undi_nic::isr_processing, last_trigger_count, netdev_rx(), netdev_rx_err(), NULL, s_SEGOFF16::offset, net_device::priv, PXENV_UNDI_ISR, PXENV_UNDI_ISR_IN_GET_NEXT, PXENV_UNDI_ISR_IN_PROCESS, PXENV_UNDI_ISR_OUT_DONE, PXENV_UNDI_ISR_OUT_RECEIVE, PXENV_UNDI_ISR_OUT_TRANSMIT, pxeparent_call(), REAL_CODE, s_SEGOFF16::segment, UNDI_HACK_EB54, and undinet_isr_triggered().
00244 { 00245 struct undi_nic *undinic = netdev->priv; 00246 struct s_PXENV_UNDI_ISR undi_isr; 00247 struct io_buffer *iobuf = NULL; 00248 size_t len; 00249 size_t frag_len; 00250 size_t max_frag_len; 00251 int rc; 00252 00253 if ( ! undinic->isr_processing ) { 00254 /* Do nothing unless ISR has been triggered */ 00255 if ( ! undinet_isr_triggered() ) { 00256 /* Allow interrupt to occur */ 00257 __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" 00258 "nop\n\t" 00259 "nop\n\t" 00260 "cli\n\t" ) : : ); 00261 return; 00262 } 00263 00264 /* Start ISR processing */ 00265 undinic->isr_processing = 1; 00266 undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS; 00267 } else { 00268 /* Continue ISR processing */ 00269 undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; 00270 } 00271 00272 /* Run through the ISR loop */ 00273 while ( 1 ) { 00274 if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR, 00275 &undi_isr, 00276 sizeof ( undi_isr ) ) ) != 0 ) 00277 break; 00278 switch ( undi_isr.FuncFlag ) { 00279 case PXENV_UNDI_ISR_OUT_TRANSMIT: 00280 /* We don't care about transmit completions */ 00281 break; 00282 case PXENV_UNDI_ISR_OUT_RECEIVE: 00283 /* Packet fragment received */ 00284 len = undi_isr.FrameLength; 00285 frag_len = undi_isr.BufferLength; 00286 if ( ( len == 0 ) || ( len < frag_len ) ) { 00287 /* Don't laugh. VMWare does it. */ 00288 DBGC ( undinic, "UNDINIC %p reported insane " 00289 "fragment (%zd of %zd bytes)\n", 00290 undinic, frag_len, len ); 00291 netdev_rx_err ( netdev, NULL, -EINVAL ); 00292 break; 00293 } 00294 if ( ! iobuf ) 00295 iobuf = alloc_iob ( len ); 00296 if ( ! iobuf ) { 00297 DBGC ( undinic, "UNDINIC %p could not " 00298 "allocate %zd bytes for RX buffer\n", 00299 undinic, len ); 00300 /* Fragment will be dropped */ 00301 netdev_rx_err ( netdev, NULL, -ENOMEM ); 00302 goto done; 00303 } 00304 max_frag_len = iob_tailroom ( iobuf ); 00305 if ( frag_len > max_frag_len ) { 00306 DBGC ( undinic, "UNDINIC %p fragment too big " 00307 "(%zd+%zd does not fit into %zd)\n", 00308 undinic, iob_len ( iobuf ), frag_len, 00309 ( iob_len ( iobuf ) + max_frag_len ) ); 00310 frag_len = max_frag_len; 00311 } 00312 copy_from_real ( iob_put ( iobuf, frag_len ), 00313 undi_isr.Frame.segment, 00314 undi_isr.Frame.offset, frag_len ); 00315 if ( iob_len ( iobuf ) == len ) { 00316 /* Whole packet received; deliver it */ 00317 netdev_rx ( netdev, iob_disown ( iobuf ) ); 00318 /* Etherboot 5.4 fails to return all packets 00319 * under mild load; pretend it retriggered. 00320 */ 00321 if ( undinic->hacks & UNDI_HACK_EB54 ) 00322 --last_trigger_count; 00323 } 00324 break; 00325 case PXENV_UNDI_ISR_OUT_DONE: 00326 /* Processing complete */ 00327 undinic->isr_processing = 0; 00328 goto done; 00329 default: 00330 /* Should never happen. VMWare does it routinely. */ 00331 DBGC ( undinic, "UNDINIC %p ISR returned invalid " 00332 "FuncFlag %04x\n", undinic, undi_isr.FuncFlag ); 00333 undinic->isr_processing = 0; 00334 goto done; 00335 } 00336 undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT; 00337 } 00338 00339 done: 00340 if ( iobuf ) { 00341 DBGC ( undinic, "UNDINIC %p returned incomplete packet " 00342 "(%zd of %zd)\n", undinic, iob_len ( iobuf ), 00343 ( iob_len ( iobuf ) + iob_tailroom ( iobuf ) ) ); 00344 netdev_rx_err ( netdev, iobuf, -EINVAL ); 00345 } 00346 }
| static int undinet_open | ( | struct net_device * | netdev | ) | [static] |
Open NIC.
| netdev | Net device |
| rc | Return status code |
Definition at line 354 of file undinet.c.
References DBGC, enable_irq, FLTR_BRDCST, FLTR_DIRECTED, FLTR_PRMSCS, undi_nic::irq, net_device::ll_addr, memcpy, memset(), s_PXENV_UNDI_OPEN::PktFilter, net_device::priv, PXENV_UNDI_OPEN, PXENV_UNDI_SET_STATION_ADDRESS, pxeparent_call(), send_eoi(), s_PXENV_UNDI_SET_STATION_ADDRESS::StationAddress, undinet_close(), and undinet_hook_isr().
00354 { 00355 struct undi_nic *undinic = netdev->priv; 00356 struct s_PXENV_UNDI_SET_STATION_ADDRESS undi_set_address; 00357 struct s_PXENV_UNDI_OPEN undi_open; 00358 int rc; 00359 00360 /* Hook interrupt service routine and enable interrupt */ 00361 undinet_hook_isr ( undinic->irq ); 00362 enable_irq ( undinic->irq ); 00363 send_eoi ( undinic->irq ); 00364 00365 /* Set station address. Required for some PXE stacks; will 00366 * spuriously fail on others. Ignore failures. We only ever 00367 * use it to set the MAC address to the card's permanent value 00368 * anyway. 00369 */ 00370 memcpy ( undi_set_address.StationAddress, netdev->ll_addr, 00371 sizeof ( undi_set_address.StationAddress ) ); 00372 pxeparent_call ( undinet_entry, PXENV_UNDI_SET_STATION_ADDRESS, 00373 &undi_set_address, sizeof ( undi_set_address ) ); 00374 00375 /* Open NIC. We ask for promiscuous operation, since it's the 00376 * only way to ask for all multicast addresses. On any 00377 * switched network, it shouldn't really make a difference to 00378 * performance. 00379 */ 00380 memset ( &undi_open, 0, sizeof ( undi_open ) ); 00381 undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS ); 00382 if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_OPEN, 00383 &undi_open, sizeof ( undi_open ) ) ) != 0 ) 00384 goto err; 00385 00386 DBGC ( undinic, "UNDINIC %p opened\n", undinic ); 00387 return 0; 00388 00389 err: 00390 undinet_close ( netdev ); 00391 return rc; 00392 }
| static void undinet_irq | ( | struct net_device * | netdev, | |
| int | enable | |||
| ) | [static] |
Enable/disable interrupts.
| netdev | Net device | |
| enable | Interrupts should be enabled |
Definition at line 441 of file undinet.c.
References DBGC, and net_device::priv.
00441 { 00442 struct undi_nic *undinic = netdev->priv; 00443 00444 /* Cannot support interrupts yet */ 00445 DBGC ( undinic, "UNDINIC %p cannot %s interrupts\n", 00446 undinic, ( enable ? "enable" : "disable" ) ); 00447 }
| int undinet_probe | ( | struct undi_device * | undi | ) |
Probe UNDI device.
| undi | UNDI device |
| rc | Return status code |
Definition at line 464 of file undinet.c.
References alloc_etherdev(), s_PXENV_START_UNDI::AX, BIOS_SEG, s_PXENV_START_UNDI::BX, DBGC, undi_device::dev, net_device::dev, s_PXENV_START_UNDI::DI, s_PXENV_START_UNDI::DX, ENOMEM, undi_device::entry, s_PXENV_START_UNDI::ES, ETH_ALEN, eth_ntoa(), find_pnp_bios(), undi_device::flags, undi_nic::hacks, net_device::hw_addr, s_PXENV_UNDI_GET_IFACE_INFO::IfaceType, s_PXENV_UNDI_GET_INFORMATION::IntNumber, undi_nic::irq, IRQ_MAX, undi_device::isapnp_csn, undi_device::isapnp_read_port, s_PXENV_UNDI_GET_IFACE_INFO::LinkSpeed, memcpy, memset(), netdev, netdev_init(), netdev_link_up(), netdev_nullify(), netdev_put(), NULL, undi_device::pci_busdevfn, s_PXENV_UNDI_GET_INFORMATION::PermNodeAddress, net_device::priv, PXENV_START_UNDI, PXENV_STOP_UNDI, PXENV_UNDI_CLEANUP, PXENV_UNDI_GET_IFACE_INFO, PXENV_UNDI_GET_INFORMATION, PXENV_UNDI_INITIALIZE, PXENV_UNDI_SHUTDOWN, PXENV_UNDI_STARTUP, pxeparent_call(), register_netdev(), s_PXENV_UNDI_GET_IFACE_INFO::ServiceFlags, strncmp(), UNDI_FL_INITIALIZED, UNDI_FL_STARTED, UNDI_HACK_EB54, and undi_set_drvdata().
Referenced by undibus_probe(), and undipci_probe().
00464 { 00465 struct net_device *netdev; 00466 struct undi_nic *undinic; 00467 struct s_PXENV_START_UNDI start_undi; 00468 struct s_PXENV_UNDI_STARTUP undi_startup; 00469 struct s_PXENV_UNDI_INITIALIZE undi_initialize; 00470 struct s_PXENV_UNDI_GET_INFORMATION undi_info; 00471 struct s_PXENV_UNDI_GET_IFACE_INFO undi_iface; 00472 struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; 00473 struct s_PXENV_UNDI_CLEANUP undi_cleanup; 00474 struct s_PXENV_STOP_UNDI stop_undi; 00475 int rc; 00476 00477 /* Allocate net device */ 00478 netdev = alloc_etherdev ( sizeof ( *undinic ) ); 00479 if ( ! netdev ) 00480 return -ENOMEM; 00481 netdev_init ( netdev, &undinet_operations ); 00482 undinic = netdev->priv; 00483 undi_set_drvdata ( undi, netdev ); 00484 netdev->dev = &undi->dev; 00485 memset ( undinic, 0, sizeof ( *undinic ) ); 00486 undinet_entry = undi->entry; 00487 DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi ); 00488 00489 /* Hook in UNDI stack */ 00490 if ( ! ( undi->flags & UNDI_FL_STARTED ) ) { 00491 memset ( &start_undi, 0, sizeof ( start_undi ) ); 00492 start_undi.AX = undi->pci_busdevfn; 00493 start_undi.BX = undi->isapnp_csn; 00494 start_undi.DX = undi->isapnp_read_port; 00495 start_undi.ES = BIOS_SEG; 00496 start_undi.DI = find_pnp_bios(); 00497 if ( ( rc = pxeparent_call ( undinet_entry, PXENV_START_UNDI, 00498 &start_undi, 00499 sizeof ( start_undi ) ) ) != 0 ) 00500 goto err_start_undi; 00501 } 00502 undi->flags |= UNDI_FL_STARTED; 00503 00504 /* Bring up UNDI stack */ 00505 if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) { 00506 memset ( &undi_startup, 0, sizeof ( undi_startup ) ); 00507 if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_STARTUP, 00508 &undi_startup, 00509 sizeof ( undi_startup ) ) ) != 0 ) 00510 goto err_undi_startup; 00511 memset ( &undi_initialize, 0, sizeof ( undi_initialize ) ); 00512 if ( ( rc = pxeparent_call ( undinet_entry, 00513 PXENV_UNDI_INITIALIZE, 00514 &undi_initialize, 00515 sizeof ( undi_initialize ))) != 0 ) 00516 goto err_undi_initialize; 00517 } 00518 undi->flags |= UNDI_FL_INITIALIZED; 00519 00520 /* Get device information */ 00521 memset ( &undi_info, 0, sizeof ( undi_info ) ); 00522 if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_INFORMATION, 00523 &undi_info, sizeof ( undi_info ) ) ) != 0 ) 00524 goto err_undi_get_information; 00525 memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN ); 00526 undinic->irq = undi_info.IntNumber; 00527 if ( undinic->irq > IRQ_MAX ) { 00528 DBGC ( undinic, "UNDINIC %p invalid IRQ %d\n", 00529 undinic, undinic->irq ); 00530 goto err_bad_irq; 00531 } 00532 DBGC ( undinic, "UNDINIC %p is %s on IRQ %d\n", 00533 undinic, eth_ntoa ( netdev->hw_addr ), undinic->irq ); 00534 00535 /* Get interface information */ 00536 memset ( &undi_iface, 0, sizeof ( undi_iface ) ); 00537 if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_IFACE_INFO, 00538 &undi_iface, 00539 sizeof ( undi_iface ) ) ) != 0 ) 00540 goto err_undi_get_iface_info; 00541 DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n", 00542 undinic, undi_iface.IfaceType, undi_iface.LinkSpeed, 00543 undi_iface.ServiceFlags ); 00544 if ( strncmp ( ( ( char * ) undi_iface.IfaceType ), "Etherboot", 00545 sizeof ( undi_iface.IfaceType ) ) == 0 ) { 00546 DBGC ( undinic, "UNDINIC %p Etherboot 5.4 workaround enabled\n", 00547 undinic ); 00548 undinic->hacks |= UNDI_HACK_EB54; 00549 } 00550 00551 /* Mark as link up; we don't handle link state */ 00552 netdev_link_up ( netdev ); 00553 00554 /* Register network device */ 00555 if ( ( rc = register_netdev ( netdev ) ) != 0 ) 00556 goto err_register; 00557 00558 DBGC ( undinic, "UNDINIC %p added\n", undinic ); 00559 return 0; 00560 00561 err_register: 00562 err_undi_get_iface_info: 00563 err_bad_irq: 00564 err_undi_get_information: 00565 err_undi_initialize: 00566 /* Shut down UNDI stack */ 00567 memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) ); 00568 pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN, &undi_shutdown, 00569 sizeof ( undi_shutdown ) ); 00570 memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) ); 00571 pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP, &undi_cleanup, 00572 sizeof ( undi_cleanup ) ); 00573 undi->flags &= ~UNDI_FL_INITIALIZED; 00574 err_undi_startup: 00575 /* Unhook UNDI stack */ 00576 memset ( &stop_undi, 0, sizeof ( stop_undi ) ); 00577 pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi, 00578 sizeof ( stop_undi ) ); 00579 undi->flags &= ~UNDI_FL_STARTED; 00580 err_start_undi: 00581 netdev_nullify ( netdev ); 00582 netdev_put ( netdev ); 00583 undi_set_drvdata ( undi, NULL ); 00584 return rc; 00585 }
| void undinet_remove | ( | struct undi_device * | undi | ) |
Remove UNDI device.
| undi | UNDI device |
Definition at line 592 of file undinet.c.
References DBGC, undi_device::flags, memset(), netdev, netdev_nullify(), netdev_put(), net_device::priv, PXENV_STOP_UNDI, PXENV_UNDI_CLEANUP, PXENV_UNDI_SHUTDOWN, pxeparent_call(), UNDI_FL_INITIALIZED, UNDI_FL_KEEP_ALL, UNDI_FL_STARTED, undi_get_drvdata(), and unregister_netdev().
Referenced by undibus_remove(), and undipci_remove().
00592 { 00593 struct net_device *netdev = undi_get_drvdata ( undi ); 00594 struct undi_nic *undinic = netdev->priv; 00595 struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; 00596 struct s_PXENV_UNDI_CLEANUP undi_cleanup; 00597 struct s_PXENV_STOP_UNDI stop_undi; 00598 00599 /* Unregister net device */ 00600 unregister_netdev ( netdev ); 00601 00602 /* If we are preparing for an OS boot, or if we cannot exit 00603 * via the PXE stack, then shut down the PXE stack. 00604 */ 00605 if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) { 00606 00607 /* Shut down UNDI stack */ 00608 memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) ); 00609 pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN, 00610 &undi_shutdown, sizeof ( undi_shutdown ) ); 00611 memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) ); 00612 pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP, 00613 &undi_cleanup, sizeof ( undi_cleanup ) ); 00614 undi->flags &= ~UNDI_FL_INITIALIZED; 00615 00616 /* Unhook UNDI stack */ 00617 memset ( &stop_undi, 0, sizeof ( stop_undi ) ); 00618 pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi, 00619 sizeof ( stop_undi ) ); 00620 undi->flags &= ~UNDI_FL_STARTED; 00621 } 00622 00623 /* Clear entry point */ 00624 memset ( &undinet_entry, 0, sizeof ( undinet_entry ) ); 00625 00626 /* Free network device */ 00627 netdev_nullify ( netdev ); 00628 netdev_put ( netdev ); 00629 00630 DBGC ( undinic, "UNDINIC %p removed\n", undinic ); 00631 }
SEGOFF16_t undinet_entry [static] |
unsigned int last_trigger_count = 0 [static] |
Last observed trigger count.
Definition at line 96 of file undinet.c.
Referenced by undinet_isr_triggered(), and undinet_poll().
struct net_device_operations undinet_operations [static] |
Initial value:
{
.open = undinet_open,
.close = undinet_close,
.transmit = undinet_transmit,
.poll = undinet_poll,
.irq = undinet_irq,
}
1.5.7.1