Example #1
0
ssize_t apei_read_mce(struct mce *m, u64 *record_id)
{
	struct cper_mce_record rcd;
	int rc, pos;

	rc = erst_get_record_id_begin(&pos);
	if (rc)
		return rc;
retry:
	rc = erst_get_record_id_next(&pos, record_id);
	if (rc)
		goto out;
	/* no more record */
	if (*record_id == APEI_ERST_INVALID_RECORD_ID)
		goto out;
	rc = erst_read(*record_id, &rcd.hdr, sizeof(rcd));
	/* someone else has cleared the record, try next one */
	if (rc == -ENOENT)
		goto retry;
	else if (rc < 0)
		goto out;
	/* try to skip other type records in storage */
	else if (rc != sizeof(rcd) ||
		 uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE))
		goto retry;
	memcpy(m, &rcd.mce, sizeof(*m));
	rc = sizeof(*m);
out:
	erst_get_record_id_end();

	return rc;
}
Example #2
0
static void apei_estatus_print_section(
	const char *pfx, const struct acpi_hest_generic_data *gdata, int sec_no)
{
	uuid_le *sec_type = (uuid_le *)gdata->section_type;
	__u16 severity;

	severity = gdata->error_severity;
	printk("%s""section: %d, severity: %d, %s\n", pfx, sec_no, severity,
	       cper_severity_str(severity));
	printk("%s""flags: 0x%02x\n", pfx, gdata->flags);
	cper_print_bits(pfx, gdata->flags, apei_estatus_section_flag_strs,
			ARRAY_SIZE(apei_estatus_section_flag_strs));
	if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
		printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id);
	if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
		printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);

	if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) {
		struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1);
		printk("%s""section_type: general processor error\n", pfx);
		if (gdata->error_data_length >= sizeof(*proc_err))
			cper_print_proc_generic(pfx, proc_err);
		else
			goto err_section_too_small;
	} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
		struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
		printk("%s""section_type: memory error\n", pfx);
		if (gdata->error_data_length >= sizeof(*mem_err))
			cper_print_mem(pfx, mem_err);
		else
			goto err_section_too_small;
	} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
		struct cper_sec_pcie *pcie = (void *)(gdata + 1);
		printk("%s""section_type: PCIe error\n", pfx);
		if (gdata->error_data_length >= sizeof(*pcie))
			cper_print_pcie(pfx, pcie, gdata);
		else
			goto err_section_too_small;
	} else
		printk("%s""section type: unknown, %pUl\n", pfx, sec_type);

	return;

err_section_too_small:
	pr_err(FW_WARN "error section length is too small\n");
}
Example #3
0
File: cper.c Project: 24hours/linux
static void cper_estatus_print_section(
	const char *pfx, const struct acpi_generic_data *gdata, int sec_no)
{
	uuid_le *sec_type = (uuid_le *)gdata->section_type;
	__u16 severity;
	char newpfx[64];

	severity = gdata->error_severity;
	printk("%s""Error %d, type: %s\n", pfx, sec_no,
	       cper_severity_str(severity));
	if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
		printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id);
	if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
		printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);

	snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
	if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) {
		struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1);
		printk("%s""section_type: general processor error\n", newpfx);
		if (gdata->error_data_length >= sizeof(*proc_err))
			cper_print_proc_generic(newpfx, proc_err);
		else
			goto err_section_too_small;
	} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
		struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
		printk("%s""section_type: memory error\n", newpfx);
		if (gdata->error_data_length >= sizeof(*mem_err))
			cper_print_mem(newpfx, mem_err);
		else
			goto err_section_too_small;
	} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
		struct cper_sec_pcie *pcie = (void *)(gdata + 1);
		printk("%s""section_type: PCIe error\n", newpfx);
		if (gdata->error_data_length >= sizeof(*pcie))
			cper_print_pcie(newpfx, pcie, gdata);
		else
			goto err_section_too_small;
	} else
		printk("%s""section type: unknown, %pUl\n", newpfx, sec_type);

	return;

err_section_too_small:
	pr_err(FW_WARN "error section length is too small\n");
}
Example #4
0
/**
 * hid_ishtp_cl_probe() - ISHTP client driver probe
 * @cl_device:		ISHTP client device instance
 *
 * This function gets called on device create on ISHTP bus
 *
 * Return: 0 on success, non zero on error
 */
