diff options
Diffstat (limited to 'hw/spapr_iommu.c')
-rw-r--r-- | hw/spapr_iommu.c | 293 |
1 files changed, 0 insertions, 293 deletions
diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c deleted file mode 100644 index 8d500bf6be..0000000000 --- a/hw/spapr_iommu.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * QEMU sPAPR IOMMU (TCE) code - * - * Copyright (c) 2010 David Gibson, IBM Corporation <dwg@au1.ibm.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ -#include "hw/hw.h" -#include "sysemu/kvm.h" -#include "hw/qdev.h" -#include "kvm_ppc.h" -#include "sysemu/dma.h" -#include "exec/address-spaces.h" - -#include "hw/spapr.h" - -#include <libfdt.h> - -/* #define DEBUG_TCE */ - -enum sPAPRTCEAccess { - SPAPR_TCE_FAULT = 0, - SPAPR_TCE_RO = 1, - SPAPR_TCE_WO = 2, - 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; - QLIST_ENTRY(sPAPRTCETable) list; -}; - - -QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables; - -static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn) -{ - sPAPRTCETable *tcet; - - QLIST_FOREACH(tcet, &spapr_tce_tables, list) { - if (tcet->liobn == liobn) { - return tcet; - } - } - - return NULL; -} - -static int spapr_tce_translate(DMAContext *dma, - dma_addr_t addr, - hwaddr *paddr, - hwaddr *len, - DMADirection dir) -{ - sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); - enum sPAPRTCEAccess access = (dir == DMA_DIRECTION_FROM_DEVICE) - ? SPAPR_TCE_WO : SPAPR_TCE_RO; - uint64_t tce; - -#ifdef DEBUG_TCE - fprintf(stderr, "spapr_tce_translate liobn=0x%" PRIx32 " addr=0x" - DMA_ADDR_FMT "\n", tcet->liobn, addr); -#endif - - if (tcet->bypass) { - *paddr = addr; - *len = (hwaddr)-1; - return 0; - } - - /* Check if we are in bound */ - if (addr >= tcet->window_size) { -#ifdef DEBUG_TCE - fprintf(stderr, "spapr_tce_translate out of bounds\n"); -#endif - return -EFAULT; - } - - 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); -#endif - - return 0; -} - -DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size) -{ - sPAPRTCETable *tcet; - - if (spapr_tce_find_by_liobn(liobn)) { - fprintf(stderr, "Attempted to create TCE table with duplicate" - " LIOBN 0x%x\n", liobn); - return NULL; - } - - if (!window_size) { - return NULL; - } - - 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; - - if (kvm_enabled()) { - tcet->table = kvmppc_create_spapr_tce(liobn, - window_size, - &tcet->fd); - } - - if (!tcet->table) { - size_t table_size = (window_size >> SPAPR_TCE_PAGE_SHIFT) - * sizeof(sPAPRTCE); - tcet->table = g_malloc0(table_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); -#endif - - QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list); - - return &tcet->dma; -} - -void spapr_tce_free(DMAContext *dma) -{ - - 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); - } -} - -void spapr_tce_set_bypass(DMAContext *dma, bool bypass) -{ - sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); - - tcet->bypass = bypass; -} - -void spapr_tce_reset(DMAContext *dma) -{ - sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma); - size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) - * sizeof(sPAPRTCE); - - tcet->bypass = false; - memset(tcet->table, 0, table_size); -} - -static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, - target_ulong tce) -{ - sPAPRTCE *tcep; - - if (ioba >= tcet->window_size) { - hcall_dprintf("spapr_vio_put_tce on out-of-boards IOBA 0x" - TARGET_FMT_lx "\n", ioba); - return H_PARAMETER; - } - - tcep = tcet->table + (ioba >> SPAPR_TCE_PAGE_SHIFT); - tcep->tce = tce; - - return H_SUCCESS; -} - -static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr, - target_ulong opcode, target_ulong *args) -{ - target_ulong liobn = args[0]; - target_ulong ioba = args[1]; - target_ulong tce = args[2]; - sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn); - - if (liobn & 0xFFFFFFFF00000000ULL) { - hcall_dprintf("spapr_vio_put_tce on out-of-boundsw LIOBN " - TARGET_FMT_lx "\n", liobn); - return H_PARAMETER; - } - - ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1); - - if (tcet) { - return put_tce_emu(tcet, ioba, tce); - } -#ifdef DEBUG_TCE - fprintf(stderr, "%s on liobn=" TARGET_FMT_lx /*%s*/ - " ioba 0x" TARGET_FMT_lx " TCE 0x" TARGET_FMT_lx "\n", - __func__, liobn, /*dev->qdev.id, */ioba, tce); -#endif - - return H_PARAMETER; -} - -void spapr_iommu_init(void) -{ - QLIST_INIT(&spapr_tce_tables); - - /* hcall-tce */ - spapr_register_hypercall(H_PUT_TCE, h_put_tce); -} - -int spapr_dma_dt(void *fdt, int node_off, const char *propname, - uint32_t liobn, uint64_t window, uint32_t size) -{ - uint32_t dma_prop[5]; - int ret; - - dma_prop[0] = cpu_to_be32(liobn); - dma_prop[1] = cpu_to_be32(window >> 32); - dma_prop[2] = cpu_to_be32(window & 0xFFFFFFFF); - dma_prop[3] = 0; /* window size is 32 bits */ - dma_prop[4] = cpu_to_be32(size); - - ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2); - if (ret < 0) { - return ret; - } - - ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2); - if (ret < 0) { - return ret; - } - - ret = fdt_setprop(fdt, node_off, propname, dma_prop, sizeof(dma_prop)); - if (ret < 0) { - return ret; - } - - return 0; -} - -int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, - DMAContext *iommu) -{ - if (!iommu) { - 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; -} |