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 *shouldbesilentlydiscarded *Onpowerdownclientmaybeforcecleaned, *silentlydiscardsuchmessages
*/ 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);
/* 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;
} return0;
}
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.