eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel/*
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * CDDL HEADER START
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel *
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * The contents of this file are subject to the terms of the
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * Common Development and Distribution License (the "License").
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * You may not use this file except in compliance with the License.
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel *
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * or http://www.opensolaris.org/os/licensing.
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * See the License for the specific language governing permissions
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * and limitations under the License.
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel *
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * When distributing Covered Code, include this CDDL HEADER in each
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * If applicable, add the following below this CDDL HEADER, with the
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * fields enclosed by brackets "[]" replaced with your own identifying
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * information: Portions Copyright [yyyy] [name of copyright owner]
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel *
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * CDDL HEADER END
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel/*
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * Copyright (c) 2009, Intel Corporation.
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * All rights reserved.
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel#include <sys/conf.h>
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel#include <sys/cmn_err.h>
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel#include <sys/ddi.h>
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel#include <sys/file.h>
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel#include <sys/modctl.h>
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel#include <sys/pci.h>
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel#include <sys/policy.h>
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel#include <sys/stat.h>
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel#include <sys/sunddi.h>
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel#include <sys/synch.h>
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel#include <sys/fipe.h>
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel/* Configurable through /etc/system. */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelint fipe_allow_attach = 1;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelint fipe_allow_detach = 1;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic kmutex_t fipe_drv_lock;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic dev_info_t *fipe_drv_dip;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel/*
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * PCI device ID for supported hardware.
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * For memory controller devices in Intel 5000/7300 series chipset, PCI vendor
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * id and PCI device id is read only, PCI subvendor id and PCI subsystem id is
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * write-once. So we could only rely on PCI vendor id and PCI device id here.
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * For all PCI functions (0,1,2,3) in device 0x10 on bus 0, they will have the
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * same PCI (vendor_id, device_id, subvendor_id, subsystem_id, class_id).
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * We only need to access PCI device (0, 0x10, 1), all other PCI functions will
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel * be filtered out by unit address.
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic struct fipe_pci_id {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel uint16_t venid;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel uint16_t devid;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel uint16_t subvenid;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel uint16_t subsysid;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel char *unitaddr;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel} fipe_mc_pciids[] = {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel { 0x8086, 0x25f0, 0xffff, 0xffff, "10,1" }, /* Intel 5000P/V/X/Z */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel { 0x8086, 0x360c, 0xffff, 0xffff, "10,1" } /* Intel 7300 NB */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel};
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel/*ARGSUSED*/
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic int
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelfipe_open(dev_t *devp, int flag, int otyp, cred_t *credp)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel{
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (otyp != OTYP_CHR) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel cmn_err(CE_NOTE, "!fipe: invalid otyp %d in open.", otyp);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (EINVAL);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (0);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel}
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel/*ARGSUSED*/
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic int
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelfipe_close(dev_t dev, int flag, int otyp, cred_t *credp)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel{
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (0);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel}
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel/*ARGSUSED*/
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic int
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelfipe_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel int *rvalp)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel{
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel int rc = 0;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_pm_policy_t policy;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel /* First check permission. */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (secpolicy_power_mgmt(credp) != 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (EPERM);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel switch (cmd) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel case FIPE_IOCTL_START:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if ((mode & FWRITE) == 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = EBADF;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel } else {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_enter(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = fipe_start();
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_exit(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = (rc == 0) ? 0 : ENXIO;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel case FIPE_IOCTL_STOP:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if ((mode & FWRITE) == 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = EBADF;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel } else {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_enter(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = fipe_stop();
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_exit(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = (rc == 0) ? 0 : ENXIO;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel case FIPE_IOCTL_GET_PMPOLICY:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if ((mode & FREAD) == 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = EBADF;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel } else {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_enter(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel policy = fipe_get_pmpolicy();
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_exit(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = ddi_copyout(&policy, (void *)arg,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel sizeof (policy), mode);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = (rc >= 0) ? 0 : EFAULT;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel case FIPE_IOCTL_SET_PMPOLICY:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if ((mode & FWRITE) == 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = EBADF;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel } else {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_enter(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = fipe_set_pmpolicy((fipe_pm_policy_t)arg);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_exit(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = (rc == 0) ? 0 : ENXIO;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel default:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel cmn_err(CE_NOTE, "!fipe: unknown ioctl command %d.", cmd);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = ENOTSUP;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (rc);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel}
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel/*ARGSUSED*/
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic int
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelfipe_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel{
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel switch (infocmd) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel case DDI_INFO_DEVT2DEVINFO:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (fipe_drv_dip != NULL) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel *result = fipe_drv_dip;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (DDI_SUCCESS);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel } else {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel *result = NULL;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (DDI_FAILURE);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel case DDI_INFO_DEVT2INSTANCE:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (fipe_drv_dip != NULL) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel *result = (void *)(uintptr_t)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel ddi_get_instance(fipe_drv_dip);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (DDI_SUCCESS);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel } else {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel *result = NULL;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (DDI_FAILURE);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel default:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel *result = NULL;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (DDI_FAILURE);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel}
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel/* Validate whether it's supported hardware. */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic int
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelfipe_validate_dip(dev_info_t *dip)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel{
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel int i, rc = -1;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel char *unitaddr;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel struct fipe_pci_id *ip;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel ddi_acc_handle_t handle;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel uint16_t venid, devid, subvenid, subsysid;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel /* Get device unit address, it's "devid,funcid" in hexadecimal. */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel "unit-address", &unitaddr) != DDI_PROP_SUCCESS) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel cmn_err(CE_CONT, "?fipe: failed to get deivce unit address.");
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (-1);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (pci_config_setup(dip, &handle) != DDI_SUCCESS) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel cmn_err(CE_CONT, "?fipe: failed to setup pcicfg handler.");
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel ddi_prop_free(unitaddr);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (-1);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel venid = pci_config_get16(handle, PCI_CONF_VENID);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel devid = pci_config_get16(handle, PCI_CONF_DEVID);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel subvenid = pci_config_get16(handle, PCI_CONF_SUBVENID);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel subsysid = pci_config_get16(handle, PCI_CONF_SUBSYSID);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel /* Validate device. */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel for (rc = -1, i = 0, ip = &fipe_mc_pciids[0];
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel i < sizeof (fipe_mc_pciids) / sizeof (fipe_mc_pciids[0]);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel i++, ip++) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if ((ip->venid == 0xffffu || ip->venid == venid) &&
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel (ip->devid == 0xffffu || ip->devid == devid) &&
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel (ip->subvenid == 0xffffu || ip->subvenid == subvenid) &&
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel (ip->subsysid == 0xffffu || ip->subsysid == subsysid) &&
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel (ip->unitaddr == NULL ||
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel strcmp(ip->unitaddr, unitaddr) == 0)) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = 0;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel pci_config_teardown(&handle);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel ddi_prop_free(unitaddr);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (rc);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel}
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic int
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelfipe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel{
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel char *ptr;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel int ignore = 0, rc = DDI_FAILURE;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_enter(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel switch (cmd) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel case DDI_ATTACH:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel /* Check whether it has been disabled by user. */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel "disable_fipe_pm", &ptr) == DDI_SUCCESS) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (strcasecmp(ptr, "true") == 0 ||
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel strcasecmp(ptr, "yes") == 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_allow_attach = 0;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel ddi_prop_free(ptr);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (fipe_allow_attach == 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel cmn_err(CE_WARN,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel "fipe: driver has been disabled by user.");
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel ignore = 1;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel /* Filter out unwanted PCI functions. */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if ((ignore = fipe_validate_dip(dip)) != 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel /* There should be only one MC device in system. */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel } else if (fipe_drv_dip != NULL) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel cmn_err(CE_NOTE,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel "!fipe: more than one hardware instances found.");
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_drv_dip = dip;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel /* Initialize and start power management subsystem. */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (fipe_init(fipe_drv_dip) != 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_drv_dip = NULL;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel } else if (fipe_start() != 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel (void) fipe_fini();
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_drv_dip = NULL;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel /* Ignore error from creating minor node. */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (ddi_create_minor_node(dip, "fipe", S_IFCHR, 0,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel "ddi_mem_pm", 0) != DDI_SUCCESS) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel cmn_err(CE_CONT,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel "?fipe: failed to create device minor node.\n");
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = DDI_SUCCESS;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel case DDI_RESUME:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (fipe_resume() == 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = DDI_SUCCESS;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel default:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_exit(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (ignore == 0 && rc != DDI_SUCCESS) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel cmn_err(CE_NOTE, "!fipe: failed to attach or resume device.");
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (rc);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel}
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel/*ARGSUSED*/
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic int
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelfipe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel{
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel int rc = DDI_FAILURE;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_enter(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel switch (cmd) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel case DDI_DETACH:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (fipe_allow_detach == 0 || dip != fipe_drv_dip) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (fipe_stop() != 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel } else if (fipe_fini() != 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel (void) fipe_start();
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel ddi_remove_minor_node(dip, NULL);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_drv_dip = NULL;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = DDI_SUCCESS;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel case DDI_SUSPEND:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (fipe_suspend() == 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel rc = DDI_SUCCESS;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel default:
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel break;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_exit(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (rc != DDI_SUCCESS) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel cmn_err(CE_NOTE, "!fipe: failed to detach or suspend device.");
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (rc);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel}
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic int
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelfipe_quiesce(dev_info_t *dip)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel{
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (dip != fipe_drv_dip) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (DDI_SUCCESS);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel /* Quiesce hardware by stopping power management subsystem. */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if (fipe_suspend() != 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel cmn_err(CE_NOTE, "!fipe: failed to quiesce device.");
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (DDI_FAILURE);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (DDI_SUCCESS);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel}
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic struct cb_ops fipe_cb_ops = {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_open,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_close,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nodev, /* not a block driver */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nodev, /* no print routine */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nodev, /* no dump routine */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nodev, /* no read routine */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nodev, /* no write routine */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_ioctl,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nodev, /* no devmap routine */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nodev, /* no mmap routine */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nodev, /* no segmap routine */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nochpoll, /* no chpoll routine */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel ddi_prop_op,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel 0, /* not a STREAMS driver */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel D_NEW | D_MP, /* safe for multi-thread/multi-processor */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel};
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic struct dev_ops fipe_ops = {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel DEVO_REV, /* devo_rev */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel 0, /* devo_refcnt */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_getinfo, /* devo_getinfo */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nulldev, /* devo_identify */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nulldev, /* devo_probe */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_attach, /* devo_attach */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_detach, /* devo_detach */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel nodev, /* devo_reset */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel &fipe_cb_ops, /* devo_cb_ops */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel NULL, /* devo_bus_ops */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel NULL, /* devo_power */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel &fipe_quiesce, /* devo_quiesce */
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel};
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic struct modldrv modldrv = {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel &mod_driverops,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel "Intel 5000/7300 memory controller driver",
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel &fipe_ops
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel};
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelstatic struct modlinkage modlinkage = {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel MODREV_1,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel (void *)&modldrv,
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel NULL
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel};
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelint
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel_init(void)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel{
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_drv_dip = NULL;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_init(&fipe_drv_lock, NULL, MUTEX_DRIVER, NULL);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (mod_install(&modlinkage));
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel}
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelint
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel_info(struct modinfo *modinfop)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel{
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (mod_info(&modlinkage, modinfop));
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel}
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishelint
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel_fini(void)
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel{
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel int err;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel if ((err = mod_remove(&modlinkage)) == 0) {
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel mutex_destroy(&fipe_drv_lock);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel fipe_drv_dip = NULL;
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel }
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel return (err);
eca2601cae391051acb146d28fba04237fe1eb85Randy Fishel}