//------------------------------------------------------------------- // pktsplit.c // // We try using the Pro1000's packet-split receive capability. // // NOTE: Written and tested for Linux kernel version 2.6.22.5. // // programmer: ALLAN CRUSE // written on: 08 JAN 2008 // revised on: 15 APR 2008 // revised on: 17 APR 2008 -- to correct KMEM_SIZE allocation //------------------------------------------------------------------- #include // for init_module() #include // for create_proc_info_entry() #include // for pci_get_device() #include // for ioremap() #include // for virt_to_phys() #define VENDOR_ID 0x8086 // Intel Corporation #define DEVICE_ID 0x109A // 82573L controller //#define DEVICE_ID 0x10B9 // 82572EI controller #define N_RX_DESC 16 // Number of RX Descriptors #define RX_BUFSIZ 1024 // Size of RX Packet-Buffer #define KMEM_SIZE ((32 + 4*RX_BUFSIZ)*N_RX_DESC) // kernel memory allocation typedef struct { unsigned long long base_addr0; unsigned long long base_addr1; unsigned long long base_addr2; unsigned long long base_addr3; } RX_DESC_FETCH; typedef struct { unsigned int mrq; unsigned short ip_identifier; unsigned short packet_chksum; unsigned int desc_status:20; unsigned int desc_errors:12; unsigned short packet_length0; unsigned short vlan_tag; unsigned short header_length:10; unsigned short header_unused:5; unsigned short header_split:1; unsigned short packet_length1; unsigned short packet_length2; unsigned short packet_length3; unsigned long long reserved; } RX_DESC_STORE; typedef union { RX_DESC_FETCH rxf; RX_DESC_STORE rxs; } RX_DESCRIPTOR; enum { E1000_CTRL = 0x0000, // Device Control E1000_STATUS = 0x0008, // Device Status E1000_CTRL_EXT = 0x0018, // Device Control Extended E1000_VET = 0x0038, // VLAN Ether Type E1000_IMC = 0x00D8, // Interrupt Mask Clear E1000_RCTL = 0x0100, // Receive Control E1000_PSRCTL = 0x2170, // Packet Split Receive Control E1000_RDBAL = 0x2800, // Rx-Descriptor Base Address Low E1000_RDBAH = 0x2804, // Rx-Descriptor Base Address High E1000_RDLEN = 0x2808, // Rx-Descriptor queue Length E1000_RDH = 0x2810, // Receive Descriptor Head E1000_RDT = 0x2818, // Receive Descriptor Tail E1000_RXDCTL = 0x2828, // Receive Descriptor Control E1000_TPR = 0x40D0, // Total Packets Received E1000_RFCTL = 0x5008, // Receive Filter Control E1000_RA = 0x5400, // Receive-address Array E1000_VFTA = 0x5600, // VLAN Filter Table Array }; char modname[] = "pktsplit"; char info_rx[] = "nicrx"; struct pci_dev *devp; unsigned char mac[6]; unsigned short vlan_id = 0x456; unsigned long mmio_base; unsigned long mmio_size; void *io, *kmem; unsigned long kmem_phys; RX_DESCRIPTOR *rxring; int my_get_info_rx( char *buf, char **start, off_t off, int count ); static int __init pktsplit_init( void ) { u16 pci_cmd; unsigned int baphys; int i, device_stat, device_ctrl, rx_control; printk( "<1>\nInstalling \'%s\' module\n", modname ); devp = pci_get_device( VENDOR_ID, DEVICE_ID, NULL ); if ( !devp ) return -ENODEV; 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; memcpy( mac, io + E1000_RA, 6 ); kmem = kzalloc( KMEM_SIZE, GFP_KERNEL ); if ( !kmem ) { iounmap( io ); return -ENOMEM; } kmem_phys = virt_to_phys( kmem ); printk( "\n Intel PRO1000 gigabit ethernet controller " ); printk( "-- HW-ADDRESS " ); for (i = 0; i < 6; i++) printk( "%02X%c", mac[i], (i<5) ? ':' : ' ' ); printk( "\n" ); printk( " kernel memory allocated at physical address %08lX \n", kmem_phys ); device_ctrl = ioread32( io + E1000_CTRL ); device_stat = ioread32( io + E1000_STATUS ); printk( " DEVICE CONTROL = %08X ", device_ctrl ); printk( " DEVICE_STATUS = %08X \n", device_stat ); pci_read_config_word( devp, 4, &pci_cmd ); pci_cmd |= (1<<2); pci_write_config_word( devp, 4, pci_cmd ); rxring = phys_to_virt( kmem_phys ); baphys = kmem_phys + 32*N_RX_DESC; for (i = 0; i < N_RX_DESC; i++) { unsigned long where = baphys + i * (4 * RX_BUFSIZ); rxring[i].rxf.base_addr0 = where + 0 * RX_BUFSIZ; rxring[i].rxf.base_addr1 = where + 1 * RX_BUFSIZ; rxring[i].rxf.base_addr2 = where + 2 * RX_BUFSIZ; rxring[i].rxf.base_addr3 = where + 3 * RX_BUFSIZ; } iowrite32( 0xFFFFFFFF, io + E1000_IMC ); iowrite32( 0x440C0241, io + E1000_CTRL ); iowrite32( 0x400C0241, io + E1000_CTRL ); udelay( 10000 ); iowrite32( 0x001401C0, io + E1000_CTRL_EXT ); iowrite32( 0x01010101, io + E1000_PSRCTL ); // 128B/1KB/1KB/1KB iowrite32( 0x00008000, io + E1000_RFCTL ); // enable packet-split iowrite32( kmem_phys, io + E1000_RDBAL ); iowrite32( 0x00000000, io + E1000_RDBAH ); iowrite32( 32*N_RX_DESC, io + E1000_RDLEN ); iowrite32( 0x01010000, io + E1000_RXDCTL ); for (i = 0; i < 0x200; i+=4) iowrite32( 0, io + 0x4000 + i ); for (i = 0; i < 0x200; i+=4) iowrite32( 0, io + E1000_VFTA + i ); iowrite32( 0x00008100, io + E1000_VET ); iowrite32( 1 << (vlan_id & 0x1F), io + E1000_VFTA + (vlan_id>>5)*4 ); rx_control = 0; rx_control |= (1<<1); // EN-bit (Enable Receive Engine) rx_control |= (1<<2); // SPB-bit (StoreBad Packets) rx_control |= (1<<3); // UPE-bit (Unicast Promiscuous Mode) rx_control |= (1<<4); // MPE-bit (Multicast Promiscuous Mode) rx_control |= (0<<5); // LPE-bit (Long Packet Enable) rx_control |= (0<<6); // LBM=0 (Loopback Mode off) rx_control |= (0<<8); // RDMTS=0 (Rx-Descriptor Min Thresh Size) rx_control |= (1<<10); // DTYPE=1 (Descriptor Type) rx_control |= (0<<12); // MO=0 ()Multicast Offset) rx_control |= (1<<15); // BAM-bit (Broadcast Address Enable) rx_control |= (0<<16); // BSIZE=0 (Receive Buffer Size = 2048) rx_control |= (1<<18); // VLE-bit (VLAN Filter Enable) rx_control |= (0<<19); // CFIEN-bit (Canonical Form Indicator Enable) rx_control |= (0<<20); // CFI=0 (Canonical Form Indicator bit-value) rx_control |= (0<<22); // DPF-bit (Discard Pause Frames) rx_control |= (1<<23); // PMCF-bit (Pass MAC Control Frames) rx_control |= (0<<25); // BSEX=0 (Buffer Size Extension) rx_control |= (0<<26); // SECRC-bit (Strip Ethernet CRC) rx_control |= (1<<27); // FLXBUF=0 (Flexible Buffer-size) iowrite32( rx_control, io + E1000_RCTL ); iowrite32( 0x00000008, io + E1000_RDT ); create_proc_info_entry( info_rx, 0, NULL, my_get_info_rx ); return 0; //SUCCESS } int my_get_info_rx( char *buf, char **start, off_t off, int count ) { int i, head, tail, len = 0; static int n_rx_packets = 0; head = ioread32( io + E1000_RDH ); tail = ioread32( io + E1000_RDT ); n_rx_packets += ioread32( io + E1000_TPR ); len += sprintf( buf+len, "\nReceive-Descriptor Ring-Buffer " ); len += sprintf( buf+len, "(head=%d, tail=%d) ", head, tail ); len += sprintf( buf+len, " Phys-Address=0x%08lX \n\n", kmem_phys ); for (i = 0; i < N_RX_DESC; i++) { len += sprintf( buf+len, " #%-2d ", i ); if ( rxring[ i ].rxs.reserved & 1 ) { RX_DESC_STORE *rdp = (RX_DESC_STORE*)&rxring[i].rxs; unsigned int stat = rdp->desc_status; unsigned int errs = rdp->desc_errors; len += sprintf( buf+len, "%04X ", rdp->vlan_tag ); len += sprintf( buf+len, "%04X ", rdp->packet_chksum ); len += sprintf( buf+len, "%04X ", rdp->header_length ); len += sprintf( buf+len, "%1X ", rdp->header_split ); len += sprintf( buf+len, "%04X ", rdp->packet_length0); len += sprintf( buf+len, "%04X ", rdp->packet_length1); len += sprintf( buf+len, "%04X ", rdp->packet_length2); len += sprintf( buf+len, "%04X ", rdp->packet_length3); if ( stat&(1<<0) ) len += sprintf( buf+len, "DD " ); if ( stat&(1<<1) ) len += sprintf( buf+len, "EOP " ); if ( stat&(1<<2) ) len += sprintf( buf+len, "IXSM " ); if ( stat&(1<<3) ) len += sprintf( buf+len, "VP " ); if ( stat&(1<<4) ) len += sprintf( buf+len, "UDPCS " ); if ( stat&(1<<5) ) len += sprintf( buf+len, "TCPCS " ); if ( stat&(1<<6) ) len += sprintf( buf+len, "IPCS " ); if ( stat&(1<<7) ) len += sprintf( buf+len, "PIF " ); if ( stat&(1<<9) ) len += sprintf( buf+len, "IPIDV " ); if ( stat&(1<<10) ) len += sprintf( buf+len, "UDPV " ); if ( stat&(1<<15) ) len += sprintf( buf+len, "ACK " ); len += sprintf( buf+len, " " ); if ( errs&(1<<4) ) len += sprintf( buf+len, "CE " ); if ( errs&(1<<5) ) len += sprintf( buf+len, "SE " ); if ( errs&(1<<6) ) len += sprintf( buf+len, "SEQ " ); if ( errs&(1<<9) ) len += sprintf( buf+len, "TCPE " ); if ( errs&(1<<10) ) len += sprintf( buf+len, "IPE " ); if ( errs&(1<<11) ) len += sprintf( buf+len, "RXE " ); len += sprintf( buf+len, "\n" ); } else { RX_DESC_FETCH *rdp = (RX_DESC_FETCH*)&rxring[i].rxf; len += sprintf( buf+len, "%016llX ", rdp->base_addr0 ); len += sprintf( buf+len, "%016llX ", rdp->base_addr1 ); len += sprintf( buf+len, "%016llX ", rdp->base_addr2 ); len += sprintf( buf+len, "%016llX ", rdp->base_addr3 ); len += sprintf( buf+len, "\n" ); } } len += sprintf( buf+len, "\n\n" ); len += sprintf( buf+len, " Total received packets: %d", n_rx_packets ); len += sprintf( buf+len, "\n\n" ); return len; } static void __exit pktsplit_exit(void ) { int rx_control; remove_proc_entry( info_rx, NULL ); rx_control = ioread32( io + E1000_RCTL ); rx_control &= ~(1<<1); iowrite32( rx_control, io + E1000_RCTL ); kfree( kmem ); iounmap( io ); printk( "<1>Removing \'%s\' module\n", modname ); } module_init( pktsplit_init ); module_exit( pktsplit_exit ); MODULE_LICENSE("GPL");