📄 e100.c
字号:
logout("EEPROM read(reg address=%#x, reg val=%#x, do=%#x, len=%#x)\n", e->address, e->data, t, e->val_len); if ( e->val_len > sizeof(e->data)*8 ) { /* Driver may do more write op to de-assert EESK, * So we let EEPROM go to idle after a register be * read complete */ e->val_type = NOP; logout("Read complete\n"); break; } e->val_len ++; } eeprom_trace(CSR(CSR_EEPROM, eedo), di, e->opcode, 0, 0); // Do eerpom write when CS de-assert break; default: break; } } } return;}static void scb_eeprom_func(E100State *s, uint32_t val, int dir){ int eecs = ((val & EEPROM_CS) != 0); int eesk = ((val & EEPROM_SK) != 0); int eedi = ((val & EEPROM_DI) != 0); logout("EEPROM: Old(cs=%#x, sk=%#x), New(cs=%#x, sk=%#x, di=%#x)\n", s->eeprom.cs, s->eeprom.sk, eecs, eesk, eedi); do_eeprom_op(s, &s->eeprom, eecs, eesk, eedi, dir); return;}static void e100_ru_command(E100State *s, uint8_t val){ switch ( val ) { case RU_NOP: /* Will not be here */ break; case RU_START: /* RU start */ SET_RU_STATE(RU_READY); logout("RU is set to ready\n"); s->ru_offset = CSR_VAL(CSR_POINTER); logout("RFD offset is at %#x\n", s->ru_offset); break; case RU_RESUME: /* RU Resume */ if ( GET_RU_STATE == RU_SUSPENDED ) SET_RU_STATE(RU_READY); logout("RU resume to ready\n"); break; case RU_ADDR_LOAD: /* Load RU base */ s->ru_base = CSR_VAL(CSR_POINTER); logout("Load RU base address at %#x\n", s->ru_base); break; case RU_DMA_REDIRECT: logout("RU DMA redirect not implemented\n"); break; case RU_ABORT: e100_interrupt(s, INT_RNR); SET_RU_STATE(RU_IDLE); logout("RU abort, go to idle\n"); break; case RU_LOAD_HDS: logout("RU load header data size(HDS) not implemented\n"); default: break; }}// This function will change CU's state, so CU start and// CU resume must set CU's state before itstatic void e100_execute_cb_list(E100State *s, int is_resume){ struct control_block cb = {0}; uint32_t cb_addr; if ( !is_resume ) s->cu_offset = CSR_VAL(CSR_POINTER); /* If call from CU resume, cu_offset has been set */ while (1) { cb_addr = s->cu_base + s->cu_offset; cpu_physical_memory_read(cb_addr, (uint8_t *)&cb, sizeof(cb)); switch ( cb.cmd ) { case CBL_NOP: /* Do nothing */ break; case CBL_IASETUP: cpu_physical_memory_read(cb_addr + 8, &s->macaddr[0], sizeof(s->macaddr)); e100_dump("Setup Individual Address:", &s->macaddr[0], 6); break; case CBL_CONFIGURE: { i82557_cfg_t *cfg = &s->config; assert(sizeof(s->config) == 22); cpu_physical_memory_read(cb_addr + 8, (uint8_t *)cfg, sizeof(s->config)); logout("Setup card configuration:" "\tbyte count:%d\n" "\tRx FIFO limit:%d\n" "\tTx FIFO limit:%d\n" "\tAdaptive interframe spacing:%d\n" "\tRx DMA max:%d\n" "\tTX DMA max:%d\n" "\tDMBC enable:%d\n" "\tLate SCB:%d\n" "\tTNO:%d\n" "\tCI:%d\n" "\tDiscard overrun RX:%d\n" "\tSave bad frame:%d\n" "\tDiscard short RX:%d\n" "\tunderrun retry:%d\n" "\tMII:%d\n" "\tNSAI:%d\n" "\tPreamble len:%d\n" "\tloopback:%d\n" "\tliner pro:%d\n" "\tPRI mode:%d\n" "\tinterframe spacing:%d\n" "\tpromiscuous:%d\n" "\tbroadcast dis:%d\n" "\tCRS CDT:%d\n" "\tstripping:%d\n" "\tpadding:%d\n" "\tRX crc:%d\n" "\tforce fdx:%d\n" "\tfdx enable:%d\n" "\tmultiple IA:%d\n" "\tmulticast all:%d\n", cfg->byte_count, cfg->rx_fifo_limit, cfg->tx_fifo_limit, cfg->adpt_inf_spacing, cfg->rx_dma_max_bytes, cfg->tx_dma_max_bytes, cfg->dmbc_en, cfg->late_scb, cfg->tno_intr, cfg->ci_intr, cfg->dis_overrun_rx, cfg->save_bad_frame, cfg->dis_short_rx, cfg->underrun_retry, cfg->mii, cfg->nsai, cfg->preamble_len, cfg->loopback, cfg->linear_prio, cfg->pri_mode, cfg->interframe_spacing, cfg->promiscuous, cfg->broadcast_dis, cfg->crs_cdt, cfg->strip, cfg->padding, cfg->rx_crc, cfg->force_fdx, cfg->fdx_en, cfg->mul_ia, cfg->mul_all); } break; case CBL_MULTCAST_ADDR_SETUP: { uint16_t mult_list_count = 0; uint16_t size = 0; cpu_physical_memory_read(cb_addr + 8, (uint8_t *)&mult_list_count, 2); mult_list_count = (mult_list_count << 2) >> 2; if ( !mult_list_count ) { logout("Multcast disabled(multicast count=0)\n"); s->is_multcast_enable = 0; memset(s->mult_list, 0x0, sizeof(s->mult_list)); break; } size = mult_list_count > sizeof(s->mult_list) ? sizeof(s->mult_list) : mult_list_count; cpu_physical_memory_read(cb_addr + 12, &s->mult_list[0], size); e100_dump("Setup Multicast list: ", &s->mult_list[0], size); break; } case CBL_TRANSMIT: { struct { struct control_block cb; tbd_t tbd; } __attribute__ ((packed)) tx; struct { uint32_t addr; uint16_t size; uint16_t is_el_set; } tx_buf = {0}; uint32_t tbd_array; uint16_t tcb_bytes; uint8_t sf; int len = s->pkt_buf_len; assert( len < sizeof(s->pkt_buf)); cpu_physical_memory_read(cb_addr, (uint8_t *)&tx, sizeof(tx)); tbd_array = le32_to_cpu(tx.tbd.tx_desc_addr); tcb_bytes = le16_to_cpu(tx.tbd.tcb_bytes); // Indicate use what mode to transmit(simple or flexible) sf = tx.cb.rs3 & 0x1; logout("Get a TBD:\n" "\tTBD array address:%#x\n" "\tTCB byte count:%#x\n" "\tEOF:%#x\n" "\tTransmit Threshold:%#x\n" "\tTBD number:%#x\n" "\tUse %s mode to send frame\n", tbd_array, tcb_bytes, tx.tbd.eof, tx.tbd.tx_threshold, tx.tbd.tbd_num, sf ? "Flexible" : "Simple"); if ( !sf || tbd_array == (uint32_t)-1 ) { /* Simple mode */ /* For simple mode, TCB bytes should not be zero. * But we still check here for safety */ if ( !tcb_bytes || tcb_bytes > sizeof(s->pkt_buf) ) break; cpu_physical_memory_read(cb_addr+16, &s->pkt_buf[0], tcb_bytes); len = tcb_bytes; logout("simple mode(size=%d)\n", len); } else { /* Flexible mode */ /* For flexible mode, TBD num should not be zero. * But we still check here for safety */ if ( !tx.tbd.tbd_num ) break; // I82557 don't support extend TCB if ( s->device == i82557C || s->device == i82557B ) { /* Standard TCB mode */ int i; for ( i=0; i<tx.tbd.tbd_num; i++ ) { cpu_physical_memory_read(tbd_array, (uint8_t *)&tx_buf, sizeof(tx_buf)); tx_buf.is_el_set &= 0x1; tx_buf.size &= 0x7fff; tbd_array += 8; if ( tx_buf.size > sizeof(s->pkt_buf) - len ) { logout("Warning: Get a too big TBD, ignore it" "(buf addr %#x, size %d, el:%#x)\n", tx_buf.addr, tx_buf.size, tx_buf.is_el_set); continue; } cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len], tx_buf.size); logout("TBD (standard mode): buf addr %#x, size %d, el:%#x\n", tx_buf.addr, tx_buf.size, tx_buf.is_el_set); len += tx_buf.size; if ( tx_buf.is_el_set ) break; } } //FIXME: Extend mode is not be tested else { /* Extend TCB mode */ /* A strandard TCB followed by two TBDs */ uint32_t tbd_addr = cb_addr+16; int i = 0; for ( ; i<2 && i<tx.tbd.tbd_num; i++ ) { cpu_physical_memory_read(tbd_array, (uint8_t *)&tx_buf, sizeof(tx_buf)); tx_buf.is_el_set &= 0x1; tbd_addr += 8; /* From Intel's spec, size of TBD equal to zero * has same effect with EL bit set */ if ( tx_buf.size == 0 ) { tx_buf.is_el_set = 1; break; } if ( tx_buf.size + len > sizeof(s->pkt_buf) ) { logout("TX frame is too large, discarding it" "(buf addr=%#x, size=%#x)\n", tx_buf.addr, tx_buf.size); //continue; break; } logout("TBD (extended mode): buf addr %#08x, size %#04x, el:%#x\n", tx_buf.addr, tx_buf.size, tx_buf.is_el_set); cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len], tx_buf.size); len += tx_buf.size; if ( tx_buf.is_el_set ) break; } /* In extend TCB mode, TDB array point to the thrid TBD * if it is not NULL(0xffffffff) and EL bit of before * two TBDs is not set */ if ( tbd_array != (uint32_t)-1 && !tx_buf.is_el_set ) { tbd_addr = tbd_array; /* TBD number includes first two TBDs, so don't * initialize i here */ for ( ; i<tx.tbd.tbd_num; i++ ) { cpu_physical_memory_read(tbd_addr, (uint8_t *)&tx_buf, sizeof(tx_buf)); tx_buf.is_el_set &= 0x1; tbd_addr += 8; cpu_physical_memory_read(tx_buf.addr, &s->pkt_buf[len], tx_buf.size); logout("TBD (extended mode): buf addr 0x%#08x, size 0x%#04x\n", tx_buf.addr, tx_buf.size); len += tx_buf.size; if ( tx_buf.is_el_set ) break; } } } } s->pkt_buf_len = len;/* Below codes are used for Threshold. But with these logic, network of guest * getting bad performance. So I comment it and leave codes here to hope anyone * fix it */#if 0 /* If threshold is set, only send packet when threshold * bytes are read */ if ( tx.tbd.tx_threshold && s->pkt_buf_len < tx.tbd.tx_threshold * 8 ) { logout("Current data length in FIFO buffer:%d\n", s->pkt_buf_len); break; }#endif if ( s->pkt_buf_len ) { qemu_send_packet(s->vc, s->pkt_buf, s->pkt_buf_len); s->statistics.tx_good_frames ++; logout("Send out frame successful(size=%d," "already sent %d frames)\n", s->pkt_buf_len, s->statistics.tx_good_frames); s->pkt_buf_len = 0; } e100_dump("Dest addr:", (uint8_t *)s->pkt_buf, 6); e100_dump("Src addr:", (uint8_t *)(s->pkt_buf+6), 6); e100_dump("type:", (uint8_t *)(s->pkt_buf+8), 2); break; } case CBL_LOAD_MICROCODE:#ifdef DEBUG_E100 { /* Don't support load marco code, just dump it */ #define MICRO_CODE_LEN 256 uint8_t micro_code[MICRO_CODE_LEN] = {0}; cpu_physical_memory_read(cb_addr+8, micro_code, MICRO_CODE_LEN); e100_dump("Load micro code:", micro_code, MICRO_CODE_LEN); }#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -