📄 e100.c
字号:
logout("Invalid operation direction(dir=%x)\n", dir);}static void eeprom_reset(E100State *s, int type){ eeprom_t *e = &s->eeprom; if ( type == EEPROM_RESET_ALL ) { memset(e, 0x0, sizeof(eeprom_t)); e->val_type = NOP; logout("EEPROM reset all\n"); return; } CSR(CSR_EEPROM, eedo) = 1; e->start_bit = 0; e->opcode = 0; e->address = 0; e->data = 0; e->val = 0; e->val_len = 0; e->val_type = NOP; e->cs = 0; e->sk = 0; logout("EEPROM select reset\n");}static void do_eeprom_op(E100State *s, eeprom_t *e, int cs, int sk, int di, int dir){ int assert_cs = (cs == 1 && e->cs == 0); int de_assert_cs = (cs == 0 && e->cs == 1); int de_assert_sk = (sk == 0 && e->sk == 1); // Chip select is not be enabled if ( cs == 0 && e->cs == 0 ) { logout("Invalid EECS signal\n"); return; } // update state e->cs = cs; e->sk = sk; // Do nothing if ( assert_cs ) { logout("EECS assert\n"); return; } // Complete one command if ( de_assert_cs ) { if ( e->val_type == DATA && e->opcode == EEPROM_WRITE ) { e->data = e->val; memcpy((void *)((unsigned long)e->contents + e->address), &e->data, sizeof(e->data)); logout("EEPROM write complete(data=%#x)\n", e->data); } eeprom_trace(0,0,0,NOP,1); eeprom_reset(s, EEPROM_SELECT_RESET); logout("EECS de-asserted\n"); return; } // Chip is selected and serial clock is change, so the operation is vaild if ( cs == 1 && de_assert_sk == 1) { // Set start bit if ( e->start_bit == 0 && di == 1 ) { e->start_bit = di; e->val_len = 0; e->val = 0; e->val_type = OPCODE; eeprom_trace(0,0,0,OPCODE,1); logout("EEPROM start bit set\n"); return; } // Data in DI is vaild else if ( e->start_bit == 1 ) { // If current operation is eeprom read, ignore DI if ( !(e->val_type == DATA && e->opcode == EEPROM_READ) ) { e->val = (e->val << 1) | di; e->val_len ++; } switch ( e->val_type ) { // Get the opcode. case OPCODE: eeprom_trace(CSR(CSR_EEPROM, eedo), di, e->opcode, 0, 0); if ( e->val_len == 2 ) { e->opcode = e->val; e->val = 0; e->val_len = 0; e->val_type = ADDR; eeprom_trace(0,0,0,ADDR,1); logout("EEPROM get opcode(opcode name=%s,opcode=%#x )\n", EEPROM_OPCODE_NAME(e->opcode), e->opcode); } break; // Get address case ADDR: eeprom_trace(CSR(CSR_EEPROM, eedo), di, e->opcode, 0, 0); if ( e->val_len == e->addr_len ) { e->address = e->val; e->val = 0; e->val_len = 0; e->val_type = DATA; // We prepare data eary for later read operation if ( e->opcode == EEPROM_READ ) { memcpy(&e->data, (void *)(e->contents + e->address), sizeof(e->data)); logout("EEPROM prepare data to read(addr=%#x,data=%#x)\n", e->address, e->data); } // Write dummy 0 to response to driver the address is written complete CSR(CSR_EEPROM, eedo) = 0; eeprom_trace(0,0,0,DATA,1); logout("EEPROM get address(addr=%#x)\n", e->address); } break; // Only do data out operation case DATA: if ( e->opcode == EEPROM_READ ) { // Start from the most significant bit //uint16_t t = ((e->data & (1<<(sizeof(e->data)*8 - e->val_len - 1))) != 0); uint16_t t = !!(e->data & (0x8000U >> e->val_len)); CSR(CSR_EEPROM, eedo) = t; 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++ ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -