Home | History | Annotate | Download | only in io
      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