1 1.7 thorpej /* $NetBSD: uturn.c,v 1.7 2023/12/03 02:17:06 thorpej Exp $ */ 2 1.1 skrll 3 1.1 skrll /* $OpenBSD: uturn.c,v 1.6 2007/12/29 01:26:14 kettenis Exp $ */ 4 1.1 skrll 5 1.1 skrll /*- 6 1.1 skrll * Copyright (c) 2012 The NetBSD Foundation, Inc. 7 1.1 skrll * All rights reserved. 8 1.1 skrll * 9 1.1 skrll * This code is derived from software contributed to The NetBSD Foundation 10 1.1 skrll * by Nick Hudson. 11 1.1 skrll * 12 1.1 skrll * Redistribution and use in source and binary forms, with or without 13 1.1 skrll * modification, are permitted provided that the following conditions 14 1.1 skrll * are met: 15 1.1 skrll * 1. Redistributions of source code must retain the above copyright 16 1.1 skrll * notice, this list of conditions and the following disclaimer. 17 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright 18 1.1 skrll * notice, this list of conditions and the following disclaimer in the 19 1.1 skrll * documentation and/or other materials provided with the distribution. 20 1.1 skrll * 21 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 1.1 skrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 1.1 skrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 1.1 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 1.1 skrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 1.1 skrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 1.1 skrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.1 skrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.1 skrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.1 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 1.1 skrll * POSSIBILITY OF SUCH DAMAGE. 32 1.1 skrll */ 33 1.1 skrll 34 1.1 skrll /* 35 1.1 skrll * Copyright (c) 2007 Mark Kettenis 36 1.1 skrll * 37 1.1 skrll * Permission to use, copy, modify, and distribute this software for any 38 1.1 skrll * purpose with or without fee is hereby granted, provided that the above 39 1.1 skrll * copyright notice and this permission notice appear in all copies. 40 1.1 skrll * 41 1.1 skrll * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 42 1.1 skrll * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 43 1.1 skrll * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 44 1.1 skrll * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 45 1.1 skrll * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 46 1.1 skrll * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 47 1.1 skrll * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 48 1.1 skrll */ 49 1.1 skrll 50 1.1 skrll /* 51 1.1 skrll * Copyright (c) 2004 Michael Shalayeff 52 1.1 skrll * All rights reserved. 53 1.1 skrll * 54 1.1 skrll * Redistribution and use in source and binary forms, with or without 55 1.1 skrll * modification, are permitted provided that the following conditions 56 1.1 skrll * are met: 57 1.1 skrll * 1. Redistributions of source code must retain the above copyright 58 1.1 skrll * notice, this list of conditions and the following disclaimer. 59 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright 60 1.1 skrll * notice, this list of conditions and the following disclaimer in the 61 1.1 skrll * documentation and/or other materials provided with the distribution. 62 1.1 skrll * 63 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 64 1.1 skrll * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 65 1.1 skrll * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 66 1.1 skrll * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 67 1.1 skrll * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 1.1 skrll * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 69 1.1 skrll * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 1.1 skrll * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 71 1.1 skrll * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 72 1.1 skrll * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 73 1.1 skrll * THE POSSIBILITY OF SUCH DAMAGE. 74 1.1 skrll */ 75 1.1 skrll 76 1.1 skrll /* 77 1.1 skrll * References: 78 1.1 skrll * 1. Hardware Cache Coherent Input/Output. Hewlett-Packard Journal, February 79 1.1 skrll * 1996. 80 1.1 skrll * 2. PA-RISC 1.1 Architecture and Instruction Set Reference Manual, 81 1.1 skrll * Hewlett-Packard, February 1994, Third Edition 82 1.1 skrll */ 83 1.1 skrll 84 1.1 skrll #include <sys/param.h> 85 1.6 skrll 86 1.1 skrll #include <sys/systm.h> 87 1.1 skrll #include <sys/device.h> 88 1.7 thorpej #include <sys/vmem.h> 89 1.6 skrll #include <sys/kmem.h> 90 1.1 skrll #include <sys/mbuf.h> 91 1.6 skrll #include <sys/reboot.h> 92 1.1 skrll #include <sys/tree.h> 93 1.1 skrll 94 1.1 skrll #include <uvm/uvm.h> 95 1.1 skrll 96 1.1 skrll #include <sys/bus.h> 97 1.1 skrll #include <machine/iomod.h> 98 1.1 skrll #include <machine/autoconf.h> 99 1.1 skrll 100 1.1 skrll #include <hppa/dev/cpudevs.h> 101 1.1 skrll 102 1.1 skrll #define UTURNDEBUG 103 1.1 skrll #ifdef UTURNDEBUG 104 1.1 skrll 105 1.1 skrll #define DPRINTF(s) do { \ 106 1.1 skrll if (uturndebug) \ 107 1.1 skrll printf s; \ 108 1.1 skrll } while(0) 109 1.1 skrll 110 1.1 skrll int uturndebug = 0; 111 1.1 skrll #else 112 1.1 skrll #define DPRINTF(s) /* */ 113 1.1 skrll #endif 114 1.1 skrll 115 1.1 skrll struct uturn_regs { 116 1.1 skrll /* Runway Supervisory Set */ 117 1.1 skrll int32_t unused1[12]; 118 1.1 skrll uint32_t io_command; /* Offset 12 */ 119 1.1 skrll #define UTURN_CMD_TLB_PURGE 33 /* Purge I/O TLB entry */ 120 1.1 skrll #define UTURN_CMD_TLB_DIRECT_WRITE 35 /* I/O TLB Writes */ 121 1.1 skrll 122 1.1 skrll uint32_t io_status; /* Offset 13 */ 123 1.1 skrll uint32_t io_control; /* Offset 14 */ 124 1.1 skrll #define UTURN_IOCTRL_TLB_REAL 0x00000000 125 1.1 skrll #define UTURN_IOCTRL_TLB_ERROR 0x00010000 126 1.1 skrll #define UTURN_IOCTRL_TLB_NORMAL 0x00020000 127 1.1 skrll 128 1.1 skrll #define UTURN_IOCTRL_MODE_OFF 0x00000000 129 1.1 skrll #define UTURN_IOCTRL_MODE_INCLUDE 0x00000080 130 1.1 skrll #define UTURN_IOCTRL_MODE_PEEK 0x00000180 131 1.1 skrll 132 1.1 skrll #define UTURN_VIRTUAL_MODE \ 133 1.1 skrll (UTURN_IOCTRL_TLB_NORMAL | UTURN_IOCTRL_MODE_INCLUDE) 134 1.1 skrll 135 1.1 skrll #define UTURN_REAL_MODE \ 136 1.1 skrll UTURN_IOCTRL_MODE_INCLUDE 137 1.1 skrll 138 1.1 skrll int32_t unused2[1]; 139 1.1 skrll 140 1.1 skrll /* Runway Auxiliary Register Set */ 141 1.1 skrll uint32_t io_err_resp; /* Offset 0 */ 142 1.1 skrll uint32_t io_err_info; /* Offset 1 */ 143 1.1 skrll uint32_t io_err_req; /* Offset 2 */ 144 1.1 skrll uint32_t io_err_resp_hi; /* Offset 3 */ 145 1.1 skrll uint32_t io_tlb_entry_m; /* Offset 4 */ 146 1.1 skrll uint32_t io_tlb_entry_l; /* Offset 5 */ 147 1.1 skrll uint32_t unused3[1]; 148 1.1 skrll uint32_t io_pdir_base; /* Offset 7 */ 149 1.1 skrll uint32_t io_io_low_hv; /* Offset 8 */ 150 1.1 skrll uint32_t io_io_high_hv; /* Offset 9 */ 151 1.1 skrll uint32_t unused4[1]; 152 1.1 skrll uint32_t io_chain_id_mask; /* Offset 11 */ 153 1.1 skrll uint32_t unused5[2]; 154 1.1 skrll uint32_t io_io_low; /* Offset 14 */ 155 1.1 skrll uint32_t io_io_high; /* Offset 15 */ 156 1.1 skrll }; 157 1.1 skrll 158 1.1 skrll 159 1.1 skrll /* Uturn supports 256 TLB entries */ 160 1.1 skrll #define UTURN_CHAINID_SHIFT 8 161 1.1 skrll #define UTURN_CHAINID_MASK 0xff 162 1.1 skrll #define UTURN_TLB_ENTRIES (1 << UTURN_CHAINID_SHIFT) 163 1.1 skrll 164 1.1 skrll #define UTURN_IOVP_SIZE PAGE_SIZE 165 1.1 skrll #define UTURN_IOVP_SHIFT PAGE_SHIFT 166 1.1 skrll #define UTURN_IOVP_MASK PAGE_MASK 167 1.1 skrll 168 1.1 skrll #define UTURN_IOVA(iovp, off) ((iovp) | (off)) 169 1.1 skrll #define UTURN_IOVP(iova) ((iova) & UTURN_IOVP_MASK) 170 1.1 skrll #define UTURN_IOVA_INDEX(iova) ((iova) >> UTURN_IOVP_SHIFT) 171 1.1 skrll 172 1.1 skrll struct uturn_softc { 173 1.1 skrll device_t sc_dv; 174 1.1 skrll 175 1.1 skrll bus_dma_tag_t sc_dmat; 176 1.1 skrll struct uturn_regs volatile *sc_regs; 177 1.1 skrll uint64_t *sc_pdir; 178 1.1 skrll uint32_t sc_chainid_shift; 179 1.1 skrll 180 1.1 skrll char sc_mapname[20]; 181 1.7 thorpej vmem_t *sc_map; 182 1.1 skrll 183 1.1 skrll struct hppa_bus_dma_tag sc_dmatag; 184 1.1 skrll }; 185 1.1 skrll 186 1.1 skrll /* 187 1.1 skrll * per-map IOVA page table 188 1.1 skrll */ 189 1.1 skrll struct uturn_page_entry { 190 1.1 skrll SPLAY_ENTRY(uturn_page_entry) upe_node; 191 1.1 skrll paddr_t upe_pa; 192 1.1 skrll vaddr_t upe_va; 193 1.1 skrll bus_addr_t upe_iova; 194 1.1 skrll }; 195 1.1 skrll 196 1.1 skrll struct uturn_page_map { 197 1.1 skrll SPLAY_HEAD(uturn_page_tree, uturn_page_entry) upm_tree; 198 1.1 skrll int upm_maxpage; /* Size of allocated page map */ 199 1.1 skrll int upm_pagecnt; /* Number of entries in use */ 200 1.1 skrll struct uturn_page_entry upm_map[1]; 201 1.1 skrll }; 202 1.1 skrll 203 1.1 skrll /* 204 1.1 skrll * per-map UTURN state 205 1.1 skrll */ 206 1.1 skrll struct uturn_map_state { 207 1.1 skrll struct uturn_softc *ums_sc; 208 1.1 skrll bus_addr_t ums_iovastart; 209 1.1 skrll bus_size_t ums_iovasize; 210 1.1 skrll struct uturn_page_map ums_map; /* map must be last (array at end) */ 211 1.1 skrll }; 212 1.1 skrll 213 1.1 skrll int uturnmatch(device_t, cfdata_t, void *); 214 1.1 skrll void uturnattach(device_t, device_t, void *); 215 1.1 skrll static device_t uturn_callback(device_t, struct confargs *); 216 1.1 skrll 217 1.1 skrll CFATTACH_DECL_NEW(uturn, sizeof(struct uturn_softc), 218 1.1 skrll uturnmatch, uturnattach, NULL, NULL); 219 1.1 skrll 220 1.1 skrll extern struct cfdriver uturn_cd; 221 1.1 skrll 222 1.1 skrll int uturn_dmamap_create(void *, bus_size_t, int, bus_size_t, bus_size_t, int, 223 1.1 skrll bus_dmamap_t *); 224 1.1 skrll void uturn_dmamap_destroy(void *, bus_dmamap_t); 225 1.1 skrll int uturn_dmamap_load(void *, bus_dmamap_t, void *, bus_size_t, struct proc *, 226 1.1 skrll int); 227 1.1 skrll int uturn_dmamap_load_mbuf(void *, bus_dmamap_t, struct mbuf *, int); 228 1.1 skrll int uturn_dmamap_load_uio(void *, bus_dmamap_t, struct uio *, int); 229 1.1 skrll int uturn_dmamap_load_raw(void *, bus_dmamap_t, bus_dma_segment_t *, int, 230 1.1 skrll bus_size_t, int); 231 1.1 skrll void uturn_dmamap_unload(void *, bus_dmamap_t); 232 1.1 skrll void uturn_dmamap_sync(void *, bus_dmamap_t, bus_addr_t, bus_size_t, int); 233 1.1 skrll int uturn_dmamem_alloc(void *, bus_size_t, bus_size_t, bus_size_t, 234 1.1 skrll bus_dma_segment_t *, int, int *, int); 235 1.1 skrll void uturn_dmamem_free(void *, bus_dma_segment_t *, int); 236 1.1 skrll int uturn_dmamem_map(void *, bus_dma_segment_t *, int, size_t, void **, int); 237 1.1 skrll void uturn_dmamem_unmap(void *, void *, size_t); 238 1.1 skrll paddr_t uturn_dmamem_mmap(void *, bus_dma_segment_t *, int, off_t, int, int); 239 1.1 skrll 240 1.1 skrll static void uturn_iommu_enter(struct uturn_softc *, bus_addr_t, pa_space_t, 241 1.1 skrll vaddr_t, paddr_t); 242 1.1 skrll static void uturn_iommu_remove(struct uturn_softc *, bus_addr_t, bus_size_t); 243 1.1 skrll 244 1.6 skrll struct uturn_map_state *uturn_iomap_create(int, int); 245 1.1 skrll void uturn_iomap_destroy(struct uturn_map_state *); 246 1.1 skrll int uturn_iomap_insert_page(struct uturn_map_state *, vaddr_t, paddr_t); 247 1.1 skrll bus_addr_t uturn_iomap_translate(struct uturn_map_state *, paddr_t); 248 1.1 skrll void uturn_iomap_clear_pages(struct uturn_map_state *); 249 1.1 skrll 250 1.1 skrll static int uturn_iomap_load_map(struct uturn_softc *, bus_dmamap_t, int); 251 1.1 skrll 252 1.1 skrll const struct hppa_bus_dma_tag uturn_dmat = { 253 1.1 skrll NULL, 254 1.1 skrll uturn_dmamap_create, uturn_dmamap_destroy, 255 1.1 skrll uturn_dmamap_load, uturn_dmamap_load_mbuf, 256 1.1 skrll uturn_dmamap_load_uio, uturn_dmamap_load_raw, 257 1.1 skrll uturn_dmamap_unload, uturn_dmamap_sync, 258 1.1 skrll 259 1.1 skrll uturn_dmamem_alloc, uturn_dmamem_free, uturn_dmamem_map, 260 1.1 skrll uturn_dmamem_unmap, uturn_dmamem_mmap 261 1.1 skrll }; 262 1.1 skrll 263 1.1 skrll int 264 1.1 skrll uturnmatch(device_t parent, cfdata_t cf, void *aux) 265 1.1 skrll { 266 1.1 skrll struct confargs *ca = aux; 267 1.1 skrll 268 1.1 skrll /* there will be only one */ 269 1.1 skrll if (ca->ca_type.iodc_type != HPPA_TYPE_IOA || 270 1.1 skrll ca->ca_type.iodc_sv_model != HPPA_IOA_UTURN) 271 1.1 skrll return 0; 272 1.1 skrll 273 1.1 skrll if (ca->ca_type.iodc_model == 0x58 && 274 1.1 skrll ca->ca_type.iodc_revision >= 0x20) 275 1.1 skrll return 0; 276 1.1 skrll 277 1.1 skrll return 1; 278 1.1 skrll } 279 1.1 skrll 280 1.1 skrll void 281 1.1 skrll uturnattach(device_t parent, device_t self, void *aux) 282 1.1 skrll { 283 1.1 skrll struct confargs *ca = aux, nca; 284 1.1 skrll struct uturn_softc *sc = device_private(self); 285 1.1 skrll bus_space_handle_t ioh; 286 1.1 skrll volatile struct uturn_regs *r; 287 1.1 skrll struct pglist pglist; 288 1.1 skrll int iova_bits; 289 1.1 skrll vaddr_t va; 290 1.1 skrll psize_t size; 291 1.1 skrll int i; 292 1.1 skrll 293 1.1 skrll if (bus_space_map(ca->ca_iot, ca->ca_hpa, IOMOD_HPASIZE, 0, &ioh)) { 294 1.1 skrll aprint_error(": can't map IO space\n"); 295 1.1 skrll return; 296 1.1 skrll } 297 1.1 skrll 298 1.1 skrll sc->sc_dv = self; 299 1.1 skrll sc->sc_dmat = ca->ca_dmatag; 300 1.1 skrll sc->sc_regs = r = bus_space_vaddr(ca->ca_iot, ioh); 301 1.1 skrll 302 1.1 skrll aprint_normal(": %x-%x", r->io_io_low << 16, r->io_io_high << 16); 303 1.1 skrll aprint_normal(": %x-%x", r->io_io_low_hv << 16, r->io_io_high_hv << 16); 304 1.1 skrll 305 1.1 skrll aprint_normal(": %s rev %d\n", 306 1.1 skrll ca->ca_type.iodc_revision < 0x10 ? "U2" : "UTurn", 307 1.1 skrll ca->ca_type.iodc_revision & 0xf); 308 1.1 skrll 309 1.1 skrll /* 310 1.1 skrll * Setup the iommu. 311 1.1 skrll */ 312 1.1 skrll 313 1.1 skrll /* XXX 28 bits gives us 256Mb of iova space */ 314 1.1 skrll /* Calculate based on %age of RAM */ 315 1.1 skrll iova_bits = 28; 316 1.1 skrll 317 1.1 skrll /* 318 1.1 skrll * size is # of pdir entries (64bits) in bytes. 1 entry per IOVA 319 1.1 skrll * page. 320 1.1 skrll */ 321 1.1 skrll size = (1 << (iova_bits - UTURN_IOVP_SHIFT)) * sizeof(uint64_t); 322 1.1 skrll 323 1.1 skrll /* 324 1.1 skrll * Chainid is the upper most bits of an IOVP used to determine which 325 1.1 skrll * TLB entry an IOVP will use. 326 1.1 skrll */ 327 1.1 skrll sc->sc_chainid_shift = iova_bits - UTURN_CHAINID_SHIFT; 328 1.1 skrll 329 1.1 skrll /* 330 1.1 skrll * Allocate memory for I/O pagetables. They need to be physically 331 1.1 skrll * contiguous. 332 1.1 skrll */ 333 1.1 skrll 334 1.1 skrll if (uvm_pglistalloc(size, 0, -1, PAGE_SIZE, 0, &pglist, 1, 0) != 0) 335 1.1 skrll panic("%s: no memory", __func__); 336 1.1 skrll 337 1.1 skrll va = (vaddr_t)VM_PAGE_TO_PHYS(TAILQ_FIRST(&pglist)); 338 1.1 skrll sc->sc_pdir = (int64_t *)va; 339 1.1 skrll 340 1.1 skrll memset(sc->sc_pdir, 0, size); 341 1.1 skrll 342 1.1 skrll r->io_chain_id_mask = UTURN_CHAINID_MASK << sc->sc_chainid_shift; 343 1.1 skrll r->io_pdir_base = VM_PAGE_TO_PHYS(TAILQ_FIRST(&pglist)); 344 1.1 skrll 345 1.1 skrll r->io_tlb_entry_m = 0; 346 1.1 skrll r->io_tlb_entry_l = 0; 347 1.1 skrll 348 1.1 skrll /* for (i = UTURN_TLB_ENTRIES; i != 0; i--) { */ 349 1.1 skrll for (i = 0; i < UTURN_TLB_ENTRIES; i++) { 350 1.1 skrll r->io_command = 351 1.1 skrll UTURN_CMD_TLB_DIRECT_WRITE | (i << sc->sc_chainid_shift); 352 1.1 skrll } 353 1.1 skrll /* 354 1.1 skrll * Go to "Virtual Mode" 355 1.1 skrll */ 356 1.1 skrll r->io_control = UTURN_VIRTUAL_MODE; 357 1.1 skrll 358 1.1 skrll snprintf(sc->sc_mapname, sizeof(sc->sc_mapname), "%s_map", 359 1.1 skrll device_xname(sc->sc_dv)); 360 1.7 thorpej sc->sc_map = vmem_create(sc->sc_mapname, 361 1.7 thorpej 0, /* base */ 362 1.7 thorpej (1 << iova_bits), /* size */ 363 1.7 thorpej PAGE_SIZE, /* quantum */ 364 1.7 thorpej NULL, /* allocfn */ 365 1.7 thorpej NULL, /* freefn */ 366 1.7 thorpej NULL, /* source */ 367 1.7 thorpej 0, /* qcache_max */ 368 1.7 thorpej VM_SLEEP, 369 1.7 thorpej IPL_VM); 370 1.7 thorpej KASSERT(sc->sc_map != NULL); 371 1.1 skrll 372 1.1 skrll sc->sc_dmatag = uturn_dmat; 373 1.1 skrll sc->sc_dmatag._cookie = sc; 374 1.1 skrll 375 1.1 skrll /* 376 1.1 skrll * U2/UTurn is actually a combination of an Upper Bus Converter (UBC) 377 1.1 skrll * and a Lower Bus Converter (LBC). This driver attaches to the UBC; 378 1.1 skrll * the LBC isn't very interesting, so we skip it. This is easy, since 379 1.1 skrll * it always is module 63, hence the MAXMODBUS - 1 below. 380 1.1 skrll */ 381 1.1 skrll nca = *ca; 382 1.1 skrll nca.ca_hpabase = r->io_io_low << 16; 383 1.1 skrll nca.ca_dmatag = &sc->sc_dmatag; 384 1.1 skrll nca.ca_nmodules = MAXMODBUS - 1; 385 1.1 skrll pdc_scanbus(self, &nca, uturn_callback); 386 1.1 skrll } 387 1.1 skrll 388 1.1 skrll static device_t 389 1.1 skrll uturn_callback(device_t self, struct confargs *ca) 390 1.1 skrll { 391 1.1 skrll 392 1.4 thorpej return config_found(self, ca, mbprint, 393 1.5 thorpej CFARGS(.submatch = mbsubmatch)); 394 1.1 skrll } 395 1.1 skrll 396 1.1 skrll /* 397 1.1 skrll * PDIR entry format (HP bit number) 398 1.1 skrll * 399 1.1 skrll * +-------+----------------+----------------------------------------------+ 400 1.1 skrll * |0 3|4 15|16 31| 401 1.1 skrll * | PPN | Virtual Index | Physical Page Number (PPN) | 402 1.1 skrll * | [0:3] | [0:11] | [4:19] | 403 1.1 skrll * +-------+----------------+----------------------------------------------+ 404 1.2 skrll * 405 1.1 skrll * +-----------------------+-----------------------------------------------+ 406 1.1 skrll * |0 19|20 24| 25 | | | | 30 | 31 | 407 1.1 skrll * | PPN | Rsvd | PH |Update | Rsvd |Lock | Safe | Valid | 408 1.1 skrll * | [20:39 | | Enable |Enable | |Enable| DMA | | 409 1.1 skrll * +-----------------------+-----------------------------------------------+ 410 1.1 skrll * 411 1.1 skrll */ 412 1.1 skrll 413 1.1 skrll #define UTURN_PENTRY_PREFETCH 0x40 414 1.1 skrll #define UTURN_PENTRY_UPDATE 0x20 415 1.1 skrll #define UTURN_PENTRY_LOCK 0x04 /* eisa devices only */ 416 1.1 skrll #define UTURN_PENTRY_SAFEDMA 0x02 /* use safe dma - for subcacheline */ 417 1.1 skrll #define UTURN_PENTRY_VALID 0x01 418 1.1 skrll 419 1.1 skrll static void 420 1.1 skrll uturn_iommu_enter(struct uturn_softc *sc, bus_addr_t iova, pa_space_t sp, 421 1.1 skrll vaddr_t va, paddr_t pa) 422 1.1 skrll { 423 1.1 skrll uint64_t pdir_entry; 424 1.1 skrll uint64_t *pdirp; 425 1.1 skrll uint32_t ci; /* coherent index */ 426 1.1 skrll 427 1.1 skrll pdirp = &sc->sc_pdir[UTURN_IOVA_INDEX(iova)]; 428 1.1 skrll 429 1.1 skrll DPRINTF(("%s: iova %lx pdir %p pdirp %p pa %lx", __func__, iova, 430 1.1 skrll sc->sc_pdir, pdirp, pa)); 431 1.1 skrll 432 1.1 skrll ci = lci(HPPA_SID_KERNEL, va); 433 1.1 skrll 434 1.1 skrll /* setup hints, etc */ 435 1.1 skrll pdir_entry = (UTURN_PENTRY_LOCK | UTURN_PENTRY_SAFEDMA | 436 1.1 skrll UTURN_PENTRY_VALID); 437 1.1 skrll 438 1.1 skrll /* 439 1.1 skrll * bottom 36 bits of pa map directly into entry to form PPN[4:39] 440 1.1 skrll * leaving last 12 bits for hints, etc. 441 1.1 skrll */ 442 1.1 skrll pdir_entry |= (pa & ~PAGE_MASK); 443 1.1 skrll 444 1.1 skrll /* mask off top PPN bits */ 445 1.1 skrll pdir_entry &= 0x0000ffffffffffffUL; 446 1.2 skrll 447 1.1 skrll /* insert the virtual index bits */ 448 1.1 skrll pdir_entry |= (((uint64_t)ci >> 12) << 48); 449 1.1 skrll 450 1.1 skrll /* PPN[0:3] of the 40bit PPN go in entry[0:3] */ 451 1.1 skrll pdir_entry |= ((((uint64_t)pa & 0x000f000000000000UL) >> 48) << 60); 452 1.1 skrll 453 1.1 skrll *pdirp = pdir_entry; 454 1.1 skrll 455 1.1 skrll DPRINTF((": pdir_entry %llx\n", pdir_entry)); 456 1.1 skrll 457 1.1 skrll /* 458 1.1 skrll * We could use PDC_MODEL_CAPABILITIES here 459 1.1 skrll */ 460 1.1 skrll fdcache(HPPA_SID_KERNEL, (vaddr_t)pdirp, sizeof(uint64_t)); 461 1.1 skrll } 462 1.1 skrll 463 1.1 skrll 464 1.1 skrll static void 465 1.1 skrll uturn_iommu_remove(struct uturn_softc *sc, bus_addr_t iova, bus_size_t size) 466 1.1 skrll { 467 1.1 skrll uint32_t chain_size = 1 << sc->sc_chainid_shift; 468 1.1 skrll bus_size_t len; 469 1.1 skrll 470 1.1 skrll KASSERT((iova & PAGE_MASK) == 0); 471 1.1 skrll KASSERT((size & PAGE_MASK) == 0); 472 1.1 skrll 473 1.1 skrll DPRINTF(("%s: sc %p iova %lx size %lx\n", __func__, sc, iova, size)); 474 1.1 skrll len = size; 475 1.1 skrll while (len != 0) { 476 1.1 skrll uint64_t *pdirp = &sc->sc_pdir[UTURN_IOVA_INDEX(iova)]; 477 1.1 skrll 478 1.1 skrll /* XXX Just the valid bit??? */ 479 1.1 skrll *pdirp = 0; 480 1.1 skrll 481 1.1 skrll /* 482 1.1 skrll * We could use PDC_MODEL_CAPABILITIES here 483 1.1 skrll */ 484 1.1 skrll fdcache(HPPA_SID_KERNEL, (vaddr_t)pdirp, sizeof(uint64_t)); 485 1.1 skrll 486 1.1 skrll iova += PAGE_SIZE; 487 1.1 skrll len -= PAGE_SIZE; 488 1.1 skrll } 489 1.1 skrll 490 1.1 skrll len = size + chain_size; 491 1.1 skrll 492 1.1 skrll while (len > chain_size) { 493 1.1 skrll sc->sc_regs->io_command = UTURN_CMD_TLB_PURGE | iova; 494 1.1 skrll iova += chain_size; 495 1.1 skrll len -= chain_size; 496 1.1 skrll } 497 1.1 skrll } 498 1.1 skrll 499 1.1 skrll int 500 1.1 skrll uturn_dmamap_create(void *v, bus_size_t size, int nsegments, 501 1.1 skrll bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamap) 502 1.1 skrll { 503 1.1 skrll struct uturn_softc *sc = v; 504 1.1 skrll bus_dmamap_t map; 505 1.1 skrll struct uturn_map_state *ums; 506 1.1 skrll int error; 507 1.1 skrll 508 1.1 skrll error = bus_dmamap_create(sc->sc_dmat, size, nsegments, maxsegsz, 509 1.1 skrll boundary, flags, &map); 510 1.1 skrll if (error) 511 1.1 skrll return (error); 512 1.1 skrll 513 1.6 skrll ums = uturn_iomap_create(atop(round_page(size)), flags); 514 1.1 skrll if (ums == NULL) { 515 1.1 skrll bus_dmamap_destroy(sc->sc_dmat, map); 516 1.1 skrll return (ENOMEM); 517 1.1 skrll } 518 1.1 skrll 519 1.1 skrll ums->ums_sc = sc; 520 1.1 skrll map->_dm_cookie = ums; 521 1.1 skrll *dmamap = map; 522 1.1 skrll 523 1.1 skrll return (0); 524 1.1 skrll } 525 1.1 skrll 526 1.1 skrll void 527 1.1 skrll uturn_dmamap_destroy(void *v, bus_dmamap_t map) 528 1.1 skrll { 529 1.1 skrll struct uturn_softc *sc = v; 530 1.1 skrll 531 1.1 skrll /* 532 1.1 skrll * The specification (man page) requires a loaded 533 1.1 skrll * map to be unloaded before it is destroyed. 534 1.1 skrll */ 535 1.1 skrll if (map->dm_nsegs) 536 1.1 skrll uturn_dmamap_unload(sc, map); 537 1.1 skrll 538 1.1 skrll if (map->_dm_cookie) 539 1.1 skrll uturn_iomap_destroy(map->_dm_cookie); 540 1.1 skrll map->_dm_cookie = NULL; 541 1.1 skrll 542 1.1 skrll bus_dmamap_destroy(sc->sc_dmat, map); 543 1.1 skrll } 544 1.1 skrll 545 1.1 skrll static int 546 1.1 skrll uturn_iomap_load_map(struct uturn_softc *sc, bus_dmamap_t map, int flags) 547 1.1 skrll { 548 1.1 skrll struct uturn_map_state *ums = map->_dm_cookie; 549 1.1 skrll struct uturn_page_map *upm = &ums->ums_map; 550 1.1 skrll struct uturn_page_entry *e; 551 1.7 thorpej int err, seg; 552 1.1 skrll paddr_t pa, paend; 553 1.1 skrll vaddr_t va; 554 1.1 skrll bus_size_t sgsize; 555 1.1 skrll bus_size_t align, boundary; 556 1.7 thorpej vmem_addr_t iovaddr; 557 1.1 skrll bus_addr_t iova; 558 1.1 skrll int i; 559 1.1 skrll 560 1.1 skrll /* XXX */ 561 1.1 skrll boundary = map->_dm_boundary; 562 1.7 thorpej align = 0; /* align to quantum */ 563 1.1 skrll 564 1.1 skrll uturn_iomap_clear_pages(ums); 565 1.1 skrll 566 1.1 skrll for (seg = 0; seg < map->dm_nsegs; seg++) { 567 1.1 skrll struct hppa_bus_dma_segment *ds = &map->dm_segs[seg]; 568 1.1 skrll 569 1.1 skrll paend = round_page(ds->ds_addr + ds->ds_len); 570 1.1 skrll for (pa = trunc_page(ds->ds_addr), va = trunc_page(ds->_ds_va); 571 1.1 skrll pa < paend; pa += PAGE_SIZE, va += PAGE_SIZE) { 572 1.1 skrll err = uturn_iomap_insert_page(ums, va, pa); 573 1.1 skrll if (err) { 574 1.1 skrll printf("iomap insert error: %d for " 575 1.1 skrll "va 0x%lx pa 0x%lx\n", err, va, pa); 576 1.1 skrll bus_dmamap_unload(sc->sc_dmat, map); 577 1.1 skrll uturn_iomap_clear_pages(ums); 578 1.1 skrll } 579 1.1 skrll } 580 1.1 skrll } 581 1.1 skrll 582 1.7 thorpej const vm_flag_t vmflags = VM_BESTFIT | 583 1.7 thorpej ((flags & BUS_DMA_NOWAIT) ? VM_NOSLEEP : VM_SLEEP); 584 1.7 thorpej 585 1.1 skrll sgsize = ums->ums_map.upm_pagecnt * PAGE_SIZE; 586 1.7 thorpej err = vmem_xalloc(sc->sc_map, sgsize, 587 1.7 thorpej align, /* align */ 588 1.7 thorpej 0, /* phase */ 589 1.7 thorpej boundary, /* nocross */ 590 1.7 thorpej VMEM_ADDR_MIN, /* minaddr */ 591 1.7 thorpej VMEM_ADDR_MAX, /* maxaddr */ 592 1.7 thorpej vmflags, 593 1.7 thorpej &iovaddr); 594 1.1 skrll if (err) 595 1.1 skrll return (err); 596 1.1 skrll 597 1.1 skrll ums->ums_iovastart = iovaddr; 598 1.1 skrll ums->ums_iovasize = sgsize; 599 1.1 skrll 600 1.1 skrll iova = iovaddr; 601 1.1 skrll for (i = 0, e = upm->upm_map; i < upm->upm_pagecnt; ++i, ++e) { 602 1.1 skrll e->upe_iova = iova; 603 1.1 skrll uturn_iommu_enter(sc, e->upe_iova, HPPA_SID_KERNEL, e->upe_va, 604 1.1 skrll e->upe_pa); 605 1.1 skrll iova += PAGE_SIZE; 606 1.1 skrll } 607 1.1 skrll 608 1.1 skrll for (seg = 0; seg < map->dm_nsegs; seg++) { 609 1.1 skrll struct hppa_bus_dma_segment *ds = &map->dm_segs[seg]; 610 1.1 skrll ds->ds_addr = uturn_iomap_translate(ums, ds->ds_addr); 611 1.1 skrll } 612 1.1 skrll 613 1.1 skrll return (0); 614 1.1 skrll } 615 1.1 skrll 616 1.1 skrll int 617 1.1 skrll uturn_dmamap_load(void *v, bus_dmamap_t map, void *addr, bus_size_t size, 618 1.1 skrll struct proc *p, int flags) 619 1.1 skrll { 620 1.1 skrll struct uturn_softc *sc = v; 621 1.1 skrll int err; 622 1.1 skrll 623 1.1 skrll err = bus_dmamap_load(sc->sc_dmat, map, addr, size, p, flags); 624 1.1 skrll if (err) 625 1.1 skrll return (err); 626 1.1 skrll 627 1.1 skrll return uturn_iomap_load_map(sc, map, flags); 628 1.1 skrll } 629 1.1 skrll 630 1.1 skrll int 631 1.1 skrll uturn_dmamap_load_mbuf(void *v, bus_dmamap_t map, struct mbuf *m, int flags) 632 1.1 skrll { 633 1.1 skrll struct uturn_softc *sc = v; 634 1.1 skrll int err; 635 1.1 skrll 636 1.1 skrll err = bus_dmamap_load_mbuf(sc->sc_dmat, map, m, flags); 637 1.1 skrll if (err) 638 1.1 skrll return (err); 639 1.1 skrll 640 1.1 skrll return uturn_iomap_load_map(sc, map, flags); 641 1.1 skrll } 642 1.1 skrll 643 1.1 skrll int 644 1.1 skrll uturn_dmamap_load_uio(void *v, bus_dmamap_t map, struct uio *uio, int flags) 645 1.1 skrll { 646 1.1 skrll struct uturn_softc *sc = v; 647 1.1 skrll 648 1.1 skrll printf("load_uio\n"); 649 1.1 skrll 650 1.1 skrll return (bus_dmamap_load_uio(sc->sc_dmat, map, uio, flags)); 651 1.1 skrll } 652 1.1 skrll 653 1.1 skrll int 654 1.1 skrll uturn_dmamap_load_raw(void *v, bus_dmamap_t map, bus_dma_segment_t *segs, 655 1.1 skrll int nsegs, bus_size_t size, int flags) 656 1.1 skrll { 657 1.1 skrll struct uturn_softc *sc = v; 658 1.1 skrll 659 1.1 skrll printf("load_raw\n"); 660 1.1 skrll 661 1.1 skrll return (bus_dmamap_load_raw(sc->sc_dmat, map, segs, nsegs, size, flags)); 662 1.1 skrll } 663 1.1 skrll 664 1.1 skrll void 665 1.1 skrll uturn_dmamap_unload(void *v, bus_dmamap_t map) 666 1.1 skrll { 667 1.1 skrll struct uturn_softc *sc = v; 668 1.1 skrll struct uturn_map_state *ums = map->_dm_cookie; 669 1.1 skrll struct uturn_page_map *upm = &ums->ums_map; 670 1.1 skrll struct uturn_page_entry *e; 671 1.7 thorpej int i; 672 1.1 skrll 673 1.1 skrll /* Remove the IOMMU entries. */ 674 1.1 skrll for (i = 0, e = upm->upm_map; i < upm->upm_pagecnt; ++i, ++e) 675 1.1 skrll uturn_iommu_remove(sc, e->upe_iova, PAGE_SIZE); 676 1.1 skrll 677 1.1 skrll /* Clear the iomap. */ 678 1.1 skrll uturn_iomap_clear_pages(ums); 679 1.1 skrll 680 1.1 skrll bus_dmamap_unload(sc->sc_dmat, map); 681 1.1 skrll 682 1.7 thorpej vmem_xfree(sc->sc_map, ums->ums_iovastart, ums->ums_iovasize); 683 1.1 skrll ums->ums_iovastart = 0; 684 1.1 skrll ums->ums_iovasize = 0; 685 1.1 skrll } 686 1.1 skrll 687 1.1 skrll void 688 1.1 skrll uturn_dmamap_sync(void *v, bus_dmamap_t map, bus_addr_t off, 689 1.1 skrll bus_size_t len, int ops) 690 1.1 skrll { 691 1.1 skrll /* Nothing to do; DMA is cache-coherent. */ 692 1.1 skrll } 693 1.1 skrll 694 1.1 skrll int 695 1.1 skrll uturn_dmamem_alloc(void *v, bus_size_t size, bus_size_t alignment, 696 1.1 skrll bus_size_t boundary, bus_dma_segment_t *segs, 697 1.1 skrll int nsegs, int *rsegs, int flags) 698 1.1 skrll { 699 1.1 skrll struct uturn_softc *sc = v; 700 1.1 skrll 701 1.1 skrll return (bus_dmamem_alloc(sc->sc_dmat, size, alignment, boundary, 702 1.1 skrll segs, nsegs, rsegs, flags)); 703 1.1 skrll } 704 1.1 skrll 705 1.1 skrll void 706 1.1 skrll uturn_dmamem_free(void *v, bus_dma_segment_t *segs, int nsegs) 707 1.1 skrll { 708 1.1 skrll struct uturn_softc *sc = v; 709 1.1 skrll 710 1.1 skrll bus_dmamem_free(sc->sc_dmat, segs, nsegs); 711 1.1 skrll } 712 1.1 skrll 713 1.1 skrll int 714 1.1 skrll uturn_dmamem_map(void *v, bus_dma_segment_t *segs, int nsegs, size_t size, 715 1.1 skrll void **kvap, int flags) 716 1.1 skrll { 717 1.1 skrll struct uturn_softc *sc = v; 718 1.1 skrll 719 1.1 skrll return (bus_dmamem_map(sc->sc_dmat, segs, nsegs, size, kvap, flags)); 720 1.1 skrll } 721 1.1 skrll 722 1.1 skrll void 723 1.1 skrll uturn_dmamem_unmap(void *v, void *kva, size_t size) 724 1.1 skrll { 725 1.1 skrll struct uturn_softc *sc = v; 726 1.1 skrll 727 1.1 skrll bus_dmamem_unmap(sc->sc_dmat, kva, size); 728 1.1 skrll } 729 1.1 skrll 730 1.1 skrll paddr_t 731 1.1 skrll uturn_dmamem_mmap(void *v, bus_dma_segment_t *segs, int nsegs, off_t off, 732 1.1 skrll int prot, int flags) 733 1.1 skrll { 734 1.1 skrll struct uturn_softc *sc = v; 735 1.1 skrll 736 1.1 skrll return (bus_dmamem_mmap(sc->sc_dmat, segs, nsegs, off, prot, flags)); 737 1.1 skrll } 738 1.1 skrll 739 1.1 skrll /* 740 1.1 skrll * Utility function used by splay tree to order page entries by pa. 741 1.1 skrll */ 742 1.1 skrll static inline int 743 1.1 skrll upe_compare(struct uturn_page_entry *a, struct uturn_page_entry *b) 744 1.1 skrll { 745 1.1 skrll return ((a->upe_pa > b->upe_pa) ? 1 : 746 1.1 skrll (a->upe_pa < b->upe_pa) ? -1 : 0); 747 1.1 skrll } 748 1.1 skrll 749 1.1 skrll SPLAY_PROTOTYPE(uturn_page_tree, uturn_page_entry, upe_node, upe_compare); 750 1.1 skrll 751 1.1 skrll SPLAY_GENERATE(uturn_page_tree, uturn_page_entry, upe_node, upe_compare); 752 1.1 skrll 753 1.1 skrll /* 754 1.1 skrll * Create a new iomap. 755 1.1 skrll */ 756 1.1 skrll struct uturn_map_state * 757 1.6 skrll uturn_iomap_create(int n, int flags) 758 1.1 skrll { 759 1.1 skrll struct uturn_map_state *ums; 760 1.1 skrll 761 1.1 skrll /* Safety for heavily fragmented data, such as mbufs */ 762 1.1 skrll n += 4; 763 1.1 skrll if (n < 16) 764 1.1 skrll n = 16; 765 1.6 skrll const size_t sz = 766 1.6 skrll sizeof(*ums) + (n - 1) * sizeof(ums->ums_map.upm_map[0]); 767 1.6 skrll ums = kmem_zalloc(sz, (flags & BUS_DMA_NOWAIT) ? KM_NOSLEEP : KM_SLEEP); 768 1.1 skrll if (ums == NULL) 769 1.1 skrll return (NULL); 770 1.1 skrll 771 1.1 skrll /* Initialize the map. */ 772 1.1 skrll ums->ums_map.upm_maxpage = n; 773 1.1 skrll SPLAY_INIT(&ums->ums_map.upm_tree); 774 1.1 skrll 775 1.1 skrll return (ums); 776 1.1 skrll } 777 1.1 skrll 778 1.1 skrll /* 779 1.1 skrll * Destroy an iomap. 780 1.1 skrll */ 781 1.1 skrll void 782 1.1 skrll uturn_iomap_destroy(struct uturn_map_state *ums) 783 1.1 skrll { 784 1.1 skrll KASSERT(ums->ums_map.upm_pagecnt == 0); 785 1.6 skrll const int n = ums->ums_map.upm_maxpage; 786 1.6 skrll const size_t sz = 787 1.6 skrll sizeof(*ums) + (n - 1) * sizeof(ums->ums_map.upm_map[0]); 788 1.1 skrll 789 1.6 skrll kmem_free(ums, sz); 790 1.1 skrll } 791 1.1 skrll 792 1.1 skrll /* 793 1.1 skrll * Insert a pa entry in the iomap. 794 1.1 skrll */ 795 1.1 skrll int 796 1.1 skrll uturn_iomap_insert_page(struct uturn_map_state *ums, vaddr_t va, paddr_t pa) 797 1.1 skrll { 798 1.1 skrll struct uturn_page_map *upm = &ums->ums_map; 799 1.1 skrll struct uturn_page_entry *e; 800 1.1 skrll 801 1.1 skrll if (upm->upm_pagecnt >= upm->upm_maxpage) { 802 1.1 skrll struct uturn_page_entry upe; 803 1.1 skrll 804 1.1 skrll upe.upe_pa = pa; 805 1.1 skrll if (SPLAY_FIND(uturn_page_tree, &upm->upm_tree, &upe)) 806 1.1 skrll return (0); 807 1.1 skrll 808 1.1 skrll return (ENOMEM); 809 1.1 skrll } 810 1.1 skrll 811 1.1 skrll e = &upm->upm_map[upm->upm_pagecnt]; 812 1.1 skrll 813 1.1 skrll e->upe_pa = pa; 814 1.1 skrll e->upe_va = va; 815 1.1 skrll e->upe_iova = 0; 816 1.1 skrll 817 1.1 skrll e = SPLAY_INSERT(uturn_page_tree, &upm->upm_tree, e); 818 1.1 skrll 819 1.1 skrll /* Duplicates are okay, but only count them once. */ 820 1.1 skrll if (e) 821 1.1 skrll return (0); 822 1.1 skrll 823 1.1 skrll ++upm->upm_pagecnt; 824 1.1 skrll 825 1.1 skrll return (0); 826 1.1 skrll } 827 1.1 skrll 828 1.1 skrll /* 829 1.1 skrll * Translate a physical address (pa) into a IOVA address. 830 1.1 skrll */ 831 1.1 skrll bus_addr_t 832 1.1 skrll uturn_iomap_translate(struct uturn_map_state *ums, paddr_t pa) 833 1.1 skrll { 834 1.1 skrll struct uturn_page_map *upm = &ums->ums_map; 835 1.1 skrll struct uturn_page_entry *e; 836 1.1 skrll struct uturn_page_entry pe; 837 1.1 skrll paddr_t offset = pa & PAGE_MASK; 838 1.1 skrll 839 1.1 skrll pe.upe_pa = trunc_page(pa); 840 1.1 skrll 841 1.1 skrll e = SPLAY_FIND(uturn_page_tree, &upm->upm_tree, &pe); 842 1.1 skrll 843 1.1 skrll if (e == NULL) { 844 1.1 skrll panic("couldn't find pa %lx\n", pa); 845 1.1 skrll return 0; 846 1.1 skrll } 847 1.1 skrll 848 1.1 skrll return (e->upe_iova | offset); 849 1.1 skrll } 850 1.1 skrll 851 1.1 skrll /* 852 1.1 skrll * Clear the iomap table and tree. 853 1.1 skrll */ 854 1.1 skrll void 855 1.1 skrll uturn_iomap_clear_pages(struct uturn_map_state *ums) 856 1.1 skrll { 857 1.1 skrll ums->ums_map.upm_pagecnt = 0; 858 1.1 skrll SPLAY_INIT(&ums->ums_map.upm_tree); 859 1.1 skrll } 860