Example #1
0
static int
acpi_tz_cooling_thread_start(struct acpi_tz_softc *sc)
{
    int error;

    ACPI_LOCK(thermal);
    if (sc->tz_cooling_proc_running) {
	ACPI_UNLOCK(thermal);
	return (0);
    }
    sc->tz_cooling_proc_running = TRUE;
    ACPI_UNLOCK(thermal);
    error = 0;
    if (sc->tz_cooling_proc == NULL) {
	error = kproc_create(acpi_tz_cooling_thread, sc,
	    &sc->tz_cooling_proc, RFHIGHPID, 0, "acpi_cooling%d",
	    device_get_unit(sc->tz_dev));
	if (error != 0) {
	    device_printf(sc->tz_dev, "could not create thread - %d", error);
	    ACPI_LOCK(thermal);
	    sc->tz_cooling_proc_running = FALSE;
	    ACPI_UNLOCK(thermal);
	}
    }
    return (error);
}
Example #2
0
/*
 * Thermal zone monitor thread.
 */
static void
acpi_tz_thread(void *arg)
{
    device_t	*devs;
    int		devcount, i;
    int		flags;
    struct acpi_tz_softc **sc;

    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);

    devs = NULL;
    devcount = 0;
    sc = NULL;

    for (;;) {
	/* If the number of devices has changed, re-evaluate. */
	if (devclass_get_count(acpi_tz_devclass) != devcount) {
	    if (devs != NULL) {
		free(devs, M_TEMP);
		free(sc, M_TEMP);
	    }
	    devclass_get_devices(acpi_tz_devclass, &devs, &devcount);
	    sc = malloc(sizeof(struct acpi_tz_softc *) * devcount, M_TEMP,
			M_WAITOK | M_ZERO);
	    for (i = 0; i < devcount; i++)
		sc[i] = device_get_softc(devs[i]);
	}

	/* Check for temperature events and act on them. */
	for (i = 0; i < devcount; i++) {
	    ACPI_LOCK(thermal);
	    flags = sc[i]->tz_flags;
	    sc[i]->tz_flags &= TZ_FLAG_NO_SCP;
	    ACPI_UNLOCK(thermal);
	    acpi_tz_timeout(sc[i], flags);
	}

	/* If more work to do, don't go to sleep yet. */
	ACPI_LOCK(thermal);
	for (i = 0; i < devcount; i++) {
	    if (sc[i]->tz_flags & ~TZ_FLAG_NO_SCP)
		break;
	}

	/*
	 * If we have no more work, sleep for a while, setting PDROP so that
	 * the mutex will not be reacquired.  Otherwise, drop the mutex and
	 * loop to handle more events.
	 */
	if (i == devcount)
	    msleep(&acpi_tz_proc, &thermal_mutex, PZERO | PDROP, "tzpoll",
		hz * acpi_tz_polling_rate);
	else
	    ACPI_UNLOCK(thermal);
    }
}
static void
acpi_cpu_startup_cx(struct acpi_cpu_softc *sc)
{
    acpi_cpu_cx_list(sc);
    
    SYSCTL_ADD_STRING(&sc->cpu_sysctl_ctx,
		      SYSCTL_CHILDREN(device_get_sysctl_tree(sc->cpu_dev)),
		      OID_AUTO, "cx_supported", CTLFLAG_RD,
		      sc->cpu_cx_supported, 0,
		      "Cx/microsecond values for supported Cx states");
    SYSCTL_ADD_PROC(&sc->cpu_sysctl_ctx,
		    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->cpu_dev)),
		    OID_AUTO, "cx_lowest", CTLTYPE_STRING | CTLFLAG_RW,
		    (void *)sc, 0, acpi_cpu_cx_lowest_sysctl, "A",
		    "lowest Cx sleep state to use");
    SYSCTL_ADD_PROC(&sc->cpu_sysctl_ctx,
		    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->cpu_dev)),
		    OID_AUTO, "cx_usage", CTLTYPE_STRING | CTLFLAG_RD,
		    (void *)sc, 0, acpi_cpu_usage_sysctl, "A",
		    "percent usage for each Cx state");

#ifdef notyet
    /* Signal platform that we can handle _CST notification. */
    if (!cpu_cx_generic && cpu_cst_cnt != 0) {
	ACPI_LOCK(acpi);
	AcpiOsWritePort(cpu_smi_cmd, cpu_cst_cnt, 8);
	ACPI_UNLOCK(acpi);
    }
