1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright (c) 2016 by Delphix. All rights reserved. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <sys/types.h> 31 #include <sys/kmem.h> 32 #include <sys/systm.h> 33 #include <sys/ddi.h> 34 #include <sys/sunddi.h> 35 #include <sys/sunndi.h> 36 #include <sys/ddidmareq.h> 37 #include <sys/ddi_impldefs.h> 38 #include <sys/ndi_impldefs.h> 39 #include <sys/fcode.h> 40 41 /* 42 * We want to call the attachment point's dma ctl op, not its parent's 43 * dma ctl op, so we have to code this ourselves. 44 */ 45 46 int 47 fc_ddi_dma_alloc_handle(dev_info_t *dip, ddi_dma_attr_t *attr, 48 int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep) 49 { 50 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_attr_t *, 51 int (*)(caddr_t), caddr_t, ddi_dma_handle_t *); 52 53 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_allochdl; 54 return ((*funcp)(dip, dip, attr, waitfp, arg, handlep)); 55 } 56 57 int 58 fc_ddi_dma_buf_bind_handle(ddi_dma_handle_t handle, struct buf *bp, 59 uint_t flags, int (*waitfp)(caddr_t), caddr_t arg, 60 ddi_dma_cookie_t *cookiep, uint_t *ccountp) 61 { 62 struct ddi_dma_req dmareq; 63 ddi_dma_impl_t *hp; 64 dev_info_t *dip; 65 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t, 66 struct ddi_dma_req *, ddi_dma_cookie_t *, uint_t *); 67 68 hp = (ddi_dma_impl_t *)handle; 69 dip = hp->dmai_rdip; 70 71 dmareq.dmar_flags = flags; 72 dmareq.dmar_fp = waitfp; 73 dmareq.dmar_arg = arg; 74 dmareq.dmar_object.dmao_size = (uint_t)bp->b_bcount; 75 76 if ((bp->b_flags & (B_PAGEIO|B_REMAPPED)) == B_PAGEIO) { 77 dmareq.dmar_object.dmao_type = DMA_OTYP_PAGES; 78 dmareq.dmar_object.dmao_obj.pp_obj.pp_pp = bp->b_pages; 79 dmareq.dmar_object.dmao_obj.pp_obj.pp_offset = 80 (uint_t)(((uintptr_t)bp->b_un.b_addr) & MMU_PAGEOFFSET); 81 } else { 82 dmareq.dmar_object.dmao_obj.virt_obj.v_addr = bp->b_un.b_addr; 83 if ((bp->b_flags & (B_SHADOW|B_REMAPPED)) == B_SHADOW) { 84 dmareq.dmar_object.dmao_obj.virt_obj.v_priv = 85 bp->b_shadow; 86 dmareq.dmar_object.dmao_type = DMA_OTYP_BUFVADDR; 87 } else { 88 dmareq.dmar_object.dmao_type = 89 (bp->b_flags & (B_PHYS | B_REMAPPED))? 90 DMA_OTYP_BUFVADDR : DMA_OTYP_VADDR; 91 dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL; 92 } 93 94 /* 95 * If the buffer has no proc pointer, or the proc 96 * struct has the kernel address space, or the buffer has 97 * been marked B_REMAPPED (meaning that it is now 98 * mapped into the kernel's address space), then 99 * the address space is kas (kernel address space). 100 */ 101 if (bp->b_proc == NULL || bp->b_proc->p_as == &kas || 102 (bp->b_flags & B_REMAPPED) != 0) { 103 dmareq.dmar_object.dmao_obj.virt_obj.v_as = 0; 104 } else { 105 dmareq.dmar_object.dmao_obj.virt_obj.v_as = 106 bp->b_proc->p_as; 107 } 108 } 109 110 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_bindhdl; 111 return ((*funcp)(dip, dip, handle, &dmareq, cookiep, ccountp)); 112 } 113 114 int 115 fc_ddi_dma_unbind_handle(ddi_dma_handle_t handle) 116 { 117 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t); 118 ddi_dma_impl_t *hp; 119 dev_info_t *dip; 120 121 hp = (ddi_dma_impl_t *)handle; 122 dip = hp->dmai_rdip; 123 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl; 124 return ((*funcp)(dip, dip, handle)); 125 } 126 127 void 128 fc_ddi_dma_free_handle(ddi_dma_handle_t *handlep) 129 { 130 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t); 131 ddi_dma_impl_t *hp; 132 dev_info_t *dip; 133 134 hp = (ddi_dma_impl_t *)*handlep; 135 dip = hp->dmai_rdip; 136 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_freehdl; 137 (void) (*funcp)(dip, dip, *handlep); 138 } 139 140 int 141 fc_ddi_dma_sync(ddi_dma_handle_t h, off_t o, size_t l, uint_t whom) 142 { 143 ddi_dma_impl_t *hp = (ddi_dma_impl_t *)h; 144 dev_info_t *dip; 145 int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t, off_t, 146 size_t, uint_t); 147 148 /* 149 * the DMA nexus driver will set DMP_NOSYNC if the 150 * platform does not require any sync operation. For 151 * example if the memory is uncached or consistent 152 * and without any I/O write buffers involved. 153 */ 154 if ((hp->dmai_rflags & DMP_NOSYNC) == DMP_NOSYNC) 155 return (DDI_SUCCESS); 156 157 dip = hp->dmai_rdip; 158 funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_flush; 159 return ((*funcp)(dip, dip, h, o, l, whom)); 160 } 161 162 /* 163 * Create untyped properties, just like 1275 properties. 164 * XXX: Assumes property encoding is the natural byte order. 165 */ 166 int 167 fc_ndi_prop_update(dev_t match_dev, dev_info_t *dip, 168 char *name, uchar_t *data, uint_t nelements) 169 { 170 return (ddi_prop_update_common(match_dev, dip, 171 DDI_PROP_HW_DEF | DDI_PROP_TYPE_ANY, 172 name, data, nelements, ddi_prop_fm_encode_bytes)); 173 } 174