mirror of
https://github.com/ipxe/ipxe
synced 2025-12-21 12:30:20 +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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user