Guest User

simple network device driver

a guest
Jun 18th, 2012
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.22 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment