Home | History | Annotate | Download | only in px
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * PCI nexus HotPlug devctl interface
     28  */
     29 #include <sys/types.h>
     30 #include <sys/conf.h>
     31 #include <sys/kmem.h>
     32 #include <sys/async.h>
     33 #include <sys/sysmacros.h>
     34 #include <sys/sunddi.h>
     35 #include <sys/sunndi.h>
     36 #include <sys/ddi_impldefs.h>
     37 #include <sys/open.h>
     38 #include <sys/errno.h>
     39 #include <sys/file.h>
     40 #include <sys/policy.h>
     41 #include "px_obj.h"
     42 #include <sys/pci_tools.h>
     43 #include "px_tools_ext.h"
     44 #include <sys/pcie_pwr.h>
     45 
     46 /*LINTLIBRARY*/
     47 
     48 static int px_open(dev_t *devp, int flags, int otyp, cred_t *credp);
     49 static int px_close(dev_t dev, int flags, int otyp, cred_t *credp);
     50 static int px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
     51 						cred_t *credp, int *rvalp);
     52 
     53 struct cb_ops px_cb_ops = {
     54 	px_open,			/* open */
     55 	px_close,			/* close */
     56 	nodev,				/* strategy */
     57 	nodev,				/* print */
     58 	nodev,				/* dump */
     59 	nodev,				/* read */
     60 	nodev,				/* write */
     61 	px_ioctl,			/* ioctl */
     62 	nodev,				/* devmap */
     63 	nodev,				/* mmap */
     64 	nodev,				/* segmap */
     65 	nochpoll,			/* poll */
     66 	pcie_prop_op,			/* cb_prop_op */
     67 	NULL,				/* streamtab */
     68 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
     69 	CB_REV,				/* rev */
     70 	nodev,				/* int (*cb_aread)() */
     71 	nodev				/* int (*cb_awrite)() */
     72 };
     73 
     74 /* ARGSUSED3 */
     75 static int
     76 px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
     77 {
     78 	px_t		*px_p = PX_DEV_TO_SOFTSTATE(*devp);
     79 	int		minor = getminor(*devp);
     80 	int		rval;
     81 
     82 	/*
     83 	 * Make sure the open is for the right file type.
     84 	 */
     85 	if (otyp != OTYP_CHR)
     86 		return (EINVAL);
     87 
     88 	/*
     89 	 * Get the soft state structure for the device.
     90 	 */
     91 	if (px_p == NULL)
     92 		return (ENXIO);
     93 
     94 	DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags);
     95 
     96 	/*
     97 	 * Handle the open by tracking the device state.
     98 	 */
     99 	mutex_enter(&px_p->px_mutex);
    100 
    101 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
    102 	case PCI_TOOL_REG_MINOR_NUM:
    103 	case PCI_TOOL_INTR_MINOR_NUM:
    104 		break;
    105 	default:
    106 		/* To handle devctl and hotplug related ioctls */
    107 		if (rval = pcie_open(px_p->px_dip, devp, flags, otyp, credp)) {
    108 			mutex_exit(&px_p->px_mutex);
    109 			return (rval);
    110 		}
    111 	}
    112 
    113 	if (flags & FEXCL) {
    114 		if (px_p->px_soft_state != PCI_SOFT_STATE_CLOSED) {
    115 			mutex_exit(&px_p->px_mutex);
    116 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
    117 			return (EBUSY);
    118 		}
    119 		px_p->px_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
    120 	} else {
    121 		if (px_p->px_soft_state == PCI_SOFT_STATE_OPEN_EXCL) {
    122 			mutex_exit(&px_p->px_mutex);
    123 			DBG(DBG_OPEN, px_p->px_dip, "busy\n");
    124 			return (EBUSY);
    125 		}
    126 		px_p->px_soft_state = PCI_SOFT_STATE_OPEN;
    127 	}
    128 
    129 	mutex_exit(&px_p->px_mutex);
    130 	return (0);
    131 }
    132 
    133 
    134 /* ARGSUSED */
    135 static int
    136 px_close(dev_t dev, int flags, int otyp, cred_t *credp)
    137 {
    138 	px_t		*px_p = PX_DEV_TO_SOFTSTATE(dev);
    139 	int		minor = getminor(dev);
    140 	int		rval;
    141 
    142 	if (otyp != OTYP_CHR)
    143 		return (EINVAL);
    144 
    145 	if (px_p == NULL)
    146 		return (ENXIO);
    147 
    148 	DBG(DBG_CLOSE, px_p->px_dip, "dev=%x: flags=%x\n", dev, flags);
    149 	mutex_enter(&px_p->px_mutex);
    150 
    151 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
    152 	case PCI_TOOL_REG_MINOR_NUM:
    153 	case PCI_TOOL_INTR_MINOR_NUM:
    154 		break;
    155 	default:
    156 		/* To handle devctl and hotplug related ioctls */
    157 		if (rval = pcie_close(px_p->px_dip, dev, flags, otyp, credp)) {
    158 			mutex_exit(&px_p->px_mutex);
    159 			return (rval);
    160 		}
    161 	}
    162 
    163 	px_p->px_soft_state = PCI_SOFT_STATE_CLOSED;
    164 	mutex_exit(&px_p->px_mutex);
    165 	return (0);
    166 }
    167 
    168 /* ARGSUSED */
    169 static int
    170 px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
    171 {
    172 	px_t		*px_p = PX_DEV_TO_SOFTSTATE(dev);
    173 	int		minor = getminor(dev);
    174 	dev_info_t	*dip;
    175 	int		rv = ENOTTY;
    176 
    177 	if (px_p == NULL)
    178 		return (ENXIO);
    179 
    180 	dip = px_p->px_dip;
    181 	DBG(DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd);
    182 
    183 #ifdef	PX_DMA_TEST
    184 	if (IS_DMATEST(cmd)) {
    185 		*rvalp = px_dma_test(cmd, dip, px_p, arg);
    186 		return (0);
    187 	}
    188 #endif	/* PX_DMA_TEST */
    189 
    190 	switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
    191 	/*
    192 	 * PCI tools.
    193 	 */
    194 	case PCI_TOOL_REG_MINOR_NUM:
    195 		switch (cmd) {
    196 		case PCITOOL_DEVICE_SET_REG:
    197 		case PCITOOL_DEVICE_GET_REG:
    198 
    199 			/* Require full privileges. */
    200 			if (secpolicy_kmdb(credp))
    201 				rv = EPERM;
    202 			else
    203 				rv = pxtool_dev_reg_ops(dip,
    204 				    (void *)arg, cmd, mode);
    205 			break;
    206 
    207 		case PCITOOL_NEXUS_SET_REG:
    208 		case PCITOOL_NEXUS_GET_REG:
    209 
    210 			/* Require full privileges. */
    211 			if (secpolicy_kmdb(credp))
    212 				rv = EPERM;
    213 			else
    214 				rv = pxtool_bus_reg_ops(dip,
    215 				    (void *)arg, cmd, mode);
    216 			break;
    217 
    218 		default:
    219 			rv = ENOTTY;
    220 		}
    221 		return (rv);
    222 	case PCI_TOOL_INTR_MINOR_NUM:
    223 		switch (cmd) {
    224 		case PCITOOL_DEVICE_SET_INTR:
    225 
    226 			/* Require full privileges. */
    227 			if (secpolicy_kmdb(credp)) {
    228 				rv = EPERM;
    229 				break;
    230 			}
    231 
    232 		/*FALLTHRU*/
    233 		/* These require no special privileges. */
    234 		case PCITOOL_DEVICE_GET_INTR:
    235 		case PCITOOL_SYSTEM_INTR_INFO:
    236 			rv = pxtool_intr(dip, (void *)arg, cmd, mode);
    237 			break;
    238 
    239 		default:
    240 			rv = ENOTTY;
    241 		}
    242 		return (rv);
    243 	default:
    244 		/* To handle devctl and hotplug related ioctls */
    245 		rv = pcie_ioctl(dip, dev, cmd, arg, mode, credp, rvalp);
    246 		break;
    247 	}
    248 
    249 	if ((cmd & ~PPMREQ_MASK) == PPMREQ) {
    250 
    251 		/* Need privileges to use these ioctls. */
    252 		if (drv_priv(credp)) {
    253 			DBG(DBG_TOOLS, dip,
    254 			    "px_tools: Insufficient privileges\n");
    255 
    256 			return (EPERM);
    257 		}
    258 		return (px_lib_pmctl(cmd, px_p));
    259 	}
    260 
    261 	return (rv);
    262 }
    263