2009-09-24 09:59:20 -06:00
/* A network driver using virtio.
2007-10-22 11:03:37 +10:00
*
* Copyright 2007 Rusty Russell < rusty @ rustcorp . com . au > IBM Corporation
*
* 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
* ( at your option ) 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 . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
//#define DEBUG
# include <linux/netdevice.h>
# include <linux/etherdevice.h>
2008-04-18 11:21:42 +08:00
# include <linux/ethtool.h>
2007-10-22 11:03:37 +10:00
# include <linux/module.h>
# include <linux/virtio.h>
# include <linux/virtio_net.h>
# include <linux/scatterlist.h>
2009-01-25 18:06:26 -08:00
# include <linux/if_vlan.h>
2007-10-22 11:03:37 +10:00
2007-12-16 15:19:43 +02:00
static int napi_weight = 128 ;
module_param ( napi_weight , int , 0444 ) ;
2008-02-04 23:50:02 -05:00
static int csum = 1 , gso = 1 ;
module_param ( csum , bool , 0444 ) ;
module_param ( gso , bool , 0444 ) ;
2007-10-22 11:03:37 +10:00
/* FIXME: MTU in config. */
2009-01-25 18:06:26 -08:00
# define MAX_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN)
2008-11-16 22:41:34 -08:00
# define GOOD_COPY_LEN 128
2007-10-22 11:03:37 +10:00
2009-02-04 09:02:45 +00:00
# define VIRTNET_SEND_COMMAND_SG_MAX 2
2009-02-04 09:02:34 +00:00
2007-10-22 11:03:37 +10:00
struct virtnet_info
{
struct virtio_device * vdev ;
2009-02-04 09:02:34 +00:00
struct virtqueue * rvq , * svq , * cvq ;
2007-10-22 11:03:37 +10:00
struct net_device * dev ;
struct napi_struct napi ;
2009-01-19 17:09:49 -08:00
unsigned int status ;
2007-10-22 11:03:37 +10:00
/* Number of input buffers, and max we've ever had. */
unsigned int num , max ;
2008-04-18 11:24:27 +08:00
/* I like... big packets and I cannot lie! */
bool big_packets ;
2008-11-16 22:41:34 -08:00
/* Host will merge rx buffers for big packets (shake it! shake it!) */
bool mergeable_rx_bufs ;
2009-08-26 12:22:32 -07:00
/* Work struct for refilling if we run low on memory. */
struct delayed_work refill ;
2008-07-25 12:06:01 -05:00
/* Chain pages by the private ptr. */
struct page * pages ;
2007-10-22 11:03:37 +10:00
} ;
2009-09-24 09:59:19 -06:00
struct skb_vnet_hdr {
union {
struct virtio_net_hdr hdr ;
struct virtio_net_hdr_mrg_rxbuf mhdr ;
} ;
2009-09-24 09:59:20 -06:00
unsigned int num_sg ;
2009-09-24 09:59:19 -06:00
} ;
2010-01-29 03:20:04 +00:00
struct padded_vnet_hdr {
struct virtio_net_hdr hdr ;
/*
* virtio_net_hdr should be in a separated sg buffer because of a
* QEMU bug , and data sg buffer shares same page with this header sg .
* This padding makes next sg 16 byte aligned after virtio_net_hdr .
*/
char padding [ 6 ] ;
} ;
2009-09-24 09:59:19 -06:00
static inline struct skb_vnet_hdr * skb_vnet_hdr ( struct sk_buff * skb )
2007-10-22 11:03:37 +10:00
{
2009-09-24 09:59:19 -06:00
return ( struct skb_vnet_hdr * ) skb - > cb ;
2007-10-22 11:03:37 +10:00
}
2010-01-29 03:20:04 +00:00
/*
* private is used to chain pages for big packets , put the whole
* most recent used list in the beginning for reuse
*/
static void give_pages ( struct virtnet_info * vi , struct page * page )
2008-11-16 22:39:18 -08:00
{
2010-01-29 03:20:04 +00:00
struct page * end ;
2008-11-16 22:39:18 -08:00
2010-01-29 03:20:04 +00:00
/* Find end of list, sew whole thing into vi->pages. */
for ( end = page ; end - > private ; end = ( struct page * ) end - > private ) ;
end - > private = ( unsigned long ) vi - > pages ;
vi - > pages = page ;
2008-11-16 22:39:18 -08:00
}
2008-07-25 12:06:01 -05:00
static struct page * get_a_page ( struct virtnet_info * vi , gfp_t gfp_mask )
{
struct page * p = vi - > pages ;
2010-01-29 03:20:04 +00:00
if ( p ) {
2008-07-25 12:06:01 -05:00
vi - > pages = ( struct page * ) p - > private ;
2010-01-29 03:20:04 +00:00
/* clear private here, it is used to chain pages */
p - > private = 0 ;
} else
2008-07-25 12:06:01 -05:00
p = alloc_page ( gfp_mask ) ;
return p ;
}
2008-02-04 23:50:07 -05:00
static void skb_xmit_done ( struct virtqueue * svq )
2007-10-22 11:03:37 +10:00
{
2008-02-04 23:50:07 -05:00
struct virtnet_info * vi = svq - > vdev - > priv ;
2007-10-22 11:03:37 +10:00
2008-02-04 23:50:07 -05:00
/* Suppress further interrupts. */
svq - > vq_ops - > disable_cb ( svq ) ;
2008-05-26 17:48:13 +10:00
2008-06-08 20:51:55 +10:00
/* We were probably waiting for more output buffers. */
2007-10-22 11:03:37 +10:00
netif_wake_queue ( vi - > dev ) ;
}
2010-01-29 03:20:04 +00:00
static void set_skb_frag ( struct sk_buff * skb , struct page * page ,
unsigned int offset , unsigned int * len )
2007-10-22 11:03:37 +10:00
{
2010-01-29 03:20:04 +00:00
int i = skb_shinfo ( skb ) - > nr_frags ;
skb_frag_t * f ;
f = & skb_shinfo ( skb ) - > frags [ i ] ;
f - > size = min ( ( unsigned ) PAGE_SIZE - offset , * len ) ;
f - > page_offset = offset ;
f - > page = page ;
skb - > data_len + = f - > size ;
skb - > len + = f - > size ;
skb_shinfo ( skb ) - > nr_frags + + ;
* len - = f - > size ;
}
2008-06-08 20:49:00 +10:00
2010-01-29 03:20:04 +00:00
static struct sk_buff * page_to_skb ( struct virtnet_info * vi ,
struct page * page , unsigned int len )
{
struct sk_buff * skb ;
struct skb_vnet_hdr * hdr ;
unsigned int copy , hdr_len , offset ;
char * p ;
2008-07-25 12:06:01 -05:00
2010-01-29 03:20:04 +00:00
p = page_address ( page ) ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
/* copy small packet so we can reuse these pages for small data */
skb = netdev_alloc_skb_ip_align ( vi - > dev , GOOD_COPY_LEN ) ;
if ( unlikely ( ! skb ) )
return NULL ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
hdr = skb_vnet_hdr ( skb ) ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
if ( vi - > mergeable_rx_bufs ) {
hdr_len = sizeof hdr - > mhdr ;
offset = hdr_len ;
} else {
hdr_len = sizeof hdr - > hdr ;
offset = sizeof ( struct padded_vnet_hdr ) ;
}
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
memcpy ( hdr , p , hdr_len ) ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
len - = hdr_len ;
p + = offset ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
copy = len ;
if ( copy > skb_tailroom ( skb ) )
copy = skb_tailroom ( skb ) ;
memcpy ( skb_put ( skb , copy ) , p , copy ) ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
len - = copy ;
offset + = copy ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
while ( len ) {
set_skb_frag ( skb , page , offset , & len ) ;
page = ( struct page * ) page - > private ;
offset = 0 ;
}
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
if ( page )
give_pages ( vi , page ) ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
return skb ;
}
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
static int receive_mergeable ( struct virtnet_info * vi , struct sk_buff * skb )
{
struct skb_vnet_hdr * hdr = skb_vnet_hdr ( skb ) ;
struct page * page ;
int num_buf , i , len ;
num_buf = hdr - > mhdr . num_buffers ;
while ( - - num_buf ) {
i = skb_shinfo ( skb ) - > nr_frags ;
if ( i > = MAX_SKB_FRAGS ) {
pr_debug ( " %s: packet too long \n " , skb - > dev - > name ) ;
skb - > dev - > stats . rx_length_errors + + ;
return - EINVAL ;
}
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
page = vi - > rvq - > vq_ops - > get_buf ( vi - > rvq , & len ) ;
if ( ! page ) {
pr_debug ( " %s: rx error: %d buffers missing \n " ,
skb - > dev - > name , hdr - > mhdr . num_buffers ) ;
skb - > dev - > stats . rx_length_errors + + ;
return - EINVAL ;
2008-11-16 22:41:34 -08:00
}
2010-01-29 03:20:04 +00:00
if ( len > PAGE_SIZE )
len = PAGE_SIZE ;
set_skb_frag ( skb , page , 0 , & len ) ;
- - vi - > num ;
}
return 0 ;
}
static void receive_buf ( struct net_device * dev , void * buf , unsigned int len )
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
struct sk_buff * skb ;
struct page * page ;
struct skb_vnet_hdr * hdr ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
if ( unlikely ( len < sizeof ( struct virtio_net_hdr ) + ETH_HLEN ) ) {
pr_debug ( " %s: short packet %i \n " , dev - > name , len ) ;
dev - > stats . rx_length_errors + + ;
if ( vi - > mergeable_rx_bufs | | vi - > big_packets )
give_pages ( vi , buf ) ;
else
dev_kfree_skb ( buf ) ;
return ;
}
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
if ( ! vi - > mergeable_rx_bufs & & ! vi - > big_packets ) {
skb = buf ;
len - = sizeof ( struct virtio_net_hdr ) ;
skb_trim ( skb , len ) ;
} else {
page = buf ;
skb = page_to_skb ( vi , page , len ) ;
if ( unlikely ( ! skb ) ) {
2008-11-16 22:41:34 -08:00
dev - > stats . rx_dropped + + ;
2010-01-29 03:20:04 +00:00
give_pages ( vi , page ) ;
return ;
2008-11-16 22:41:34 -08:00
}
2010-01-29 03:20:04 +00:00
if ( vi - > mergeable_rx_bufs )
if ( receive_mergeable ( vi , skb ) ) {
dev_kfree_skb ( skb ) ;
return ;
}
2008-04-18 11:24:27 +08:00
}
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
hdr = skb_vnet_hdr ( skb ) ;
2008-04-18 11:24:27 +08:00
skb - > truesize + = skb - > data_len ;
2007-10-22 11:03:37 +10:00
dev - > stats . rx_bytes + = skb - > len ;
dev - > stats . rx_packets + + ;
2009-09-24 09:59:19 -06:00
if ( hdr - > hdr . flags & VIRTIO_NET_HDR_F_NEEDS_CSUM ) {
2007-10-22 11:03:37 +10:00
pr_debug ( " Needs csum! \n " ) ;
2009-09-24 09:59:19 -06:00
if ( ! skb_partial_csum_set ( skb ,
hdr - > hdr . csum_start ,
hdr - > hdr . csum_offset ) )
2007-10-22 11:03:37 +10:00
goto frame_err ;
}
2008-06-08 20:49:00 +10:00
skb - > protocol = eth_type_trans ( skb , dev ) ;
pr_debug ( " Receiving skb proto 0x%04x len %i type %i \n " ,
ntohs ( skb - > protocol ) , skb - > len , skb - > pkt_type ) ;
2009-09-24 09:59:19 -06:00
if ( hdr - > hdr . gso_type ! = VIRTIO_NET_HDR_GSO_NONE ) {
2007-10-22 11:03:37 +10:00
pr_debug ( " GSO! \n " ) ;
2009-09-24 09:59:19 -06:00
switch ( hdr - > hdr . gso_type & ~ VIRTIO_NET_HDR_GSO_ECN ) {
2007-10-22 11:03:37 +10:00
case VIRTIO_NET_HDR_GSO_TCPV4 :
skb_shinfo ( skb ) - > gso_type = SKB_GSO_TCPV4 ;
break ;
case VIRTIO_NET_HDR_GSO_UDP :
skb_shinfo ( skb ) - > gso_type = SKB_GSO_UDP ;
break ;
case VIRTIO_NET_HDR_GSO_TCPV6 :
skb_shinfo ( skb ) - > gso_type = SKB_GSO_TCPV6 ;
break ;
default :
if ( net_ratelimit ( ) )
printk ( KERN_WARNING " %s: bad gso type %u. \n " ,
2009-09-24 09:59:19 -06:00
dev - > name , hdr - > hdr . gso_type ) ;
2007-10-22 11:03:37 +10:00
goto frame_err ;
}
2009-09-24 09:59:19 -06:00
if ( hdr - > hdr . gso_type & VIRTIO_NET_HDR_GSO_ECN )
2008-02-04 23:50:02 -05:00
skb_shinfo ( skb ) - > gso_type | = SKB_GSO_TCP_ECN ;
2009-09-24 09:59:19 -06:00
skb_shinfo ( skb ) - > gso_size = hdr - > hdr . gso_size ;
2007-10-22 11:03:37 +10:00
if ( skb_shinfo ( skb ) - > gso_size = = 0 ) {
if ( net_ratelimit ( ) )
printk ( KERN_WARNING " %s: zero gso size. \n " ,
dev - > name ) ;
goto frame_err ;
}
/* Header must be checked, and gso_segs computed. */
skb_shinfo ( skb ) - > gso_type | = SKB_GSO_DODGY ;
skb_shinfo ( skb ) - > gso_segs = 0 ;
}
netif_receive_skb ( skb ) ;
return ;
frame_err :
dev - > stats . rx_frame_errors + + ;
dev_kfree_skb ( skb ) ;
}
2010-01-29 03:20:04 +00:00
static int add_recvbuf_small ( struct virtnet_info * vi , gfp_t gfp )
2007-10-22 11:03:37 +10:00
{
struct sk_buff * skb ;
2010-01-29 03:20:04 +00:00
struct skb_vnet_hdr * hdr ;
struct scatterlist sg [ 2 ] ;
int err ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
skb = netdev_alloc_skb_ip_align ( vi - > dev , MAX_PACKET_LEN ) ;
if ( unlikely ( ! skb ) )
return - ENOMEM ;
2007-10-22 11:03:37 +10:00
2010-01-29 03:20:04 +00:00
skb_put ( skb , MAX_PACKET_LEN ) ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
hdr = skb_vnet_hdr ( skb ) ;
sg_set_buf ( sg , & hdr - > hdr , sizeof hdr - > hdr ) ;
2008-04-18 11:24:27 +08:00
2010-01-29 03:20:04 +00:00
skb_to_sgvec ( skb , sg + 1 , 0 , skb - > len ) ;
2008-04-18 11:24:27 +08:00
2010-01-29 03:20:04 +00:00
err = vi - > rvq - > vq_ops - > add_buf ( vi - > rvq , sg , 0 , 2 , skb ) ;
if ( err < 0 )
dev_kfree_skb ( skb ) ;
2008-04-18 11:24:27 +08:00
2010-01-29 03:20:04 +00:00
return err ;
}
2008-04-18 11:24:27 +08:00
2010-01-29 03:20:04 +00:00
static int add_recvbuf_big ( struct virtnet_info * vi , gfp_t gfp )
{
struct scatterlist sg [ MAX_SKB_FRAGS + 2 ] ;
struct page * first , * list = NULL ;
char * p ;
int i , err , offset ;
/* page in sg[MAX_SKB_FRAGS + 1] is list tail */
for ( i = MAX_SKB_FRAGS + 1 ; i > 1 ; - - i ) {
first = get_a_page ( vi , gfp ) ;
if ( ! first ) {
if ( list )
give_pages ( vi , list ) ;
return - ENOMEM ;
2008-04-18 11:24:27 +08:00
}
2010-01-29 03:20:04 +00:00
sg_set_buf ( & sg [ i ] , page_address ( first ) , PAGE_SIZE ) ;
2008-04-18 11:24:27 +08:00
2010-01-29 03:20:04 +00:00
/* chain new page in list head to match sg */
first - > private = ( unsigned long ) list ;
list = first ;
}
2007-10-22 11:03:37 +10:00
2010-01-29 03:20:04 +00:00
first = get_a_page ( vi , gfp ) ;
if ( ! first ) {
give_pages ( vi , list ) ;
return - ENOMEM ;
}
p = page_address ( first ) ;
/* sg[0], sg[1] share the same page */
/* a separated sg[0] for virtio_net_hdr only during to QEMU bug*/
sg_set_buf ( & sg [ 0 ] , p , sizeof ( struct virtio_net_hdr ) ) ;
/* sg[1] for data packet, from offset */
offset = sizeof ( struct padded_vnet_hdr ) ;
sg_set_buf ( & sg [ 1 ] , p + offset , PAGE_SIZE - offset ) ;
/* chain first in list head */
first - > private = ( unsigned long ) list ;
err = vi - > rvq - > vq_ops - > add_buf ( vi - > rvq , sg , 0 , MAX_SKB_FRAGS + 2 ,
first ) ;
if ( err < 0 )
give_pages ( vi , first ) ;
return err ;
2007-10-22 11:03:37 +10:00
}
2010-01-29 03:20:04 +00:00
static int add_recvbuf_mergeable ( struct virtnet_info * vi , gfp_t gfp )
2008-11-16 22:41:34 -08:00
{
2010-01-29 03:20:04 +00:00
struct page * page ;
struct scatterlist sg ;
2008-11-16 22:41:34 -08:00
int err ;
2010-01-29 03:20:04 +00:00
page = get_a_page ( vi , gfp ) ;
if ( ! page )
return - ENOMEM ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
sg_init_one ( & sg , page_address ( page ) , PAGE_SIZE ) ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
err = vi - > rvq - > vq_ops - > add_buf ( vi - > rvq , & sg , 0 , 1 , page ) ;
if ( err < 0 )
give_pages ( vi , page ) ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
return err ;
}
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
/* Returns false if we couldn't fill entirely (OOM). */
static bool try_fill_recv ( struct virtnet_info * vi , gfp_t gfp )
{
int err ;
bool oom = false ;
2008-11-16 22:41:34 -08:00
2010-01-29 03:20:04 +00:00
do {
if ( vi - > mergeable_rx_bufs )
err = add_recvbuf_mergeable ( vi , gfp ) ;
else if ( vi - > big_packets )
err = add_recvbuf_big ( vi , gfp ) ;
else
err = add_recvbuf_small ( vi , gfp ) ;
2008-11-16 22:41:34 -08:00
2009-09-23 22:26:31 -06:00
if ( err < 0 ) {
2010-01-29 03:20:04 +00:00
oom = true ;
2008-11-16 22:41:34 -08:00
break ;
}
2010-01-29 03:20:04 +00:00
+ + vi - > num ;
2009-08-26 14:58:28 +05:30
} while ( err > 0 ) ;
2008-11-16 22:41:34 -08:00
if ( unlikely ( vi - > num > vi - > max ) )
vi - > max = vi - > num ;
vi - > rvq - > vq_ops - > kick ( vi - > rvq ) ;
2009-08-26 12:22:32 -07:00
return ! oom ;
2008-11-16 22:41:34 -08:00
}
2008-02-04 23:49:57 -05:00
static void skb_recv_done ( struct virtqueue * rvq )
2007-10-22 11:03:37 +10:00
{
struct virtnet_info * vi = rvq - > vdev - > priv ;
2008-02-04 23:49:57 -05:00
/* Schedule NAPI, Suppress further interrupts if successful. */
2009-01-19 16:43:59 -08:00
if ( napi_schedule_prep ( & vi - > napi ) ) {
2008-02-04 23:49:57 -05:00
rvq - > vq_ops - > disable_cb ( rvq ) ;
2009-01-19 16:43:59 -08:00
__napi_schedule ( & vi - > napi ) ;
2008-02-04 23:49:57 -05:00
}
2007-10-22 11:03:37 +10:00
}
2009-08-26 12:22:32 -07:00
static void refill_work ( struct work_struct * work )
{
struct virtnet_info * vi ;
bool still_empty ;
vi = container_of ( work , struct virtnet_info , refill . work ) ;
napi_disable ( & vi - > napi ) ;
2010-01-25 15:51:01 -08:00
still_empty = ! try_fill_recv ( vi , GFP_KERNEL ) ;
2009-08-26 12:22:32 -07:00
napi_enable ( & vi - > napi ) ;
/* In theory, this can happen: if we don't get any buffers in
* we will * never * try to fill again . */
if ( still_empty )
schedule_delayed_work ( & vi - > refill , HZ / 2 ) ;
}
2007-10-22 11:03:37 +10:00
static int virtnet_poll ( struct napi_struct * napi , int budget )
{
struct virtnet_info * vi = container_of ( napi , struct virtnet_info , napi ) ;
2010-01-29 03:20:04 +00:00
void * buf ;
2007-10-22 11:03:37 +10:00
unsigned int len , received = 0 ;
again :
while ( received < budget & &
2010-01-29 03:20:04 +00:00
( buf = vi - > rvq - > vq_ops - > get_buf ( vi - > rvq , & len ) ) ! = NULL ) {
receive_buf ( vi - > dev , buf , len ) ;
- - vi - > num ;
2007-10-22 11:03:37 +10:00
received + + ;
}
2009-08-26 12:22:32 -07:00
if ( vi - > num < vi - > max / 2 ) {
if ( ! try_fill_recv ( vi , GFP_ATOMIC ) )
schedule_delayed_work ( & vi - > refill , 0 ) ;
}
2007-10-22 11:03:37 +10:00
2007-11-19 11:20:43 -05:00
/* Out of packets? */
if ( received < budget ) {
2009-01-19 16:43:59 -08:00
napi_complete ( napi ) ;
2009-12-03 07:58:21 +00:00
if ( unlikely ( ! vi - > rvq - > vq_ops - > enable_cb ( vi - > rvq ) ) & &
napi_schedule_prep ( napi ) ) {
virtio: fix race in enable_cb
There is a race in virtio_net, dealing with disabling/enabling the callback.
I saw the following oops:
kernel BUG at /space/kvm/drivers/virtio/virtio_ring.c:218!
illegal operation: 0001 [#1] SMP
Modules linked in: sunrpc dm_mod
CPU: 2 Not tainted 2.6.25-rc1zlive-host-10623-gd358142-dirty #99
Process swapper (pid: 0, task: 000000000f85a610, ksp: 000000000f873c60)
Krnl PSW : 0404300180000000 00000000002b81a6 (vring_disable_cb+0x16/0x20)
R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3
Krnl GPRS: 0000000000000001 0000000000000001 0000000010005800 0000000000000001
000000000f3a0900 000000000f85a610 0000000000000000 0000000000000000
0000000000000000 000000000f870000 0000000000000000 0000000000001237
000000000f3a0920 000000000010ff74 00000000002846f6 000000000fa0bcd8
Krnl Code: 00000000002b819a: a7110001 tmll %r1,1
00000000002b819e: a7840004 brc 8,2b81a6
00000000002b81a2: a7f40001 brc 15,2b81a4
>00000000002b81a6: a51b0001 oill %r1,1
00000000002b81aa: 40102000 sth %r1,0(%r2)
00000000002b81ae: 07fe bcr 15,%r14
00000000002b81b0: eb7ff0380024 stmg %r7,%r15,56(%r15)
00000000002b81b6: a7f13e00 tmll %r15,15872
Call Trace:
([<000000000fa0bcd0>] 0xfa0bcd0)
[<00000000002b8350>] vring_interrupt+0x5c/0x6c
[<000000000010ab08>] do_extint+0xb8/0xf0
[<0000000000110716>] ext_no_vtime+0x16/0x1a
[<0000000000107e72>] cpu_idle+0x1c2/0x1e0
The problem can be triggered with a high amount of host->guest traffic.
I think its the following race:
poll says netif_rx_complete
poll calls enable_cb
enable_cb opens the interrupt mask
a new packet comes, an interrupt is triggered----\
enable_cb sees that there is more work |
enable_cb disables the interrupt |
. V
. interrupt is delivered
. skb_recv_done does atomic napi test, ok
some waiting disable_cb is called->check fails->bang!
.
poll would do napi check
poll would do disable_cb
The fix is to let enable_cb not disable the interrupt again, but expect the
caller to do the cleanup if it returns false. In that case, the interrupt is
only disabled, if the napi test_set_bit was successful.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (cleaned up doco)
2008-03-14 14:17:05 +01:00
vi - > rvq - > vq_ops - > disable_cb ( vi - > rvq ) ;
2009-01-19 16:43:59 -08:00
__napi_schedule ( napi ) ;
2007-10-22 11:03:37 +10:00
goto again ;
virtio: fix race in enable_cb
There is a race in virtio_net, dealing with disabling/enabling the callback.
I saw the following oops:
kernel BUG at /space/kvm/drivers/virtio/virtio_ring.c:218!
illegal operation: 0001 [#1] SMP
Modules linked in: sunrpc dm_mod
CPU: 2 Not tainted 2.6.25-rc1zlive-host-10623-gd358142-dirty #99
Process swapper (pid: 0, task: 000000000f85a610, ksp: 000000000f873c60)
Krnl PSW : 0404300180000000 00000000002b81a6 (vring_disable_cb+0x16/0x20)
R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3
Krnl GPRS: 0000000000000001 0000000000000001 0000000010005800 0000000000000001
000000000f3a0900 000000000f85a610 0000000000000000 0000000000000000
0000000000000000 000000000f870000 0000000000000000 0000000000001237
000000000f3a0920 000000000010ff74 00000000002846f6 000000000fa0bcd8
Krnl Code: 00000000002b819a: a7110001 tmll %r1,1
00000000002b819e: a7840004 brc 8,2b81a6
00000000002b81a2: a7f40001 brc 15,2b81a4
>00000000002b81a6: a51b0001 oill %r1,1
00000000002b81aa: 40102000 sth %r1,0(%r2)
00000000002b81ae: 07fe bcr 15,%r14
00000000002b81b0: eb7ff0380024 stmg %r7,%r15,56(%r15)
00000000002b81b6: a7f13e00 tmll %r15,15872
Call Trace:
([<000000000fa0bcd0>] 0xfa0bcd0)
[<00000000002b8350>] vring_interrupt+0x5c/0x6c
[<000000000010ab08>] do_extint+0xb8/0xf0
[<0000000000110716>] ext_no_vtime+0x16/0x1a
[<0000000000107e72>] cpu_idle+0x1c2/0x1e0
The problem can be triggered with a high amount of host->guest traffic.
I think its the following race:
poll says netif_rx_complete
poll calls enable_cb
enable_cb opens the interrupt mask
a new packet comes, an interrupt is triggered----\
enable_cb sees that there is more work |
enable_cb disables the interrupt |
. V
. interrupt is delivered
. skb_recv_done does atomic napi test, ok
some waiting disable_cb is called->check fails->bang!
.
poll would do napi check
poll would do disable_cb
The fix is to let enable_cb not disable the interrupt again, but expect the
caller to do the cleanup if it returns false. In that case, the interrupt is
only disabled, if the napi test_set_bit was successful.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> (cleaned up doco)
2008-03-14 14:17:05 +01:00
}
2007-10-22 11:03:37 +10:00
}
return received ;
}
2009-09-24 09:59:20 -06:00
static unsigned int free_old_xmit_skbs ( struct virtnet_info * vi )
2007-10-22 11:03:37 +10:00
{
struct sk_buff * skb ;
2009-09-24 09:59:20 -06:00
unsigned int len , tot_sgs = 0 ;
2007-10-22 11:03:37 +10:00
while ( ( skb = vi - > svq - > vq_ops - > get_buf ( vi - > svq , & len ) ) ! = NULL ) {
pr_debug ( " Sent skb %p \n " , skb ) ;
2008-05-02 21:50:43 -05:00
vi - > dev - > stats . tx_bytes + = skb - > len ;
2007-10-22 11:03:37 +10:00
vi - > dev - > stats . tx_packets + + ;
2009-09-24 09:59:20 -06:00
tot_sgs + = skb_vnet_hdr ( skb ) - > num_sg ;
2009-10-14 14:36:43 +00:00
dev_kfree_skb_any ( skb ) ;
2007-10-22 11:03:37 +10:00
}
2009-09-24 09:59:20 -06:00
return tot_sgs ;
2007-10-22 11:03:37 +10:00
}
2008-05-02 21:50:46 -05:00
static int xmit_skb ( struct virtnet_info * vi , struct sk_buff * skb )
2007-10-22 11:03:37 +10:00
{
2008-05-02 21:50:45 -05:00
struct scatterlist sg [ 2 + MAX_SKB_FRAGS ] ;
2009-09-24 09:59:19 -06:00
struct skb_vnet_hdr * hdr = skb_vnet_hdr ( skb ) ;
2007-10-22 11:03:37 +10:00
const unsigned char * dest = ( ( struct ethhdr * ) skb - > data ) - > h_dest ;
2008-05-02 21:50:45 -05:00
sg_init_table ( sg , 2 + MAX_SKB_FRAGS ) ;
2007-11-07 16:34:49 +11:00
2008-10-27 15:59:26 -07:00
pr_debug ( " %s: xmit %p %pM \n " , vi - > dev - > name , skb , dest ) ;
2007-10-22 11:03:37 +10:00
if ( skb - > ip_summed = = CHECKSUM_PARTIAL ) {
2009-09-24 09:59:19 -06:00
hdr - > hdr . flags = VIRTIO_NET_HDR_F_NEEDS_CSUM ;
hdr - > hdr . csum_start = skb - > csum_start - skb_headroom ( skb ) ;
hdr - > hdr . csum_offset = skb - > csum_offset ;
2007-10-22 11:03:37 +10:00
} else {
2009-09-24 09:59:19 -06:00
hdr - > hdr . flags = 0 ;
hdr - > hdr . csum_offset = hdr - > hdr . csum_start = 0 ;
2007-10-22 11:03:37 +10:00
}
if ( skb_is_gso ( skb ) ) {
2009-09-24 09:59:19 -06:00
hdr - > hdr . hdr_len = skb_headlen ( skb ) ;
hdr - > hdr . gso_size = skb_shinfo ( skb ) - > gso_size ;
2008-02-04 23:50:02 -05:00
if ( skb_shinfo ( skb ) - > gso_type & SKB_GSO_TCPV4 )
2009-09-24 09:59:19 -06:00
hdr - > hdr . gso_type = VIRTIO_NET_HDR_GSO_TCPV4 ;
2007-10-22 11:03:37 +10:00
else if ( skb_shinfo ( skb ) - > gso_type & SKB_GSO_TCPV6 )
2009-09-24 09:59:19 -06:00
hdr - > hdr . gso_type = VIRTIO_NET_HDR_GSO_TCPV6 ;
2007-10-22 11:03:37 +10:00
else if ( skb_shinfo ( skb ) - > gso_type & SKB_GSO_UDP )
2009-09-24 09:59:19 -06:00
hdr - > hdr . gso_type = VIRTIO_NET_HDR_GSO_UDP ;
2007-10-22 11:03:37 +10:00
else
BUG ( ) ;
2008-02-04 23:50:02 -05:00
if ( skb_shinfo ( skb ) - > gso_type & SKB_GSO_TCP_ECN )
2009-09-24 09:59:19 -06:00
hdr - > hdr . gso_type | = VIRTIO_NET_HDR_GSO_ECN ;
2007-10-22 11:03:37 +10:00
} else {
2009-09-24 09:59:19 -06:00
hdr - > hdr . gso_type = VIRTIO_NET_HDR_GSO_NONE ;
hdr - > hdr . gso_size = hdr - > hdr . hdr_len = 0 ;
2007-10-22 11:03:37 +10:00
}
2009-09-24 09:59:19 -06:00
hdr - > mhdr . num_buffers = 0 ;
2008-11-16 22:41:34 -08:00
/* Encode metadata header at front. */
if ( vi - > mergeable_rx_bufs )
2010-01-29 03:20:04 +00:00
sg_set_buf ( sg , & hdr - > mhdr , sizeof hdr - > mhdr ) ;
2008-11-16 22:41:34 -08:00
else
2010-01-29 03:20:04 +00:00
sg_set_buf ( sg , & hdr - > hdr , sizeof hdr - > hdr ) ;
2008-11-16 22:41:34 -08:00
2009-09-24 09:59:20 -06:00
hdr - > num_sg = skb_to_sgvec ( skb , sg + 1 , 0 , skb - > len ) + 1 ;
return vi - > svq - > vq_ops - > add_buf ( vi - > svq , sg , hdr - > num_sg , 0 , skb ) ;
2008-05-26 17:48:13 +10:00
}
2009-08-31 19:50:51 +00:00
static netdev_tx_t start_xmit ( struct sk_buff * skb , struct net_device * dev )
2008-05-02 21:50:46 -05:00
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
2009-09-24 09:59:20 -06:00
int capacity ;
2008-02-04 23:50:07 -05:00
again :
/* Free up any pending old buffers before queueing new ones. */
free_old_xmit_skbs ( vi ) ;
2008-05-02 21:50:46 -05:00
2009-10-28 04:03:38 -07:00
/* Try to transmit */
2009-09-24 09:59:20 -06:00
capacity = xmit_skb ( vi , skb ) ;
/* This can happen with OOM and indirect buffers. */
if ( unlikely ( capacity < 0 ) ) {
netif_stop_queue ( dev ) ;
dev_warn ( & dev - > dev , " Unexpected full queue \n " ) ;
if ( unlikely ( ! vi - > svq - > vq_ops - > enable_cb ( vi - > svq ) ) ) {
vi - > svq - > vq_ops - > disable_cb ( vi - > svq ) ;
netif_start_queue ( dev ) ;
goto again ;
}
return NETDEV_TX_BUSY ;
2007-10-22 11:03:37 +10:00
}
2009-09-24 09:59:20 -06:00
vi - > svq - > vq_ops - > kick ( vi - > svq ) ;
2009-10-28 04:03:38 -07:00
2009-09-24 09:59:20 -06:00
/* Don't wait up for transmitted skbs to be freed. */
skb_orphan ( skb ) ;
nf_reset ( skb ) ;
/* Apparently nice girls don't return TX_BUSY; stop the queue
* before it gets out of hand . Naturally , this wastes entries . */
if ( capacity < 2 + MAX_SKB_FRAGS ) {
netif_stop_queue ( dev ) ;
if ( unlikely ( ! vi - > svq - > vq_ops - > enable_cb ( vi - > svq ) ) ) {
/* More just got used, free them then recheck. */
capacity + = free_old_xmit_skbs ( vi ) ;
if ( capacity > = 2 + MAX_SKB_FRAGS ) {
netif_start_queue ( dev ) ;
vi - > svq - > vq_ops - > disable_cb ( vi - > svq ) ;
}
}
2008-05-02 21:50:46 -05:00
}
2009-09-24 09:59:20 -06:00
return NETDEV_TX_OK ;
2007-10-22 11:03:37 +10:00
}
2009-02-04 16:36:34 -08:00
static int virtnet_set_mac_address ( struct net_device * dev , void * p )
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
struct virtio_device * vdev = vi - > vdev ;
int ret ;
ret = eth_mac_addr ( dev , p ) ;
if ( ret )
return ret ;
2009-04-04 16:40:19 -07:00
if ( virtio_has_feature ( vdev , VIRTIO_NET_F_MAC ) )
vdev - > config - > set ( vdev , offsetof ( struct virtio_net_config , mac ) ,
dev - > dev_addr , dev - > addr_len ) ;
2009-02-04 16:36:34 -08:00
return 0 ;
}
2008-02-29 16:24:50 +05:30
# ifdef CONFIG_NET_POLL_CONTROLLER
static void virtnet_netpoll ( struct net_device * dev )
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
napi_schedule ( & vi - > napi ) ;
}
# endif
2007-10-22 11:03:37 +10:00
static int virtnet_open ( struct net_device * dev )
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
napi_enable ( & vi - > napi ) ;
2008-02-04 23:50:07 -05:00
/* If all buffers were filled by other side before we napi_enabled, we
* won ' t get another interrupt , so process any outstanding packets
virtio net: fix oops on interface-up
I got the following oops during interface ifup. Unfortunately its not
easily reproducable so I cant say for sure that my fix fixes this
problem, but I am confident and I think its correct anyway:
<2>kernel BUG at /space/kvm/drivers/virtio/virtio_ring.c:234!
<4>illegal operation: 0001 [#1] PREEMPT SMP
<4>Modules linked in:
<4>CPU: 0 Not tainted 2.6.24zlive-guest-07293-gf1ca151-dirty #91
<4>Process swapper (pid: 0, task: 0000000000800938, ksp: 000000000084ddb8)
<4>Krnl PSW : 0404300180000000 0000000000466374 (vring_disable_cb+0x30/0x34)
<4> R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3
<4>Krnl GPRS: 0000000000000001 0000000000000001 0000000010003800 0000000000466344
<4> 000000000e980900 00000000008848b0 000000000084e748 0000000000000000
<4> 000000000087b300 0000000000001237 0000000000001237 000000000f85bdd8
<4> 000000000e980920 00000000001137c0 0000000000464754 000000000f85bdd8
<4>Krnl Code: 0000000000466368: e3b0b0700004 lg %r11,112(%r11)
<4> 000000000046636e: 07fe bcr 15,%r14
<4> 0000000000466370: a7f40001 brc 15,466372
<4> >0000000000466374: a7f4fff6 brc 15,466360
<4> 0000000000466378: eb7ff0500024 stmg %r7,%r15,80(%r15)
<4> 000000000046637e: a7f13e00 tmll %r15,15872
<4> 0000000000466382: b90400ef lgr %r14,%r15
<4> 0000000000466386: a7840001 brc 8,466388
<4>Call Trace:
<4>([<000201500f85c000>] 0x201500f85c000)
<4> [<0000000000466556>] vring_interrupt+0x72/0x88
<4> [<00000000004801a0>] kvm_extint_handler+0x34/0x44
<4> [<000000000010d22c>] do_extint+0xbc/0xf8
<4> [<0000000000113f98>] ext_no_vtime+0x16/0x1a
<4> [<000000000010a182>] cpu_idle+0x216/0x238
<4>([<000000000010a162>] cpu_idle+0x1f6/0x238)
<4> [<0000000000568656>] rest_init+0xaa/0xb8
<4> [<000000000084ee2c>] start_kernel+0x3fc/0x490
<4> [<0000000000100020>] _stext+0x20/0x80
<4>
<4> <0>Kernel panic - not syncing: Fatal exception in interrupt
<4>
After looking at the code and the dump I think the following scenario
happened: Ifup was running on cpu2 and the interrupt arrived on cpu0.
Now virtnet_open on cpu 2 managed to execute napi_enable and disable_cb
but did not execute rx_schedule. Meanwhile on cpu 0 skb_recv_done was
called by vring_interrupt, executed netif_rx_schedule_prep, which
succeeded and therefore called disable_cb. This triggered the BUG_ON,
as interrupts were already disabled by cpu 2.
I think the proper solution is to make the call to disable_cb depend on
the atomic update of NAPI_STATE_SCHED by using netif_rx_schedule_prep
in the same way as skb_recv_done.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2008-02-06 08:50:11 +01:00
* now . virtnet_poll wants re - enable the queue , so we disable here .
* We synchronize against interrupts via NAPI_STATE_SCHED */
2009-01-19 16:43:59 -08:00
if ( napi_schedule_prep ( & vi - > napi ) ) {
virtio net: fix oops on interface-up
I got the following oops during interface ifup. Unfortunately its not
easily reproducable so I cant say for sure that my fix fixes this
problem, but I am confident and I think its correct anyway:
<2>kernel BUG at /space/kvm/drivers/virtio/virtio_ring.c:234!
<4>illegal operation: 0001 [#1] PREEMPT SMP
<4>Modules linked in:
<4>CPU: 0 Not tainted 2.6.24zlive-guest-07293-gf1ca151-dirty #91
<4>Process swapper (pid: 0, task: 0000000000800938, ksp: 000000000084ddb8)
<4>Krnl PSW : 0404300180000000 0000000000466374 (vring_disable_cb+0x30/0x34)
<4> R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3
<4>Krnl GPRS: 0000000000000001 0000000000000001 0000000010003800 0000000000466344
<4> 000000000e980900 00000000008848b0 000000000084e748 0000000000000000
<4> 000000000087b300 0000000000001237 0000000000001237 000000000f85bdd8
<4> 000000000e980920 00000000001137c0 0000000000464754 000000000f85bdd8
<4>Krnl Code: 0000000000466368: e3b0b0700004 lg %r11,112(%r11)
<4> 000000000046636e: 07fe bcr 15,%r14
<4> 0000000000466370: a7f40001 brc 15,466372
<4> >0000000000466374: a7f4fff6 brc 15,466360
<4> 0000000000466378: eb7ff0500024 stmg %r7,%r15,80(%r15)
<4> 000000000046637e: a7f13e00 tmll %r15,15872
<4> 0000000000466382: b90400ef lgr %r14,%r15
<4> 0000000000466386: a7840001 brc 8,466388
<4>Call Trace:
<4>([<000201500f85c000>] 0x201500f85c000)
<4> [<0000000000466556>] vring_interrupt+0x72/0x88
<4> [<00000000004801a0>] kvm_extint_handler+0x34/0x44
<4> [<000000000010d22c>] do_extint+0xbc/0xf8
<4> [<0000000000113f98>] ext_no_vtime+0x16/0x1a
<4> [<000000000010a182>] cpu_idle+0x216/0x238
<4>([<000000000010a162>] cpu_idle+0x1f6/0x238)
<4> [<0000000000568656>] rest_init+0xaa/0xb8
<4> [<000000000084ee2c>] start_kernel+0x3fc/0x490
<4> [<0000000000100020>] _stext+0x20/0x80
<4>
<4> <0>Kernel panic - not syncing: Fatal exception in interrupt
<4>
After looking at the code and the dump I think the following scenario
happened: Ifup was running on cpu2 and the interrupt arrived on cpu0.
Now virtnet_open on cpu 2 managed to execute napi_enable and disable_cb
but did not execute rx_schedule. Meanwhile on cpu 0 skb_recv_done was
called by vring_interrupt, executed netif_rx_schedule_prep, which
succeeded and therefore called disable_cb. This triggered the BUG_ON,
as interrupts were already disabled by cpu 2.
I think the proper solution is to make the call to disable_cb depend on
the atomic update of NAPI_STATE_SCHED by using netif_rx_schedule_prep
in the same way as skb_recv_done.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2008-02-06 08:50:11 +01:00
vi - > rvq - > vq_ops - > disable_cb ( vi - > rvq ) ;
2009-01-19 16:43:59 -08:00
__napi_schedule ( & vi - > napi ) ;
virtio net: fix oops on interface-up
I got the following oops during interface ifup. Unfortunately its not
easily reproducable so I cant say for sure that my fix fixes this
problem, but I am confident and I think its correct anyway:
<2>kernel BUG at /space/kvm/drivers/virtio/virtio_ring.c:234!
<4>illegal operation: 0001 [#1] PREEMPT SMP
<4>Modules linked in:
<4>CPU: 0 Not tainted 2.6.24zlive-guest-07293-gf1ca151-dirty #91
<4>Process swapper (pid: 0, task: 0000000000800938, ksp: 000000000084ddb8)
<4>Krnl PSW : 0404300180000000 0000000000466374 (vring_disable_cb+0x30/0x34)
<4> R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:3 PM:0 EA:3
<4>Krnl GPRS: 0000000000000001 0000000000000001 0000000010003800 0000000000466344
<4> 000000000e980900 00000000008848b0 000000000084e748 0000000000000000
<4> 000000000087b300 0000000000001237 0000000000001237 000000000f85bdd8
<4> 000000000e980920 00000000001137c0 0000000000464754 000000000f85bdd8
<4>Krnl Code: 0000000000466368: e3b0b0700004 lg %r11,112(%r11)
<4> 000000000046636e: 07fe bcr 15,%r14
<4> 0000000000466370: a7f40001 brc 15,466372
<4> >0000000000466374: a7f4fff6 brc 15,466360
<4> 0000000000466378: eb7ff0500024 stmg %r7,%r15,80(%r15)
<4> 000000000046637e: a7f13e00 tmll %r15,15872
<4> 0000000000466382: b90400ef lgr %r14,%r15
<4> 0000000000466386: a7840001 brc 8,466388
<4>Call Trace:
<4>([<000201500f85c000>] 0x201500f85c000)
<4> [<0000000000466556>] vring_interrupt+0x72/0x88
<4> [<00000000004801a0>] kvm_extint_handler+0x34/0x44
<4> [<000000000010d22c>] do_extint+0xbc/0xf8
<4> [<0000000000113f98>] ext_no_vtime+0x16/0x1a
<4> [<000000000010a182>] cpu_idle+0x216/0x238
<4>([<000000000010a162>] cpu_idle+0x1f6/0x238)
<4> [<0000000000568656>] rest_init+0xaa/0xb8
<4> [<000000000084ee2c>] start_kernel+0x3fc/0x490
<4> [<0000000000100020>] _stext+0x20/0x80
<4>
<4> <0>Kernel panic - not syncing: Fatal exception in interrupt
<4>
After looking at the code and the dump I think the following scenario
happened: Ifup was running on cpu2 and the interrupt arrived on cpu0.
Now virtnet_open on cpu 2 managed to execute napi_enable and disable_cb
but did not execute rx_schedule. Meanwhile on cpu 0 skb_recv_done was
called by vring_interrupt, executed netif_rx_schedule_prep, which
succeeded and therefore called disable_cb. This triggered the BUG_ON,
as interrupts were already disabled by cpu 2.
I think the proper solution is to make the call to disable_cb depend on
the atomic update of NAPI_STATE_SCHED by using netif_rx_schedule_prep
in the same way as skb_recv_done.
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
2008-02-06 08:50:11 +01:00
}
2007-10-22 11:03:37 +10:00
return 0 ;
}
2009-02-04 09:02:34 +00:00
/*
* Send command via the control virtqueue and check status . Commands
* supported by the hypervisor , as indicated by feature bits , should
* never fail unless improperly formated .
*/
static bool virtnet_send_command ( struct virtnet_info * vi , u8 class , u8 cmd ,
struct scatterlist * data , int out , int in )
{
2009-05-01 17:27:56 +00:00
struct scatterlist * s , sg [ VIRTNET_SEND_COMMAND_SG_MAX + 2 ] ;
2009-02-04 09:02:34 +00:00
struct virtio_net_ctrl_hdr ctrl ;
virtio_net_ctrl_ack status = ~ 0 ;
unsigned int tmp ;
2009-05-01 17:27:56 +00:00
int i ;
2009-02-04 09:02:34 +00:00
2009-04-11 14:50:23 +00:00
/* Caller should know better */
BUG_ON ( ! virtio_has_feature ( vi - > vdev , VIRTIO_NET_F_CTRL_VQ ) | |
( out + in > VIRTNET_SEND_COMMAND_SG_MAX ) ) ;
2009-02-04 09:02:34 +00:00
out + + ; /* Add header */
in + + ; /* Add return status */
ctrl . class = class ;
ctrl . cmd = cmd ;
sg_init_table ( sg , out + in ) ;
sg_set_buf ( & sg [ 0 ] , & ctrl , sizeof ( ctrl ) ) ;
2009-05-01 17:27:56 +00:00
for_each_sg ( data , s , out + in - 2 , i )
sg_set_buf ( & sg [ i + 1 ] , sg_virt ( s ) , s - > length ) ;
2009-02-04 09:02:34 +00:00
sg_set_buf ( & sg [ out + in - 1 ] , & status , sizeof ( status ) ) ;
2009-09-23 22:26:31 -06:00
BUG_ON ( vi - > cvq - > vq_ops - > add_buf ( vi - > cvq , sg , out , in , vi ) < 0 ) ;
2009-02-04 09:02:34 +00:00
vi - > cvq - > vq_ops - > kick ( vi - > cvq ) ;
/*
* Spin for a response , the kick causes an ioport write , trapping
* into the hypervisor , so the request should be handled immediately .
*/
while ( ! vi - > cvq - > vq_ops - > get_buf ( vi - > cvq , & tmp ) )
cpu_relax ( ) ;
return status = = VIRTIO_NET_OK ;
}
2007-10-22 11:03:37 +10:00
static int virtnet_close ( struct net_device * dev )
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
napi_disable ( & vi - > napi ) ;
return 0 ;
}
2008-04-18 11:21:42 +08:00
static int virtnet_set_tx_csum ( struct net_device * dev , u32 data )
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
struct virtio_device * vdev = vi - > vdev ;
if ( data & & ! virtio_has_feature ( vdev , VIRTIO_NET_F_CSUM ) )
return - ENOSYS ;
return ethtool_op_set_tx_hw_csum ( dev , data ) ;
}
2009-02-04 09:02:40 +00:00
static void virtnet_set_rx_mode ( struct net_device * dev )
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
2009-02-04 09:02:45 +00:00
struct scatterlist sg [ 2 ] ;
2009-02-04 09:02:40 +00:00
u8 promisc , allmulti ;
2009-02-04 09:02:45 +00:00
struct virtio_net_ctrl_mac * mac_data ;
struct dev_addr_list * addr ;
2009-05-22 23:22:17 +00:00
struct netdev_hw_addr * ha ;
2010-01-25 13:36:10 -08:00
int uc_count ;
2010-02-08 04:30:35 +00:00
int mc_count ;
2009-02-04 09:02:45 +00:00
void * buf ;
int i ;
2009-02-04 09:02:40 +00:00
/* We can't dynamicaly set ndo_set_rx_mode, so return gracefully */
if ( ! virtio_has_feature ( vi - > vdev , VIRTIO_NET_F_CTRL_RX ) )
return ;
2009-02-04 09:02:45 +00:00
promisc = ( ( dev - > flags & IFF_PROMISC ) ! = 0 ) ;
allmulti = ( ( dev - > flags & IFF_ALLMULTI ) ! = 0 ) ;
2009-02-04 09:02:40 +00:00
2009-05-01 17:27:56 +00:00
sg_init_one ( sg , & promisc , sizeof ( promisc ) ) ;
2009-02-04 09:02:40 +00:00
if ( ! virtnet_send_command ( vi , VIRTIO_NET_CTRL_RX ,
VIRTIO_NET_CTRL_RX_PROMISC ,
2009-02-04 09:02:45 +00:00
sg , 1 , 0 ) )
2009-02-04 09:02:40 +00:00
dev_warn ( & dev - > dev , " Failed to %sable promisc mode. \n " ,
promisc ? " en " : " dis " ) ;
2009-05-01 17:27:56 +00:00
sg_init_one ( sg , & allmulti , sizeof ( allmulti ) ) ;
2009-02-04 09:02:40 +00:00
if ( ! virtnet_send_command ( vi , VIRTIO_NET_CTRL_RX ,
VIRTIO_NET_CTRL_RX_ALLMULTI ,
2009-02-04 09:02:45 +00:00
sg , 1 , 0 ) )
2009-02-04 09:02:40 +00:00
dev_warn ( & dev - > dev , " Failed to %sable allmulti mode. \n " ,
allmulti ? " en " : " dis " ) ;
2009-02-04 09:02:45 +00:00
2010-01-25 13:36:10 -08:00
uc_count = netdev_uc_count ( dev ) ;
2010-02-08 04:30:35 +00:00
mc_count = netdev_mc_count ( dev ) ;
2009-02-04 09:02:45 +00:00
/* MAC filter - use one buffer for both lists */
2010-02-08 04:30:35 +00:00
buf = kzalloc ( ( ( uc_count + mc_count ) * ETH_ALEN ) +
( 2 * sizeof ( mac_data - > entries ) ) , GFP_ATOMIC ) ;
mac_data = buf ;
2009-02-04 09:02:45 +00:00
if ( ! buf ) {
dev_warn ( & dev - > dev , " No memory for MAC address buffer \n " ) ;
return ;
}
2009-05-01 17:27:56 +00:00
sg_init_table ( sg , 2 ) ;
2009-02-04 09:02:45 +00:00
/* Store the unicast list and count in the front of the buffer */
2010-01-25 13:36:10 -08:00
mac_data - > entries = uc_count ;
2009-05-22 23:22:17 +00:00
i = 0 ;
2010-01-25 13:36:10 -08:00
netdev_for_each_uc_addr ( ha , dev )
2009-05-22 23:22:17 +00:00
memcpy ( & mac_data - > macs [ i + + ] [ 0 ] , ha - > addr , ETH_ALEN ) ;
2009-02-04 09:02:45 +00:00
sg_set_buf ( & sg [ 0 ] , mac_data ,
2010-01-25 13:36:10 -08:00
sizeof ( mac_data - > entries ) + ( uc_count * ETH_ALEN ) ) ;
2009-02-04 09:02:45 +00:00
/* multicast list and count fill the end */
2010-01-25 13:36:10 -08:00
mac_data = ( void * ) & mac_data - > macs [ uc_count ] [ 0 ] ;
2009-02-04 09:02:45 +00:00
2010-02-08 04:30:35 +00:00
mac_data - > entries = mc_count ;
2010-02-23 23:17:07 +00:00
i = 0 ;
netdev_for_each_mc_addr ( addr , dev )
memcpy ( & mac_data - > macs [ i + + ] [ 0 ] , addr - > da_addr , ETH_ALEN ) ;
2009-02-04 09:02:45 +00:00
sg_set_buf ( & sg [ 1 ] , mac_data ,
2010-02-08 04:30:35 +00:00
sizeof ( mac_data - > entries ) + ( mc_count * ETH_ALEN ) ) ;
2009-02-04 09:02:45 +00:00
if ( ! virtnet_send_command ( vi , VIRTIO_NET_CTRL_MAC ,
VIRTIO_NET_CTRL_MAC_TABLE_SET ,
sg , 2 , 0 ) )
dev_warn ( & dev - > dev , " Failed to set MAC fitler table. \n " ) ;
kfree ( buf ) ;
2009-02-04 09:02:40 +00:00
}
2009-05-01 17:31:10 +00:00
static void virtnet_vlan_rx_add_vid ( struct net_device * dev , u16 vid )
2009-02-04 09:02:50 +00:00
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
struct scatterlist sg ;
2009-05-01 17:27:56 +00:00
sg_init_one ( & sg , & vid , sizeof ( vid ) ) ;
2009-02-04 09:02:50 +00:00
if ( ! virtnet_send_command ( vi , VIRTIO_NET_CTRL_VLAN ,
VIRTIO_NET_CTRL_VLAN_ADD , & sg , 1 , 0 ) )
dev_warn ( & dev - > dev , " Failed to add VLAN ID %d. \n " , vid ) ;
}
2009-05-01 17:31:10 +00:00
static void virtnet_vlan_rx_kill_vid ( struct net_device * dev , u16 vid )
2009-02-04 09:02:50 +00:00
{
struct virtnet_info * vi = netdev_priv ( dev ) ;
struct scatterlist sg ;
2009-05-01 17:27:56 +00:00
sg_init_one ( & sg , & vid , sizeof ( vid ) ) ;
2009-02-04 09:02:50 +00:00
if ( ! virtnet_send_command ( vi , VIRTIO_NET_CTRL_VLAN ,
VIRTIO_NET_CTRL_VLAN_DEL , & sg , 1 , 0 ) )
dev_warn ( & dev - > dev , " Failed to kill VLAN ID %d. \n " , vid ) ;
}
2009-09-02 01:03:33 -07:00
static const struct ethtool_ops virtnet_ethtool_ops = {
2008-04-18 11:21:42 +08:00
. set_tx_csum = virtnet_set_tx_csum ,
. set_sg = ethtool_op_set_sg ,
2008-11-16 22:40:36 -08:00
. set_tso = ethtool_op_set_tso ,
2009-07-14 14:21:02 +00:00
. set_ufo = ethtool_op_set_ufo ,
2009-01-19 17:09:49 -08:00
. get_link = ethtool_op_get_link ,
2008-04-18 11:21:42 +08:00
} ;
2008-11-26 13:58:11 +00:00
# define MIN_MTU 68
# define MAX_MTU 65535
static int virtnet_change_mtu ( struct net_device * dev , int new_mtu )
{
if ( new_mtu < MIN_MTU | | new_mtu > MAX_MTU )
return - EINVAL ;
dev - > mtu = new_mtu ;
return 0 ;
}
2009-01-06 10:44:22 -08:00
static const struct net_device_ops virtnet_netdev = {
. ndo_open = virtnet_open ,
. ndo_stop = virtnet_close ,
. ndo_start_xmit = start_xmit ,
. ndo_validate_addr = eth_validate_addr ,
2009-02-04 16:36:34 -08:00
. ndo_set_mac_address = virtnet_set_mac_address ,
2009-02-04 09:02:40 +00:00
. ndo_set_rx_mode = virtnet_set_rx_mode ,
2009-01-06 10:44:22 -08:00
. ndo_change_mtu = virtnet_change_mtu ,
2009-05-01 17:31:10 +00:00
. ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid ,
. ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid ,
2009-01-06 10:44:22 -08:00
# ifdef CONFIG_NET_POLL_CONTROLLER
. ndo_poll_controller = virtnet_netpoll ,
# endif
} ;
2009-01-19 17:09:49 -08:00
static void virtnet_update_status ( struct virtnet_info * vi )
{
u16 v ;
if ( ! virtio_has_feature ( vi - > vdev , VIRTIO_NET_F_STATUS ) )
return ;
vi - > vdev - > config - > get ( vi - > vdev ,
offsetof ( struct virtio_net_config , status ) ,
& v , sizeof ( v ) ) ;
/* Ignore unknown (future) status bits */
v & = VIRTIO_NET_S_LINK_UP ;
if ( vi - > status = = v )
return ;
vi - > status = v ;
if ( vi - > status & VIRTIO_NET_S_LINK_UP ) {
netif_carrier_on ( vi - > dev ) ;
netif_wake_queue ( vi - > dev ) ;
} else {
netif_carrier_off ( vi - > dev ) ;
netif_stop_queue ( vi - > dev ) ;
}
}
static void virtnet_config_changed ( struct virtio_device * vdev )
{
struct virtnet_info * vi = vdev - > priv ;
virtnet_update_status ( vi ) ;
}
2007-10-22 11:03:37 +10:00
static int virtnet_probe ( struct virtio_device * vdev )
{
int err ;
struct net_device * dev ;
struct virtnet_info * vi ;
2009-06-12 22:16:36 -06:00
struct virtqueue * vqs [ 3 ] ;
vq_callback_t * callbacks [ ] = { skb_recv_done , skb_xmit_done , NULL } ;
const char * names [ ] = { " input " , " output " , " control " } ;
int nvqs ;
2007-10-22 11:03:37 +10:00
/* Allocate ourselves a network device with room for our info */
dev = alloc_etherdev ( sizeof ( struct virtnet_info ) ) ;
if ( ! dev )
return - ENOMEM ;
/* Set up network device as normal. */
2009-01-06 10:44:22 -08:00
dev - > netdev_ops = & virtnet_netdev ;
2007-10-22 11:03:37 +10:00
dev - > features = NETIF_F_HIGHDMA ;
2008-04-18 11:21:42 +08:00
SET_ETHTOOL_OPS ( dev , & virtnet_ethtool_ops ) ;
2007-10-22 11:03:37 +10:00
SET_NETDEV_DEV ( dev , & vdev - > dev ) ;
/* Do we support "hardware" checksums? */
2008-05-02 21:50:50 -05:00
if ( csum & & virtio_has_feature ( vdev , VIRTIO_NET_F_CSUM ) ) {
2007-10-22 11:03:37 +10:00
/* This opens up the world of extra features. */
dev - > features | = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_FRAGLIST ;
2008-05-02 21:50:50 -05:00
if ( gso & & virtio_has_feature ( vdev , VIRTIO_NET_F_GSO ) ) {
2008-02-04 23:50:02 -05:00
dev - > features | = NETIF_F_TSO | NETIF_F_UFO
| NETIF_F_TSO_ECN | NETIF_F_TSO6 ;
}
2008-05-02 21:50:46 -05:00
/* Individual feature bits: what can host handle? */
2008-05-02 21:50:50 -05:00
if ( gso & & virtio_has_feature ( vdev , VIRTIO_NET_F_HOST_TSO4 ) )
2008-05-02 21:50:46 -05:00
dev - > features | = NETIF_F_TSO ;
2008-05-02 21:50:50 -05:00
if ( gso & & virtio_has_feature ( vdev , VIRTIO_NET_F_HOST_TSO6 ) )
2008-05-02 21:50:46 -05:00
dev - > features | = NETIF_F_TSO6 ;
2008-05-02 21:50:50 -05:00
if ( gso & & virtio_has_feature ( vdev , VIRTIO_NET_F_HOST_ECN ) )
2008-05-02 21:50:46 -05:00
dev - > features | = NETIF_F_TSO_ECN ;
2008-05-02 21:50:50 -05:00
if ( gso & & virtio_has_feature ( vdev , VIRTIO_NET_F_HOST_UFO ) )
2008-05-02 21:50:46 -05:00
dev - > features | = NETIF_F_UFO ;
2007-10-22 11:03:37 +10:00
}
/* Configuration may specify what MAC to use. Otherwise random. */
2008-05-02 21:50:50 -05:00
if ( virtio_has_feature ( vdev , VIRTIO_NET_F_MAC ) ) {
2008-02-04 23:49:56 -05:00
vdev - > config - > get ( vdev ,
offsetof ( struct virtio_net_config , mac ) ,
dev - > dev_addr , dev - > addr_len ) ;
2009-04-04 16:40:19 -07:00
} else
2007-10-22 11:03:37 +10:00
random_ether_addr ( dev - > dev_addr ) ;
/* Set up our device-specific information */
vi = netdev_priv ( dev ) ;
2007-12-16 15:19:43 +02:00
netif_napi_add ( dev , & vi - > napi , virtnet_poll , napi_weight ) ;
2007-10-22 11:03:37 +10:00
vi - > dev = dev ;
vi - > vdev = vdev ;
2008-02-18 10:02:51 +01:00
vdev - > priv = vi ;
2008-07-25 12:06:01 -05:00
vi - > pages = NULL ;
2009-08-26 12:22:32 -07:00
INIT_DELAYED_WORK ( & vi - > refill , refill_work ) ;
2007-10-22 11:03:37 +10:00
2008-04-18 11:24:27 +08:00
/* If we can receive ANY GSO packets, we must allocate large ones. */
2009-12-03 07:58:21 +00:00
if ( virtio_has_feature ( vdev , VIRTIO_NET_F_GUEST_TSO4 ) | |
virtio_has_feature ( vdev , VIRTIO_NET_F_GUEST_TSO6 ) | |
virtio_has_feature ( vdev , VIRTIO_NET_F_GUEST_ECN ) )
2008-04-18 11:24:27 +08:00
vi - > big_packets = true ;
2008-11-16 22:41:34 -08:00
if ( virtio_has_feature ( vdev , VIRTIO_NET_F_MRG_RXBUF ) )
vi - > mergeable_rx_bufs = true ;
2009-06-12 22:16:36 -06:00
/* We expect two virtqueues, receive then send,
* and optionally control . */
nvqs = virtio_has_feature ( vi - > vdev , VIRTIO_NET_F_CTRL_VQ ) ? 3 : 2 ;
err = vdev - > config - > find_vqs ( vdev , nvqs , vqs , callbacks , names ) ;
if ( err )
2007-10-22 11:03:37 +10:00
goto free ;
2009-06-12 22:16:36 -06:00
vi - > rvq = vqs [ 0 ] ;
vi - > svq = vqs [ 1 ] ;
2007-10-22 11:03:37 +10:00
2009-02-04 09:02:34 +00:00
if ( virtio_has_feature ( vi - > vdev , VIRTIO_NET_F_CTRL_VQ ) ) {
2009-06-12 22:16:36 -06:00
vi - > cvq = vqs [ 2 ] ;
2009-02-04 09:02:50 +00:00
if ( virtio_has_feature ( vi - > vdev , VIRTIO_NET_F_CTRL_VLAN ) )
dev - > features | = NETIF_F_HW_VLAN_FILTER ;
2009-02-04 09:02:34 +00:00
}
2007-10-22 11:03:37 +10:00
err = register_netdev ( dev ) ;
if ( err ) {
pr_debug ( " virtio_net: registering device failed \n " ) ;
2009-06-12 22:16:36 -06:00
goto free_vqs ;
2007-10-22 11:03:37 +10:00
}
2008-02-04 23:50:02 -05:00
/* Last of all, set up some receive buffers. */
2009-08-26 12:22:32 -07:00
try_fill_recv ( vi , GFP_KERNEL ) ;
2008-02-04 23:50:02 -05:00
/* If we didn't even get one input buffer, we're useless. */
if ( vi - > num = = 0 ) {
err = - ENOMEM ;
goto unregister ;
}
2009-01-19 17:09:49 -08:00
vi - > status = VIRTIO_NET_S_LINK_UP ;
virtnet_update_status ( vi ) ;
2009-03-18 18:40:02 -07:00
netif_carrier_on ( dev ) ;
2009-01-19 17:09:49 -08:00
2007-10-22 11:03:37 +10:00
pr_debug ( " virtnet: registered device %s \n " , dev - > name ) ;
return 0 ;
2008-02-04 23:50:02 -05:00
unregister :
unregister_netdev ( dev ) ;
2009-08-26 12:22:32 -07:00
cancel_delayed_work_sync ( & vi - > refill ) ;
2009-06-12 22:16:36 -06:00
free_vqs :
vdev - > config - > del_vqs ( vdev ) ;
2007-10-22 11:03:37 +10:00
free :
free_netdev ( dev ) ;
return err ;
}
2010-01-29 03:20:04 +00:00
static void free_unused_bufs ( struct virtnet_info * vi )
{
void * buf ;
2010-02-08 14:14:42 +00:00
while ( 1 ) {
buf = vi - > svq - > vq_ops - > detach_unused_buf ( vi - > svq ) ;
if ( ! buf )
break ;
dev_kfree_skb ( buf ) ;
}
2010-01-29 03:20:04 +00:00
while ( 1 ) {
buf = vi - > rvq - > vq_ops - > detach_unused_buf ( vi - > rvq ) ;
if ( ! buf )
break ;
if ( vi - > mergeable_rx_bufs | | vi - > big_packets )
give_pages ( vi , buf ) ;
else
dev_kfree_skb ( buf ) ;
- - vi - > num ;
}
BUG_ON ( vi - > num ! = 0 ) ;
}
2009-09-30 22:28:34 +00:00
static void __devexit virtnet_remove ( struct virtio_device * vdev )
2007-10-22 11:03:37 +10:00
{
2007-11-19 11:20:42 -05:00
struct virtnet_info * vi = vdev - > priv ;
2008-02-04 23:50:02 -05:00
2008-02-04 23:50:03 -05:00
/* Stop all the virtqueues. */
vdev - > config - > reset ( vdev ) ;
2008-02-04 23:50:02 -05:00
2007-11-19 11:20:42 -05:00
unregister_netdev ( vi - > dev ) ;
2009-08-26 12:22:32 -07:00
cancel_delayed_work_sync ( & vi - > refill ) ;
2010-02-08 14:14:42 +00:00
/* Free unused buffers in both send and recv, if any. */
2010-01-29 03:20:04 +00:00
free_unused_bufs ( vi ) ;
2008-07-25 12:06:01 -05:00
2009-06-12 22:16:36 -06:00
vdev - > config - > del_vqs ( vi - > vdev ) ;
2008-07-25 12:06:01 -05:00
while ( vi - > pages )
__free_pages ( get_a_page ( vi , GFP_KERNEL ) , 0 ) ;
2007-11-19 11:20:42 -05:00
free_netdev ( vi - > dev ) ;
2007-10-22 11:03:37 +10:00
}
static struct virtio_device_id id_table [ ] = {
{ VIRTIO_ID_NET , VIRTIO_DEV_ANY_ID } ,
{ 0 } ,
} ;
2008-05-02 21:50:50 -05:00
static unsigned int features [ ] = {
2008-07-08 17:10:42 +10:00
VIRTIO_NET_F_CSUM , VIRTIO_NET_F_GUEST_CSUM ,
VIRTIO_NET_F_GSO , VIRTIO_NET_F_MAC ,
2008-05-02 21:50:50 -05:00
VIRTIO_NET_F_HOST_TSO4 , VIRTIO_NET_F_HOST_UFO , VIRTIO_NET_F_HOST_TSO6 ,
2008-04-18 11:24:27 +08:00
VIRTIO_NET_F_HOST_ECN , VIRTIO_NET_F_GUEST_TSO4 , VIRTIO_NET_F_GUEST_TSO6 ,
2009-07-14 14:21:02 +00:00
VIRTIO_NET_F_GUEST_ECN , VIRTIO_NET_F_GUEST_UFO ,
2009-02-04 09:02:34 +00:00
VIRTIO_NET_F_MRG_RXBUF , VIRTIO_NET_F_STATUS , VIRTIO_NET_F_CTRL_VQ ,
2009-02-04 09:02:50 +00:00
VIRTIO_NET_F_CTRL_RX , VIRTIO_NET_F_CTRL_VLAN ,
2008-05-02 21:50:50 -05:00
} ;
2009-11-05 01:32:44 -08:00
static struct virtio_driver virtio_net_driver = {
2008-05-02 21:50:50 -05:00
. feature_table = features ,
. feature_table_size = ARRAY_SIZE ( features ) ,
2007-10-22 11:03:37 +10:00
. driver . name = KBUILD_MODNAME ,
. driver . owner = THIS_MODULE ,
. id_table = id_table ,
. probe = virtnet_probe ,
. remove = __devexit_p ( virtnet_remove ) ,
2009-01-19 17:09:49 -08:00
. config_changed = virtnet_config_changed ,
2007-10-22 11:03:37 +10:00
} ;
static int __init init ( void )
{
2009-11-05 01:32:44 -08:00
return register_virtio_driver ( & virtio_net_driver ) ;
2007-10-22 11:03:37 +10:00
}
static void __exit fini ( void )
{
2009-11-05 01:32:44 -08:00
unregister_virtio_driver ( & virtio_net_driver ) ;
2007-10-22 11:03:37 +10:00
}
module_init ( init ) ;
module_exit ( fini ) ;
MODULE_DEVICE_TABLE ( virtio , id_table ) ;
MODULE_DESCRIPTION ( " Virtio network driver " ) ;
MODULE_LICENSE ( " GPL " ) ;