//------------------------------------------------------------------- // txburst.c (For demonstrating hardware flow control) // // This module allows the user to trigger the transmission of // multiple network packets in a single burst, either with or // without our Intel controller's flow control being enabled. // // programmer: ALLAN CRUSE // written on: 26 FEB 2008 //------------------------------------------------------------------- #include // for init_module() #include // for create_proc_info_entry() #include // for pci_get_device() #define VENDOR_ID 0x8086 // Intel Corporation #define DEVICE_ID 0x109A // 82573L controller //#define DEVICE_ID 0x10B9 // 82572EI controller #define N_TX_DESC 32 // number of TX Descriptors #define PKTBUF_LEN 0x0600 // length of packet-buffers #define KMEM_SIZE (N_TX_DESC * PKTBUF_LEN + (1<<12)) typedef struct { unsigned long long base_address; unsigned short packet_length; unsigned char cksum_offset; unsigned char desc_command; unsigned char desc_status; unsigned char cksum_origin; unsigned short special_info; } TX_DESCRIPTOR; enum { E1000_CTRL = 0x0000, E1000_STATUS = 0x0008, E1000_IMC = 0x00D8, E1000_RCTL = 0x0100, E1000_TCTL = 0x0400, E1000_TDBAL = 0x3800, E1000_TDBAH = 0x3804, E1000_TDLEN = 0x3808, E1000_TDH = 0x3810, E1000_TDT = 0x3818, E1000_TXDCTL = 0x3828, E1000_RA = 0x5400, E1000_FCAL = 0x0028, // Flow Control Address Low E1000_FCAH = 0x002C, // Flow Control Address High E1000_FCT = 0x0030, // Flow Control Type E1000_FCTTV = 0x0170, // Flow Control TX Timer Value E1000_FCRTL = 0x2160, // Flow Control RX Threshold Low E1000_FCRTH = 0x2168, // Flow Control RX Threshold High E1000_XONRXC = 0x4048, // XON Received Count E1000_XONTXC = 0x404C, // XON Transmitted Count E1000_XOFFRXC = 0x4050, // XOFF Received Count E1000_XOFFTXC = 0x4054, // XOFF Transmitted Count }; char modname[] = "txburst"; struct pci_dev *devp; unsigned int mmio_base; unsigned int mmio_size; void *io, *kmem; unsigned int kmem_phys; TX_DESCRIPTOR *txring; int my_get_info( char *buf, char **start, off_t off, int count ) { // turns on the 'transmit' engine iowrite32( ioread32( io + E1000_TCTL ) | (1<<1), io + E1000_TCTL ); return sprintf( buf, "\ntransmitting packet-burst\n\n" ); } static int __init my_init( void ) { u16 cmd; int i; printk( "<1>\nInstalling \'%s\' module\n", modname ); // detect the Intel PRO1000 network controller devp = pci_get_device( VENDOR_ID, DEVICE_ID, NULL ); if ( !devp ) return -ENODEV; // remap controller's i/o-memory to kernel address-range mmio_base = pci_resource_start( devp, 0 ); mmio_size = pci_resource_len( devp, 0 ); io = ioremap_nocache( mmio_base, mmio_size ); if ( !io ) return -ENOSPC; // allocate memory for descriptors and packet-buffers kmem = kzalloc( KMEM_SIZE, GFP_KERNEL ); if ( !kmem ) { iounmap( io ); return -ENOMEM; } kmem_phys = virt_to_phys( kmem ); printk( " physmem = %08X \n", kmem_phys ); // initialize our TX descriptors txring = (TX_DESCRIPTOR*)kmem; for (i = 0; i < N_TX_DESC; i++) { unsigned int addr = kmem_phys + (1<<12) + i*PKTBUF_LEN; txring[ i ].base_address = addr; txring[ i ].desc_command = (1<<0)|(1<<1)|(1<<3); txring[ i ].packet_length = 1500; txring[ i ].desc_status = 0; txring[ i ].cksum_origin = 0; txring[ i ].cksum_offset = 0; txring[ i ].special_info = 0; } // initialize our packet-buffers for (i = 0; i < N_TX_DESC; i++) { unsigned char *cp = phys_to_virt( txring[i].base_address ); memset( cp+0, 0xFF, 6 ); memcpy( cp+6, io + E1000_RA, 6 ); memset( cp+12, 0x08, 1 ); memset( cp+13, 0x00, 1 ); *(short*)(cp+14) = 60; memset( cp+16, 'a' + i, 60 ); cp[ 75 ] = '\n'; } // insure Bus Master cabability is enabled pci_read_config_word( devp, 4, &cmd ); cmd |= (1<<2); pci_write_config_word( devp, 4, cmd ); // reset the network controller iowrite32( 0xFFFFFFFF, io + E1000_IMC ); iowrite32( 0x00000000, io + E1000_STATUS ); iowrite32( 0x040C0241, io + E1000_CTRL ); iowrite32( 0x000C0241, io + E1000_CTRL ); while ( ( ioread32( io + E1000_STATUS ) & 3 ) != 3 ); // configure the 'receive' and 'transmit' engines iowrite32( 0x0480001E, io + E1000_RCTL ); iowrite32( 0x0103F0F8, io + E1000_TCTL ); iowrite32( kmem_phys, io + E1000_TDBAL ); iowrite32( 0x00000000, io + E1000_TDBAH ); iowrite32( 16 * N_TX_DESC, io + E1000_TDLEN ); iowrite32( 0x01010000, io + E1000_TXDCTL ); iowrite32( 26, io + E1000_TDT ); // configure Flow Control iowrite32( 0x00C28001, io + E1000_FCAL ); iowrite32( 0x00000100, io + E1000_FCAH ); iowrite32( 0x00008808, io + E1000_FCT ); iowrite32( 0x00000680, io + E1000_FCTTV ); iowrite32( 0x800047F8, io + E1000_FCRTL ); iowrite32( 0x00004800, io + E1000_FCRTH ); // clear statistics registers ioread32( io + E1000_XOFFRXC ); ioread32( io + E1000_XONRXC ); ioread32( io + E1000_XOFFTXC ); ioread32( io + E1000_XONTXC ); // enable flow control ///// iowrite32( ioread32( io + E1000_CTRL ) | (3<<27), io + E1000_CTRL ); create_proc_info_entry( modname, 0, NULL, my_get_info ); return 0; //SUCCESS } static void __exit my_exit(void ) { remove_proc_entry( modname, NULL ); iowrite32( 0xFFFFFFFF, io + E1000_IMC ); iowrite32( ioread32( io + E1000_TCTL ) & ~(1<<1), io + E1000_TCTL ); iowrite32( ioread32( io + E1000_RCTL ) & ~(1<<1), io + E1000_RCTL ); iowrite32( ioread32( io + E1000_CTRL ) & ~(3<<27), io + E1000_CTRL ); printk( "<1>Removing \'%s\' module\n", modname ); printk( "\n" ); printk( "XOFF packets sent = %d ", ioread32( io + E1000_XOFFTXC ) ); printk( "XOFF packets received = %d ", ioread32( io + E1000_XOFFRXC ) ); printk( "\n" ); printk( "XON packets sent = %d ", ioread32( io + E1000_XONTXC ) ); printk( "XON packets received = %d ", ioread32( io + E1000_XONTXC ) ); printk( "\n" ); kfree( kmem ); iounmap( io ); } module_init( my_init ); module_exit( my_exit ); MODULE_LICENSE("GPL");