static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
{
	struct ishtp_cl *hid_ishtp_cl;
	struct ishtp_cl_data *client_data;
	int rv;

	if (!cl_device)
		return	-ENODEV;

	if (uuid_le_cmp(hid_ishtp_guid,
			cl_device->fw_client->props.protocol_name) != 0)
		return	-ENODEV;

	client_data = devm_kzalloc(&cl_device->dev, sizeof(*client_data),
				   GFP_KERNEL);
	if (!client_data)
		return -ENOMEM;

	hid_ishtp_cl = ishtp_cl_allocate(cl_device->ishtp_dev);
	if (!hid_ishtp_cl)
		return -ENOMEM;

	cl_device->driver_data = hid_ishtp_cl;
	hid_ishtp_cl->client_data = client_data;
	client_data->hid_ishtp_cl = hid_ishtp_cl;
	client_data->cl_device = cl_device;

	init_waitqueue_head(&client_data->init_wait);
	init_waitqueue_head(&client_data->ishtp_resume_wait);

	INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler);

	rv = hid_ishtp_cl_init(hid_ishtp_cl, 0);
	if (rv) {
		ishtp_cl_free(hid_ishtp_cl);
		return rv;
	}
	ishtp_get_device(cl_device);

	return 0;
}
Example #5
0
ssize_t apei_read_mce(struct mce *m, u64 *record_id)
{
	struct cper_mce_record rcd;
	ssize_t len;

	if (!m || !record_id)
		return -EINVAL;

	len = erst_read_next(&rcd.hdr, sizeof(rcd));
	if (len <= 0)
		return len;
	/* Can not skip other records in storage via ERST unless clear them */
	else if (len != sizeof(rcd) ||
		 uuid_le_cmp(rcd.hdr.creator_id, CPER_CREATOR_MCE)) {
		printk(KERN_WARNING
			"MCE-APEI: Can not skip the unknown record in ERST");
		return -EIO;
	}

	memcpy(m, &rcd.mce, sizeof(*m));
	*record_id = rcd.hdr.record_id;

	return sizeof(*m);
}
Example #6
0
/* Creates the VISORCHANNEL abstraction for a data area in memory, but does
 * NOT modify this data area.
 */
static VISORCHANNEL *
visorchannel_create_guts(HOSTADDRESS physaddr, ulong channelBytes,
			 VISORCHANNEL *parent, ulong off, uuid_le guid,
			 BOOL needs_lock)
{
	VISORCHANNEL *p = NULL;
	void *rc = NULL;

	p = kmalloc(sizeof(VISORCHANNEL), GFP_KERNEL|__GFP_NORETRY);
	if (p == NULL) {
		ERRDRV("allocation failed: (status=0)\n");
		rc = NULL;
		goto Away;
	}
	p->memregion = NULL;
	p->needs_lock = needs_lock;
	spin_lock_init(&p->insert_lock);
	spin_lock_init(&p->remove_lock);

	/* prepare chan_hdr (abstraction to read/write channel memory) */
	if (parent == NULL)
		p->memregion =
		    visor_memregion_create(physaddr, sizeof(CHANNEL_HEADER));
	else
		p->memregion =
		    visor_memregion_create_overlapped(parent->memregion,
						      off,
						      sizeof(CHANNEL_HEADER));
	if (p->memregion == NULL) {
		ERRDRV("visor_memregion_create failed failed: (status=0)\n");
		rc = NULL;
		goto Away;
	}
	if (visor_memregion_read(p->memregion, 0, &p->chan_hdr,
				 sizeof(CHANNEL_HEADER)) < 0) {
		ERRDRV("visor_memregion_read failed: (status=0)\n");
		rc = NULL;
		goto Away;
	}
	if (channelBytes == 0)
		/* we had better be a CLIENT of this channel */
		channelBytes = (ulong) p->chan_hdr.Size;
	if (uuid_le_cmp(guid, NULL_UUID_LE) == 0)
		/* we had better be a CLIENT of this channel */
		guid = p->chan_hdr.Type;
	if (visor_memregion_resize(p->memregion, channelBytes) < 0) {
		ERRDRV("visor_memregion_resize failed: (status=0)\n");
		rc = NULL;
		goto Away;
	}
	p->size = channelBytes;
	p->guid = guid;

	rc = p;
Away:

	if (rc == NULL) {
		if (p != NULL) {
			visorchannel_destroy(p);
			p = NULL;
		}
	}
	return rc;
}
Example #7
0
/**
 * mei_ioctl_connect_client - the connect to fw client IOCTL function
 *
 * @dev: the device structure
 * @data: IOCTL connect data, input and output parameters
 * @file: private data of the file object
 *
 * Locking: called under "dev->device_lock" lock
 *
 * returns 0 on success, <0 on failure.
 */
