diff options
author | Mole Shang <[email protected]> | 2024-02-13 21:32:02 +0800 |
---|---|---|
committer | Mole Shang <[email protected]> | 2024-02-13 21:50:47 +0800 |
commit | 904885a96efd1dd0221585f67477f5a39bcce7f7 (patch) | |
tree | b635f479f94b5d970fb0b12e1718689710c7b9f6 /kernel/e1000.c | |
parent | 89ef6f717ed4b3e702e5f6f906f58fe1ea27d366 (diff) | |
download | xv6-labs-904885a96efd1dd0221585f67477f5a39bcce7f7.tar.gz xv6-labs-904885a96efd1dd0221585f67477f5a39bcce7f7.tar.bz2 xv6-labs-904885a96efd1dd0221585f67477f5a39bcce7f7.zip |
lab net: finishnet
Diffstat (limited to 'kernel/e1000.c')
-rw-r--r-- | kernel/e1000.c | 65 |
1 files changed, 57 insertions, 8 deletions
diff --git a/kernel/e1000.c b/kernel/e1000.c index 70a2adf..c9ba9e2 100644 --- a/kernel/e1000.c +++ b/kernel/e1000.c @@ -95,26 +95,75 @@ e1000_init(uint32 *xregs) int e1000_transmit(struct mbuf *m) { - // - // Your code here. - // // the mbuf contains an ethernet frame; program it into // the TX descriptor ring so that the e1000 sends it. Stash // a pointer so that it can be freed after sending. - // + acquire(&e1000_lock); + + int cur_idx = regs[E1000_TDT]; + // check if the STAT_DD bit is set in current descriptor + // if not set, means a previous tx in this descripter is still in flight, return an error. + if(!(tx_ring[cur_idx].status | E1000_TXD_STAT_DD)){ + release(&e1000_lock); + return -1; + } + + // free previous mbuf and update current descriptor + if(tx_mbufs[cur_idx]) + mbuffree(tx_mbufs[cur_idx]); + tx_ring[cur_idx].addr = (uint64)m->head; + tx_ring[cur_idx].length = (uint64)m->len; + tx_ring[cur_idx].cmd = E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP; + // also clear status bits + tx_ring[cur_idx].status = 0; + + // stash current mbuf to tx_mbufs (would be freed later) + tx_mbufs[cur_idx] = m; + + // update the ring position to point to the next descriptor; + regs[E1000_TDT] = (cur_idx + 1) % TX_RING_SIZE; + + release(&e1000_lock); return 0; } static void e1000_recv(void) { - // - // Your code here. - // // Check for packets that have arrived from the e1000 // Create and deliver an mbuf for each packet (using net_rx()). - // + while(1){ + acquire(&e1000_lock); + int cur_idx = (regs[E1000_RDT]+1) % RX_RING_SIZE; + + // check if last rx is completed. If not, skip passing to net_rx() + if(!(rx_ring[cur_idx].status | E1000_RXD_STAT_DD)) + break; + + // update the mbuf's length to the len reported by rx_desc + // mbufput(rx_mbufs[cur_idx], rx_ring[cur_idx].length); + rx_mbufs[cur_idx]->len = rx_ring[cur_idx].length; + + // stash mbuf, for later net_rx() + struct mbuf *rx_buf = rx_mbufs[cur_idx]; + + // net_rx() would free the passed mbuf invisibly, so we need to re-alloc it + rx_mbufs[cur_idx] = mbufalloc(0); + if(!rx_mbufs[cur_idx]) + panic("e1000_recv: mbufalloc"); + + // update buffer addr and clear status bits + rx_ring[cur_idx].addr = (uint64)rx_mbufs[cur_idx]->head; + rx_ring[cur_idx].status = 0; + + // update the E1000_RDT register to point to next position + regs[E1000_RDT] = cur_idx; + release(&e1000_lock); + + // pass to the network stack, must not hold the lock coz it can lead to deadlocks under different cpus + net_rx(rx_buf); + } } void |