xref: /onnv-gate/usr/src/uts/sun4u/io/pci/pci_devctl.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * PCI nexus HotPlug devctl interface
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate #include <sys/types.h>
33*0Sstevel@tonic-gate #include <sys/conf.h>
34*0Sstevel@tonic-gate #include <sys/kmem.h>
35*0Sstevel@tonic-gate #include <sys/async.h>
36*0Sstevel@tonic-gate #include <sys/sysmacros.h>
37*0Sstevel@tonic-gate #include <sys/sunddi.h>
38*0Sstevel@tonic-gate #include <sys/sunndi.h>
39*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
40*0Sstevel@tonic-gate #include <sys/pci/pci_obj.h>
41*0Sstevel@tonic-gate #include <sys/pci_tools.h>
42*0Sstevel@tonic-gate #include <sys/pci_tools_var.h>
43*0Sstevel@tonic-gate #include <sys/open.h>
44*0Sstevel@tonic-gate #include <sys/errno.h>
45*0Sstevel@tonic-gate #include <sys/file.h>
46*0Sstevel@tonic-gate #include <sys/policy.h>
47*0Sstevel@tonic-gate #include <sys/hotplug/pci/pcihp.h>
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate /*LINTLIBRARY*/
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate static int pci_open(dev_t *devp, int flags, int otyp, cred_t *credp);
52*0Sstevel@tonic-gate static int pci_close(dev_t dev, int flags, int otyp, cred_t *credp);
53*0Sstevel@tonic-gate static int pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
54*0Sstevel@tonic-gate 						cred_t *credp, int *rvalp);
55*0Sstevel@tonic-gate static int pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
56*0Sstevel@tonic-gate     int flags, char *name, caddr_t valuep, int *lengthp);
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate struct cb_ops pci_cb_ops = {
59*0Sstevel@tonic-gate 	pci_open,			/* open */
60*0Sstevel@tonic-gate 	pci_close,			/* close */
61*0Sstevel@tonic-gate 	nodev,				/* strategy */
62*0Sstevel@tonic-gate 	nodev,				/* print */
63*0Sstevel@tonic-gate 	nodev,				/* dump */
64*0Sstevel@tonic-gate 	nodev,				/* read */
65*0Sstevel@tonic-gate 	nodev,				/* write */
66*0Sstevel@tonic-gate 	pci_ioctl,			/* ioctl */
67*0Sstevel@tonic-gate 	nodev,				/* devmap */
68*0Sstevel@tonic-gate 	nodev,				/* mmap */
69*0Sstevel@tonic-gate 	nodev,				/* segmap */
70*0Sstevel@tonic-gate 	nochpoll,			/* poll */
71*0Sstevel@tonic-gate 	pci_prop_op,			/* cb_prop_op */
72*0Sstevel@tonic-gate 	NULL,				/* streamtab */
73*0Sstevel@tonic-gate 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
74*0Sstevel@tonic-gate 	CB_REV,				/* rev */
75*0Sstevel@tonic-gate 	nodev,				/* int (*cb_aread)() */
76*0Sstevel@tonic-gate 	nodev				/* int (*cb_awrite)() */
77*0Sstevel@tonic-gate };
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate /* ARGSUSED3 */
80*0Sstevel@tonic-gate static int
81*0Sstevel@tonic-gate pci_open(dev_t *devp, int flags, int otyp, cred_t *credp)
82*0Sstevel@tonic-gate {
83*0Sstevel@tonic-gate 	pci_t *pci_p;
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	/*
86*0Sstevel@tonic-gate 	 * Make sure the open is for the right file type.
87*0Sstevel@tonic-gate 	 */
88*0Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
89*0Sstevel@tonic-gate 		return (EINVAL);
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	/*
92*0Sstevel@tonic-gate 	 * Get the soft state structure for the device.
93*0Sstevel@tonic-gate 	 */
94*0Sstevel@tonic-gate 	pci_p = DEV_TO_SOFTSTATE(*devp);
95*0Sstevel@tonic-gate 	if (pci_p == NULL)
96*0Sstevel@tonic-gate 		return (ENXIO);
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	/*
99*0Sstevel@tonic-gate 	 * Handle the open by tracking the device state.
100*0Sstevel@tonic-gate 	 */
101*0Sstevel@tonic-gate 	DEBUG2(DBG_OPEN, pci_p->pci_dip, "devp=%x: flags=%x\n", devp, flags);
102*0Sstevel@tonic-gate 	mutex_enter(&pci_p->pci_mutex);
103*0Sstevel@tonic-gate 	if (flags & FEXCL) {
104*0Sstevel@tonic-gate 		if (pci_p->pci_soft_state != PCI_SOFT_STATE_CLOSED) {
105*0Sstevel@tonic-gate 			mutex_exit(&pci_p->pci_mutex);
106*0Sstevel@tonic-gate 			DEBUG0(DBG_OPEN, pci_p->pci_dip, "busy\n");
107*0Sstevel@tonic-gate 			return (EBUSY);
108*0Sstevel@tonic-gate 		}
109*0Sstevel@tonic-gate 		pci_p->pci_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
110*0Sstevel@tonic-gate 	} else {
111*0Sstevel@tonic-gate 		if (pci_p->pci_soft_state == PCI_SOFT_STATE_OPEN_EXCL) {
112*0Sstevel@tonic-gate 			mutex_exit(&pci_p->pci_mutex);
113*0Sstevel@tonic-gate 			DEBUG0(DBG_OPEN, pci_p->pci_dip, "busy\n");
114*0Sstevel@tonic-gate 			return (EBUSY);
115*0Sstevel@tonic-gate 		}
116*0Sstevel@tonic-gate 		pci_p->pci_soft_state = PCI_SOFT_STATE_OPEN;
117*0Sstevel@tonic-gate 	}
118*0Sstevel@tonic-gate 	pci_p->pci_open_count++;
119*0Sstevel@tonic-gate 	mutex_exit(&pci_p->pci_mutex);
120*0Sstevel@tonic-gate 	return (0);
121*0Sstevel@tonic-gate }
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate /* ARGSUSED */
125*0Sstevel@tonic-gate static int
126*0Sstevel@tonic-gate pci_close(dev_t dev, int flags, int otyp, cred_t *credp)
127*0Sstevel@tonic-gate {
128*0Sstevel@tonic-gate 	pci_t *pci_p;
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	if (otyp != OTYP_CHR)
131*0Sstevel@tonic-gate 		return (EINVAL);
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate 	pci_p = DEV_TO_SOFTSTATE(dev);
134*0Sstevel@tonic-gate 	if (pci_p == NULL)
135*0Sstevel@tonic-gate 		return (ENXIO);
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	DEBUG2(DBG_CLOSE, pci_p->pci_dip, "dev=%x: flags=%x\n", dev, flags);
138*0Sstevel@tonic-gate 	mutex_enter(&pci_p->pci_mutex);
139*0Sstevel@tonic-gate 	pci_p->pci_soft_state = PCI_SOFT_STATE_CLOSED;
140*0Sstevel@tonic-gate 	pci_p->pci_open_count = 0;
141*0Sstevel@tonic-gate 	mutex_exit(&pci_p->pci_mutex);
142*0Sstevel@tonic-gate 	return (0);
143*0Sstevel@tonic-gate }
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate /* ARGSUSED */
146*0Sstevel@tonic-gate static int
147*0Sstevel@tonic-gate pci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
148*0Sstevel@tonic-gate {
149*0Sstevel@tonic-gate 	pci_t *pci_p;
150*0Sstevel@tonic-gate 	dev_info_t *dip;
151*0Sstevel@tonic-gate 	struct devctl_iocdata *dcp;
152*0Sstevel@tonic-gate 	uint_t bus_state;
153*0Sstevel@tonic-gate 	int rv = 0;
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 	pci_p = DEV_TO_SOFTSTATE(dev);
156*0Sstevel@tonic-gate 	if (pci_p == NULL)
157*0Sstevel@tonic-gate 		return (ENXIO);
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	dip = pci_p->pci_dip;
160*0Sstevel@tonic-gate 	DEBUG2(DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd);
161*0Sstevel@tonic-gate #ifdef PCI_DMA_TEST
162*0Sstevel@tonic-gate 	if (IS_DMATEST(cmd)) {
163*0Sstevel@tonic-gate 		*rvalp = pci_dma_test(cmd, dip, pci_p, arg);
164*0Sstevel@tonic-gate 		return (0);
165*0Sstevel@tonic-gate 	}
166*0Sstevel@tonic-gate #endif
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	/*
169*0Sstevel@tonic-gate 	 * PCI tools.
170*0Sstevel@tonic-gate 	 */
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	if ((cmd & ~IOCPARM_MASK) == PCITOOL_IOC) {
173*0Sstevel@tonic-gate 		switch (cmd) {
174*0Sstevel@tonic-gate 		case PCITOOL_DEVICE_SET_REG:
175*0Sstevel@tonic-gate 		case PCITOOL_DEVICE_GET_REG:
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 			/* Require full privileges. */
178*0Sstevel@tonic-gate 			if (secpolicy_kmdb(credp))
179*0Sstevel@tonic-gate 				rv = EPERM;
180*0Sstevel@tonic-gate 			else
181*0Sstevel@tonic-gate 				rv = pcitool_dev_reg_ops(
182*0Sstevel@tonic-gate 				    dev, (void *)arg, cmd, mode);
183*0Sstevel@tonic-gate 			break;
184*0Sstevel@tonic-gate 
185*0Sstevel@tonic-gate 		case PCITOOL_NEXUS_SET_REG:
186*0Sstevel@tonic-gate 		case PCITOOL_NEXUS_GET_REG:
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 			/* Require full privileges. */
189*0Sstevel@tonic-gate 			if (secpolicy_kmdb(credp))
190*0Sstevel@tonic-gate 				rv = EPERM;
191*0Sstevel@tonic-gate 			else
192*0Sstevel@tonic-gate 				rv = pcitool_bus_reg_ops(
193*0Sstevel@tonic-gate 				    dev, (void *)arg, cmd, mode);
194*0Sstevel@tonic-gate 			break;
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 		case PCITOOL_DEVICE_SET_INTR:
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 			/* Require PRIV_SYS_RES_CONFIG, same as psradm */
199*0Sstevel@tonic-gate 			if (secpolicy_ponline(credp)) {
200*0Sstevel@tonic-gate 				rv = EPERM;
201*0Sstevel@tonic-gate 				break;
202*0Sstevel@tonic-gate 			}
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 		/*FALLTHRU*/
205*0Sstevel@tonic-gate 		/* These require no special privileges. */
206*0Sstevel@tonic-gate 		case PCITOOL_DEVICE_GET_INTR:
207*0Sstevel@tonic-gate 		case PCITOOL_DEVICE_NUM_INTR:
208*0Sstevel@tonic-gate 			rv = pcitool_intr_admn(dev, (void *)arg, cmd, mode);
209*0Sstevel@tonic-gate 			break;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 		default:
212*0Sstevel@tonic-gate 			rv = ENOTTY;
213*0Sstevel@tonic-gate 			break;
214*0Sstevel@tonic-gate 		}
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate 		return (rv);
217*0Sstevel@tonic-gate 	}
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	/*
220*0Sstevel@tonic-gate 	 * We can use the generic implementation for these ioctls
221*0Sstevel@tonic-gate 	 */
222*0Sstevel@tonic-gate 	switch (cmd) {
223*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_GETSTATE:
224*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_ONLINE:
225*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_OFFLINE:
226*0Sstevel@tonic-gate 	case DEVCTL_BUS_GETSTATE:
227*0Sstevel@tonic-gate 		return (ndi_devctl_ioctl(dip, cmd, arg, mode, 0));
228*0Sstevel@tonic-gate 	}
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	/*
231*0Sstevel@tonic-gate 	 * read devctl ioctl data
232*0Sstevel@tonic-gate 	 */
233*0Sstevel@tonic-gate 	if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
234*0Sstevel@tonic-gate 		return (EFAULT);
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	switch (cmd) {
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	case DEVCTL_DEVICE_RESET:
239*0Sstevel@tonic-gate 		DEBUG0(DBG_IOCTL, dip, "DEVCTL_DEVICE_RESET\n");
240*0Sstevel@tonic-gate 		rv = ENOTSUP;
241*0Sstevel@tonic-gate 		break;
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	case DEVCTL_BUS_QUIESCE:
245*0Sstevel@tonic-gate 		DEBUG0(DBG_IOCTL, dip, "DEVCTL_BUS_QUIESCE\n");
246*0Sstevel@tonic-gate 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
247*0Sstevel@tonic-gate 			if (bus_state == BUS_QUIESCED)
248*0Sstevel@tonic-gate 				break;
249*0Sstevel@tonic-gate 		(void) ndi_set_bus_state(dip, BUS_QUIESCED);
250*0Sstevel@tonic-gate 		break;
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	case DEVCTL_BUS_UNQUIESCE:
253*0Sstevel@tonic-gate 		DEBUG0(DBG_IOCTL, dip, "DEVCTL_BUS_UNQUIESCE\n");
254*0Sstevel@tonic-gate 		if (ndi_get_bus_state(dip, &bus_state) == NDI_SUCCESS)
255*0Sstevel@tonic-gate 			if (bus_state == BUS_ACTIVE)
256*0Sstevel@tonic-gate 				break;
257*0Sstevel@tonic-gate 		(void) ndi_set_bus_state(dip, BUS_ACTIVE);
258*0Sstevel@tonic-gate 		break;
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	case DEVCTL_BUS_RESET:
261*0Sstevel@tonic-gate 		DEBUG0(DBG_IOCTL, dip, "DEVCTL_BUS_RESET\n");
262*0Sstevel@tonic-gate 		rv = ENOTSUP;
263*0Sstevel@tonic-gate 		break;
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	case DEVCTL_BUS_RESETALL:
266*0Sstevel@tonic-gate 		DEBUG0(DBG_IOCTL, dip, "DEVCTL_BUS_RESETALL\n");
267*0Sstevel@tonic-gate 		rv = ENOTSUP;
268*0Sstevel@tonic-gate 		break;
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	default:
271*0Sstevel@tonic-gate 		rv = ENOTTY;
272*0Sstevel@tonic-gate 	}
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	ndi_dc_freehdl(dcp);
275*0Sstevel@tonic-gate 	return (rv);
276*0Sstevel@tonic-gate }
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate static int pci_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
279*0Sstevel@tonic-gate     int flags, char *name, caddr_t valuep, int *lengthp)
280*0Sstevel@tonic-gate {
281*0Sstevel@tonic-gate 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
282*0Sstevel@tonic-gate 	    "hotplug-capable"))
283*0Sstevel@tonic-gate 		return ((pcihp_get_cb_ops())->cb_prop_op(dev, dip,
284*0Sstevel@tonic-gate 		    prop_op, flags, name, valuep, lengthp));
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp));
287*0Sstevel@tonic-gate }
288