mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'bonzini/iommu-for-anthony' into staging
# By Paolo Bonzini (12) and others # Via Paolo Bonzini * bonzini/iommu-for-anthony: (25 commits) memory: render_memory_region: factor out fr constant setters memory: as_update_topology_pass: Improve comments memory: Fix comment typo memory: give name to every AddressSpace dma: eliminate DMAContext spapr_vio: take care of creating our own AddressSpace/DMAContext pci: use memory core for iommu support dma: eliminate old-style IOMMU support spapr: use memory core for iommu support spapr: make IOMMU translation go through IOMMUTLBEntry spapr: convert TCE API to use an opaque type vfio: abort if an emulated iommu is used memory: Add iommu map/unmap notifiers memory: iommu support memory: make section size a 128-bit integer exec: reorganize mem_add to match Int128 version Revert "s390x: reduce TARGET_PHYS_ADDR_SPACE_BITS to 62" Revert "memory: limit sections in the radix tree to the actual address space size" exec: return MemoryRegion from address_space_translate exec: Implement subpage_read/write via address_space_rw ... Message-id: 1371739493-10187-1-git-send-email-pbonzini@redhat.com Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
@@ -256,8 +256,8 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
|
||||
}
|
||||
|
||||
sz = size;
|
||||
section = address_space_translate(&address_space_memory, paddr, &xlat, &sz,
|
||||
false);
|
||||
section = address_space_translate_for_iotlb(&address_space_memory, paddr,
|
||||
&xlat, &sz);
|
||||
assert(sz >= TARGET_PAGE_SIZE);
|
||||
|
||||
#if defined(DEBUG_TLB)
|
||||
|
||||
+12
-180
@@ -14,41 +14,33 @@
|
||||
|
||||
/* #define DEBUG_IOMMU */
|
||||
|
||||
static void do_dma_memory_set(AddressSpace *as,
|
||||
dma_addr_t addr, uint8_t c, dma_addr_t len)
|
||||
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;
|
||||
address_space_rw(as, addr, fillbuf, l, true);
|
||||
error |= address_space_rw(as, addr, fillbuf, l, true);
|
||||
len -= l;
|
||||
addr += l;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c, dma_addr_t len)
|
||||
{
|
||||
dma_barrier(dma, DMA_DIRECTION_FROM_DEVICE);
|
||||
|
||||
if (dma_has_iommu(dma)) {
|
||||
return iommu_dma_memory_set(dma, addr, c, len);
|
||||
}
|
||||
do_dma_memory_set(dma->as, addr, c, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint, DMAContext *dma)
|
||||
void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint, AddressSpace *as)
|
||||
{
|
||||
qsg->sg = g_malloc(alloc_hint * sizeof(ScatterGatherEntry));
|
||||
qsg->nsg = 0;
|
||||
qsg->nalloc = alloc_hint;
|
||||
qsg->size = 0;
|
||||
qsg->dma = dma;
|
||||
qsg->as = as;
|
||||
}
|
||||
|
||||
void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len)
|
||||
@@ -108,7 +100,7 @@ static void dma_bdrv_unmap(DMAAIOCB *dbs)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dbs->iov.niov; ++i) {
|
||||
dma_memory_unmap(dbs->sg->dma, dbs->iov.iov[i].iov_base,
|
||||
dma_memory_unmap(dbs->sg->as, dbs->iov.iov[i].iov_base,
|
||||
dbs->iov.iov[i].iov_len, dbs->dir,
|
||||
dbs->iov.iov[i].iov_len);
|
||||
}
|
||||
@@ -156,7 +148,7 @@ static void dma_bdrv_cb(void *opaque, int ret)
|
||||
while (dbs->sg_cur_index < dbs->sg->nsg) {
|
||||
cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
|
||||
cur_len = dbs->sg->sg[dbs->sg_cur_index].len - dbs->sg_cur_byte;
|
||||
mem = dma_memory_map(dbs->sg->dma, cur_addr, &cur_len, dbs->dir);
|
||||
mem = dma_memory_map(dbs->sg->as, cur_addr, &cur_len, dbs->dir);
|
||||
if (!mem)
|
||||
break;
|
||||
qemu_iovec_add(&dbs->iov, mem, cur_len);
|
||||
@@ -253,7 +245,7 @@ static uint64_t dma_buf_rw(uint8_t *ptr, int32_t len, QEMUSGList *sg,
|
||||
while (len > 0) {
|
||||
ScatterGatherEntry entry = sg->sg[sg_cur_index++];
|
||||
int32_t xfer = MIN(len, entry.len);
|
||||
dma_memory_rw(sg->dma, entry.base, ptr, xfer, dir);
|
||||
dma_memory_rw(sg->as, entry.base, ptr, xfer, dir);
|
||||
ptr += xfer;
|
||||
len -= xfer;
|
||||
resid -= xfer;
|
||||
@@ -277,163 +269,3 @@ void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie,
|
||||
{
|
||||
bdrv_acct_start(bs, cookie, sg->size, type);
|
||||
}
|
||||
|
||||
bool iommu_dma_memory_valid(DMAContext *dma, dma_addr_t addr, dma_addr_t len,
|
||||
DMADirection dir)
|
||||
{
|
||||
hwaddr paddr, plen;
|
||||
|
||||
#ifdef DEBUG_IOMMU
|
||||
fprintf(stderr, "dma_memory_check context=%p addr=0x" DMA_ADDR_FMT
|
||||
" len=0x" DMA_ADDR_FMT " dir=%d\n", dma, addr, len, dir);
|
||||
#endif
|
||||
|
||||
while (len) {
|
||||
if (dma->translate(dma, addr, &paddr, &plen, dir) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The translation might be valid for larger regions. */
|
||||
if (plen > len) {
|
||||
plen = len;
|
||||
}
|
||||
|
||||
if (!address_space_access_valid(dma->as, paddr, len,
|
||||
dir == DMA_DIRECTION_FROM_DEVICE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
len -= plen;
|
||||
addr += plen;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int iommu_dma_memory_set(DMAContext *dma, dma_addr_t addr, uint8_t c,
|
||||
dma_addr_t len)
|
||||
{
|
||||
hwaddr paddr, plen;
|
||||
int err;
|
||||
|
||||
#ifdef DEBUG_IOMMU
|
||||
fprintf(stderr, "dma_memory_set context=%p addr=0x" DMA_ADDR_FMT
|
||||
" len=0x" DMA_ADDR_FMT "\n", dma, addr, len);
|
||||
#endif
|
||||
|
||||
while (len) {
|
||||
err = dma->translate(dma, addr, &paddr, &plen,
|
||||
DMA_DIRECTION_FROM_DEVICE);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The translation might be valid for larger regions. */
|
||||
if (plen > len) {
|
||||
plen = len;
|
||||
}
|
||||
|
||||
do_dma_memory_set(dma->as, paddr, c, plen);
|
||||
|
||||
len -= plen;
|
||||
addr += plen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dma_context_init(DMAContext *dma, AddressSpace *as, DMATranslateFunc translate,
|
||||
DMAMapFunc map, DMAUnmapFunc unmap)
|
||||
{
|
||||
#ifdef DEBUG_IOMMU
|
||||
fprintf(stderr, "dma_context_init(%p, %p, %p, %p)\n",
|
||||
dma, translate, map, unmap);
|
||||
#endif
|
||||
dma->as = as;
|
||||
dma->translate = translate;
|
||||
dma->map = map;
|
||||
dma->unmap = unmap;
|
||||
}
|
||||
|
||||
void *iommu_dma_memory_map(DMAContext *dma, dma_addr_t addr, dma_addr_t *len,
|
||||
DMADirection dir)
|
||||
{
|
||||
int err;
|
||||
hwaddr paddr, plen;
|
||||
void *buf;
|
||||
|
||||
if (dma->map) {
|
||||
return dma->map(dma, addr, len, dir);
|
||||
}
|
||||
|
||||
plen = *len;
|
||||
err = dma->translate(dma, addr, &paddr, &plen, dir);
|
||||
if (err) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this is true, the virtual region is contiguous,
|
||||
* but the translated physical region isn't. We just
|
||||
* clamp *len, much like address_space_map() does.
|
||||
*/
|
||||
if (plen < *len) {
|
||||
*len = plen;
|
||||
}
|
||||
|
||||
buf = address_space_map(dma->as, paddr, &plen, dir == DMA_DIRECTION_FROM_DEVICE);
|
||||
*len = plen;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void iommu_dma_memory_unmap(DMAContext *dma, void *buffer, dma_addr_t len,
|
||||
DMADirection dir, dma_addr_t access_len)
|
||||
{
|
||||
if (dma->unmap) {
|
||||
dma->unmap(dma, buffer, len, dir, access_len);
|
||||
return;
|
||||
}
|
||||
|
||||
address_space_unmap(dma->as, buffer, len, dir == DMA_DIRECTION_FROM_DEVICE,
|
||||
access_len);
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, uint64_t prp1, uint64_t prp2,
|
||||
return NVME_INVALID_FIELD | NVME_DNR;
|
||||
}
|
||||
|
||||
qemu_sglist_init(qsg, num_prps, pci_dma_context(&n->parent_obj));
|
||||
pci_dma_sglist_init(qsg, &n->parent_obj, num_prps);
|
||||
qemu_sglist_add(qsg, prp1, trans_len);
|
||||
len -= trans_len;
|
||||
if (len) {
|
||||
|
||||
+1
-1
@@ -726,7 +726,7 @@ int rom_load_all(void)
|
||||
addr = rom->addr;
|
||||
addr += rom->romsize;
|
||||
section = memory_region_find(get_system_memory(), rom->addr, 1);
|
||||
rom->isrom = section.size && memory_region_is_rom(section.mr);
|
||||
rom->isrom = int128_nz(section.size) && memory_region_is_rom(section.mr);
|
||||
}
|
||||
qemu_register_reset(rom_reset, NULL);
|
||||
roms_loaded = 1;
|
||||
|
||||
@@ -1133,7 +1133,7 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
|
||||
DPRINT_TRACE("Window %u framebuffer changed: address=0x%08x, len=0x%x\n",
|
||||
win, fb_start_addr, w->fb_len);
|
||||
|
||||
if (w->mem_section.size != w->fb_len ||
|
||||
if (int128_get64(w->mem_section.size) != w->fb_len ||
|
||||
!memory_region_is_ram(w->mem_section.mr)) {
|
||||
DPRINT_ERROR("Failed to find window %u framebuffer region\n", win);
|
||||
goto error_return;
|
||||
@@ -1155,7 +1155,7 @@ static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
|
||||
|
||||
error_return:
|
||||
w->mem_section.mr = NULL;
|
||||
w->mem_section.size = 0;
|
||||
w->mem_section.size = int128_zero();
|
||||
w->host_fb_addr = NULL;
|
||||
w->fb_len = 0;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,8 @@ void framebuffer_update_display(
|
||||
src_len = src_width * rows;
|
||||
|
||||
mem_section = memory_region_find(address_space, base, src_len);
|
||||
if (mem_section.size != src_len || !memory_region_is_ram(mem_section.mr)) {
|
||||
if (int128_get64(mem_section.size) != src_len ||
|
||||
!memory_region_is_ram(mem_section.mr)) {
|
||||
return;
|
||||
}
|
||||
mem = mem_section.mr;
|
||||
|
||||
+4
-4
@@ -1074,7 +1074,7 @@ static inline const PL330InsnDesc *pl330_fetch_insn(PL330Chan *ch)
|
||||
uint8_t opcode;
|
||||
int i;
|
||||
|
||||
dma_memory_read(&dma_context_memory, ch->pc, &opcode, 1);
|
||||
dma_memory_read(&address_space_memory, ch->pc, &opcode, 1);
|
||||
for (i = 0; insn_desc[i].size; i++) {
|
||||
if ((opcode & insn_desc[i].opmask) == insn_desc[i].opcode) {
|
||||
return &insn_desc[i];
|
||||
@@ -1088,7 +1088,7 @@ static inline void pl330_exec_insn(PL330Chan *ch, const PL330InsnDesc *insn)
|
||||
uint8_t buf[PL330_INSN_MAXSIZE];
|
||||
|
||||
assert(insn->size <= PL330_INSN_MAXSIZE);
|
||||
dma_memory_read(&dma_context_memory, ch->pc, buf, insn->size);
|
||||
dma_memory_read(&address_space_memory, ch->pc, buf, insn->size);
|
||||
insn->exec(ch, buf[0], &buf[1], insn->size - 1);
|
||||
}
|
||||
|
||||
@@ -1153,7 +1153,7 @@ static int pl330_exec_cycle(PL330Chan *channel)
|
||||
if (q != NULL && q->len <= pl330_fifo_num_free(&s->fifo)) {
|
||||
int len = q->len - (q->addr & (q->len - 1));
|
||||
|
||||
dma_memory_read(&dma_context_memory, q->addr, buf, len);
|
||||
dma_memory_read(&address_space_memory, q->addr, buf, len);
|
||||
if (PL330_ERR_DEBUG > 1) {
|
||||
DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
|
||||
q->addr, len);
|
||||
@@ -1185,7 +1185,7 @@ static int pl330_exec_cycle(PL330Chan *channel)
|
||||
fifo_res = pl330_fifo_get(&s->fifo, buf, len, q->tag);
|
||||
}
|
||||
if (fifo_res == PL330_FIFO_OK || q->z) {
|
||||
dma_memory_write(&dma_context_memory, q->addr, buf, len);
|
||||
dma_memory_write(&address_space_memory, q->addr, buf, len);
|
||||
if (PL330_ERR_DEBUG > 1) {
|
||||
DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
|
||||
q->addr, len);
|
||||
|
||||
+9
-9
@@ -597,7 +597,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
||||
if (!cmd_fis) {
|
||||
/* map cmd_fis */
|
||||
uint64_t tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr);
|
||||
cmd_fis = dma_memory_map(ad->hba->dma, tbl_addr, &cmd_len,
|
||||
cmd_fis = dma_memory_map(ad->hba->as, tbl_addr, &cmd_len,
|
||||
DMA_DIRECTION_TO_DEVICE);
|
||||
cmd_mapped = 1;
|
||||
}
|
||||
@@ -630,7 +630,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
||||
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
|
||||
|
||||
if (cmd_mapped) {
|
||||
dma_memory_unmap(ad->hba->dma, cmd_fis, cmd_len,
|
||||
dma_memory_unmap(ad->hba->as, cmd_fis, cmd_len,
|
||||
DMA_DIRECTION_TO_DEVICE, cmd_len);
|
||||
}
|
||||
}
|
||||
@@ -657,7 +657,7 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
|
||||
}
|
||||
|
||||
/* map PRDT */
|
||||
if (!(prdt = dma_memory_map(ad->hba->dma, prdt_addr, &prdt_len,
|
||||
if (!(prdt = dma_memory_map(ad->hba->as, prdt_addr, &prdt_len,
|
||||
DMA_DIRECTION_TO_DEVICE))){
|
||||
DPRINTF(ad->port_no, "map failed\n");
|
||||
return -1;
|
||||
@@ -691,7 +691,7 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
|
||||
goto out;
|
||||
}
|
||||
|
||||
qemu_sglist_init(sglist, (sglist_alloc_hint - off_idx), ad->hba->dma);
|
||||
qemu_sglist_init(sglist, (sglist_alloc_hint - off_idx), ad->hba->as);
|
||||
qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos),
|
||||
le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);
|
||||
|
||||
@@ -703,7 +703,7 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
|
||||
}
|
||||
|
||||
out:
|
||||
dma_memory_unmap(ad->hba->dma, prdt, prdt_len,
|
||||
dma_memory_unmap(ad->hba->as, prdt, prdt_len,
|
||||
DMA_DIRECTION_TO_DEVICE, prdt_len);
|
||||
return r;
|
||||
}
|
||||
@@ -836,7 +836,7 @@ static int handle_cmd(AHCIState *s, int port, int slot)
|
||||
tbl_addr = le64_to_cpu(cmd->tbl_addr);
|
||||
|
||||
cmd_len = 0x80;
|
||||
cmd_fis = dma_memory_map(s->dma, tbl_addr, &cmd_len,
|
||||
cmd_fis = dma_memory_map(s->as, tbl_addr, &cmd_len,
|
||||
DMA_DIRECTION_FROM_DEVICE);
|
||||
|
||||
if (!cmd_fis) {
|
||||
@@ -963,7 +963,7 @@ static int handle_cmd(AHCIState *s, int port, int slot)
|
||||
}
|
||||
|
||||
out:
|
||||
dma_memory_unmap(s->dma, cmd_fis, cmd_len, DMA_DIRECTION_FROM_DEVICE,
|
||||
dma_memory_unmap(s->as, cmd_fis, cmd_len, DMA_DIRECTION_FROM_DEVICE,
|
||||
cmd_len);
|
||||
|
||||
if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
|
||||
@@ -1145,12 +1145,12 @@ static const IDEDMAOps ahci_dma_ops = {
|
||||
.reset = ahci_dma_reset,
|
||||
};
|
||||
|
||||
void ahci_init(AHCIState *s, DeviceState *qdev, DMAContext *dma, int ports)
|
||||
void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports)
|
||||
{
|
||||
qemu_irq *irqs;
|
||||
int i;
|
||||
|
||||
s->dma = dma;
|
||||
s->as = as;
|
||||
s->ports = ports;
|
||||
s->dev = g_malloc0(sizeof(AHCIDevice) * ports);
|
||||
ahci_reg_init(s);
|
||||
|
||||
+2
-2
@@ -297,7 +297,7 @@ typedef struct AHCIState {
|
||||
uint32_t idp_index; /* Current IDP index */
|
||||
int32_t ports;
|
||||
qemu_irq irq;
|
||||
DMAContext *dma;
|
||||
AddressSpace *as;
|
||||
} AHCIState;
|
||||
|
||||
typedef struct AHCIPCIState {
|
||||
@@ -338,7 +338,7 @@ typedef struct NCQFrame {
|
||||
uint8_t reserved10;
|
||||
} QEMU_PACKED NCQFrame;
|
||||
|
||||
void ahci_init(AHCIState *s, DeviceState *qdev, DMAContext *dma, int ports);
|
||||
void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports);
|
||||
void ahci_uninit(AHCIState *s);
|
||||
|
||||
void ahci_reset(AHCIState *s);
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
|
||||
uint8_t *sata_cap;
|
||||
d = DO_UPCAST(struct AHCIPCIState, card, dev);
|
||||
|
||||
ahci_init(&d->ahci, &dev->qdev, pci_dma_context(dev), 6);
|
||||
ahci_init(&d->ahci, &dev->qdev, pci_get_address_space(dev), 6);
|
||||
|
||||
pci_config_set_prog_interface(d->card.config, AHCI_PROGMODE_MAJOR_REV_1);
|
||||
|
||||
|
||||
+2
-2
@@ -71,7 +71,7 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
|
||||
s->io_buffer_size = io->len;
|
||||
|
||||
qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1,
|
||||
&dma_context_memory);
|
||||
&address_space_memory);
|
||||
qemu_sglist_add(&s->sg, io->addr, io->len);
|
||||
io->addr += io->len;
|
||||
io->len = 0;
|
||||
@@ -128,7 +128,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
||||
s->io_buffer_size = io->len;
|
||||
|
||||
qemu_sglist_init(&s->sg, io->len / MACIO_PAGE_SIZE + 1,
|
||||
&dma_context_memory);
|
||||
&address_space_memory);
|
||||
qemu_sglist_add(&s->sg, io->addr, io->len);
|
||||
io->addr += io->len;
|
||||
io->len = 0;
|
||||
|
||||
+4
-2
@@ -1939,6 +1939,8 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
||||
void *vaddr;
|
||||
int ret;
|
||||
|
||||
assert(!memory_region_is_iommu(section->mr));
|
||||
|
||||
if (vfio_listener_skipped_section(section)) {
|
||||
DPRINTF("SKIPPING region_add %"HWADDR_PRIx" - %"PRIx64"\n",
|
||||
section->offset_within_address_space,
|
||||
@@ -1953,7 +1955,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
|
||||
}
|
||||
|
||||
iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
|
||||
end = (section->offset_within_address_space + section->size) &
|
||||
end = (section->offset_within_address_space + int128_get64(section->size)) &
|
||||
TARGET_PAGE_MASK;
|
||||
|
||||
if (iova >= end) {
|
||||
@@ -1997,7 +1999,7 @@ static void vfio_listener_region_del(MemoryListener *listener,
|
||||
}
|
||||
|
||||
iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
|
||||
end = (section->offset_within_address_space + section->size) &
|
||||
end = (section->offset_within_address_space + int128_get64(section->size)) &
|
||||
TARGET_PAGE_MASK;
|
||||
|
||||
if (iova >= end) {
|
||||
|
||||
+17
-20
@@ -786,6 +786,7 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
|
||||
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
|
||||
PCIConfigReadFunc *config_read = pc->config_read;
|
||||
PCIConfigWriteFunc *config_write = pc->config_write;
|
||||
AddressSpace *dma_as;
|
||||
|
||||
if (devfn < 0) {
|
||||
for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
|
||||
@@ -801,21 +802,21 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
|
||||
PCI_SLOT(devfn), PCI_FUNC(devfn), name, bus->devices[devfn]->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pci_dev->bus = bus;
|
||||
if (bus->dma_context_fn) {
|
||||
pci_dev->dma = bus->dma_context_fn(bus, bus->dma_context_opaque, devfn);
|
||||
if (bus->iommu_fn) {
|
||||
dma_as = bus->iommu_fn(bus, bus->iommu_opaque, devfn);
|
||||
} else {
|
||||
/* FIXME: Make dma_context_fn use MemoryRegions instead, so this path is
|
||||
* taken unconditionally */
|
||||
/* FIXME: inherit memory region from bus creator */
|
||||
memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master",
|
||||
get_system_memory(), 0,
|
||||
memory_region_size(get_system_memory()));
|
||||
memory_region_set_enabled(&pci_dev->bus_master_enable_region, false);
|
||||
address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region);
|
||||
pci_dev->dma = g_new(DMAContext, 1);
|
||||
dma_context_init(pci_dev->dma, &pci_dev->bus_master_as, NULL, NULL, NULL);
|
||||
dma_as = &address_space_memory;
|
||||
}
|
||||
|
||||
memory_region_init_alias(&pci_dev->bus_master_enable_region, "bus master",
|
||||
dma_as->root, 0, memory_region_size(dma_as->root));
|
||||
memory_region_set_enabled(&pci_dev->bus_master_enable_region, false);
|
||||
address_space_init(&pci_dev->bus_master_as, &pci_dev->bus_master_enable_region,
|
||||
name);
|
||||
|
||||
pci_dev->devfn = devfn;
|
||||
pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
|
||||
pci_dev->irq_state = 0;
|
||||
@@ -869,12 +870,8 @@ static void do_pci_unregister_device(PCIDevice *pci_dev)
|
||||
pci_dev->bus->devices[pci_dev->devfn] = NULL;
|
||||
pci_config_free(pci_dev);
|
||||
|
||||
if (!pci_dev->bus->dma_context_fn) {
|
||||
address_space_destroy(&pci_dev->bus_master_as);
|
||||
memory_region_destroy(&pci_dev->bus_master_enable_region);
|
||||
g_free(pci_dev->dma);
|
||||
pci_dev->dma = NULL;
|
||||
}
|
||||
address_space_destroy(&pci_dev->bus_master_as);
|
||||
memory_region_destroy(&pci_dev->bus_master_enable_region);
|
||||
}
|
||||
|
||||
static void pci_unregister_io_regions(PCIDevice *pci_dev)
|
||||
@@ -2231,10 +2228,10 @@ static void pci_device_class_init(ObjectClass *klass, void *data)
|
||||
k->props = pci_props;
|
||||
}
|
||||
|
||||
void pci_setup_iommu(PCIBus *bus, PCIDMAContextFunc fn, void *opaque)
|
||||
void pci_setup_iommu(PCIBus *bus, PCIIOMMUFunc fn, void *opaque)
|
||||
{
|
||||
bus->dma_context_fn = fn;
|
||||
bus->dma_context_opaque = opaque;
|
||||
bus->iommu_fn = fn;
|
||||
bus->iommu_opaque = opaque;
|
||||
}
|
||||
|
||||
static const TypeInfo pci_device_type_info = {
|
||||
|
||||
+57
-62
@@ -36,15 +36,13 @@ enum sPAPRTCEAccess {
|
||||
SPAPR_TCE_RW = 3,
|
||||
};
|
||||
|
||||
typedef struct sPAPRTCETable sPAPRTCETable;
|
||||
|
||||
struct sPAPRTCETable {
|
||||
DMAContext dma;
|
||||
uint32_t liobn;
|
||||
uint32_t window_size;
|
||||
sPAPRTCE *table;
|
||||
bool bypass;
|
||||
int fd;
|
||||
MemoryRegion iommu;
|
||||
QLIST_ENTRY(sPAPRTCETable) list;
|
||||
};
|
||||
|
||||
@@ -70,15 +68,9 @@ static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int spapr_tce_translate(DMAContext *dma,
|
||||
dma_addr_t addr,
|
||||
hwaddr *paddr,
|
||||
hwaddr *len,
|
||||
DMADirection dir)
|
||||
static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr)
|
||||
{
|
||||
sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
|
||||
enum sPAPRTCEAccess access = (dir == DMA_DIRECTION_FROM_DEVICE)
|
||||
? SPAPR_TCE_WO : SPAPR_TCE_RO;
|
||||
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
|
||||
uint64_t tce;
|
||||
|
||||
#ifdef DEBUG_TCE
|
||||
@@ -87,9 +79,13 @@ static int spapr_tce_translate(DMAContext *dma,
|
||||
#endif
|
||||
|
||||
if (tcet->bypass) {
|
||||
*paddr = addr;
|
||||
*len = (hwaddr)-1;
|
||||
return 0;
|
||||
return (IOMMUTLBEntry) {
|
||||
.target_as = &address_space_memory,
|
||||
.iova = 0,
|
||||
.translated_addr = 0,
|
||||
.addr_mask = ~(hwaddr)0,
|
||||
.perm = IOMMU_RW,
|
||||
};
|
||||
}
|
||||
|
||||
/* Check if we are in bound */
|
||||
@@ -97,32 +93,30 @@ static int spapr_tce_translate(DMAContext *dma,
|
||||
#ifdef DEBUG_TCE
|
||||
fprintf(stderr, "spapr_tce_translate out of bounds\n");
|
||||
#endif
|
||||
return -EFAULT;
|
||||
return (IOMMUTLBEntry) { .perm = IOMMU_NONE };
|
||||
}
|
||||
|
||||
tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT].tce;
|
||||
|
||||
/* Check TCE */
|
||||
if (!(tce & access)) {
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* How much til end of page ? */
|
||||
*len = ((~addr) & SPAPR_TCE_PAGE_MASK) + 1;
|
||||
|
||||
/* Translate */
|
||||
*paddr = (tce & ~SPAPR_TCE_PAGE_MASK) |
|
||||
(addr & SPAPR_TCE_PAGE_MASK);
|
||||
|
||||
#ifdef DEBUG_TCE
|
||||
fprintf(stderr, " -> *paddr=0x" TARGET_FMT_plx ", *len=0x"
|
||||
TARGET_FMT_plx "\n", *paddr, *len);
|
||||
fprintf(stderr, " -> *paddr=0x%llx, *len=0x%llx\n",
|
||||
(tce & ~SPAPR_TCE_PAGE_MASK), SPAPR_TCE_PAGE_MASK + 1);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return (IOMMUTLBEntry) {
|
||||
.target_as = &address_space_memory,
|
||||
.iova = addr & ~SPAPR_TCE_PAGE_MASK,
|
||||
.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK,
|
||||
.addr_mask = SPAPR_TCE_PAGE_MASK,
|
||||
.perm = tce,
|
||||
};
|
||||
}
|
||||
|
||||
DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size)
|
||||
static MemoryRegionIOMMUOps spapr_iommu_ops = {
|
||||
.translate = spapr_tce_translate_iommu,
|
||||
};
|
||||
|
||||
sPAPRTCETable *spapr_tce_new_table(uint32_t liobn, size_t window_size)
|
||||
{
|
||||
sPAPRTCETable *tcet;
|
||||
|
||||
@@ -137,8 +131,6 @@ DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size)
|
||||
}
|
||||
|
||||
tcet = g_malloc0(sizeof(*tcet));
|
||||
dma_context_init(&tcet->dma, &address_space_memory, spapr_tce_translate, NULL, NULL);
|
||||
|
||||
tcet->liobn = liobn;
|
||||
tcet->window_size = window_size;
|
||||
|
||||
@@ -155,43 +147,43 @@ DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size)
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TCE
|
||||
fprintf(stderr, "spapr_iommu: New TCE table, liobn=0x%x, context @ %p, "
|
||||
"table @ %p, fd=%d\n", liobn, &tcet->dma, tcet->table, tcet->fd);
|
||||
fprintf(stderr, "spapr_iommu: New TCE table @ %p, liobn=0x%x, "
|
||||
"table @ %p, fd=%d\n", tcet, liobn, tcet->table, tcet->fd);
|
||||
#endif
|
||||
|
||||
memory_region_init_iommu(&tcet->iommu, &spapr_iommu_ops,
|
||||
"iommu-spapr", UINT64_MAX);
|
||||
|
||||
QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list);
|
||||
|
||||
return &tcet->dma;
|
||||
return tcet;
|
||||
}
|
||||
|
||||
void spapr_tce_free(DMAContext *dma)
|
||||
void spapr_tce_free(sPAPRTCETable *tcet)
|
||||
{
|
||||
QLIST_REMOVE(tcet, list);
|
||||
|
||||
if (dma) {
|
||||
sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
|
||||
|
||||
QLIST_REMOVE(tcet, list);
|
||||
|
||||
if (!kvm_enabled() ||
|
||||
(kvmppc_remove_spapr_tce(tcet->table, tcet->fd,
|
||||
tcet->window_size) != 0)) {
|
||||
g_free(tcet->table);
|
||||
}
|
||||
|
||||
g_free(tcet);
|
||||
if (!kvm_enabled() ||
|
||||
(kvmppc_remove_spapr_tce(tcet->table, tcet->fd,
|
||||
tcet->window_size) != 0)) {
|
||||
g_free(tcet->table);
|
||||
}
|
||||
|
||||
g_free(tcet);
|
||||
}
|
||||
|
||||
void spapr_tce_set_bypass(DMAContext *dma, bool bypass)
|
||||
MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet)
|
||||
{
|
||||
sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
|
||||
return &tcet->iommu;
|
||||
}
|
||||
|
||||
void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass)
|
||||
{
|
||||
tcet->bypass = bypass;
|
||||
}
|
||||
|
||||
void spapr_tce_reset(DMAContext *dma)
|
||||
void spapr_tce_reset(sPAPRTCETable *tcet)
|
||||
{
|
||||
sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
|
||||
size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT)
|
||||
* sizeof(sPAPRTCE);
|
||||
|
||||
@@ -203,6 +195,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
|
||||
target_ulong tce)
|
||||
{
|
||||
sPAPRTCE *tcep;
|
||||
IOMMUTLBEntry entry;
|
||||
|
||||
if (ioba >= tcet->window_size) {
|
||||
hcall_dprintf("spapr_vio_put_tce on out-of-bounds IOBA 0x"
|
||||
@@ -213,6 +206,13 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
|
||||
tcep = tcet->table + (ioba >> SPAPR_TCE_PAGE_SHIFT);
|
||||
tcep->tce = tce;
|
||||
|
||||
entry.target_as = &address_space_memory,
|
||||
entry.iova = ioba & ~SPAPR_TCE_PAGE_MASK;
|
||||
entry.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK;
|
||||
entry.addr_mask = SPAPR_TCE_PAGE_MASK;
|
||||
entry.perm = tce;
|
||||
memory_region_notify_iommu(&tcet->iommu, entry);
|
||||
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -277,17 +277,12 @@ int spapr_dma_dt(void *fdt, int node_off, const char *propname,
|
||||
}
|
||||
|
||||
int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
|
||||
DMAContext *iommu)
|
||||
sPAPRTCETable *tcet)
|
||||
{
|
||||
if (!iommu) {
|
||||
if (!tcet) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (iommu->translate == spapr_tce_translate) {
|
||||
sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, iommu);
|
||||
return spapr_dma_dt(fdt, node_off, propname,
|
||||
tcet->liobn, 0, tcet->window_size);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return spapr_dma_dt(fdt, node_off, propname,
|
||||
tcet->liobn, 0, tcet->window_size);
|
||||
}
|
||||
|
||||
+9
-7
@@ -506,12 +506,11 @@ static const MemoryRegionOps spapr_msi_ops = {
|
||||
/*
|
||||
* PHB PCI device
|
||||
*/
|
||||
static DMAContext *spapr_pci_dma_context_fn(PCIBus *bus, void *opaque,
|
||||
int devfn)
|
||||
static AddressSpace *spapr_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||
{
|
||||
sPAPRPHBState *phb = opaque;
|
||||
|
||||
return phb->dma;
|
||||
return &phb->iommu_as;
|
||||
}
|
||||
|
||||
static int spapr_phb_init(SysBusDevice *s)
|
||||
@@ -646,12 +645,15 @@ static int spapr_phb_init(SysBusDevice *s)
|
||||
|
||||
sphb->dma_window_start = 0;
|
||||
sphb->dma_window_size = 0x40000000;
|
||||
sphb->dma = spapr_tce_new_dma_context(sphb->dma_liobn, sphb->dma_window_size);
|
||||
if (!sphb->dma) {
|
||||
sphb->tcet = spapr_tce_new_table(sphb->dma_liobn, sphb->dma_window_size);
|
||||
if (!sphb->tcet) {
|
||||
fprintf(stderr, "Unable to create TCE table for %s\n", sphb->dtbusname);
|
||||
return -1;
|
||||
}
|
||||
pci_setup_iommu(bus, spapr_pci_dma_context_fn, sphb);
|
||||
address_space_init(&sphb->iommu_as, spapr_tce_get_iommu(sphb->tcet),
|
||||
sphb->dtbusname);
|
||||
|
||||
pci_setup_iommu(bus, spapr_pci_dma_iommu, sphb);
|
||||
|
||||
QLIST_INSERT_HEAD(&spapr->phbs, sphb, list);
|
||||
|
||||
@@ -676,7 +678,7 @@ static void spapr_phb_reset(DeviceState *qdev)
|
||||
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
|
||||
|
||||
/* Reset the IOMMU state */
|
||||
spapr_tce_reset(sphb->dma);
|
||||
spapr_tce_reset(sphb->tcet);
|
||||
}
|
||||
|
||||
static Property spapr_phb_properties[] = {
|
||||
|
||||
+7
-6
@@ -142,7 +142,7 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
|
||||
}
|
||||
}
|
||||
|
||||
ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->dma);
|
||||
ret = spapr_tcet_dma_dt(fdt, node_off, "ibm,my-dma-window", dev->tcet);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -315,8 +315,8 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
|
||||
|
||||
static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
|
||||
{
|
||||
if (dev->dma) {
|
||||
spapr_tce_reset(dev->dma);
|
||||
if (dev->tcet) {
|
||||
spapr_tce_reset(dev->tcet);
|
||||
}
|
||||
free_crq(dev);
|
||||
}
|
||||
@@ -341,12 +341,12 @@ static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev->dma) {
|
||||
if (!dev->tcet) {
|
||||
rtas_st(rets, 0, -3);
|
||||
return;
|
||||
}
|
||||
|
||||
spapr_tce_set_bypass(dev->dma, !!enable);
|
||||
spapr_tce_set_bypass(dev->tcet, !!enable);
|
||||
|
||||
rtas_st(rets, 0, 0);
|
||||
}
|
||||
@@ -453,7 +453,8 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
|
||||
|
||||
if (pc->rtce_window_size) {
|
||||
uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg;
|
||||
dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size);
|
||||
dev->tcet = spapr_tce_new_table(liobn, pc->rtce_window_size);
|
||||
address_space_init(&dev->as, spapr_tce_get_iommu(dev->tcet), qdev->id);
|
||||
}
|
||||
|
||||
return pc->init(dev);
|
||||
|
||||
+2
-2
@@ -232,7 +232,7 @@ static int megasas_map_sgl(MegasasState *s, MegasasCmd *cmd, union mfi_sgl *sgl)
|
||||
MEGASAS_MAX_SGE);
|
||||
return iov_count;
|
||||
}
|
||||
qemu_sglist_init(&cmd->qsg, iov_count, pci_dma_context(&s->dev));
|
||||
pci_dma_sglist_init(&cmd->qsg, &s->dev, iov_count);
|
||||
for (i = 0; i < iov_count; i++) {
|
||||
dma_addr_t iov_pa, iov_size_p;
|
||||
|
||||
@@ -628,7 +628,7 @@ static int megasas_map_dcmd(MegasasState *s, MegasasCmd *cmd)
|
||||
}
|
||||
iov_pa = megasas_sgl_get_addr(cmd, &cmd->frame->dcmd.sgl);
|
||||
iov_size = megasas_sgl_get_len(cmd, &cmd->frame->dcmd.sgl);
|
||||
qemu_sglist_init(&cmd->qsg, 1, pci_dma_context(&s->dev));
|
||||
pci_dma_sglist_init(&cmd->qsg, &s->dev, 1);
|
||||
qemu_sglist_add(&cmd->qsg, iov_pa, iov_size);
|
||||
cmd->iov_size = iov_size;
|
||||
return cmd->iov_size;
|
||||
|
||||
@@ -80,7 +80,7 @@ static void virtio_scsi_bad_req(void)
|
||||
static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg,
|
||||
hwaddr *addr, int num)
|
||||
{
|
||||
qemu_sglist_init(qsgl, num, &dma_context_memory);
|
||||
qemu_sglist_init(qsgl, num, &address_space_memory);
|
||||
while (num--) {
|
||||
qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len);
|
||||
}
|
||||
|
||||
@@ -617,7 +617,7 @@ pvscsi_build_sglist(PVSCSIState *s, PVSCSIRequest *r)
|
||||
{
|
||||
PCIDevice *d = PCI_DEVICE(s);
|
||||
|
||||
qemu_sglist_init(&r->sgl, 1, pci_dma_context(d));
|
||||
pci_dma_sglist_init(&r->sgl, d, 1);
|
||||
if (r->req.flags & PVSCSI_FLAG_CMD_WITH_SG_LIST) {
|
||||
pvscsi_convert_sglist(r);
|
||||
} else {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user