daily pastebin goal
61%
SHARE
TWEET

simple network device driver

a guest Jun 18th, 2012 19 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //-------------------------------------------------------------------
  2. //      mynetdvr.c
  3. //
  4. //      This module implements a minimal Linux network device-driver
  5. //      for our Intel PRO1000 gibabit ethernet interface controller.
  6. //
  7. //      NOTE: Written and tested with Linux kernel version 2.6.22.5.
  8. //
  9. //      programmer: ALLAN CRUSE
  10. //      written on: 22 FEB 2008
  11. //-------------------------------------------------------------------
  12.  
  13. #include <linux/module.h>       // for init_module()
  14. #include <linux/etherdevice.h>  // for alloc_etherdev()
  15. #include <linux/interrupt.h>    // for request_irq()
  16. #include <linux/proc_fs.h>      // for create_proc_info_entry()
  17. #include <linux/pci.h>          // for pci_get_device()
  18.  
  19. #define VENDOR_ID       0x8086  // Intel Corporation
  20. #define DEVICE_ID       0x109A  // 82573L controller
  21. //#define DEVICE_ID     0x10B9  // 82572EI controller
  22. #define INTR_MASK   0xFFFFFFFF  // nic interrupt mask
  23. #define N_RX_DESC            8  // number of RX Descriptors
  24. #define N_TX_DESC            8  // number of TX Descriptors
  25. #define RX_BUFSIZ         2048  // size of RX packet-buffer
  26. #define TX_BUFSIZ         2048  // size of TX packet-buffer
  27.  
  28.  
  29. typedef struct  {
  30.                 unsigned long long      base_address;
  31.                 unsigned short          packet_length;
  32.                 unsigned short          packet_chksum;
  33.                 unsigned char           desc_status;
  34.                 unsigned char           desc_errors;
  35.                 unsigned short          vlan_tag;
  36.                 } RX_DESCRIPTOR;
  37.  
  38. typedef struct  {
  39.                 unsigned long long      base_address;
  40.                 unsigned short          packet_length;
  41.                 unsigned char           cksum_offset;
  42.                 unsigned char           desc_command;
  43.                 unsigned char           desc_status;
  44.                 unsigned char           cksum_origin;
  45.                 unsigned short          special_info;
  46.                 } TX_DESCRIPTOR;
  47.  
  48.  
  49. typedef struct  {
  50.                 RX_DESCRIPTOR   rxring[ N_RX_DESC ];           
  51.                 TX_DESCRIPTOR   txring[ N_TX_DESC ];           
  52.                 unsigned char   rxbuff[ N_RX_DESC * RX_BUFSIZ ];
  53.                 unsigned char   txbuff[ N_TX_DESC * TX_BUFSIZ ];
  54.                 unsigned int    rxnext;
  55.                 struct tasklet_struct   rx_tasklet;
  56.                 } MY_DRIVERDATA;
  57.  
  58.  
  59.  
  60.  
  61. enum    {
  62.         E1000_CTRL      = 0x0000,       // Device Control
  63.         E1000_STATUS    = 0x0008,       // Device Status
  64.         E1000_ICR       = 0x00C0,       // Interrupt Cause Read
  65.         E1000_ICS       = 0x00C8,       // Interrupt Cause Set 
  66.         E1000_IMS       = 0x00D0,       // Interrupt Mask Set  
  67.         E1000_IMC       = 0x00D8,       // Interrupt Mask Clear
  68.         E1000_RCTL      = 0x0100,       // Receive Control
  69.         E1000_TCTL      = 0x0400,       // Transmit Control
  70.         E1000_RDBAL     = 0x2800,       // RX Descriptor Base-Address Low
  71.         E1000_RDBAH     = 0x2804,       // RX Descriptor Base-Address High
  72.         E1000_RDLEN     = 0x2808,       // RX Descriptor-queue Length  
  73.         E1000_RDH       = 0x2810,       // RX Descriptor-queue Head
  74.         E1000_RDT       = 0x2818,       // RX Descriptor-queue Tail
  75.         E1000_RXDCTL    = 0x2828,       // RX Descriptor-queue Control
  76.         E1000_TDBAL     = 0x3800,       // TX Descriptor Base-Address Low
  77.         E1000_TDBAH     = 0x3804,       // TX Descriptor Base-Address High
  78.         E1000_TDLEN     = 0x3808,       // TX Descriptor-queue Length  
  79.         E1000_TDH       = 0x3810,       // TX Descriptor-queue Head
  80.         E1000_TDT       = 0x3818,       // TX Descriptor-queue Tail
  81.         E1000_TXDCTL    = 0x3828,       // TX Descriptor-queue Control
  82.         E1000_RA        = 0x5400,       // Receive-address Array       
  83.         };
  84.  
  85.  
  86.  
  87. // function prototypes
  88. static int __init my_init( void );
  89. static void __exit my_exit( void );
  90. irqreturn_t my_isr( int, void * );
  91. void my_rx_handler( unsigned long );
  92. int my_open( struct net_device * );
  93. int my_stop( struct net_device * );
  94. int my_hard_start_xmit( struct sk_buff *, struct net_device * );
  95. int my_get_info( char *buf, char **start, off_t off, int buflen );
  96.  
  97. module_init( my_init );
  98. module_exit( my_exit );
  99. MODULE_LICENSE("GPL");
  100.  
  101.  
  102.  
  103. // global variables
  104. char modname[] = "mynetdvr";
  105. struct pci_dev  *devp;
  106. unsigned int    mmio_base;
  107. unsigned int    mmio_size;
  108. void            *io;
  109. struct net_device  *my_netdev;
  110.  
  111.  
  112.  
  113. static int __init my_init( void )
  114. {
  115.         u16     pci_cmd;
  116.  
  117.         printk( "<1>\nInstalling \'%s\' module\n", modname );
  118.  
  119.         // detect presence of the Intel Pro1000 controller
  120.         devp = pci_get_device( VENDOR_ID, DEVICE_ID, NULL );
  121.         if ( !devp ) return -ENODEV;
  122.  
  123.         // map the controller's i/o-memory into kernel space
  124.         mmio_base = pci_resource_start( devp, 0 );
  125.         mmio_size = pci_resource_len( devp, 0 );
  126.         io = ioremap_nocache( mmio_base, mmio_size );
  127.         if ( !io ) return -ENOSPC;
  128.  
  129.         // insure the controller's Bus Master capability is enabled
  130.         pci_read_config_word( devp, 4, &pci_cmd );
  131.         pci_cmd |= (1<<2);
  132.         pci_write_config_word( devp, 4, pci_cmd );
  133.  
  134.         // allocate kernel memory for the 'net_device' structure
  135.         my_netdev = alloc_etherdev( sizeof( MY_DRIVERDATA ) );
  136.         if ( !my_netdev ) { iounmap( io ); return -ENOMEM; }
  137.  
  138.         // initialize essential fields in the 'net_device' structure
  139.         memcpy( my_netdev->perm_addr, io + E1000_RA, 6 );
  140.         memcpy( my_netdev->dev_addr,  io + E1000_RA, 6 );
  141.  
  142.         my_netdev->open                 = my_open;
  143.         my_netdev->stop                 = my_stop;
  144.         my_netdev->hard_start_xmit      = my_hard_start_xmit;
  145.         my_netdev->mem_start            = mmio_base;
  146.         my_netdev->mem_end              = mmio_base + mmio_size;
  147.         my_netdev->irq                  = devp->irq;
  148.         my_netdev->flags                |= IFF_PROMISC;
  149.  
  150.         // create our driver's pseudo-file (for debugging)
  151.         create_proc_info_entry( modname, 0, NULL, my_get_info );
  152.  
  153.         // register this driver's 'net_device' structure
  154.         return  register_netdev( my_netdev );
  155. }
  156.  
  157.  
  158. static void __exit my_exit( void )
  159. {
  160.         remove_proc_entry( modname, NULL );
  161.  
  162.         unregister_netdev( my_netdev );
  163.         iounmap( io );
  164.         free_netdev( my_netdev );
  165.  
  166.         printk( "<1>Removing \'%s\' module\n", modname );
  167. }
  168.  
  169. int my_open( struct net_device *dev )
  170. {
  171.         //--------------------------------------------------------
  172.         // The kernel calls this function whenever the 'ifconfig'
  173.         // command is executed to bring up the device interface.
  174.         // This function needs to call 'netif_start_queue()'.
  175.         //--------------------------------------------------------
  176.  
  177.         MY_DRIVERDATA   *mdp = (MY_DRIVERDATA *)dev->priv;     
  178.         RX_DESCRIPTOR   *rxq = mdp->rxring;
  179.         TX_DESCRIPTOR   *txq = mdp->txring;
  180.         unsigned long   rbuf = virt_to_phys( mdp->rxbuff );
  181.         unsigned long   tbuf = virt_to_phys( mdp->txbuff );
  182.         unsigned long   rxdescaddr = virt_to_phys( rxq );
  183.         unsigned long   txdescaddr = virt_to_phys( txq );
  184.         int             i;
  185.  
  186.         printk( " %s: opening the \'%s\' device \n", modname, dev->name );
  187.  
  188.         // reset the network controller
  189.         iowrite32( 0xFFFFFFFF, io + E1000_IMC );       
  190.         iowrite32( 0x00000000, io + E1000_STATUS );
  191.         iowrite32( 0x040C0241, io + E1000_CTRL );
  192.         iowrite32( 0x000C0241, io + E1000_CTRL );
  193.         while ( ( ioread32( io + E1000_STATUS )&3 ) != 3 );
  194.  
  195.         // initialize the RX Descriptor-queues
  196.         for (i = 0; i < N_RX_DESC; i++ )
  197.                 {
  198.                 rxq[ i ].base_address = rbuf + i * RX_BUFSIZ;
  199.                 rxq[ i ].packet_length = 0;
  200.                 rxq[ i ].packet_chksum = 0;
  201.                 rxq[ i ].desc_status = 0;
  202.                 rxq[ i ].desc_errors = 0;
  203.                 rxq[ i ].vlan_tag = 0;
  204.                 }
  205.  
  206.         // initialize the TX Descriptor-queues
  207.         for (i = 0; i < N_TX_DESC; i++ )
  208.                 {
  209.                 txq[ i ].base_address = tbuf + i * TX_BUFSIZ;
  210.                 txq[ i ].packet_length = 0;
  211.                 txq[ i ].cksum_offset = 0;
  212.                 txq[ i ].desc_command = (1<<0)|(1<<1)|(1<<3);   // EOP/IFCS/RS
  213.                 txq[ i ].desc_status = 0;
  214.                 txq[ i ].cksum_origin = 0;
  215.                 txq[ i ].special_info = 0;
  216.                 }
  217.  
  218.         // configure the controller's Receive Engine
  219.         iowrite32( 0x0400801C, io + E1000_RCTL );
  220.         iowrite32( rxdescaddr, io + E1000_RDBAL );
  221.         iowrite32( 0x00000000, io + E1000_RDBAH );
  222.         iowrite32( N_RX_DESC * 16, io + E1000_RDLEN );
  223.         iowrite32( 0x01010000, io + E1000_RXDCTL );
  224.  
  225.         // configure the controller's Transmit Engine
  226.         iowrite32( 0x0103F0F8, io + E1000_TCTL );
  227.         iowrite32( txdescaddr, io + E1000_TDBAL );
  228.         iowrite32( 0x00000000, io + E1000_TDBAH );
  229.         iowrite32( N_TX_DESC * 16, io + E1000_TDLEN );
  230.         iowrite32( 0x01010000, io + E1000_TXDCTL );
  231.  
  232.         // initialize our tasklet
  233.         mdp->rxnext = 0;
  234.         tasklet_init( &mdp->rx_tasklet, my_rx_handler, (unsigned long)dev );
  235.  
  236.         // install our driver's interrupt-handler
  237.         i = dev->irq;
  238.         if ( request_irq( i, my_isr, IRQF_SHARED, dev->name, dev ) < 0 )
  239.                 return -EBUSY;
  240.  
  241.         // unmask interrupts
  242.         ioread32( io + E1000_ICR );
  243.         iowrite32( INTR_MASK, io + E1000_IMS );
  244.  
  245.         // start the receive engine
  246.         iowrite32( N_RX_DESC, io + E1000_RDT );
  247.         iowrite32( ioread32( io + E1000_RCTL ) | (1<<1), io + E1000_RCTL );
  248.                
  249.         // start the transmit engine
  250.         iowrite32( ioread32( io + E1000_TCTL ) | (1<<1), io + E1000_TCTL );
  251.         netif_start_queue( dev );
  252.         return  0;  // SUCCESS
  253. }
  254.  
  255.  
  256. int my_stop( struct net_device *dev )
  257. {
  258.         //--------------------------------------------------------
  259.         // The kernel calls this function whenever the 'ifconfig'
  260.         // command is executed to shut down the device interface.
  261.         // This function needs to call 'netif_stop_queue()'.
  262.         //--------------------------------------------------------
  263.  
  264.         MY_DRIVERDATA   *mdp = (MY_DRIVERDATA *)dev->priv;     
  265.  
  266.         printk( " %s: stopping the \'%s\' device \n", modname, dev->name );
  267.  
  268.         // stop the controller's transmit and receive engines
  269.         iowrite32( ioread32( io + E1000_RCTL ) & ~(1<<1), io + E1000_RCTL );
  270.         iowrite32( ioread32( io + E1000_TCTL ) & ~(1<<1), io + E1000_TCTL );
  271.  
  272.         // disable controller interrupts and remove interrupt-handler
  273.         iowrite32( 0xFFFFFFFF, io + E1000_IMC );
  274.         free_irq( dev->irq, dev );
  275.  
  276.         // stop our tasklet and the network interface queue
  277.         tasklet_kill( &mdp->rx_tasklet );
  278.         netif_stop_queue( dev );
  279.         return  0;  // SUCCESS
  280. }
  281.  
  282.  
  283. int my_hard_start_xmit( struct sk_buff *skb, struct net_device *dev )
  284. {
  285.         //------------------------------------------------------------
  286.         // The kernel calls this function whenever its protocol layer
  287.         // has a packet that it wants the controller to transmit.  It
  288.         // must either call the 'netif_free_skb()' function itself or
  289.         // else arrange for it to be called by our interrupt-handler.  
  290.         //------------------------------------------------------------
  291.  
  292.         MY_DRIVERDATA   *mdp = (MY_DRIVERDATA*)dev->priv;
  293.         TX_DESCRIPTOR   *txq = mdp->txring;
  294.         unsigned int    curr = ioread32( io + E1000_TDT );
  295.         unsigned int    next = (1 + curr) % N_TX_DESC;
  296.         unsigned char   *src = skb->data;
  297.         unsigned char   *dst = phys_to_virt( txq[ curr ].base_address );
  298.         unsigned short  len  = skb->len;
  299.  
  300.         // save the timestamp
  301.         dev->trans_start = jiffies;
  302.  
  303.         // copy the socket-buffer's data into the next packet-buffer
  304.         if ( len > TX_BUFSIZ ) len = TX_BUFSIZ;
  305.         memcpy( dst, src, len );
  306.  
  307.         // setup the next TX Descriptor
  308.         txq[ curr ].packet_length = len;
  309.         txq[ curr ].cksum_offset = 0;
  310.         txq[ curr ].cksum_origin = 0;
  311.         txq[ curr ].special_info = 0;
  312.         txq[ curr ].desc_status = 0;
  313.         txq[ curr ].desc_command = (1<<0)|(1<<1)|(1<<3);  // EOP/IFCS/RS
  314.                
  315.         // initiate the transmission
  316.         iowrite32( next, io + E1000_TDT );
  317.  
  318.         // update the 'net_device' statistics
  319.         dev->stats.tx_packets += 1;
  320.         dev->stats.tx_bytes += len;
  321.  
  322.         // it is essential to free the socket-buffer structure
  323.         dev_kfree_skb( skb );
  324.         return  0;  // SUCCESS
  325. }
  326.  
  327.  
  328. void my_rx_handler( unsigned long data )
  329. {
  330.         //--------------------------------------------------------------
  331.         // This function is scheduled by our driver's interrupt-handler
  332.         // whenever the controller has received some new packets.
  333.         //--------------------------------------------------------------
  334.  
  335.         struct net_device       *dev = (struct net_device*)data;
  336.         MY_DRIVERDATA           *mdp = (MY_DRIVERDATA*)dev->priv;
  337.         RX_DESCRIPTOR           *rdq = (RX_DESCRIPTOR*)mdp->rxring;
  338.         unsigned int            curr = mdp->rxnext;
  339.         void                    *src = phys_to_virt( rdq[ curr ].base_address );
  340.         int                     len = rdq[ curr ].packet_length;
  341.         struct sk_buff          *skb = dev_alloc_skb( len + NET_IP_ALIGN );
  342.  
  343.         // allocate a new socket-buffer
  344.         if ( !skb ) { dev->stats.rx_dropped += 1; return; }
  345.  
  346.         // copy received packet-data into this socket-buffer
  347.         memcpy( skb_put( skb, len ), src, len );
  348.  
  349.         // adjust the socket-buffer's parameters
  350.         skb->dev = dev;
  351.         skb->protocol = eth_type_trans( skb, dev );
  352.         skb->ip_summed = CHECKSUM_NONE;
  353.        
  354.         // clear the current descriptor's status
  355.         rdq[ curr ].desc_status = 0;
  356.         rdq[ curr ].desc_errors = 0;
  357.        
  358.         // advance our driver's 'rxnext' index
  359.         mdp->rxnext = (1 + curr) % N_RX_DESC;
  360.  
  361.         // update the 'net_device' statistics
  362.         dev->stats.rx_packets += 1;
  363.         dev->stats.rx_bytes += len;
  364.  
  365.         // record the timestamp
  366.         dev->last_rx = jiffies;
  367.  
  368.         // now hand over the socket-buffer to the kernel
  369.         netif_rx( skb );
  370. }
  371.  
  372.  
  373. irqreturn_t my_isr( int irq, void *dev_id )
  374. {
  375.         struct net_device       *dev = (struct net_device*)dev_id;
  376.         MY_DRIVERDATA           *mdp = (MY_DRIVERDATA*)dev->priv;
  377.         unsigned int            intr_cause = ioread32( io + E1000_ICR );
  378.  
  379.         if ( intr_cause == 0 ) return IRQ_NONE;
  380.  
  381.         // clear these interrupts
  382.         iowrite32( intr_cause, io + E1000_ICR );
  383.  
  384.         // schedule our interrupt-handler's 'bottom-half'
  385.         if ( intr_cause & (1<<7) ) tasklet_schedule( &mdp->rx_tasklet );
  386.  
  387.         return  IRQ_HANDLED;
  388. }
  389.  
  390.  
  391.  
  392.  
  393.  
  394. int my_get_info( char *buf, char **start, off_t off, int buflen )
  395. {
  396.         MY_DRIVERDATA           *mdp = (MY_DRIVERDATA*)my_netdev->priv;
  397.         RX_DESCRIPTOR           *rdq = mdp->rxring;
  398.         TX_DESCRIPTOR           *tdq = mdp->txring;
  399.         unsigned int            rxhead = ioread32( io + E1000_RDH );
  400.         unsigned int            rxtail = ioread32( io + E1000_RDT );
  401.         unsigned int            txhead = ioread32( io + E1000_TDH );
  402.         unsigned int            txtail = ioread32( io + E1000_TDT );
  403.         int                     i, len = 0;
  404.  
  405.         len += sprintf( buf+len, "\n Receive-Descriptor Queue " );
  406.         len += sprintf( buf+len, "(head=%d, tail=%d) \n\n", rxhead, rxtail );
  407.         for (i = 0; i < N_RX_DESC; i++)
  408.                 {
  409.                 unsigned int    ba = virt_to_phys( rdq+i );
  410.                 len += sprintf( buf+len, " #%-2d ", i );
  411.                 len += sprintf( buf+len, "%08X: ", ba );
  412.                 len += sprintf( buf+len, "%016llX ", rdq[i].base_address );    
  413.                 len += sprintf( buf+len, "%04X ", rdq[i].packet_length );      
  414.                 len += sprintf( buf+len, "%04X ", rdq[i].packet_chksum );      
  415.                 len += sprintf( buf+len, "%02X ", rdq[i].desc_status );        
  416.                 len += sprintf( buf+len, "%02X ", rdq[i].desc_errors );        
  417.                 len += sprintf( buf+len, "%04X ", rdq[i].vlan_tag );    
  418.                 len += sprintf( buf+len, "\n" );
  419.                 }
  420.        
  421.         len += sprintf( buf+len, "\n Transmit-Descriptor Queue " );
  422.         len += sprintf( buf+len, "(head=%d, tail=%d) \n\n", txhead, txtail );
  423.         for (i = 0; i < N_TX_DESC; i++)
  424.                 {
  425.                 unsigned int    ba = virt_to_phys( tdq+i );
  426.                 len += sprintf( buf+len, " #%-2d ", i );
  427.                 len += sprintf( buf+len, "%08X: ", ba );
  428.                 len += sprintf( buf+len, "%016llX ", tdq[i].base_address );    
  429.                 len += sprintf( buf+len, "%04X ", tdq[i].packet_length );      
  430.                 len += sprintf( buf+len, "%02X ", tdq[i].cksum_offset );        
  431.                 len += sprintf( buf+len, "%02X ", tdq[i].desc_command );        
  432.                 len += sprintf( buf+len, "%02X ", tdq[i].desc_status );        
  433.                 len += sprintf( buf+len, "%02X ", tdq[i].cksum_origin );        
  434.                 len += sprintf( buf+len, "%04X ", tdq[i].special_info );        
  435.                 len += sprintf( buf+len, "\n" );
  436.                 }
  437.  
  438.         len += sprintf( buf+len, "\n" );
  439.         return  len;
  440. }
RAW Paste Data
Pastebin PRO WINTER Special!
Get 40% OFF Pastebin PRO accounts!
Top