/*------------------------------------------------------------------------ * ethInterrupt - decode and handle interrupt from an Ethernet device *------------------------------------------------------------------------ */ interrupt ethInterrupt(void) { struct ether *ethptr; /* ptr to control block */ struct ag71xx *nicptr; /* ptr to device CSRs */ uint32 status; uint32 mask; /* Initialize structure pointers */ ethptr = ðertab[0]; /* default physical Ethernet */ if (!ethptr) { return; } nicptr = ethptr->csr; if (!nicptr) { return; } /* Obtain status bits from device */ mask = nicptr->interruptMask; status = nicptr->interruptStatus & mask; /* Record status in ether struct */ ethptr->interruptStatus = status; if (status == 0) { return; } sched_cntl(DEFER_START); if (status & IRQ_TX_PKTSENT) { /* handle transmitter interrupt */ ethptr->txirq++; txPackets(ethptr, nicptr); } if (status & IRQ_RX_PKTRECV) { /* handle receiver interrupt */ ethptr->rxirq++; rxPackets(ethptr, nicptr); } /* Handle errors (transmit or receive overflow) */ if (status & IRQ_RX_OVERFLOW) { /* Clear interrupt and restart processing */ nicptr->rxStatus = RX_STAT_OVERFLOW; nicptr->rxControl = RX_CTRL_RXE; ethptr->errors++; } if ((status & IRQ_TX_UNDERFLOW) || (status & IRQ_TX_BUSERR) || (status & IRQ_RX_BUSERR)) { panic("Catastrophic Ethernet error"); } sched_cntl(DEFER_STOP); return; }
/*------------------------------------------------------------------------ * e1000Interrupt - decode and handle interrupt from an E1000 device *------------------------------------------------------------------------ */ interrupt e1000Interrupt(void) { uint32 status; struct dentry *devptr; /* address of device control blk*/ struct ether *ethptr; /* ptr to control block */ /* Initialize structure pointers */ devptr = (struct dentry *) &devtab[ETHER0]; /* Obtain a pointer to the tty control block */ ethptr = ðertab[devptr->dvminor]; /* Invoke the device-specific interrupt handler */ /* Disable device interrupt */ e1000IrqDisable(ethptr); /* Obtain status bits from device */ status = e1000_io_readl(ethptr->iobase, E1000_ICR); /* Not our interrupt */ if (status == 0) { e1000IrqEnable(ethptr); return; } sched_cntl(DEFER_START); if (status & E1000_ICR_LSC) { } if (status & E1000_ICR_RXT0) { ethptr->rxIrq++; e1000_rxPackets(ethptr); } if (status & E1000_ICR_TXDW) { ethptr->txIrq++; e1000_txPackets(ethptr); } /* Enable device interrupt */ e1000IrqEnable(ethptr); sched_cntl(DEFER_STOP); return; }
/*------------------------------------------------------------------------ * udp_release - release a previously-registered UDP slot *------------------------------------------------------------------------ */ status udp_release ( uid32 slot /* table slot to release */ ) { intmask mask; /* saved interrupt mask */ struct udpentry *udptr; /* pointer to udptab entry */ struct netpacket *pkt; /* ptr to packet being read */ /* Insure only one process can access the UDP table at a time */ mask = disable(); /* Verify that the slot is valid */ if ( (slot < 0) || (slot >= UDP_SLOTS) ) { restore(mask); return SYSERR; } /* Get pointer to table entry */ udptr = &udptab[slot]; /* Verify that the slot has been registered and is valid */ if (udptr->udstate == UDP_FREE) { restore(mask); return SYSERR; } sched_cntl(DEFER_START); while (udptr->udcount > 0) { pkt = udptr->udqueue[udptr->udhead++]; if (udptr->udhead >= UDP_QSIZ) { udptr->udhead = 0; } freebuf((char *)pkt); udptr->udcount--; } udptr->udstate = UDP_FREE; sched_cntl(DEFER_STOP); restore(mask); return OK; }
/*------------------------------------------------------------------------ * udp_release - release a previously-registered remote IP, remote * port, and local port (exact match required) *------------------------------------------------------------------------ */ status udp_release ( uint32 remip, /* remote IP address or zero */ uint16 remport, /* remote UDP protocol port */ uint16 locport /* local UDP protocol port */ ) { int32 i; /* index into udptab */ struct udpentry *udptr; /* pointer to udptab entry */ struct eth_packet *pkt; /* ptr to packet being read */ for (i=0; i<UDP_SLOTS; i++) { udptr = &udptab[i]; if (udptr->udstate != UDP_USED) { continue; } if ((remport == udptr->udremport) && (locport == udptr->udlocport) && (remip == udptr->udremip ) ) { /* Entry in table matches */ sched_cntl(DEFER_START); while (udptr->udcount > 0) { pkt = udptr->udqueue[udptr->udhead++]; if (udptr->udhead >= UDP_SLOTS) { udptr->udhead = 0; } freebuf((char *)pkt); udptr->udcount--; } udptr->udstate = UDP_FREE; sched_cntl(DEFER_STOP); return OK; } } return SYSERR; }
void e100_txPackets(struct ether *ethptr) /* ptr to control block */ { struct e100_tx_desc *descptr;/* ptr to ring descriptor */ uint32 head; /* pos to reclaim descriptor */ char *pktptr; /* ptr used during packet copy */ int numdesc; /* num. of descriptor reclaimed */ //kprintf("SCB Status = %2x\r\n", inb(ethptr->iobase + E100_STATUS)); //kprintf("Enter e100_txPackets\r\n"); for (numdesc = 0; numdesc < E100_BLK_PER_INT; numdesc++) { head = ethptr->txHead; descptr = (struct e100_tx_desc *)ethptr->txRing + head; //kprintf("In e100_intr, descptr = %d\r\n", (int32)descptr); //kprintf("descptr->status = %x\r\n", descptr->status); if (!(descptr->status & cb_complete)) { //kprintf("Before, break, descptr->status = %x\r\n", descptr->status); break; } //kprintf("descptr->status = %4x\r\n",descptr->status); /* Clear the write-back descriptor and buffer */ //descptr->status |= cb_complete; descptr->command = 0; //descptr->link = 0; descptr->u.tcb.tbd_array = 0; descptr->u.tcb.tcb_byte_count = 0; descptr->u.tcb.threshold = 0; descptr->u.tcb.tbd_num = 0; pktptr = descptr->u.tcb.data; memset(pktptr, '\0', ETH_BUF_SIZE); ethptr->txHead = (ethptr->txHead + 1) % ethptr->txRingSize; if (ethptr->txHead == ethptr->txTail ) { break; } } //signaln(ethptr->osem, numdesc); return; } /*------------------------------------------------------------------------ * e100_intr - decode and handle interrupt from an E100 device *------------------------------------------------------------------------ */ interrupt e100_intr( struct ether *ethptr ) { uint8 stat_ack; /* kprintf("Enter interrupt handler!\r\n"); kprintf("SCB Status = %2x\r\n", inb(ethptr->iobase + E100_STATUS)); */ /* Disable device interrupt */ e100_disable_irq(ethptr); /* Obtain stat_ack bits from device */ stat_ack = inb(ethptr->iobase + E100_STAT_ACK); outb(ethptr->iobase + E100_STAT_ACK, stat_ack); /* kprintf("stat_ack = %x\r\n", stat_ack); kprintf("stat_ack_rx = %x\r\n", stat_ack_rx); kprintf("stat_ack_tx = %x\r\n", stat_ack_tx); */ /* Not our interrupt */ if (stat_ack == stat_ack_not_ours) { e100_enable_irq(ethptr); return; } sched_cntl(DEFER_START); if (stat_ack & stat_ack_rx) { ethptr->rxIrq++; e100_rxPackets(ethptr); } if (stat_ack & stat_ack_tx) { ethptr->txIrq++; e100_txPackets(ethptr); } /* struct e100_tx_desc *descptr1; struct e100_rx_desc *descptr2; descptr1 = (struct e100_tx_desc *)ethptr->txRing; kprintf("Tx block: descptr->status = %x\r\n", descptr1->status); kprintf("Tx block: descptr->command = %x\r\n", descptr1->command); //kprintf("Tx block: descptr->size = %x\r\n", descptr->size); kprintf("Tx block: descptr->link = %x\r\n", descptr1->link); kprintf("=======================================\r\n"); descptr2 = (struct e100_rx_desc *)ethptr->rxRing; kprintf("Rx block: descptr->status = %x\r\n", descptr2->status); kprintf("Rx block: descptr->command = %x\r\n", descptr2->command); kprintf("Rx block: descptr->size = %x\r\n", descptr2->size); kprintf("Rx block: descptr->link = %x\r\n", descptr2->link); */ /* Enable device interrupt */ e100_enable_irq(ethptr); sched_cntl(DEFER_STOP); return; }
/*------------------------------------------------------------------------ * ttyInterrupt - handle an interrupt for a tty (serial) device *------------------------------------------------------------------------ */ void ttyInterrupt(void) { struct dentry *devptr; /* address of device control blk*/ struct ttycblk *typtr; /* pointer to ttytab entry */ struct uart_csreg *csrptr; /* address of UART's CSR */ byte iir = 0; /* interrupt identification */ byte lsr = 0; /* line status */ /* Get CSR address of the device (assume console for now) */ devptr = (struct dentry *) &devtab[CONSOLE]; csrptr = (struct uart_csreg *) devptr->dvcsr; /* Obtain a pointer to the tty control block */ typtr = &ttytab[ devptr->dvminor ]; /* Decode hardware interrupt request from UART device */ /* Check interrupt identification register */ iir = inb( (int)&csrptr->iir ); if (iir & UART_IIR_IRQ) { return; } /* Decode the interrupt cause based upon the value extracted */ /* from the UART interrupt identification register. Clear */ /* the interrupt source and perform the appropriate handling */ /* to coordinate with the upper half of the driver */ /* Decode the interrupt cause */ iir &= UART_IIR_IDMASK; /* mask off the interrupt ID */ switch (iir) { /* Receiver line status interrupt (error) */ case UART_IIR_RLSI: lsr = inb( (int)&csrptr->lsr ); return; /* Receiver data available or timed out */ case UART_IIR_RDA: case UART_IIR_RTO: sched_cntl(DEFER_START); /* While chars avail. in UART buffer, call ttyInter_in */ while ( (inb( (int)&csrptr->lsr) & UART_LSR_DR) != 0) { ttyInter_in(typtr, csrptr); } sched_cntl(DEFER_STOP); return; /* Transmitter output FIFO is empty (i.e., ready for more) */ case UART_IIR_THRE: /* Read from LSR to clear interrupt */ lsr = inb( (int)&csrptr->lsr ); ttyInter_out(typtr, csrptr); return; /* Modem status change (simply ignore) */ case UART_IIR_MSC: return; } }