/* * These read/write handlers of the OPB address space should be common * with the P9 LPC Controller which uses direct MMIOs. * * TODO: rework to use address_space_stq() and address_space_ldq() * instead. */ static bool opb_read(PnvLpcController *lpc, uint32_t addr, uint8_t *data, int sz) { bool success; /* XXX Handle access size limits and FW read caching here */ success = !address_space_rw(&lpc->opb_as, addr, MEMTXATTRS_UNSPECIFIED, data, sz, false); return success; }
static void dp8393x_do_load_cam(dp8393xState *s) { uint16_t data[8]; int width, size; uint16_t index = 0; width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; size = sizeof(uint16_t) * 4 * width; while (s->regs[SONIC_CDC] & 0x1f) { /* Fill current entry */ address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->cam[index][0] = data[1 * width] & 0xff; s->cam[index][1] = data[1 * width] >> 8; s->cam[index][2] = data[2 * width] & 0xff; s->cam[index][3] = data[2 * width] >> 8; s->cam[index][4] = data[3 * width] & 0xff; s->cam[index][5] = data[3 * width] >> 8; DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index, s->cam[index][0], s->cam[index][1], s->cam[index][2], s->cam[index][3], s->cam[index][4], s->cam[index][5]); /* Move to next entry */ s->regs[SONIC_CDC]--; s->regs[SONIC_CDP] += size; index++; } /* Read CAM enable */ address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP], MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_CE] = data[0 * width]; DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]); /* Done */ s->regs[SONIC_CR] &= ~SONIC_CR_LCAM; s->regs[SONIC_ISR] |= SONIC_ISR_LCD; dp8393x_update_irq(s); }
static void do_dma_memory_set(AddressSpace *as, dma_addr_t addr, uint8_t c, dma_addr_t len) { #define FILLBUF_SIZE 512 uint8_t fillbuf[FILLBUF_SIZE]; int l; memset(fillbuf, c, FILLBUF_SIZE); while (len > 0) { l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE; address_space_rw(as, addr, fillbuf, l, true); len -= l; addr += l; } }
int dma_memory_set(AddressSpace *as, dma_addr_t addr, uint8_t c, dma_addr_t len) { dma_barrier(as, DMA_DIRECTION_FROM_DEVICE); #define FILLBUF_SIZE 512 uint8_t fillbuf[FILLBUF_SIZE]; int l; bool error = false; memset(fillbuf, c, FILLBUF_SIZE); while (len > 0) { l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE; error |= address_space_rw(as, addr, fillbuf, l, true); len -= l; addr += l; } return error; }
static void dp8393x_do_read_rra(dp8393xState *s) { uint16_t data[8]; int width, size; /* Read memory */ width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; size = sizeof(uint16_t) * 4 * width; address_space_rw(&s->as, (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP], MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); /* Update SONIC registers */ s->regs[SONIC_CRBA0] = data[0 * width]; s->regs[SONIC_CRBA1] = data[1 * width]; s->regs[SONIC_RBWC0] = data[2 * width]; s->regs[SONIC_RBWC1] = data[3 * width]; DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n", s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1], s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]); /* Go to next entry */ s->regs[SONIC_RRP] += size; /* Handle wrap */ if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) { s->regs[SONIC_RRP] = s->regs[SONIC_RSA]; } /* Check resource exhaustion */ if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP]) { s->regs[SONIC_ISR] |= SONIC_ISR_RBE; dp8393x_update_irq(s); } /* Done */ s->regs[SONIC_CR] &= ~SONIC_CR_RRRA; }
int iommu_dma_memory_rw(DMAContext *dma, dma_addr_t addr, void *buf, dma_addr_t len, DMADirection dir) { hwaddr paddr, plen; int err; #ifdef DEBUG_IOMMU fprintf(stderr, "dma_memory_rw context=%p addr=0x" DMA_ADDR_FMT " len=0x" DMA_ADDR_FMT " dir=%d\n", dma, addr, len, dir); #endif while (len) { err = dma->translate(dma, addr, &paddr, &plen, dir); if (err) { /* * In case of failure on reads from the guest, we clean the * destination buffer so that a device that doesn't test * for errors will not expose qemu internal memory. */ memset(buf, 0, len); return -1; } /* The translation might be valid for larger regions. */ if (plen > len) { plen = len; } address_space_rw(dma->as, paddr, buf, plen, dir == DMA_DIRECTION_FROM_DEVICE); len -= plen; addr += plen; buf += plen; } return 0; }
static int hax_handle_io(CPUArchState *env, uint32_t df, uint16_t port, int direction, int size, int count, void *buffer) { uint8_t *ptr; int i; MemTxAttrs attrs = { 0 }; if (!df) { ptr = (uint8_t *) buffer; } else { ptr = buffer + size * count - size; } for (i = 0; i < count; i++) { address_space_rw(&address_space_io, port, attrs, ptr, size, direction == HAX_EXIT_IO_OUT); if (!df) { ptr += size; } else { ptr -= size; } } return 0; }
AUXReply aux_request(AUXBus *bus, AUXCommand cmd, uint32_t address, uint8_t len, uint8_t *data) { AUXReply ret = AUX_NACK; I2CBus *i2c_bus = aux_get_i2c_bus(bus); size_t i; bool is_write = false; DPRINTF("request at address 0x%" PRIX32 ", command %u, len %u\n", address, cmd, len); switch (cmd) { /* * Forward the request on the AUX bus.. */ case WRITE_AUX: case READ_AUX: is_write = cmd == READ_AUX ? false : true; for (i = 0; i < len; i++) { if (!address_space_rw(&bus->aux_addr_space, address++, MEMTXATTRS_UNSPECIFIED, data++, 1, is_write)) { ret = AUX_I2C_ACK; } else { ret = AUX_NACK; break; } } break; /* * Classic I2C transactions.. */ case READ_I2C: case WRITE_I2C: is_write = cmd == READ_I2C ? false : true; if (i2c_bus_busy(i2c_bus)) { i2c_end_transfer(i2c_bus); } if (i2c_start_transfer(i2c_bus, address, is_write)) { ret = AUX_I2C_NACK; break; } ret = AUX_I2C_ACK; while (len > 0) { if (i2c_send_recv(i2c_bus, data++, is_write) < 0) { ret = AUX_I2C_NACK; break; } len--; } i2c_end_transfer(i2c_bus); break; /* * I2C MOT transactions. * * Here we send a start when: * - We didn't start transaction yet. * - We had a READ and we do a WRITE. * - We changed the address. */ case WRITE_I2C_MOT: case READ_I2C_MOT: is_write = cmd == READ_I2C_MOT ? false : true; ret = AUX_I2C_NACK; if (!i2c_bus_busy(i2c_bus)) { /* * No transactions started.. */ if (i2c_start_transfer(i2c_bus, address, is_write)) { break; } } else if ((address != bus->last_i2c_address) || (bus->last_transaction != cmd)) { /* * Transaction started but we need to restart.. */ i2c_end_transfer(i2c_bus); if (i2c_start_transfer(i2c_bus, address, is_write)) { break; } } bus->last_transaction = cmd; bus->last_i2c_address = address; while (len > 0) { if (i2c_send_recv(i2c_bus, data++, is_write) < 0) { i2c_end_transfer(i2c_bus); break; } len--; } if (len == 0) { ret = AUX_I2C_ACK; } break; default: DPRINTF("Not implemented!\n"); return AUX_NACK; } DPRINTF("reply: %u\n", ret); return ret; }
static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf, size_t size) { dp8393xState *s = qemu_get_nic_opaque(nc); uint16_t data[10]; int packet_type; uint32_t available, address; int width, rx_len = size; uint32_t checksum; width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER | SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC); packet_type = dp8393x_receive_filter(s, buf, size); if (packet_type < 0) { DPRINTF("packet not for netcard\n"); return -1; } /* XXX: Check byte ordering */ /* Check for EOL */ if (s->regs[SONIC_LLFA] & 0x1) { /* Are we still in resource exhaustion? */ size = sizeof(uint16_t) * 1 * width; address = dp8393x_crda(s) + sizeof(uint16_t) * 5 * width; address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); if (data[0 * width] & 0x1) { /* Still EOL ; stop reception */ return -1; } else { s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; } } /* Save current position */ s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1]; s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0]; /* Calculate the ethernet checksum */ checksum = cpu_to_le32(crc32(0, buf, rx_len)); /* Put packet into RBA */ DPRINTF("Receive packet at %08x\n", dp8393x_crba(s)); address = dp8393x_crba(s); address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED, (uint8_t *)buf, rx_len, 1); address += rx_len; address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED, (uint8_t *)&checksum, 4, 1); rx_len += 4; s->regs[SONIC_CRBA1] = address >> 16; s->regs[SONIC_CRBA0] = address & 0xffff; available = dp8393x_rbwc(s); available -= rx_len / 2; s->regs[SONIC_RBWC1] = available >> 16; s->regs[SONIC_RBWC0] = available & 0xffff; /* Update status */ if (dp8393x_rbwc(s) < s->regs[SONIC_EOBC]) { s->regs[SONIC_RCR] |= SONIC_RCR_LPKT; } s->regs[SONIC_RCR] |= packet_type; s->regs[SONIC_RCR] |= SONIC_RCR_PRX; if (s->loopback_packet) { s->regs[SONIC_RCR] |= SONIC_RCR_LBK; s->loopback_packet = 0; } /* Write status to memory */ DPRINTF("Write status at %08x\n", dp8393x_crda(s)); data[0 * width] = s->regs[SONIC_RCR]; /* status */ data[1 * width] = rx_len; /* byte count */ data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */ data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */ data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */ size = sizeof(uint16_t) * 5 * width; address_space_rw(&s->as, dp8393x_crda(s), MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); /* Move to next descriptor */ size = sizeof(uint16_t) * width; address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 5 * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_LLFA] = data[0 * width]; if (s->regs[SONIC_LLFA] & 0x1) { /* EOL detected */ s->regs[SONIC_ISR] |= SONIC_ISR_RDE; } else { data[0 * width] = 0; /* in_use */ address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 6 * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1); s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX; s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff); if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) { /* Read next RRA */ dp8393x_do_read_rra(s); } } /* Done */ dp8393x_update_irq(s); return size; }
static void dp8393x_do_transmit_packets(dp8393xState *s) { NetClientState *nc = qemu_get_queue(s->nic); uint16_t data[12]; int width, size; int tx_len, len; uint16_t i; width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1; while (1) { /* Read memory */ size = sizeof(uint16_t) * 6 * width; s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA]; DPRINTF("Transmit packet at %08x\n", dp8393x_ttda(s)); address_space_rw(&s->as, dp8393x_ttda(s) + sizeof(uint16_t) * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); tx_len = 0; /* Update registers */ s->regs[SONIC_TCR] = data[0 * width] & 0xf000; s->regs[SONIC_TPS] = data[1 * width]; s->regs[SONIC_TFC] = data[2 * width]; s->regs[SONIC_TSA0] = data[3 * width]; s->regs[SONIC_TSA1] = data[4 * width]; s->regs[SONIC_TFS] = data[5 * width]; /* Handle programmable interrupt */ if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) { s->regs[SONIC_ISR] |= SONIC_ISR_PINT; } else { s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT; } for (i = 0; i < s->regs[SONIC_TFC]; ) { /* Append fragment */ len = s->regs[SONIC_TFS]; if (tx_len + len > sizeof(s->tx_buffer)) { len = sizeof(s->tx_buffer) - tx_len; } address_space_rw(&s->as, dp8393x_tsa(s), MEMTXATTRS_UNSPECIFIED, &s->tx_buffer[tx_len], len, 0); tx_len += len; i++; if (i != s->regs[SONIC_TFC]) { /* Read next fragment details */ size = sizeof(uint16_t) * 3 * width; address_space_rw(&s->as, dp8393x_ttda(s) + sizeof(uint16_t) * (4 + 3 * i) * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_TSA0] = data[0 * width]; s->regs[SONIC_TSA1] = data[1 * width]; s->regs[SONIC_TFS] = data[2 * width]; } } /* Handle Ethernet checksum */ if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) { /* Don't append FCS there, to look like slirp packets * which don't have one */ } else { /* Remove existing FCS */ tx_len -= 4; } if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) { /* Loopback */ s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; if (nc->info->can_receive(nc)) { s->loopback_packet = 1; nc->info->receive(nc, s->tx_buffer, tx_len); } } else { /* Transmit packet */ qemu_send_packet(nc, s->tx_buffer, tx_len); } s->regs[SONIC_TCR] |= SONIC_TCR_PTX; /* Write status */ data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */ size = sizeof(uint16_t) * width; address_space_rw(&s->as, dp8393x_ttda(s), MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1); if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) { /* Read footer of packet */ size = sizeof(uint16_t) * width; address_space_rw(&s->as, dp8393x_ttda(s) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width, MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0); s->regs[SONIC_CTDA] = data[0 * width] & ~0x1; if (data[0 * width] & 0x1) { /* EOL detected */ break; } } } /* Done */ s->regs[SONIC_CR] &= ~SONIC_CR_TXP; s->regs[SONIC_ISR] |= SONIC_ISR_TXDN; dp8393x_update_irq(s); }