#endif
}
Example #4
0
/* Create a struct for tracking per-device suspend notification. */
static struct apm_clone_data *
apm_create_clone(struct cdev *dev, struct acpi_softc *acpi_sc)
{
	struct apm_clone_data *clone;

	clone = malloc(sizeof(*clone), M_APMDEV, M_WAITOK);
	clone->cdev = dev;
	clone->acpi_sc = acpi_sc;
	clone->notify_status = APM_EV_NONE;
	bzero(&clone->sel_read, sizeof(clone->sel_read));
	knlist_init_mtx(&clone->sel_read.si_note, &acpi_mutex);

	/*
	 * The acpi device is always managed by devd(8) and is considered
	 * writable (i.e., ack is required to allow suspend to proceed.)
	 */
	if (strcmp("acpi", devtoname(dev)) == 0)
		clone->flags = ACPI_EVF_DEVD | ACPI_EVF_WRITE;
	else
		clone->flags = ACPI_EVF_NONE;

	ACPI_LOCK(acpi);
	STAILQ_INSERT_TAIL(&acpi_sc->apm_cdevs, clone, entries);
	ACPI_UNLOCK(acpi);
	return (clone);
}
Example #5
0
static void
acpi_tz_signal(struct acpi_tz_softc *sc, int flags)
{
    ACPI_LOCK(thermal);
    sc->tz_flags |= flags;
    ACPI_UNLOCK(thermal);
    wakeup(&acpi_tz_proc);
}
Example #6
0
static void
apmreadfiltdetach(struct knote *kn)
{
	struct	apm_clone_data *clone;

	ACPI_LOCK(acpi);
	clone = kn->kn_hook;
	knlist_remove(&clone->sel_read.si_note, kn, 0);
	ACPI_UNLOCK(acpi);
}
Example #7
0
static void
acpi_cst_startup(struct acpi_cst_softc *sc)
{
    struct acpi_cpu_softc *cpu = sc->cst_parent;
    int i, bm_rld_done = 0;

    for (i = 0; i < sc->cst_cx_count; ++i) {
	struct acpi_cst_cx *cx = &sc->cst_cx_states[i];
	int error;

	/* If there are C3(+) states, always enable bus master wakeup */
	if (cx->type >= ACPI_STATE_C3 && !bm_rld_done &&
	    (acpi_cst_quirks & ACPI_CST_QUIRK_NO_BM) == 0) {
	    acpi_cst_c3_bm_rld(sc);
	    bm_rld_done = 1;
	}

	/* Redo the Cx setup, since quirks have been changed */
	error = acpi_cst_cx_setup(cx);
	if (error)
	    panic("C%d startup setup failed: %d", i + 1, error);
    }

    acpi_cst_support_list(sc);
    
    SYSCTL_ADD_STRING(&cpu->pcpu_sysctl_ctx,
		      SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree),
		      OID_AUTO, "cx_supported", CTLFLAG_RD,
		      sc->cst_cx_supported, 0,
		      "Cx/microsecond values for supported Cx states");
    SYSCTL_ADD_PROC(&cpu->pcpu_sysctl_ctx,
		    SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree),
		    OID_AUTO, "cx_lowest", CTLTYPE_STRING | CTLFLAG_RW,
		    (void *)sc, 0, acpi_cst_lowest_sysctl, "A",
		    "requested lowest Cx sleep state");
    SYSCTL_ADD_PROC(&cpu->pcpu_sysctl_ctx,
		    SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree),
		    OID_AUTO, "cx_lowest_use", CTLTYPE_STRING | CTLFLAG_RD,
		    (void *)sc, 0, acpi_cst_lowest_use_sysctl, "A",
		    "lowest Cx sleep state to use");
    SYSCTL_ADD_PROC(&cpu->pcpu_sysctl_ctx,
		    SYSCTL_CHILDREN(cpu->pcpu_sysctl_tree),
		    OID_AUTO, "cx_usage", CTLTYPE_STRING | CTLFLAG_RD,
		    (void *)sc, 0, acpi_cst_usage_sysctl, "A",
		    "percent usage for each Cx state");

#ifdef notyet
    /* Signal platform that we can handle _CST notification. */
    if (!acpi_cst_use_fadt && acpi_cst_ctrl != 0) {
	ACPI_LOCK(acpi);
	AcpiOsWritePort(acpi_cst_smi_cmd, acpi_cst_ctrl, 8);
	ACPI_UNLOCK(acpi);
    }
