arch/powerpc/platforms/pseries/papr_platform_attributes.c

Source file repositories/reference/linux-study-clean/arch/powerpc/platforms/pseries/papr_platform_attributes.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/platforms/pseries/papr_platform_attributes.c
Extension
.c
Size
8983 bytes
Lines
364
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

struct energy_scale_attribute {
	__be64 id;
	__be64 val;
	u8 desc[64];
	u8 value_desc[64];
} __packed;

struct h_energy_scale_info_hdr {
	__be64 num_attrs;
	__be64 array_offset;
	u8 data_header_version;
} __packed;

struct papr_attr {
	u64 id;
	struct kobj_attribute kobj_attr;
};

struct papr_group {
	struct attribute_group pg;
	struct papr_attr pgattrs[KOBJ_MAX_ATTRS];
};

static struct papr_group *papr_groups;
/* /sys/firmware/papr */
static struct kobject *papr_kobj;
/* /sys/firmware/papr/energy_scale_info */
static struct kobject *esi_kobj;

/*
 * Energy modes can change dynamically hence making a new hcall each time the
 * information needs to be retrieved
 */
static int papr_get_attr(u64 id, struct energy_scale_attribute *esi)
{
	int esi_buf_size = ESI_HDR_SIZE + (CURR_MAX_ESI_ATTRS * ESI_ATTR_SIZE);
	int ret, max_esi_attrs = CURR_MAX_ESI_ATTRS;
	struct energy_scale_attribute *curr_esi;
	struct h_energy_scale_info_hdr *hdr;
	char *buf;

	buf = kmalloc(esi_buf_size, GFP_KERNEL);
	if (buf == NULL)
		return -ENOMEM;

retry:
	ret = plpar_hcall_norets(H_GET_ENERGY_SCALE_INFO, ESI_FLAGS_SINGLE,
				 id, virt_to_phys(buf),
				 esi_buf_size);

	/*
	 * If the hcall fails with not enough memory for either the
	 * header or data, attempt to allocate more
	 */
	if (ret == H_PARTIAL || ret == H_P4) {
		char *temp_buf;

		max_esi_attrs += 4;
		esi_buf_size = ESI_HDR_SIZE + (CURR_MAX_ESI_ATTRS * max_esi_attrs);

		temp_buf = krealloc(buf, esi_buf_size, GFP_KERNEL);
		if (temp_buf) {
			buf = temp_buf;
		} else {
			ret = -ENOMEM;
			goto out_buf;
		}

		goto retry;
	}

	if (ret != H_SUCCESS) {
		pr_warn("hcall failed: H_GET_ENERGY_SCALE_INFO");
		ret = -EIO;
		goto out_buf;
	}

	hdr = (struct h_energy_scale_info_hdr *) buf;
	curr_esi = (struct energy_scale_attribute *)
		(buf + be64_to_cpu(hdr->array_offset));

	if (esi_buf_size <
	    be64_to_cpu(hdr->array_offset) + (be64_to_cpu(hdr->num_attrs)
	    * sizeof(struct energy_scale_attribute))) {
		ret = -EIO;
		goto out_buf;
	}

	*esi = *curr_esi;

Annotation

Implementation Notes