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; }
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"); }
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"); }
/** * 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; }
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); }
/* 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; }
/** * 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; }
/** * 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; }
/* * 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; }