17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57aadd8d4Skini * Common Development and Distribution License (the "License").
67aadd8d4Skini * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
22d5ace945SErwin T Tsaur * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate */
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * PCI nexus HotPlug devctl interface
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <sys/conf.h>
317c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
327c478bd9Sstevel@tonic-gate #include <sys/async.h>
337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
347c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
357c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
367c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
377c478bd9Sstevel@tonic-gate #include <sys/open.h>
387c478bd9Sstevel@tonic-gate #include <sys/errno.h>
397c478bd9Sstevel@tonic-gate #include <sys/file.h>
4069cd775fSschwartz #include <sys/policy.h>
417c478bd9Sstevel@tonic-gate #include "px_obj.h"
4269cd775fSschwartz #include <sys/pci_tools.h>
43d4476ccbSschwartz #include "px_tools_ext.h"
44d4bc0535SKrishna Elango #include <sys/pcie_pwr.h>
457c478bd9Sstevel@tonic-gate
467c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate static int px_open(dev_t *devp, int flags, int otyp, cred_t *credp);
497c478bd9Sstevel@tonic-gate static int px_close(dev_t dev, int flags, int otyp, cred_t *credp);
507c478bd9Sstevel@tonic-gate static int px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
517c478bd9Sstevel@tonic-gate cred_t *credp, int *rvalp);
527c478bd9Sstevel@tonic-gate
537c478bd9Sstevel@tonic-gate struct cb_ops px_cb_ops = {
547c478bd9Sstevel@tonic-gate px_open, /* open */
557c478bd9Sstevel@tonic-gate px_close, /* close */
567c478bd9Sstevel@tonic-gate nodev, /* strategy */
577c478bd9Sstevel@tonic-gate nodev, /* print */
587c478bd9Sstevel@tonic-gate nodev, /* dump */
597c478bd9Sstevel@tonic-gate nodev, /* read */
607c478bd9Sstevel@tonic-gate nodev, /* write */
617c478bd9Sstevel@tonic-gate px_ioctl, /* ioctl */
627c478bd9Sstevel@tonic-gate nodev, /* devmap */
637c478bd9Sstevel@tonic-gate nodev, /* mmap */
647c478bd9Sstevel@tonic-gate nodev, /* segmap */
657c478bd9Sstevel@tonic-gate nochpoll, /* poll */
66*26947304SEvan Yan pcie_prop_op, /* cb_prop_op */
677c478bd9Sstevel@tonic-gate NULL, /* streamtab */
687c478bd9Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* Driver compatibility flag */
697c478bd9Sstevel@tonic-gate CB_REV, /* rev */
707c478bd9Sstevel@tonic-gate nodev, /* int (*cb_aread)() */
717c478bd9Sstevel@tonic-gate nodev /* int (*cb_awrite)() */
727c478bd9Sstevel@tonic-gate };
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate /* ARGSUSED3 */
757c478bd9Sstevel@tonic-gate static int
px_open(dev_t * devp,int flags,int otyp,cred_t * credp)767c478bd9Sstevel@tonic-gate px_open(dev_t *devp, int flags, int otyp, cred_t *credp)
777c478bd9Sstevel@tonic-gate {
78*26947304SEvan Yan px_t *px_p = PX_DEV_TO_SOFTSTATE(*devp);
79*26947304SEvan Yan int minor = getminor(*devp);
80b65731f1Skini int rval;
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate * Make sure the open is for the right file type.
847c478bd9Sstevel@tonic-gate */
857c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR)
867c478bd9Sstevel@tonic-gate return (EINVAL);
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate /*
897c478bd9Sstevel@tonic-gate * Get the soft state structure for the device.
907c478bd9Sstevel@tonic-gate */
917c478bd9Sstevel@tonic-gate if (px_p == NULL)
927c478bd9Sstevel@tonic-gate return (ENXIO);
937c478bd9Sstevel@tonic-gate
94*26947304SEvan Yan DBG(DBG_OPEN, px_p->px_dip, "devp=%x: flags=%x\n", devp, flags);
95*26947304SEvan Yan
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate * Handle the open by tracking the device state.
987c478bd9Sstevel@tonic-gate */
997c478bd9Sstevel@tonic-gate mutex_enter(&px_p->px_mutex);
100b65731f1Skini
101*26947304SEvan Yan switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
102*26947304SEvan Yan case PCI_TOOL_REG_MINOR_NUM:
103*26947304SEvan Yan case PCI_TOOL_INTR_MINOR_NUM:
104*26947304SEvan Yan break;
105*26947304SEvan Yan default:
106*26947304SEvan Yan /* To handle devctl and hotplug related ioctls */
107*26947304SEvan Yan if (rval = pcie_open(px_p->px_dip, devp, flags, otyp, credp)) {
108b65731f1Skini mutex_exit(&px_p->px_mutex);
109b65731f1Skini return (rval);
110b65731f1Skini }
111*26947304SEvan Yan }
112b65731f1Skini
113*26947304SEvan Yan if (flags & FEXCL) {
114*26947304SEvan Yan if (px_p->px_soft_state != PCI_SOFT_STATE_CLOSED) {
115*26947304SEvan Yan mutex_exit(&px_p->px_mutex);
116*26947304SEvan Yan DBG(DBG_OPEN, px_p->px_dip, "busy\n");
117*26947304SEvan Yan return (EBUSY);
118*26947304SEvan Yan }
119*26947304SEvan Yan px_p->px_soft_state = PCI_SOFT_STATE_OPEN_EXCL;
120*26947304SEvan Yan } else {
121*26947304SEvan Yan if (px_p->px_soft_state == PCI_SOFT_STATE_OPEN_EXCL) {
122*26947304SEvan Yan mutex_exit(&px_p->px_mutex);
123*26947304SEvan Yan DBG(DBG_OPEN, px_p->px_dip, "busy\n");
124*26947304SEvan Yan return (EBUSY);
125*26947304SEvan Yan }
126*26947304SEvan Yan px_p->px_soft_state = PCI_SOFT_STATE_OPEN;
127*26947304SEvan Yan }
128*26947304SEvan Yan
1297c478bd9Sstevel@tonic-gate mutex_exit(&px_p->px_mutex);
1307c478bd9Sstevel@tonic-gate return (0);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate /* ARGSUSED */
1357c478bd9Sstevel@tonic-gate static int
px_close(dev_t dev,int flags,int otyp,cred_t * credp)1367c478bd9Sstevel@tonic-gate px_close(dev_t dev, int flags, int otyp, cred_t *credp)
1377c478bd9Sstevel@tonic-gate {
138*26947304SEvan Yan px_t *px_p = PX_DEV_TO_SOFTSTATE(dev);
139*26947304SEvan Yan int minor = getminor(dev);
140b65731f1Skini int rval;
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR)
1437c478bd9Sstevel@tonic-gate return (EINVAL);
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate if (px_p == NULL)
1467c478bd9Sstevel@tonic-gate return (ENXIO);
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate DBG(DBG_CLOSE, px_p->px_dip, "dev=%x: flags=%x\n", dev, flags);
1497c478bd9Sstevel@tonic-gate mutex_enter(&px_p->px_mutex);
150b65731f1Skini
151*26947304SEvan Yan switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
152*26947304SEvan Yan case PCI_TOOL_REG_MINOR_NUM:
153*26947304SEvan Yan case PCI_TOOL_INTR_MINOR_NUM:
154*26947304SEvan Yan break;
155*26947304SEvan Yan default:
156*26947304SEvan Yan /* To handle devctl and hotplug related ioctls */
157*26947304SEvan Yan if (rval = pcie_close(px_p->px_dip, dev, flags, otyp, credp)) {
158b65731f1Skini mutex_exit(&px_p->px_mutex);
159b65731f1Skini return (rval);
160b65731f1Skini }
161*26947304SEvan Yan }
162b65731f1Skini
163*26947304SEvan Yan px_p->px_soft_state = PCI_SOFT_STATE_CLOSED;
1647c478bd9Sstevel@tonic-gate mutex_exit(&px_p->px_mutex);
1657c478bd9Sstevel@tonic-gate return (0);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate /* ARGSUSED */
1697c478bd9Sstevel@tonic-gate static int
px_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1707c478bd9Sstevel@tonic-gate px_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp)
1717c478bd9Sstevel@tonic-gate {
172*26947304SEvan Yan px_t *px_p = PX_DEV_TO_SOFTSTATE(dev);
17369cd775fSschwartz int minor = getminor(dev);
174*26947304SEvan Yan dev_info_t *dip;
175*26947304SEvan Yan int rv = ENOTTY;
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate if (px_p == NULL)
1787c478bd9Sstevel@tonic-gate return (ENXIO);
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate dip = px_p->px_dip;
1817c478bd9Sstevel@tonic-gate DBG(DBG_IOCTL, dip, "dev=%x: cmd=%x\n", dev, cmd);
18269cd775fSschwartz
1837c478bd9Sstevel@tonic-gate #ifdef PX_DMA_TEST
1847c478bd9Sstevel@tonic-gate if (IS_DMATEST(cmd)) {
1857c478bd9Sstevel@tonic-gate *rvalp = px_dma_test(cmd, dip, px_p, arg);
1867c478bd9Sstevel@tonic-gate return (0);
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate #endif /* PX_DMA_TEST */
1897c478bd9Sstevel@tonic-gate
190*26947304SEvan Yan switch (PCI_MINOR_NUM_TO_PCI_DEVNUM(minor)) {
1917c478bd9Sstevel@tonic-gate /*
1927c478bd9Sstevel@tonic-gate * PCI tools.
1937c478bd9Sstevel@tonic-gate */
19469cd775fSschwartz case PCI_TOOL_REG_MINOR_NUM:
19569cd775fSschwartz switch (cmd) {
19669cd775fSschwartz case PCITOOL_DEVICE_SET_REG:
19769cd775fSschwartz case PCITOOL_DEVICE_GET_REG:
19869cd775fSschwartz
19969cd775fSschwartz /* Require full privileges. */
20069cd775fSschwartz if (secpolicy_kmdb(credp))
20169cd775fSschwartz rv = EPERM;
20269cd775fSschwartz else
20369cd775fSschwartz rv = pxtool_dev_reg_ops(dip,
20469cd775fSschwartz (void *)arg, cmd, mode);
20569cd775fSschwartz break;
20669cd775fSschwartz
20769cd775fSschwartz case PCITOOL_NEXUS_SET_REG:
20869cd775fSschwartz case PCITOOL_NEXUS_GET_REG:
20969cd775fSschwartz
21069cd775fSschwartz /* Require full privileges. */
21169cd775fSschwartz if (secpolicy_kmdb(credp))
21269cd775fSschwartz rv = EPERM;
21369cd775fSschwartz else
21469cd775fSschwartz rv = pxtool_bus_reg_ops(dip,
21569cd775fSschwartz (void *)arg, cmd, mode);
21669cd775fSschwartz break;
21769cd775fSschwartz
21869cd775fSschwartz default:
21969cd775fSschwartz rv = ENOTTY;
22069cd775fSschwartz }
22169cd775fSschwartz return (rv);
22269cd775fSschwartz case PCI_TOOL_INTR_MINOR_NUM:
22369cd775fSschwartz switch (cmd) {
22469cd775fSschwartz case PCITOOL_DEVICE_SET_INTR:
22569cd775fSschwartz
226d5ace945SErwin T Tsaur /* Require full privileges. */
227d5ace945SErwin T Tsaur if (secpolicy_kmdb(credp)) {
22869cd775fSschwartz rv = EPERM;
22969cd775fSschwartz break;
23069cd775fSschwartz }
23169cd775fSschwartz
23269cd775fSschwartz /*FALLTHRU*/
23369cd775fSschwartz /* These require no special privileges. */
23469cd775fSschwartz case PCITOOL_DEVICE_GET_INTR:
2352917a9c9Sschwartz case PCITOOL_SYSTEM_INTR_INFO:
23669cd775fSschwartz rv = pxtool_intr(dip, (void *)arg, cmd, mode);
23769cd775fSschwartz break;
23869cd775fSschwartz
23969cd775fSschwartz default:
24069cd775fSschwartz rv = ENOTTY;
24169cd775fSschwartz }
24269cd775fSschwartz return (rv);
24369cd775fSschwartz default:
244*26947304SEvan Yan /* To handle devctl and hotplug related ioctls */
245*26947304SEvan Yan rv = pcie_ioctl(dip, dev, cmd, arg, mode, credp, rvalp);
24669cd775fSschwartz break;
24769cd775fSschwartz }
24869cd775fSschwartz
24969cd775fSschwartz if ((cmd & ~PPMREQ_MASK) == PPMREQ) {
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate /* Need privileges to use these ioctls. */
2527c478bd9Sstevel@tonic-gate if (drv_priv(credp)) {
2537c478bd9Sstevel@tonic-gate DBG(DBG_TOOLS, dip,
2547c478bd9Sstevel@tonic-gate "px_tools: Insufficient privileges\n");
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate return (EPERM);
2577c478bd9Sstevel@tonic-gate }
2587c478bd9Sstevel@tonic-gate return (px_lib_pmctl(cmd, px_p));
25969cd775fSschwartz }
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate return (rv);
2627c478bd9Sstevel@tonic-gate }
263