static int mei_ioctl_connect_client(struct file *file,
			struct mei_connect_client_data *data)
{
	struct mei_device *dev;
	struct mei_client *client;
	struct mei_cl *cl;
	int i;
	int rets;

	cl = file->private_data;
	if (WARN_ON(!cl || !cl->dev))
		return -ENODEV;

	dev = cl->dev;

	if (dev->dev_state != MEI_DEV_ENABLED) {
		rets = -ENODEV;
		goto end;
	}

	if (cl->state != MEI_FILE_INITIALIZING &&
	    cl->state != MEI_FILE_DISCONNECTED) {
		rets = -EBUSY;
		goto end;
	}

	/* find ME client we're trying to connect to */
	i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
	if (i < 0 || dev->me_clients[i].props.fixed_address) {
		dev_dbg(&dev->pdev->dev, "Cannot connect to FW Client UUID = %pUl\n",
				&data->in_client_uuid);
		rets = -ENOTTY;
		goto end;
	}

	cl->me_client_id = dev->me_clients[i].client_id;

	dev_dbg(&dev->pdev->dev, "Connect to FW Client ID = %d\n",
			cl->me_client_id);
	dev_dbg(&dev->pdev->dev, "FW Client - Protocol Version = %d\n",
			dev->me_clients[i].props.protocol_version);
	dev_dbg(&dev->pdev->dev, "FW Client - Max Msg Len = %d\n",
			dev->me_clients[i].props.max_msg_length);

	/* if we're connecting to amthif client then we will use the
	 * existing connection
	 */
	if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
		dev_dbg(&dev->pdev->dev, "FW Client is amthi\n");
		if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) {
			rets = -ENODEV;
			goto end;
		}
		mei_cl_unlink(cl);

		kfree(cl);
		cl = NULL;
		dev->iamthif_open_count++;
		file->private_data = &dev->iamthif_cl;

		client = &data->out_client_properties;
		client->max_msg_length =
			dev->me_clients[i].props.max_msg_length;
		client->protocol_version =
			dev->me_clients[i].props.protocol_version;
		rets = dev->iamthif_cl.status;

		goto end;
	}


	/* prepare the output buffer */
	client = &data->out_client_properties;
	client->max_msg_length = dev->me_clients[i].props.max_msg_length;
	client->protocol_version = dev->me_clients[i].props.protocol_version;
	dev_dbg(&dev->pdev->dev, "Can connect?\n");


	rets = mei_cl_connect(cl, file);

end:
	return rets;
}
Example #8
0
/**
 * mei_ioctl_connect_client - the connect to fw client IOCTL function
 *
 * @file: private data of the file object
 * @data: IOCTL connect data, input and output parameters
 *
 * Locking: called under "dev->device_lock" lock
 *
 * Return: 0 on success, <0 on failure.
 */
static int mei_ioctl_connect_client(struct file *file,
			struct mei_connect_client_data *data)
{
	struct mei_device *dev;
	struct mei_client *client;
	struct mei_me_client *me_cl;
	struct mei_cl *cl;
	int rets;

	cl = file->private_data;
	dev = cl->dev;

	if (dev->dev_state != MEI_DEV_ENABLED)
		return -ENODEV;

	if (cl->state != MEI_FILE_INITIALIZING &&
	    cl->state != MEI_FILE_DISCONNECTED)
		return  -EBUSY;

	/* find ME client we're trying to connect to */
	me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
	if (!me_cl) {
		dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
			&data->in_client_uuid);
		rets = -ENOTTY;
		goto end;
	}

	if (me_cl->props.fixed_address) {
		bool forbidden = dev->override_fixed_address ?
			 !dev->allow_fixed_address : !dev->hbm_f_fa_supported;
		if (forbidden) {
			dev_dbg(dev->dev, "Connection forbidden to FW Client UUID = %pUl\n",
				&data->in_client_uuid);
			rets = -ENOTTY;
			goto end;
		}
	}

	dev_dbg(dev->dev, "Connect to FW Client ID = %d\n",
			me_cl->client_id);
	dev_dbg(dev->dev, "FW Client - Protocol Version = %d\n",
			me_cl->props.protocol_version);
	dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n",
			me_cl->props.max_msg_length);

	/* if we're connecting to amthif client then we will use the
	 * existing connection
	 */
	if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
		dev_dbg(dev->dev, "FW Client is amthi\n");
		if (!mei_cl_is_connected(&dev->iamthif_cl)) {
			rets = -ENODEV;
			goto end;
		}
		mei_cl_unlink(cl);

		kfree(cl);
		cl = NULL;
		dev->iamthif_open_count++;
		file->private_data = &dev->iamthif_cl;

		client = &data->out_client_properties;
		client->max_msg_length = me_cl->props.max_msg_length;
		client->protocol_version = me_cl->props.protocol_version;
		rets = dev->iamthif_cl.status;

		goto end;
	}

	/* prepare the output buffer */
	client = &data->out_client_properties;
	client->max_msg_length = me_cl->props.max_msg_length;
	client->protocol_version = me_cl->props.protocol_version;
	dev_dbg(dev->dev, "Can connect?\n");

	rets = mei_cl_connect(cl, me_cl, file);

