#define REALTEK_VENDER_ID 0x10EC #define REALTEK_DEVICE_ID 0x8139 //#define REALTEK_VENDER_ID 0x10b5 //#define REALTEK_DEVICE_ID 0x9050 //#define VENDOR_ID 0x10b5 //#define DEVICE_ID 0x9050 #include #include #include #include #include int print_pci(struct pci_dev *pdev); #define TX_BUF_SIZE 1536 /* should be at least MTU + 14 + 4 */ #define TOTAL_TX_BUF_SIZE (TX_BUF_SIZE * NUM_TX_SIZE) /* 8139 register offsets */ #define TSD0 0x10 #define TSAD0 0x20 #define RBSTART 0x30 #define CR 0x37 #define CAPR 0x38 #define IMR 0x3c #define ISR 0x3e #define TCR 0x40 #define RCR 0x44 #define MPC 0x4c #define MULINT 0x5c /* TSD register commands */ #define TxHostOwns 0x2000 #define TxUnderrun 0x4000 #define TxStatOK 0x8000 #define TxOutOfWindow 0x20000000 #define TxAborted 0x40000000 #define TxCarrierLost 0x80000000 /* CR register commands */ #define RxBufEmpty 0x01 #define CmdTxEnb 0x04 #define CmdRxEnb 0x08 #define CmdReset 0x10 /* ISR Bits */ #define RxOK 0x01 #define RxErr 0x02 #define TxOK 0x04 #define TxErr 0x08 #define RxOverFlow 0x10 #define RxUnderrun 0x20 #define RxFIFOOver 0x40 #define CableLen 0x2000 #define TimeOut 0x4000 #define SysErr 0x8000 #define INT_MASK (RxOK | RxErr | TxOK | TxErr | \ RxOverFlow | RxUnderrun | RxFIFOOver | \ CableLen | TimeOut | SysErr) #define NUM_TX_SIZE 4 #define NUM_TX_DESC 4 /* Size of the in-memory receive ring. */ #define RX_BUF_LEN_IDX 2 /* 0==8K, 1==16K, 2==32K, 3==64K */ #define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) #define RX_BUF_PAD 16 /* see 11th and 12th bit of RCR: 0x44 */ #define RX_BUF_WRAP_PAD 2048 /* spare padding to handle pkt wrap */ #define RX_BUF_TOT_LEN (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) static void rtl8139_init_ring (struct net_device *dev); static void rtl8139_hw_start (struct net_device *dev); static void rtl8139_chip_reset (void *ioaddr); struct rtl8139_private { struct pci_dev *pci_dev; /* PCI device */ void *mmio_addr; /* memory mapped I/O addr */ unsigned long regs_len; /* length of I/O or MMI/O region */ unsigned int tx_flag; unsigned int cur_tx; unsigned int dirty_tx; unsigned char *tx_buf[NUM_TX_DESC]; /* Tx bounce buffers */ unsigned char *tx_bufs; /* Tx bounce buffer region. */ dma_addr_t tx_bufs_dma; struct net_device_stats stats; unsigned char *rx_ring; dma_addr_t rx_ring_dma; unsigned int cur_rx; }; static struct pci_dev* probe_for_realtek8139(void) { struct pci_dev *pdev = NULL; /* Ensure we are not working on a non-PCI system */ //if(!pci_present( )) { // printk("<1>pci not present\n"); // return pdev; //} //else // printk("<1>pci device is present\n"); /* Look for RealTek 8139 NIC */ pdev = pci_find_device(REALTEK_VENDER_ID, REALTEK_DEVICE_ID, NULL); if(pdev) { //printk("Found PCI device with vendorid = %x deviceid = %x\n", REALTEK_VENDER_ID, REALTEK_DEVICE_ID); // device found, enable it if(pci_enable_device(pdev)) { //printk("Could not enable the device\n"); return NULL; } else printk("Device enabled\n"); } else { //printk("device not found\n"); return pdev; } return pdev; } #define DRIVER "rtl8139" static struct net_device *rtl8139_dev = NULL; static int rtl8139_init(struct pci_dev *pdev, struct net_device **dev_out) { struct net_device *dev; struct rtl8139_private *tp; /* * alloc_etherdev allocates memory for dev and dev->priv. * dev->priv shall have sizeof(struct rtl8139_private) memory * allocated. */ printk("rtl8139_init is called\n"); dev = alloc_etherdev(sizeof(struct rtl8139_private)); if(!dev) { printk("Could not allocate etherdev\n"); return -1; } //printk("rtl8139_init , initializing the structure struct net_device \n"); tp = dev->priv; tp->pci_dev = pdev; *dev_out = dev; //printk("rtl8139_init exiting .........\n"); return 0; } static void rtl8139_interrupt (int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device*)dev_instance; struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned short isr = readw(ioaddr + ISR); /* clear all interrupt. * Specs says reading ISR clears all interrupts and writing * has no effect. But this does not seem to be case. I keep on * getting interrupt unless I forcibly clears all interrupt :-( */ writew(0xffff, ioaddr + ISR); if((isr & TxOK) || (isr & TxErr)) { while((tp->dirty_tx != tp->cur_tx) || netif_queue_stopped(dev)) { unsigned int txstatus = readl(ioaddr + TSD0 + tp->dirty_tx * sizeof(int)); if(!(txstatus & (TxStatOK | TxAborted | TxUnderrun))) break; /* yet not transmitted */ if(txstatus & TxStatOK) { printk("Transmit OK interrupt\n"); tp->stats.tx_bytes += (txstatus & 0x1fff); tp->stats.tx_packets++; } else { printk("Transmit Error interrupt\n"); tp->stats.tx_errors++; } tp->dirty_tx++; tp->dirty_tx = tp->dirty_tx % NUM_TX_DESC; if((tp->dirty_tx == tp->cur_tx) & netif_queue_stopped(dev)) { printk("waking up queue\n"); netif_wake_queue(dev); } } } if(isr & RxErr) { /* TODO: Need detailed analysis of error status */ printk("receive err interrupt\n"); tp->stats.rx_errors++; } if(isr & RxOK) { printk("receive interrupt received\n"); while((readb(ioaddr + CR) & RxBufEmpty) == 0) { unsigned int rx_status; unsigned short rx_size; unsigned short pkt_size; struct sk_buff *skb; if(tp->cur_rx > RX_BUF_LEN) tp->cur_rx = tp->cur_rx % RX_BUF_LEN; /* TODO: need to convert rx_status from little to host endian * XXX: My CPU is little endian only :-) */ rx_status = *(unsigned int*)(tp->rx_ring + tp->cur_rx); rx_size = rx_status >> 16; /* first two bytes are receive status register * and next two bytes are frame length */ pkt_size = rx_size - 4; /* hand over packet to system */ skb = dev_alloc_skb (pkt_size + 2); if (skb) { skb->dev = dev; skb_reserve (skb, 2); /* 16 byte align the IP fields */ skb_copy_and_csum_dev(skb, tp->rx_ring + tp->cur_rx + 4); //eth_copy_and_sum( skb, tp->rx_ring + tp->cur_rx + 4, pkt_size, 0); skb_put (skb, pkt_size); skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); dev->last_rx = jiffies; tp->stats.rx_bytes += pkt_size; tp->stats.rx_packets++; } else { printk("Memory squeeze, dropping packet.\n"); tp->stats.rx_dropped++; } /* update tp->cur_rx to next writing location * / tp->cur_rx = (tp->cur_rx + rx_size + 4 + 3) & ~3; /* update CAPR */ writew(tp->cur_rx, ioaddr + CAPR); } } if(isr & CableLen) printk("cable length change interrupt\n"); if(isr & TimeOut) printk("time interrupt\n"); if(isr & SysErr) printk("system err interrupt\n"); return; } static int rtl8139_open(struct net_device *dev) { int retval; struct rtl8139_private *tp = dev->priv; printk("rtl8139_open is called\n"); /* get the IRQ * second arg is interrupt handler * third is flags, 0 means no IRQ sharing */ retval = request_irq(dev->irq, rtl8139_interrupt, 0 , dev->name, NULL); //retval = request_irq(dev->irq, rtl8139_interrupt, SA_INTERRUPT, dev->name, dev); if(retval) return retval; /* get memory for Tx buffers * memory must be DMAable */ tp->tx_bufs = pci_alloc_consistent( tp->pci_dev, TOTAL_TX_BUF_SIZE, &tp->tx_bufs_dma); if(!tp->tx_bufs) { free_irq(dev->irq, dev); return -ENOMEM; } tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN, &tp->rx_ring_dma); if((!tp->tx_bufs) || (!tp->rx_ring)) { free_irq(dev->irq, dev); if(tp->tx_bufs) { pci_free_consistent(tp->pci_dev, TOTAL_TX_BUF_SIZE, tp->tx_bufs, tp->tx_bufs_dma); tp->tx_bufs = NULL; } if(tp->rx_ring) { pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN, tp->rx_ring, tp->rx_ring_dma); tp->rx_ring = NULL; } return -ENOMEM; } tp->tx_flag = 0; rtl8139_init_ring(dev); rtl8139_hw_start(dev); return 0; } static void rtl8139_init_ring (struct net_device *dev) { struct rtl8139_private *tp = dev->priv; int i; tp->cur_tx = 0; tp->dirty_tx = 0; for (i = 0; i < NUM_TX_DESC; i++) tp->tx_buf[i] = &tp->tx_bufs[i * TX_BUF_SIZE]; return; } static void rtl8139_hw_start (struct net_device *dev) { struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 i; rtl8139_chip_reset(ioaddr); /* Must enable Tx/Rx before setting transfer thresholds! */ writeb(CmdTxEnb | CmdRxEnb, ioaddr + CR); /* tx config */ writel(0x00000600, ioaddr + TCR); /* DMA burst size 1024 */ /* rx config */ writel(((1 << 12) | (7 << 8) | (1 << 7) | (1 << 3) | (1 << 2) | (1 << 1)), ioaddr + RCR); /* init Tx buffer DMA addresses */ for (i = 0; i < NUM_TX_DESC; i++) { writel(tp->tx_bufs_dma + (tp->tx_buf[i] - tp->tx_bufs), ioaddr + TSAD0 + (i * 4)); } /* init RBSTART */ writel(tp->rx_ring_dma, ioaddr + RBSTART); /* initialize missed packet counter */ writel(0, ioaddr + MPC); /* no early-rx interrupts */ writew((readw(ioaddr + MULINT) & 0xF000), ioaddr + MULINT); /* Enable all known interrupts by setting the interrupt mask. */ writew(INT_MASK, ioaddr + IMR); netif_start_queue (dev); return; } static void rtl8139_chip_reset (void *ioaddr) { int i; /* Soft reset the chip. */ writeb(CmdReset, ioaddr + CR); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) { barrier(); if ((readb(ioaddr + CR) & CmdReset) == 0) break; udelay (10); } return; } static int rtl8139_stop(struct net_device *dev) { printk("rtl8139_open is called\n"); free_irq(dev->irq, NULL); return 0; } static int rtl8139_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct rtl8139_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; unsigned int entry = tp->cur_tx; unsigned int len = skb->len; #define ETH_MIN_LEN 60 /* minimum Ethernet frame size */ printk("rtl8139_start_xmit is called\n"); if (len < TX_BUF_SIZE) { if(len < ETH_MIN_LEN) memset(tp->tx_buf[entry], 0, ETH_MIN_LEN); skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); dev_kfree_skb(skb); } else { skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); dev_kfree_skb(skb); return 0; } writel(tp->tx_flag | max(len, (unsigned int)ETH_MIN_LEN), ioaddr + TSD0 + (entry * sizeof (u32))); entry++; tp->cur_tx = entry % NUM_TX_DESC; if(tp->cur_tx == tp->dirty_tx) { netif_stop_queue(dev); } return 0; } static struct net_device_stats* rtl8139_get_stats(struct net_device *dev) { struct rtl8139_private *tp; printk("rtl8139_get_stats is called\n"); tp = netdev_priv(dev); return &tp->stats; //return 0; } int init_module(void) { struct pci_dev *pdev; unsigned long mmio_start, mmio_end, mmio_len, mmio_flags; void *ioaddr; struct rtl8139_private *tp; int i, err = 0; pdev = probe_for_realtek8139( ); if(!pdev) return 0; print_pci(pdev); if(rtl8139_init(pdev, &rtl8139_dev)) { printk("Could not initialize device\n"); return 0; } tp = rtl8139_dev->priv; // rtl8139 private information //printk("Reading the PCI BAR registers \n"); // get PCI memory mapped I/O space base address from BAR1 mmio_start = pci_resource_start(pdev, 1); mmio_end = pci_resource_end(pdev, 1); mmio_len = pci_resource_len(pdev, 1); mmio_flags = pci_resource_flags(pdev, 1); //printk("Checking the PCI BAR registers for Memory mapped flag \n"); // make sure above region is MMI/O if(!(mmio_flags & IORESOURCE_MEM)) { printk("region not MMI/O region\n"); goto cleanup1; } else printk("region is Memory mapped region\n"); //printk("Calling pci_request_region \n"); // get PCI memory space if(pci_request_regions(pdev, DRIVER)) { printk("Could not get PCI region\n"); goto cleanup1; } //printk("Calling pci_set_master\n"); pci_set_master(pdev); //printk("Calling ioremap\n"); // ioremap MMI/O region ioaddr = ioremap(mmio_start, mmio_len); if(!ioaddr) { printk("Could not ioremap\n"); goto cleanup2; } //printk("Assigning ioaddress and length \n"); rtl8139_dev->base_addr = (long)ioaddr; tp->mmio_addr = ioaddr; tp->regs_len = mmio_len; // UPDATE NET_DEVICE //printk("Assigning hardware address \n"); for(i = 0; i < 6; i++) { // Hardware Address rtl8139_dev->dev_addr[i] = readb(rtl8139_dev->base_addr+i); rtl8139_dev->broadcast[i] = 0xff; } rtl8139_dev->hard_header_len = 14; //printk("Assigning function address \n"); memcpy(rtl8139_dev->name, DRIVER, sizeof(DRIVER)); // Device Name rtl8139_dev->irq = pdev->irq; // Interrupt Number rtl8139_dev->open = rtl8139_open; rtl8139_dev->stop = rtl8139_stop; rtl8139_dev->hard_start_xmit = rtl8139_start_xmit; rtl8139_dev->get_stats = rtl8139_get_stats; if(rtl8139_dev != NULL) printk("rtl8139_dev is not NULL\n"); //printk("Calling register_netdev \n"); // register the device if(register_netdev(rtl8139_dev)) { printk("Could not register netdevice\n"); goto cleanup0; } //printk("AFTEr the call to register_netdev \n"); goto noerror; cleanup0: //printk("Error so, unregister_netdev \n"); unregister_netdev(rtl8139_dev); err = 1; cleanup2: //printk("Error so, unmap \n"); iounmap(tp->mmio_addr); err = 1; cleanup1: //printk("Error so, pci_release_regions \n"); pci_release_regions(tp->pci_dev); err = 1; noerror: //printk("Init function exiting fine ...............\n"); return err; } void cleanup_module(void) { struct rtl8139_private *tp; tp = rtl8139_dev->priv; iounmap(tp->mmio_addr); pci_release_regions(tp->pci_dev); unregister_netdev(rtl8139_dev); pci_disable_device(tp->pci_dev); return; } // Should be called after pci_find_device and pci_enable_device have been called int print_pci(struct pci_dev *dev) { int i; int start, end, length, resflags; for (i = 0; i < 6; i++) { start = pci_resource_start (dev, i); if (!start) continue; end = pci_resource_end (dev, i); length = pci_resource_len (dev, i); resflags = pci_resource_flags (dev, i); if (resflags & IORESOURCE_IO) { printk("----------------------------------------------------------------\n"); printk("Base %d Starting Address = %x End Address = %x Length = %d\n",i, start, end, length); printk ("This Port is I/O mapped. "); if (resflags & IORESOURCE_PREFETCH) printk ("It is Prefetchable."); else printk ("It is NON Prefetchable."); if (resflags & IORESOURCE_READONLY) printk ("This is read only.\n"); else printk ("This is readable and writable.\n"); if (check_region (start, length) < 0) printk ("Base %d starting Address = %x End Address = %x Length = %d resource is not available \n", i, start, end, length); //else if (request_region (start, length, DRIVER_NAME) < 0) // printk ("The Resource is not allocated for BAR %d\n", i); // else // printk ("The Resource is allocated for BAR %d\n", i); } else { if (resflags & IORESOURCE_MEM) { printk ("Base %d Starting Address = %x End Address = %x Length = %d\n",i, start, end, length); printk ("This Port is Memory mapped. "); if (resflags & IORESOURCE_PREFETCH) printk ("It is Prefetchable. "); else printk ("It is NON Prefetchable. "); if (resflags & IORESOURCE_READONLY) printk ("It is read only.\n"); else printk ("This is readable and writable.\n"); if (check_mem_region (start, length) < 0) printk ("Base %d starting Address = %x End Address = %x Length = %d resource is not available \n", i, start, end, length); else { //if (request_mem_region (start, length, DRIVER_NAME) < 0) // printk("The Resource is not allocated for BAR %d\n", i); //else // printk ("The Resource is allocated for BAR %d\n", i); } } } } return 0; }