diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2012-09-12 16:57:20 +0000 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2012-10-04 15:54:18 +0200 |
commit | 53724ee565565f69560dbe17553bede8c0169379 (patch) | |
tree | ef73b2b50f6b30ee1c55c24da8ff858632ca9e3f /hw/spapr_vio.c | |
parent | 490d4a2b6edafb27cd688ded7fdb1290453d71b0 (diff) |
pseries: Rework implementation of TCE bypass
On the pseries machine the IOMMU (aka TCE tables) is always active for all
PCI and VIO devices. Mostly to simplify the SLOF firmware, we implement an
extension which allows the IOMMU to be temporarily disabled for certain
devices.
Currently this is implemented by setting the device's DMAContext pointer to
NULL (thus reverting to qemu's default no-IOMMU DMA behaviour), then
replacing it when bypass mode is disabled.
This approach causes a bunch of complications though. It complexifies the
management of the DMAContext lifetimes, it's problematic for savevm/loadvm,
and it means that while bypass is active we have nowhere to store the
device's LIOBN (Logical IO Bus Number, used to identify DMA address
spaces). At present we regenerate the LIOBN from other address information
but this restricts how we can allocate LIOBNs.
This patch gives up on this approach, replacing it with the much simpler
one of having a 'bypass' boolean flag in the TCE state structure.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw/spapr_vio.c')
-rw-r--r-- | hw/spapr_vio.c | 26 |
1 files changed, 10 insertions, 16 deletions
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 752836e76c..848806d3f1 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -316,14 +316,9 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev) { - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - if (dev->dma) { - spapr_tce_free(dev->dma); + spapr_tce_reset(dev->dma); } - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); - free_crq(dev); } @@ -346,16 +341,14 @@ static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token, rtas_st(rets, 0, -3); return; } - if (enable) { - spapr_tce_free(dev->dma); - dev->dma = NULL; - } else { - VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + if (!dev->dma) { + rtas_st(rets, 0, -3); + return; } + spapr_tce_set_bypass(dev->dma, !!enable); + rtas_st(rets, 0, 0); } @@ -421,7 +414,6 @@ static int spapr_vio_busdev_init(DeviceState *qdev) { VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); - uint32_t liobn; char *id; if (dev->reg != -1) { @@ -463,8 +455,10 @@ static int spapr_vio_busdev_init(DeviceState *qdev) return -1; } - liobn = SPAPR_VIO_BASE_LIOBN | dev->reg; - dev->dma = spapr_tce_new_dma_context(liobn, pc->rtce_window_size); + 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); + } return pc->init(dev); } |