/** * mei_cl_hbm_equal - check if hbm is addressed to the client * * @cl: host client * @mei_hdr: header of mei client message * * Return: true if matches, false otherwise
*/ staticinlineint mei_cl_hbm_equal(struct mei_cl *cl, struct mei_msg_hdr *mei_hdr)
{ return mei_cl_host_addr(cl) == mei_hdr->host_addr &&
mei_cl_me_id(cl) == mei_hdr->me_addr;
}
/** * mei_irq_discard_msg - discard received message * * @dev: mei device * @hdr: message header * @discard_len: the length of the message to discard (excluding header)
*/ staticvoid mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr,
size_t discard_len)
{ if (hdr->dma_ring) {
mei_dma_ring_read(dev, NULL,
hdr->extension[dev->rd_msg_hdr_count - 2]);
discard_len = 0;
} /* * no need to check for size as it is guaranteed * that length fits into rd_msg_buf
*/
mei_read_slots(dev, dev->rd_msg_buf, discard_len);
dev_dbg(dev->dev, "discarding message " MEI_HDR_FMT "\n",
MEI_HDR_PRM(hdr));
}
if (gsc_f2h) {
u32 ext_hdr_len = mei_ext_hdr_len(&gsc_f2h->hdr);
if (!dev->hbm_f_gsc_supported) {
cl_err(dev, cl, "gsc extended header is not supported\n");
cb->status = -EPROTO; goto discard;
}
if (length) {
cl_err(dev, cl, "no data allowed in cb with gsc\n");
cb->status = -EPROTO; goto discard;
} if (ext_hdr_len > sizeof(*gsc_f2h)) {
cl_err(dev, cl, "gsc extended header is too big %u\n", ext_hdr_len);
cb->status = -EPROTO; goto discard;
}
memcpy(cb->ext_hdr, gsc_f2h, ext_hdr_len);
}
if (mei_slots2data(*slots) < mei_hdr->length) {
dev_err(dev->dev, "less data available than length=%08x.\n",
*slots); /* we can't read the message */
ret = -ENODATA; goto end;
}
ext_hdr_end = 1;
hdr_size_left = mei_hdr->length;
if (mei_hdr->extended) { if (!dev->rd_msg_hdr[1]) {
dev->rd_msg_hdr[1] = mei_read_hdr(dev);
dev->rd_msg_hdr_count++;
(*slots)--;
dev_dbg(dev->dev, "extended header is %08x\n", dev->rd_msg_hdr[1]);
}
meta_hdr = ((struct mei_ext_meta_hdr *)&dev->rd_msg_hdr[1]); if (check_add_overflow((u32)sizeof(*meta_hdr),
mei_slots2data(meta_hdr->size),
&hdr_size_ext)) {
dev_err(dev->dev, "extended message size too big %d\n",
meta_hdr->size); return -EBADMSG;
} if (hdr_size_left < hdr_size_ext) {
dev_err(dev->dev, "corrupted message header len %d\n",
mei_hdr->length); return -EBADMSG;
}
hdr_size_left -= hdr_size_ext;
ext_hdr_end = meta_hdr->size + 2; for (i = dev->rd_msg_hdr_count; i < ext_hdr_end; i++) {
dev->rd_msg_hdr[i] = mei_read_hdr(dev);
dev_dbg(dev->dev, "extended header %d is %08x\n", i,
dev->rd_msg_hdr[i]);
dev->rd_msg_hdr_count++;
(*slots)--;
}
}
if (mei_hdr->dma_ring) { if (hdr_size_left != sizeof(dev->rd_msg_hdr[ext_hdr_end])) {
dev_err(dev->dev, "corrupted message header len %d\n",
mei_hdr->length); return -EBADMSG;
}
/* HBM message */ if (hdr_is_hbm(mei_hdr)) {
ret = mei_hbm_dispatch(dev, mei_hdr); if (ret) {
dev_dbg(dev->dev, "mei_hbm_dispatch failed ret = %d\n",
ret); goto end;
} goto reset_slots;
}
/* find recipient cl */
list_for_each_entry(cl, &dev->file_list, link) { if (mei_cl_hbm_equal(cl, mei_hdr)) {
cl_dbg(dev, cl, "got a message\n");
ret = mei_cl_irq_read_msg(cl, mei_hdr, meta_hdr, cmpl_list); goto reset_slots;
}
}
/* if no recipient cl was found we assume corrupted header */ /* A message for not connected fixed address clients * should be silently discarded * On power down client may be force cleaned, * silently discard such messages
*/ if (hdr_is_fixed(mei_hdr) ||
dev->dev_state == MEI_DEV_POWER_DOWN) {
mei_irq_discard_msg(dev, mei_hdr, mei_hdr->length);
ret = 0; goto reset_slots;
}
dev_err(dev->dev, "no destination client found 0x%08X\n", dev->rd_msg_hdr[0]);
ret = -EBADMSG; goto end;
reset_slots: /* reset the number of slots and header */
memset(dev->rd_msg_hdr, 0, sizeof(dev->rd_msg_hdr));
dev->rd_msg_hdr_count = 0;
*slots = mei_count_full_read_slots(dev); if (*slots == -EOVERFLOW) { /* overflow - reset */
dev_err(dev->dev, "resetting due to slots overflow.\n"); /* set the event since message has been read */
ret = -ERANGE; goto end;
}
end: return ret;
}
EXPORT_SYMBOL_GPL(mei_irq_read_handler);
/** * mei_irq_write_handler - dispatch write requests * after irq received * * @dev: the device structure * @cmpl_list: An instance of our list structure * * Return: 0 on success, <0 on failure.
*/ int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list)
{
/* complete control write list CB */
dev_dbg(dev->dev, "complete control write list cb.\n");
list_for_each_entry_safe(cb, next, &dev->ctrl_wr_list, list) {
cl = cb->cl; switch (cb->fop_type) { case MEI_FOP_DISCONNECT: /* send disconnect message */
ret = mei_cl_irq_disconnect(cl, cb, cmpl_list); if (ret) return ret;
break; case MEI_FOP_READ: /* send flow control message */
ret = mei_cl_irq_read(cl, cb, cmpl_list); if (ret) return ret;
break; case MEI_FOP_CONNECT: /* connect message */
ret = mei_cl_irq_connect(cl, cb, cmpl_list); if (ret) return ret;
break; case MEI_FOP_DISCONNECT_RSP: /* send disconnect resp */
ret = mei_cl_irq_disconnect_rsp(cl, cb, cmpl_list); if (ret) return ret; break;
case MEI_FOP_NOTIFY_START: case MEI_FOP_NOTIFY_STOP:
ret = mei_cl_irq_notify(cl, cb, cmpl_list); if (ret) return ret; break; case MEI_FOP_DMA_MAP:
ret = mei_cl_irq_dma_map(cl, cb, cmpl_list); if (ret) return ret; break; case MEI_FOP_DMA_UNMAP:
ret = mei_cl_irq_dma_unmap(cl, cb, cmpl_list); if (ret) return ret; break; default:
BUG();
}
} /* complete write list CB */
dev_dbg(dev->dev, "complete write list cb.\n");
list_for_each_entry_safe(cb, next, &dev->write_list, list) {
cl = cb->cl;
ret = mei_cl_irq_write(cl, cb, cmpl_list); if (ret) return ret;
} return 0;
}
EXPORT_SYMBOL_GPL(mei_irq_write_handler);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.