mirror of
https://github.com/ipxe/ipxe
synced 2026-02-14 02:31:26 +03:00
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.
This commit is contained in:
@@ -394,7 +394,6 @@ static int undinet_transmit ( struct net_device *netdev,
|
|||||||
* Poll for received packets
|
* Poll for received packets
|
||||||
*
|
*
|
||||||
* @v netdev Network device
|
* @v netdev Network device
|
||||||
* @v rx_quota Maximum number of packets to receive
|
|
||||||
*
|
*
|
||||||
* Fun, fun, fun. UNDI drivers don't use polling; they use
|
* Fun, fun, fun. UNDI drivers don't use polling; they use
|
||||||
* interrupts. We therefore cheat and pretend that an interrupt has
|
* 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
|
* of installing a genuine interrupt service routine and dealing with
|
||||||
* the wonderful 8259 Programmable Interrupt Controller. Joy.
|
* 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 undi_nic *undinic = netdev->priv;
|
||||||
struct s_PXENV_UNDI_ISR undi_isr;
|
struct s_PXENV_UNDI_ISR undi_isr;
|
||||||
struct io_buffer *iobuf = NULL;
|
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 */
|
/* Run through the ISR loop */
|
||||||
while ( rx_quota ) {
|
while ( 1 ) {
|
||||||
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
|
if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
|
||||||
sizeof ( undi_isr ) ) ) != 0 )
|
sizeof ( undi_isr ) ) ) != 0 )
|
||||||
break;
|
break;
|
||||||
@@ -487,7 +486,6 @@ static void undinet_poll ( struct net_device *netdev, unsigned int rx_quota ) {
|
|||||||
/* Whole packet received; deliver it */
|
/* Whole packet received; deliver it */
|
||||||
netdev_rx ( netdev, iobuf );
|
netdev_rx ( netdev, iobuf );
|
||||||
iobuf = NULL;
|
iobuf = NULL;
|
||||||
--rx_quota;
|
|
||||||
/* Etherboot 5.4 fails to return all packets
|
/* Etherboot 5.4 fails to return all packets
|
||||||
* under mild load; pretend it retriggered.
|
* 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 );
|
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
|
* Probe UNDI device
|
||||||
*
|
*
|
||||||
@@ -622,6 +643,7 @@ int undinet_probe ( struct undi_device *undi ) {
|
|||||||
netdev = alloc_etherdev ( sizeof ( *undinic ) );
|
netdev = alloc_etherdev ( sizeof ( *undinic ) );
|
||||||
if ( ! netdev )
|
if ( ! netdev )
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
netdev_init ( netdev, &undinet_operations );
|
||||||
undinic = netdev->priv;
|
undinic = netdev->priv;
|
||||||
undi_set_drvdata ( undi, netdev );
|
undi_set_drvdata ( undi, netdev );
|
||||||
netdev->dev = &undi->dev;
|
netdev->dev = &undi->dev;
|
||||||
@@ -685,12 +707,6 @@ int undinet_probe ( struct undi_device *undi ) {
|
|||||||
undinic->hacks |= UNDI_HACK_EB54;
|
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 */
|
/* Register network device */
|
||||||
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
||||||
goto err_register;
|
goto err_register;
|
||||||
@@ -716,6 +732,7 @@ int undinet_probe ( struct undi_device *undi ) {
|
|||||||
undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
|
undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
|
||||||
sizeof ( stop_undi ) );
|
sizeof ( stop_undi ) );
|
||||||
err_start_undi:
|
err_start_undi:
|
||||||
|
netdev_nullify ( netdev );
|
||||||
netdev_put ( netdev );
|
netdev_put ( netdev );
|
||||||
undi_set_drvdata ( undi, NULL );
|
undi_set_drvdata ( undi, NULL );
|
||||||
return rc;
|
return rc;
|
||||||
@@ -751,6 +768,7 @@ void undinet_remove ( struct undi_device *undi ) {
|
|||||||
undi->flags &= ~UNDI_FL_STARTED;
|
undi->flags &= ~UNDI_FL_STARTED;
|
||||||
|
|
||||||
/* Free network device */
|
/* Free network device */
|
||||||
|
netdev_nullify ( netdev );
|
||||||
netdev_put ( netdev );
|
netdev_put ( netdev );
|
||||||
|
|
||||||
DBGC ( undinic, "UNDINIC %p removed\n", undinic );
|
DBGC ( undinic, "UNDINIC %p removed\n", undinic );
|
||||||
|
|||||||
@@ -36,13 +36,10 @@ static int legacy_transmit ( struct net_device *netdev, struct io_buffer *iobuf
|
|||||||
return 0;
|
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 nic *nic = netdev->priv;
|
||||||
struct io_buffer *iobuf;
|
struct io_buffer *iobuf;
|
||||||
|
|
||||||
if ( ! rx_quota )
|
|
||||||
return;
|
|
||||||
|
|
||||||
iobuf = alloc_iob ( ETH_FRAME_LEN );
|
iobuf = alloc_iob ( ETH_FRAME_LEN );
|
||||||
if ( ! iobuf )
|
if ( ! iobuf )
|
||||||
return;
|
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 ) {
|
static int legacy_open ( struct net_device *netdev __unused ) {
|
||||||
struct nic *nic = netdev->priv;
|
/* Nothing to do */
|
||||||
|
|
||||||
nic->nic_op->irq ( nic, ENABLE );
|
|
||||||
return 0;
|
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;
|
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,
|
int legacy_probe ( void *hwdev,
|
||||||
void ( * set_drvdata ) ( void *hwdev, void *priv ),
|
void ( * set_drvdata ) ( void *hwdev, void *priv ),
|
||||||
struct device *dev,
|
struct device *dev,
|
||||||
@@ -84,27 +91,21 @@ int legacy_probe ( void *hwdev,
|
|||||||
netdev = alloc_etherdev ( 0 );
|
netdev = alloc_etherdev ( 0 );
|
||||||
if ( ! netdev )
|
if ( ! netdev )
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
netdev_init ( netdev, &legacy_operations );
|
||||||
netdev->priv = &nic;
|
netdev->priv = &nic;
|
||||||
memset ( &nic, 0, sizeof ( nic ) );
|
memset ( &nic, 0, sizeof ( nic ) );
|
||||||
set_drvdata ( hwdev, netdev );
|
set_drvdata ( hwdev, netdev );
|
||||||
netdev->dev = dev;
|
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;
|
nic.node_addr = netdev->ll_addr;
|
||||||
|
|
||||||
if ( ! probe ( &nic, hwdev ) ) {
|
if ( ! probe ( &nic, hwdev ) ) {
|
||||||
netdev_put ( netdev );
|
rc = -ENODEV;
|
||||||
return -ENODEV;
|
goto err_probe;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( rc = register_netdev ( netdev ) ) != 0 ) {
|
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
||||||
disable ( &nic, hwdev );
|
goto err_register;
|
||||||
netdev_put ( netdev );
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do not remove this message */
|
/* Do not remove this message */
|
||||||
printf ( "WARNING: Using legacy NIC wrapper on %s\n",
|
printf ( "WARNING: Using legacy NIC wrapper on %s\n",
|
||||||
@@ -112,6 +113,13 @@ int legacy_probe ( void *hwdev,
|
|||||||
|
|
||||||
legacy_registered = 1;
|
legacy_registered = 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_register:
|
||||||
|
disable ( &nic, hwdev );
|
||||||
|
err_probe:
|
||||||
|
netdev_nullify ( netdev );
|
||||||
|
netdev_put ( netdev );
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void legacy_remove ( void *hwdev,
|
void legacy_remove ( void *hwdev,
|
||||||
@@ -122,6 +130,7 @@ void legacy_remove ( void *hwdev,
|
|||||||
|
|
||||||
unregister_netdev ( netdev );
|
unregister_netdev ( netdev );
|
||||||
disable ( nic, hwdev );
|
disable ( nic, hwdev );
|
||||||
|
netdev_nullify ( netdev );
|
||||||
netdev_put ( netdev );
|
netdev_put ( netdev );
|
||||||
legacy_registered = 0;
|
legacy_registered = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,35 +112,34 @@ static int pnic_api_check ( uint16_t api_version ) {
|
|||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
POLL - Wait for a frame
|
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 pnic *pnic = netdev->priv;
|
||||||
struct io_buffer *iobuf;
|
struct io_buffer *iobuf;
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
uint16_t qlen;
|
uint16_t qlen;
|
||||||
|
|
||||||
/* Fetch all available packets */
|
/* Fetch all available packets */
|
||||||
while ( rx_quota ) {
|
while ( 1 ) {
|
||||||
if ( pnic_command ( pnic, PNIC_CMD_RECV_QLEN, NULL, 0,
|
if ( pnic_command ( pnic, PNIC_CMD_RECV_QLEN, NULL, 0,
|
||||||
&qlen, sizeof ( qlen ), NULL )
|
&qlen, sizeof ( qlen ), NULL )
|
||||||
!= PNIC_STATUS_OK )
|
!= PNIC_STATUS_OK )
|
||||||
break;
|
return;
|
||||||
if ( qlen == 0 )
|
if ( qlen == 0 )
|
||||||
break;
|
return;
|
||||||
iobuf = alloc_iob ( ETH_FRAME_LEN );
|
iobuf = alloc_iob ( ETH_FRAME_LEN );
|
||||||
if ( ! iobuf ) {
|
if ( ! iobuf ) {
|
||||||
DBG ( "could not allocate buffer\n" );
|
DBG ( "could not allocate buffer\n" );
|
||||||
netdev_rx_err ( netdev, NULL, -ENOMEM );
|
netdev_rx_err ( netdev, NULL, -ENOMEM );
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
if ( pnic_command ( pnic, PNIC_CMD_RECV, NULL, 0,
|
if ( pnic_command ( pnic, PNIC_CMD_RECV, NULL, 0,
|
||||||
iobuf->data, ETH_FRAME_LEN, &length )
|
iobuf->data, ETH_FRAME_LEN, &length )
|
||||||
!= PNIC_STATUS_OK ) {
|
!= PNIC_STATUS_OK ) {
|
||||||
netdev_rx_err ( netdev, iobuf, -EIO );
|
netdev_rx_err ( netdev, iobuf, -EIO );
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
iob_put ( iobuf, length );
|
iob_put ( iobuf, length );
|
||||||
netdev_rx ( netdev, iobuf );
|
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
|
OPEN - Open network device
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
static int pnic_open ( struct net_device *netdev ) {
|
static int pnic_open ( struct net_device *netdev __unused ) {
|
||||||
struct pnic *pnic = netdev->priv;
|
/* Nothing to do */
|
||||||
static const uint8_t enable = 1;
|
|
||||||
|
|
||||||
/* Enable interrupts */
|
|
||||||
pnic_command ( pnic, PNIC_CMD_MASK_IRQ, &enable,
|
|
||||||
sizeof ( enable ), NULL, 0, NULL );
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
CLOSE - Close network device
|
CLOSE - Close network device
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
static void pnic_close ( struct net_device *netdev ) {
|
static void pnic_close ( struct net_device *netdev __unused ) {
|
||||||
struct pnic *pnic = netdev->priv;
|
/* Nothing to do */
|
||||||
static const uint8_t disable = 0;
|
|
||||||
|
|
||||||
/* Disable interrupts */
|
|
||||||
pnic_command ( pnic, PNIC_CMD_MASK_IRQ, &disable,
|
|
||||||
sizeof ( disable ), NULL, 0, NULL );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
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
|
DISABLE - Turn off ethernet interface
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
@@ -196,6 +206,7 @@ static void pnic_remove ( struct pci_device *pci ) {
|
|||||||
|
|
||||||
unregister_netdev ( netdev );
|
unregister_netdev ( netdev );
|
||||||
pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL );
|
pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL );
|
||||||
|
netdev_nullify ( netdev );
|
||||||
netdev_put ( netdev );
|
netdev_put ( netdev );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,6 +225,7 @@ static int pnic_probe ( struct pci_device *pci,
|
|||||||
netdev = alloc_etherdev ( sizeof ( *pnic ) );
|
netdev = alloc_etherdev ( sizeof ( *pnic ) );
|
||||||
if ( ! netdev )
|
if ( ! netdev )
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
netdev_init ( netdev, &pnic_operations );
|
||||||
pnic = netdev->priv;
|
pnic = netdev->priv;
|
||||||
pci_set_drvdata ( pci, netdev );
|
pci_set_drvdata ( pci, netdev );
|
||||||
netdev->dev = &pci->dev;
|
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,
|
status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0,
|
||||||
netdev->ll_addr, ETH_ALEN, NULL );
|
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 */
|
/* Register network device */
|
||||||
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
||||||
goto err;
|
goto err;
|
||||||
@@ -252,6 +258,7 @@ static int pnic_probe ( struct pci_device *pci,
|
|||||||
|
|
||||||
err:
|
err:
|
||||||
/* Free net device */
|
/* Free net device */
|
||||||
|
netdev_nullify ( netdev );
|
||||||
netdev_put ( netdev );
|
netdev_put ( netdev );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -302,12 +302,6 @@ static struct nvo_fragment rtl_nvo_fragments[] = {
|
|||||||
*/
|
*/
|
||||||
static void rtl_reset ( struct rtl8139_nic *rtl ) {
|
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 */
|
/* Reset chip */
|
||||||
outb ( CmdReset, rtl->ioaddr + ChipCmd );
|
outb ( CmdReset, rtl->ioaddr + ChipCmd );
|
||||||
mdelay ( 10 );
|
mdelay ( 10 );
|
||||||
@@ -346,9 +340,6 @@ static int rtl_open ( struct net_device *netdev ) {
|
|||||||
outl ( ( ( TX_DMA_BURST << 8 ) | ( TX_IPG << 24 ) ),
|
outl ( ( ( TX_DMA_BURST << 8 ) | ( TX_IPG << 24 ) ),
|
||||||
rtl->ioaddr + TxConfig );
|
rtl->ioaddr + TxConfig );
|
||||||
|
|
||||||
/* Enable interrupts */
|
|
||||||
outw ( ( ROK | RER | TOK | TER ), rtl->ioaddr + IntrMask );
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,13 +391,12 @@ static int rtl_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Poll for received packets
|
* Poll for received packets
|
||||||
*
|
*
|
||||||
* @v netdev Network device
|
* @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;
|
struct rtl8139_nic *rtl = netdev->priv;
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
unsigned int tsad;
|
unsigned int tsad;
|
||||||
@@ -433,7 +423,7 @@ static void rtl_poll ( struct net_device *netdev, unsigned int rx_quota ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Handle received packets */
|
/* Handle received packets */
|
||||||
while ( rx_quota && ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ){
|
while ( ! ( inw ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ) {
|
||||||
rx_status = * ( ( uint16_t * )
|
rx_status = * ( ( uint16_t * )
|
||||||
( rtl->rx.ring + rtl->rx.offset ) );
|
( rtl->rx.ring + rtl->rx.offset ) );
|
||||||
rx_len = * ( ( uint16_t * )
|
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 );
|
rtl->rx.ring, wrapped_len );
|
||||||
|
|
||||||
netdev_rx ( netdev, rx_iob );
|
netdev_rx ( netdev, rx_iob );
|
||||||
rx_quota--;
|
|
||||||
} else {
|
} else {
|
||||||
DBG ( "RX bad packet (status %#04x len %d)\n",
|
DBG ( "RX bad packet (status %#04x len %d)\n",
|
||||||
rx_status, rx_len );
|
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
|
* Probe PCI device
|
||||||
*
|
*
|
||||||
@@ -490,6 +501,7 @@ static int rtl_probe ( struct pci_device *pci,
|
|||||||
netdev = alloc_etherdev ( sizeof ( *rtl ) );
|
netdev = alloc_etherdev ( sizeof ( *rtl ) );
|
||||||
if ( ! netdev )
|
if ( ! netdev )
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
netdev_init ( netdev, &rtl_operations );
|
||||||
rtl = netdev->priv;
|
rtl = netdev->priv;
|
||||||
pci_set_drvdata ( pci, netdev );
|
pci_set_drvdata ( pci, netdev );
|
||||||
netdev->dev = &pci->dev;
|
netdev->dev = &pci->dev;
|
||||||
@@ -504,12 +516,6 @@ static int rtl_probe ( struct pci_device *pci,
|
|||||||
rtl_init_eeprom ( rtl );
|
rtl_init_eeprom ( rtl );
|
||||||
nvs_read ( &rtl->eeprom.nvs, EE_MAC, netdev->ll_addr, ETH_ALEN );
|
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 */
|
/* Register network device */
|
||||||
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
||||||
goto err_register_netdev;
|
goto err_register_netdev;
|
||||||
@@ -526,6 +532,7 @@ static int rtl_probe ( struct pci_device *pci,
|
|||||||
unregister_netdev ( netdev );
|
unregister_netdev ( netdev );
|
||||||
err_register_netdev:
|
err_register_netdev:
|
||||||
rtl_reset ( rtl );
|
rtl_reset ( rtl );
|
||||||
|
netdev_nullify ( netdev );
|
||||||
netdev_put ( netdev );
|
netdev_put ( netdev );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -543,6 +550,7 @@ static void rtl_remove ( struct pci_device *pci ) {
|
|||||||
nvo_unregister ( &rtl->nvo );
|
nvo_unregister ( &rtl->nvo );
|
||||||
unregister_netdev ( netdev );
|
unregister_netdev ( netdev );
|
||||||
rtl_reset ( rtl );
|
rtl_reset ( rtl );
|
||||||
|
netdev_nullify ( netdev );
|
||||||
netdev_put ( netdev );
|
netdev_put ( netdev );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,41 +128,8 @@ struct ll_protocol {
|
|||||||
const uint8_t *ll_broadcast;
|
const uint8_t *ll_broadcast;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/** Network device operations */
|
||||||
* Network device statistics
|
struct net_device_operations {
|
||||||
*
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
/** Open network device
|
/** Open network device
|
||||||
*
|
*
|
||||||
* @v netdev Network device
|
* @v netdev Network device
|
||||||
@@ -199,20 +166,62 @@ struct net_device {
|
|||||||
* This method is guaranteed to be called only when the device
|
* This method is guaranteed to be called only when the device
|
||||||
* is open.
|
* is open.
|
||||||
*/
|
*/
|
||||||
int ( * transmit ) ( struct net_device *netdev, struct io_buffer *iobuf );
|
int ( * transmit ) ( struct net_device *netdev,
|
||||||
/** Poll for received packet
|
struct io_buffer *iobuf );
|
||||||
|
/** Poll for completed and received packets
|
||||||
*
|
*
|
||||||
* @v netdev Network device
|
* @v netdev Network device
|
||||||
* @v rx_quota Maximum number of packets to receive
|
|
||||||
*
|
*
|
||||||
* This method should cause the hardware to check for received
|
* This method should cause the hardware to check for
|
||||||
* packets. Any received packets should be delivered via
|
* completed transmissions and received packets. Any received
|
||||||
* netdev_rx(), up to a maximum of @c rx_quota packets.
|
* packets should be delivered via netdev_rx().
|
||||||
*
|
*
|
||||||
* This method is guaranteed to be called only when the device
|
* This method is guaranteed to be called only when the device
|
||||||
* is open.
|
* 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 */
|
/** Link-layer protocol */
|
||||||
struct ll_protocol *ll_protocol;
|
struct ll_protocol *ll_protocol;
|
||||||
@@ -248,6 +257,30 @@ struct net_device {
|
|||||||
#define __net_protocol __table ( struct net_protocol, net_protocols, 01 )
|
#define __net_protocol __table ( struct net_protocol, net_protocols, 01 )
|
||||||
|
|
||||||
extern struct list_head net_devices;
|
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
|
* 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 ( struct net_device *netdev, struct io_buffer *iobuf );
|
||||||
extern void netdev_rx_err ( struct net_device *netdev,
|
extern void netdev_rx_err ( struct net_device *netdev,
|
||||||
struct io_buffer *iobuf, int rc );
|
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 io_buffer * netdev_rx_dequeue ( struct net_device *netdev );
|
||||||
extern struct net_device * alloc_netdev ( size_t priv_size );
|
extern struct net_device * alloc_netdev ( size_t priv_size );
|
||||||
extern int register_netdev ( struct net_device *netdev );
|
extern int register_netdev ( struct net_device *netdev );
|
||||||
extern int netdev_open ( struct net_device *netdev );
|
extern int netdev_open ( struct net_device *netdev );
|
||||||
extern void netdev_close ( struct net_device *netdev );
|
extern void netdev_close ( struct net_device *netdev );
|
||||||
extern void unregister_netdev ( 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 ( const char *name );
|
||||||
extern struct net_device * find_netdev_by_location ( unsigned int bus_type,
|
extern struct net_device * find_netdev_by_location ( unsigned int bus_type,
|
||||||
unsigned int location );
|
unsigned int location );
|
||||||
|
|||||||
@@ -69,7 +69,13 @@ void pxe_set_netdev ( struct net_device *netdev ) {
|
|||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int pxe_netdev_open ( void ) {
|
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 ) {
|
static void pxe_netdev_close ( void ) {
|
||||||
|
netdev_irq ( pxe_netdev, 0 );
|
||||||
netdev_close ( pxe_netdev );
|
netdev_close ( pxe_netdev );
|
||||||
undi_tx_count = 0;
|
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
|
/* Call poll(). This should acknowledge the device
|
||||||
* interrupt and queue up any received packet.
|
* interrupt and queue up any received packet.
|
||||||
*/
|
*/
|
||||||
if ( netdev_poll ( pxe_netdev, -1U ) ) {
|
netdev_poll ( pxe_netdev );
|
||||||
/* Packet waiting in queue */
|
|
||||||
DBG ( " OURS" );
|
/* Disable interrupts to avoid interrupt storm */
|
||||||
undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
|
netdev_irq ( pxe_netdev, 0 );
|
||||||
} else {
|
|
||||||
DBG ( " NOT_OURS" );
|
/* Always say it was ours for the sake of simplicity */
|
||||||
undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
|
undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case PXENV_UNDI_ISR_IN_PROCESS :
|
case PXENV_UNDI_ISR_IN_PROCESS :
|
||||||
case PXENV_UNDI_ISR_IN_GET_NEXT :
|
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 ) {
|
if ( ! iobuf ) {
|
||||||
/* No more packets remaining */
|
/* No more packets remaining */
|
||||||
undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
|
undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
|
||||||
|
/* Re-enable interrupts */
|
||||||
|
netdev_irq ( pxe_netdev, 1 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ int netdev_tx ( struct net_device *netdev, struct io_buffer *iobuf ) {
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ( rc = netdev->transmit ( netdev, iobuf ) ) != 0 )
|
if ( ( rc = netdev->op->transmit ( netdev, iobuf ) ) != 0 )
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
return 0;
|
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 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
|
* Polls the network device for completed transmissions and received
|
||||||
* packets will be added to the RX packet queue via netdev_rx().
|
* 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 )
|
if ( netdev->state & NETDEV_OPEN )
|
||||||
netdev->poll ( netdev, rx_quota );
|
netdev->op->poll ( netdev );
|
||||||
|
|
||||||
return ( ! list_empty ( &netdev->rx_queue ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -317,7 +313,7 @@ int netdev_open ( struct net_device *netdev ) {
|
|||||||
DBGC ( netdev, "NETDEV %p opening\n", netdev );
|
DBGC ( netdev, "NETDEV %p opening\n", netdev );
|
||||||
|
|
||||||
/* Open the device */
|
/* Open the device */
|
||||||
if ( ( rc = netdev->open ( netdev ) ) != 0 )
|
if ( ( rc = netdev->op->open ( netdev ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* Mark as opened */
|
/* Mark as opened */
|
||||||
@@ -339,7 +335,7 @@ void netdev_close ( struct net_device *netdev ) {
|
|||||||
DBGC ( netdev, "NETDEV %p closing\n", netdev );
|
DBGC ( netdev, "NETDEV %p closing\n", netdev );
|
||||||
|
|
||||||
/* Close the device */
|
/* Close the device */
|
||||||
netdev->close ( netdev );
|
netdev->op->close ( netdev );
|
||||||
|
|
||||||
/* Flush TX and RX queues */
|
/* Flush TX and RX queues */
|
||||||
netdev_tx_flush ( netdev );
|
netdev_tx_flush ( netdev );
|
||||||
@@ -367,6 +363,15 @@ void unregister_netdev ( struct net_device *netdev ) {
|
|||||||
DBGC ( netdev, "NETDEV %p unregistered\n", 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
|
* 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 ) {
|
list_for_each_entry ( netdev, &net_devices, list ) {
|
||||||
|
|
||||||
/* Poll for new packets */
|
/* Poll for new packets */
|
||||||
netdev_poll ( netdev, -1U );
|
netdev_poll ( netdev );
|
||||||
|
|
||||||
/* Process at most one received packet. Give priority
|
/* Process at most one received packet. Give priority
|
||||||
* to getting packets out of the NIC over processing
|
* to getting packets out of the NIC over processing
|
||||||
|
|||||||
57
src/net/nullnet.c
Normal file
57
src/net/nullnet.c
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006 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 <stdint.h>
|
||||||
|
#include <gpxe/iobuf.h>
|
||||||
|
#include <gpxe/netdevice.h>
|
||||||
|
|
||||||
|
/** @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,
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user