📄 e100.c
字号:
/* Initialize EEDO bit to 1. Due to driver would detect dummy 0 at * EEDO bit, so initialize it to 1 is safety a way. */ CSR(CSR_EEPROM, eedo) = 1; // no pending interrupts s->scb_stat = 0; return;}static void e100_software_reset(E100State *s){ memset(s->pci_mem.mem, 0x0, sizeof(s->pci_mem.mem)); // Clear multicast list memset(s->mult_list, 0x0, sizeof(s->mult_list)); // Set MDI register to default value memcpy(&s->mdimem[0], &e100_mdi_default[0], sizeof(s->mdimem)); s->is_multcast_enable = 1; /* Clean FIFO buffer */ memset(s->pkt_buf, 0x0, sizeof(s->pkt_buf)); s->pkt_buf_len = 0; memset(&s->statistics, 0x0, sizeof(s->statistics)); e100_selective_reset(s); return;}static void e100_reset(void *opaque){ E100State *s = (E100State *) opaque; logout("%p\n", s); e100_software_reset(s);}static void e100_save(QEMUFile * f, void *opaque){ //TODO return;}static int e100_load(QEMUFile * f, void *opaque, int version_id){ //TODO return 0;}/* Interrupt functions */static void e100_interrupt(E100State *s, uint16_t int_type){ //TODO: Add another i8255x card supported mask bit if ( !CSR(CSR_CMD,m) ) { //Set bit in stat/ack, so driver can no what interrupt happen CSR_VAL(CSR_STATUS) |= int_type; s->scb_stat = CSR(CSR_STATUS, stat_ack); /* SCB maske and SCB Bit M do not disable interrupt. */ logout("Trigger an interrupt(type = %s(%#x), SCB Status = %#x)\n", INT_NAME(int_type), int_type, CSR_VAL(CSR_STATUS)); pci_set_irq(s->pci_dev, 0, 1); }}static void e100_interrupt_ack(E100State * s, uint8_t ack){ /* Ignore acknowledege if driver write 0 to ack or * according interrupt bit is not set */ if ( !ack || !(s->scb_stat & ack) ) { logout("Illegal interrupt ack(ack=%#x, SCB Stat/Ack=%#x), ignore it\n", ack, s->scb_stat); // Due to we do write operation before e100_execute(), so // we must restore value of ack field here CSR(CSR_STATUS, stat_ack) = s->scb_stat; return; } s->scb_stat &= ~ack; CSR(CSR_STATUS, stat_ack) = s->scb_stat; logout("Interrupt ack(name=%s,val=%#x)\n", INT_NAME(({uint16_t bit = ack<<8;bit;})),ack); if ( !s->scb_stat ) { logout("All interrupts are acknowledeged, de-assert interrupt line\n"); pci_set_irq(s->pci_dev, 0, 0); }}static void e100_self_test(uint32_t res_addr){ struct { uint32_t st_sign; /* Self Test Signature */ uint32_t st_result; /* Self Test Results */ } test_res; test_res.st_sign = (uint32_t)-1; test_res.st_result = 0; // Our self test always success cpu_physical_memory_write(res_addr, (uint8_t *)&test_res, sizeof(test_res)); logout("Write self test result to %#x\n", res_addr);}static void scb_port_func(E100State *s, uint32_t val, int dir){#define PORT_SELECTION_MASK 0xfU uint32_t sel = val & PORT_SELECTION_MASK; switch ( sel ) { case PORT_SOFTWARE_RESET: logout("do PORT_SOFTWARE_RESET!\n"); e100_software_reset(s); break; case PORT_SELF_TEST: e100_self_test(val & ~PORT_SELECTION_MASK); logout("do PORT_SELF_TEST!\n"); break; case PORT_SELECTIVE_RESET: logout("do PORT_SELECTIVE_RESET!\n"); e100_selective_reset(s); break; case PORT_DUMP: logout("do PORT_SOFTWARE_RESET!\n"); break; case PORT_DUMP_WAKE_UP: logout("do PORT_SOFTWARE_RESET!\n"); break; default: logout("Unkonw SCB port command(selection function = %#x)\n", sel); }}static void e100_write_mdi(E100State *s, uint32_t val){ uint32_t ie = (val & 0x20000000) >> 29; uint32_t opcode = (val & 0x0c000000) >> 26; uint32_t phyaddr = (val & 0x03e00000) >> 21; uint32_t regaddr = (val & 0x001f0000) >> 16; uint32_t data = val & 0x0000ffff; logout("Write MDI:\n" "\topcode:%#x\n" "\tphy address:%#x\n" "\treg address:%#x\n" "\tie:%#x\n" "\tdata:%#x\n", opcode, phyaddr, regaddr, ie, data); /* We use default value --- PHY1 * If driver operate on other PHYs, do nothing and * deceive it that the operation is finished */ if ( phyaddr != 1 ) { logout("Unsupport PHY address(phy = %#x)\n", phyaddr); goto done; } // 1: MDI write // 2: MDI read if ( opcode != MDI_WRITE && opcode != MDI_READ ) { logout("Invalid Opcode(opcode = %#x)\n", opcode); return; } // Current only support MDI generic registers. if ( regaddr > 6 ) { logout("Invalid phy register index( phy register addr = %#x)\n", regaddr); } if ( opcode == MDI_WRITE ) { // MDI write switch ( regaddr ) { case 0: // Control Register if ( data & 0x8000 ) // Reset { /* Reset status and control registers to default. */ s->mdimem[0] = e100_mdi_default[0]; s->mdimem[1] = e100_mdi_default[1]; data = s->mdimem[regaddr]; } else { /* Restart Auto Configuration = Normal Operation */ data &= ~0x0200; } break; case 1: // Status Register logout("Invalid write on readonly register(opcode = %#x)\n", opcode); data = s->mdimem[regaddr]; break; case 2: case 3: case 4: case 5: case 6: break; } s->mdimem[regaddr] = data; logout("MDI WRITE: reg = %#x, data = %#x\n", regaddr, data); } else if ( opcode == MDI_READ ) { // MDI read switch ( regaddr ) { case 0: // Control Register if ( data & 0x8000 ) // Reset { /* Reset status and control registers to default. */ s->mdimem[0] = e100_mdi_default[0]; s->mdimem[1] = e100_mdi_default[1]; } break; case 1: // Status Register // Auto Negotiation complete, set sticky bit to 1 s->mdimem[regaddr] |= 0x0026; break; case 2: // PHY Identification Register (Word 1) case 3: // PHY Identification Register (Word 2) break; case 5: // Auto-Negotiation Link Partner Ability Register s->mdimem[regaddr] = 0x41fe; break; case 6: // Auto-Negotiation Expansion Register s->mdimem[regaddr] = 0x0001; break; } data = s->mdimem[regaddr]; logout("MDI READ: reg = %#x, data = %#x\n", regaddr, data); } /* Emulation takes no time to finish MDI transaction. * Set MDI bit in SCB status register. */done: val |= BIT(28); val = (val & 0xffff0000) + data; CSR_WRITE(SCB_MDI, val, uint32_t); if ( ie ) e100_interrupt(s, (uint16_t)INT_MDI);}static void scb_mdi_func(E100State *s, uint32_t val, int dir){ if ( dir == OP_READ ) // Do nothing, just tell driver we are ready CSR_VAL(CSR_MDI) |= BIT(28); else if ( dir == OP_WRITE ) e100_write_mdi(s, val); else 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -