drivers/leds/leds-powernv.c

Source file repositories/reference/linux-study-clean/drivers/leds/leds-powernv.c

File Facts

System
Linux kernel
Corpus path
drivers/leds/leds-powernv.c
Extension
.c
Size
8851 bytes
Lines
339
Domain
Driver Families
Bucket
drivers/leds
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct led_type_map {
	const int	type;
	const char	*desc;
};
static const struct led_type_map led_type_map[] = {
	{OPAL_SLOT_LED_TYPE_ID,		"identify"},
	{OPAL_SLOT_LED_TYPE_FAULT,	"fault"},
	{OPAL_SLOT_LED_TYPE_ATTN,	"attention"},
	{-1,				NULL},
};

struct powernv_led_common {
	/*
	 * By default unload path resets all the LEDs. But on PowerNV
	 * platform we want to retain LED state across reboot as these
	 * are controlled by firmware. Also service processor can modify
	 * the LEDs independent of OS. Hence avoid resetting LEDs in
	 * unload path.
	 */
	bool		led_disabled;

	/* Max supported LED type */
	__be64		max_led_type;

	/* glabal lock */
	struct mutex	lock;
};

/* PowerNV LED data */
struct powernv_led_data {
	struct led_classdev	cdev;
	char			*loc_code;	/* LED location code */
	int			led_type;	/* OPAL_SLOT_LED_TYPE_* */

	struct powernv_led_common *common;
};


/* Returns OPAL_SLOT_LED_TYPE_* for given led type string */
static int powernv_get_led_type(const char *led_type_desc)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(led_type_map); i++)
		if (!strcmp(led_type_map[i].desc, led_type_desc))
			return led_type_map[i].type;

	return -1;
}

/*
 * This commits the state change of the requested LED through an OPAL call.
 * This function is called from work queue task context when ever it gets
 * scheduled. This function can sleep at opal_async_wait_response call.
 */
static int powernv_led_set(struct powernv_led_data *powernv_led,
			    enum led_brightness value)
{
	int rc, token;
	u64 led_mask, led_value = 0;
	__be64 max_type;
	struct opal_msg msg;
	struct device *dev = powernv_led->cdev.dev;
	struct powernv_led_common *powernv_led_common = powernv_led->common;

	/* Prepare for the OPAL call */
	max_type = powernv_led_common->max_led_type;
	led_mask = OPAL_SLOT_LED_STATE_ON << powernv_led->led_type;
	if (value)
		led_value = led_mask;

	/* OPAL async call */
	token = opal_async_get_token_interruptible();
	if (token < 0) {
		if (token != -ERESTARTSYS)
			dev_err(dev, "%s: Couldn't get OPAL async token\n",
				__func__);
		return token;
	}

	rc = opal_leds_set_ind(token, powernv_led->loc_code,
			       led_mask, led_value, &max_type);
	if (rc != OPAL_ASYNC_COMPLETION) {
		dev_err(dev, "%s: OPAL set LED call failed for %s [rc=%d]\n",
			__func__, powernv_led->loc_code, rc);
		goto out_token;
	}

	rc = opal_async_wait_response(token, &msg);
	if (rc) {

Annotation

Implementation Notes