undinet.c File Reference

UNDI network device driver. More...

#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.


Detailed Description

UNDI network device driver.

Definition in file undinet.c.


Define Documentation

#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 )

Definition at line 93 of file undinet.c.

Referenced by undinet_isr_triggered().

#define undinet_tbd   __use_data16 ( undinet_tbd )

Definition at line 159 of file undinet.c.

Referenced by undinet_transmit().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER   ) 

static void undinet_close ( struct net_device netdev  )  [static]

Close NIC.

Parameters:
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.

Parameters:
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.

Parameters:
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.

Return values:
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.

Parameters:
netdev Network device
iobuf I/O buffer
Return values:
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.

Parameters:
netdev Network device
Fun, fun, fun. UNDI drivers don't use polling; they use interrupts. We therefore cheat and pretend that an interrupt has occurred every time undinet_poll() is called. This isn't too much of a hack; PCI devices share IRQs and so the first thing that a proper ISR should do is call PXENV_UNDI_ISR to determine whether or not the UNDI NIC generated the interrupt; there is no harm done by spurious calls to PXENV_UNDI_ISR. Similarly, we wouldn't be handling them any more rapidly than the usual rate of undinet_poll() being called even if we did implement a full ISR. So it should work. Ha!

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.

Parameters:
netdev Net device
Return values:
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.

Parameters:
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.

Parameters:
undi UNDI device
Return values:
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.

Parameters:
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 }


Variable Documentation

Address of UNDI entry point.

Definition at line 67 of file undinet.c.

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().

Initial value:

 {
        .open           = undinet_open,
        .close          = undinet_close,
        .transmit       = undinet_transmit,
        .poll           = undinet_poll,
        .irq            = undinet_irq,
}
UNDI network device operations.

Definition at line 450 of file undinet.c.


Generated on Tue Apr 6 20:01:12 2010 for gPXE by  doxygen 1.5.7.1