diff options
author | randyf <none@none> | 2007-10-20 16:00:42 -0700 |
---|---|---|
committer | randyf <none@none> | 2007-10-20 16:00:42 -0700 |
commit | 2df1fe9ca32bb227b9158c67f5c00b54c20b10fd (patch) | |
tree | 358c576f885c00d42a760d9e35e5b66e77209fe2 /usr/src/uts/common/io/ppm | |
parent | 10b3fbf593a6678eec9b50a01903ef4eb73111e4 (diff) | |
download | illumos-gate-2df1fe9ca32bb227b9158c67f5c00b54c20b10fd.tar.gz |
PSARC/2005/469 X86 Energy Star compliance
PSARC/2006/632 PSMI extension for state save and restore
6330209 nge needs to support DDI_SUSPEND/DDI_RESUME
6381827 Suspend to RAM on x86
6393154 audio810 needs to support DDI_SUSPEND/DDI_RESUME
6397047 fd, fdc needs to support Suspend/Resume
6401974 cannot enter S3 with ohci PME enable set on Tyan 2865 with Sun or Tyan 2.01 BIOS
6422613 memscrubber doesn't re-acquire lock before CALLB_CPR_EXIT
6455736 ata/dadk/cmdk should support DDI_SUSPEND/DDI_RESUME
6511370 CPR on SPARC regression
6586018 TODOP Macros in i86pc/sys/machclock.h not in sun4u/sun4v equivilent (Sparc only)
6610124 It takes more than 3 minutes after printing "pci_pre_resume nv_sata:0"
6617143 powerd/pmconfig emits a different default message for an existing on or off action.
--HG--
rename : usr/src/cmd/power/power.conf => usr/src/cmd/power/power.conf.sparc
Diffstat (limited to 'usr/src/uts/common/io/ppm')
-rw-r--r-- | usr/src/uts/common/io/ppm/ppm.c | 175 | ||||
-rw-r--r-- | usr/src/uts/common/io/ppm/ppm_subr.c | 74 |
2 files changed, 223 insertions, 26 deletions
diff --git a/usr/src/uts/common/io/ppm/ppm.c b/usr/src/uts/common/io/ppm/ppm.c index b35a2e369d..e52ff63b78 100644 --- a/usr/src/uts/common/io/ppm/ppm.c +++ b/usr/src/uts/common/io/ppm/ppm.c @@ -206,8 +206,10 @@ int _init(void) { if (ddi_soft_state_init( - &ppm_statep, sizeof (ppm_unit_t), 1) != DDI_SUCCESS) + &ppm_statep, sizeof (ppm_unit_t), 1) != DDI_SUCCESS) { + PPMD(D_INIT, ("ppm: soft state init\n")) return (DDI_FAILURE); + } if (mod_install(&modlinkage) != DDI_SUCCESS) { ddi_soft_state_fini(&ppm_statep); @@ -220,7 +222,12 @@ _init(void) int _fini(void) { - return (mod_remove(&modlinkage)); + int error; + + if ((error = mod_remove(&modlinkage)) == DDI_SUCCESS) + ddi_soft_state_fini(&ppm_statep); + + return (error); } @@ -679,7 +686,7 @@ err_bydom: STRUCT_INIT(norm, mode); ret = ddi_copyin((caddr_t)arg, STRUCT_BUF(norm), - STRUCT_SIZE(norm), mode); + STRUCT_SIZE(norm), mode); if (ret != 0) return (EFAULT); @@ -755,6 +762,10 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip, ppm_owned_t *owned; int mode; int ret = DDI_SUCCESS; + static int ppm_manage_sx(s3a_t *, int); + static int ppm_search_list(pm_searchargs_t *); + int *res = (int *)result; + s3a_t s3args; #ifdef DEBUG char *str = "ppm_ctlops"; @@ -765,8 +776,9 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip, str, ddi_binding_name(rdip), ctlstr)) #endif - if (ctlop != DDI_CTLOPS_POWER) + if (ctlop != DDI_CTLOPS_POWER) { return (DDI_FAILURE); + } unitp = (ppm_unit_t *)ddi_get_soft_state(ppm_statep, ppm_inst); @@ -779,8 +791,6 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip, ppm_manage_led(PPM_LED_BLINKING); else ppm_manage_led(PPM_LED_SOLIDON); - PPMD(D_LOWEST, ("%s: %sall devices are at lowest power \n", - str, mode ? "" : "not ")) return (DDI_SUCCESS); /* undo the claiming of 'rdip' at attach time */ @@ -984,9 +994,37 @@ ppm_ctlops(dev_info_t *dip, dev_info_t *rdip, return (DDI_FAILURE); } + case PMR_PPM_ENTER_SX: + case PMR_PPM_EXIT_SX: + s3args.s3a_state = reqp->req.ppm_power_enter_sx_req.sx_state; + s3args.s3a_test_point = + reqp->req.ppm_power_enter_sx_req.test_point; + s3args.s3a_wakephys = reqp->req.ppm_power_enter_sx_req.wakephys; + s3args.s3a_psr = reqp->req.ppm_power_enter_sx_req.psr; + ret = ppm_manage_sx(&s3args, + reqp->request_type == PMR_PPM_ENTER_SX); + if (ret) { + PPMD(D_CPR, ("ppm_manage_sx returns %d\n", ret)) + return (DDI_FAILURE); + } else { + return (DDI_SUCCESS); + } + + case PMR_PPM_SEARCH_LIST: + ret = ppm_search_list(reqp->req.ppm_search_list_req.searchlist); + reqp->req.ppm_search_list_req.result = ret; + *res = ret; + if (ret) { + PPMD(D_CPR, ("ppm_search_list returns %d\n", ret)) + return (DDI_FAILURE); + } else { + PPMD(D_CPR, ("ppm_search_list returns %d\n", ret)) + return (DDI_SUCCESS); + } + default: cmn_err(CE_WARN, "ppm_ctlops: unrecognized ctlops req(%d)", - reqp->request_type); + reqp->request_type); return (DDI_FAILURE); } } @@ -1246,7 +1284,7 @@ ppm_bringup_domains() } mutex_exit(&domp->lock); } - PPMD(D_CPR, ("%s[%d]: exit, ret=%d\n", str, ppmbringup, ret)) + PPMD(D_CPR, ("%s[%d]: exit\n", str, ppmbringup)) return (ret); } @@ -1275,6 +1313,15 @@ ppm_sync_bookkeeping() mutex_exit(&domp->lock); continue; } + + /* + * skip NULL .devlist slot, for some may host pci device + * that can not tolerate clock off or not even participate + * in PM. + */ + if (domp->devlist == NULL) + continue; + switch (domp->model) { case PPMD_FET: ret = ppm_fetset(domp, PPMD_OFF); @@ -1291,7 +1338,7 @@ ppm_sync_bookkeeping() } mutex_exit(&domp->lock); } - PPMD(D_CPR, ("%s[%d]: exit, ret=%d\n", str, ppmsyncbp, ret)) + PPMD(D_CPR, ("%s[%d]: exit\n", str, ppmsyncbp)) return (ret); } @@ -1655,14 +1702,14 @@ ppm_fetset(ppm_domain_t *domp, uint8_t value) * we might wait for longer than required */ PPMD(D_FET, ("%s : waiting %lu micro seconds " - "before on\n", domp->name, - delay - temp)) + "before on\n", domp->name, + delay - temp)); drv_usecwait(delay - temp); } } } switch (dc->method) { -#if !defined(__x86) +#ifdef sun4u case PPMDC_I2CKIO: { i2c_gpio_t i2c_req; i2c_req.reg_mask = dc->m_un.i2c.mask; @@ -1739,7 +1786,7 @@ ppm_fetget(ppm_domain_t *domp, uint8_t *lvl) } switch (dc->method) { -#if !defined(__x86) +#ifdef sun4u case PPMDC_I2CKIO: { i2c_gpio_t i2c_req; i2c_req.reg_mask = dc->m_un.i2c.mask; @@ -1773,7 +1820,7 @@ ppm_fetget(ppm_domain_t *domp, uint8_t *lvl) } off_val = (dc->cmd == PPMDC_FET_OFF) ? dc->m_un.kio.val : - dc->next->m_un.kio.val; + dc->next->m_un.kio.val; *lvl = (kio_val == off_val) ? PPMD_OFF : PPMD_ON; PPMD(D_FET, ("%s: %s domain FET %s\n", str, domp->name, @@ -2187,7 +2234,7 @@ ppm_gpioset(ppm_domain_t *domp, int key) } switch (dc->method) { -#if !defined(__x86) +#ifdef sun4u case PPMDC_I2CKIO: { i2c_gpio_t i2c_req; ppm_dev_t *pdev; @@ -2223,6 +2270,7 @@ ppm_gpioset(ppm_domain_t *domp, int key) break; } #endif + case PPMDC_KIO: ret = ldi_ioctl(dc->lh, dc->m_un.kio.iowr, (intptr_t)&(dc->m_un.kio.val), FWRITE | FKIOCTL, kcred, @@ -2666,3 +2714,100 @@ ppm_power_down_domain(dev_info_t *dip) mutex_exit(&domp->lock); return (ret); } + +static int +ppm_manage_sx(s3a_t *s3ap, int enter) +{ + ppm_domain_t *domp = ppm_lookup_domain("domain_estar"); + ppm_dc_t *dc; + int ret = 0; + + if (domp == NULL) { + PPMD(D_CPR, ("ppm_manage_sx: can't find estar domain\n")) + return (ENODEV); + } + PPMD(D_CPR, ("ppm_manage_sx %x, enter %d\n", s3ap->s3a_state, + enter)) + switch (s3ap->s3a_state) { + case S3: + if (enter) { + dc = ppm_lookup_dc(domp, PPMDC_ENTER_S3); + } else { + dc = ppm_lookup_dc(domp, PPMDC_EXIT_S3); + } + ASSERT(dc && dc->method == PPMDC_KIO); + PPMD(D_CPR, + ("ppm_manage_sx: calling acpi driver (handle %p)" + " with %x\n", (void *)dc->lh, dc->m_un.kio.iowr)) + ret = ldi_ioctl(dc->lh, dc->m_un.kio.iowr, + (intptr_t)s3ap, FWRITE | FKIOCTL, kcred, NULL); + break; + + case S4: + /* S4 is not supported yet */ + return (EINVAL); + default: + ASSERT(0); + } + return (ret); +} + +/* + * Search enable/disable lists, which are encoded in ppm.conf as an array + * of char strings. + */ +static int +ppm_search_list(pm_searchargs_t *sl) +{ + int i; + int flags = DDI_PROP_DONTPASS; + ppm_unit_t *unitp = ddi_get_soft_state(ppm_statep, ppm_inst); + char **pp; + char *starp; + uint_t nelements; + char *manuf = sl->pms_manufacturer; + char *prod = sl->pms_product; + + if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, unitp->dip, flags, + sl->pms_listname, &pp, &nelements) != DDI_PROP_SUCCESS) { + PPMD(D_CPR, ("ppm_search_list prop lookup %s failed--EINVAL\n", + sl->pms_listname)) + return (EINVAL); + } + ASSERT((nelements & 1) == 0); /* must be even */ + + PPMD(D_CPR, ("ppm_search_list looking for %s, %s\n", manuf, prod)) + + for (i = 0; i < nelements; i += 2) { + PPMD(D_CPR, ("checking %s, %s", pp[i], pp[i+1])) + /* we support only a trailing '*' pattern match */ + if ((starp = strchr(pp[i], '*')) != NULL && *(starp + 1) == 0) { + /* LINTED - ptrdiff overflow */ + if (strncmp(manuf, pp[i], (starp - pp[i])) != 0) { + PPMD(D_CPR, (" no match %s with %s\n", + manuf, pp[i + 1])) + continue; + } + } + if ((starp = strchr(pp[i + 1], '*')) != NULL && + *(starp + 1) == 0) { + if (strncmp(prod, + /* LINTED - ptrdiff overflow */ + pp[i + 1], (starp - pp[i + 1])) != 0) { + PPMD(D_CPR, (" no match %s with %s\n", + prod, pp[i + 1])) + continue; + } + } + if (strcmp(manuf, pp[i]) == 0 && + (strcmp(prod, pp[i + 1]) == 0)) { + PPMD(D_CPR, (" match\n")) + ddi_prop_free(pp); + return (0); + } + PPMD(D_CPR, (" no match %s with %s or %s with %s\n", + manuf, pp[i], prod, pp[i + 1])) + } + ddi_prop_free(pp); + return (ENODEV); +} diff --git a/usr/src/uts/common/io/ppm/ppm_subr.c b/usr/src/uts/common/io/ppm/ppm_subr.c index 4bcd24c877..617ac3a380 100644 --- a/usr/src/uts/common/io/ppm/ppm_subr.c +++ b/usr/src/uts/common/io/ppm/ppm_subr.c @@ -207,6 +207,7 @@ ppm_lookup_hndl(int model, ppm_dc_t *key_dc) #define PPM_CTRL_PROP_SUFFIX "-control" struct ppm_domit ppm_domit_data[] = { + "SX", PPMD_SX, 0, PPMD_ON, "CPU", PPMD_CPU, PPMD_LOCK_ALL, PPMD_ON, "FET", PPMD_FET, PPMD_LOCK_ONE, PPMD_ON, "PCI", PPMD_PCI, PPMD_LOCK_ONE, PPMD_ON, @@ -401,11 +402,19 @@ ppm_lookup_dev(dev_info_t *dip) PPM_GET_PATHNAME(dip, path); for (domp = ppm_domain_p; domp; domp = domp->next) { - if (PPM_DOMAIN_UP(domp)) + if (PPM_DOMAIN_UP(domp)) { for (dbp = domp->conflist; dbp; dbp = dbp->next) { + /* + * allow claiming root without knowing + * its full name + */ + if (dip == ddi_root_node() && + strcmp(dbp->name, "/") == 0) + return (domp); if (ppm_match_devs(path, dbp) == 0) return (domp); } + } } return (NULL); @@ -514,7 +523,8 @@ ppm_match_devs(char *dev_path, ppm_db_t *dbp) /* "<exact match>*" */ if (dbp->name[dbp->wcpos[0] + 1] == 0) { cp = path + dbp->wcpos[0]; - while (*cp && (*cp++ != '/')); + while (*cp && (*cp++ != '/')) + ; return ((*cp == 0) ? 0 : -1); } @@ -761,6 +771,22 @@ ppm_init_cb(dev_info_t *dip) for (domp = ppm_domain_p; domp != NULL; domp = domp->next) { for (dc = domp->dc; dc; dc = dc->next) { + /* + * Warning: This code is rather confusing. + * + * It intends to ensure that ppm_init_lyr() is only + * called ONCE for a device that may be associated + * with more than one domain control. + * So, what it does is first to check to see if + * there is a handle, and then if not it goes on + * to call the init_lyr() routine. + * + * The non-obvious thing is that the ppm_init_lyr() + * routine, in addition to opening the device + * associated with the dc (domain control) in + * question, has the side-effect of creating the + * handle for that dc as well. + */ if (ppm_lookup_hndl(domp->model, dc) != NULL) continue; @@ -979,6 +1005,8 @@ struct ppm_confdefs { char *sym; int val; } ppm_confdefs_table[] = { + "ENTER_S3", PPMDC_ENTER_S3, + "EXIT_S3", PPMDC_EXIT_S3, "CPU_NEXT", PPMDC_CPU_NEXT, "PRE_CHNG", PPMDC_PRE_CHNG, "CPU_GO", PPMDC_CPU_GO, @@ -991,7 +1019,9 @@ struct ppm_confdefs { "LED_OFF", PPMDC_LED_OFF, "KIO", PPMDC_KIO, "VCORE", PPMDC_VCORE, +#ifdef sun4u "I2CKIO", PPMDC_I2CKIO, +#endif "CPUSPEEDKIO", PPMDC_CPUSPEEDKIO, "PRE_PWR_OFF", PPMDC_PRE_PWR_OFF, "PRE_PWR_ON", PPMDC_PRE_PWR_ON, @@ -1103,14 +1133,20 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc) (void) ppm_stoi(dclist[i], &dc->m_un.cpu.speeds); continue; } +#ifdef sun4u if (strstr(dclist[i], "mask=")) { (void) ppm_stoi(dclist[i], &dc->m_un.i2c.mask); continue; } +#endif /* This must be before the if statement for delay */ if (strstr(dclist[i], "post_delay=")) { +#ifdef sun4u ASSERT(dc->method == PPMDC_KIO || dc->method == PPMDC_I2CKIO); +#else + ASSERT(dc->method == PPMDC_KIO); +#endif /* * all delays are uint_t type instead of clock_t. * If the delay is too long, it might get truncated. @@ -1119,13 +1155,15 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc) switch (dc->method) { case PPMDC_KIO: (void) ppm_stoi(dclist[i], - &dc->m_un.kio.post_delay); + &dc->m_un.kio.post_delay); break; +#ifdef sun4u case PPMDC_I2CKIO: (void) ppm_stoi(dclist[i], - &dc->m_un.i2c.post_delay); + &dc->m_un.i2c.post_delay); break; +#endif default: break; @@ -1133,9 +1171,14 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc) continue; } if (strstr(dclist[i], "delay=")) { +#ifdef sun4u + ASSERT(dc->method == PPMDC_VCORE || + dc->method == PPMDC_KIO || + dc->method == PPMDC_I2CKIO); +#else ASSERT(dc->method == PPMDC_VCORE || - dc->method == PPMDC_KIO || - dc->method == PPMDC_I2CKIO); + dc->method == PPMDC_KIO); +#endif /* * all delays are uint_t type instead of clock_t. @@ -1148,9 +1191,11 @@ ppm_parse_dc(char **dc_namep, ppm_dc_t *dc) (void) ppm_stoi(dclist[i], &dc->m_un.kio.delay); break; +#ifdef sun4u case PPMDC_I2CKIO: (void) ppm_stoi(dclist[i], &dc->m_un.i2c.delay); break; +#endif case PPMDC_VCORE: (void) ppm_stoi(dclist[i], &dc->m_un.cpu.delay); @@ -1227,6 +1272,8 @@ ppm_lookup_dc(ppm_domain_t *domp, int cmd) case PPMDC_PWR_ON: case PPMDC_RESET_OFF: case PPMDC_RESET_ON: + case PPMDC_ENTER_S3: + case PPMDC_EXIT_S3: break; default: PPMD(D_PPMDC, ("%s: cmd(%d) unrecognized\n", str, cmd)) @@ -1234,9 +1281,11 @@ ppm_lookup_dc(ppm_domain_t *domp, int cmd) } for (dc = domp->dc; dc; dc = dc->next) { - if (dc->cmd == cmd) + if (dc->cmd == cmd) { return (dc); + } } + return (NULL); } @@ -1315,6 +1364,7 @@ ppm_get_ctlstr(int ctlop, uint_t mask) FLINTSTR(D_LOCKS, PMR_PPM_UNLOCK_POWER), FLINTSTR(D_LOCKS, PMR_PPM_TRY_LOCK_POWER), FLINTSTR(D_LOCKS, PMR_PPM_POWER_LOCK_OWNER), + FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_PPM_ENTER_SX), FLINTSTR(D_CTLOPS1 | D_CTLOPS2, PMR_UNKNOWN), }; @@ -1334,13 +1384,15 @@ ppm_print_dc(ppm_dc_t *dc) PPMD(D_PPMDC, ("\nAdds ppm_dc: path(%s),\n cmd(%x), " "method(%x), ", d->path, d->cmd, d->method)) - if (d->method == PPMDC_I2CKIO) { + if (d->method == PPMDC_KIO) { + PPMD(D_PPMDC, ("kio.iowr(%x), kio.val(0x%X)", + d->m_un.kio.iowr, d->m_un.kio.val)) +#ifdef sun4u + } else if (d->method == PPMDC_I2CKIO) { PPMD(D_PPMDC, ("i2c.iowr(%x), i2c.val(0x%X), " "i2c.mask(0x%X)", d->m_un.i2c.iowr, d->m_un.i2c.val, d->m_un.i2c.mask)) - } else if (d->method == PPMDC_KIO) { - PPMD(D_PPMDC, ("kio.iowr(%x), kio.val(0x%X)", - d->m_un.kio.iowr, d->m_un.kio.val)) +#endif } else if (d->method == PPMDC_VCORE) { PPMD(D_PPMDC, ("cpu: .iord(%x), .iowr(%x), .val(0x%X), " ".delay(0x%x)", |