From: David Gibson <david@gibson.dropbear.id.au>
To: agraf@suse.de, qemu-devel@nongnu.org
Cc: paulus@samba.org, anton@samba.org
Subject: [Qemu-devel] [PATCH 21/26] Implement TCE translation for sPAPR VIO
Date: Wed, 16 Mar 2011 15:56:58 +1100 [thread overview]
Message-ID: <1300251423-6715-22-git-send-email-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <1300251423-6715-1-git-send-email-david@gibson.dropbear.id.au>
From: Ben Herrenschmidt <benh@kernel.crashing.org>
This patch implements the necessary infrastructure and hypercalls for
sPAPR's TCE (Translation Control Entry) IOMMU mechanism. This is necessary
for all virtual IO devices which do DMA (i.e. nearly all of them).
Signed-off-by: Ben Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
hw/spapr.c | 3 +-
hw/spapr_vio.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/spapr_vio.h | 32 ++++++++
3 files changed, 266 insertions(+), 1 deletions(-)
diff --git a/hw/spapr.c b/hw/spapr.c
index e7f8864..a362889 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -62,7 +62,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
uint32_t start_prop = cpu_to_be32(initrd_base);
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
- char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt";
+ char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
+ "\0hcall-tce";
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
int i;
char *modelname;
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 45edd94..37cf51e 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -37,6 +37,7 @@
#endif /* CONFIG_FDT */
/* #define DEBUG_SPAPR */
+/* #define DEBUG_TCE */
#ifdef DEBUG_SPAPR
#define dprintf(fmt, ...) \
@@ -114,6 +115,28 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
return ret;
}
+ if (dev->rtce_window_size) {
+ uint32_t dma_prop[] = {cpu_to_be32(dev->reg),
+ 0, 0,
+ 0, cpu_to_be32(dev->rtce_window_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, "ibm,my-dma-window", dma_prop,
+ sizeof(dma_prop));
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
if (info->devnode) {
ret = (info->devnode)(dev, fdt, node_off);
if (ret < 0) {
@@ -125,6 +148,210 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
}
#endif /* CONFIG_FDT */
+/*
+ * RTCE handling
+ */
+
+static void rtce_init(VIOsPAPRDevice *dev)
+{
+ size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT)
+ * sizeof(VIOsPAPR_RTCE);
+
+ if (size) {
+ dev->rtce_table = qemu_mallocz(size);
+ }
+}
+
+static target_ulong h_put_tce(CPUState *env, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong liobn = args[0];
+ target_ulong ioba = args[1];
+ target_ulong tce = args[2];
+ VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, liobn);
+ VIOsPAPR_RTCE *rtce;
+
+ if (!dev) {
+ fprintf(stderr, "spapr_vio_put_tce on non-existent LIOBN "
+ TARGET_FMT_lx "\n",
+ liobn);
+ return H_PARAMETER;
+ }
+
+ ioba &= ~(SPAPR_VIO_TCE_PAGE_SIZE - 1);
+
+#ifdef DEBUG_TCE
+ fprintf(stderr, "spapr_vio_put_tce on %s ioba 0x" TARGET_FMT_lx
+ " TCE 0x" TARGET_FMT_lx "\n", dev->qdev.id, ioba, tce);
+#endif
+
+ if (ioba >= dev->rtce_window_size) {
+ fprintf(stderr, "spapr_vio_put_tce on out-of-boards IOBA 0x" TARGET_FMT_lx "\n",
+ ioba);
+ return H_PARAMETER;
+ }
+
+ rtce = dev->rtce_table + (ioba >> SPAPR_VIO_TCE_PAGE_SHIFT);
+ rtce->tce = tce;
+
+ return H_SUCCESS;
+}
+
+int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba,
+ target_ulong len, enum VIOsPAPR_TCEAccess access)
+{
+ int start, end, i;
+
+ start = ioba >> SPAPR_VIO_TCE_PAGE_SHIFT;
+ end = (ioba + len - 1) >> SPAPR_VIO_TCE_PAGE_SHIFT;
+
+ for (i = start; i <= end; i++) {
+ if ((dev->rtce_table[i].tce & access) != access) {
+ fprintf(stderr, "FAIL on %d\n", i);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* XX Might want to special case KVM for speed ? */
+int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr, const void *buf,
+ uint32_t size)
+{
+#ifdef DEBUG_TCE
+ fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
+ (unsigned long long)taddr, size);
+#endif
+
+ while(size) {
+ uint64_t tce;
+ uint32_t lsize;
+ uint64_t txaddr;
+
+ /* Check if we are in bound */
+ if (taddr >= dev->rtce_window_size) {
+ fprintf(stderr, "spapr_tce_dma_write out of bounds\n");
+ return -H_DEST_PARM;
+ }
+ tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
+
+ /* How much til end of page ? */
+ lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
+
+ /* Check TCE */
+ if (!(tce & 2))
+ return -H_DEST_PARM;
+
+ /* Translate */
+ txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) | (taddr & SPAPR_VIO_TCE_PAGE_MASK);
+
+#ifdef DEBUG_TCE
+ fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
+ (unsigned long long)txaddr, lsize);
+#endif
+
+ /* Do it */
+ cpu_physical_memory_write(txaddr, buf, lsize);
+ buf += lsize;
+ taddr += lsize;
+ size -= lsize;
+ }
+ return 0;
+}
+
+/* XX Might want to special case KVM for speed ? */
+int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size)
+{
+ uint8_t *zeroes;
+
+#ifdef DEBUG_TCE
+ fprintf(stderr, "spapr_tce_dma_zero taddr=0x%llx size=0x%x\n",
+ (unsigned long long)taddr, size);
+#endif
+
+ /* FIXME: do this better... */
+ zeroes = alloca(size);
+ memset(zeroes, 0, size);
+ return spapr_tce_dma_write(dev, taddr, zeroes, size);
+}
+
+void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val)
+{
+ spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val)
+{
+ val = tswap16(val);
+ spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+
+void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val)
+{
+ val = tswap32(val);
+ spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val)
+{
+ val = tswap64(val);
+ spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr, void *buf,
+ uint32_t size)
+{
+#ifdef DEBUG_TCE
+ fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
+ (unsigned long long)taddr, size);
+#endif
+
+ while(size) {
+ uint64_t tce;
+ uint32_t lsize;
+ uint64_t txaddr;
+
+ /* Check if we are in bound */
+ if (taddr >= dev->rtce_window_size) {
+ fprintf(stderr, "spapr_tce_dma_read out of bounds\n");
+ return -H_DEST_PARM;
+ }
+ tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
+
+ /* How much til end of page ? */
+ lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
+
+ /* Check TCE */
+ if (!(tce & 1)) {
+ return H_DEST_PARM;
+ }
+
+ /* Translate */
+ txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) | (taddr & SPAPR_VIO_TCE_PAGE_MASK);
+
+#ifdef DEBUG_TCE
+ fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
+ (unsigned long long)txaddr, lsize);
+#endif
+ /* Do it */
+ cpu_physical_memory_read(txaddr, buf, lsize);
+ buf += lsize;
+ taddr += lsize;
+ size -= lsize;
+ }
+ return H_SUCCESS;
+}
+
+uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr)
+{
+ uint64_t val;
+
+ spapr_tce_dma_read(dev, taddr, &val, sizeof(val));
+ return tswap64(val);
+}
+
static int spapr_vio_busdev_init(DeviceState *dev, DeviceInfo *info)
{
VIOsPAPRDeviceInfo *_info = (VIOsPAPRDeviceInfo *)info;
@@ -137,6 +364,8 @@ static int spapr_vio_busdev_init(DeviceState *dev, DeviceInfo *info)
_dev->qdev.id = id;
+ rtce_init(_dev);
+
return _info->init(_dev);
}
@@ -190,6 +419,9 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
/* hcall-vio */
spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
+ /* hcall-tce */
+ spapr_register_hypercall(H_PUT_TCE, h_put_tce);
+
for (_info = device_info_list; _info; _info = _info->next) {
VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)_info;
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 2013927..1b15d3e 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -21,12 +21,29 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#define SPAPR_VIO_TCE_PAGE_SHIFT 12
+#define SPAPR_VIO_TCE_PAGE_SIZE (1ULL << SPAPR_VIO_TCE_PAGE_SHIFT)
+#define SPAPR_VIO_TCE_PAGE_MASK (SPAPR_VIO_TCE_PAGE_SIZE - 1)
+
+enum VIOsPAPR_TCEAccess {
+ SPAPR_TCE_FAULT = 0,
+ SPAPR_TCE_RO = 1,
+ SPAPR_TCE_WO = 2,
+ SPAPR_TCE_RW = 3,
+};
+
+typedef struct VIOsPAPR_RTCE {
+ uint64_t tce;
+} VIOsPAPR_RTCE;
+
typedef struct VIOsPAPRDevice {
DeviceState qdev;
uint32_t reg;
qemu_irq qirq;
uint32_t vio_irq_num;
target_ulong signal_state;
+ uint32_t rtce_window_size;
+ VIOsPAPR_RTCE *rtce_table;
} VIOsPAPRDevice;
typedef struct VIOsPAPRBus {
@@ -49,6 +66,21 @@ extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
+int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba,
+ target_ulong len,
+ enum VIOsPAPR_TCEAccess access);
+
+int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr,
+ void *buf, uint32_t size);
+int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr,
+ const void *buf, uint32_t size);
+int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size);
+void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val);
+void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val);
+void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val);
+void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val);
+uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr);
+
void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
void spapr_vty_create(VIOsPAPRBus *bus,
uint32_t reg, CharDriverState *chardev,
--
1.7.1
next prev parent reply other threads:[~2011-03-16 4:57 UTC|newest]
Thread overview: 82+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-03-16 4:56 [Qemu-devel] Implement emulation of pSeries logical partitions (v3) David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 01/26] Clean up PowerPC SLB handling code David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 02/26] Allow qemu_devtree_setprop() to take arbitrary values David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 03/26] Add a hook to allow hypercalls to be emulated on PowerPC David Gibson
2011-03-16 13:46 ` [Qemu-devel] " Alexander Graf
2011-03-16 16:58 ` Stefan Hajnoczi
2011-03-17 2:26 ` David Gibson
2011-03-16 20:44 ` [Qemu-devel] " Anthony Liguori
2011-03-17 4:55 ` David Gibson
2011-03-17 13:20 ` Anthony Liguori
2011-03-18 4:03 ` David Gibson
2011-03-18 6:57 ` Alexander Graf
2011-03-16 4:56 ` [Qemu-devel] [PATCH 04/26] Implement PowerPC slbmfee and slbmfev instructions David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 05/26] Implement missing parts of the logic for the POWER PURR David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 06/26] Correct ppc popcntb logic, implement popcntw and popcntd David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 07/26] Clean up slb_lookup() function David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 08/26] Parse SDR1 on mtspr instead of at translate time David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 09/26] Use "hash" more consistently in ppc mmu code David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 10/26] Better factor the ppc hash translation path David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 11/26] Support 1T segments on ppc David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 12/26] Add POWER7 support for ppc David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 13/26] Start implementing pSeries logical partition machine David Gibson
2011-03-16 14:30 ` [Qemu-devel] " Alexander Graf
2011-03-16 21:59 ` [Qemu-devel] " Anthony Liguori
2011-03-16 23:46 ` Alexander Graf
2011-03-17 3:08 ` David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 14/26] Implement the bus structure for PAPR virtual IO David Gibson
2011-03-16 14:43 ` [Qemu-devel] " Alexander Graf
2011-03-16 22:04 ` [Qemu-devel] " Anthony Liguori
2011-03-17 3:19 ` David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 15/26] Virtual hash page table handling on pSeries machine David Gibson
2011-03-16 15:03 ` [Qemu-devel] " Alexander Graf
2011-03-17 1:03 ` [Qemu-devel] Re: [PATCH 15/26] Virtual hash page table handling on pSeries machine' David Gibson
2011-03-17 7:35 ` Alexander Graf
2011-03-16 4:56 ` [Qemu-devel] [PATCH 16/26] Implement hcall based RTAS for pSeries machines David Gibson
2011-03-16 15:08 ` [Qemu-devel] " Alexander Graf
2011-03-17 1:22 ` David Gibson
2011-03-17 7:36 ` Alexander Graf
2011-03-16 22:08 ` [Qemu-devel] " Anthony Liguori
2011-03-16 4:56 ` [Qemu-devel] [PATCH 17/26] Implement assorted pSeries hcalls and RTAS methods David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 18/26] Implement the PAPR (pSeries) virtualized interrupt controller (xics) David Gibson
2011-03-16 15:47 ` [Qemu-devel] " Alexander Graf
2011-03-17 1:29 ` David Gibson
2011-03-17 7:37 ` Alexander Graf
2011-03-16 22:16 ` [Qemu-devel] " Anthony Liguori
2011-03-17 1:34 ` David Gibson
2011-03-17 13:13 ` Anthony Liguori
2011-03-23 3:48 ` David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 19/26] Add PAPR H_VIO_SIGNAL hypercall and infrastructure for VIO interrupts David Gibson
2011-03-16 15:49 ` [Qemu-devel] " Alexander Graf
2011-03-17 1:38 ` David Gibson
2011-03-17 7:38 ` Alexander Graf
2011-03-16 4:56 ` [Qemu-devel] [PATCH 20/26] Add (virtual) interrupt to PAPR virtual tty device David Gibson
2011-03-16 4:56 ` David Gibson [this message]
2011-03-16 16:03 ` [Qemu-devel] Re: [PATCH 21/26] Implement TCE translation for sPAPR VIO Alexander Graf
2011-03-16 20:05 ` Benjamin Herrenschmidt
2011-03-16 20:21 ` Anthony Liguori
2011-03-16 20:22 ` Anthony Liguori
2011-03-16 20:36 ` Benjamin Herrenschmidt
2011-03-17 1:43 ` David Gibson
2011-03-16 22:20 ` [Qemu-devel] " Anthony Liguori
2011-03-18 1:58 ` David Gibson
2011-03-16 4:56 ` [Qemu-devel] [PATCH 22/26] Implement sPAPR Virtual LAN (ibmveth) David Gibson
2011-03-16 16:12 ` [Qemu-devel] " Alexander Graf
2011-03-17 2:04 ` David Gibson
2011-03-16 22:29 ` [Qemu-devel] " Anthony Liguori
2011-03-17 2:09 ` David Gibson
2011-03-16 4:57 ` [Qemu-devel] [PATCH 23/26] Implement PAPR CRQ hypercalls David Gibson
2011-03-16 16:15 ` [Qemu-devel] " Alexander Graf
2011-03-16 4:57 ` [Qemu-devel] [PATCH 24/26] Implement PAPR virtual SCSI interface (ibmvscsi) David Gibson
2011-03-16 16:41 ` [Qemu-devel] " Alexander Graf
2011-03-16 16:51 ` Anthony Liguori
2011-03-16 20:08 ` Benjamin Herrenschmidt
2011-03-16 20:19 ` Anthony Liguori
2011-03-16 4:57 ` [Qemu-devel] [PATCH 25/26] Add a PAPR TCE-bypass mechanism for the pSeries machine David Gibson
2011-03-16 16:43 ` [Qemu-devel] " Alexander Graf
2011-03-17 2:21 ` David Gibson
2011-03-17 3:25 ` Benjamin Herrenschmidt
2011-03-17 7:44 ` Alexander Graf
2011-03-17 8:44 ` Benjamin Herrenschmidt
2011-03-17 9:37 ` Alexander Graf
2011-03-16 4:57 ` [Qemu-devel] [PATCH 26/26] Implement PAPR VPA functions for pSeries shared processor partitions David Gibson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1300251423-6715-22-git-send-email-david@gibson.dropbear.id.au \
--to=david@gibson.dropbear.id.au \
--cc=agraf@suse.de \
--cc=anton@samba.org \
--cc=paulus@samba.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).