From owner-svn-src-projects@FreeBSD.ORG Sun Sep 15 21:18:52 2013 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id 29B2E84F; Sun, 15 Sep 2013 21:18:52 +0000 (UTC) (envelope-from nwhitehorn@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 1632D2644; Sun, 15 Sep 2013 21:18:52 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id r8FLIp5j056155; Sun, 15 Sep 2013 21:18:51 GMT (envelope-from nwhitehorn@svn.freebsd.org) Received: (from nwhitehorn@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id r8FLIpU9056151; Sun, 15 Sep 2013 21:18:51 GMT (envelope-from nwhitehorn@svn.freebsd.org) Message-Id: <201309152118.r8FLIpU9056151@svn.freebsd.org> From: Nathan Whitehorn Date: Sun, 15 Sep 2013 21:18:51 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r255603 - in projects/pseries: conf powerpc/pseries X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 15 Sep 2013 21:18:52 -0000 Author: nwhitehorn Date: Sun Sep 15 21:18:50 2013 New Revision: 255603 URL: http://svnweb.freebsd.org/changeset/base/255603 Log: Add support for the PAPR IOMMU. This makes DMA work at least on the QEMU pSeries emulator. Thanks to kib for working through some details on IRC. Added: projects/pseries/powerpc/pseries/plpar_iommu.c (contents, props changed) projects/pseries/powerpc/pseries/plpar_iommu.h (contents, props changed) Modified: projects/pseries/conf/files.powerpc projects/pseries/powerpc/pseries/rtas_pci.c Modified: projects/pseries/conf/files.powerpc ============================================================================== --- projects/pseries/conf/files.powerpc Sun Sep 15 16:27:25 2013 (r255602) +++ projects/pseries/conf/files.powerpc Sun Sep 15 21:18:50 2013 (r255603) @@ -229,6 +229,7 @@ powerpc/pseries/phyp-hvcall.S optional p powerpc/pseries/mmu_phyp.c optional pseries powerpc64 powerpc/pseries/phyp_console.c optional pseries powerpc64 powerpc/pseries/platform_chrp.c optional pseries +powerpc/pseries/plpar_iommu.c optional pseries powerpc64 powerpc/pseries/rtas_dev.c optional pseries powerpc/pseries/rtas_pci.c optional pseries pci powerpc/pseries/vdevice.c optional pseries powerpc64 Added: projects/pseries/powerpc/pseries/plpar_iommu.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/pseries/powerpc/pseries/plpar_iommu.c Sun Sep 15 21:18:50 2013 (r255603) @@ -0,0 +1,231 @@ +/*- + * Copyright (c) 2013, Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +MALLOC_DEFINE(M_PHYPIOMMU, "iommu", "IOMMU data for PAPR LPARs"); + +struct papr_iommu_map { + uint32_t iobn; + vmem_t *vmem; + struct papr_iommu_map *next; +}; + +static SLIST_HEAD(iommu_maps, iommu_map) iommu_map_head = + SLIST_HEAD_INITIALIZER(iommu_map_head); +static int papr_supports_stuff_tce = -1; + +struct iommu_map { + uint32_t iobn; + vmem_t *vmem; + + SLIST_ENTRY(iommu_map) entries; +}; + +struct dma_window { + struct iommu_map *map; + bus_addr_t start; + bus_addr_t end; +}; + +int +phyp_iommu_set_dma_tag(device_t dev, device_t child, bus_dma_tag_t tag) +{ + device_t p; + phandle_t node; + cell_t dma_acells, dma_scells, dmawindow[5]; + struct iommu_map *i; + + for (p = child; p != NULL; p = device_get_parent(p)) { + if (ofw_bus_has_prop(p, "ibm,my-dma-window")) + break; + if (ofw_bus_has_prop(p, "ibm,dma-window")) + break; + } + + if (p == NULL) + return (ENXIO); + + node = ofw_bus_get_node(p); + if (OF_getprop(node, "ibm,#dma-size-cells", &dma_scells, + sizeof(cell_t)) <= 0) + OF_searchprop(node, "#size-cells", &dma_scells, sizeof(cell_t)); + if (OF_getprop(node, "ibm,#dma-address-cells", &dma_acells, + sizeof(cell_t)) <= 0) + OF_searchprop(node, "#address-cells", &dma_acells, + sizeof(cell_t)); + + if (ofw_bus_has_prop(p, "ibm,my-dma-window")) + OF_getprop(node, "ibm,my-dma-window", dmawindow, + sizeof(cell_t)*(dma_scells + dma_acells + 1)); + else + OF_getprop(node, "ibm,dma-window", dmawindow, + sizeof(cell_t)*(dma_scells + dma_acells + 1)); + + struct dma_window *window = malloc(sizeof(struct dma_window), + M_PHYPIOMMU, M_WAITOK); + if (dma_acells == 1) + window->start = dmawindow[1]; + else + window->start = ((uint64_t)(dmawindow[1]) << 32) | dmawindow[2]; + if (dma_scells == 1) + window->end = window->start + dmawindow[dma_acells + 1]; + else + window->end = window->start + + (((uint64_t)(dmawindow[dma_acells + 1]) << 32) | + dmawindow[dma_acells + 2]); + + window->map = NULL; + SLIST_FOREACH(i, &iommu_map_head, entries) { + if (i->iobn == dmawindow[0]) { + window->map = i; + break; + } + } + + if (window->map == NULL) { + window->map = malloc(sizeof(struct iommu_map), M_PHYPIOMMU, + M_WAITOK); + window->map->iobn = dmawindow[0]; + window->map->vmem = vmem_create("IOMMU mappings", 0, + trunc_page(VMEM_ADDR_MAX), PAGE_SIZE, 0, + M_BESTFIT | M_NOWAIT); + } + + /* + * Check experimentally whether we can use H_STUFF_TCE. It is required + * by the spec but some firmware (e.g. QEMU) does not actually support + * it + */ + if (papr_supports_stuff_tce == -1) + papr_supports_stuff_tce = !(phyp_hcall(H_STUFF_TCE, + window->map->iobn, 0, 0, 0) == H_FUNCTION); + + bus_dma_tag_set_iommu(tag, dev, window); + + return (0); +} + +int +phyp_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs, + bus_addr_t min, bus_addr_t max, bus_size_t alignment, bus_addr_t boundary, + void *cookie) +{ + struct dma_window *window = cookie; + bus_addr_t minaddr, maxaddr; + bus_addr_t alloced; + bus_size_t allocsize; + int error, i, j; + uint64_t tce; + minaddr = window->start; + maxaddr = window->end; + + /* XXX: handle exclusion range in a more useful way */ + if (min < maxaddr) + maxaddr = min; + + /* XXX: is this correct? */ + if (alignment % PAGE_SIZE != 0) + alignment = PAGE_SIZE; + + /* XXX: consolidate segs? */ + for (i = 0; i < *nsegs; i++) { + allocsize = round_page(segs[i].ds_len + + (segs[i].ds_addr & PAGE_MASK)); + error = vmem_xalloc(window->map->vmem, allocsize, alignment, 0, + boundary, minaddr, maxaddr, M_BESTFIT | M_NOWAIT, &alloced); + if (error != 0) { + panic("VMEM failure: %d\n", error); + return (error); + } + + tce = trunc_page(segs[i].ds_addr); + tce |= 0x3; /* read/write */ + if (papr_supports_stuff_tce) { + error = phyp_hcall(H_STUFF_TCE, window->map->iobn, + alloced, tce, allocsize/PAGE_SIZE); + } else { + for (j = 0; j < allocsize; j += PAGE_SIZE) + error = phyp_hcall(H_PUT_TCE, window->map->iobn, + alloced + j, tce + j); + } + + segs[i].ds_addr = alloced + (segs[i].ds_addr & PAGE_MASK); + if (error < 0) { + panic("IOMMU mapping error: %d\n", error); + return (ENOMEM); + } + } + + return (0); +} + +int +phyp_iommu_unmap(device_t dev, bus_dma_segment_t *segs, int nsegs, void *cookie) +{ + struct dma_window *window = cookie; + bus_addr_t pageround; + bus_size_t roundedsize; + int i; + bus_addr_t j; + + for (i = 0; i < nsegs; i++) { + pageround = trunc_page(segs[i].ds_addr); + roundedsize = round_page(segs[i].ds_len + + (segs[i].ds_addr & PAGE_MASK)); + + if (papr_supports_stuff_tce) { + phyp_hcall(H_STUFF_TCE, window->map->iobn, pageround, 0, + roundedsize/PAGE_SIZE); + } else { + for (j = 0; j < roundedsize; j += PAGE_SIZE) + phyp_hcall(H_PUT_TCE, window->map->iobn, + pageround + j, 0); + } + + vmem_xfree(window->map->vmem, pageround, roundedsize); + } + + return (0); +} + Added: projects/pseries/powerpc/pseries/plpar_iommu.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ projects/pseries/powerpc/pseries/plpar_iommu.h Sun Sep 15 21:18:50 2013 (r255603) @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2013, Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PSERIES_PHYP_IOMMU_H_ +#define _PSERIES_PHYP_IOMMU_H_ + +#include +#include + +int phyp_iommu_set_dma_tag(device_t dev, device_t child, bus_dma_tag_t tag); +int phyp_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs, + bus_addr_t min, bus_addr_t max, bus_size_t alignment, bus_addr_t boundary, + void *cookie); +int phyp_iommu_unmap(device_t dev, bus_dma_segment_t *segs, int nsegs, + void *cookie); + +#endif + Modified: projects/pseries/powerpc/pseries/rtas_pci.c ============================================================================== --- projects/pseries/powerpc/pseries/rtas_pci.c Sun Sep 15 16:27:25 2013 (r255602) +++ projects/pseries/powerpc/pseries/rtas_pci.c Sun Sep 15 21:18:50 2013 (r255603) @@ -54,8 +54,10 @@ __FBSDID("$FreeBSD: projects/pseries/pow #include #include +#include #include "pcib_if.h" +#include "iommu_if.h" /* * Device interface. @@ -72,6 +74,11 @@ static void rtaspci_write_config(device u_int, u_int32_t, int); /* + * IOMMU LPAR interface + */ +static bus_dma_tag_t rtaspci_get_dma_tag(device_t dev, device_t child); + +/* * Driver methods. */ static device_method_t rtaspci_methods[] = { @@ -83,11 +90,19 @@ static device_method_t rtaspci_methods[] DEVMETHOD(pcib_read_config, rtaspci_read_config), DEVMETHOD(pcib_write_config, rtaspci_write_config), + /* IOMMU functions */ + DEVMETHOD(bus_get_dma_tag, rtaspci_get_dma_tag), +#ifdef __powerpc64__ + DEVMETHOD(iommu_map, phyp_iommu_map), + DEVMETHOD(iommu_unmap, phyp_iommu_unmap), +#endif + DEVMETHOD_END }; struct rtaspci_softc { struct ofw_pci_softc pci_sc; + bus_dma_tag_t dma_tag; cell_t read_pci_config, write_pci_config; cell_t ex_read_pci_config, ex_write_pci_config; @@ -134,6 +149,15 @@ rtaspci_attach(device_t dev) OF_getprop(ofw_bus_get_node(dev), "ibm,pci-config-space-type", &sc->sc_extended_config, sizeof(sc->sc_extended_config)); + bus_dma_tag_create(bus_get_dma_tag(dev), + 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, + NULL, NULL, BUS_SPACE_MAXSIZE, 0, BUS_SPACE_MAXSIZE, + 0, NULL, NULL, &sc->dma_tag); +#ifdef __powerpc64__ + if (!(mfmsr() & PSL_HV)) + phyp_iommu_set_dma_tag(dev, dev, sc->dma_tag); +#endif + return (ofw_pci_attach(dev)); } @@ -201,3 +225,12 @@ rtaspci_write_config(device_t dev, u_int width, val, &pcierror); } +static bus_dma_tag_t +rtaspci_get_dma_tag(device_t dev, device_t child) +{ + struct rtaspci_softc *sc; + + sc = device_get_softc(dev); + return (sc->dma_tag); +} +