static int isp_fill_channel_info(struct fthd_private *dev_priv, int offset, int num_channels) { struct isp_channel_info info; struct fw_channel *chan; int i; if (!num_channels) return -EINVAL; dev_priv->channels = kzalloc(num_channels * sizeof(struct fw_channel *), GFP_KERNEL); if (!dev_priv->channels) goto out; dev_priv->num_channels = num_channels; for(i = 0; i < num_channels; i++) { FTHD_S2_MEMCPY_FROMIO(&info, offset + i * 256, sizeof(info)); chan = kzalloc(sizeof(struct fw_channel), GFP_KERNEL); if (!chan) goto out; dev_priv->channels[i] = chan; pr_debug("Channel %d: %s, type %d, source %d, size %d, offset %x\n", i, info.name, info.type, info.source, info.size, info.offset); chan->name = kstrdup(info.name, GFP_KERNEL); if (!chan->name) goto out; chan->type = info.type; chan->source = info.source; chan->size = info.size; chan->offset = info.offset; spin_lock_init(&chan->lock); init_waitqueue_head(&chan->wq); } dev_priv->channel_terminal = isp_get_chan_index(dev_priv, "TERMINAL"); dev_priv->channel_debug = isp_get_chan_index(dev_priv, "DEBUG"); dev_priv->channel_shared_malloc = isp_get_chan_index(dev_priv, "SHAREDMALLOC"); dev_priv->channel_io = isp_get_chan_index(dev_priv, "IO"); dev_priv->channel_buf_h2t = isp_get_chan_index(dev_priv, "BUF_H2T"); dev_priv->channel_buf_t2h = isp_get_chan_index(dev_priv, "BUF_T2H"); dev_priv->channel_io_t2h = isp_get_chan_index(dev_priv, "IO_T2H"); if (!dev_priv->channel_terminal || !dev_priv->channel_debug || !dev_priv->channel_shared_malloc || !dev_priv->channel_io || !dev_priv->channel_buf_h2t || !dev_priv->channel_buf_t2h || !dev_priv->channel_io_t2h) { dev_err(&dev_priv->pdev->dev, "did not find all of the required channels\n"); goto out; } return 0; out: isp_free_channel_info(dev_priv); return -ENOMEM; }
void fthd_buffer_return_handler(struct fthd_private *dev_priv, u32 offset, int size) { struct dma_descriptor_list list; struct h2t_buf_ctx *ctx; int i; FTHD_S2_MEMCPY_FROMIO(&list, offset, sizeof(list)); for(i = 0; i < list.count; i++) { ctx = (struct h2t_buf_ctx *)list.desc[i].tag; pr_debug("%d: field0: %d, count %d, pool %d, addr0 0x%08x, addr1 0x%08x tag 0x%08llx vb = %p, ctx = %p\n", i, list.field0, list.desc[i].count, list.desc[i].pool, list.desc[i].addr0, list.desc[i].addr1, list.desc[i].tag, ctx->vb, ctx); if (ctx->state == BUF_HW_QUEUED || ctx->state == BUF_DRV_QUEUED) { ctx->state = BUF_ALLOC; vb2_buffer_done(ctx->vb, VB2_BUF_STATE_DONE); } } }
int fthd_isp_debug_cmd(struct fthd_private *dev_priv, enum fthd_isp_cmds command, void *buf, int request_len, int *response_len) { struct isp_mem_obj *request; struct isp_cmd_hdr cmd; u32 address, request_size, response_size; u32 entry; int len, ret; memset(&cmd, 0, sizeof(cmd)); if (response_len) { len = max(request_len, *response_len); } else { len = request_len; } len += sizeof(struct isp_cmd_hdr); pr_debug("sending debug cmd %d to firmware\n", command); request = isp_mem_create(dev_priv, FTHD_MEM_CMD, len); if (!request) { dev_err(&dev_priv->pdev->dev, "failed to allocate cmd memory object\n"); return -ENOMEM; } cmd.opcode = command; FTHD_S2_MEMCPY_TOIO(request->offset, &cmd, sizeof(struct isp_cmd_hdr)); if (request_len) FTHD_S2_MEMCPY_TOIO(request->offset + sizeof(struct isp_cmd_hdr), buf, request_len); ret = fthd_channel_ringbuf_send(dev_priv, dev_priv->channel_debug, request->offset, request_len + 8, (response_len ? *response_len : 0) + 8, &entry); if (ret) goto out; if (entry == (u32)-1) { ret = -EIO; goto out; } ret = fthd_channel_wait_ready(dev_priv, dev_priv->channel_debug, entry, 20000); if (ret) { if (response_len) *response_len = 0; goto out; } FTHD_S2_MEMCPY_FROMIO(&cmd, request->offset, sizeof(struct isp_cmd_hdr)); address = FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_ADDRESS_FLAGS); request_size = FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_REQUEST_SIZE); response_size = FTHD_S2_MEM_READ(entry + FTHD_RINGBUF_RESPONSE_SIZE); /* XXX: response size in the ringbuf is zero after command completion, how is buffer size verification done? */ if (response_len && *response_len) FTHD_S2_MEMCPY_FROMIO(buf, (address & ~3) + sizeof(struct isp_cmd_hdr), *response_len); pr_info("status %04x, request_len %d response len %d address_flags %x\n", cmd.status, request_size, response_size, address); ret = 0; out: isp_mem_destroy(request); return ret; }