#endif
}
Example #8
0
static void
acpi_px_startup(void *arg)
{

	/* Signal to the platform that we are taking over CPU control. */
	if (AcpiGbl_FADT.PstateControl == 0)
		return;
	ACPI_LOCK(acpi);
	AcpiOsWritePort(AcpiGbl_FADT.SmiCommand, AcpiGbl_FADT.PstateControl, 8);
	ACPI_UNLOCK(acpi);
}
Example #9
0
static int
apmreadfilt(struct knote *kn, long hint)
{
	struct	apm_clone_data *clone;
	int	sleeping;

	ACPI_LOCK(acpi);
	clone = kn->kn_hook;
	sleeping = clone->acpi_sc->acpi_next_sstate ? 1 : 0;
	ACPI_UNLOCK(acpi);
	return (sleeping);
}
Example #10
0
static int
apmkqfilter(struct cdev *dev, struct knote *kn)
{
	struct	apm_clone_data *clone;

	ACPI_LOCK(acpi);
	clone = dev->si_drv1;
	kn->kn_hook = clone;
	kn->kn_fop = &apm_readfiltops;
	knlist_add(&clone->sel_read.si_note, kn, 0);
	ACPI_UNLOCK(acpi);
	return (0);
}
Example #11
0
static int
apmkqfilter(struct cdev *dev, struct knote *kn)
{
	struct	apm_clone_data *clone;

	devfs_get_cdevpriv((void **)&clone);
	ACPI_LOCK(acpi);
	kn->kn_hook = clone;
	kn->kn_fop = &apm_readfiltops;
	knlist_add(&clone->sel_read.si_note, kn, 0);
	ACPI_UNLOCK(acpi);
	return (0);
}
Example #12
0
/*
 * Passive cooling thread; monitors current temperature according to the
 * cooling interval and calculates whether to scale back CPU frequency.
 */
