134ea023dSSven Schnelle /* 234ea023dSSven Schnelle * QEMU TULIP Emulation 334ea023dSSven Schnelle * 434ea023dSSven Schnelle * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org> 534ea023dSSven Schnelle * 634ea023dSSven Schnelle * This work is licensed under the GNU GPL license version 2 or later. 734ea023dSSven Schnelle */ 834ea023dSSven Schnelle 934ea023dSSven Schnelle #include "qemu/osdep.h" 1034ea023dSSven Schnelle #include "qemu/log.h" 1134ea023dSSven Schnelle #include "hw/irq.h" 1234ea023dSSven Schnelle #include "hw/pci/pci.h" 1334ea023dSSven Schnelle #include "hw/qdev-properties.h" 1434ea023dSSven Schnelle #include "hw/nvram/eeprom93xx.h" 1534ea023dSSven Schnelle #include "migration/vmstate.h" 1634ea023dSSven Schnelle #include "sysemu/sysemu.h" 1734ea023dSSven Schnelle #include "tulip.h" 1834ea023dSSven Schnelle #include "trace.h" 1934ea023dSSven Schnelle #include "net/eth.h" 2034ea023dSSven Schnelle 2157af4d7fSEduardo Habkost struct TULIPState { 2234ea023dSSven Schnelle PCIDevice dev; 2334ea023dSSven Schnelle MemoryRegion io; 2434ea023dSSven Schnelle MemoryRegion memory; 2534ea023dSSven Schnelle NICConf c; 2634ea023dSSven Schnelle qemu_irq irq; 2734ea023dSSven Schnelle NICState *nic; 2834ea023dSSven Schnelle eeprom_t *eeprom; 2934ea023dSSven Schnelle uint32_t csr[16]; 3034ea023dSSven Schnelle 3134ea023dSSven Schnelle /* state for MII */ 3234ea023dSSven Schnelle uint32_t old_csr9; 3334ea023dSSven Schnelle uint32_t mii_word; 3434ea023dSSven Schnelle uint32_t mii_bitcnt; 3534ea023dSSven Schnelle 3634ea023dSSven Schnelle hwaddr current_rx_desc; 3734ea023dSSven Schnelle hwaddr current_tx_desc; 3834ea023dSSven Schnelle 3934ea023dSSven Schnelle uint8_t rx_frame[2048]; 4034ea023dSSven Schnelle uint8_t tx_frame[2048]; 4134ea023dSSven Schnelle uint16_t tx_frame_len; 4234ea023dSSven Schnelle uint16_t rx_frame_len; 4334ea023dSSven Schnelle uint16_t rx_frame_size; 4434ea023dSSven Schnelle 4534ea023dSSven Schnelle uint32_t rx_status; 4634ea023dSSven Schnelle uint8_t filter[16][6]; 4757af4d7fSEduardo Habkost }; 4834ea023dSSven Schnelle 4934ea023dSSven Schnelle static const VMStateDescription vmstate_pci_tulip = { 5034ea023dSSven Schnelle .name = "tulip", 5134ea023dSSven Schnelle .fields = (VMStateField[]) { 5234ea023dSSven Schnelle VMSTATE_PCI_DEVICE(dev, TULIPState), 5334ea023dSSven Schnelle VMSTATE_UINT32_ARRAY(csr, TULIPState, 16), 5434ea023dSSven Schnelle VMSTATE_UINT32(old_csr9, TULIPState), 5534ea023dSSven Schnelle VMSTATE_UINT32(mii_word, TULIPState), 5634ea023dSSven Schnelle VMSTATE_UINT32(mii_bitcnt, TULIPState), 5734ea023dSSven Schnelle VMSTATE_UINT64(current_rx_desc, TULIPState), 5834ea023dSSven Schnelle VMSTATE_UINT64(current_tx_desc, TULIPState), 5934ea023dSSven Schnelle VMSTATE_BUFFER(rx_frame, TULIPState), 6034ea023dSSven Schnelle VMSTATE_BUFFER(tx_frame, TULIPState), 6134ea023dSSven Schnelle VMSTATE_UINT16(rx_frame_len, TULIPState), 6234ea023dSSven Schnelle VMSTATE_UINT16(tx_frame_len, TULIPState), 6334ea023dSSven Schnelle VMSTATE_UINT16(rx_frame_size, TULIPState), 6434ea023dSSven Schnelle VMSTATE_UINT32(rx_status, TULIPState), 6534ea023dSSven Schnelle VMSTATE_UINT8_2DARRAY(filter, TULIPState, 16, 6), 6634ea023dSSven Schnelle VMSTATE_END_OF_LIST() 6734ea023dSSven Schnelle } 6834ea023dSSven Schnelle }; 6934ea023dSSven Schnelle 7034ea023dSSven Schnelle static void tulip_desc_read(TULIPState *s, hwaddr p, 7134ea023dSSven Schnelle struct tulip_descriptor *desc) 7234ea023dSSven Schnelle { 7334ea023dSSven Schnelle if (s->csr[0] & CSR0_DBO) { 7434ea023dSSven Schnelle desc->status = ldl_be_pci_dma(&s->dev, p); 7534ea023dSSven Schnelle desc->control = ldl_be_pci_dma(&s->dev, p + 4); 7634ea023dSSven Schnelle desc->buf_addr1 = ldl_be_pci_dma(&s->dev, p + 8); 7734ea023dSSven Schnelle desc->buf_addr2 = ldl_be_pci_dma(&s->dev, p + 12); 7834ea023dSSven Schnelle } else { 7934ea023dSSven Schnelle desc->status = ldl_le_pci_dma(&s->dev, p); 8034ea023dSSven Schnelle desc->control = ldl_le_pci_dma(&s->dev, p + 4); 8134ea023dSSven Schnelle desc->buf_addr1 = ldl_le_pci_dma(&s->dev, p + 8); 8234ea023dSSven Schnelle desc->buf_addr2 = ldl_le_pci_dma(&s->dev, p + 12); 8334ea023dSSven Schnelle } 8434ea023dSSven Schnelle } 8534ea023dSSven Schnelle 8634ea023dSSven Schnelle static void tulip_desc_write(TULIPState *s, hwaddr p, 8734ea023dSSven Schnelle struct tulip_descriptor *desc) 8834ea023dSSven Schnelle { 89*a423a1b5SPhilippe Mathieu-Daudé const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED; 90*a423a1b5SPhilippe Mathieu-Daudé 9134ea023dSSven Schnelle if (s->csr[0] & CSR0_DBO) { 92*a423a1b5SPhilippe Mathieu-Daudé stl_be_pci_dma(&s->dev, p, desc->status, attrs); 93*a423a1b5SPhilippe Mathieu-Daudé stl_be_pci_dma(&s->dev, p + 4, desc->control, attrs); 94*a423a1b5SPhilippe Mathieu-Daudé stl_be_pci_dma(&s->dev, p + 8, desc->buf_addr1, attrs); 95*a423a1b5SPhilippe Mathieu-Daudé stl_be_pci_dma(&s->dev, p + 12, desc->buf_addr2, attrs); 9634ea023dSSven Schnelle } else { 97*a423a1b5SPhilippe Mathieu-Daudé stl_le_pci_dma(&s->dev, p, desc->status, attrs); 98*a423a1b5SPhilippe Mathieu-Daudé stl_le_pci_dma(&s->dev, p + 4, desc->control, attrs); 99*a423a1b5SPhilippe Mathieu-Daudé stl_le_pci_dma(&s->dev, p + 8, desc->buf_addr1, attrs); 100*a423a1b5SPhilippe Mathieu-Daudé stl_le_pci_dma(&s->dev, p + 12, desc->buf_addr2, attrs); 10134ea023dSSven Schnelle } 10234ea023dSSven Schnelle } 10334ea023dSSven Schnelle 10434ea023dSSven Schnelle static void tulip_update_int(TULIPState *s) 10534ea023dSSven Schnelle { 10634ea023dSSven Schnelle uint32_t ie = s->csr[5] & s->csr[7]; 10734ea023dSSven Schnelle bool assert = false; 10834ea023dSSven Schnelle 10934ea023dSSven Schnelle s->csr[5] &= ~(CSR5_AIS | CSR5_NIS); 11034ea023dSSven Schnelle 11134ea023dSSven Schnelle if (ie & (CSR5_TI | CSR5_TU | CSR5_RI | CSR5_GTE | CSR5_ERI)) { 11234ea023dSSven Schnelle s->csr[5] |= CSR5_NIS; 11334ea023dSSven Schnelle } 11434ea023dSSven Schnelle 11534ea023dSSven Schnelle if (ie & (CSR5_LC | CSR5_GPI | CSR5_FBE | CSR5_LNF | CSR5_ETI | CSR5_RWT | 11634ea023dSSven Schnelle CSR5_RPS | CSR5_RU | CSR5_UNF | CSR5_LNP_ANC | CSR5_TJT | 11734ea023dSSven Schnelle CSR5_TPS)) { 11834ea023dSSven Schnelle s->csr[5] |= CSR5_AIS; 11934ea023dSSven Schnelle } 12034ea023dSSven Schnelle 12134ea023dSSven Schnelle assert = s->csr[5] & s->csr[7] & (CSR5_AIS | CSR5_NIS); 12234ea023dSSven Schnelle trace_tulip_irq(s->csr[5], s->csr[7], assert ? "assert" : "deassert"); 12334ea023dSSven Schnelle qemu_set_irq(s->irq, assert); 12434ea023dSSven Schnelle } 12534ea023dSSven Schnelle 12634ea023dSSven Schnelle static bool tulip_rx_stopped(TULIPState *s) 12734ea023dSSven Schnelle { 12834ea023dSSven Schnelle return ((s->csr[5] >> CSR5_RS_SHIFT) & CSR5_RS_MASK) == CSR5_RS_STOPPED; 12934ea023dSSven Schnelle } 13034ea023dSSven Schnelle 13134ea023dSSven Schnelle static void tulip_dump_tx_descriptor(TULIPState *s, 13234ea023dSSven Schnelle struct tulip_descriptor *desc) 13334ea023dSSven Schnelle { 13434ea023dSSven Schnelle trace_tulip_descriptor("TX ", s->current_tx_desc, 13534ea023dSSven Schnelle desc->status, desc->control >> 22, 13634ea023dSSven Schnelle desc->control & 0x7ff, (desc->control >> 11) & 0x7ff, 13734ea023dSSven Schnelle desc->buf_addr1, desc->buf_addr2); 13834ea023dSSven Schnelle } 13934ea023dSSven Schnelle 14034ea023dSSven Schnelle static void tulip_dump_rx_descriptor(TULIPState *s, 14134ea023dSSven Schnelle struct tulip_descriptor *desc) 14234ea023dSSven Schnelle { 14334ea023dSSven Schnelle trace_tulip_descriptor("RX ", s->current_rx_desc, 14434ea023dSSven Schnelle desc->status, desc->control >> 22, 14534ea023dSSven Schnelle desc->control & 0x7ff, (desc->control >> 11) & 0x7ff, 14634ea023dSSven Schnelle desc->buf_addr1, desc->buf_addr2); 14734ea023dSSven Schnelle } 14834ea023dSSven Schnelle 14934ea023dSSven Schnelle static void tulip_next_rx_descriptor(TULIPState *s, 15034ea023dSSven Schnelle struct tulip_descriptor *desc) 15134ea023dSSven Schnelle { 15234ea023dSSven Schnelle if (desc->control & RDES1_RER) { 15334ea023dSSven Schnelle s->current_rx_desc = s->csr[3]; 15434ea023dSSven Schnelle } else if (desc->control & RDES1_RCH) { 15534ea023dSSven Schnelle s->current_rx_desc = desc->buf_addr2; 15634ea023dSSven Schnelle } else { 15734ea023dSSven Schnelle s->current_rx_desc += sizeof(struct tulip_descriptor) + 15834ea023dSSven Schnelle (((s->csr[0] >> CSR0_DSL_SHIFT) & CSR0_DSL_MASK) << 2); 15934ea023dSSven Schnelle } 16034ea023dSSven Schnelle s->current_rx_desc &= ~3ULL; 16134ea023dSSven Schnelle } 16234ea023dSSven Schnelle 16334ea023dSSven Schnelle static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc) 16434ea023dSSven Schnelle { 16534ea023dSSven Schnelle int len1 = (desc->control >> RDES1_BUF1_SIZE_SHIFT) & RDES1_BUF1_SIZE_MASK; 16634ea023dSSven Schnelle int len2 = (desc->control >> RDES1_BUF2_SIZE_SHIFT) & RDES1_BUF2_SIZE_MASK; 16734ea023dSSven Schnelle int len; 16834ea023dSSven Schnelle 16934ea023dSSven Schnelle if (s->rx_frame_len && len1) { 17034ea023dSSven Schnelle if (s->rx_frame_len > len1) { 17134ea023dSSven Schnelle len = len1; 17234ea023dSSven Schnelle } else { 17334ea023dSSven Schnelle len = s->rx_frame_len; 17434ea023dSSven Schnelle } 1758ffb7265SPrasad J Pandit 17634ea023dSSven Schnelle pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame + 17734ea023dSSven Schnelle (s->rx_frame_size - s->rx_frame_len), len); 17834ea023dSSven Schnelle s->rx_frame_len -= len; 17934ea023dSSven Schnelle } 18034ea023dSSven Schnelle 18134ea023dSSven Schnelle if (s->rx_frame_len && len2) { 18234ea023dSSven Schnelle if (s->rx_frame_len > len2) { 18334ea023dSSven Schnelle len = len2; 18434ea023dSSven Schnelle } else { 18534ea023dSSven Schnelle len = s->rx_frame_len; 18634ea023dSSven Schnelle } 1878ffb7265SPrasad J Pandit 18834ea023dSSven Schnelle pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame + 18934ea023dSSven Schnelle (s->rx_frame_size - s->rx_frame_len), len); 19034ea023dSSven Schnelle s->rx_frame_len -= len; 19134ea023dSSven Schnelle } 19234ea023dSSven Schnelle } 19334ea023dSSven Schnelle 19434ea023dSSven Schnelle static bool tulip_filter_address(TULIPState *s, const uint8_t *addr) 19534ea023dSSven Schnelle { 19634ea023dSSven Schnelle static const char broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 19734ea023dSSven Schnelle bool ret = false; 19834ea023dSSven Schnelle int i; 19934ea023dSSven Schnelle 20034ea023dSSven Schnelle for (i = 0; i < 16 && ret == false; i++) { 20134ea023dSSven Schnelle if (!memcmp(&s->filter[i], addr, ETH_ALEN)) { 20234ea023dSSven Schnelle ret = true; 20334ea023dSSven Schnelle } 20434ea023dSSven Schnelle } 20534ea023dSSven Schnelle 20634ea023dSSven Schnelle if (!memcmp(addr, broadcast, ETH_ALEN)) { 20734ea023dSSven Schnelle return true; 20834ea023dSSven Schnelle } 20934ea023dSSven Schnelle 21034ea023dSSven Schnelle if (s->csr[6] & (CSR6_PR | CSR6_RA)) { 21134ea023dSSven Schnelle /* Promiscuous mode enabled */ 21234ea023dSSven Schnelle s->rx_status |= RDES0_FF; 21334ea023dSSven Schnelle return true; 21434ea023dSSven Schnelle } 21534ea023dSSven Schnelle 21634ea023dSSven Schnelle if ((s->csr[6] & CSR6_PM) && (addr[0] & 1)) { 21734ea023dSSven Schnelle /* Pass all Multicast enabled */ 21834ea023dSSven Schnelle s->rx_status |= RDES0_MF; 21934ea023dSSven Schnelle return true; 22034ea023dSSven Schnelle } 22134ea023dSSven Schnelle 22234ea023dSSven Schnelle if (s->csr[6] & CSR6_IF) { 22334ea023dSSven Schnelle ret ^= true; 22434ea023dSSven Schnelle } 22534ea023dSSven Schnelle return ret; 22634ea023dSSven Schnelle } 22734ea023dSSven Schnelle 22834ea023dSSven Schnelle static ssize_t tulip_receive(TULIPState *s, const uint8_t *buf, size_t size) 22934ea023dSSven Schnelle { 23034ea023dSSven Schnelle struct tulip_descriptor desc; 23134ea023dSSven Schnelle 23234ea023dSSven Schnelle trace_tulip_receive(buf, size); 23334ea023dSSven Schnelle 2348ffb7265SPrasad J Pandit if (size < 14 || size > sizeof(s->rx_frame) - 4 2358ffb7265SPrasad J Pandit || s->rx_frame_len || tulip_rx_stopped(s)) { 23634ea023dSSven Schnelle return 0; 23734ea023dSSven Schnelle } 23834ea023dSSven Schnelle 23934ea023dSSven Schnelle if (!tulip_filter_address(s, buf)) { 24034ea023dSSven Schnelle return size; 24134ea023dSSven Schnelle } 24234ea023dSSven Schnelle 24334ea023dSSven Schnelle do { 24434ea023dSSven Schnelle tulip_desc_read(s, s->current_rx_desc, &desc); 24534ea023dSSven Schnelle tulip_dump_rx_descriptor(s, &desc); 24634ea023dSSven Schnelle 24734ea023dSSven Schnelle if (!(desc.status & RDES0_OWN)) { 24834ea023dSSven Schnelle s->csr[5] |= CSR5_RU; 24934ea023dSSven Schnelle tulip_update_int(s); 25034ea023dSSven Schnelle return s->rx_frame_size - s->rx_frame_len; 25134ea023dSSven Schnelle } 25234ea023dSSven Schnelle desc.status = 0; 25334ea023dSSven Schnelle 25434ea023dSSven Schnelle if (!s->rx_frame_len) { 25534ea023dSSven Schnelle s->rx_frame_size = size + 4; 25634ea023dSSven Schnelle s->rx_status = RDES0_LS | 25734ea023dSSven Schnelle ((s->rx_frame_size & RDES0_FL_MASK) << RDES0_FL_SHIFT); 25834ea023dSSven Schnelle desc.status |= RDES0_FS; 25934ea023dSSven Schnelle memcpy(s->rx_frame, buf, size); 26034ea023dSSven Schnelle s->rx_frame_len = s->rx_frame_size; 26134ea023dSSven Schnelle } 26234ea023dSSven Schnelle 26334ea023dSSven Schnelle tulip_copy_rx_bytes(s, &desc); 26434ea023dSSven Schnelle 26534ea023dSSven Schnelle if (!s->rx_frame_len) { 26634ea023dSSven Schnelle desc.status |= s->rx_status; 26734ea023dSSven Schnelle s->csr[5] |= CSR5_RI; 26834ea023dSSven Schnelle tulip_update_int(s); 26934ea023dSSven Schnelle } 27034ea023dSSven Schnelle tulip_dump_rx_descriptor(s, &desc); 27134ea023dSSven Schnelle tulip_desc_write(s, s->current_rx_desc, &desc); 27234ea023dSSven Schnelle tulip_next_rx_descriptor(s, &desc); 27334ea023dSSven Schnelle } while (s->rx_frame_len); 27434ea023dSSven Schnelle return size; 27534ea023dSSven Schnelle } 27634ea023dSSven Schnelle 27734ea023dSSven Schnelle static ssize_t tulip_receive_nc(NetClientState *nc, 27834ea023dSSven Schnelle const uint8_t *buf, size_t size) 27934ea023dSSven Schnelle { 28034ea023dSSven Schnelle return tulip_receive(qemu_get_nic_opaque(nc), buf, size); 28134ea023dSSven Schnelle } 28234ea023dSSven Schnelle 28334ea023dSSven Schnelle static NetClientInfo net_tulip_info = { 28434ea023dSSven Schnelle .type = NET_CLIENT_DRIVER_NIC, 28534ea023dSSven Schnelle .size = sizeof(NICState), 28634ea023dSSven Schnelle .receive = tulip_receive_nc, 28734ea023dSSven Schnelle }; 28834ea023dSSven Schnelle 28934ea023dSSven Schnelle static const char *tulip_reg_name(const hwaddr addr) 29034ea023dSSven Schnelle { 29134ea023dSSven Schnelle switch (addr) { 29234ea023dSSven Schnelle case CSR(0): 29334ea023dSSven Schnelle return "CSR0"; 29434ea023dSSven Schnelle 29534ea023dSSven Schnelle case CSR(1): 29634ea023dSSven Schnelle return "CSR1"; 29734ea023dSSven Schnelle 29834ea023dSSven Schnelle case CSR(2): 29934ea023dSSven Schnelle return "CSR2"; 30034ea023dSSven Schnelle 30134ea023dSSven Schnelle case CSR(3): 30234ea023dSSven Schnelle return "CSR3"; 30334ea023dSSven Schnelle 30434ea023dSSven Schnelle case CSR(4): 30534ea023dSSven Schnelle return "CSR4"; 30634ea023dSSven Schnelle 30734ea023dSSven Schnelle case CSR(5): 30834ea023dSSven Schnelle return "CSR5"; 30934ea023dSSven Schnelle 31034ea023dSSven Schnelle case CSR(6): 31134ea023dSSven Schnelle return "CSR6"; 31234ea023dSSven Schnelle 31334ea023dSSven Schnelle case CSR(7): 31434ea023dSSven Schnelle return "CSR7"; 31534ea023dSSven Schnelle 31634ea023dSSven Schnelle case CSR(8): 31734ea023dSSven Schnelle return "CSR8"; 31834ea023dSSven Schnelle 31934ea023dSSven Schnelle case CSR(9): 32034ea023dSSven Schnelle return "CSR9"; 32134ea023dSSven Schnelle 32234ea023dSSven Schnelle case CSR(10): 32334ea023dSSven Schnelle return "CSR10"; 32434ea023dSSven Schnelle 32534ea023dSSven Schnelle case CSR(11): 32634ea023dSSven Schnelle return "CSR11"; 32734ea023dSSven Schnelle 32834ea023dSSven Schnelle case CSR(12): 32934ea023dSSven Schnelle return "CSR12"; 33034ea023dSSven Schnelle 33134ea023dSSven Schnelle case CSR(13): 33234ea023dSSven Schnelle return "CSR13"; 33334ea023dSSven Schnelle 33434ea023dSSven Schnelle case CSR(14): 33534ea023dSSven Schnelle return "CSR14"; 33634ea023dSSven Schnelle 33734ea023dSSven Schnelle case CSR(15): 33834ea023dSSven Schnelle return "CSR15"; 33934ea023dSSven Schnelle 34034ea023dSSven Schnelle default: 34134ea023dSSven Schnelle break; 34234ea023dSSven Schnelle } 34334ea023dSSven Schnelle return ""; 34434ea023dSSven Schnelle } 34534ea023dSSven Schnelle 34634ea023dSSven Schnelle static const char *tulip_rx_state_name(int state) 34734ea023dSSven Schnelle { 34834ea023dSSven Schnelle switch (state) { 34934ea023dSSven Schnelle case CSR5_RS_STOPPED: 35034ea023dSSven Schnelle return "STOPPED"; 35134ea023dSSven Schnelle 35234ea023dSSven Schnelle case CSR5_RS_RUNNING_FETCH: 35334ea023dSSven Schnelle return "RUNNING/FETCH"; 35434ea023dSSven Schnelle 35534ea023dSSven Schnelle case CSR5_RS_RUNNING_CHECK_EOR: 35634ea023dSSven Schnelle return "RUNNING/CHECK EOR"; 35734ea023dSSven Schnelle 35834ea023dSSven Schnelle case CSR5_RS_RUNNING_WAIT_RECEIVE: 35934ea023dSSven Schnelle return "WAIT RECEIVE"; 36034ea023dSSven Schnelle 36134ea023dSSven Schnelle case CSR5_RS_SUSPENDED: 36234ea023dSSven Schnelle return "SUSPENDED"; 36334ea023dSSven Schnelle 36434ea023dSSven Schnelle case CSR5_RS_RUNNING_CLOSE: 36534ea023dSSven Schnelle return "RUNNING/CLOSE"; 36634ea023dSSven Schnelle 36734ea023dSSven Schnelle case CSR5_RS_RUNNING_FLUSH: 36834ea023dSSven Schnelle return "RUNNING/FLUSH"; 36934ea023dSSven Schnelle 37034ea023dSSven Schnelle case CSR5_RS_RUNNING_QUEUE: 37134ea023dSSven Schnelle return "RUNNING/QUEUE"; 37234ea023dSSven Schnelle 37334ea023dSSven Schnelle default: 37434ea023dSSven Schnelle break; 37534ea023dSSven Schnelle } 37634ea023dSSven Schnelle return ""; 37734ea023dSSven Schnelle } 37834ea023dSSven Schnelle 37934ea023dSSven Schnelle static const char *tulip_tx_state_name(int state) 38034ea023dSSven Schnelle { 38134ea023dSSven Schnelle switch (state) { 38234ea023dSSven Schnelle case CSR5_TS_STOPPED: 38334ea023dSSven Schnelle return "STOPPED"; 38434ea023dSSven Schnelle 38534ea023dSSven Schnelle case CSR5_TS_RUNNING_FETCH: 38634ea023dSSven Schnelle return "RUNNING/FETCH"; 38734ea023dSSven Schnelle 38834ea023dSSven Schnelle case CSR5_TS_RUNNING_WAIT_EOT: 38934ea023dSSven Schnelle return "RUNNING/WAIT EOT"; 39034ea023dSSven Schnelle 39134ea023dSSven Schnelle case CSR5_TS_RUNNING_READ_BUF: 39234ea023dSSven Schnelle return "RUNNING/READ BUF"; 39334ea023dSSven Schnelle 39434ea023dSSven Schnelle case CSR5_TS_RUNNING_SETUP: 39534ea023dSSven Schnelle return "RUNNING/SETUP"; 39634ea023dSSven Schnelle 39734ea023dSSven Schnelle case CSR5_TS_SUSPENDED: 39834ea023dSSven Schnelle return "SUSPENDED"; 39934ea023dSSven Schnelle 40034ea023dSSven Schnelle case CSR5_TS_RUNNING_CLOSE: 40134ea023dSSven Schnelle return "RUNNING/CLOSE"; 40234ea023dSSven Schnelle 40334ea023dSSven Schnelle default: 40434ea023dSSven Schnelle break; 40534ea023dSSven Schnelle } 40634ea023dSSven Schnelle return ""; 40734ea023dSSven Schnelle } 40834ea023dSSven Schnelle 40934ea023dSSven Schnelle static void tulip_update_rs(TULIPState *s, int state) 41034ea023dSSven Schnelle { 41134ea023dSSven Schnelle s->csr[5] &= ~(CSR5_RS_MASK << CSR5_RS_SHIFT); 41234ea023dSSven Schnelle s->csr[5] |= (state & CSR5_RS_MASK) << CSR5_RS_SHIFT; 41334ea023dSSven Schnelle trace_tulip_rx_state(tulip_rx_state_name(state)); 41434ea023dSSven Schnelle } 41534ea023dSSven Schnelle 41634ea023dSSven Schnelle static uint16_t tulip_mdi_default[] = { 41734ea023dSSven Schnelle /* MDI Registers 0 - 6, 7 */ 41834ea023dSSven Schnelle 0x3100, 0xf02c, 0x7810, 0x0000, 0x0501, 0x4181, 0x0000, 0x0000, 41934ea023dSSven Schnelle /* MDI Registers 8 - 15 */ 42034ea023dSSven Schnelle 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 42134ea023dSSven Schnelle /* MDI Registers 16 - 31 */ 42234ea023dSSven Schnelle 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 42334ea023dSSven Schnelle 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 42434ea023dSSven Schnelle }; 42534ea023dSSven Schnelle 42634ea023dSSven Schnelle /* Readonly mask for MDI (PHY) registers */ 42734ea023dSSven Schnelle static const uint16_t tulip_mdi_mask[] = { 42834ea023dSSven Schnelle 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000, 42934ea023dSSven Schnelle 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 43034ea023dSSven Schnelle 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 43134ea023dSSven Schnelle 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 43234ea023dSSven Schnelle }; 43334ea023dSSven Schnelle 43434ea023dSSven Schnelle static uint16_t tulip_mii_read(TULIPState *s, int phy, int reg) 43534ea023dSSven Schnelle { 43634ea023dSSven Schnelle uint16_t ret = 0; 43734ea023dSSven Schnelle if (phy == 1) { 43834ea023dSSven Schnelle ret = tulip_mdi_default[reg]; 43934ea023dSSven Schnelle } 44034ea023dSSven Schnelle trace_tulip_mii_read(phy, reg, ret); 44134ea023dSSven Schnelle return ret; 44234ea023dSSven Schnelle } 44334ea023dSSven Schnelle 44434ea023dSSven Schnelle static void tulip_mii_write(TULIPState *s, int phy, int reg, uint16_t data) 44534ea023dSSven Schnelle { 44634ea023dSSven Schnelle trace_tulip_mii_write(phy, reg, data); 44734ea023dSSven Schnelle 44834ea023dSSven Schnelle if (phy != 1) { 44934ea023dSSven Schnelle return; 45034ea023dSSven Schnelle } 45134ea023dSSven Schnelle 45234ea023dSSven Schnelle tulip_mdi_default[reg] &= ~tulip_mdi_mask[reg]; 45334ea023dSSven Schnelle tulip_mdi_default[reg] |= (data & tulip_mdi_mask[reg]); 45434ea023dSSven Schnelle } 45534ea023dSSven Schnelle 45634ea023dSSven Schnelle static void tulip_mii(TULIPState *s) 45734ea023dSSven Schnelle { 45834ea023dSSven Schnelle uint32_t changed = s->old_csr9 ^ s->csr[9]; 45934ea023dSSven Schnelle uint16_t data; 46034ea023dSSven Schnelle int op, phy, reg; 46134ea023dSSven Schnelle 46234ea023dSSven Schnelle if (!(changed & CSR9_MDC)) { 46334ea023dSSven Schnelle return; 46434ea023dSSven Schnelle } 46534ea023dSSven Schnelle 46634ea023dSSven Schnelle if (!(s->csr[9] & CSR9_MDC)) { 46734ea023dSSven Schnelle return; 46834ea023dSSven Schnelle } 46934ea023dSSven Schnelle 47034ea023dSSven Schnelle s->mii_bitcnt++; 47134ea023dSSven Schnelle s->mii_word <<= 1; 47234ea023dSSven Schnelle 47334ea023dSSven Schnelle if (s->csr[9] & CSR9_MDO && (s->mii_bitcnt < 16 || 47434ea023dSSven Schnelle !(s->csr[9] & CSR9_MII))) { 47534ea023dSSven Schnelle /* write op or address bits */ 47634ea023dSSven Schnelle s->mii_word |= 1; 47734ea023dSSven Schnelle } 47834ea023dSSven Schnelle 47934ea023dSSven Schnelle if (s->mii_bitcnt >= 16 && (s->csr[9] & CSR9_MII)) { 48034ea023dSSven Schnelle if (s->mii_word & 0x8000) { 48134ea023dSSven Schnelle s->csr[9] |= CSR9_MDI; 48234ea023dSSven Schnelle } else { 48334ea023dSSven Schnelle s->csr[9] &= ~CSR9_MDI; 48434ea023dSSven Schnelle } 48534ea023dSSven Schnelle } 48634ea023dSSven Schnelle 48734ea023dSSven Schnelle if (s->mii_word == 0xffffffff) { 48834ea023dSSven Schnelle s->mii_bitcnt = 0; 48934ea023dSSven Schnelle } else if (s->mii_bitcnt == 16) { 49034ea023dSSven Schnelle op = (s->mii_word >> 12) & 0x0f; 49134ea023dSSven Schnelle phy = (s->mii_word >> 7) & 0x1f; 49234ea023dSSven Schnelle reg = (s->mii_word >> 2) & 0x1f; 49334ea023dSSven Schnelle 49434ea023dSSven Schnelle if (op == 6) { 49534ea023dSSven Schnelle s->mii_word = tulip_mii_read(s, phy, reg); 49634ea023dSSven Schnelle } 49734ea023dSSven Schnelle } else if (s->mii_bitcnt == 32) { 49834ea023dSSven Schnelle op = (s->mii_word >> 28) & 0x0f; 49934ea023dSSven Schnelle phy = (s->mii_word >> 23) & 0x1f; 50034ea023dSSven Schnelle reg = (s->mii_word >> 18) & 0x1f; 50134ea023dSSven Schnelle data = s->mii_word & 0xffff; 50234ea023dSSven Schnelle 50334ea023dSSven Schnelle if (op == 5) { 50434ea023dSSven Schnelle tulip_mii_write(s, phy, reg, data); 50534ea023dSSven Schnelle } 50634ea023dSSven Schnelle } 50734ea023dSSven Schnelle } 50834ea023dSSven Schnelle 50934ea023dSSven Schnelle static uint32_t tulip_csr9_read(TULIPState *s) 51034ea023dSSven Schnelle { 51134ea023dSSven Schnelle if (s->csr[9] & CSR9_SR) { 51234ea023dSSven Schnelle if (eeprom93xx_read(s->eeprom)) { 51334ea023dSSven Schnelle s->csr[9] |= CSR9_SR_DO; 51434ea023dSSven Schnelle } else { 51534ea023dSSven Schnelle s->csr[9] &= ~CSR9_SR_DO; 51634ea023dSSven Schnelle } 51734ea023dSSven Schnelle } 51834ea023dSSven Schnelle 51934ea023dSSven Schnelle tulip_mii(s); 52034ea023dSSven Schnelle return s->csr[9]; 52134ea023dSSven Schnelle } 52234ea023dSSven Schnelle 52334ea023dSSven Schnelle static void tulip_update_ts(TULIPState *s, int state) 52434ea023dSSven Schnelle { 52534ea023dSSven Schnelle s->csr[5] &= ~(CSR5_TS_MASK << CSR5_TS_SHIFT); 52634ea023dSSven Schnelle s->csr[5] |= (state & CSR5_TS_MASK) << CSR5_TS_SHIFT; 52734ea023dSSven Schnelle trace_tulip_tx_state(tulip_tx_state_name(state)); 52834ea023dSSven Schnelle } 52934ea023dSSven Schnelle 53034ea023dSSven Schnelle static uint64_t tulip_read(void *opaque, hwaddr addr, 53134ea023dSSven Schnelle unsigned size) 53234ea023dSSven Schnelle { 53334ea023dSSven Schnelle TULIPState *s = opaque; 53434ea023dSSven Schnelle uint64_t data = 0; 53534ea023dSSven Schnelle 53634ea023dSSven Schnelle switch (addr) { 53734ea023dSSven Schnelle case CSR(9): 53834ea023dSSven Schnelle data = tulip_csr9_read(s); 53934ea023dSSven Schnelle break; 54034ea023dSSven Schnelle 54134ea023dSSven Schnelle case CSR(12): 54234ea023dSSven Schnelle /* Fake autocompletion complete until we have PHY emulation */ 54334ea023dSSven Schnelle data = 5 << CSR12_ANS_SHIFT; 54434ea023dSSven Schnelle break; 54534ea023dSSven Schnelle 54634ea023dSSven Schnelle default: 54734ea023dSSven Schnelle if (addr & 7) { 54834ea023dSSven Schnelle qemu_log_mask(LOG_GUEST_ERROR, "%s: read access at unknown address" 54934ea023dSSven Schnelle " 0x%"PRIx64"\n", __func__, addr); 55034ea023dSSven Schnelle } else { 55134ea023dSSven Schnelle data = s->csr[addr >> 3]; 55234ea023dSSven Schnelle } 55334ea023dSSven Schnelle break; 55434ea023dSSven Schnelle } 55534ea023dSSven Schnelle trace_tulip_reg_read(addr, tulip_reg_name(addr), size, data); 55634ea023dSSven Schnelle return data; 55734ea023dSSven Schnelle } 55834ea023dSSven Schnelle 55934ea023dSSven Schnelle static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc) 56034ea023dSSven Schnelle { 56134ea023dSSven Schnelle if (s->tx_frame_len) { 56234ea023dSSven Schnelle if ((s->csr[6] >> CSR6_OM_SHIFT) & CSR6_OM_MASK) { 56334ea023dSSven Schnelle /* Internal or external Loopback */ 56434ea023dSSven Schnelle tulip_receive(s, s->tx_frame, s->tx_frame_len); 5658ffb7265SPrasad J Pandit } else if (s->tx_frame_len <= sizeof(s->tx_frame)) { 56634ea023dSSven Schnelle qemu_send_packet(qemu_get_queue(s->nic), 56734ea023dSSven Schnelle s->tx_frame, s->tx_frame_len); 56834ea023dSSven Schnelle } 56934ea023dSSven Schnelle } 57034ea023dSSven Schnelle 57134ea023dSSven Schnelle if (desc->control & TDES1_IC) { 57234ea023dSSven Schnelle s->csr[5] |= CSR5_TI; 57334ea023dSSven Schnelle tulip_update_int(s); 57434ea023dSSven Schnelle } 57534ea023dSSven Schnelle } 57634ea023dSSven Schnelle 5778ffb7265SPrasad J Pandit static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc) 57834ea023dSSven Schnelle { 57934ea023dSSven Schnelle int len1 = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK; 58034ea023dSSven Schnelle int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK; 58134ea023dSSven Schnelle 5828ffb7265SPrasad J Pandit if (s->tx_frame_len + len1 > sizeof(s->tx_frame)) { 58397d7fb5aSPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR, 58497d7fb5aSPhilippe Mathieu-Daudé "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n", 58597d7fb5aSPhilippe Mathieu-Daudé __func__, s->tx_frame_len, len1, sizeof(s->tx_frame)); 5868ffb7265SPrasad J Pandit return -1; 5878ffb7265SPrasad J Pandit } 58834ea023dSSven Schnelle if (len1) { 58934ea023dSSven Schnelle pci_dma_read(&s->dev, desc->buf_addr1, 59034ea023dSSven Schnelle s->tx_frame + s->tx_frame_len, len1); 59134ea023dSSven Schnelle s->tx_frame_len += len1; 59234ea023dSSven Schnelle } 59334ea023dSSven Schnelle 5948ffb7265SPrasad J Pandit if (s->tx_frame_len + len2 > sizeof(s->tx_frame)) { 59597d7fb5aSPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR, 59697d7fb5aSPhilippe Mathieu-Daudé "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n", 59797d7fb5aSPhilippe Mathieu-Daudé __func__, s->tx_frame_len, len2, sizeof(s->tx_frame)); 5988ffb7265SPrasad J Pandit return -1; 5998ffb7265SPrasad J Pandit } 60034ea023dSSven Schnelle if (len2) { 60134ea023dSSven Schnelle pci_dma_read(&s->dev, desc->buf_addr2, 60234ea023dSSven Schnelle s->tx_frame + s->tx_frame_len, len2); 60334ea023dSSven Schnelle s->tx_frame_len += len2; 60434ea023dSSven Schnelle } 60534ea023dSSven Schnelle desc->status = (len1 + len2) ? 0 : 0x7fffffff; 6068ffb7265SPrasad J Pandit 6078ffb7265SPrasad J Pandit return 0; 60834ea023dSSven Schnelle } 60934ea023dSSven Schnelle 61034ea023dSSven Schnelle static void tulip_setup_filter_addr(TULIPState *s, uint8_t *buf, int n) 61134ea023dSSven Schnelle { 61234ea023dSSven Schnelle int offset = n * 12; 61334ea023dSSven Schnelle 61434ea023dSSven Schnelle s->filter[n][0] = buf[offset]; 61534ea023dSSven Schnelle s->filter[n][1] = buf[offset + 1]; 61634ea023dSSven Schnelle 61734ea023dSSven Schnelle s->filter[n][2] = buf[offset + 4]; 61834ea023dSSven Schnelle s->filter[n][3] = buf[offset + 5]; 61934ea023dSSven Schnelle 62034ea023dSSven Schnelle s->filter[n][4] = buf[offset + 8]; 62134ea023dSSven Schnelle s->filter[n][5] = buf[offset + 9]; 62234ea023dSSven Schnelle 62334ea023dSSven Schnelle trace_tulip_setup_filter(n, s->filter[n][5], s->filter[n][4], 62434ea023dSSven Schnelle s->filter[n][3], s->filter[n][2], s->filter[n][1], s->filter[n][0]); 62534ea023dSSven Schnelle } 62634ea023dSSven Schnelle 62734ea023dSSven Schnelle static void tulip_setup_frame(TULIPState *s, 62834ea023dSSven Schnelle struct tulip_descriptor *desc) 62934ea023dSSven Schnelle { 63034ea023dSSven Schnelle uint8_t buf[4096]; 63134ea023dSSven Schnelle int len = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK; 63234ea023dSSven Schnelle int i; 63334ea023dSSven Schnelle 63434ea023dSSven Schnelle trace_tulip_setup_frame(); 63534ea023dSSven Schnelle 63634ea023dSSven Schnelle if (len == 192) { 63734ea023dSSven Schnelle pci_dma_read(&s->dev, desc->buf_addr1, buf, len); 63834ea023dSSven Schnelle for (i = 0; i < 16; i++) { 63934ea023dSSven Schnelle tulip_setup_filter_addr(s, buf, i); 64034ea023dSSven Schnelle } 64134ea023dSSven Schnelle } 64234ea023dSSven Schnelle 64334ea023dSSven Schnelle desc->status = 0x7fffffff; 64434ea023dSSven Schnelle 64534ea023dSSven Schnelle if (desc->control & TDES1_IC) { 64634ea023dSSven Schnelle s->csr[5] |= CSR5_TI; 64734ea023dSSven Schnelle tulip_update_int(s); 64834ea023dSSven Schnelle } 64934ea023dSSven Schnelle } 65034ea023dSSven Schnelle 65134ea023dSSven Schnelle static void tulip_next_tx_descriptor(TULIPState *s, 65234ea023dSSven Schnelle struct tulip_descriptor *desc) 65334ea023dSSven Schnelle { 65434ea023dSSven Schnelle if (desc->control & TDES1_TER) { 65534ea023dSSven Schnelle s->current_tx_desc = s->csr[4]; 65634ea023dSSven Schnelle } else if (desc->control & TDES1_TCH) { 65734ea023dSSven Schnelle s->current_tx_desc = desc->buf_addr2; 65834ea023dSSven Schnelle } else { 65934ea023dSSven Schnelle s->current_tx_desc += sizeof(struct tulip_descriptor) + 66034ea023dSSven Schnelle (((s->csr[0] >> CSR0_DSL_SHIFT) & CSR0_DSL_MASK) << 2); 66134ea023dSSven Schnelle } 66234ea023dSSven Schnelle s->current_tx_desc &= ~3ULL; 66334ea023dSSven Schnelle } 66434ea023dSSven Schnelle 66534ea023dSSven Schnelle static uint32_t tulip_ts(TULIPState *s) 66634ea023dSSven Schnelle { 66734ea023dSSven Schnelle return (s->csr[5] >> CSR5_TS_SHIFT) & CSR5_TS_MASK; 66834ea023dSSven Schnelle } 66934ea023dSSven Schnelle 67034ea023dSSven Schnelle static void tulip_xmit_list_update(TULIPState *s) 67134ea023dSSven Schnelle { 6728ffb7265SPrasad J Pandit #define TULIP_DESC_MAX 128 6738ffb7265SPrasad J Pandit uint8_t i = 0; 67434ea023dSSven Schnelle struct tulip_descriptor desc; 67534ea023dSSven Schnelle 67634ea023dSSven Schnelle if (tulip_ts(s) != CSR5_TS_SUSPENDED) { 67734ea023dSSven Schnelle return; 67834ea023dSSven Schnelle } 67934ea023dSSven Schnelle 6808ffb7265SPrasad J Pandit for (i = 0; i < TULIP_DESC_MAX; i++) { 68134ea023dSSven Schnelle tulip_desc_read(s, s->current_tx_desc, &desc); 68234ea023dSSven Schnelle tulip_dump_tx_descriptor(s, &desc); 68334ea023dSSven Schnelle 68434ea023dSSven Schnelle if (!(desc.status & TDES0_OWN)) { 68534ea023dSSven Schnelle tulip_update_ts(s, CSR5_TS_SUSPENDED); 68634ea023dSSven Schnelle s->csr[5] |= CSR5_TU; 68734ea023dSSven Schnelle tulip_update_int(s); 68834ea023dSSven Schnelle return; 68934ea023dSSven Schnelle } 69034ea023dSSven Schnelle 69134ea023dSSven Schnelle if (desc.control & TDES1_SET) { 69234ea023dSSven Schnelle tulip_setup_frame(s, &desc); 69334ea023dSSven Schnelle } else { 69434ea023dSSven Schnelle if (desc.control & TDES1_FS) { 69534ea023dSSven Schnelle s->tx_frame_len = 0; 69634ea023dSSven Schnelle } 69734ea023dSSven Schnelle 6988ffb7265SPrasad J Pandit if (!tulip_copy_tx_buffers(s, &desc)) { 69934ea023dSSven Schnelle if (desc.control & TDES1_LS) { 70034ea023dSSven Schnelle tulip_tx(s, &desc); 70134ea023dSSven Schnelle } 70234ea023dSSven Schnelle } 7038ffb7265SPrasad J Pandit } 70434ea023dSSven Schnelle tulip_desc_write(s, s->current_tx_desc, &desc); 70534ea023dSSven Schnelle tulip_next_tx_descriptor(s, &desc); 70634ea023dSSven Schnelle } 70734ea023dSSven Schnelle } 70834ea023dSSven Schnelle 70934ea023dSSven Schnelle static void tulip_csr9_write(TULIPState *s, uint32_t old_val, 71034ea023dSSven Schnelle uint32_t new_val) 71134ea023dSSven Schnelle { 71234ea023dSSven Schnelle if (new_val & CSR9_SR) { 71334ea023dSSven Schnelle eeprom93xx_write(s->eeprom, 71434ea023dSSven Schnelle !!(new_val & CSR9_SR_CS), 71534ea023dSSven Schnelle !!(new_val & CSR9_SR_SK), 71634ea023dSSven Schnelle !!(new_val & CSR9_SR_DI)); 71734ea023dSSven Schnelle } 71834ea023dSSven Schnelle } 71934ea023dSSven Schnelle 72034ea023dSSven Schnelle static void tulip_reset(TULIPState *s) 72134ea023dSSven Schnelle { 72234ea023dSSven Schnelle trace_tulip_reset(); 72334ea023dSSven Schnelle 72434ea023dSSven Schnelle s->csr[0] = 0xfe000000; 72534ea023dSSven Schnelle s->csr[1] = 0xffffffff; 72634ea023dSSven Schnelle s->csr[2] = 0xffffffff; 72734ea023dSSven Schnelle s->csr[5] = 0xf0000000; 72834ea023dSSven Schnelle s->csr[6] = 0x32000040; 72934ea023dSSven Schnelle s->csr[7] = 0xf3fe0000; 73034ea023dSSven Schnelle s->csr[8] = 0xe0000000; 73134ea023dSSven Schnelle s->csr[9] = 0xfff483ff; 73234ea023dSSven Schnelle s->csr[11] = 0xfffe0000; 73334ea023dSSven Schnelle s->csr[12] = 0x000000c6; 73434ea023dSSven Schnelle s->csr[13] = 0xffff0000; 73534ea023dSSven Schnelle s->csr[14] = 0xffffffff; 73634ea023dSSven Schnelle s->csr[15] = 0x8ff00000; 73734ea023dSSven Schnelle } 73834ea023dSSven Schnelle 73934ea023dSSven Schnelle static void tulip_qdev_reset(DeviceState *dev) 74034ea023dSSven Schnelle { 74134ea023dSSven Schnelle PCIDevice *d = PCI_DEVICE(dev); 74234ea023dSSven Schnelle TULIPState *s = TULIP(d); 74334ea023dSSven Schnelle 74434ea023dSSven Schnelle tulip_reset(s); 74534ea023dSSven Schnelle } 74634ea023dSSven Schnelle 74734ea023dSSven Schnelle static void tulip_write(void *opaque, hwaddr addr, 74834ea023dSSven Schnelle uint64_t data, unsigned size) 74934ea023dSSven Schnelle { 75034ea023dSSven Schnelle TULIPState *s = opaque; 75134ea023dSSven Schnelle trace_tulip_reg_write(addr, tulip_reg_name(addr), size, data); 75234ea023dSSven Schnelle 75334ea023dSSven Schnelle switch (addr) { 75434ea023dSSven Schnelle case CSR(0): 75534ea023dSSven Schnelle s->csr[0] = data; 75634ea023dSSven Schnelle if (data & CSR0_SWR) { 75734ea023dSSven Schnelle tulip_reset(s); 75834ea023dSSven Schnelle tulip_update_int(s); 75934ea023dSSven Schnelle } 76034ea023dSSven Schnelle break; 76134ea023dSSven Schnelle 76234ea023dSSven Schnelle case CSR(1): 76334ea023dSSven Schnelle tulip_xmit_list_update(s); 76434ea023dSSven Schnelle break; 76534ea023dSSven Schnelle 76634ea023dSSven Schnelle case CSR(2): 76734ea023dSSven Schnelle qemu_flush_queued_packets(qemu_get_queue(s->nic)); 76834ea023dSSven Schnelle break; 76934ea023dSSven Schnelle 77034ea023dSSven Schnelle case CSR(3): 77134ea023dSSven Schnelle s->csr[3] = data & ~3ULL; 77234ea023dSSven Schnelle s->current_rx_desc = s->csr[3]; 77334ea023dSSven Schnelle qemu_flush_queued_packets(qemu_get_queue(s->nic)); 77434ea023dSSven Schnelle break; 77534ea023dSSven Schnelle 77634ea023dSSven Schnelle case CSR(4): 77734ea023dSSven Schnelle s->csr[4] = data & ~3ULL; 77834ea023dSSven Schnelle s->current_tx_desc = s->csr[4]; 77934ea023dSSven Schnelle tulip_xmit_list_update(s); 78034ea023dSSven Schnelle break; 78134ea023dSSven Schnelle 78234ea023dSSven Schnelle case CSR(5): 78334ea023dSSven Schnelle /* Status register, write clears bit */ 78434ea023dSSven Schnelle s->csr[5] &= ~(data & (CSR5_TI | CSR5_TPS | CSR5_TU | CSR5_TJT | 78534ea023dSSven Schnelle CSR5_LNP_ANC | CSR5_UNF | CSR5_RI | CSR5_RU | 78634ea023dSSven Schnelle CSR5_RPS | CSR5_RWT | CSR5_ETI | CSR5_GTE | 78734ea023dSSven Schnelle CSR5_LNF | CSR5_FBE | CSR5_ERI | CSR5_AIS | 78834ea023dSSven Schnelle CSR5_NIS | CSR5_GPI | CSR5_LC)); 78934ea023dSSven Schnelle tulip_update_int(s); 79034ea023dSSven Schnelle break; 79134ea023dSSven Schnelle 79234ea023dSSven Schnelle case CSR(6): 79334ea023dSSven Schnelle s->csr[6] = data; 79434ea023dSSven Schnelle if (s->csr[6] & CSR6_SR) { 79534ea023dSSven Schnelle tulip_update_rs(s, CSR5_RS_RUNNING_WAIT_RECEIVE); 79634ea023dSSven Schnelle qemu_flush_queued_packets(qemu_get_queue(s->nic)); 79734ea023dSSven Schnelle } else { 79834ea023dSSven Schnelle tulip_update_rs(s, CSR5_RS_STOPPED); 79934ea023dSSven Schnelle } 80034ea023dSSven Schnelle 80134ea023dSSven Schnelle if (s->csr[6] & CSR6_ST) { 80234ea023dSSven Schnelle tulip_update_ts(s, CSR5_TS_SUSPENDED); 80334ea023dSSven Schnelle tulip_xmit_list_update(s); 80434ea023dSSven Schnelle } else { 80534ea023dSSven Schnelle tulip_update_ts(s, CSR5_TS_STOPPED); 80634ea023dSSven Schnelle } 80734ea023dSSven Schnelle break; 80834ea023dSSven Schnelle 80934ea023dSSven Schnelle case CSR(7): 81034ea023dSSven Schnelle s->csr[7] = data; 81134ea023dSSven Schnelle tulip_update_int(s); 81234ea023dSSven Schnelle break; 81334ea023dSSven Schnelle 81434ea023dSSven Schnelle case CSR(8): 81534ea023dSSven Schnelle s->csr[9] = data; 81634ea023dSSven Schnelle break; 81734ea023dSSven Schnelle 81834ea023dSSven Schnelle case CSR(9): 81934ea023dSSven Schnelle tulip_csr9_write(s, s->csr[9], data); 82034ea023dSSven Schnelle /* don't clear MII read data */ 82134ea023dSSven Schnelle s->csr[9] &= CSR9_MDI; 82234ea023dSSven Schnelle s->csr[9] |= (data & ~CSR9_MDI); 82334ea023dSSven Schnelle tulip_mii(s); 82434ea023dSSven Schnelle s->old_csr9 = s->csr[9]; 82534ea023dSSven Schnelle break; 82634ea023dSSven Schnelle 82734ea023dSSven Schnelle case CSR(10): 82834ea023dSSven Schnelle s->csr[10] = data; 82934ea023dSSven Schnelle break; 83034ea023dSSven Schnelle 83134ea023dSSven Schnelle case CSR(11): 83234ea023dSSven Schnelle s->csr[11] = data; 83334ea023dSSven Schnelle break; 83434ea023dSSven Schnelle 83534ea023dSSven Schnelle case CSR(12): 83634ea023dSSven Schnelle /* SIA Status register, some bits are cleared by writing 1 */ 83734ea023dSSven Schnelle s->csr[12] &= ~(data & (CSR12_MRA | CSR12_TRA | CSR12_ARA)); 83834ea023dSSven Schnelle break; 83934ea023dSSven Schnelle 84034ea023dSSven Schnelle case CSR(13): 84134ea023dSSven Schnelle s->csr[13] = data; 84234ea023dSSven Schnelle break; 84334ea023dSSven Schnelle 84434ea023dSSven Schnelle case CSR(14): 84534ea023dSSven Schnelle s->csr[14] = data; 84634ea023dSSven Schnelle break; 84734ea023dSSven Schnelle 84834ea023dSSven Schnelle case CSR(15): 84934ea023dSSven Schnelle s->csr[15] = data; 85034ea023dSSven Schnelle break; 85134ea023dSSven Schnelle 85234ea023dSSven Schnelle default: 85334ea023dSSven Schnelle qemu_log_mask(LOG_GUEST_ERROR, "%s: write to CSR at unknown address " 85434ea023dSSven Schnelle "0x%"PRIx64"\n", __func__, addr); 85534ea023dSSven Schnelle break; 85634ea023dSSven Schnelle } 85734ea023dSSven Schnelle } 85834ea023dSSven Schnelle 85934ea023dSSven Schnelle static const MemoryRegionOps tulip_ops = { 86034ea023dSSven Schnelle .read = tulip_read, 86134ea023dSSven Schnelle .write = tulip_write, 86234ea023dSSven Schnelle .endianness = DEVICE_LITTLE_ENDIAN, 86334ea023dSSven Schnelle .impl = { 86434ea023dSSven Schnelle .min_access_size = 4, 86534ea023dSSven Schnelle .max_access_size = 4, 86634ea023dSSven Schnelle }, 86734ea023dSSven Schnelle }; 86834ea023dSSven Schnelle 86934ea023dSSven Schnelle static void tulip_idblock_crc(TULIPState *s, uint16_t *srom) 87034ea023dSSven Schnelle { 87134ea023dSSven Schnelle int word, n; 87234ea023dSSven Schnelle int bit; 87334ea023dSSven Schnelle unsigned char bitval, crc; 87434ea023dSSven Schnelle const int len = 9; 87534ea023dSSven Schnelle n = 0; 87634ea023dSSven Schnelle crc = -1; 87734ea023dSSven Schnelle 87834ea023dSSven Schnelle for (word = 0; word < len; word++) { 87934ea023dSSven Schnelle for (bit = 15; bit >= 0; bit--) { 88034ea023dSSven Schnelle if ((word == (len - 1)) && (bit == 7)) { 88134ea023dSSven Schnelle /* 88234ea023dSSven Schnelle * Insert the correct CRC result into input data stream 88334ea023dSSven Schnelle * in place. 88434ea023dSSven Schnelle */ 88534ea023dSSven Schnelle srom[len - 1] = (srom[len - 1] & 0xff00) | (unsigned short)crc; 88634ea023dSSven Schnelle break; 88734ea023dSSven Schnelle } 88834ea023dSSven Schnelle n++; 88934ea023dSSven Schnelle bitval = ((srom[word] >> bit) & 1) ^ ((crc >> 7) & 1); 89034ea023dSSven Schnelle crc = crc << 1; 89134ea023dSSven Schnelle if (bitval == 1) { 89234ea023dSSven Schnelle crc ^= 6; 89334ea023dSSven Schnelle crc |= 0x01; 89434ea023dSSven Schnelle } 89534ea023dSSven Schnelle } 89634ea023dSSven Schnelle } 89734ea023dSSven Schnelle } 89834ea023dSSven Schnelle 89934ea023dSSven Schnelle static uint16_t tulip_srom_crc(TULIPState *s, uint8_t *eeprom, size_t len) 90034ea023dSSven Schnelle { 90134ea023dSSven Schnelle unsigned long crc = 0xffffffff; 90234ea023dSSven Schnelle unsigned long flippedcrc = 0; 90334ea023dSSven Schnelle unsigned char currentbyte; 90434ea023dSSven Schnelle unsigned int msb, bit, i; 90534ea023dSSven Schnelle 90634ea023dSSven Schnelle for (i = 0; i < len; i++) { 90734ea023dSSven Schnelle currentbyte = eeprom[i]; 90834ea023dSSven Schnelle for (bit = 0; bit < 8; bit++) { 90934ea023dSSven Schnelle msb = (crc >> 31) & 1; 91034ea023dSSven Schnelle crc <<= 1; 91134ea023dSSven Schnelle if (msb ^ (currentbyte & 1)) { 91234ea023dSSven Schnelle crc ^= 0x04c11db6; 91334ea023dSSven Schnelle crc |= 0x00000001; 91434ea023dSSven Schnelle } 91534ea023dSSven Schnelle currentbyte >>= 1; 91634ea023dSSven Schnelle } 91734ea023dSSven Schnelle } 91834ea023dSSven Schnelle 91934ea023dSSven Schnelle for (i = 0; i < 32; i++) { 92034ea023dSSven Schnelle flippedcrc <<= 1; 92134ea023dSSven Schnelle bit = crc & 1; 92234ea023dSSven Schnelle crc >>= 1; 92334ea023dSSven Schnelle flippedcrc += bit; 92434ea023dSSven Schnelle } 92534ea023dSSven Schnelle return (flippedcrc ^ 0xffffffff) & 0xffff; 92634ea023dSSven Schnelle } 92734ea023dSSven Schnelle 92834ea023dSSven Schnelle static const uint8_t eeprom_default[128] = { 92934ea023dSSven Schnelle 0x3c, 0x10, 0x4f, 0x10, 0x00, 0x00, 0x00, 0x00, 93034ea023dSSven Schnelle 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93134ea023dSSven Schnelle 0x56, 0x08, 0x04, 0x01, 0x00, 0x80, 0x48, 0xb3, 93234ea023dSSven Schnelle 0x0e, 0xa7, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x08, 93334ea023dSSven Schnelle 0x01, 0x8d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x78, 93434ea023dSSven Schnelle 0xe0, 0x01, 0x00, 0x50, 0x00, 0x18, 0x00, 0x00, 93534ea023dSSven Schnelle 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93634ea023dSSven Schnelle 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93734ea023dSSven Schnelle 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93834ea023dSSven Schnelle 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 93934ea023dSSven Schnelle 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 94034ea023dSSven Schnelle 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x6b, 94134ea023dSSven Schnelle 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 94234ea023dSSven Schnelle 0x48, 0xb3, 0x0e, 0xa7, 0x40, 0x00, 0x00, 0x00, 94334ea023dSSven Schnelle 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 94434ea023dSSven Schnelle 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 94534ea023dSSven Schnelle }; 94634ea023dSSven Schnelle 94734ea023dSSven Schnelle static void tulip_fill_eeprom(TULIPState *s) 94834ea023dSSven Schnelle { 94934ea023dSSven Schnelle uint16_t *eeprom = eeprom93xx_data(s->eeprom); 95034ea023dSSven Schnelle memcpy(eeprom, eeprom_default, 128); 95134ea023dSSven Schnelle 95234ea023dSSven Schnelle /* patch in our mac address */ 95334ea023dSSven Schnelle eeprom[10] = cpu_to_le16(s->c.macaddr.a[0] | (s->c.macaddr.a[1] << 8)); 95434ea023dSSven Schnelle eeprom[11] = cpu_to_le16(s->c.macaddr.a[2] | (s->c.macaddr.a[3] << 8)); 95534ea023dSSven Schnelle eeprom[12] = cpu_to_le16(s->c.macaddr.a[4] | (s->c.macaddr.a[5] << 8)); 95634ea023dSSven Schnelle tulip_idblock_crc(s, eeprom); 95734ea023dSSven Schnelle eeprom[63] = cpu_to_le16(tulip_srom_crc(s, (uint8_t *)eeprom, 126)); 95834ea023dSSven Schnelle } 95934ea023dSSven Schnelle 96034ea023dSSven Schnelle static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp) 96134ea023dSSven Schnelle { 96234ea023dSSven Schnelle TULIPState *s = DO_UPCAST(TULIPState, dev, pci_dev); 96334ea023dSSven Schnelle uint8_t *pci_conf; 96434ea023dSSven Schnelle 96534ea023dSSven Schnelle pci_conf = s->dev.config; 96634ea023dSSven Schnelle pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */ 96734ea023dSSven Schnelle 96834ea023dSSven Schnelle s->eeprom = eeprom93xx_new(&pci_dev->qdev, 64); 96934ea023dSSven Schnelle tulip_fill_eeprom(s); 97034ea023dSSven Schnelle 97134ea023dSSven Schnelle memory_region_init_io(&s->io, OBJECT(&s->dev), &tulip_ops, s, 97234ea023dSSven Schnelle "tulip-io", 128); 97334ea023dSSven Schnelle 97434ea023dSSven Schnelle memory_region_init_io(&s->memory, OBJECT(&s->dev), &tulip_ops, s, 97534ea023dSSven Schnelle "tulip-mem", 128); 97634ea023dSSven Schnelle 97734ea023dSSven Schnelle pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io); 97834ea023dSSven Schnelle pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->memory); 97934ea023dSSven Schnelle 98034ea023dSSven Schnelle s->irq = pci_allocate_irq(&s->dev); 98134ea023dSSven Schnelle 98234ea023dSSven Schnelle qemu_macaddr_default_if_unset(&s->c.macaddr); 98334ea023dSSven Schnelle 98434ea023dSSven Schnelle s->nic = qemu_new_nic(&net_tulip_info, &s->c, 98534ea023dSSven Schnelle object_get_typename(OBJECT(pci_dev)), 98634ea023dSSven Schnelle pci_dev->qdev.id, s); 98734ea023dSSven Schnelle qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a); 98834ea023dSSven Schnelle } 98934ea023dSSven Schnelle 99034ea023dSSven Schnelle static void pci_tulip_exit(PCIDevice *pci_dev) 99134ea023dSSven Schnelle { 99234ea023dSSven Schnelle TULIPState *s = DO_UPCAST(TULIPState, dev, pci_dev); 99334ea023dSSven Schnelle 99434ea023dSSven Schnelle qemu_del_nic(s->nic); 99534ea023dSSven Schnelle qemu_free_irq(s->irq); 99634ea023dSSven Schnelle eeprom93xx_free(&pci_dev->qdev, s->eeprom); 99734ea023dSSven Schnelle } 99834ea023dSSven Schnelle 99934ea023dSSven Schnelle static void tulip_instance_init(Object *obj) 100034ea023dSSven Schnelle { 100134ea023dSSven Schnelle PCIDevice *pci_dev = PCI_DEVICE(obj); 100234ea023dSSven Schnelle TULIPState *d = DO_UPCAST(TULIPState, dev, pci_dev); 100334ea023dSSven Schnelle 100434ea023dSSven Schnelle device_add_bootindex_property(obj, &d->c.bootindex, 100534ea023dSSven Schnelle "bootindex", "/ethernet-phy@0", 100640c2281cSMarkus Armbruster &pci_dev->qdev); 100734ea023dSSven Schnelle } 100834ea023dSSven Schnelle 100934ea023dSSven Schnelle static Property tulip_properties[] = { 101034ea023dSSven Schnelle DEFINE_NIC_PROPERTIES(TULIPState, c), 101134ea023dSSven Schnelle DEFINE_PROP_END_OF_LIST(), 101234ea023dSSven Schnelle }; 101334ea023dSSven Schnelle 101434ea023dSSven Schnelle static void tulip_class_init(ObjectClass *klass, void *data) 101534ea023dSSven Schnelle { 101634ea023dSSven Schnelle DeviceClass *dc = DEVICE_CLASS(klass); 101734ea023dSSven Schnelle PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 101834ea023dSSven Schnelle 101934ea023dSSven Schnelle k->realize = pci_tulip_realize; 102034ea023dSSven Schnelle k->exit = pci_tulip_exit; 102134ea023dSSven Schnelle k->vendor_id = PCI_VENDOR_ID_DEC; 102234ea023dSSven Schnelle k->device_id = PCI_DEVICE_ID_DEC_21143; 102334ea023dSSven Schnelle k->subsystem_vendor_id = 0x103c; 102434ea023dSSven Schnelle k->subsystem_id = 0x104f; 102534ea023dSSven Schnelle k->class_id = PCI_CLASS_NETWORK_ETHERNET; 102634ea023dSSven Schnelle dc->vmsd = &vmstate_pci_tulip; 10274f67d30bSMarc-André Lureau device_class_set_props(dc, tulip_properties); 102834ea023dSSven Schnelle dc->reset = tulip_qdev_reset; 102934ea023dSSven Schnelle set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); 103034ea023dSSven Schnelle } 103134ea023dSSven Schnelle 103234ea023dSSven Schnelle static const TypeInfo tulip_info = { 103334ea023dSSven Schnelle .name = TYPE_TULIP, 103434ea023dSSven Schnelle .parent = TYPE_PCI_DEVICE, 103534ea023dSSven Schnelle .instance_size = sizeof(TULIPState), 103634ea023dSSven Schnelle .class_init = tulip_class_init, 103734ea023dSSven Schnelle .instance_init = tulip_instance_init, 103834ea023dSSven Schnelle .interfaces = (InterfaceInfo[]) { 103934ea023dSSven Schnelle { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 104034ea023dSSven Schnelle { }, 104134ea023dSSven Schnelle }, 104234ea023dSSven Schnelle }; 104334ea023dSSven Schnelle 104434ea023dSSven Schnelle static void tulip_register_types(void) 104534ea023dSSven Schnelle { 104634ea023dSSven Schnelle type_register_static(&tulip_info); 104734ea023dSSven Schnelle } 104834ea023dSSven Schnelle 104934ea023dSSven Schnelle type_init(tulip_register_types) 1050