root/usr/src/uts/common/sys/pcie_pwr.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_PCIE_PWR_H
#define _SYS_PCIE_PWR_H

#ifdef  __cplusplus
extern "C" {
#endif

/* index of counters for each level */
#define PCIE_D3_INDEX           PM_LEVEL_D3
#define PCIE_D2_INDEX           PM_LEVEL_D2
#define PCIE_D1_INDEX           PM_LEVEL_D1
#define PCIE_D0_INDEX           PM_LEVEL_D0
#define PCIE_UNKNOWN_INDEX      PM_LEVEL_D0 + 1
#define PCIE_MAX_PWR_LEVELS     5

/*
 * PCIe nexus power management data structure
 */
typedef struct pcie_pwr {
        /*
         * general data structure fields
         */
        kmutex_t        pwr_lock;       /* to protect the counters and  */
                                        /* power level change           */
        int             pwr_pmcaps;     /* pm capability */
        ddi_acc_handle_t pwr_conf_hdl;  /* for config access */
        uint8_t         pwr_pmcsr_offset; /* PMCSR offset */
        int             pwr_link_lvl;   /* link level. Currently not used */
        int             pwr_func_lvl;   /* function power level */
        int             pwr_flags;      /* flags */
        int             pwr_hold;       /* for temporarily keeping busy */
        /*
         * counters to keep track of child's power level.
         * D3,D2,D1,D0 and unknown respectively.
         */
        int             pwr_counters[PCIE_MAX_PWR_LEVELS];

} pcie_pwr_t;

typedef struct pcie_pwr_child {
        /*
         * Per child dip counters decsribing
         * a child's components
         */
        int     pwr_child_counters[PCIE_MAX_PWR_LEVELS];
} pcie_pwr_child_t;

typedef struct pcie_pm {
        pcie_pwr_t      *pcie_pwr_p;    /* nexus PM info */
        pcie_pwr_child_t *pcie_par_pminfo; /* PM info created by the parent */
} pcie_pm_t;

#define PCIE_PMINFO(dip)        \
        ((pcie_pm_t *)(DEVI(dip)->devi_nex_pm))

#define PCIE_NEXUS_PMINFO(dip)  \
        (PCIE_PMINFO(dip)->pcie_pwr_p)

#define PCIE_PAR_PMINFO(dip)    \
        (PCIE_PMINFO(dip)->pcie_par_pminfo)

#define PCIE_CHILD_COUNTERS(cdip)       \
        (PCIE_PAR_PMINFO(cdip)->pwr_child_counters)

#define PCIE_SET_PMINFO(dip, pminfo_p)  \
        (DEVI(dip)->devi_nex_pm = (pminfo_p))

#define PCIE_RESET_PMINFO(dip)  \
        (DEVI(dip)->devi_nex_pm = NULL)

#define PCIE_IS_COMPS_COUNTED(cdip)     \
        (PCIE_PMINFO(cdip) && PCIE_PAR_PMINFO(cdip))

/*
 * pmcap field: device power management capability.
 * First 4 bits must indicate support for D3, D2, D1 and D0
 * respectively. Their bit position matches with their index
 * into the counters array.
 */
#define PCIE_SUPPORTS_D3        0x01 /* Supports D1 */
#define PCIE_SUPPORTS_D2        0x02 /* Supports D2 */
#define PCIE_SUPPORTS_D1        0x04 /* Supports D2 */
#define PCIE_SUPPORTS_D0        0x08 /* Supports D2 */
#define PCIE_L2_CAP             0x10 /* if with Vaux, optional */
#define PCIE_L0s_L1_CAP         0x20 /* ASPM, L0s must, L1 optional */

#define PCIE_DEFAULT_LEVEL_SUPPORTED    (PCIE_SUPPORTS_D3 | PCIE_SUPPORTS_D0)

#define PCIE_LEVEL_SUPPORTED(pmcaps, level)     \
        ((pmcaps) & (1 << (level)))

#define PCIE_SUPPORTS_DEVICE_PM(dip)    \
        (ddi_prop_exists(DDI_DEV_T_ANY, (dip),  \
            DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "pm-components") == 1)
/*
 * flags field
 */
#define PCIE_ASPM_ENABLED               0x01
#define PCIE_SLOT_LOADED                0x02
#define PCIE_PM_BUSY                    0x04
#define PCIE_NO_CHILD_PM                0x08

#define PM_LEVEL_L3     0
#define PM_LEVEL_L2     1
#define PM_LEVEL_L1     2
#define PM_LEVEL_L0     3

/* ioctl definitions for ppm drivers */
#define PPMREQ                  (('P' << 24) | ('M' << 16))
#define PPMREQ_MASK             0xffff
#define PPMREQ_PRE_PWR_OFF      (PPMREQ | 1)
#define PPMREQ_PRE_PWR_ON       (PPMREQ | 2)
#define PPMREQ_POST_PWR_ON      (PPMREQ | 3)

/* settle time in microseconds before PCI operation */
#define PCI_CLK_SETTLE_TIME     10000

/*
 * Interface with other parts of the driver(s) code
 */

/*
 * We link pcie_pwr.o into several drivers (px, pcieb, pcieb_bcm, pcieb_plx),
 * which causes the symbols below to be duplicated.  This isn't an issue in
 * practice, since they aren't used from outside the module that they're
 * part of.  However, lint does not know this, and when it does global
 * crosschecks for the kernel, it complains.  To prevent this, we rename the
 * symbols to driver-specific names when we're doing a lint run.
 */

#if defined(lint)
#if defined(PX_MOD_NAME)
#define pwr_common_setup        PX_MOD_NAME##_pwr_common_setup
#define pwr_common_teardown     PX_MOD_NAME##_pwr_common_teardown
#define pcie_bus_power          PX_MOD_NAME##_pcie_bus_power
#define pcie_power              PX_MOD_NAME##_pcie_power
#define pcie_pm_add_child       PX_MOD_NAME##_pcie_pm_add_child
#define pcie_pm_remove_child    PX_MOD_NAME##_pcie_pm_remove_child
#define pcie_pwr_suspend        PX_MOD_NAME##_pcie_pwr_suspend
#define pcie_pwr_resume         PX_MOD_NAME##_pcie_pwr_resume
#define pcie_pm_hold            PX_MOD_NAME##_pcie_pm_hold
#define pcie_pm_release         PX_MOD_NAME##_pcie_pm_release
#endif /* PX_MOD_NAME */

#if defined(PX_PLX)
#define pwr_common_setup        PX_PLX##_pwr_common_setup
#define pwr_common_teardown     PX_PLX##_pwr_common_teardown
#define pcie_bus_power          PX_PLX##_pcie_bus_power
#define pcie_power              PX_PLX##_pcie_power
#define pcie_pm_add_child       PX_PLX##_pcie_pm_add_child
#define pcie_pm_remove_child    PX_PLX##_pcie_pm_remove_child
#define pcie_pwr_suspend        PX_PLX##_pcie_pwr_suspend
#define pcie_pwr_resume         PX_PLX##_pcie_pwr_resume
#define pcie_pm_hold            PX_PLX##_pcie_pm_hold
#define pcie_pm_release         PX_PLX##_pcie_pm_release
#endif /* PX_PLX */
#endif /* lint */

extern int pcie_plat_pwr_setup(dev_info_t *dip);
extern void pcie_plat_pwr_teardown(dev_info_t *dip);
extern int pwr_common_setup(dev_info_t *dip);
extern void pwr_common_teardown(dev_info_t *dip);
extern int pcie_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
    void *arg, void *result);
extern int pcie_power(dev_info_t *dip, int component, int level);

extern int pcie_pm_add_child(dev_info_t *dip, dev_info_t *cdip);
extern int pcie_pm_remove_child(dev_info_t *dip, dev_info_t *cdip);
extern int pcie_pwr_suspend(dev_info_t *dip);
extern int pcie_pwr_resume(dev_info_t *dip);
extern int pcie_pm_hold(dev_info_t *dip);
extern void pcie_pm_release(dev_info_t *dip);

#ifdef  __cplusplus
}
#endif

#endif  /* _SYS_PCIE_PWR_H */