end:
	mei_me_cl_put(me_cl);
	return rets;
}
Example #9
0
/*
 * visorchannel_create_guts() - creates the struct visorchannel abstraction
 *                              for a data area in memory, but does NOT modify
 *                              this data area
 * @physaddr:      physical address of start of channel
 * @channel_bytes: size of the channel in bytes; this may 0 if the channel has
 *                 already been initialized in memory (which is true for all
 *                 channels provided to guest environments by the s-Par
 *                 back-end), in which case the actual channel size will be
 *                 read from the channel header in memory
 * @gfp:           gfp_t to use when allocating memory for the data struct
 * @guid:          uuid that identifies channel type; this may 0 if the channel
 *                 has already been initialized in memory (which is true for all
 *                 channels provided to guest environments by the s-Par
 *                 back-end), in which case the actual channel guid will be
 *                 read from the channel header in memory
 * @needs_lock:    must specify true if you have multiple threads of execution
 *                 that will be calling visorchannel methods of this
 *                 visorchannel at the same time
 *
 * Return: pointer to visorchannel that was created if successful,
 *         otherwise NULL
 */
static struct visorchannel *
visorchannel_create_guts(u64 physaddr, unsigned long channel_bytes,
			 gfp_t gfp, uuid_le guid, bool needs_lock)
{
	struct visorchannel *channel;
	int err;
	size_t size = sizeof(struct channel_header);

	if (physaddr == 0)
		return NULL;

	channel = kzalloc(sizeof(*channel), gfp);
	if (!channel)
		return NULL;

	channel->needs_lock = needs_lock;
	spin_lock_init(&channel->insert_lock);
	spin_lock_init(&channel->remove_lock);

	/*
	 * Video driver constains the efi framebuffer so it will get a
	 * conflict resource when requesting its full mem region. Since
	 * we are only using the efi framebuffer for video we can ignore
	 * this. Remember that we haven't requested it so we don't try to
	 * release later on.
	 */
	channel->requested = request_mem_region(physaddr, size, MYDRVNAME);
	if (!channel->requested && uuid_le_cmp(guid, spar_video_guid))
		/* we only care about errors if this is not the video channel */
		goto err_destroy_channel;

	channel->mapped = memremap(physaddr, size, MEMREMAP_WB);
	if (!channel->mapped) {
		release_mem_region(physaddr, size);
		goto err_destroy_channel;
	}

	channel->physaddr = physaddr;
	channel->nbytes = size;

	err = visorchannel_read(channel, 0, &channel->chan_hdr,
				sizeof(struct channel_header));
	if (err)
		goto err_destroy_channel;

	/* we had better be a CLIENT of this channel */
	if (channel_bytes == 0)
		channel_bytes = (ulong)channel->chan_hdr.size;
	if (uuid_le_cmp(guid, NULL_UUID_LE) == 0)
		guid = channel->chan_hdr.chtype;

	memunmap(channel->mapped);
	if (channel->requested)
		release_mem_region(channel->physaddr, channel->nbytes);
	channel->mapped = NULL;
	channel->requested = request_mem_region(channel->physaddr,
						channel_bytes, MYDRVNAME);
	if (!channel->requested && uuid_le_cmp(guid, spar_video_guid))
		/* we only care about errors if this is not the video channel */
		goto err_destroy_channel;

	channel->mapped = memremap(channel->physaddr, channel_bytes,
			MEMREMAP_WB);
	if (!channel->mapped) {
		release_mem_region(channel->physaddr, channel_bytes);
		goto err_destroy_channel;
	}

	channel->nbytes = channel_bytes;
	channel->guid = guid;
	return channel;

err_destroy_channel:
	visorchannel_destroy(channel);
	return NULL;
}