diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c index d54429bd..865c6e8d 100644 --- a/src/arch/i386/drivers/net/undinet.c +++ b/src/arch/i386/drivers/net/undinet.c @@ -675,7 +675,7 @@ int undinet_probe ( struct undi_device *undi ) { undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi, sizeof ( stop_undi ) ); err_start_undi: - free_netdev ( netdev ); + netdev_put ( netdev ); undi_set_drvdata ( undi, NULL ); return rc; } @@ -710,7 +710,7 @@ void undinet_remove ( struct undi_device *undi ) { undi->flags &= ~UNDI_FL_STARTED; /* Free network device */ - free_netdev ( netdev ); + netdev_put ( netdev ); DBGC ( undinic, "UNDINIC %p removed\n", undinic ); } diff --git a/src/core/hotplug.c b/src/core/hotplug.c deleted file mode 100644 index 0f5f4730..00000000 --- a/src/core/hotplug.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2007 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 - -/** @file - * - * Hotplug support - * - */ - -/** - * Forget all persistent references to an object - * - * @v list List of persistent references - */ -void forget_references ( struct list_head *list ) { - struct reference *ref; - struct reference *ref_tmp; - - list_for_each_entry_safe ( ref, ref_tmp, list, list ) { - ref->forget ( ref ); - } - - /* The list had really better be empty by now, otherwise we're - * screwed. - */ - assert ( list_empty ( list ) ); -} diff --git a/src/drivers/net/legacy.c b/src/drivers/net/legacy.c index 27d225a4..60077d73 100644 --- a/src/drivers/net/legacy.c +++ b/src/drivers/net/legacy.c @@ -90,13 +90,13 @@ int legacy_probe ( void *hwdev, nic.node_addr = netdev->ll_addr; if ( ! probe ( &nic, hwdev ) ) { - free_netdev ( netdev ); + netdev_put ( netdev ); return -ENODEV; } if ( ( rc = register_netdev ( netdev ) ) != 0 ) { disable ( &nic, hwdev ); - free_netdev ( netdev ); + netdev_put ( netdev ); return rc; } @@ -116,7 +116,7 @@ void legacy_remove ( void *hwdev, unregister_netdev ( netdev ); disable ( nic, hwdev ); - free_netdev ( netdev ); + netdev_put ( netdev ); legacy_registered = 0; } diff --git a/src/drivers/net/pnic.c b/src/drivers/net/pnic.c index 95571961..5d6b90c7 100644 --- a/src/drivers/net/pnic.c +++ b/src/drivers/net/pnic.c @@ -206,7 +206,7 @@ static void pnic_remove ( struct pci_device *pci ) { unregister_netdev ( netdev ); pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL ); - free_netdev ( netdev ); + netdev_put ( netdev ); } /************************************************************************** @@ -220,20 +220,18 @@ static int pnic_probe ( struct pci_device *pci, uint16_t status; int rc; - /* Fix up PCI device */ - adjust_pci_device ( pci ); - /* Allocate net device */ netdev = alloc_etherdev ( sizeof ( *pnic ) ); - if ( ! netdev ) { - rc = -ENOMEM; - goto err; - } + if ( ! netdev ) + return -ENOMEM; pnic = netdev->priv; pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; pnic->ioaddr = pci->ioaddr; + /* Fix up PCI device */ + adjust_pci_device ( pci ); + /* API version check */ status = pnic_command_quiet ( pnic, PNIC_CMD_API_VER, NULL, 0, &api_version, @@ -264,7 +262,7 @@ static int pnic_probe ( struct pci_device *pci, err: /* Free net device */ - free_netdev ( netdev ); + netdev_put ( netdev ); return rc; } diff --git a/src/drivers/net/rtl8139.c b/src/drivers/net/rtl8139.c index 7806a6b8..2f68bf6c 100644 --- a/src/drivers/net/rtl8139.c +++ b/src/drivers/net/rtl8139.c @@ -501,25 +501,22 @@ static void rtl_irq(struct nic *nic, irq_action_t action) static int rtl_probe ( struct pci_device *pci, const struct pci_device_id *id __unused ) { struct net_device *netdev; - struct rtl8139_nic *rtl = NULL; - int registered_netdev = 0; + struct rtl8139_nic *rtl; int rc; - /* Fix up PCI device */ - adjust_pci_device ( pci ); - /* Allocate net device */ netdev = alloc_etherdev ( sizeof ( *rtl ) ); - if ( ! netdev ) { - rc = -ENOMEM; - goto err; - } + if ( ! netdev ) + return -ENOMEM; rtl = netdev->priv; pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( rtl, 0, sizeof ( *rtl ) ); rtl->ioaddr = pci->ioaddr; + /* Fix up PCI device */ + adjust_pci_device ( pci ); + /* Reset the NIC, set up EEPROM access and read MAC address */ rtl_reset ( rtl ); rtl_init_eeprom ( rtl ); @@ -533,25 +530,21 @@ static int rtl_probe ( struct pci_device *pci, /* Register network device */ if ( ( rc = register_netdev ( netdev ) ) != 0 ) - goto err; - registered_netdev = 1; + goto err_register_netdev; /* Register non-volatile storage */ if ( rtl->nvo.nvs ) { if ( ( rc = nvo_register ( &rtl->nvo ) ) != 0 ) - goto err; + goto err_register_nvo; } return 0; - err: - /* Disable NIC */ - if ( rtl ) - rtl_reset ( rtl ); - if ( registered_netdev ) - unregister_netdev ( netdev ); - /* Free net device */ - free_netdev ( netdev ); + err_register_nvo: + unregister_netdev ( netdev ); + err_register_netdev: + rtl_reset ( rtl ); + netdev_put ( netdev ); return rc; } @@ -568,7 +561,7 @@ static void rtl_remove ( struct pci_device *pci ) { nvo_unregister ( &rtl->nvo ); unregister_netdev ( netdev ); rtl_reset ( rtl ); - free_netdev ( netdev ); + netdev_put ( netdev ); } static struct pci_device_id rtl8139_nics[] = { diff --git a/src/include/gpxe/aoe.h b/src/include/gpxe/aoe.h index 3c54b6bb..eb5e1133 100644 --- a/src/include/gpxe/aoe.h +++ b/src/include/gpxe/aoe.h @@ -13,7 +13,6 @@ #include #include #include -#include /** An AoE ATA command */ struct aoecmd { @@ -87,8 +86,6 @@ struct aoe_session { /** Network device */ struct net_device *netdev; - /** Reference to network device */ - struct reference netdev_ref; /** Major number */ uint16_t major; diff --git a/src/include/gpxe/dhcp.h b/src/include/gpxe/dhcp.h index 1ec7ca03..16609baf 100644 --- a/src/include/gpxe/dhcp.h +++ b/src/include/gpxe/dhcp.h @@ -13,7 +13,6 @@ #include #include #include -#include /** BOOTP/DHCP server port */ #define BOOTPS_PORT 67 @@ -449,6 +448,8 @@ struct dhcp_packet { struct dhcp_option_block options[NUM_OPT_BLOCKS]; }; +struct udp_connection {}; + /** A DHCP session */ struct dhcp_session { /** UDP connection for this session */ @@ -456,8 +457,6 @@ struct dhcp_session { /** Network device being configured */ struct net_device *netdev; - /** Persistent reference to network device */ - struct reference netdev_ref; /** Options obtained from server */ struct dhcp_option_block *options; diff --git a/src/include/gpxe/hotplug.h b/src/include/gpxe/hotplug.h deleted file mode 100644 index e6e132de..00000000 --- a/src/include/gpxe/hotplug.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _GPXE_HOTPLUG_H -#define _GPXE_HOTPLUG_H - -/** @file - * - * Hotplug support - * - */ - -#include - -/** - * A persistent reference to another data structure - * - * This data structure should be embedded within any data structure - * (the referrer) which holds a persistent reference to a separate, - * volatile data structure (the referee). - */ -struct reference { - /** List of persistent references */ - struct list_head list; - /** Forget persistent reference - * - * @v ref Persistent reference - * - * This method is called immediately before the referred-to - * data structure is destroyed. The reference holder must - * forget all references to the referee before returning from - * this method. - * - * This method must also call ref_del() to remove the - * reference. - */ - void ( * forget ) ( struct reference *ref ); -}; - -/** - * Add persistent reference - * - * @v ref Persistent reference - * @v list List of persistent references - */ -static inline void ref_add ( struct reference *ref, struct list_head *list ) { - list_add ( &ref->list, list ); -} - -/** - * Remove persistent reference - * - * @v ref Persistent reference - */ -static inline void ref_del ( struct reference *ref ) { - list_del ( &ref->list ); -} - -extern void forget_references ( struct list_head *list ); - -#endif /* _GPXE_HOTPLUG_H */ diff --git a/src/include/gpxe/ip.h b/src/include/gpxe/ip.h index 9a5b7a81..974c6457 100644 --- a/src/include/gpxe/ip.h +++ b/src/include/gpxe/ip.h @@ -9,7 +9,6 @@ #include #include -#include /* IP constants */ @@ -44,8 +43,6 @@ struct ipv4_miniroute { /** Network device */ struct net_device *netdev; - /** Reference to network device */ - struct reference netdev_ref; /** IPv4 address */ struct in_addr address; diff --git a/src/include/gpxe/netdevice.h b/src/include/gpxe/netdevice.h index c71c0928..9800ef56 100644 --- a/src/include/gpxe/netdevice.h +++ b/src/include/gpxe/netdevice.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include struct io_buffer; struct net_device; @@ -137,14 +137,14 @@ struct ll_protocol { * 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; - /** List of persistent reference holders */ - struct list_head references; /** Open network device * @@ -251,6 +251,28 @@ static inline int have_netdevs ( void ) { return ( ! list_empty ( &net_devices ) ); } +/** + * Get reference to network device + * + * @v netdev Network device + * @ret netdev Network device + */ +static inline __attribute__ (( always_inline )) struct net_device * +netdev_get ( struct net_device *netdev ) { + ref_get ( &netdev->refcnt ); + return netdev; +} + +/** + * Drop reference to network device + * + * @v netdev Network device + */ +static inline __attribute__ (( always_inline )) void +netdev_put ( struct net_device *netdev ) { + ref_put ( &netdev->refcnt ); +} + extern int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ); void netdev_tx_complete ( struct net_device *netdev, struct io_buffer *iobuf ); void netdev_tx_complete_next ( struct net_device *netdev ); @@ -262,7 +284,6 @@ 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 free_netdev ( struct net_device *netdev ); struct net_device * find_netdev ( const char *name ); struct net_device * find_pci_netdev ( unsigned int busdevfn ); diff --git a/src/net/aoe.c b/src/net/aoe.c index 084a3d4d..36721df6 100644 --- a/src/net/aoe.c +++ b/src/net/aoe.c @@ -265,19 +265,6 @@ struct net_protocol aoe_protocol __net_protocol = { .rx = aoe_rx, }; -/** - * Forget reference to net_device - * - * @v ref Persistent reference - */ -static void aoe_forget_netdev ( struct reference *ref ) { - struct aoe_session *aoe - = container_of ( ref, struct aoe_session, netdev_ref ); - - aoe->netdev = NULL; - ref_del ( &aoe->netdev_ref ); -} - /** * Open AoE session * @@ -288,8 +275,6 @@ void aoe_open ( struct aoe_session *aoe ) { sizeof ( aoe->target ) ); aoe->tag = AOE_TAG_MAGIC; aoe->timer.expired = aoe_timer_expired; - aoe->netdev_ref.forget = aoe_forget_netdev; - ref_add ( &aoe->netdev_ref, &aoe->netdev->references ); list_add ( &aoe->list, &aoe_sessions ); } @@ -299,8 +284,6 @@ void aoe_open ( struct aoe_session *aoe ) { * @v aoe AoE session */ void aoe_close ( struct aoe_session *aoe ) { - if ( aoe->netdev ) - ref_del ( &aoe->netdev_ref ); list_del ( &aoe->list ); } diff --git a/src/net/ipv4.c b/src/net/ipv4.c index a6fb65ed..e1219edb 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -30,8 +30,6 @@ struct list_head ipv4_miniroutes = LIST_HEAD_INIT ( ipv4_miniroutes ); /** List of fragment reassembly buffers */ static LIST_HEAD ( frag_buffers ); -static void ipv4_forget_netdev ( struct reference *ref ); - /** * Add IPv4 minirouting table entry * @@ -61,7 +59,7 @@ static struct ipv4_miniroute * add_ipv4_miniroute ( struct net_device *netdev, } /* Record routing information */ - miniroute->netdev = netdev; + miniroute->netdev = netdev_get ( netdev ); miniroute->address = address; miniroute->netmask = netmask; miniroute->gateway = gateway; @@ -75,10 +73,6 @@ static struct ipv4_miniroute * add_ipv4_miniroute ( struct net_device *netdev, list_add ( &miniroute->list, &ipv4_miniroutes ); } - /* Record reference to net_device */ - miniroute->netdev_ref.forget = ipv4_forget_netdev; - ref_add ( &miniroute->netdev_ref, &netdev->references ); - return miniroute; } @@ -95,23 +89,11 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) { DBG ( "gw %s ", inet_ntoa ( miniroute->gateway ) ); DBG ( "via %s\n", miniroute->netdev->name ); - ref_del ( &miniroute->netdev_ref ); + netdev_put ( miniroute->netdev ); list_del ( &miniroute->list ); free ( miniroute ); } -/** - * Forget reference to net_device - * - * @v ref Persistent reference - */ -static void ipv4_forget_netdev ( struct reference *ref ) { - struct ipv4_miniroute *miniroute - = container_of ( ref, struct ipv4_miniroute, netdev_ref ); - - del_ipv4_miniroute ( miniroute ); -} - /** * Add IPv4 interface * diff --git a/src/net/ipv6.c b/src/net/ipv6.c index 98e1631d..86074065 100644 --- a/src/net/ipv6.c +++ b/src/net/ipv6.c @@ -32,8 +32,6 @@ struct ipv6_miniroute { /* Network device */ struct net_device *netdev; - /** Reference to network device */ - struct reference netdev_ref; /* Destination prefix */ struct in6_addr prefix; @@ -48,8 +46,6 @@ struct ipv6_miniroute { /** List of IPv6 miniroutes */ static LIST_HEAD ( miniroutes ); -static void ipv6_forget_netdev ( struct reference *ref ); - /** * Add IPv6 minirouting table entry * @@ -69,7 +65,7 @@ static struct ipv6_miniroute * add_ipv6_miniroute ( struct net_device *netdev, miniroute = malloc ( sizeof ( *miniroute ) ); if ( miniroute ) { /* Record routing information */ - miniroute->netdev = netdev; + miniroute->netdev = netdev_get ( netdev ); miniroute->prefix = prefix; miniroute->prefix_len = prefix_len; miniroute->address = address; @@ -81,10 +77,6 @@ static struct ipv6_miniroute * add_ipv6_miniroute ( struct net_device *netdev, } else { list_add ( &miniroute->list, &miniroutes ); } - - /* Record reference to net_device */ - miniroute->netdev_ref.forget = ipv6_forget_netdev; - ref_add ( &miniroute->netdev_ref, &netdev->references ); } return miniroute; @@ -96,23 +88,11 @@ static struct ipv6_miniroute * add_ipv6_miniroute ( struct net_device *netdev, * @v miniroute Routing table entry */ static void del_ipv6_miniroute ( struct ipv6_miniroute *miniroute ) { - ref_del ( &miniroute->netdev_ref ); + netdev_put ( miniroute->netdev ); list_del ( &miniroute->list ); free ( miniroute ); } -/** - * Forget reference to net_device - * - * @v ref Persistent reference - */ -static void ipv6_forget_netdev ( struct reference *ref ) { - struct ipv6_miniroute *miniroute - = container_of ( ref, struct ipv6_miniroute, netdev_ref ); - - del_ipv6_miniroute ( miniroute ); -} - /** * Add IPv6 interface * diff --git a/src/net/netdevice.c b/src/net/netdevice.c index ddcb296f..294f0786 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -115,6 +115,19 @@ void netdev_tx_complete_next ( struct net_device *netdev ) { } } +/** + * Flush device's transmit queue + * + * @v netdev Network device + */ +static void netdev_tx_flush ( struct net_device *netdev ) { + + /* Discard any packets in the TX queue */ + while ( ! list_empty ( &netdev->tx_queue ) ) { + netdev_tx_complete_next ( netdev ); + } +} + /** * Add packet to receive queue * @@ -168,6 +181,36 @@ struct io_buffer * netdev_rx_dequeue ( struct net_device *netdev ) { return NULL; } +/** + * Flush device's receive queue + * + * @v netdev Network device + */ +static void netdev_rx_flush ( struct net_device *netdev ) { + struct io_buffer *iobuf; + + /* Discard any packets in the RX queue */ + while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) { + DBGC ( netdev, "NETDEV %p discarding received %p\n", + netdev, iobuf ); + free_iob ( iobuf ); + } +} + +/** + * Free network device + * + * @v refcnt Network device reference counter + */ +static void free_netdev ( struct refcnt *refcnt ) { + struct net_device *netdev = + container_of ( refcnt, struct net_device, refcnt ); + + netdev_tx_flush ( netdev ); + netdev_rx_flush ( netdev ); + free ( netdev ); +} + /** * Allocate network device * @@ -184,7 +227,7 @@ struct net_device * alloc_netdev ( size_t priv_size ) { netdev = malloc ( total_len ); if ( netdev ) { memset ( netdev, 0, total_len ); - INIT_LIST_HEAD ( &netdev->references ); + netdev->refcnt.free = free_netdev; INIT_LIST_HEAD ( &netdev->tx_queue ); INIT_LIST_HEAD ( &netdev->rx_queue ); netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) ); @@ -209,6 +252,7 @@ int register_netdev ( struct net_device *netdev ) { ifindex++ ); /* Add to device list */ + netdev_get ( netdev ); list_add_tail ( &netdev->list, &net_devices ); DBGC ( netdev, "NETDEV %p registered as %s (phys %s hwaddr %s)\n", netdev, netdev->name, netdev->dev->name, @@ -247,7 +291,6 @@ int netdev_open ( struct net_device *netdev ) { * @v netdev Network device */ void netdev_close ( struct net_device *netdev ) { - struct io_buffer *iobuf; /* Do nothing if device is already closed */ if ( ! ( netdev->state & NETDEV_OPEN ) ) @@ -258,17 +301,9 @@ void netdev_close ( struct net_device *netdev ) { /* Close the device */ netdev->close ( netdev ); - /* Discard any packets in the TX queue */ - while ( ! list_empty ( &netdev->tx_queue ) ) { - netdev_tx_complete_next ( netdev ); - } - - /* Discard any packets in the RX queue */ - while ( ( iobuf = netdev_rx_dequeue ( netdev ) ) ) { - DBGC ( netdev, "NETDEV %p discarding received %p\n", - netdev, iobuf ); - free_iob ( iobuf ); - } + /* Flush TX and RX queues */ + netdev_tx_flush ( netdev ); + netdev_rx_flush ( netdev ); /* Mark as closed */ netdev->state &= ~NETDEV_OPEN; @@ -286,23 +321,12 @@ void unregister_netdev ( struct net_device *netdev ) { /* Ensure device is closed */ netdev_close ( netdev ); - /* Kill off any persistent references to this device */ - forget_references ( &netdev->references ); - /* Remove from device list */ list_del ( &netdev->list ); + netdev_put ( netdev ); DBGC ( netdev, "NETDEV %p unregistered\n", netdev ); } -/** - * Free network device - * - * @v netdev Network device - */ -void free_netdev ( struct net_device *netdev ) { - free ( netdev ); -} - /** * Get network device by name * diff --git a/src/net/udp.c b/src/net/udp.c index ca0c816f..404dd727 100644 --- a/src/net/udp.c +++ b/src/net/udp.c @@ -140,7 +140,7 @@ static int udp_open_common ( struct xfer_interface *xfer, * @ret rc Return status code */ int udp_open ( struct xfer_interface *xfer, struct sockaddr *peer, - struct sockaddr *local ) { + struct sockaddr *local ) { return udp_open_common ( xfer, peer, local, 0 ); } diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index 2caea335..4ecb17bf 100644 --- a/src/net/udp/dhcp.c +++ b/src/net/udp/dhcp.c @@ -493,6 +493,8 @@ udp_to_dhcp ( struct udp_connection *conn ) { return container_of ( conn, struct dhcp_session, udp ); } +#if 0 + /** * Mark DHCP session as complete * @@ -515,9 +517,6 @@ static void dhcp_done ( struct dhcp_session *dhcp, int rc ) { /* Close UDP connection */ udp_close ( &dhcp->udp ); - /* Release reference on net device */ - ref_del ( &dhcp->netdev_ref ); - /* Mark async operation as complete */ async_done ( &dhcp->async, rc ); } @@ -705,19 +704,6 @@ static struct udp_operations dhcp_udp_operations = { .newdata = dhcp_newdata, }; -/** - * Forget reference to net_device - * - * @v ref Persistent reference - */ -static void dhcp_forget_netdev ( struct reference *ref ) { - struct dhcp_session *dhcp - = container_of ( ref, struct dhcp_session, netdev_ref ); - - /* Kill DHCP session immediately */ - dhcp_done ( dhcp, -ENETUNREACH ); -} - /** * Initiate DHCP on a network interface * @@ -742,13 +728,12 @@ int start_dhcp ( struct dhcp_session *dhcp, struct async *parent ) { if ( ( rc = udp_open ( &dhcp->udp, htons ( BOOTPC_PORT ) ) ) != 0 ) return rc; - /* Add persistent reference to net device */ - dhcp->netdev_ref.forget = dhcp_forget_netdev; - ref_add ( &dhcp->netdev_ref, &dhcp->netdev->references ); - /* Proof of concept: just send a single DHCPDISCOVER */ dhcp_send_request ( dhcp ); async_init ( &dhcp->async, &default_async_operations, parent ); return 0; } + + +#endif