📄 e100.c
字号:
CSR(CSR_CMD, simb) = 0x3f; // Set PHY to 1 CSR_VAL(CSR_MDI) |= BIT(21); /* 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){ E100State *s = (E100State *)opaque; int i; pci_device_save(s->pci_dev, f); qemu_put_be32s(f, &s->mmio_index); qemu_put_8s(f, &s->scb_stat); for(i = 0; i < REGION_NUM; i++) { qemu_put_be32s(f, &s->region_base_addr[i]); } qemu_put_buffer(f, s->macaddr, 6); for(i = 0; i < 32; i++) { qemu_put_be16s(f, &s->mdimem[i]); } /* Save eeprom. */ qemu_put_8s(f, &s->eeprom.start_bit); qemu_put_8s(f, &s->eeprom.opcode); qemu_put_8s(f, &s->eeprom.address); qemu_put_be16s(f, &s->eeprom.data); qemu_put_be32s(f, &s->eeprom.val); qemu_put_be32s(f, &s->eeprom.val); qemu_put_be32s(f, &s->eeprom.val_len); qemu_put_be32s(f, &s->eeprom.val_type); qemu_put_8s(f, &s->eeprom.cs); qemu_put_8s(f, &s->eeprom.sk); qemu_put_be16s(f, &s->eeprom.addr_len); for(i = 0; i < 256; i++) { qemu_put_be16s(f, &s->eeprom.contents[i]); } qemu_put_be32s(f, &s->device); qemu_put_buffer(f, s->mult_list, 8); qemu_put_be32s(f, &s->is_multcast_enable); qemu_put_be32s(f, &s->cu_base); qemu_put_be32s(f, &s->cu_offset); qemu_put_be32s(f, &s->cu_next); qemu_put_be32s(f, &s->ru_base); qemu_put_be32s(f, &s->ru_offset); qemu_put_be32s(f, &s->statsaddr); /* Save statistics. */ qemu_put_be32s(f, &s->statistics.tx_good_frames); qemu_put_be32s(f, &s->statistics.tx_max_collisions); qemu_put_be32s(f, &s->statistics.tx_late_collisions); qemu_put_be32s(f, &s->statistics.tx_underruns); qemu_put_be32s(f, &s->statistics.tx_lost_crs); qemu_put_be32s(f, &s->statistics.tx_deferred); qemu_put_be32s(f, &s->statistics.tx_single_collisions); qemu_put_be32s(f, &s->statistics.tx_multiple_collisions); qemu_put_be32s(f, &s->statistics.tx_total_collisions); qemu_put_be32s(f, &s->statistics.rx_good_frames); qemu_put_be32s(f, &s->statistics.rx_crc_errors); qemu_put_be32s(f, &s->statistics.rx_alignment_errors); qemu_put_be32s(f, &s->statistics.rx_resource_errors); qemu_put_be32s(f, &s->statistics.rx_overrun_errors); qemu_put_be32s(f, &s->statistics.rx_short_frame_errors); qemu_put_be32s(f, &s->statistics.complete_word); qemu_put_buffer(f, (uint8_t*)(&s->config), sizeof(s->config)); qemu_put_buffer(f, s->pkt_buf, MAX_ETH_FRAME_SIZE+4); qemu_put_be32s(f, &s->pkt_buf_len); qemu_put_buffer(f, (uint8_t*)(&s->pci_mem), sizeof(s->pci_mem));}static int e100_load(QEMUFile * f, void *opaque, int version_id){ E100State *s = (E100State *)opaque; int i, ret; if (version_id > 3) return -EINVAL; ret = pci_device_load(s->pci_dev, f); if (ret < 0) return ret; qemu_get_be32s(f, &s->mmio_index); qemu_get_8s(f, &s->scb_stat); for(i = 0; i < REGION_NUM; i++) { qemu_get_be32s(f, &s->region_base_addr[i]); } qemu_get_buffer(f, s->macaddr, 6); for(i = 0; i < 32; i++) { qemu_get_be16s(f, &s->mdimem[i]); } /* Load eeprom. */ qemu_get_8s(f, &s->eeprom.start_bit); qemu_get_8s(f, &s->eeprom.opcode); qemu_get_8s(f, &s->eeprom.address); qemu_get_be16s(f, &s->eeprom.data); qemu_get_be32s(f, &s->eeprom.val); qemu_get_be32s(f, &s->eeprom.val); qemu_get_be32s(f, &s->eeprom.val_len); qemu_get_be32s(f, &s->eeprom.val_type); qemu_get_8s(f, &s->eeprom.cs); qemu_get_8s(f, &s->eeprom.sk); qemu_get_be16s(f, &s->eeprom.addr_len); for(i = 0; i < 256; i++) { qemu_get_be16s(f, &s->eeprom.contents[i]); } qemu_get_be32s(f, &s->device); qemu_get_buffer(f, s->mult_list, 8); qemu_get_be32s(f, &s->is_multcast_enable); qemu_get_be32s(f, &s->cu_base); qemu_get_be32s(f, &s->cu_offset); qemu_get_be32s(f, &s->cu_next); qemu_get_be32s(f, &s->ru_base); qemu_get_be32s(f, &s->ru_offset); qemu_get_be32s(f, &s->statsaddr); /* Load statistics. */ qemu_get_be32s(f, &s->statistics.tx_good_frames); qemu_get_be32s(f, &s->statistics.tx_max_collisions); qemu_get_be32s(f, &s->statistics.tx_late_collisions); qemu_get_be32s(f, &s->statistics.tx_underruns); qemu_get_be32s(f, &s->statistics.tx_lost_crs); qemu_get_be32s(f, &s->statistics.tx_deferred); qemu_get_be32s(f, &s->statistics.tx_single_collisions); qemu_get_be32s(f, &s->statistics.tx_multiple_collisions); qemu_get_be32s(f, &s->statistics.tx_total_collisions); qemu_get_be32s(f, &s->statistics.rx_good_frames); qemu_get_be32s(f, &s->statistics.rx_crc_errors); qemu_get_be32s(f, &s->statistics.rx_alignment_errors); qemu_get_be32s(f, &s->statistics.rx_resource_errors); qemu_get_be32s(f, &s->statistics.rx_overrun_errors); qemu_get_be32s(f, &s->statistics.rx_short_frame_errors); qemu_get_be32s(f, &s->statistics.complete_word); qemu_put_buffer(f, (uint8_t*)(&s->config), sizeof(s->config)); qemu_get_buffer(f, s->pkt_buf, MAX_ETH_FRAME_SIZE+4); qemu_get_be32s(f, &s->pkt_buf_len); qemu_get_buffer(f, (uint8_t*)(&s->pci_mem), sizeof(s->pci_mem)); 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -