structures.
DHCP still broken and #if 0'd out.
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;
}
undi->flags &= ~UNDI_FL_STARTED;
/* Free network device */
- free_netdev ( netdev );
+ netdev_put ( netdev );
DBGC ( undinic, "UNDINIC %p removed\n", undinic );
}
+++ /dev/null
-/*
- * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * 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 <assert.h>
-#include <gpxe/hotplug.h>
-
-/** @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 ) );
-}
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;
}
unregister_netdev ( netdev );
disable ( nic, hwdev );
- free_netdev ( netdev );
+ netdev_put ( netdev );
legacy_registered = 0;
}
unregister_netdev ( netdev );
pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL );
- free_netdev ( netdev );
+ netdev_put ( netdev );
}
/**************************************************************************
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,
err:
/* Free net device */
- free_netdev ( netdev );
+ netdev_put ( netdev );
return rc;
}
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 );
/* 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;
}
nvo_unregister ( &rtl->nvo );
unregister_netdev ( netdev );
rtl_reset ( rtl );
- free_netdev ( netdev );
+ netdev_put ( netdev );
}
static struct pci_device_id rtl8139_nics[] = {
#include <gpxe/retry.h>
#include <gpxe/async.h>
#include <gpxe/ata.h>
-#include <gpxe/hotplug.h>
/** An AoE ATA command */
struct aoecmd {
/** Network device */
struct net_device *netdev;
- /** Reference to network device */
- struct reference netdev_ref;
/** Major number */
uint16_t major;
#include <gpxe/udp.h>
#include <gpxe/async.h>
#include <gpxe/retry.h>
-#include <gpxe/hotplug.h>
/** BOOTP/DHCP server port */
#define BOOTPS_PORT 67
struct dhcp_option_block options[NUM_OPT_BLOCKS];
};
+struct udp_connection {};
+
/** A DHCP session */
struct dhcp_session {
/** UDP connection for this 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;
+++ /dev/null
-#ifndef _GPXE_HOTPLUG_H
-#define _GPXE_HOTPLUG_H
-
-/** @file
- *
- * Hotplug support
- *
- */
-
-#include <gpxe/list.h>
-
-/**
- * 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 */
#include <ip.h>
#include <gpxe/retry.h>
-#include <gpxe/hotplug.h>
/* IP constants */
/** Network device */
struct net_device *netdev;
- /** Reference to network device */
- struct reference netdev_ref;
/** IPv4 address */
struct in_addr address;
#include <stdint.h>
#include <gpxe/list.h>
#include <gpxe/tables.h>
-#include <gpxe/hotplug.h>
+#include <gpxe/refcnt.h>
struct io_buffer;
struct net_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;
- /** List of persistent reference holders */
- struct list_head references;
/** Open network device
*
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 );
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 );
.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
*
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 );
}
* @v aoe AoE session
*/
void aoe_close ( struct aoe_session *aoe ) {
- if ( aoe->netdev )
- ref_del ( &aoe->netdev_ref );
list_del ( &aoe->list );
}
/** List of fragment reassembly buffers */
static LIST_HEAD ( frag_buffers );
-static void ipv4_forget_netdev ( struct reference *ref );
-
/**
* Add IPv4 minirouting table entry
*
}
/* Record routing information */
- miniroute->netdev = netdev;
+ miniroute->netdev = netdev_get ( netdev );
miniroute->address = address;
miniroute->netmask = netmask;
miniroute->gateway = gateway;
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;
}
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
*
/* Network device */
struct net_device *netdev;
- /** Reference to network device */
- struct reference netdev_ref;
/* Destination prefix */
struct in6_addr prefix;
/** List of IPv6 miniroutes */
static LIST_HEAD ( miniroutes );
-static void ipv6_forget_netdev ( struct reference *ref );
-
/**
* Add IPv6 minirouting table entry
*
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;
} 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;
* @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
*
}
}
+/**
+ * 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
*
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
*
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 ) );
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,
* @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 ) )
/* 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;
/* 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
*
* @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 );
}
return container_of ( conn, struct dhcp_session, udp );
}
+#if 0
+
/**
* Mark DHCP session as complete
*
/* 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 );
}
.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
*
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