void nic_isr(snic *nic) { uint isr; /* Illinois Sreet Residence Hall */ uint overload; if(!nic || !nic->iobase) return; /* make sure card was initialized */ outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase); overload=MAX_LOAD+1; while((isr=inb_p(nic->iobase+INTERRUPTSTATUS))) { if((--overload)<=0) break; if(isr & ISR_OVW) nic_overrun(nic); else if(isr & (ISR_PRX | ISR_RXE)) nic_rx(nic); if(isr & ISR_PTX) nic_tx(nic); else if(isr & ISR_TXE) nic_tx_err(nic); if(isr & ISR_CNT) nic_counters(nic); if(isr & ISR_RDC) outb_p(ISR_RDC, nic->iobase+ INTERRUPTSTATUS); outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); } if(isr) { outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); if(!overload) { kprintf("NE2000: Too many requests in ISR. ISR:%X MaxLoad:%X\n", isr, MAX_LOAD); outb_p(ISR_ALL, nic->iobase + INTERRUPTSTATUS); // clear } else { kprintf("NE2000: Unhandeled interrupt, ISR:%X\n",isr); outb_p(0xff, nic->iobase + INTERRUPTSTATUS); // Ack it anyway } } }
static int ring_ovfl(snic *nic) { unsigned char isr; int iobase = nic->iobase; int i; outportg(0x21, iobase); outportg(0x0, iobase + REMOTEBYTECOUNT0); outportg(0x0, iobase + REMOTEBYTECOUNT1); for (i=0; i<0x7fff; i++) { isr=inportb(iobase+INTERRUPTSTATUS); if ((isr & 0x80) == 0) break; } outportg(TCR_INTERNAL_LOOPBACK, iobase + TRANSMITCONFIGURATION); outportg(0x22, iobase); //? nic_rx(nic); outportg(0x10, iobase+INTERRUPTSTATUS); outportg(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION); return 0; }
static void nic_hw_xmit(struct net_device *netdev) { struct nic_priv *priv = netdev_priv(netdev); struct iphdr *iph; u32 *saddr, *daddr; struct in_device* in_dev; struct in_ifaddr* if_info; if (priv->tx_len < sizeof(struct ethhdr) + sizeof(struct iphdr)) { netif_info(priv, hw, netdev, "%s(#%d), too short\n", __func__, __LINE__); return; } dump(priv->tx_buf); iph = (struct iphdr *)(priv->tx_buf + sizeof(struct ethhdr)); saddr = &iph->saddr; daddr = &iph->daddr; netif_info(priv, hw, netdev, "%s(#%d), orig, src:%pI4, dst:%pI4, len:%d\n", __func__, __LINE__, saddr, daddr, priv->tx_len); in_dev = nic_dev[(netdev == nic_dev[0] ? 1 : 0)]->ip_ptr; if (in_dev) { if_info = in_dev->ifa_list; for (if_info = in_dev->ifa_list; if_info; if_info=if_info->ifa_next) { #if 0 printk("label:%s, address=%pI4\n", if_info->ifa_label, &if_info->ifa_address); #endif *saddr = *daddr = if_info->ifa_address; ((u8 *)saddr)[3]++; netif_info(priv, hw, netdev, "%s(#%d), new, src:%pI4, dst:%pI4\n", __func__, __LINE__, saddr, daddr); break; } if (!if_info) { /* drop packet */ netdev->stats.tx_dropped++; netif_info(priv, hw, netdev, "%s(#%d), drop packet\n", __func__, __LINE__); return; } } iph->check = 0; /* and rebuild the checksum (ip needs it) */ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); netdev->stats.tx_packets++; netdev->stats.tx_bytes += priv->tx_len; nic_rx(nic_dev[(netdev == nic_dev[0] ? 1 : 0)], priv->tx_len, priv->tx_buf); }
// Main interrupt handling task. void nic_isr(int irq) { unsigned int isr; int iobase = nic.iobase; int status = 0; struct kthread *ithr; // Remember the previous interrupted thread and clear its task busy bit ithr = (struct kthread *)current_thread; // Change the high level task related pointers to point to // this nic thread. current_process = &system_process; current_thread = nic_intr_thread; current_thread->kt_schedinf.sc_state = THREAD_STATE_RUNNING; current_thread->kt_schedinf.sc_tqleft = TIME_QUANTUM; ithr->kt_schedinf.sc_state = THREAD_STATE_READY; ithr->kt_cr0 = get_cr0(); gdt_table[ithr->kt_tssdesc >> 3].b &= 0xfffffdff; math_state_save(&ithr->kt_fps); math_state_restore(&nic_intr_thread->kt_fps); add_readyq(ithr); // Enable interrupts now sti_intr(); _lock(&nic.busy); outportg(NIC_DMA_DISABLE | NIC_PAGE0, iobase); while ((isr=inportb(iobase+INTERRUPTSTATUS))) { if (isr & (ISR_CNT | ISR_OVW | ISR_PTX | ISR_TXE)) { if (isr & (ISR_CNT | ISR_OVW)) { ring_ovfl(&nic); status = ETRANSMISSION; } if(isr & ISR_PTX) { out_byte(iobase+INTERRUPTSTATUS, 0x0a); status = 1; } else if (isr & ISR_TXE) { out_byte(iobase+INTERRUPTSTATUS, 0x0a); status = ETRANSMISSION; } if (tx_wait_pkt != NULL) { tx_wait_pkt->status = status; event_wakeup((struct event_t *)&tx_wait_pkt->threadwait); tx_wait_pkt = NULL; } } if(isr & (ISR_PRX | ISR_RXE)) { nic_rx(&nic); } } out_byte(iobase+INTERRUPTSTATUS, 0xff); outportg(IMR_DEFAULT, iobase +INTERRUPTMASK); unlock(&nic.busy); // Schedule the interrupted thread at this point. cli_intr(); current_thread->kt_schedinf.sc_state = THREAD_STATE_SLEEP; //current_thread->kt_schedinf.sc_reccpuusage = 0; enable_irq(9); // Enable the same irq again. scheduler(); return; }