From 4c418d2100228b1c478908c08f51811a474e0e1e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 7 Jul 2007 16:43:39 +0100 Subject: [PATCH] Use net_device_operations structure and netdev_nullify() to allow for safe dropping of the netdev ref by the driver while other refs still exist. Add netdev_irq() method. Net device open()/close() methods should no longer enable or disable IRQs. Remove rx_quota; it wasn't used anywhere and added too much complexity to implementing correct interrupt-masking behaviour in pxe_undi.c. --- src/arch/i386/drivers/net/undinet.c | 38 ++++++--- src/drivers/net/legacy.c | 51 +++++++----- src/drivers/net/pnic.c | 63 ++++++++------- src/drivers/net/rtl8139.c | 48 ++++++----- src/include/gpxe/netdevice.h | 120 ++++++++++++++++++---------- src/interface/pxe/pxe_undi.c | 26 +++--- src/net/netdevice.c | 33 ++++---- src/net/nullnet.c | 57 +++++++++++++ 8 files changed, 291 insertions(+), 145 deletions(-) create mode 100644 src/net/nullnet.c diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c index 46a759cc..3ed0ed64 100644 --- a/src/arch/i386/drivers/net/undinet.c +++ b/src/arch/i386/drivers/net/undinet.c @@ -394,7 +394,6 @@ static int undinet_transmit ( struct net_device *netdev, * Poll for received packets * * @v netdev Network device - * @v rx_quota Maximum number of packets to receive * * Fun, fun, fun. UNDI drivers don't use polling; they use * interrupts. We therefore cheat and pretend that an interrupt has @@ -412,7 +411,7 @@ static int undinet_transmit ( struct net_device *netdev, * of installing a genuine interrupt service routine and dealing with * the wonderful 8259 Programmable Interrupt Controller. Joy. */ -static void undinet_poll ( struct net_device *netdev, unsigned int rx_quota ) { +static void undinet_poll ( struct net_device *netdev ) { struct undi_nic *undinic = netdev->priv; struct s_PXENV_UNDI_ISR undi_isr; struct io_buffer *iobuf = NULL; @@ -454,7 +453,7 @@ static void undinet_poll ( struct net_device *netdev, unsigned int rx_quota ) { } /* Run through the ISR loop */ - while ( rx_quota ) { + while ( 1 ) { if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr, sizeof ( undi_isr ) ) ) != 0 ) break; @@ -487,7 +486,6 @@ static void undinet_poll ( struct net_device *netdev, unsigned int rx_quota ) { /* Whole packet received; deliver it */ netdev_rx ( netdev, iobuf ); iobuf = NULL; - --rx_quota; /* Etherboot 5.4 fails to return all packets * under mild load; pretend it retriggered. */ @@ -599,6 +597,29 @@ static void undinet_close ( struct net_device *netdev ) { DBGC ( undinic, "UNDINIC %p closed\n", undinic ); } +/** + * Enable/disable interrupts + * + * @v netdev Net device + * @v enable Interrupts should be enabled + */ +static void undinet_irq ( struct net_device *netdev, int enable ) { + struct undi_nic *undinic = netdev->priv; + + /* Cannot support interrupts yet */ + DBGC ( undinic, "UNDINIC %p cannot %s interrupts\n", + undinic, ( enable ? "enable" : "disable" ) ); +} + +/** UNDI network device operations */ +static struct net_device_operations undinet_operations = { + .open = undinet_open, + .close = undinet_close, + .transmit = undinet_transmit, + .poll = undinet_poll, + .irq = undinet_irq, +}; + /** * Probe UNDI device * @@ -622,6 +643,7 @@ int undinet_probe ( struct undi_device *undi ) { netdev = alloc_etherdev ( sizeof ( *undinic ) ); if ( ! netdev ) return -ENOMEM; + netdev_init ( netdev, &undinet_operations ); undinic = netdev->priv; undi_set_drvdata ( undi, netdev ); netdev->dev = &undi->dev; @@ -685,12 +707,6 @@ int undinet_probe ( struct undi_device *undi ) { undinic->hacks |= UNDI_HACK_EB54; } - /* Point to NIC specific routines */ - netdev->open = undinet_open; - netdev->close = undinet_close; - netdev->transmit = undinet_transmit; - netdev->poll = undinet_poll; - /* Register network device */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) goto err_register; @@ -716,6 +732,7 @@ int undinet_probe ( struct undi_device *undi ) { undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi, sizeof ( stop_undi ) ); err_start_undi: + netdev_nullify ( netdev ); netdev_put ( netdev ); undi_set_drvdata ( undi, NULL ); return rc; @@ -751,6 +768,7 @@ void undinet_remove ( struct undi_device *undi ) { undi->flags &= ~UNDI_FL_STARTED; /* Free network device */ + netdev_nullify ( netdev ); netdev_put ( netdev ); DBGC ( undinic, "UNDINIC %p removed\n", undinic ); diff --git a/src/drivers/net/legacy.c b/src/drivers/net/legacy.c index 2d4633d4..6ae2fbec 100644 --- a/src/drivers/net/legacy.c +++ b/src/drivers/net/legacy.c @@ -36,13 +36,10 @@ static int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf return 0; } -static void legacy_poll ( struct net_device *netdev, unsigned int rx_quota ) { +static void legacy_poll ( struct net_device *netdev ) { struct nic *nic = netdev->priv; struct io_buffer *iobuf; - if ( ! rx_quota ) - return; - iobuf = alloc_iob ( ETH_FRAME_LEN ); if ( ! iobuf ) return; @@ -57,19 +54,29 @@ static void legacy_poll ( struct net_device *netdev, unsigned int rx_quota ) { } } -static int legacy_open ( struct net_device *netdev ) { - struct nic *nic = netdev->priv; - - nic->nic_op->irq ( nic, ENABLE ); +static int legacy_open ( struct net_device *netdev __unused ) { + /* Nothing to do */ return 0; } -static void legacy_close ( struct net_device *netdev ) { +static void legacy_close ( struct net_device *netdev __unused ) { + /* Nothing to do */ +} + +static void legacy_irq ( struct net_device *netdev __unused, int enable ) { struct nic *nic = netdev->priv; - nic->nic_op->irq ( nic, DISABLE ); + nic->nic_op->irq ( nic, ( enable ? ENABLE : DISABLE ) ); } +static struct net_device_operations legacy_operations = { + .open = legacy_open, + .close = legacy_close, + .transmit = legacy_transmit, + .poll = legacy_poll, + .irq = legacy_irq, +}; + int legacy_probe ( void *hwdev, void ( * set_drvdata ) ( void *hwdev, void *priv ), struct device *dev, @@ -84,27 +91,21 @@ int legacy_probe ( void *hwdev, netdev = alloc_etherdev ( 0 ); if ( ! netdev ) return -ENOMEM; + netdev_init ( netdev, &legacy_operations ); netdev->priv = &nic; memset ( &nic, 0, sizeof ( nic ) ); set_drvdata ( hwdev, netdev ); netdev->dev = dev; - netdev->open = legacy_open; - netdev->close = legacy_close; - netdev->transmit = legacy_transmit; - netdev->poll = legacy_poll; nic.node_addr = netdev->ll_addr; if ( ! probe ( &nic, hwdev ) ) { - netdev_put ( netdev ); - return -ENODEV; + rc = -ENODEV; + goto err_probe; } - if ( ( rc = register_netdev ( netdev ) ) != 0 ) { - disable ( &nic, hwdev ); - netdev_put ( netdev ); - return rc; - } + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register; /* Do not remove this message */ printf ( "WARNING: Using legacy NIC wrapper on %s\n", @@ -112,6 +113,13 @@ int legacy_probe ( void *hwdev, legacy_registered = 1; return 0; + + err_register: + disable ( &nic, hwdev ); + err_probe: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + return rc; } void legacy_remove ( void *hwdev, @@ -122,6 +130,7 @@ void legacy_remove ( void *hwdev, unregister_netdev ( netdev ); disable ( nic, hwdev ); + netdev_nullify ( netdev ); netdev_put ( netdev ); legacy_registered = 0; } diff --git a/src/drivers/net/pnic.c b/src/drivers/net/pnic.c index 38b4af6d..b431ec52 100644 --- a/src/drivers/net/pnic.c +++ b/src/drivers/net/pnic.c @@ -112,35 +112,34 @@ static int pnic_api_check ( uint16_t api_version ) { /************************************************************************** POLL - Wait for a frame ***************************************************************************/ -static void pnic_poll ( struct net_device *netdev, unsigned int rx_quota ) { +static void pnic_poll ( struct net_device *netdev ) { struct pnic *pnic = netdev->priv; struct io_buffer *iobuf; uint16_t length; uint16_t qlen; /* Fetch all available packets */ - while ( rx_quota ) { + while ( 1 ) { if ( pnic_command ( pnic, PNIC_CMD_RECV_QLEN, NULL, 0, &qlen, sizeof ( qlen ), NULL ) != PNIC_STATUS_OK ) - break; + return; if ( qlen == 0 ) - break; + return; iobuf = alloc_iob ( ETH_FRAME_LEN ); if ( ! iobuf ) { DBG ( "could not allocate buffer\n" ); netdev_rx_err ( netdev, NULL, -ENOMEM ); - break; + return; } if ( pnic_command ( pnic, PNIC_CMD_RECV, NULL, 0, iobuf->data, ETH_FRAME_LEN, &length ) != PNIC_STATUS_OK ) { netdev_rx_err ( netdev, iobuf, -EIO ); - break; + return; } iob_put ( iobuf, length ); netdev_rx ( netdev, iobuf ); - --rx_quota; } } @@ -164,29 +163,40 @@ static int pnic_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) /************************************************************************** OPEN - Open network device ***************************************************************************/ -static int pnic_open ( struct net_device *netdev ) { - struct pnic *pnic = netdev->priv; - static const uint8_t enable = 1; - - /* Enable interrupts */ - pnic_command ( pnic, PNIC_CMD_MASK_IRQ, &enable, - sizeof ( enable ), NULL, 0, NULL ); - +static int pnic_open ( struct net_device *netdev __unused ) { + /* Nothing to do */ return 0; } /************************************************************************** CLOSE - Close network device ***************************************************************************/ -static void pnic_close ( struct net_device *netdev ) { - struct pnic *pnic = netdev->priv; - static const uint8_t disable = 0; - - /* Disable interrupts */ - pnic_command ( pnic, PNIC_CMD_MASK_IRQ, &disable, - sizeof ( disable ), NULL, 0, NULL ); +static void pnic_close ( struct net_device *netdev __unused ) { + /* Nothing to do */ } +/************************************************************************** +IRQ - Enable/disable interrupts +***************************************************************************/ +static void pnic_irq ( struct net_device *netdev, int enable ) { + struct pnic *pnic = netdev->priv; + uint8_t mask = ( enable ? 1 : 0 ); + + pnic_command ( pnic, PNIC_CMD_MASK_IRQ, &mask, sizeof ( mask ), + NULL, 0, NULL ); +} + +/************************************************************************** +OPERATIONS TABLE +***************************************************************************/ +static struct net_device_operations pnic_operations = { + .open = pnic_open, + .close = pnic_close, + .transmit = pnic_transmit, + .poll = pnic_poll, + .irq = pnic_irq, +}; + /************************************************************************** DISABLE - Turn off ethernet interface ***************************************************************************/ @@ -196,6 +206,7 @@ static void pnic_remove ( struct pci_device *pci ) { unregister_netdev ( netdev ); pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL ); + netdev_nullify ( netdev ); netdev_put ( netdev ); } @@ -214,6 +225,7 @@ static int pnic_probe ( struct pci_device *pci, netdev = alloc_etherdev ( sizeof ( *pnic ) ); if ( ! netdev ) return -ENOMEM; + netdev_init ( netdev, &pnic_operations ); pnic = netdev->priv; pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; @@ -238,12 +250,6 @@ static int pnic_probe ( struct pci_device *pci, status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0, netdev->ll_addr, ETH_ALEN, NULL ); - /* Point to NIC specific routines */ - netdev->open = pnic_open; - netdev->close = pnic_close; - netdev->poll = pnic_poll; - netdev->transmit = pnic_transmit; - /* Register network device */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) goto err; @@ -252,6 +258,7 @@ static int pnic_probe ( struct pci_device *pci, err: /* Free net device */ + netdev_nullify ( netdev ); netdev_put ( netdev ); return rc; } diff --git a/src/drivers/net/rtl8139.c b/src/drivers/net/rtl8139.c index 54bda07f..8b40918f 100644 --- a/src/drivers/net/rtl8139.c +++ b/src/drivers/net/rtl8139.c @@ -302,12 +302,6 @@ static struct nvo_fragment rtl_nvo_fragments[] = { */ static void rtl_reset ( struct rtl8139_nic *rtl ) { - /* Disable interrupts. May not be necessary, but datasheet - * doesn't say that the reset command also resets the - * interrupt mask. - */ - outw ( 0, rtl->ioaddr + IntrMask ); - /* Reset chip */ outb ( CmdReset, rtl->ioaddr + ChipCmd ); mdelay ( 10 ); @@ -346,9 +340,6 @@ static int rtl_open ( struct net_device *netdev ) { outl ( ( ( TX_DMA_BURST << 8 ) | ( TX_IPG << 24 ) ), rtl->ioaddr + TxConfig ); - /* Enable interrupts */ - outw ( ( ROK | RER | TOK | TER ), rtl->ioaddr + IntrMask ); - return 0; } @@ -400,13 +391,12 @@ static int rtl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { return 0; } -/** +/** * Poll for received packets * * @v netdev Network device - * @v rx_quota Maximum number of packets to receive */ -static void rtl_poll ( struct net_device *netdev, unsigned int rx_quota ) { +static void rtl_poll ( struct net_device *netdev ) { struct rtl8139_nic *rtl = netdev->priv; unsigned int status; unsigned int tsad; @@ -433,7 +423,7 @@ static void rtl_poll ( struct net_device *netdev, unsigned int rx_quota ) { } /* Handle received packets */ - while ( rx_quota && ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ){ + while ( ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ) { rx_status = * ( ( uint16_t * ) ( rtl->rx.ring + rtl->rx.offset ) ); rx_len = * ( ( uint16_t * ) @@ -461,7 +451,6 @@ static void rtl_poll ( struct net_device *netdev, unsigned int rx_quota ) { rtl->rx.ring, wrapped_len ); netdev_rx ( netdev, rx_iob ); - rx_quota--; } else { DBG ( "RX bad packet (status %#04x len %d)\n", rx_status, rx_len ); @@ -473,6 +462,28 @@ static void rtl_poll ( struct net_device *netdev, unsigned int rx_quota ) { } } +/** + * Enable/disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void rtl_irq ( struct net_device *netdev, int enable ) { + struct rtl8139_nic *rtl = netdev->priv; + + outw ( ( enable ? ( ROK | RER | TOK | TER ) : 0 ), + rtl->ioaddr + IntrMask ); +} + +/** RTL8139 net device operations */ +static struct net_device_operations rtl_operations = { + .open = rtl_open, + .close = rtl_close, + .transmit = rtl_transmit, + .poll = rtl_poll, + .irq = rtl_irq, +}; + /** * Probe PCI device * @@ -490,6 +501,7 @@ static int rtl_probe ( struct pci_device *pci, netdev = alloc_etherdev ( sizeof ( *rtl ) ); if ( ! netdev ) return -ENOMEM; + netdev_init ( netdev, &rtl_operations ); rtl = netdev->priv; pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; @@ -504,12 +516,6 @@ static int rtl_probe ( struct pci_device *pci, rtl_init_eeprom ( rtl ); nvs_read ( &rtl->eeprom.nvs, EE_MAC, netdev->ll_addr, ETH_ALEN ); - /* Point to NIC specific routines */ - netdev->open = rtl_open; - netdev->close = rtl_close; - netdev->transmit = rtl_transmit; - netdev->poll = rtl_poll; - /* Register network device */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) goto err_register_netdev; @@ -526,6 +532,7 @@ static int rtl_probe ( struct pci_device *pci, unregister_netdev ( netdev ); err_register_netdev: rtl_reset ( rtl ); + netdev_nullify ( netdev ); netdev_put ( netdev ); return rc; } @@ -543,6 +550,7 @@ static void rtl_remove ( struct pci_device *pci ) { nvo_unregister ( &rtl->nvo ); unregister_netdev ( netdev ); rtl_reset ( rtl ); + netdev_nullify ( netdev ); netdev_put ( netdev ); } diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index d6b9a1be..d82c6d8f 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -128,41 +128,8 @@ struct ll_protocol { const uint8_t *ll_broadcast; }; -/** - * Network device statistics - * - */ -struct net_device_stats { - /** Count of successfully completed transmissions */ - unsigned int tx_ok; - /** Count of transmission errors */ - unsigned int tx_err; - /** Count of successfully received packets */ - unsigned int rx_ok; - /** Count of reception errors */ - unsigned int rx_err; -}; - -/** - * A network device - * - * This structure represents a piece of networking hardware. It has - * properties such as a link-layer address and methods for - * transmitting and receiving raw packets. - * - * Note that this structure must represent a generic network device, - * not just an Ethernet device. - */ -struct net_device { - /** Reference counter */ - struct refcnt refcnt; - /** List of network devices */ - struct list_head list; - /** Name of this network device */ - char name[8]; - /** Underlying hardware device */ - struct device *dev; - +/** Network device operations */ +struct net_device_operations { /** Open network device * * @v netdev Network device @@ -199,20 +166,62 @@ struct net_device { * This method is guaranteed to be called only when the device * is open. */ - int ( * transmit ) ( struct net_device *netdev, struct io_buffer *iobuf ); - /** Poll for received packet + int ( * transmit ) ( struct net_device *netdev, + struct io_buffer *iobuf ); + /** Poll for completed and received packets * * @v netdev Network device - * @v rx_quota Maximum number of packets to receive * - * This method should cause the hardware to check for received - * packets. Any received packets should be delivered via - * netdev_rx(), up to a maximum of @c rx_quota packets. + * This method should cause the hardware to check for + * completed transmissions and received packets. Any received + * packets should be delivered via netdev_rx(). * * This method is guaranteed to be called only when the device * is open. */ - void ( * poll ) ( struct net_device *netdev, unsigned int rx_quota ); + void ( * poll ) ( struct net_device *netdev ); + /** Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ + void ( * irq ) ( struct net_device *netdev, int enable ); +}; + +/** Network device statistics */ +struct net_device_stats { + /** Count of successfully completed transmissions */ + unsigned int tx_ok; + /** Count of transmission errors */ + unsigned int tx_err; + /** Count of successfully received packets */ + unsigned int rx_ok; + /** Count of reception errors */ + unsigned int rx_err; +}; + +/** + * A network device + * + * This structure represents a piece of networking hardware. It has + * properties such as a link-layer address and methods for + * transmitting and receiving raw packets. + * + * Note that this structure must represent a generic network device, + * not just an Ethernet device. + */ +struct net_device { + /** Reference counter */ + struct refcnt refcnt; + /** List of network devices */ + struct list_head list; + /** Name of this network device */ + char name[8]; + /** Underlying hardware device */ + struct device *dev; + + /** Network device operations */ + struct net_device_operations *op; /** Link-layer protocol */ struct ll_protocol *ll_protocol; @@ -248,6 +257,30 @@ struct net_device { #define __net_protocol __table ( struct net_protocol, net_protocols, 01 ) extern struct list_head net_devices; +extern struct net_device_operations null_netdev_operations; + +/** + * Initialise a network device + * + * @v netdev Network device + * @v op Network device operations + */ +static inline void netdev_init ( struct net_device *netdev, + struct net_device_operations *op ) { + netdev->op = op; +} + +/** + * Stop using a network device + * + * @v netdev Network device + * + * Drivers should call this method immediately before the final call + * to netdev_put(). + */ +static inline void netdev_nullify ( struct net_device *netdev ) { + netdev->op = &null_netdev_operations; +} /** * Get printable network device hardware address @@ -300,13 +333,14 @@ extern void netdev_tx_complete_next_err ( struct net_device *netdev, int rc ); extern void netdev_rx ( struct net_device *netdev, struct io_buffer *iobuf ); extern void netdev_rx_err ( struct net_device *netdev, struct io_buffer *iobuf, int rc ); -extern int netdev_poll ( struct net_device *netdev, unsigned int rx_quota ); +extern void netdev_poll ( struct net_device *netdev ); extern struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev ); extern struct net_device * alloc_netdev ( size_t priv_size ); extern int register_netdev ( struct net_device *netdev ); extern int netdev_open ( struct net_device *netdev ); extern void netdev_close ( struct net_device *netdev ); extern void unregister_netdev ( struct net_device *netdev ); +extern void netdev_irq ( struct net_device *netdev, int enable ); extern struct net_device * find_netdev ( const char *name ); extern struct net_device * find_netdev_by_location ( unsigned int bus_type, unsigned int location ); diff --git a/src/interface/pxe/pxe_undi.c b/src/interface/pxe/pxe_undi.c index cc23de70..f19dfcc5 100644 --- a/src/interface/pxe/pxe_undi.c +++ b/src/interface/pxe/pxe_undi.c @@ -69,7 +69,13 @@ void pxe_set_netdev ( struct net_device *netdev ) { * @ret rc Return status code */ static int pxe_netdev_open ( void ) { - return netdev_open ( pxe_netdev ); + int rc; + + if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 ) + return rc; + + netdev_irq ( pxe_netdev, 1 ); + return 0; } /** @@ -77,6 +83,7 @@ static int pxe_netdev_open ( void ) { * */ static void pxe_netdev_close ( void ) { + netdev_irq ( pxe_netdev, 0 ); netdev_close ( pxe_netdev ); undi_tx_count = 0; } @@ -543,14 +550,13 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { /* Call poll(). This should acknowledge the device * interrupt and queue up any received packet. */ - if ( netdev_poll ( pxe_netdev, -1U ) ) { - /* Packet waiting in queue */ - DBG ( " OURS" ); - undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS; - } else { - DBG ( " NOT_OURS" ); - undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS; - } + netdev_poll ( pxe_netdev ); + + /* Disable interrupts to avoid interrupt storm */ + netdev_irq ( pxe_netdev, 0 ); + + /* Always say it was ours for the sake of simplicity */ + undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS; break; case PXENV_UNDI_ISR_IN_PROCESS : case PXENV_UNDI_ISR_IN_GET_NEXT : @@ -570,6 +576,8 @@ PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) { if ( ! iobuf ) { /* No more packets remaining */ undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE; + /* Re-enable interrupts */ + netdev_irq ( pxe_netdev, 1 ); break; } diff --git a/src/net/netdevice.c b/src/net/netdevice.c index d72392ca..460de89c 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -68,7 +68,7 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) { goto err; } - if ( ( rc = netdev->transmit ( netdev, iobuf ) ) != 0 ) + if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 ) goto err; return 0; @@ -187,22 +187,18 @@ void netdev_rx_err ( struct net_device *netdev, } /** - * Poll for packet on network device + * Poll for completed and received packets on network device * * @v netdev Network device - * @v rx_quota Maximum number of packets to receive - * @ret True There are packets present in the receive queue - * @ret False There are no packets present in the receive queue * - * Polls the network device for received packets. Any received - * packets will be added to the RX packet queue via netdev_rx(). + * Polls the network device for completed transmissions and received + * packets. Any received packets will be added to the RX packet queue + * via netdev_rx(). */ -int netdev_poll ( struct net_device *netdev, unsigned int rx_quota ) { +void netdev_poll ( struct net_device *netdev ) { if ( netdev->state & NETDEV_OPEN ) - netdev->poll ( netdev, rx_quota ); - - return ( ! list_empty ( &netdev->rx_queue ) ); + netdev->op->poll ( netdev ); } /** @@ -317,7 +313,7 @@ int netdev_open ( struct net_device *netdev ) { DBGC ( netdev, "NETDEV %p opening\n", netdev ); /* Open the device */ - if ( ( rc = netdev->open ( netdev ) ) != 0 ) + if ( ( rc = netdev->op->open ( netdev ) ) != 0 ) return rc; /* Mark as opened */ @@ -339,7 +335,7 @@ void netdev_close ( struct net_device *netdev ) { DBGC ( netdev, "NETDEV %p closing\n", netdev ); /* Close the device */ - netdev->close ( netdev ); + netdev->op->close ( netdev ); /* Flush TX and RX queues */ netdev_tx_flush ( netdev ); @@ -367,6 +363,15 @@ void unregister_netdev ( struct net_device *netdev ) { DBGC ( netdev, "NETDEV %p unregistered\n", netdev ); } +/** Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +void netdev_irq ( struct net_device *netdev, int enable ) { + netdev->op->irq ( netdev, enable ); +} + /** * Get network device by name * @@ -462,7 +467,7 @@ static void net_step ( struct process *process __unused ) { list_for_each_entry ( netdev, &net_devices, list ) { /* Poll for new packets */ - netdev_poll ( netdev, -1U ); + netdev_poll ( netdev ); /* Process at most one received packet. Give priority * to getting packets out of the NIC over processing diff --git a/src/net/nullnet.c b/src/net/nullnet.c new file mode 100644 index 00000000..4b6ba4c1 --- /dev/null +++ b/src/net/nullnet.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2006 Michael Brown . + * + * 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 +#include +#include + +/** @file + * + * Null network device + * + */ + +static int null_open ( struct net_device *netdev __unused ) { + return -ENODEV; +}; + +static void null_close ( struct net_device *netdev __unused ) { + /* Do nothing */ +}; + +static int null_transmit ( struct net_device *netdev __unused, + struct io_buffer *iobuf __unused ) { + return -ENODEV; +}; + +static void null_poll ( struct net_device *netdev __unused ) { + /* Do nothing */ +} + +static void null_irq ( struct net_device *netdev __unused, + int enable __unused ) { + /* Do nothing */ +} + +struct net_device_operations null_netdev_operations = { + .open = null_open, + .close = null_close, + .transmit = null_transmit, + .poll = null_poll, + .irq = null_irq, +};