static void
acpi_tz_cooling_thread(void *arg)
{
    struct acpi_tz_softc *sc;
    int error, perf, curr_temp, prev_temp;

    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);

    sc = (struct acpi_tz_softc *)arg;

    prev_temp = sc->tz_temperature;
    while (sc->tz_cooling_enabled) {
	if (sc->tz_cooling_active)
	    (void)acpi_tz_get_temperature(sc);
	curr_temp = sc->tz_temperature;
	if (curr_temp >= sc->tz_zone.psv)
	    sc->tz_cooling_active = TRUE;
	if (sc->tz_cooling_active) {
	    perf = sc->tz_zone.tc1 * (curr_temp - prev_temp) +
		   sc->tz_zone.tc2 * (curr_temp - sc->tz_zone.psv);
	    perf /= 10;

	    if (perf != 0) {
		error = acpi_tz_cpufreq_update(sc, perf);

		/*
		 * If error and not simply a higher priority setting was
		 * active, disable cooling.
		 */
		if (error != 0 && error != EPERM) {
		    device_printf(sc->tz_dev,
			"failed to set new freq, disabling passive cooling\n");
		    sc->tz_cooling_enabled = FALSE;
		}
	    }
	}
	prev_temp = curr_temp;
	tsleep(&sc->tz_cooling_proc, PZERO, "cooling",
	    hz * sc->tz_zone.tsp / 10);
    }
    if (sc->tz_cooling_active) {
	acpi_tz_cpufreq_restore(sc);
	sc->tz_cooling_active = FALSE;
    }
    sc->tz_cooling_proc = NULL;
    ACPI_LOCK(thermal);
    sc->tz_cooling_proc_running = FALSE;
    ACPI_UNLOCK(thermal);
    kproc_exit(0);
}
Example #13
0
static int
apmpoll(struct cdev *dev, int events, struct thread *td)
{
	struct	apm_clone_data *clone;
	int revents;

	revents = 0;
	ACPI_LOCK(acpi);
	clone = dev->si_drv1;
	if (clone->acpi_sc->acpi_next_sstate)
		revents |= events & (POLLIN | POLLRDNORM);
	else
		selrecord(td, &clone->sel_read);
	ACPI_UNLOCK(acpi);
	return (revents);
}
Example #14
0
static void
apmdtor(void *data)
{
	struct	apm_clone_data *clone;
	struct	acpi_softc *acpi_sc;

	clone = data;
	acpi_sc = clone->acpi_sc;

	/* We are about to lose a reference so check if suspend should occur */
	if (acpi_sc->acpi_next_sstate != 0 &&
	    clone->notify_status != APM_EV_ACKED)
		acpi_AckSleepState(clone, 0);

	/* Remove this clone's data from the list and free it. */
	ACPI_LOCK(acpi);
	STAILQ_REMOVE(&acpi_sc->apm_cdevs, clone, apm_clone_data, entries);
	seldrain(&clone->sel_read);
	knlist_destroy(&clone->sel_read.si_note);
	ACPI_UNLOCK(acpi);
	free(clone, M_APMDEV);
}
Example #15
0
static int
apmclose(struct cdev *dev, int flag, int fmt, d_thread_t *td)
{
	struct	apm_clone_data *clone;
	struct	acpi_softc *acpi_sc;

	clone = dev->si_drv1;
	acpi_sc = clone->acpi_sc;

	/* We are about to lose a reference so check if suspend should occur */
	if (acpi_sc->acpi_next_sstate != 0 &&
	    clone->notify_status != APM_EV_ACKED)
		acpi_AckSleepState(clone, 0);

	/* Remove this clone's data from the list and free it. */
	ACPI_LOCK(acpi);
	STAILQ_REMOVE(&acpi_sc->apm_cdevs, clone, apm_clone_data, entries);
	knlist_destroy(&clone->sel_read.si_note);
	ACPI_UNLOCK(acpi);
	free(clone, M_APMDEV);
	destroy_dev_sched(dev);
	return (0);
}
Example #16
0
static int
apmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
{
	int	error;
	struct	apm_clone_data *clone;
	struct	acpi_softc *acpi_sc;
	struct	apm_info info;
	struct 	apm_event_info *ev_info;
	apm_info_old_t aiop;

	error = 0;
	clone = dev->si_drv1;
	acpi_sc = clone->acpi_sc;

	switch (cmd) {
	case APMIO_SUSPEND:
		if ((flag & FWRITE) == 0)
			return (EPERM);
		if (acpi_sc->acpi_next_sstate == 0) {
			if (acpi_sc->acpi_suspend_sx != ACPI_STATE_S5) {
				error = acpi_ReqSleepState(acpi_sc,
				    acpi_sc->acpi_suspend_sx);
			} else {
				printf(
			"power off via apm suspend not supported\n");
				error = ENXIO;
			}
		} else
			error = acpi_AckSleepState(clone, 0);
		break;
	case APMIO_STANDBY:
		if ((flag & FWRITE) == 0)
			return (EPERM);
		if (acpi_sc->acpi_next_sstate == 0) {
			if (acpi_sc->acpi_standby_sx != ACPI_STATE_S5) {
				error = acpi_ReqSleepState(acpi_sc,
				    acpi_sc->acpi_standby_sx);
			} else {
				printf(
			"power off via apm standby not supported\n");
				error = ENXIO;
			}
		} else
			error = acpi_AckSleepState(clone, 0);
		break;
	case APMIO_NEXTEVENT:
		printf("apm nextevent start\n");
		ACPI_LOCK(acpi);
		if (acpi_sc->acpi_next_sstate != 0 && clone->notify_status ==
		    APM_EV_NONE) {
			ev_info = (struct apm_event_info *)addr;
			if (acpi_sc->acpi_next_sstate <= ACPI_STATE_S3)
				ev_info->type = PMEV_STANDBYREQ;
			else
				ev_info->type = PMEV_SUSPENDREQ;
			ev_info->index = 0;
			clone->notify_status = APM_EV_NOTIFIED;
			printf("apm event returning %d\n", ev_info->type);
		} else
			error = EAGAIN;
		ACPI_UNLOCK(acpi);
		break;
	case APMIO_GETINFO_OLD:
		if (acpi_capm_get_info(&info))
			error = ENXIO;
		aiop = (apm_info_old_t)addr;
		aiop->ai_major = info.ai_major;
		aiop->ai_minor = info.ai_minor;
		aiop->ai_acline = info.ai_acline;
		aiop->ai_batt_stat = info.ai_batt_stat;
		aiop->ai_batt_life = info.ai_batt_life;
		aiop->ai_status = info.ai_status;
		break;
	case APMIO_GETINFO:
		if (acpi_capm_get_info((apm_info_t)addr))
			error = ENXIO;
		break;
	case APMIO_GETPWSTATUS:
		if (acpi_capm_get_pwstatus((apm_pwstatus_t)addr))
			error = ENXIO;
		break;
	case APMIO_ENABLE:
		if ((flag & FWRITE) == 0)
			return (EPERM);
		apm_active = 1;
		break;
	case APMIO_DISABLE:
		if ((flag & FWRITE) == 0)
			return (EPERM);
		apm_active = 0;
		break;
	case APMIO_HALTCPU:
		break;
	case APMIO_NOTHALTCPU:
		break;
	case APMIO_DISPLAY:
		if ((flag & FWRITE) == 0)
			return (EPERM);
		break;
	case APMIO_BIOS:
		if ((flag & FWRITE) == 0)
			return (EPERM);
		bzero(addr, sizeof(struct apm_bios_arg));
		break;
	default:
		error = EINVAL;
		break;
	}

	return (error);
}