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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* from 4.1.1 sbusdev/dmaga.c 1.14 */ 28 29 /* 30 * SBus DMA gate array 'driver' 31 */ 32 33 #include <sys/debug.h> 34 #include <sys/types.h> 35 #include <sys/kmem.h> 36 #include <sys/modctl.h> 37 #include <sys/conf.h> 38 #include <sys/ddi.h> 39 #include <sys/sunddi.h> 40 #include <sys/ddi_impldefs.h> 41 #include <sys/ddi_subrdefs.h> 42 #include <sys/dmaga.h> 43 44 typedef struct dma_softc { 45 struct dma_softc *dma_next; /* next in a linked list */ 46 struct dmaga *dma_regs; /* pointer to mapped in registers */ 47 dev_info_t *dma_dev; /* backpointer to dev structure */ 48 int dma_use; /* use count */ 49 } dma_softc_t; 50 51 static dma_softc_t *dma_softc; 52 53 static int dmaattach(dev_info_t *dev, ddi_attach_cmd_t cmd); 54 static int dmadetach(dev_info_t *dev, ddi_detach_cmd_t cmd); 55 56 /* 57 * Configuration data structures 58 */ 59 static struct cb_ops dma_cb_ops = { 60 nodev, /* open */ 61 nodev, /* close */ 62 nodev, /* strategy */ 63 nodev, /* print */ 64 nodev, /* dump */ 65 nodev, /* read */ 66 nodev, /* write */ 67 nodev, /* ioctl */ 68 nodev, /* devmap */ 69 nodev, /* mmap */ 70 nodev, /* segmap */ 71 nochpoll, /* poll */ 72 ddi_prop_op, /* cb_prop_op */ 73 0, /* streamtab */ 74 D_MP | D_HOTPLUG, /* Driver compatibility flag */ 75 CB_REV, /* rev */ 76 nodev, /* int (*cb_aread)() */ 77 nodev /* int (*cb_awrite)() */ 78 }; 79 80 static struct bus_ops dma_bus_ops = { 81 BUSO_REV, 82 i_ddi_bus_map, 83 0, 84 0, 85 0, 86 i_ddi_map_fault, 87 ddi_dma_map, 88 ddi_dma_allochdl, 89 ddi_dma_freehdl, 90 ddi_dma_bindhdl, 91 ddi_dma_unbindhdl, 92 ddi_dma_flush, 93 ddi_dma_win, 94 ddi_dma_mctl, 95 ddi_ctlops, 96 ddi_bus_prop_op, 97 0, /* (*bus_get_eventcookie)(); */ 98 0, /* (*bus_add_eventcall)(); */ 99 0, /* (*bus_remove_eventcall)(); */ 100 0, /* (*bus_post_event)(); */ 101 0, /* bus_intr_ctl */ 102 0, /* bus_config */ 103 0, /* bus_unconfig */ 104 0, /* bus_fm_init */ 105 0, /* bus_fm_fini */ 106 0, /* bus_fm_access_enter */ 107 0, /* bus_fm_access_exit */ 108 0, /* bus_power */ 109 i_ddi_intr_ops /* bus_intr_op */ 110 }; 111 112 static struct dev_ops dma_ops = { 113 114 DEVO_REV, /* devo_rev, */ 115 0, /* refcnt */ 116 ddi_no_info, /* info */ 117 nulldev, /* identify */ 118 nulldev, /* probe */ 119 dmaattach, /* attach */ 120 dmadetach, /* detach */ 121 nodev, /* reset */ 122 &dma_cb_ops, /* driver operations */ 123 &dma_bus_ops, /* bus operations */ 124 nulldev, /* power */ 125 ddi_quiesce_not_supported, /* devo_quiesce */ 126 }; 127 128 static struct modldrv modldrv = { 129 &mod_driverops, /* Type of module. This one is a driver */ 130 "Direct Memory Access driver", /* Name and version */ 131 &dma_ops, /* driver ops */ 132 }; 133 134 static struct modlinkage modlinkage = { 135 MODREV_1, (void *)&modldrv, 0 136 }; 137 138 static kmutex_t dmaautolock; 139 140 int 141 _init(void) 142 { 143 int status; 144 145 mutex_init(&dmaautolock, NULL, MUTEX_DRIVER, NULL); 146 status = mod_install(&modlinkage); 147 if (status != 0) { 148 mutex_destroy(&dmaautolock); 149 } 150 return (status); 151 } 152 153 int 154 _fini(void) 155 { 156 int status; 157 158 status = mod_remove(&modlinkage); 159 if (status == 0) { 160 mutex_destroy(&dmaautolock); 161 } 162 return (status); 163 } 164 165 int 166 _info(struct modinfo *modinfop) 167 { 168 return (mod_info(&modlinkage, modinfop)); 169 } 170 171 /*ARGSUSED1*/ 172 static int 173 dmaattach(dev_info_t *dev, ddi_attach_cmd_t cmd) 174 { 175 dma_softc_t *dp; 176 177 switch (cmd) { 178 case DDI_ATTACH: 179 break; 180 181 case DDI_RESUME: 182 return (DDI_SUCCESS); 183 184 default: 185 return (DDI_FAILURE); 186 } 187 188 dp = (dma_softc_t *)kmem_zalloc(sizeof (dma_softc_t), KM_SLEEP); 189 190 /* 191 * map in the device registers 192 */ 193 if (ddi_map_regs(dev, 0, (caddr_t *)&dp->dma_regs, 0, 0)) { 194 cmn_err(CE_WARN, "dma%d: unable to map registers", 195 ddi_get_instance(dev)); 196 kmem_free(dp, sizeof (dma_softc_t)); 197 return (DDI_FAILURE); 198 } 199 200 ddi_set_driver_private(dev, dp); 201 202 dp->dma_dev = dev; 203 mutex_enter(&dmaautolock); 204 dp->dma_next = dma_softc; 205 dma_softc = dp; 206 mutex_exit(&dmaautolock); 207 ddi_report_dev(dev); 208 return (DDI_SUCCESS); 209 } 210 211 /*ARGSUSED*/ 212 static int 213 dmadetach(dev_info_t *devi, ddi_detach_cmd_t cmd) 214 { 215 dma_softc_t *dp, *pdp = NULL; 216 217 switch (cmd) { 218 case DDI_SUSPEND: 219 return (DDI_SUCCESS); 220 221 case DDI_DETACH: 222 mutex_enter(&dmaautolock); 223 for (dp = dma_softc; dp; pdp = dp, dp = dp->dma_next) { 224 if (dp->dma_dev == devi) 225 break; 226 } 227 ASSERT(dp != NULL); 228 if (dp->dma_use) { 229 mutex_exit(&dmaautolock); 230 return (DDI_FAILURE); 231 } 232 if (dma_softc == dp) { 233 dma_softc = dp->dma_next; 234 } else if (dp->dma_next == NULL) { 235 pdp->dma_next = NULL; 236 } else { 237 pdp->dma_next = dp->dma_next; 238 } 239 mutex_exit(&dmaautolock); 240 ddi_unmap_regs(devi, 0, (caddr_t *)(&dp->dma_regs), 0, 0); 241 kmem_free(dp, sizeof (dma_softc_t)); 242 return (DDI_SUCCESS); 243 244 default: 245 return (DDI_FAILURE); 246 } 247 } 248 249 /* 250 * For DMA debugging: 251 * 252 * #define DMA_ALLOC_DEBUG 253 */ 254 255 #ifdef DMA_ALLOC_DEBUG 256 int dma_alloc_debug = 1; 257 #endif /* DMA_ALLOC_DEBUG */ 258 259 struct dmaga * 260 dma_alloc(dev_info_t *cdev) 261 { 262 dma_softc_t *dp; 263 264 /* 265 * What we need to do is 'find' the dma gate array 266 * 'associated' with the caller. 267 * 268 * We first try to find a dma gate array which is the 269 * parent of the caller. 270 */ 271 for (dp = dma_softc; dp; dp = dp->dma_next) { 272 if (ddi_get_parent(cdev) == dp->dma_dev) { 273 dp->dma_use++; 274 #ifdef DMA_ALLOC_DEBUG 275 if (dma_alloc_debug) { 276 cmn_err(CE_CONT, 277 "?dma_alloc %s esp%d -> %s dma%d (dp %x)", 278 ddi_get_name(cdev), ddi_get_instance(cdev), 279 ddi_get_name(dp->dma_dev), 280 ddi_get_instance(dp->dma_dev), dp); 281 } 282 #endif /* DMA_ALLOC_DEBUG */ 283 return (dp->dma_regs); 284 } 285 } 286 287 /* 288 * Next we try to find a dma gate array by checking the 289 * 'reg' property 290 */ 291 for (dp = dma_softc; dp; dp = dp->dma_next) { 292 if (dma_affinity(dp->dma_dev, cdev) == DDI_SUCCESS) { 293 dp->dma_use++; 294 #ifdef DMA_ALLOC_DEBUG 295 if (dma_alloc_debug) { 296 cmn_err(CE_CONT, 297 "?dma_alloc %s esp%d -> %s dma%d (dp %x)", 298 ddi_get_name(cdev), ddi_get_instance(cdev), 299 ddi_get_name(dp->dma_dev), 300 ddi_get_instance(dp->dma_dev), dp); 301 } 302 #endif /* DMA_ALLOC_DEBUG */ 303 return (dp->dma_regs); 304 } 305 } 306 307 /* 308 * Next we try to find a dma gate array which claims 'affinity' 309 */ 310 for (dp = dma_softc; dp; dp = dp->dma_next) { 311 if (ddi_dev_affinity(dp->dma_dev, cdev) == DDI_SUCCESS) { 312 dp->dma_use++; 313 #ifdef DMA_ALLOC_DEBUG 314 if (dma_alloc_debug) { 315 cmn_err(CE_CONT, 316 "?dma_alloc %s esp%d -> %s dma%d (dp %x)", 317 ddi_get_name(cdev), ddi_get_instance(cdev), 318 ddi_get_name(dp->dma_dev), 319 ddi_get_instance(dp->dma_dev), dp); 320 } 321 #endif /* DMA_ALLOC_DEBUG */ 322 return (dp->dma_regs); 323 } 324 } 325 326 #ifdef DMA_ALLOC_DEBUG 327 if (dma_alloc_debug) 328 cmn_err(CE_CONT, "?dma_alloc returns 0"); 329 #endif /* DMA_ALLOC_DEBUG */ 330 331 return ((struct dmaga *)0); 332 } 333 334 void 335 dma_free(struct dmaga *regs) 336 { 337 dma_softc_t *dp; 338 339 /* 340 * We used to lock exclusive access upon the mapped 341 * in registers for the DMA gate array, but this has 342 * not been actually ever needed. If we end up needing 343 * it, then this routine becomes useful for that. 344 * 345 * Barring that, this routine is useful for tracking 346 * who might still be using a dma gate array's registers. 347 * 348 * XXX We should probably complain if the dma_use count 349 * goes negative. 350 */ 351 for (dp = dma_softc; dp; dp = dp->dma_next) { 352 if (dp->dma_regs == regs) { 353 dp->dma_use--; 354 if (dp->dma_use <= 0) 355 dp->dma_use = 0; 356 break; 357 } 358 } 359 } 360 361 /* 362 * this is a workaround for 1149413. If multiple scsi cards show 363 * up in one SBus slot we have a problem. If we can't figure out the 364 * correct dma engine by looking at the parent and if we don't have 365 * a nexus driver that handles affinity we 'guess' the right dma 366 * engine by looking at the 'reg' property of dma engine and scsi 367 * card. If they have the right 'distance' we assume we got the 368 * right one. This turns out to be only a problem for third party 369 * SBus expansion boxes with missing nexus driver and sport8 scsi 370 * cards where esp and dma are siblings. 371 */ 372 373 /* 374 * 'distance' between esp and dma reg property if esp and dma 375 * are siblings in the device tree. 376 */ 377 static int restrict_affinity = 1; 378 static uint_t restrict_affinity_delta = 0x100000; 379 380 int 381 dma_affinity(dev_info_t *dma, dev_info_t *cdev) 382 { 383 uint_t delta; 384 385 if (strcmp(ddi_get_name(cdev), "esp") != 0) { 386 return (DDI_FAILURE); 387 } else if ((DEVI_PD(dma) && sparc_pd_getnreg(dma) > 0) && 388 (DEVI_PD(cdev) && sparc_pd_getnreg(cdev) > 0)) { 389 uint_t slot = sparc_pd_getreg(dma, 0)->regspec_bustype; 390 uint_t slot_b = 391 sparc_pd_getreg(cdev, 0)->regspec_bustype; 392 uint_t addr = sparc_pd_getreg(dma, 0)->regspec_addr; 393 uint_t addr_b = 394 sparc_pd_getreg(cdev, 0)->regspec_addr; 395 if (addr > addr_b) { 396 delta = addr - addr_b; 397 } else { 398 delta = addr_b - addr; 399 } 400 if ((slot == slot_b) && (!restrict_affinity || 401 (restrict_affinity_delta == delta))) 402 return (DDI_SUCCESS); 403 } 404 return (DDI_FAILURE); 405 } 406