📄 pcnet32_dev.c
字号:
write_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_STOP); // set up the interrupt handler int_set_io_interrupt_handler(nic->irq, &pcnet32_int, nic, "pcnet32"); SHOW_FLOW(3, "device mapped irq 0x%x", nic->irq + 0x20); // fetch ethernet address for (i = 0; i < 6; i++) { nic->mac_addr[i] = READ_8(nic, i); } SHOW_FLOW(3, "MAC Address: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", nic->mac_addr[0], nic->mac_addr[1], nic->mac_addr[2], nic->mac_addr[3], nic->mac_addr[4], nic->mac_addr[5]); return 0;}void pcnet32_start(pcnet32 *nic){ int i = 0; struct pcnet32_init *init; SHOW_FLOW(3, "starting %p", nic); SHOW_FLOW0(3, "resetting device"); READ_32(nic, PCNET_IO_RESET); WRITE_32(nic, PCNET_IO_RESET, 0); // give the device time to figure it out thread_snooze(10000); // set us up in 32-bit wide structure mode WRITE_32(nic, PCNET_IO_DATAPORT, 0); write_bcr(nic, PCNET_BCR_SWMODE, 0x0002); // now we build the initialization block in the // buffer area (which is unused right now) init = (struct pcnet32_init*)nic->buffers; memset(init, 0, sizeof(struct pcnet32_init)); init->flags = nic->init_mode; memcpy(init->paddr, &nic->mac_addr, sizeof(nic->mac_addr)); init->rxaddr = nic->rxring_phys; init->txaddr = nic->txring_phys; write_csr(nic, PCNET_CSR_IADDR0, nic->buffers_phys & 0xffff); write_csr(nic, PCNET_CSR_IADDR1, (nic->buffers_phys >> 16) & 0xffff); write_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_INIT); // wait for it to finish initializing. while ( !(read_csr(nic, PCNET_CSR_STATUS) & PCNET_STATUS_IDON) ); // Initialize the rxring for (i = 0; i < nic->rxring_count; i++) rxdesc_init(nic, i); // Initialize the txring memset(nic->txring, 0, nic->txring_count * sizeof(struct pcnet32_txdesc)); // write the start and interrupt enable bits. write_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_STRT | PCNET_STATUS_IENA); // for the sake of verification, we'll read csr0 and dprint it. SHOW_FLOW(3, "csr0 (status) = 0x%.4x", read_csr(nic, PCNET_CSR_STATUS)); // start the thread thread_resume_thread(nic->thread);}void pcnet32_stop(pcnet32 *nic){ SHOW_FLOW(3, "Stopping pcnet device %p", nic); // start the thread thread_suspend_thread(nic->thread); // stop the device. write_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_STOP);}void pcnet32_delete(pcnet32 *nic){ sem_delete(nic->interrupt_sem); vm_delete_region(vm_get_kernel_aspace_id(), nic->buffers_region); vm_delete_region(vm_get_kernel_aspace_id(), nic->txring_region); mutex_destroy(&nic->rxring_mutex); sem_delete(nic->rxring_sem); vm_delete_region(vm_get_kernel_aspace_id(), nic->rxring_region); kfree(nic);}static void rxdesc_init(pcnet32 *nic, uint16 index){ uint16 masked_index = RXRING_INDEX(nic, index); struct pcnet32_rxdesc *desc = nic->rxring + masked_index; uint32 buffer = BUFFER_PHYS(nic, RXRING_BUFFER(nic, masked_index)); desc->buffer_addr = buffer; desc->buffer_length = -nic->rx_buffersize; desc->message_length = 0; desc->user = 0; // enable the controller to write to this receive buffer. desc->status = PCNET_RXSTATUS_OWN;}ssize_t pcnet32_xmit(pcnet32 *nic, const char *ptr, ssize_t len){ uint16 index = 0; uint8 *buffer = NULL; SHOW_FLOW(3, "nic %p data %p len %d", nic, ptr, len); index = TXRING_INDEX(nic, nic->txring_head); SHOW_FLOW(3, "using txring index %d", index); // XXX need support for spanning packets in case a size other than 2048 is used. // Examine OWN bit of tx descriptor at tx_queue_tail; // if (OWN == 1) return "Out of buffer"; if ((len > nic->tx_buffersize) || (nic->txring[index].status & PCNET_TXSTATUS_OWN)) { SHOW_FLOW0(3, "packet was too large or no more txbuffers."); return ERR_VFS_INSUFFICIENT_BUF; } // Get buffer address from descriptor at end_tx_queue; buffer = TXRING_BUFFER(nic, index); nic->txring[index].buffer_addr = BUFFER_PHYS(nic, buffer); // Copy packet to tx buffer; memcpy(buffer, ptr, len); // Set up BCNT field of descriptor; nic->txring[index].buffer_length = -len; // Set OWN, STP, and ENP bits of descriptor; nic->txring[index].status |= PCNET_TXSTATUS_OWN | PCNET_TXSTATUS_STP | PCNET_TXSTATUS_ENP; // tx_queue_tail = tx_queue_tail + 1; // if (tx_queue_tail > last_tx_descriptor) tx_queue_tail = first_tx_descriptor; nic->txring_head++; // set the transmit demand bit in CSR0 modify_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_TDMD, PCNET_STATUS_TDMD); // return "OK"; return len;}ssize_t pcnet32_rx(pcnet32 *nic, char *buf, ssize_t buf_len){ uint16 index = 0; ssize_t real_len = -1; SHOW_FLOW(3, "nic %p data %p buf_len %d", nic, buf, buf_len); // here we loop through consuming rxring descriptors until we get // one suitable for returning. while (true) { // consume 1 descriptor at a time, whether it's an error or a // valid packet. sem_acquire(nic->rxring_sem, 1); SHOW_FLOW(3, "nic %p rx semaphore was signalled", nic); // the semaphor has been released at least once, so we will // lock the rxring and grab the next available descriptor. mutex_lock(&nic->rxring_mutex); // grab the index we want. index = RXRING_INDEX(nic, nic->rxring_tail); if (nic->rxring[index].status & PCNET_RXSTATUS_ERR) { SHOW_FLOW(3, "rxring descriptor %d reported an error: 0x%.4x", index, nic->rxring[index].status); } if (nic->rxring[index].status & PCNET_RXSTATUS_OWN) { SHOW_FLOW(3, "warning: descriptor %d should have been owned by the software is owned by the hardware.", index); nic->rxring_tail++; mutex_unlock(&nic->rxring_mutex); continue; // skip this descriptor altogether. } else if ((size_t)buf_len >= nic->rxring[index].message_length) // got one { real_len = nic->rxring[index].message_length; // copy the buffer memcpy(buf, RXRING_BUFFER(nic, index), real_len); // reinitialize the buffer and give it back to the controller. rxdesc_init(nic, index); SHOW_FLOW(3, "Got index %d, len %d and cleared it, returning to caller. rxstatus = 0x%x.", index, nic->rxring[index].message_length, nic->rxring[index].status); // move the tail up. nic->rxring_tail++; mutex_unlock(&nic->rxring_mutex); return real_len; } else { // there is a packet, but it's too large for the buffer. // So we don't want to do anything with the ring, we just // want to unlock our mutex and return. mutex_unlock(&nic->rxring_mutex); return ERR_TOO_BIG; } } return real_len;}// these two return false when there is nothing left to do.static bool pcnet32_rxint(pcnet32 *nic){ uint32 index; index = RXRING_INDEX(nic, nic->rxring_head); SHOW_FLOW(3, "Next rxring index (%d) status = 0x%x.", index, nic->rxring[index].status); if ( !(nic->rxring[index].status & PCNET_RXSTATUS_OWN) ) { SHOW_FLOW(3, "Got packet len %d, index %d", nic->rxring[index].message_length, index); nic->rxring_head++; sem_release(nic->rxring_sem, 1); return true; } SHOW_FLOW0(3, "No more packets."); return false;}static int pcnet32_thread(void *data){ pcnet32 *nic = (pcnet32 *)data; while (true) { sem_acquire(nic->interrupt_sem, 1); SHOW_FLOW(3, "Acquired semaphore, status = 0x%x", nic->interrupt_status); // check if there is a 'fatal error' (BABL and MERR) if ((nic->interrupt_status & PCNET_STATUS_ERR) && (nic->interrupt_status & PCNET_STATUS_BABL || nic->interrupt_status & PCNET_STATUS_MERR)) { // fatal error. Stop everything and reinitialize the device. pcnet32_stop(nic); pcnet32_start(nic); } mutex_lock(&nic->rxring_mutex); while (pcnet32_rxint(nic)); mutex_unlock(&nic->rxring_mutex); // re-enable pcnet interrupts write_csr(nic, PCNET_CSR_STATUS, PCNET_STATUS_IENA); SHOW_FLOW(3, "Finished iteration, status = 0x%x", read_csr(nic, PCNET_CSR_STATUS)); } return 0;}static int pcnet32_int(void* data){ pcnet32 *nic = (pcnet32 *)data; uint32 status; acquire_spinlock(&nic->control_lock); int_disable_interrupts(); status = read_csr(nic, PCNET_CSR_STATUS); SHOW_FLOW(3, "handling irq: status 0x%x", status); // clear the bits that caused this to happen and disable pcnet interrupts // for the time being write_csr(nic, PCNET_CSR_STATUS, status & ~PCNET_STATUS_IENA); int_restore_interrupts(); release_spinlock(&nic->control_lock); nic->interrupt_status = status; sem_release_etc(nic->interrupt_sem, 1, SEM_FLAG_NO_RESCHED); SHOW_FLOW(3, "interrupt handled. pcnet status 0x%.8x", read_csr(nic, PCNET_CSR_STATUS)); return INT_RESCHEDULE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -