예제 #1
0
/*
 * Query ACPI processor ID by evaluating ACPI _MAT, _UID, and PROCESSOR
 * objects.
 */
static ACPI_STATUS
acpidev_cpu_get_procid(acpidev_walk_info_t *infop, uint32_t *idp)
{
	int id;
	ACPI_HANDLE hdl;
	struct acpidev_cpu_MAT_arg mat;

	if (infop->awi_info->Type != ACPI_TYPE_PROCESSOR &&
	    infop->awi_info->Type != ACPI_TYPE_DEVICE) {
		ACPIDEV_DEBUG(CE_WARN,
		    "!acpidev: object %s is not PROCESSOR or DEVICE.",
		    infop->awi_name);
		return (AE_BAD_PARAMETER);
	}
	hdl = infop->awi_hdl;

	/*
	 * First try to evaluate _MAT.
	 * According to the ACPI Spec3.0b, it's legal for ACPI PROCESSOR objects
	 * to have ACPI method objects.
	 */
	bzero(&mat, sizeof (mat));
	(void) acpidev_walk_apic(NULL, hdl, ACPIDEV_METHOD_NAME_MAT,
	    acpidev_cpu_query_MAT, &mat);
	if (mat.found) {
		*idp = mat.proc_id;
		return (AE_OK);
	}

	/* Then evalute PROCESSOR object. */
	if (infop->awi_info->Type == ACPI_TYPE_PROCESSOR) {
		ACPI_BUFFER rb;

		rb.Pointer = NULL;
		rb.Length = ACPI_ALLOCATE_BUFFER;
		if (ACPI_SUCCESS(AcpiEvaluateObjectTyped(hdl, NULL, NULL, &rb,
		    ACPI_TYPE_PROCESSOR))) {
			*idp = ((ACPI_OBJECT *)rb.Pointer)->Processor.ProcId;
			AcpiOsFree(rb.Pointer);
			return (AE_OK);
		} else {
			ACPIDEV_DEBUG(CE_WARN,
			    "!acpidev: failed to evaluate ACPI object %s.",
			    infop->awi_name);
		}
	}

	/*
	 * Finally, try to evalute the _UID method.
	 * According to the ACPI Spec3.0b, it's legal for ACPI PROCESSOR objects
	 * to have ACPI method objects.
	 * The CPU _UID method should return Processor Id as an integer on x86.
	 */
	if (ACPI_SUCCESS(acpica_eval_int(hdl, METHOD_NAME__UID, &id))) {
		*idp = id;
		return (AE_OK);
	}

	return (AE_NOT_FOUND);
}
예제 #2
0
static acpidev_filter_result_t
acpidev_cpu_filter_func(acpidev_walk_info_t *infop, ACPI_HANDLE hdl,
    acpidev_filter_rule_t *afrp, char *devname, int len)
{
	acpidev_filter_result_t res;

	ASSERT(afrp != NULL);
	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
		uint32_t procid;
		uint32_t apicid;

		if (acpidev_cpu_get_procid(infop, &procid) != 0) {
			ACPIDEV_DEBUG(CE_WARN,
			    "!acpidev: failed to query processor id for %s.",
			    infop->awi_name);
			return (ACPIDEV_FILTER_SKIP);
		} else if (acpidev_cpu_get_apicid(procid, &apicid) != 0) {
			ACPIDEV_DEBUG(CE_WARN,
			    "!acpidev: failed to query apic id for %s.",
			    infop->awi_name);
			return (ACPIDEV_FILTER_SKIP);
		}

		infop->awi_scratchpad[0] = procid;
		infop->awi_scratchpad[1] = apicid;
	} else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
		struct acpidev_cpu_MAT_arg mat;

		bzero(&mat, sizeof (mat));
		(void) acpidev_walk_apic(NULL, hdl, ACPIDEV_METHOD_NAME_MAT,
		    acpidev_cpu_query_MAT, &mat);
		if (!mat.found) {
			cmn_err(CE_WARN,
			    "!acpidev: failed to walk apic resource for %s.",
			    infop->awi_name);
			return (ACPIDEV_FILTER_SKIP);
		} else if (!mat.enabled) {
			ACPIDEV_DEBUG(CE_NOTE,
			    "!acpidev: CPU %s has been disabled.",
			    infop->awi_name);
			return (ACPIDEV_FILTER_SKIP);
		}
		/* Save processor id and APIC id in scratchpad memory. */
		infop->awi_scratchpad[0] = mat.proc_id;
		infop->awi_scratchpad[1] = mat.apic_id;
	}

	res = acpidev_filter_default(infop, hdl, afrp, devname, len);

	return (res);
}
예제 #3
0
/*
 * Lookup the dip for a CPU if ACPI CPU autoconfig is enabled.
 */
static int
acpidev_cpu_lookup_dip(cpu_t *cp, dev_info_t **dipp)
{
	uint32_t apicid;
	ACPI_HANDLE hdl;
	dev_info_t *dip = NULL;

	*dipp = NULL;
	if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
		apicid = cpuid_get_apicid(cp);
		if (acpica_get_cpu_object_by_cpuid(cp->cpu_id, &hdl) == 0 ||
		    (apicid != UINT32_MAX &&
		    acpica_get_cpu_object_by_apicid(apicid, &hdl) == 0)) {
			ASSERT(hdl != NULL);
			if (ACPI_SUCCESS(acpica_get_devinfo(hdl, &dip))) {
				ASSERT(dip != NULL);
				*dipp = dip;
				return (PSM_SUCCESS);
			}
		}
		ACPIDEV_DEBUG(CE_WARN,
		    "!acpidev: failed to lookup dip for cpu %d(%p).",
		    cp->cpu_id, (void *)cp);
	}

	return (PSM_FAILURE);
}
예제 #4
0
static ACPI_STATUS
acpidev_memory_probe(acpidev_walk_info_t *infop)
{
	ACPI_STATUS rc = AE_OK;
	int flags;

	ASSERT(infop != NULL);
	ASSERT(infop->awi_hdl != NULL);
	ASSERT(infop->awi_info != NULL);
	if (infop->awi_info->Type != ACPI_TYPE_DEVICE ||
	    acpidev_match_device_id(infop->awi_info,
	    ACPIDEV_ARRAY_PARAM(acpidev_memory_device_ids)) == 0) {
		return (AE_OK);
	}

	flags = ACPIDEV_PROCESS_FLAG_SCAN;
	switch (infop->awi_op_type) {
	case ACPIDEV_OP_BOOT_PROBE:
		if (acpica_get_devcfg_feature(ACPI_DEVCFG_MEMORY)) {
			flags |= ACPIDEV_PROCESS_FLAG_CREATE;
			acpidev_dr_check(infop);
		}
		break;

	case ACPIDEV_OP_BOOT_REPROBE:
		break;

	case ACPIDEV_OP_HOTPLUG_PROBE:
		if (acpica_get_devcfg_feature(ACPI_DEVCFG_MEMORY)) {
			flags |= ACPIDEV_PROCESS_FLAG_CREATE |
			    ACPIDEV_PROCESS_FLAG_SYNCSTATUS |
			    ACPIDEV_PROCESS_FLAG_HOLDBRANCH;
		}
		break;

	default:
		ACPIDEV_DEBUG(CE_WARN, "!acpidev: unknown operation type %u "
		    "in acpidev_memory_probe.", infop->awi_op_type);
		rc = AE_BAD_PARAMETER;
		break;
	}

	if (rc == AE_OK) {
		rc = acpidev_process_object(infop, flags);
	}
	if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
		cmn_err(CE_WARN,
		    "!acpidev: failed to process memory object %s.",
		    infop->awi_name);
	} else {
		rc = AE_OK;
	}

	return (rc);
}
static acpidev_filter_result_t
acpidev_scope_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
{
	acpidev_filter_result_t res;

	ASSERT(infop != NULL);
	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
		res = acpidev_filter_device(infop, infop->awi_hdl,
		    ACPIDEV_ARRAY_PARAM(acpidev_scope_filters),
		    devname, maxlen);
	} else {
		ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u "
		    "in acpidev_scope_filter().", infop->awi_op_type);
		res = ACPIDEV_FILTER_FAILED;
	}

	return (res);
}
예제 #6
0
/* Extract information from the enabled CPUs using the MADT table. */
static ACPI_STATUS
acpidev_cpu_parse_MADT(ACPI_SUBTABLE_HEADER *ap, void *context)
{
	uint32_t *cntp;
	ACPI_MADT_LOCAL_APIC *mpa;
	ACPI_MADT_LOCAL_X2APIC *mpx2a;

	cntp = (uint32_t *)context;
	switch (ap->Type) {
	case ACPI_MADT_TYPE_LOCAL_APIC:
		mpa = (ACPI_MADT_LOCAL_APIC *)ap;
		if (mpa->LapicFlags & ACPI_MADT_ENABLED) {
			ASSERT(mpa->Id != 255);
			ASSERT(*cntp < acpidev_cpu_map_count);
			acpidev_cpu_map[*cntp].proc_id = mpa->ProcessorId;
			acpidev_cpu_map[*cntp].apic_id = mpa->Id;
			(*cntp)++;
		}
		break;

	case ACPI_MADT_TYPE_LOCAL_X2APIC:
		mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
		/* See comment at beginning about 255 limitation. */
		if (mpx2a->LocalApicId < 255) {
			ACPIDEV_DEBUG(CE_WARN,
			    "!acpidev: encountered CPU with X2APIC Id < 255.");
		} else if (mpx2a->LapicFlags & ACPI_MADT_ENABLED) {
			ASSERT(*cntp < acpidev_cpu_map_count);
			acpidev_cpu_map[*cntp].proc_id = mpx2a->Uid;
			acpidev_cpu_map[*cntp].apic_id = mpx2a->LocalApicId;
			(*cntp)++;
		}
		break;

	default:
		break;
	}

	return (AE_OK);
}
static ACPI_STATUS
acpidev_scope_probe(acpidev_walk_info_t *infop)
{
	ACPI_STATUS rc;
	int flags;

	ASSERT(infop != NULL);
	ASSERT(infop->awi_hdl != NULL);
	ASSERT(infop->awi_info != NULL);
	if (infop->awi_info->Type != ACPI_TYPE_LOCAL_SCOPE) {
		return (AE_OK);
	}

	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
		flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
		rc = acpidev_process_object(infop, flags);
	} else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
		flags = ACPIDEV_PROCESS_FLAG_SCAN;
		rc = acpidev_process_object(infop, flags);
	} else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
		flags = ACPIDEV_PROCESS_FLAG_SCAN;
		rc = acpidev_process_object(infop, flags);
	} else {
		ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u "
		    "in acpidev_scope_probe().", infop->awi_op_type);
		rc = AE_BAD_PARAMETER;
	}
	if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
		cmn_err(CE_WARN,
		    "!acpidev: failed to process scope object %s.",
		    infop->awi_name);
	} else {
		rc = AE_OK;
	}

	return (rc);
}
예제 #8
0
static ACPI_STATUS
acpidev_cpu_init(acpidev_walk_info_t *infop)
{
	int count;
	uint32_t pxmid;
	dev_info_t *dip;
	ACPI_HANDLE hdl;
	char unitaddr[64];
	char **compatpp;
	static char *compatible[] = {
		ACPIDEV_HID_PROCESSOR,
		ACPIDEV_TYPE_CPU,
		"cpu"
	};

	ASSERT(infop != NULL);
	dip = infop->awi_dip;
	hdl = infop->awi_hdl;

	/* Create "apic_id", "processor_id" and "proximity_id" properties. */
	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
	    ACPIDEV_PROP_NAME_PROCESSOR_ID, infop->awi_scratchpad[0]) !=
	    NDI_SUCCESS) {
		cmn_err(CE_WARN,
		    "!acpidev: failed to set processor_id property for %s.",
		    infop->awi_name);
		return (AE_ERROR);
	}
	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
	    ACPIDEV_PROP_NAME_LOCALAPIC_ID, infop->awi_scratchpad[1]) !=
	    NDI_SUCCESS) {
		cmn_err(CE_WARN,
		    "!acpidev: failed to set apic_id property for %s.",
		    infop->awi_name);
		return (AE_ERROR);
	}
	if (ACPI_SUCCESS(acpidev_cpu_get_proximity_id(infop->awi_hdl,
	    infop->awi_scratchpad[1], &pxmid))) {
		if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
		    ACPIDEV_PROP_NAME_PROXIMITY_ID, pxmid) != NDI_SUCCESS) {
			cmn_err(CE_WARN, "!acpidev: failed to set proximity id "
			    "property for %s.", infop->awi_name);
			return (AE_ERROR);
		}
	}

	/* Set "compatible" property for CPU dip */
	count = sizeof (compatible) / sizeof (compatible[0]);
	if (infop->awi_info->Type == ACPI_TYPE_PROCESSOR) {
		compatpp = compatible;
	} else if (infop->awi_info->Type == ACPI_TYPE_DEVICE) {
		/*
		 * skip first item for pseudo processor HID.
		 * acpidev_set_compatible() will handle HID/CID for CPU device.
		 */
		compatpp = &compatible[1];
		count--;
	} else {
		return (AE_BAD_PARAMETER);
	}
	if (ACPI_FAILURE(acpidev_set_compatible(infop, compatpp, count))) {
		return (AE_ERROR);
	}

	/*
	 * Set device unit-address property.
	 * First try to generate meaningful unit address from _UID,
	 * then use Processor Id if that fails.
	 */
	if ((infop->awi_info->Valid & ACPI_VALID_UID) == 0 ||
	    acpidev_generate_unitaddr(infop->awi_info->UniqueId.String,
	    ACPIDEV_ARRAY_PARAM(acpidev_cpu_uid_formats),
	    unitaddr, sizeof (unitaddr)) == NULL) {
		(void) snprintf(unitaddr, sizeof (unitaddr), "%u",
		    (uint32_t)infop->awi_scratchpad[0]);
	}
	if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) {
		return (AE_ERROR);
	}

	/*
	 * Build binding information for CPUs.
	 */
	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
		if (ACPI_FAILURE(acpica_add_processor_to_map(
		    infop->awi_scratchpad[0], hdl, infop->awi_scratchpad[1]))) {
			cmn_err(CE_WARN, "!acpidev: failed to bind processor "
			    "id/object handle for %s.", infop->awi_name);
			return (AE_ERROR);
		}
	} else {
		ACPIDEV_DEBUG(CE_WARN,
		    "!acpidev: unknown operation type %u in acpidev_cpu_init.",
		    infop->awi_op_type);
		return (AE_BAD_PARAMETER);
	}

	return (AE_OK);
}
예제 #9
0
static ACPI_STATUS
acpidev_cpu_probe(acpidev_walk_info_t *infop)
{
	ACPI_STATUS rc = AE_OK;
	int flags;

	ASSERT(infop != NULL);
	ASSERT(infop->awi_hdl != NULL);
	ASSERT(infop->awi_info != NULL);
	ASSERT(infop->awi_class_curr == &acpidev_class_cpu);
	if (infop->awi_info->Type != ACPI_TYPE_PROCESSOR &&
	    (infop->awi_info->Type != ACPI_TYPE_DEVICE ||
	    acpidev_match_device_id(infop->awi_info,
	    ACPIDEV_ARRAY_PARAM(acpidev_processor_device_ids)) == 0)) {
		return (AE_OK);
	}

	flags = ACPIDEV_PROCESS_FLAG_SCAN;
	switch (infop->awi_op_type) {
	case  ACPIDEV_OP_BOOT_PROBE:
		/*
		 * Mark device as offline. It will be changed to online state
		 * when the corresponding CPU starts up.
		 */
		if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
			flags |= ACPIDEV_PROCESS_FLAG_CREATE |
			    ACPIDEV_PROCESS_FLAG_OFFLINE;
		}
		break;

	case ACPIDEV_OP_BOOT_REPROBE:
		break;

	case ACPIDEV_OP_HOTPLUG_PROBE:
		if (acpica_get_devcfg_feature(ACPI_DEVCFG_CPU)) {
			flags |= ACPIDEV_PROCESS_FLAG_CREATE |
			    ACPIDEV_PROCESS_FLAG_OFFLINE |
			    ACPIDEV_PROCESS_FLAG_SYNCSTATUS |
			    ACPIDEV_PROCESS_FLAG_HOLDBRANCH;
		}
		break;

	default:
		ACPIDEV_DEBUG(CE_WARN, "!acpidev: unknown operation type %u in "
		    "acpidev_cpu_probe().", infop->awi_op_type);
		rc = AE_BAD_PARAMETER;
		break;
	}

	if (rc == AE_OK) {
		rc = acpidev_process_object(infop, flags);
	}
	if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
		cmn_err(CE_WARN,
		    "!acpidev: failed to process processor object %s.",
		    infop->awi_name);
	} else {
		rc = AE_OK;
	}

	return (rc);
}
예제 #10
0
/*
 * Extract information for enabled CPUs from the buffer returned
 * by the _MAT method.
 */
static ACPI_STATUS
acpidev_cpu_query_MAT(ACPI_SUBTABLE_HEADER *ap, void *context)
{
	ACPI_MADT_LOCAL_APIC *mpa;
	ACPI_MADT_LOCAL_X2APIC *mpx2a;
	struct acpidev_cpu_MAT_arg *rp;

	rp = (struct acpidev_cpu_MAT_arg *)context;
	switch (ap->Type) {
	case ACPI_MADT_TYPE_LOCAL_APIC:
		mpa = (ACPI_MADT_LOCAL_APIC *)ap;
		ASSERT(mpa->Id != 255);
		rp->found = B_TRUE;
		rp->proc_id = mpa->ProcessorId;
		rp->apic_id = mpa->Id;
		if (mpa->LapicFlags & ACPI_MADT_ENABLED) {
			rp->enabled = B_TRUE;
		} else {
			rp->enabled = B_FALSE;
		}
		return (AE_CTRL_TERMINATE);

	case ACPI_MADT_TYPE_LOCAL_X2APIC:
		mpx2a = (ACPI_MADT_LOCAL_X2APIC *)ap;
		if (mpx2a->LocalApicId >= 255) {
			rp->found = B_TRUE;
			rp->proc_id = mpx2a->Uid;
			rp->apic_id = mpx2a->LocalApicId;
			if (mpx2a->LapicFlags & ACPI_MADT_ENABLED) {
				rp->enabled = B_TRUE;
			} else {
				rp->enabled = B_FALSE;
			}
			return (AE_CTRL_TERMINATE);
		} else {
			ACPIDEV_DEBUG(CE_WARN, "!acpidev: encountered CPU "
			    "with X2APIC Id < 255 in _MAT.");
		}
		break;

	case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
		/* UNIMPLEMENTED */
		break;

	case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
		/* UNIMPLEMENTED */
		break;

	default:
		/*
		 * According to the ACPI Spec, the buffer returned by _MAT
		 * for a processor object should only contain Local APIC,
		 * Local SAPIC, and local APIC NMI entries.
		 * x2APIC Specification extends it to support Processor
		 * x2APIC and x2APIC NMI Structure.
		 */
		ACPIDEV_DEBUG(CE_NOTE,
		    "!acpidev: unknown APIC entry type %u in _MAT.", ap->Type);
		break;
	}

	return (AE_OK);
}