summaryrefslogtreecommitdiff
path: root/usr/src/uts/i86pc/io
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/i86pc/io')
-rw-r--r--usr/src/uts/i86pc/io/acpippm.conf28
-rw-r--r--usr/src/uts/i86pc/io/cbe.c50
-rw-r--r--usr/src/uts/i86pc/io/consplat.c3
-rw-r--r--usr/src/uts/i86pc/io/gfx_private/gfxp_vgatext.c320
-rw-r--r--usr/src/uts/i86pc/io/mc/mcamd_drv.c20
-rw-r--r--usr/src/uts/i86pc/io/mp_platform_common.c182
-rw-r--r--usr/src/uts/i86pc/io/pci/pci.c68
-rw-r--r--usr/src/uts/i86pc/io/pciex/npe.c61
-rw-r--r--usr/src/uts/i86pc/io/pcplusmp/apic.c11
-rw-r--r--usr/src/uts/i86pc/io/ppm.conf46
-rw-r--r--usr/src/uts/i86pc/io/ppm/acpippm.c443
-rw-r--r--usr/src/uts/i86pc/io/ppm/acpippm.h41
-rw-r--r--usr/src/uts/i86pc/io/ppm/acpisleep.c214
-rw-r--r--usr/src/uts/i86pc/io/psm/psm_common.c38
-rw-r--r--usr/src/uts/i86pc/io/psm/uppc.c2
-rw-r--r--usr/src/uts/i86pc/io/todpc_subr.c229
16 files changed, 1610 insertions, 146 deletions
diff --git a/usr/src/uts/i86pc/io/acpippm.conf b/usr/src/uts/i86pc/io/acpippm.conf
new file mode 100644
index 0000000000..53112bd96d
--- /dev/null
+++ b/usr/src/uts/i86pc/io/acpippm.conf
@@ -0,0 +1,28 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+
+name="acpippm" parent="pseudo" instance=0;
diff --git a/usr/src/uts/i86pc/io/cbe.c b/usr/src/uts/i86pc/io/cbe.c
index 7667bb2219..6bf01fa283 100644
--- a/usr/src/uts/i86pc/io/cbe.c
+++ b/usr/src/uts/i86pc/io/cbe.c
@@ -38,6 +38,7 @@
#include <sys/psm.h>
#include <sys/atomic.h>
#include <sys/clock.h>
+#include <sys/x86_archext.h>
#include <sys/ddi_impldefs.h>
#include <sys/ddi_intr.h>
#include <sys/avintr.h>
@@ -58,6 +59,8 @@ static ddi_softint_hdl_impl_t cbe_clock_hdl =
cyclic_id_t cbe_hres_cyclic;
int cbe_psm_timer_mode = TIMER_ONESHOT;
+extern int tsc_gethrtime_enable;
+
void cbe_hres_tick(void);
int
@@ -200,6 +203,43 @@ cbe_configure(cpu_t *cpu)
return (cpu);
}
+#ifndef __xpv
+/*
+ * declarations needed for time adjustment
+ */
+extern void tsc_suspend(void);
+extern void tsc_resume(void);
+/*
+ * Call the resume function in the cyclic, instead of inline in the
+ * resume path.
+ */
+extern int tsc_resume_in_cyclic;
+#endif
+
+/*ARGSUSED*/
+static void
+cbe_suspend(cyb_arg_t arg)
+{
+#ifndef __xpv
+ /*
+ * This is an x86 backend, so let the tsc_suspend
+ * that is specific to x86 platforms do the work.
+ */
+ tsc_suspend();
+#endif
+}
+
+/*ARGSUSED*/
+static void
+cbe_resume(cyb_arg_t arg)
+{
+#ifndef __xpv
+ if (tsc_resume_in_cyclic) {
+ tsc_resume();
+ }
+#endif
+}
+
void
cbe_enable(void *arg)
{
@@ -209,7 +249,11 @@ cbe_enable(void *arg)
if ((cbe_psm_timer_mode != TIMER_ONESHOT) && (me == 0))
return;
- ASSERT(!CPU_IN_SET(cbe_enabled, me));
+ /*
+ * Added (me == 0) to the ASSERT because the timer isn't
+ * disabled on CPU 0, and cbe_enable is called when we resume.
+ */
+ ASSERT((me == 0) || !CPU_IN_SET(cbe_enabled, me));
CPUSET_ADD(cbe_enabled, me);
if (cbe_psm_timer_mode == TIMER_ONESHOT)
(*psm_timer_enable)();
@@ -268,8 +312,8 @@ cbe_init(void)
cbe_set_level, /* cyb_set_level */
cbe_restore_level, /* cyb_restore_level */
cbe_xcall, /* cyb_xcall */
- NULL, /* cyb_suspend */
- NULL /* cyb_resume */
+ cbe_suspend, /* cyb_suspend */
+ cbe_resume /* cyb_resume */
};
hrtime_t resolution;
cyc_handler_t hdlr;
diff --git a/usr/src/uts/i86pc/io/consplat.c b/usr/src/uts/i86pc/io/consplat.c
index cfb0f5e861..feecc2d3d5 100644
--- a/usr/src/uts/i86pc/io/consplat.c
+++ b/usr/src/uts/i86pc/io/consplat.c
@@ -54,7 +54,8 @@ static char *
gfxdrv_name[] = {
"vgatext",
"i915",
- "nvidia"
+ "atiatom",
+ "nvidia",
};
int
diff --git a/usr/src/uts/i86pc/io/gfx_private/gfxp_vgatext.c b/usr/src/uts/i86pc/io/gfx_private/gfxp_vgatext.c
index 543349655c..a9d3c3827e 100644
--- a/usr/src/uts/i86pc/io/gfx_private/gfxp_vgatext.c
+++ b/usr/src/uts/i86pc/io/gfx_private/gfxp_vgatext.c
@@ -49,6 +49,9 @@
#include <sys/kd.h>
#include <sys/ddi_impldefs.h>
+
+
+
#include "gfx_private.h"
#define MYNAME "gfxp_vgatext"
@@ -151,6 +154,12 @@ static struct fbgattr vgatext_attr = {
#define GFXP_FLAG_CONSOLE 0x00000001
#define GFXP_IS_CONSOLE(softc) ((softc)->flags & GFXP_FLAG_CONSOLE)
+/*
+ * Global name used to write the softc pointer in, for the
+ * data wrapper vgatext_return_pointers()
+ */
+
+
int gfxp_vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd,
gfxp_vgatext_softc_ptr_t ptr);
static int vgatext_devinit(struct vgatext_softc *, struct vis_devinit *data);
@@ -168,9 +177,16 @@ static void vgatext_polled_cursor(struct vis_polledio_arg *,
struct vis_conscursor *);
static void vgatext_init(struct vgatext_softc *);
static void vgatext_set_text(struct vgatext_softc *);
+
+static void vgatext_save_text(struct vgatext_softc *softc);
+static void vgatext_restore_textmode(struct vgatext_softc *softc);
+static int vgatext_suspend(struct vgatext_softc *softc);
+static void vgatext_resume(struct vgatext_softc *softc);
+
#if defined(USE_BORDERS)
static void vgatext_init_graphics(struct vgatext_softc *);
#endif
+
static int vgatext_kdsetmode(struct vgatext_softc *softc, int mode);
static void vgatext_setfont(struct vgatext_softc *softc);
static void vgatext_get_cursor(struct vgatext_softc *softc,
@@ -220,7 +236,8 @@ gfxp_check_for_console(dev_info_t *devi, struct vgatext_softc *softc,
if (pci_config_setup(devi, &pci_conf) != DDI_SUCCESS) {
cmn_err(CE_WARN,
- MYNAME ": can't get PCI conf handle");
+ MYNAME
+ ": can't get PCI conf handle");
return;
}
@@ -294,25 +311,30 @@ gfxp_vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd,
int pci_pcie_bus = 0;
+
switch (cmd) {
case DDI_ATTACH:
- break;
+ break;
case DDI_RESUME:
- return (DDI_SUCCESS);
+ vgatext_resume(softc);
+ return (DDI_SUCCESS);
+
default:
- return (DDI_FAILURE);
+ return (DDI_FAILURE);
}
/* DDI_ATTACH */
+ softc->devi = devi; /* Copy and init DEVI */
+
softc->polledio.arg = (struct vis_polledio_arg *)softc;
softc->polledio.display = vgatext_polled_display;
softc->polledio.copy = vgatext_polled_copy;
softc->polledio.cursor = vgatext_polled_cursor;
error = ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_get_parent(devi),
- DDI_PROP_DONTPASS, "device_type", &parent_type);
+ DDI_PROP_DONTPASS, "device_type", &parent_type);
if (error != DDI_SUCCESS) {
cmn_err(CE_WARN, MYNAME ": can't determine parent type.");
goto fail;
@@ -321,46 +343,50 @@ gfxp_vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd,
/* Not enable AGP and DRM by default */
if (STREQ(parent_type, "isa") || STREQ(parent_type, "eisa")) {
reg_rnumber = vgatext_get_isa_reg_index(devi, 1, VGA_REG_ADDR,
- &reg_offset);
+ &reg_offset);
if (reg_rnumber < 0) {
cmn_err(CE_WARN,
- MYNAME ": can't find reg entry for registers");
+ MYNAME
+ ": can't find reg entry for registers");
error = DDI_FAILURE;
goto fail;
}
softc->fb_regno = vgatext_get_isa_reg_index(devi, 0,
- VGA_MEM_ADDR, &mem_offset);
+ VGA_MEM_ADDR, &mem_offset);
if (softc->fb_regno < 0) {
cmn_err(CE_WARN,
- MYNAME ": can't find reg entry for memory");
+ MYNAME
+ ": can't find reg entry for memory");
error = DDI_FAILURE;
goto fail;
}
} else if (STREQ(parent_type, "pci") || STREQ(parent_type, "pciex")) {
pci_pcie_bus = 1;
reg_rnumber = vgatext_get_pci_reg_index(devi,
- PCI_REG_ADDR_M|PCI_REG_REL_M,
- PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR,
- &reg_offset);
+ PCI_REG_ADDR_M|PCI_REG_REL_M,
+ PCI_ADDR_IO|PCI_RELOCAT_B, VGA_REG_ADDR,
+ &reg_offset);
if (reg_rnumber < 0) {
cmn_err(CE_WARN,
- MYNAME ": can't find reg entry for registers");
+ MYNAME
+ ": can't find reg entry for registers");
error = DDI_FAILURE;
goto fail;
}
softc->fb_regno = vgatext_get_pci_reg_index(devi,
- PCI_REG_ADDR_M|PCI_REG_REL_M,
- PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR,
- &mem_offset);
+ PCI_REG_ADDR_M|PCI_REG_REL_M,
+ PCI_ADDR_MEM32|PCI_RELOCAT_B, VGA_MEM_ADDR,
+ &mem_offset);
if (softc->fb_regno < 0) {
cmn_err(CE_WARN,
- MYNAME ": can't find reg entry for memory");
+ MYNAME
+ ": can't find reg entry for memory");
error = DDI_FAILURE;
goto fail;
}
} else {
cmn_err(CE_WARN, MYNAME ": unknown parent type \"%s\".",
- parent_type);
+ parent_type);
error = DDI_FAILURE;
goto fail;
}
@@ -368,8 +394,8 @@ gfxp_vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd,
parent_type = NULL;
error = ddi_regs_map_setup(devi, reg_rnumber,
- (caddr_t *)&softc->regs.addr, reg_offset, VGA_REG_SIZE,
- &dev_attr, &softc->regs.handle);
+ (caddr_t *)&softc->regs.addr, reg_offset, VGA_REG_SIZE,
+ &dev_attr, &softc->regs.handle);
if (error != DDI_SUCCESS)
goto fail;
softc->regs.mapped = B_TRUE;
@@ -377,9 +403,9 @@ gfxp_vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd,
softc->fb_size = VGA_MEM_SIZE;
error = ddi_regs_map_setup(devi, softc->fb_regno,
- (caddr_t *)&softc->fb.addr,
- mem_offset, softc->fb_size,
- &dev_attr, &softc->fb.handle);
+ (caddr_t *)&softc->fb.addr,
+ mem_offset, softc->fb_size,
+ &dev_attr, &softc->fb.handle);
if (error != DDI_SUCCESS)
goto fail;
softc->fb.mapped = B_TRUE;
@@ -397,7 +423,7 @@ gfxp_vgatext_attach(dev_info_t *devi, ddi_attach_cmd_t cmd,
goto fail;
if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(),
- DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) {
+ DDI_PROP_DONTPASS, "console", &cons) == DDI_SUCCESS) {
if (strcmp(cons, "graphics") == 0) {
happyface_boot = 1;
vgatext_silent = 1;
@@ -429,7 +455,15 @@ gfxp_vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd,
{
struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
+
+
+
+
switch (cmd) {
+
+ case DDI_SUSPEND:
+ return (vgatext_suspend(softc));
+ /* break; */
case DDI_DETACH:
if (softc->fb.mapped)
ddi_regs_map_free(&softc->fb.handle);
@@ -439,7 +473,7 @@ gfxp_vgatext_detach(dev_info_t *devi, ddi_detach_cmd_t cmd,
default:
cmn_err(CE_WARN, "gfxp_vgatext_detach: unknown cmd 0x%x\n",
- cmd);
+ cmd);
return (DDI_FAILURE);
}
}
@@ -478,7 +512,7 @@ gfxp_vgatext_ioctl(
{
struct vgatext_softc *softc = (struct vgatext_softc *)ptr;
static char kernel_only[] =
- "gfxp_vgatext_ioctl: %s is a kernel only ioctl";
+ "gfxp_vgatext_ioctl: %s is a kernel only ioctl";
int err;
int kd_mode;
@@ -494,58 +528,59 @@ gfxp_vgatext_ioctl(
case VIS_DEVINIT:
- if (!(mode & FKIOCTL)) {
- cmn_err(CE_CONT, kernel_only, "VIS_DEVINIT");
- return (ENXIO);
- }
+ if (!(mode & FKIOCTL)) {
+ cmn_err(CE_CONT, kernel_only, "VIS_DEVINIT");
+ return (ENXIO);
+ }
- err = vgatext_devinit(softc, (struct vis_devinit *)data);
- if (err != 0) {
- cmn_err(CE_WARN,
- "gfxp_vgatext_ioctl: could not initialize console");
- return (err);
- }
- break;
+ err = vgatext_devinit(softc, (struct vis_devinit *)data);
+ if (err != 0) {
+ cmn_err(CE_WARN,
+ "gfxp_vgatext_ioctl: could not"
+ " initialize console");
+ return (err);
+ }
+ break;
case VIS_CONSCOPY: /* move */
{
- struct vis_conscopy pma;
+ struct vis_conscopy pma;
- if (ddi_copyin((void *)data, &pma,
- sizeof (struct vis_conscopy), mode))
- return (EFAULT);
+ if (ddi_copyin((void *)data, &pma,
+ sizeof (struct vis_conscopy), mode))
+ return (EFAULT);
- vgatext_cons_copy(softc, &pma);
- break;
+ vgatext_cons_copy(softc, &pma);
+ break;
}
case VIS_CONSDISPLAY: /* display */
{
- struct vis_consdisplay display_request;
+ struct vis_consdisplay display_request;
- if (ddi_copyin((void *)data, &display_request,
- sizeof (display_request), mode))
- return (EFAULT);
+ if (ddi_copyin((void *)data, &display_request,
+ sizeof (display_request), mode))
+ return (EFAULT);
- vgatext_cons_display(softc, &display_request);
- break;
+ vgatext_cons_display(softc, &display_request);
+ break;
}
case VIS_CONSCURSOR:
{
- struct vis_conscursor cursor_request;
+ struct vis_conscursor cursor_request;
- if (ddi_copyin((void *)data, &cursor_request,
- sizeof (cursor_request), mode))
- return (EFAULT);
+ if (ddi_copyin((void *)data, &cursor_request,
+ sizeof (cursor_request), mode))
+ return (EFAULT);
- vgatext_cons_cursor(softc, &cursor_request);
+ vgatext_cons_cursor(softc, &cursor_request);
- if (cursor_request.action == VIS_GET_CURSOR &&
- ddi_copyout(&cursor_request, (void *)data,
- sizeof (cursor_request), mode))
- return (EFAULT);
- break;
+ if (cursor_request.action == VIS_GET_CURSOR &&
+ ddi_copyout(&cursor_request, (void *)data,
+ sizeof (cursor_request), mode))
+ return (EFAULT);
+ break;
}
case VIS_GETCMAP:
@@ -576,6 +611,92 @@ gfxp_vgatext_ioctl(
return (0);
}
+/*
+ * vgatext_save_text
+ * vgatext_restore_textmode
+ * vgatext_suspend
+ * vgatext_resume
+ *
+ * Routines to save and restore contents of the VGA text area
+ * Mostly, this is to support Suspend/Resume operation for graphics
+ * device drivers. Here in the VGAtext common code, we simply squirrel
+ * away the contents of the hardware's text area during Suspend and then
+ * put it back during Resume
+ */
+static void
+vgatext_save_text(struct vgatext_softc *softc)
+{
+ unsigned i;
+
+ for (i = 0; i < sizeof (softc->shadow); i++)
+ softc->shadow[i] = softc->text_base[i];
+}
+
+static void
+vgatext_restore_textmode(struct vgatext_softc *softc)
+{
+ unsigned i;
+
+ vgatext_init(softc);
+ for (i = 0; i < sizeof (softc->shadow); i++) {
+ softc->text_base[i] = softc->shadow[i];
+ }
+ if (softc->cursor.visible) {
+ vgatext_set_cursor(softc,
+ softc->cursor.row, softc->cursor.col);
+ }
+ vgatext_restore_colormap(softc);
+}
+
+static int
+vgatext_suspend(struct vgatext_softc *softc)
+{
+ switch (softc->mode) {
+ case KD_TEXT:
+ vgatext_save_text(softc);
+ break;
+
+ case KD_GRAPHICS:
+ break;
+
+ default:
+ cmn_err(CE_WARN, MYNAME ": unknown mode in vgatext_suspend.");
+ return (DDI_FAILURE);
+ }
+ return (DDI_SUCCESS);
+}
+
+static void
+vgatext_resume(struct vgatext_softc *softc)
+{
+
+ switch (softc->mode) {
+ case KD_TEXT:
+ vgatext_restore_textmode(softc);
+ break;
+
+ case KD_GRAPHICS:
+
+ /*
+ * Upon RESUME, the graphics device will always actually
+ * be in TEXT mode even though the Xorg server did not
+ * make that mode change itself (the suspend code did).
+ * We want first, therefore, to restore textmode
+ * operation fully, and then the Xorg server will
+ * do the rest to restore the device to its
+ * (hi resolution) graphics mode
+ */
+ vgatext_restore_textmode(softc);
+#if defined(USE_BORDERS)
+ vgatext_init_graphics(softc);
+#endif
+ break;
+ default:
+ cmn_err(CE_WARN, MYNAME ": unknown mode in vgatext_resume.");
+ break;
+ }
+}
+
static int
vgatext_kdsetmode(struct vgatext_softc *softc, int mode)
{
@@ -593,21 +714,23 @@ vgatext_kdsetmode(struct vgatext_softc *softc, int mode)
softc->current_base = softc->text_base;
if (softc->cursor.visible) {
vgatext_set_cursor(softc,
- softc->cursor.row, softc->cursor.col);
+ softc->cursor.row, softc->cursor.col);
}
vgatext_restore_colormap(softc);
break;
case KD_GRAPHICS:
+
+
if (vgatext_silent == 1) {
extern void progressbar_stop(void);
vgatext_silent = 0;
progressbar_stop();
}
- for (i = 0; i < sizeof (softc->shadow); i++) {
- softc->shadow[i] = softc->text_base[i];
- }
+ vgatext_save_text(softc);
+
+
softc->current_base = softc->shadow;
#if defined(USE_BORDERS)
vgatext_init_graphics(softc);
@@ -637,7 +760,7 @@ gfxp_vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
}
if (!(off >= VGA_MMAP_FB_BASE &&
- off < VGA_MMAP_FB_BASE + softc->fb_size)) {
+ off < VGA_MMAP_FB_BASE + softc->fb_size)) {
cmn_err(CE_WARN, "vgatext: Can't map offset 0x%llx", off);
return (-1);
}
@@ -647,9 +770,9 @@ gfxp_vgatext_devmap(dev_t dev, devmap_cookie_t dhp, offset_t off, size_t len,
else
length = len;
- if ((err = devmap_devmem_setup(dhp, softc->devi, NULL, softc->fb_regno,
- off - VGA_MMAP_FB_BASE,
- length, PROT_ALL, 0, &dev_attr)) < 0) {
+ if ((err = devmap_devmem_setup(dhp, softc->devi,
+ NULL, softc->fb_regno, off - VGA_MMAP_FB_BASE,
+ length, PROT_ALL, 0, &dev_attr)) < 0) {
return (err);
}
@@ -709,10 +832,10 @@ vgatext_cons_display(struct vgatext_softc *softc, struct vis_consdisplay *da)
* system startup graphics.
*/
attr = (solaris_color_to_pc_color[da->bg_color & 0xf] << 4)
- | solaris_color_to_pc_color[da->fg_color & 0xf];
+ | solaris_color_to_pc_color[da->fg_color & 0xf];
string = da->data;
addr = (struct cgatext *)softc->current_base
- + (da->row * TEXT_COLS + da->col);
+ + (da->row * TEXT_COLS + da->col);
for (i = 0; i < da->width; i++) {
addr->ch = string[i];
addr->attr = attr;
@@ -915,20 +1038,20 @@ vgatext_set_text(struct vgatext_softc *softc)
/* set sequencer registers */
vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
- (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) &
- ~VGA_SEQ_RST_SYN_NO_SYNC_RESET));
+ (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) &
+ ~VGA_SEQ_RST_SYN_NO_SYNC_RESET));
for (i = 1; i < NUM_SEQ_REG; i++) {
vga_set_seq(&softc->regs, i, VGA_SEQ_TEXT[i]);
}
vga_set_seq(&softc->regs, VGA_SEQ_RST_SYN,
- (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) |
- VGA_SEQ_RST_SYN_NO_ASYNC_RESET |
- VGA_SEQ_RST_SYN_NO_SYNC_RESET));
+ (vga_get_seq(&softc->regs, VGA_SEQ_RST_SYN) |
+ VGA_SEQ_RST_SYN_NO_ASYNC_RESET |
+ VGA_SEQ_RST_SYN_NO_SYNC_RESET));
/* set crt controller registers */
vga_set_crtc(&softc->regs, VGA_CRTC_VRE,
- (vga_get_crtc(&softc->regs, VGA_CRTC_VRE) &
- ~VGA_CRTC_VRE_LOCK));
+ (vga_get_crtc(&softc->regs, VGA_CRTC_VRE) &
+ ~VGA_CRTC_VRE_LOCK));
for (i = 0; i < NUM_CRTC_REG; i++) {
vga_set_crtc(&softc->regs, i, VGA_CRTC_TEXT[i]);
}
@@ -946,8 +1069,8 @@ vgatext_set_text(struct vgatext_softc *softc)
/* set palette */
for (i = 0; i < VGA_TEXT_CMAP_ENTRIES; i++) {
vga_put_cmap(&softc->regs, i, VGA_TEXT_PALETTES[i][0] << 2,
- VGA_TEXT_PALETTES[i][1] << 2,
- VGA_TEXT_PALETTES[i][2] << 2);
+ VGA_TEXT_PALETTES[i][1] << 2,
+ VGA_TEXT_PALETTES[i][2] << 2);
}
for (i = VGA_TEXT_CMAP_ENTRIES; i < VGA8_CMAP_ENTRIES; i++) {
vga_put_cmap(&softc->regs, i, 0, 0, 0);
@@ -970,10 +1093,10 @@ vgatext_init(struct vgatext_softc *softc)
vga_set_atr(&softc->regs, VGA_ATR_MODE, atr_mode);
#if defined(USE_BORDERS)
vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
- vga_get_atr(&softc->regs, VGA_BRIGHT_WHITE));
+ vga_get_atr(&softc->regs, VGA_BRIGHT_WHITE));
#else
vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
- vga_get_atr(&softc->regs, VGA_BLACK));
+ vga_get_atr(&softc->regs, VGA_BLACK));
#endif
vgatext_setfont(softc); /* need selectable font? */
}
@@ -983,7 +1106,7 @@ static void
vgatext_init_graphics(struct vgatext_softc *softc)
{
vga_set_atr(&softc->regs, VGA_ATR_BDR_CLR,
- vga_get_atr(&softc->regs, VGA_BLACK));
+ vga_get_atr(&softc->regs, VGA_BLACK));
}
#endif
@@ -1044,9 +1167,9 @@ vgatext_save_colormap(struct vgatext_softc *softc)
}
for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
vga_get_cmap(&softc->regs, i,
- &softc->colormap[i].red,
- &softc->colormap[i].green,
- &softc->colormap[i].blue);
+ &softc->colormap[i].red,
+ &softc->colormap[i].green,
+ &softc->colormap[i].blue);
}
}
@@ -1060,9 +1183,9 @@ vgatext_restore_colormap(struct vgatext_softc *softc)
}
for (i = 0; i < VGA8_CMAP_ENTRIES; i++) {
vga_put_cmap(&softc->regs, i,
- softc->colormap[i].red,
- softc->colormap[i].green,
- softc->colormap[i].blue);
+ softc->colormap[i].red,
+ softc->colormap[i].green,
+ softc->colormap[i].blue);
}
}
@@ -1097,7 +1220,7 @@ vgatext_get_pci_reg_index(
pci_regspec_t *reg;
if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
- "reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
+ "reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
return (-1);
}
@@ -1156,7 +1279,7 @@ vgatext_get_isa_reg_index(
struct regspec *reg;
if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
- "reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
+ "reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
return (-1);
}
@@ -1176,3 +1299,22 @@ vgatext_get_isa_reg_index(
return (-1);
}
+
+/*
+ * This vgatext function is used to return the fb, and reg pointers
+ * and handles for peer graphics drivers.
+ */
+
+void
+vgatext_return_pointers(struct vgatext_softc *softc,
+ struct vgaregmap *fbs,
+ struct vgaregmap *regss)
+{
+
+ fbs->addr = softc->fb.addr;
+ fbs->handle = softc->fb.handle;
+ fbs->mapped = softc->fb.mapped;
+ regss->addr = softc->regs.addr;
+ regss->handle = softc->regs.handle;
+ regss->mapped = softc->regs.mapped;
+}
diff --git a/usr/src/uts/i86pc/io/mc/mcamd_drv.c b/usr/src/uts/i86pc/io/mc/mcamd_drv.c
index d7c9371795..284de242a9 100644
--- a/usr/src/uts/i86pc/io/mc/mcamd_drv.c
+++ b/usr/src/uts/i86pc/io/mc/mcamd_drv.c
@@ -1491,6 +1491,17 @@ mc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
int chipid, rc;
mc_t *mc;
+ /*
+ * This driver has no hardware state, but does
+ * claim to have a reg property, so it will be
+ * called on suspend. It is probably better to
+ * make sure it doesn't get called on suspend,
+ * but it is just as easy to make sure we just
+ * return DDI_SUCCESS if called.
+ */
+ if (cmd == DDI_RESUME)
+ return (DDI_SUCCESS);
+
if (cmd != DDI_ATTACH || mc_no_attach != 0)
return (DDI_FAILURE);
@@ -1672,7 +1683,14 @@ mc_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
static int
mc_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
- return (DDI_FAILURE);
+ /*
+ * See the comment about suspend in
+ * mc_attach().
+ */
+ if (cmd == DDI_SUSPEND)
+ return (DDI_SUCCESS);
+ else
+ return (DDI_FAILURE);
}
static struct dev_ops mc_ops = {
diff --git a/usr/src/uts/i86pc/io/mp_platform_common.c b/usr/src/uts/i86pc/io/mp_platform_common.c
index 7acbca94a8..563b6b7cdd 100644
--- a/usr/src/uts/i86pc/io/mp_platform_common.c
+++ b/usr/src/uts/i86pc/io/mp_platform_common.c
@@ -30,8 +30,9 @@
* PSMI 1.2 extensions are supported only in 2.7 and later versions.
* PSMI 1.3 and 1.4 extensions are supported in Solaris 10.
* PSMI 1.5 extensions are supported in Solaris Nevada.
+ * PSMI 1.6 extensions are supported in Solaris Nevada.
*/
-#define PSMI_1_5
+#define PSMI_1_6
#include <sys/processor.h>
#include <sys/time.h>
@@ -3989,3 +3990,182 @@ apic_is_ioapic_AMD_813x(uint32_t physaddr)
ndi_rele_devi(ioapicsnode);
return (rv);
}
+
+struct apic_state {
+ int32_t as_task_reg;
+ int32_t as_dest_reg;
+ int32_t as_format_reg;
+ int32_t as_local_timer;
+ int32_t as_pcint_vect;
+ int32_t as_int_vect0;
+ int32_t as_int_vect1;
+ int32_t as_err_vect;
+ int32_t as_init_count;
+ int32_t as_divide_reg;
+ int32_t as_spur_int_reg;
+ int32_t as_ioapic[6][24]; /* spec says 23 */
+};
+
+
+static void
+apic_save_state(struct apic_state *sp)
+{
+ int i;
+
+ PMD(PMD_SX, ("apic_save_state %p\n", (void *)sp))
+ /*
+ * First the local APIC.
+ */
+ sp->as_task_reg = apicadr[APIC_TASK_REG];
+ sp->as_dest_reg = apicadr[APIC_DEST_REG];
+ sp->as_format_reg = apicadr[APIC_FORMAT_REG];
+ sp->as_local_timer = apicadr[APIC_LOCAL_TIMER];
+ sp->as_pcint_vect = apicadr[APIC_PCINT_VECT];
+ sp->as_int_vect0 = apicadr[APIC_INT_VECT0];
+ sp->as_int_vect1 = apicadr[APIC_INT_VECT1];
+ sp->as_err_vect = apicadr[APIC_ERR_VECT];
+ sp->as_init_count = apicadr[APIC_INIT_COUNT];
+ sp->as_divide_reg = apicadr[APIC_DIVIDE_REG];
+ sp->as_spur_int_reg = apicadr[APIC_SPUR_INT_REG];
+
+ /*
+ * if on the boot processor then save the IO APICs.
+ */
+ if (psm_get_cpu_id() == 0) {
+ for (i = 0; i < apic_io_max; i++) {
+ volatile uint32_t *ioapic = apicioadr[i];
+ int intin_max, j;
+
+ /* Bits 23-16 define the maximum redirection entries */
+ ioapic[APIC_IO_REG] = APIC_VERS_CMD;
+ intin_max = (ioapic[APIC_IO_DATA] >> 16) & 0xff;
+#if 0 /* debug */
+ prom_printf("\nIOAPIC %d (%d redirs):\n",
+ i, intin_max+1);
+#endif /* debug */
+ for (j = 0; j <= intin_max; j++) {
+ ioapic[APIC_IO_REG] = APIC_RDT_CMD + 2*j;
+ sp->as_ioapic[i][j] = ioapic[APIC_IO_DATA];
+#if 0 /* debug */
+ prom_printf("\t%d: %x\n", j, as_ioapic[i][j]);
+#endif /* debug */
+ }
+ }
+ }
+}
+
+static void
+apic_restore_state(struct apic_state *sp)
+{
+ int i;
+ int iflag;
+ apic_irq_t *irqp;
+ int rv;
+ int retval = 0;
+
+ /*
+ * First the local APIC.
+ */
+ apicadr[APIC_TASK_REG] = sp->as_task_reg;
+ apicadr[APIC_DEST_REG] = sp->as_dest_reg;
+ apicadr[APIC_FORMAT_REG] = sp->as_format_reg;
+ apicadr[APIC_LOCAL_TIMER] = sp->as_local_timer;
+ apicadr[APIC_PCINT_VECT] = sp->as_pcint_vect;
+ apicadr[APIC_INT_VECT0] = sp->as_int_vect0;
+ apicadr[APIC_INT_VECT1] = sp->as_int_vect1;
+ apicadr[APIC_ERR_VECT] = sp->as_err_vect;
+ apicadr[APIC_INIT_COUNT] = sp->as_init_count;
+ apicadr[APIC_DIVIDE_REG] = sp->as_divide_reg;
+ apicadr[APIC_SPUR_INT_REG] = sp->as_spur_int_reg;
+
+ /*
+ * the following only needs to be done once, so we do it on the
+ * boot processor, since we know that we only have one of those
+ */
+ if (psm_get_cpu_id() == 0) {
+ /*
+ * regenerate the IO APICs.
+ */
+
+ iflag = intr_clear();
+ lock_set(&apic_ioapic_lock);
+
+ for (i = apic_min_device_irq; i < apic_max_device_irq; i++) {
+ if ((irqp = apic_irq_table[i]) == NULL)
+ continue;
+ for (; irqp; irqp = irqp->airq_next) {
+ if (irqp->airq_mps_intr_index == FREE_INDEX)
+ continue;
+ if (irqp->airq_temp_cpu != IRQ_UNINIT) {
+ rv = apic_setup_io_intr(irqp, i,
+ B_FALSE);
+ if (rv) {
+ PMD(PMD_SX,
+ ("apic_setup_io_intr(%p, "
+ "%d) %d\n", (void *)irqp,
+ i, rv));
+ }
+ retval |= rv;
+ }
+ }
+ }
+
+ PMD(PMD_SX, ("apic_restore_state retval %x\n", retval))
+
+ lock_clear(&apic_ioapic_lock);
+ intr_restore(iflag);
+
+
+ /*
+ * restore acpi link device mappings
+ */
+ acpi_restore_link_devices();
+ }
+}
+
+/*
+ * Returns 0 on success
+ */
+int
+apic_state(psm_state_request_t *rp)
+{
+ PMD(PMD_SX, ("apic_state "))
+ switch (rp->psr_cmd) {
+ case PSM_STATE_ALLOC:
+ rp->req.psm_state_req.psr_state =
+ kmem_zalloc(sizeof (struct apic_state), KM_NOSLEEP);
+ if (rp->req.psm_state_req.psr_state == NULL)
+ return (ENOMEM);
+ rp->req.psm_state_req.psr_state_size =
+ sizeof (struct apic_state);
+ PMD(PMD_SX, (":STATE_ALLOC: state %p, size %lx\n",
+ rp->req.psm_state_req.psr_state,
+ rp->req.psm_state_req.psr_state_size))
+ return (0);
+
+ case PSM_STATE_FREE:
+ kmem_free(rp->req.psm_state_req.psr_state,
+ rp->req.psm_state_req.psr_state_size);
+ PMD(PMD_SX, (" STATE_FREE: state %p, size %lx\n",
+ rp->req.psm_state_req.psr_state,
+ rp->req.psm_state_req.psr_state_size))
+ return (0);
+
+ case PSM_STATE_SAVE:
+ PMD(PMD_SX, (" STATE_SAVE: state %p, size %lx\n",
+ rp->req.psm_state_req.psr_state,
+ rp->req.psm_state_req.psr_state_size))
+ apic_save_state(rp->req.psm_state_req.psr_state);
+ return (0);
+
+ case PSM_STATE_RESTORE:
+ apic_restore_state(rp->req.psm_state_req.psr_state);
+ PMD(PMD_SX, (" STATE_RESTORE: state %p, size %lx\n",
+ rp->req.psm_state_req.psr_state,
+ rp->req.psm_state_req.psr_state_size))
+ return (0);
+
+ default:
+ return (EINVAL);
+ }
+}
diff --git a/usr/src/uts/i86pc/io/pci/pci.c b/usr/src/uts/i86pc/io/pci/pci.c
index 1af5ca17fb..7cd0b38d4e 100644
--- a/usr/src/uts/i86pc/io/pci/pci.c
+++ b/usr/src/uts/i86pc/io/pci/pci.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -221,6 +221,16 @@ pci_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
*/
int instance = ddi_get_instance(devi);
pci_state_t *pcip = NULL;
+ switch (cmd) {
+ case DDI_ATTACH:
+ break;
+
+ case DDI_RESUME:
+ return (DDI_SUCCESS);
+
+ default:
+ return (DDI_FAILURE);
+ }
if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type", "pci")
!= DDI_PROP_SUCCESS) {
@@ -285,23 +295,30 @@ pci_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
pci_state_t *pcip;
pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(devi));
- if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) {
- ddi_fm_handler_unregister(devi);
- pci_ereport_teardown(devi);
- }
- mutex_destroy(&pcip->pci_peek_poke_mutex);
- mutex_destroy(&pcip->pci_err_mutex);
- ddi_fm_fini(devi);
- /* Uninitialize pcitool support. */
- pcitool_uninit(devi);
- /* Uninitialize hotplug support on this bus. */
- (void) pcihp_uninit(devi);
+ switch (cmd) {
+ case DDI_DETACH:
+ if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE) {
+ ddi_fm_handler_unregister(devi);
+ pci_ereport_teardown(devi);
+ }
+ mutex_destroy(&pcip->pci_peek_poke_mutex);
+ mutex_destroy(&pcip->pci_err_mutex);
+ ddi_fm_fini(devi); /* Uninitialize pcitool support. */
+ pcitool_uninit(devi);
- ddi_soft_state_free(pci_statep, instance);
+ /* Uninitialize hotplug support on this bus. */
+ (void) pcihp_uninit(devi);
- return (DDI_SUCCESS);
+ ddi_soft_state_free(pci_statep, instance);
+
+ return (DDI_SUCCESS);
+ case DDI_SUSPEND:
+ return (DDI_SUCCESS);
+ default:
+ return (DDI_FAILURE);
+ }
}
static int
@@ -510,6 +527,7 @@ pci_ctlops(dev_info_t *dip, dev_info_t *rdip,
int rn;
int totreg;
pci_state_t *pcip;
+ struct attachspec *asp;
switch (ctlop) {
case DDI_CTLOPS_REPORTDEV:
@@ -537,8 +555,8 @@ pci_ctlops(dev_info_t *dip, dev_info_t *rdip,
*(int *)result = 0;
if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip,
- DDI_PROP_DONTPASS, "reg", (int **)&drv_regp,
- &reglen) != DDI_PROP_SUCCESS) {
+ DDI_PROP_DONTPASS, "reg", (int **)&drv_regp,
+ &reglen) != DDI_PROP_SUCCESS) {
return (DDI_FAILURE);
}
@@ -578,6 +596,21 @@ pci_ctlops(dev_info_t *dip, dev_info_t *rdip,
pci_common_peekpoke, &pcip->pci_err_mutex,
&pcip->pci_peek_poke_mutex));
+ /* for now only X86 systems support PME wakeup from suspended state */
+ case DDI_CTLOPS_ATTACH:
+ asp = (struct attachspec *)arg;
+ if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE)
+ if (pci_pre_resume(rdip) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+ return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+
+ case DDI_CTLOPS_DETACH:
+ asp = (struct attachspec *)arg;
+ if (asp->cmd == DDI_SUSPEND && asp->when == DDI_POST)
+ if (pci_post_suspend(rdip) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+ return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+
default:
return (ddi_ctlops(dip, rdip, ctlop, arg, result));
}
@@ -679,8 +712,7 @@ pci_initchild(dev_info_t *child)
* Support for the "command-preserve" property.
*/
command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
- DDI_PROP_DONTPASS,
- "command-preserve", 0);
+ DDI_PROP_DONTPASS, "command-preserve", 0);
command = pci_config_get16(config_handle, PCI_CONF_COMM);
command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
command |= (pci_command_default & ~command_preserve);
diff --git a/usr/src/uts/i86pc/io/pciex/npe.c b/usr/src/uts/i86pc/io/pciex/npe.c
index 80ff196f44..fde4276cc7 100644
--- a/usr/src/uts/i86pc/io/pciex/npe.c
+++ b/usr/src/uts/i86pc/io/pciex/npe.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -228,6 +228,9 @@ npe_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
int instance = ddi_get_instance(devi);
pci_state_t *pcip = NULL;
+ if (cmd == DDI_RESUME)
+ return (DDI_SUCCESS);
+
if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "device_type",
"pciex") != DDI_PROP_SUCCESS) {
cmn_err(CE_WARN, "npe: 'device_type' prop create failed");
@@ -282,20 +285,29 @@ npe_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
pcip = ddi_get_soft_state(npe_statep, ddi_get_instance(devi));
- /* Uninitialize pcitool support. */
- pcitool_uninit(devi);
+ switch (cmd) {
+ case DDI_DETACH:
- /*
- * Uninitialize hotplug support on this bus.
- */
- (void) pcihp_uninit(devi);
+ /* Uninitialize pcitool support. */
+ pcitool_uninit(devi);
- if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE)
- ddi_fm_handler_unregister(devi);
+ /*
+ * Uninitialize hotplug support on this bus.
+ */
+ (void) pcihp_uninit(devi);
- ddi_fm_fini(devi);
- ddi_soft_state_free(npe_statep, instance);
- return (DDI_SUCCESS);
+ if (pcip->pci_fmcap & DDI_FM_ERRCB_CAPABLE)
+ ddi_fm_handler_unregister(devi);
+
+ ddi_fm_fini(devi);
+ ddi_soft_state_free(npe_statep, instance);
+ return (DDI_SUCCESS);
+
+ case DDI_SUSPEND:
+ return (DDI_SUCCESS);
+ default:
+ return (DDI_FAILURE);
+ }
}
@@ -598,6 +610,7 @@ npe_ctlops(dev_info_t *dip, dev_info_t *rdip,
int totreg;
uint_t reglen;
pci_regspec_t *drv_regp;
+ struct attachspec *asp;
switch (ctlop) {
case DDI_CTLOPS_REPORTDEV:
@@ -662,6 +675,30 @@ npe_ctlops(dev_info_t *dip, dev_info_t *rdip,
case DDI_CTLOPS_POKE:
return (pci_common_peekpoke(dip, rdip, ctlop, arg, result));
+ /* X86 systems support PME wakeup from suspended state */
+ case DDI_CTLOPS_ATTACH:
+ asp = (struct attachspec *)arg;
+ /* only do this for immediate children */
+ if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE &&
+ ddi_get_parent(rdip) == dip)
+ if (pci_pre_resume(rdip) != DDI_SUCCESS) {
+ /* Not good, better stop now. */
+ cmn_err(CE_PANIC,
+ "Couldn't pre-resume device %p",
+ (void *) dip);
+ /* NOTREACHED */
+ }
+ return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+
+ case DDI_CTLOPS_DETACH:
+ asp = (struct attachspec *)arg;
+ /* only do this for immediate children */
+ if (asp->cmd == DDI_SUSPEND && asp->when == DDI_POST &&
+ ddi_get_parent(rdip) == dip)
+ if (pci_post_suspend(rdip) != DDI_SUCCESS)
+ return (DDI_FAILURE);
+ return (ddi_ctlops(dip, rdip, ctlop, arg, result));
+
default:
break;
}
diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic.c b/usr/src/uts/i86pc/io/pcplusmp/apic.c
index f31aa2dbcc..e63f2d596a 100644
--- a/usr/src/uts/i86pc/io/pcplusmp/apic.c
+++ b/usr/src/uts/i86pc/io/pcplusmp/apic.c
@@ -31,8 +31,9 @@
* PSMI 1.2 extensions are supported only in 2.7 and later versions.
* PSMI 1.3 and 1.4 extensions are supported in Solaris 10.
* PSMI 1.5 extensions are supported in Solaris Nevada.
+ * PSMI 1.6 extensions are supported in Solaris Nevada.
*/
-#define PSMI_1_5
+#define PSMI_1_6
#include <sys/processor.h>
#include <sys/time.h>
@@ -238,12 +239,13 @@ static struct psm_ops apic_ops = {
apic_timer_disable,
apic_post_cyclic_setup,
apic_preshutdown,
- apic_intr_ops /* Advanced DDI Interrupt framework */
+ apic_intr_ops, /* Advanced DDI Interrupt framework */
+ apic_state, /* save, restore apic state for S3 */
};
static struct psm_info apic_psm_info = {
- PSM_INFO_VER01_5, /* version */
+ PSM_INFO_VER01_6, /* version */
PSM_OWN_EXCLUSIVE, /* ownership */
(struct psm_ops *)&apic_ops, /* operation */
APIC_PCPLUSMP_NAME, /* machine name */
@@ -1371,6 +1373,9 @@ apic_preshutdown(int cmd, int fcn)
APIC_VERBOSE_POWEROFF(("apic_preshutdown(%d,%d); m=%d a=%d\n",
cmd, fcn, apic_poweroff_method, apic_enable_acpi));
+ if ((cmd != A_SHUTDOWN) || (fcn != AD_POWEROFF)) {
+ return;
+ }
}
static void
diff --git a/usr/src/uts/i86pc/io/ppm.conf b/usr/src/uts/i86pc/io/ppm.conf
index 830e94a28a..ea1f555526 100644
--- a/usr/src/uts/i86pc/io/ppm.conf
+++ b/usr/src/uts/i86pc/io/ppm.conf
@@ -34,6 +34,7 @@ name="ppm" parent="pseudo" instance=0;
# the nature of the domain;
#
# "domain_xxx-model" - PM model: CPU
+# "domain_xxx-model" - PM model: SX
#
# "domain_xxx-propname" - a property name that is exported by device in
# a domain. Currently, it is used by PCI_PROP model to identify devices
@@ -58,7 +59,7 @@ name="ppm" parent="pseudo" instance=0;
#
# which keywords apply depends on cmd. There are two sets as shown below.
# Here is the first:
-# cmd=[PCI_ON | PCI_OFF]
+# cmd=[ENTER_S3 | ENTER_S4]
# path=<prompath> - control device's prom pathname (includes minor)
# method=[KIO|I2CKIO] This selects a method which may be
# an ioctl that sets a single value or an i2c ioctl that
@@ -69,7 +70,48 @@ name="ppm" parent="pseudo" instance=0;
# the relevant bits of a register will be set
# mask=<integer> - which bits of val are relevant (if method is I2CKIO)
#
+ppm-domains="domain_cpu" , "domain_estar";
-ppm-domains="domain_cpu";
+#
+# CPU domain
+#
domain_cpu-devices="/cpus/cpu@*";
domain_cpu-model="CPU";
+
+#
+# Estar domain
+# 0x4101 is APPMIOC_ENTER_S3 (('A' << 8) | 1)
+# 0x4102 is APPMIOC_EXIT_S3 (('A' << 8) | 2)
+#
+domain_estar-devices="/";
+domain_estar-model="SX";
+domain_estar-control=
+ "cmd=ENTER_S3 path=/pseudo/acpippm@0:acpi-ppm method=KIO iowr=0x4101",
+ "cmd=EXIT_S3 path=/pseudo/acpippm@0:acpi-ppm method=KIO iowr=0x4102";
+
+#
+# S3-enable whitelist
+#
+S3-support-enable =
+ "Sun Microsystems", "Sun Ultra 40 Workstation",
+ "Sun Microsystems", "Sun Ultra 20 Workstation";
+
+S3-support-disable =
+ "Sun Microsystems", "Sun Blade x8400 Server Module",
+ "Sun Microsystems", "Sun Fire*";
+
+S3-autoenable =
+ "Sun Microsystems", "Sun Ultra 40 Workstation",
+ "Sun Microsystems", "Sun Ultra 20 Workstation";
+
+S3-autodisable =
+ "Sun Microsystems", "Sun Blade x8400 Server Module",
+ "Sun Microsystems", "Sun Fire*";
+
+autopm-enable =
+ "Sun Microsystems", "Sun Ultra 40 Workstation",
+ "Sun Microsystems", "Sun Ultra 20 Workstation";
+
+autopm-disable =
+ "Sun Microsystems", "Sun Blade x8400 Server Module",
+ "Sun Microsystems", "Sun Fire*";
diff --git a/usr/src/uts/i86pc/io/ppm/acpippm.c b/usr/src/uts/i86pc/io/ppm/acpippm.c
new file mode 100644
index 0000000000..a8e5019e50
--- /dev/null
+++ b/usr/src/uts/i86pc/io/ppm/acpippm.c
@@ -0,0 +1,443 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/open.h>
+#include <sys/modctl.h>
+#include <sys/promif.h>
+#include <sys/stat.h>
+#include <sys/ddi_impldefs.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/epm.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+#include <sys/psm_types.h>
+
+/*
+ * ACPI Power Management Driver
+ *
+ * acpippm deals with those bits of ppm functionality that
+ * must be mediated by ACPI
+ *
+ * The routines in this driver is referenced by Platform
+ * Power Management driver of X86 workstation systems.
+ * acpippm driver is loaded because it is listed as a platform driver
+ * It is initially configured as a pseudo driver.
+ */
+
+/*
+ * Configuration Function prototypes and data structures
+ */
+static int appm_attach(dev_info_t *, ddi_attach_cmd_t);
+static int appm_detach(dev_info_t *, ddi_detach_cmd_t);
+static int appm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
+static int appm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
+static int appm_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
+static int appm_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
+
+/*
+ * Configuration data structures
+ */
+static struct cb_ops appm_cbops = {
+ appm_open, /* open */
+ appm_close, /* close */
+ nodev, /* strategy */
+ nodev, /* print */
+ nodev, /* dump */
+ nodev, /* read */
+ nodev, /* write */
+ appm_ioctl, /* ioctl */
+ nodev, /* devmap */
+ nodev, /* mmap */
+ nodev, /* segmap */
+ nochpoll, /* chpoll */
+ ddi_prop_op, /* prop_op */
+ NULL, /* stream */
+ D_MP | D_NEW, /* flag */
+ CB_REV, /* rev */
+ nodev, /* aread */
+ nodev, /* awrite */
+};
+
+static struct dev_ops appm_ops = {
+ DEVO_REV, /* devo_rev */
+ 0, /* refcnt */
+ appm_getinfo, /* getinfo */
+ nulldev, /* identify */
+ nulldev, /* probe */
+ appm_attach, /* attach */
+ appm_detach, /* detach */
+ nodev, /* reset */
+ &appm_cbops, /* cb_ops */
+ NULL, /* bus_ops */
+ NULL /* power */
+};
+
+extern struct mod_ops mod_driverops;
+
+static struct modldrv modldrv = {
+ &mod_driverops,
+ "ACPI ppm driver v1.8",
+ &appm_ops,
+};
+
+static struct modlinkage modlinkage = {
+ MODREV_1,
+ &modldrv,
+ NULL
+};
+
+/*
+ * Driver state structure
+ */
+typedef struct {
+ dev_info_t *dip;
+ ddi_acc_handle_t devid_hndl;
+ ddi_acc_handle_t estar_hndl;
+ int lyropen; /* ref count */
+} appm_unit;
+
+/*
+ * Driver global variables
+ *
+ * appm_lock synchronize the access of lyr handle to each appm
+ * minor device, therefore write to tomatillo device is
+ * sequentialized. Lyr protocol requires pairing up lyr open
+ * and close, so only a single reference is allowed per minor node.
+ */
+static void *appm_statep;
+static kmutex_t appm_lock;
+
+/*
+ * S3 stuff:
+ */
+char _depends_on[] = "misc/acpica";
+
+extern int acpi_enter_sleepstate(s3a_t *);
+extern int acpi_exit_sleepstate(s3a_t *);
+
+
+int
+_init(void)
+{
+ int error;
+
+ if ((error = ddi_soft_state_init(&appm_statep,
+ sizeof (appm_unit), 0)) != DDI_SUCCESS) {
+ return (error);
+ }
+
+ mutex_init(&appm_lock, NULL, MUTEX_DRIVER, NULL);
+
+ if ((error = mod_install(&modlinkage)) != DDI_SUCCESS) {
+ mutex_destroy(&appm_lock);
+ ddi_soft_state_fini(&appm_statep);
+ return (error);
+ }
+
+ return (error);
+}
+
+int
+_fini(void)
+{
+ int error;
+
+ if ((error = mod_remove(&modlinkage)) == DDI_SUCCESS) {
+ mutex_destroy(&appm_lock);
+ ddi_soft_state_fini(&appm_statep);
+ }
+
+ return (error);
+
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+ return (mod_info(&modlinkage, modinfop));
+}
+
+
+
+/*
+ * Driver attach(9e) entry point
+ */
+static int
+appm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+ char *str = "appm_attach";
+ int instance;
+ appm_unit *unitp;
+ int rv = DDI_SUCCESS;
+
+ switch (cmd) {
+ case DDI_ATTACH:
+ break;
+ case DDI_RESUME:
+ return (DDI_SUCCESS);
+ default:
+ cmn_err(CE_WARN, "%s: cmd %d unsupported.\n", str, cmd);
+ return (DDI_FAILURE);
+ }
+
+ instance = ddi_get_instance(dip);
+ rv = ddi_soft_state_zalloc(appm_statep, instance);
+ if (rv != DDI_SUCCESS) {
+ cmn_err(CE_WARN, "%s: failed alloc for dev(%s@%s)",
+ str, ddi_binding_name(dip),
+ ddi_get_name_addr(dip) ? ddi_get_name_addr(dip) : " ");
+ return (rv);
+ }
+
+ if ((unitp = ddi_get_soft_state(appm_statep, instance)) == NULL) {
+ rv = DDI_FAILURE;
+ goto doerrs;
+ }
+
+ /*
+ * Export "ddi-kernel-ioctl" property - prepared to support
+ * kernel ioctls (driver layering).
+ * XXX is this still needed?
+ * XXXX (RSF) Not that I am aware of.
+ */
+ rv = ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
+ DDI_KERNEL_IOCTL, NULL, 0);
+ if (rv != DDI_PROP_SUCCESS)
+ goto doerrs;
+
+ ddi_report_dev(dip);
+ unitp->dip = dip;
+
+ /*
+ * XXX here we would do whatever we need to to determine if the
+ * XXX platform supports ACPI, and fail the attach if not.
+ * XXX If it does, we do whatever setup is needed to get access to
+ * XXX ACPI register space.
+ */
+
+ unitp->lyropen = 0;
+
+ /*
+ * create minor node for kernel_ioctl calls
+ */
+ rv = ddi_create_minor_node(dip, "acpi-ppm", S_IFCHR, instance, 0, 0);
+ if (rv != DDI_SUCCESS)
+ goto doerrs;
+
+ return (rv);
+
+doerrs:
+
+ if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS |
+ DDI_PROP_NOTPROM, DDI_KERNEL_IOCTL))
+ ddi_prop_remove_all(dip);
+
+ ddi_soft_state_free(appm_statep, instance);
+
+ return (rv);
+}
+
+
+/*
+ * Driver getinfo(9e) entry routine
+ */
+/* ARGSUSED */
+static int
+appm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+ appm_unit *unitp;
+ int instance;
+
+ switch (cmd) {
+ case DDI_INFO_DEVT2DEVINFO:
+ instance = getminor((dev_t)arg);
+ unitp = ddi_get_soft_state(appm_statep, instance);
+ if (unitp == NULL) {
+ return (DDI_FAILURE);
+ }
+ *result = (void *) unitp->dip;
+ return (DDI_SUCCESS);
+
+ case DDI_INFO_DEVT2INSTANCE:
+ instance = getminor((dev_t)arg);
+ *result = (void *)(uintptr_t)instance;
+ return (DDI_SUCCESS);
+
+ default:
+ return (DDI_FAILURE);
+ }
+}
+
+
+/*
+ * detach(9e)
+ */
+/* ARGSUSED */
+static int
+appm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+ char *str = "appm_detach";
+
+ switch (cmd) {
+ case DDI_DETACH:
+ return (DDI_FAILURE);
+ case DDI_SUSPEND:
+ return (DDI_SUCCESS);
+ default:
+ cmn_err(CE_WARN, "%s: cmd %d unsupported", str, cmd);
+ return (DDI_FAILURE);
+ }
+}
+
+
+/* ARGSUSED */
+static int
+appm_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
+{
+ appm_unit *unitp;
+
+ /* not intended to allow sysadmin level root process to open it */
+ if (drv_priv(cred_p) != DDI_SUCCESS)
+ return (EPERM);
+
+ if ((unitp = ddi_get_soft_state(
+ appm_statep, getminor(*dev_p))) == NULL) {
+ cmn_err(CE_WARN, "appm_open: failed to get soft state!");
+ return (DDI_FAILURE);
+ }
+
+ mutex_enter(&appm_lock);
+ if (unitp->lyropen != 0) {
+ mutex_exit(&appm_lock);
+ return (EBUSY);
+ }
+ unitp->lyropen++;
+ mutex_exit(&appm_lock);
+
+ return (DDI_SUCCESS);
+}
+
+
+/* ARGSUSED */
+static int
+appm_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
+{
+ appm_unit *unitp;
+
+ if ((unitp =
+ ddi_get_soft_state(appm_statep, getminor(dev))) == NULL)
+ return (DDI_FAILURE);
+
+ mutex_enter(&appm_lock);
+ unitp->lyropen = 0;
+ mutex_exit(&appm_lock);
+
+ return (DDI_SUCCESS);
+}
+
+
+/*
+ * must match ppm.conf
+ */
+#define APPMIOC ('A' << 8)
+#define APPMIOC_ENTER_S3 (APPMIOC | 1) /* arg *s3a_t */
+#define APPMIOC_EXIT_S3 (APPMIOC | 2) /* arg *s3a_t */
+
+/* ARGSUSED3 */
+static int
+appm_ioctl(dev_t dev, int cmd, intptr_t arg, int flag,
+ cred_t *cred_p, int *rval_p)
+{
+ static boolean_t acpi_initted = B_FALSE;
+ char *str = "appm_ioctl";
+ int ret;
+ s3a_t *s3ap = (s3a_t *)arg;
+
+ PMD(PMD_SX, ("%s: called with %x\n", str, cmd))
+
+ if (drv_priv(cred_p) != 0) {
+ PMD(PMD_SX, ("%s: EPERM\n", str))
+ return (EPERM);
+ }
+
+ if (ddi_get_soft_state(appm_statep, getminor(dev)) == NULL) {
+ PMD(PMD_SX, ("%s: no soft state: EIO\n", str))
+ return (EIO);
+ }
+
+ if (!acpi_initted) {
+ PMD(PMD_SX, ("%s: !acpi_initted\n", str))
+ if (acpica_init() == 0) {
+ acpi_initted = B_TRUE;
+ } else {
+ if (rval_p != NULL) {
+ *rval_p = EINVAL;
+ }
+ PMD(PMD_SX, ("%s: EINVAL\n", str))
+ return (EINVAL);
+ }
+ }
+
+ PMD(PMD_SX, ("%s: looking for cmd %x\n", str, cmd))
+ switch (cmd) {
+ case APPMIOC_ENTER_S3:
+ /*
+ * suspend to RAM (ie S3)
+ */
+ PMD(PMD_SX, ("%s: cmd %x, arg %p\n", str, cmd, (void *)arg))
+ ret = acpi_enter_sleepstate(s3ap);
+ break;
+
+ case APPMIOC_EXIT_S3:
+ /*
+ * return from S3
+ */
+ PMD(PMD_SX, ("%s: cmd %x, arg %p\n", str, cmd, (void *)arg))
+ ret = acpi_exit_sleepstate(s3ap);
+ break;
+
+ default:
+ PMD(PMD_SX, ("%s: cmd %x unrecognized: ENOTTY\n", str, cmd))
+ return (ENOTTY);
+ }
+
+ /*
+ * upon failure return EINVAL
+ */
+ if (ret != 0) {
+ if (rval_p != NULL) {
+ *rval_p = EINVAL;
+ }
+ return (EINVAL);
+ }
+
+ return (0);
+}
diff --git a/usr/src/uts/i86pc/io/ppm/acpippm.h b/usr/src/uts/i86pc/io/ppm/acpippm.h
new file mode 100644
index 0000000000..c60aedfc15
--- /dev/null
+++ b/usr/src/uts/i86pc/io/ppm/acpippm.h
@@ -0,0 +1,41 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SYS_ACPIPPM_H
+#define _SYS_ACPIPPM_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYS_ACPIPPM_H */
diff --git a/usr/src/uts/i86pc/io/ppm/acpisleep.c b/usr/src/uts/i86pc/io/ppm/acpisleep.c
new file mode 100644
index 0000000000..d1ab6c5c34
--- /dev/null
+++ b/usr/src/uts/i86pc/io/ppm/acpisleep.c
@@ -0,0 +1,214 @@
+/*
+ * 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 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/types.h>
+#include <sys/smp_impldefs.h>
+#include <sys/promif.h>
+
+#include <sys/kmem.h>
+#include <sys/archsystm.h>
+#include <sys/cpuvar.h>
+#include <sys/pte.h>
+#include <vm/seg_kmem.h>
+#include <sys/epm.h>
+#include <sys/machsystm.h>
+#include <sys/clock.h>
+
+#include <sys/cpr_wakecode.h>
+#include <sys/acpi/acpi.h>
+
+#ifdef OLDPMCODE
+#include "acpi.h"
+#endif
+
+#include <sys/x86_archext.h>
+#include <sys/reboot.h>
+#include <sys/cpu_module.h>
+#include <sys/kdi.h>
+
+/*
+ * S3 stuff
+ */
+
+int acpi_rtc_wake = 0x0; /* wake in N seconds */
+
+#if 0 /* debug */
+static uint8_t branchbuf[64 * 1024]; /* for the HDT branch trace stuff */
+#endif /* debug */
+
+extern int boothowto;
+
+#define BOOTCPU 0 /* cpu 0 is always the boot cpu */
+
+extern void kernel_wc_code(void);
+extern tod_ops_t *tod_ops;
+extern int flushes_require_xcalls;
+extern int tsc_gethrtime_enable;
+
+extern cpuset_t cpu_ready_set;
+extern void *(*cpu_pause_func)(void *);
+
+/*
+ * This probably belong in apic.c, along with the save/restore stuff.
+ */
+static void
+reinit_picmode(void)
+{
+ ACPI_OBJECT_LIST arglist;
+ ACPI_OBJECT arg;
+ ACPI_STATUS status;
+
+ /* Setup parameter object */
+ arglist.Count = 1;
+ arglist.Pointer = &arg;
+ arg.Type = ACPI_TYPE_INTEGER;
+ arg.Integer.Value = 1;
+
+ status = AcpiEvaluateObject(NULL, "\\_PIC", &arglist, NULL);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ PMD(PMD_SX, ("Method _PIC failed, %d\n", status))
+ }
+}
+
+
+/*
+ * This is what we've all been waiting for!
+ */
+int
+acpi_enter_sleepstate(s3a_t *s3ap)
+{
+ ACPI_PHYSICAL_ADDRESS wakephys = s3ap->s3a_wakephys;
+ caddr_t wakevirt = rm_platter_va;
+ /*LINTED*/
+ wakecode_t *wp = (wakecode_t *)wakevirt;
+ uint_t Sx = s3ap->s3a_state;
+
+ PT(PT_SWV);
+ /* Set waking vector */
+ if (AcpiSetFirmwareWakingVector(wakephys) != AE_OK) {
+ PT(PT_SWV_FAIL);
+ PMD(PMD_SX, ("Can't SetFirmwareWakingVector(%lx)\n",
+ (long)wakephys))
+ goto insomnia;
+ }
+
+ PT(PT_EWE);
+ /* Enable wake events */
+ if (AcpiEnableEvent(ACPI_EVENT_POWER_BUTTON, 0) != AE_OK) {
+ PT(PT_EWE_FAIL);
+ PMD(PMD_SX, ("Can't EnableEvent(POWER_BUTTON)\n"))
+ }
+ if (acpi_rtc_wake > 0) {
+ PT(PT_RTCW);
+ if (AcpiEnableEvent(ACPI_EVENT_RTC, 0) != AE_OK) {
+ PT(PT_RTCW_FAIL);
+ PMD(PMD_SX, ("Can't EnableEvent(RTC)\n"))
+ }
+
+ /*
+ * Set RTC to wake us in a wee while.
+ */
+ mutex_enter(&tod_lock);
+ PT(PT_TOD);
+ TODOP_SETWAKE(tod_ops, acpi_rtc_wake);
+ mutex_exit(&tod_lock);
+ }
+
+ /*
+ * Prepare for sleep ... could've done this earlier?
+ */
+ PT(PT_SXP);
+ PMD(PMD_SX, ("Calling AcpiEnterSleepStatePrep(%d) ...\n", Sx))
+ if (AcpiEnterSleepStatePrep(Sx) != AE_OK) {
+ PMD(PMD_SX, ("... failed\n!"))
+ goto insomnia;
+ }
+
+ switch (s3ap->s3a_test_point) {
+ case DEVICE_SUSPEND_TO_RAM:
+ case LOOP_BACK_PASS:
+ return (0);
+ case LOOP_BACK_FAIL:
+ return (1);
+ default:
+ ASSERT(s3ap->s3a_test_point == LOOP_BACK_NONE ||
+ s3ap->s3a_test_point == FORCE_SUSPEND_TO_RAM);
+ }
+
+ /*
+ * Tell the hardware to sleep.
+ */
+ PT(PT_SXE);
+ PMD(PMD_SX, ("Calling AcpiEnterSleepState(%d) ...\n", Sx))
+ if (AcpiEnterSleepState(Sx) != AE_OK) {
+ PT(PT_SXE_FAIL);
+ PMD(PMD_SX, ("... failed!\n"))
+ }
+
+insomnia:
+ PT(PT_INSOM);
+ /* cleanup is done in the caller */
+ return (1);
+}
+
+int
+acpi_exit_sleepstate(s3a_t *s3ap)
+{
+ int Sx = s3ap->s3a_state;
+
+ PT(PT_WOKE);
+ PMD(PMD_SX, ("!We woke up!\n"))
+
+ PT(PT_LSS);
+ if (AcpiLeaveSleepState(Sx) != AE_OK) {
+ PT(PT_LSS_FAIL);
+ PMD(PMD_SX, ("Problem with LeaveSleepState!\n"))
+ }
+
+ PT(PT_DPB);
+ if (AcpiDisableEvent(ACPI_EVENT_POWER_BUTTON, 0) != AE_OK) {
+ PT(PT_DPB_FAIL);
+ PMD(PMD_SX, ("Problem w/ DisableEvent(POWER_BUTTON)\n"))
+ }
+ if (acpi_rtc_wake > 0 &&
+ AcpiDisableEvent(ACPI_EVENT_RTC, 0) != AE_OK) {
+ PT(PT_DRTC_FAIL);
+ PMD(PMD_SX, ("Problem w/ DisableEvent(RTC)\n"))
+ }
+
+ PMD(PMD_SX, ("Restore state of APICs\n"))
+
+ /* Restore state of APICs */
+ PT(PT_ACPIREINIT);
+ reinit_picmode();
+ PT(PT_ACPIRESTORE);
+
+ PMD(PMD_SX, ("Exiting acpi_sleepstate() => 0\n"))
+
+ return (0);
+}
diff --git a/usr/src/uts/i86pc/io/psm/psm_common.c b/usr/src/uts/i86pc/io/psm/psm_common.c
index fd92327093..bfbcfcb1be 100644
--- a/usr/src/uts/i86pc/io/psm/psm_common.c
+++ b/usr/src/uts/i86pc/io/psm/psm_common.c
@@ -623,9 +623,9 @@ acpi_get_current_irq_resource(acpi_psm_lnk_t *acpipsmlnkp, int *pci_irqp,
}
intr_flagp->intr_el = psm_acpi_edgelevel(
- rp->Data.Irq.Triggering);
+ rp->Data.Irq.Triggering);
intr_flagp->intr_po = psm_acpi_po(
- rp->Data.Irq.Polarity);
+ rp->Data.Irq.Polarity);
irq = rp->Data.Irq.Interrupts[0];
status = ACPI_PSM_SUCCESS;
} else if (rp->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
@@ -644,9 +644,9 @@ acpi_get_current_irq_resource(acpi_psm_lnk_t *acpipsmlnkp, int *pci_irqp,
}
intr_flagp->intr_el = psm_acpi_edgelevel(
- rp->Data.ExtendedIrq.Triggering);
+ rp->Data.ExtendedIrq.Triggering);
intr_flagp->intr_po = psm_acpi_po(
- rp->Data.ExtendedIrq.Polarity);
+ rp->Data.ExtendedIrq.Polarity);
irq = rp->Data.ExtendedIrq.Interrupts[0];
status = ACPI_PSM_SUCCESS;
}
@@ -799,7 +799,7 @@ acpi_get_possible_irq_resources(acpi_psm_lnk_t *acpipsmlnkp,
/* NEEDSWORK: move this into add_irqlist_entry someday */
irqlist = kmem_zalloc(irqlist_len * sizeof (*irqlist),
- KM_SLEEP);
+ KM_SLEEP);
for (i = 0; i < irqlist_len; i++)
if (resp->Type == ACPI_RESOURCE_TYPE_IRQ)
irqlist[i] = ((uint8_t *)tmplist)[i];
@@ -808,7 +808,7 @@ acpi_get_possible_irq_resources(acpi_psm_lnk_t *acpipsmlnkp,
intr_flags.intr_el = psm_acpi_edgelevel(el);
intr_flags.intr_po = psm_acpi_po(po);
acpi_add_irqlist_entry(irqlistp, irqlist, irqlist_len,
- &intr_flags);
+ &intr_flags);
}
AcpiOsFree(rsb.Pointer);
@@ -925,6 +925,32 @@ acpi_get_irq_lnk_cache_ent(ACPI_HANDLE lnkobj, int *pci_irqp,
return (ret);
}
+/*
+ * Walk the irq_cache_table and re-configure the link device to
+ * the saved state.
+ */
+void
+acpi_restore_link_devices(void)
+{
+ irq_cache_t *irqcachep;
+ acpi_psm_lnk_t psmlnk;
+ int i, status;
+
+ /* XXX: may not need to hold this mutex */
+ mutex_enter(&acpi_irq_cache_mutex);
+ for (irqcachep = irq_cache_table, i = 0; i < irq_cache_valid;
+ irqcachep++, i++) {
+ /* only field used from psmlnk in set_irq is lnkobj */
+ psmlnk.lnkobj = irqcachep->lnkobj;
+ status = acpi_set_irq_resource(&psmlnk, irqcachep->irq);
+ /* warn if set_irq failed; soldier on */
+ if (status != ACPI_PSM_SUCCESS)
+ cmn_err(CE_WARN, "restore_link failed for IRQ 0x%x\n",
+ irqcachep->irq);
+ }
+ mutex_exit(&acpi_irq_cache_mutex);
+}
+
int
acpi_poweroff(void)
{
diff --git a/usr/src/uts/i86pc/io/psm/uppc.c b/usr/src/uts/i86pc/io/psm/uppc.c
index 51181b0415..2fd3f860c5 100644
--- a/usr/src/uts/i86pc/io/psm/uppc.c
+++ b/usr/src/uts/i86pc/io/psm/uppc.c
@@ -25,7 +25,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
-#define PSMI_1_5
+#define PSMI_1_6
#include <sys/mutex.h>
#include <sys/types.h>
diff --git a/usr/src/uts/i86pc/io/todpc_subr.c b/usr/src/uts/i86pc/io/todpc_subr.c
index 7e55876af3..5b92cb9077 100644
--- a/usr/src/uts/i86pc/io/todpc_subr.c
+++ b/usr/src/uts/i86pc/io/todpc_subr.c
@@ -47,13 +47,79 @@
#include <sys/stat.h>
#include <sys/sunddi.h>
+#include <sys/acpi/acpi.h>
+#include <sys/acpica.h>
+
static int todpc_rtcget(unsigned char *buf);
static void todpc_rtcput(unsigned char *buf);
+#define CLOCK_RES 1000 /* 1 microsec in nanosecs */
+
+int clock_res = CLOCK_RES;
+
+/*
+ * The minimum sleep time till an alarm can be fired.
+ * This can be tuned in /etc/system, but if the value is too small,
+ * there is a danger that it will be missed if it takes too long to
+ * get from the set point to sleep. Or that it can fire quickly, and
+ * generate a power spike on the hardware. And small values are
+ * probably only usefull for test setups.
+ */
+int clock_min_alarm = 4;
+
/*
* Machine-dependent clock routines.
*/
+extern long gmt_lag;
+
+struct rtc_offset {
+ int8_t loaded;
+ uint8_t day_alrm;
+ uint8_t mon_alrm;
+ uint8_t century;
+};
+
+static struct rtc_offset pc_rtc_offset = {0, 0, 0, 0};
+
+
+/*
+ * Entry point for ACPI to pass RTC or other clock values that
+ * are useful to TOD.
+ */
+void
+pc_tod_set_rtc_offsets(FADT_DESCRIPTOR *fadt) {
+ int ok = 0;
+
+ /*
+ * ASSERT is for debugging, but we don't want the machine
+ * falling over because for some reason we didn't get a valid
+ * pointer.
+ */
+ ASSERT(fadt);
+ if (fadt == NULL) {
+ return;
+ }
+
+ if (fadt->DayAlrm) {
+ pc_rtc_offset.day_alrm = fadt->DayAlrm;
+ ok = 1;
+ }
+
+ if (fadt->MonAlrm) {
+ pc_rtc_offset.mon_alrm = fadt->MonAlrm;
+ ok = 1;
+ }
+
+ if (fadt->Century) {
+ pc_rtc_offset.century = fadt->Century;
+ ok = 1;
+ }
+
+ pc_rtc_offset.loaded = ok;
+}
+
+
/*
* Write the specified time into the clock chip.
* Must be called with tod_lock held.
@@ -123,7 +189,7 @@ todpc_get(tod_ops_t *top)
if (tod.tod_year < 69) {
if (range_warn && tod.tod_year > 38) {
cmn_err(CE_WARN, "hardware real-time clock is out "
- "of range -- time needs to be reset");
+ "of range -- time needs to be reset");
range_warn = 0;
}
tod.tod_year += 100 + YRBASE; /* 20xx year */
@@ -135,12 +201,12 @@ todpc_get(tod_ops_t *top)
}
if (century_warn && BCD_TO_BYTE(rtc.rtc_century) != compute_century) {
cmn_err(CE_NOTE,
- "The hardware real-time clock appears to have the "
- "wrong century: %d.\nSolaris will still operate "
- "correctly, but other OS's/firmware agents may "
- "not.\nUse date(1) to set the date to the current "
- "time to correct the RTC.",
- BCD_TO_BYTE(rtc.rtc_century));
+ "The hardware real-time clock appears to have the "
+ "wrong century: %d.\nSolaris will still operate "
+ "correctly, but other OS's/firmware agents may "
+ "not.\nUse date(1) to set the date to the current "
+ "time to correct the RTC.",
+ BCD_TO_BYTE(rtc.rtc_century));
century_warn = 0;
}
tod.tod_month = BCD_TO_BYTE(rtc.rtc_mon);
@@ -156,6 +222,109 @@ todpc_get(tod_ops_t *top)
return (ts);
}
+#include <sys/promif.h>
+/*
+ * Write the specified wakeup alarm into the clock chip.
+ * Must be called with tod_lock held.
+ */
+void
+/*ARGSUSED*/
+todpc_setalarm(tod_ops_t *top, int nsecs)
+{
+ struct rtc_t rtc;
+ int delta, asec, amin, ahr, adom, amon;
+ int day_alrm = pc_rtc_offset.day_alrm;
+ int mon_alrm = pc_rtc_offset.mon_alrm;
+
+ ASSERT(MUTEX_HELD(&tod_lock));
+
+ /* A delay of zero is not allowed */
+ if (nsecs == 0)
+ return;
+
+ /* Make sure that we delay no less than the minimum time */
+ if (nsecs < clock_min_alarm)
+ nsecs = clock_min_alarm;
+
+ if (todpc_rtcget((unsigned char *)&rtc))
+ return;
+
+ /*
+ * Compute alarm secs, mins and hrs, and where appropriate, dom
+ * and mon. rtc bytes are in binary-coded decimal, so we have
+ * to convert.
+ */
+ delta = nsecs + BCD_TO_BYTE(rtc.rtc_sec);
+ asec = delta % 60;
+
+ delta = (delta / 60) + BCD_TO_BYTE(rtc.rtc_min);
+ amin = delta % 60;
+
+ delta = (delta / 60) + BCD_TO_BYTE(rtc.rtc_hr);
+ ahr = delta % 24;
+
+ if (day_alrm == 0 && delta >= 24) {
+ prom_printf("No day alarm - set to end of today!\n");
+ asec = 59;
+ amin = 59;
+ ahr = 23;
+ } else {
+ int mon = BCD_TO_BYTE(rtc.rtc_mon);
+ static int dpm[] =
+ {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+ adom = (delta / 24) + BCD_TO_BYTE(rtc.rtc_dom);
+
+ if (mon_alrm == 0) {
+ if (adom > dpm[mon]) {
+ prom_printf("No mon alarm - "
+ "set to end of current month!\n");
+ asec = 59;
+ amin = 59;
+ ahr = 23;
+ adom = dpm[mon];
+ }
+ } else {
+ for (amon = mon;
+ amon <= 12 && adom > dpm[amon]; amon++) {
+ adom -= dpm[amon];
+ }
+ if (amon > 12) {
+ prom_printf("Alarm too far in future - "
+ "set to end of current year!\n");
+ asec = 59;
+ amin = 59;
+ ahr = 23;
+ adom = dpm[12];
+ amon = 12;
+ }
+ rtc.rtc_amon = BYTE_TO_BCD(amon);
+ }
+
+ rtc.rtc_adom = BYTE_TO_BCD(adom);
+ }
+
+ rtc.rtc_asec = BYTE_TO_BCD(asec);
+ rtc.rtc_amin = BYTE_TO_BCD(amin);
+ rtc.rtc_ahr = BYTE_TO_BCD(ahr);
+
+ rtc.rtc_statusb |= RTC_AIE; /* Enable alarm interrupt */
+
+ todpc_rtcput((unsigned char *)&rtc);
+}
+
+/*
+ * Clear an alarm. This is effectively setting an alarm of 0.
+ */
+void
+/*ARGSUSED*/
+todpc_clralarm(tod_ops_t *top)
+{
+ mutex_enter(&tod_lock);
+ todpc_setalarm(top, 0);
+ mutex_exit(&tod_lock);
+}
+
/*
* Routine to read contents of real time clock to the specified buffer.
* Returns ENXIO if clock not valid, or EAGAIN if clock data cannot be read
@@ -176,9 +345,18 @@ todpc_rtcget(unsigned char *buf)
int i;
int retries = 256;
unsigned char *rawp;
+ unsigned char century = RTC_CENTURY;
+ unsigned char day_alrm;
+ unsigned char mon_alrm;
ASSERT(MUTEX_HELD(&tod_lock));
+ day_alrm = pc_rtc_offset.day_alrm;
+ mon_alrm = pc_rtc_offset.mon_alrm;
+ if (pc_rtc_offset.century != 0) {
+ century = pc_rtc_offset.century;
+ }
+
outb(RTC_ADDR, RTC_D); /* check if clock valid */
reg = inb(RTC_DATA);
if ((reg & RTC_VRT) == 0)
@@ -198,8 +376,18 @@ checkuip:
outb(RTC_ADDR, i);
*rawp++ = inb(RTC_DATA);
}
- outb(RTC_ADDR, RTC_CENTURY); /* do century */
+ outb(RTC_ADDR, century); /* do century */
((struct rtc_t *)buf)->rtc_century = inb(RTC_DATA);
+
+ if (day_alrm > 0) {
+ outb(RTC_ADDR, day_alrm);
+ ((struct rtc_t *)buf)->rtc_adom = inb(RTC_DATA) & 0x3f;
+ }
+ if (mon_alrm > 0) {
+ outb(RTC_ADDR, mon_alrm);
+ ((struct rtc_t *)buf)->rtc_amon = inb(RTC_DATA);
+ }
+
outb(RTC_ADDR, 0); /* re-read Seconds register */
reg = inb(RTC_DATA);
if (reg != ((struct rtc_t *)buf)->rtc_sec ||
@@ -221,6 +409,13 @@ todpc_rtcput(unsigned char *buf)
{
unsigned char reg;
int i;
+ unsigned char century = RTC_CENTURY;
+ unsigned char day_alrm = pc_rtc_offset.day_alrm;
+ unsigned char mon_alrm = pc_rtc_offset.mon_alrm;
+
+ if (pc_rtc_offset.century != 0) {
+ century = pc_rtc_offset.century;
+ }
outb(RTC_ADDR, RTC_B);
reg = inb(RTC_DATA);
@@ -230,8 +425,20 @@ todpc_rtcput(unsigned char *buf)
outb(RTC_ADDR, i);
outb(RTC_DATA, buf[i]);
}
- outb(RTC_ADDR, RTC_CENTURY); /* do century */
+ outb(RTC_ADDR, century); /* do century */
outb(RTC_DATA, ((struct rtc_t *)buf)->rtc_century);
+
+ if (day_alrm > 0) {
+ outb(RTC_ADDR, day_alrm);
+ outb(RTC_DATA, ((struct rtc_t *)buf)->rtc_adom);
+ }
+ if (mon_alrm > 0) {
+ outb(RTC_ADDR, mon_alrm);
+ outb(RTC_DATA, ((struct rtc_t *)buf)->rtc_amon);
+ }
+
+ outb(RTC_ADDR, RTC_B);
+ reg = inb(RTC_DATA);
outb(RTC_ADDR, RTC_B);
outb(RTC_DATA, reg & ~RTC_SET); /* allow time update */
}
@@ -240,6 +447,10 @@ static tod_ops_t todpc_ops = {
TOD_OPS_VERSION,
todpc_get,
todpc_set,
+ NULL,
+ NULL,
+ todpc_setalarm,
+ todpc_clralarm,
NULL
};