/* Allocate the requested number of contiguous LSB slots * from the LSB bitmap. Look in the private range for this * queue first; failing that, check the public area. * If no space is available, wait around. * Return: first slot number
*/ static u32 ccp_lsb_alloc(struct ccp_cmd_queue *cmd_q, unsignedint count)
{ struct ccp_device *ccp; int start;
/* First look at the map for the queue */ if (cmd_q->lsb >= 0) {
start = (u32)bitmap_find_next_zero_area(cmd_q->lsbmap,
LSB_SIZE,
0, count, 0); if (start < LSB_SIZE) {
bitmap_set(cmd_q->lsbmap, start, count); return start + cmd_q->lsb * LSB_SIZE;
}
}
/* No joy; try to get an entry from the shared blocks */
ccp = cmd_q->ccp; for (;;) {
mutex_lock(&ccp->sb_mutex);
/* Wait for KSB entries to become available */ if (wait_event_interruptible(ccp->sb_queue, ccp->sb_avail)) return 0;
}
}
/* Free a number of LSB slots from the bitmap, starting at * the indicated starting slot number.
*/ staticvoid ccp_lsb_free(struct ccp_cmd_queue *cmd_q, unsignedint start, unsignedint count)
{ if (!start) return;
if (cmd_q->lsb == start) { /* An entry from the private LSB */
bitmap_clear(cmd_q->lsbmap, start, count);
} else { /* From the shared LSBs */ struct ccp_device *ccp = cmd_q->ccp;
/* The data used by this command must be flushed to memory */
wmb();
/* Write the new tail address back to the queue register */
tail = low_address(cmd_q->qdma_tail + cmd_q->qidx * Q_DESC_SIZE);
iowrite32(tail, cmd_q->reg_tail_lo);
/* Turn the queue back on using our cached control register */
iowrite32(cmd_q->qcontrol | CMD5_Q_RUN, cmd_q->reg_control);
mutex_unlock(&cmd_q->q_mutex);
if (CCP5_CMD_IOC(desc)) { /* Wait for the job to complete */
ret = wait_event_interruptible(cmd_q->int_queue,
cmd_q->int_rcvd); if (ret || cmd_q->cmd_error) { /* Log the error and flush the queue by * moving the head pointer
*/ if (cmd_q->cmd_error)
ccp_log_error(cmd_q->ccp,
cmd_q->cmd_error);
iowrite32(tail, cmd_q->reg_head_lo); if (!ret)
ret = -EIO;
}
cmd_q->int_rcvd = 0;
}
staticint ccp_find_lsb_regions(struct ccp_cmd_queue *cmd_q, u64 status)
{ int q_mask = 1 << cmd_q->id; int queues = 0; int j;
/* Build a bit mask to know which LSBs this queue has access to. * Don't bother with segment 0 as it has special privileges.
*/ for (j = 1; j < MAX_LSB_CNT; j++) { if (status & q_mask)
bitmap_set(cmd_q->lsbmask, j, 1);
status >>= LSB_REGION_WIDTH;
}
queues = bitmap_weight(cmd_q->lsbmask, MAX_LSB_CNT);
dev_dbg(cmd_q->ccp->dev, "Queue %d can access %d LSB regions\n",
cmd_q->id, queues);
return queues ? 0 : -EINVAL;
}
staticint ccp_find_and_assign_lsb_to_q(struct ccp_device *ccp, int lsb_cnt, int n_lsbs, unsignedlong *lsb_pub)
{
DECLARE_BITMAP(qlsb, MAX_LSB_CNT); int bitno; int qlsb_wgt; int i;
/* For each queue: * If the count of potential LSBs available to a queue matches the * ordinal given to us in lsb_cnt: * Copy the mask of possible LSBs for this queue into "qlsb"; * For each bit in qlsb, see if the corresponding bit in the * aggregation mask is set; if so, we have a match. * If we have a match, clear the bit in the aggregation to * mark it as no longer available. * If there is no match, clear the bit in qlsb and keep looking.
*/ for (i = 0; i < ccp->cmd_q_count; i++) { struct ccp_cmd_queue *cmd_q = &ccp->cmd_q[i];
if (qlsb_wgt == lsb_cnt) {
bitmap_copy(qlsb, cmd_q->lsbmask, MAX_LSB_CNT);
bitno = find_first_bit(qlsb, MAX_LSB_CNT); while (bitno < MAX_LSB_CNT) { if (test_bit(bitno, lsb_pub)) { /* We found an available LSB * that this queue can access
*/
cmd_q->lsb = bitno;
bitmap_clear(lsb_pub, bitno, 1);
dev_dbg(ccp->dev, "Queue %d gets LSB %d\n",
i, bitno); break;
}
bitmap_clear(qlsb, bitno, 1);
bitno = find_first_bit(qlsb, MAX_LSB_CNT);
} if (bitno >= MAX_LSB_CNT) return -EINVAL;
n_lsbs--;
}
} return n_lsbs;
}
/* For each queue, from the most- to least-constrained: * find an LSB that can be assigned to the queue. If there are N queues that * can only use M LSBs, where N > M, fail; otherwise, every queue will get a * dedicated LSB. Remaining LSB regions become a shared resource. * If we have fewer LSBs than queues, all LSB regions become shared resources.
*/ staticint ccp_assign_lsbs(struct ccp_device *ccp)
{
DECLARE_BITMAP(lsb_pub, MAX_LSB_CNT);
DECLARE_BITMAP(qlsb, MAX_LSB_CNT); int n_lsbs = 0; int bitno; int i, lsb_cnt; int rc = 0;
bitmap_zero(lsb_pub, MAX_LSB_CNT);
/* Create an aggregate bitmap to get a total count of available LSBs */ for (i = 0; i < ccp->cmd_q_count; i++)
bitmap_or(lsb_pub,
lsb_pub, ccp->cmd_q[i].lsbmask,
MAX_LSB_CNT);
n_lsbs = bitmap_weight(lsb_pub, MAX_LSB_CNT);
if (n_lsbs >= ccp->cmd_q_count) { /* We have enough LSBS to give every queue a private LSB. * Brute force search to start with the queues that are more * constrained in LSB choice. When an LSB is privately * assigned, it is removed from the public mask. * This is an ugly N squared algorithm with some optimization.
*/ for (lsb_cnt = 1;
n_lsbs && (lsb_cnt <= MAX_LSB_CNT);
lsb_cnt++) {
rc = ccp_find_and_assign_lsb_to_q(ccp, lsb_cnt, n_lsbs,
lsb_pub); if (rc < 0) return -EINVAL;
n_lsbs = rc;
}
}
rc = 0; /* What's left of the LSBs, according to the public mask, now become * shared. Any zero bits in the lsb_pub mask represent an LSB region * that can't be used as a shared resource, so mark the LSB slots for * them as "in use".
*/
bitmap_copy(qlsb, lsb_pub, MAX_LSB_CNT);
bitno = find_first_zero_bit(qlsb, MAX_LSB_CNT); while (bitno < MAX_LSB_CNT) {
bitmap_set(ccp->lsbmap, bitno * LSB_SIZE, LSB_SIZE);
bitmap_set(qlsb, bitno, 1);
bitno = find_first_zero_bit(qlsb, MAX_LSB_CNT);
}
/* On error, only save the first error value */ if ((status & INT_ERROR) && !cmd_q->cmd_error)
cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status);
cmd_q->int_rcvd = 1;
/* Acknowledge the interrupt and wake the kthread */
iowrite32(status, cmd_q->reg_interrupt_status);
wake_up_interruptible(&cmd_q->int_queue);
}
}
ccp5_enable_queue_interrupts(ccp);
}
/* Find available queues */
qmr = ioread32(ccp->io_regs + Q_MASK_REG); /* * Check for a access to the registers. If this read returns * 0xffffffff, it's likely that the system is running a broken * BIOS which disallows access to the device. Stop here and fail * the initialization (but not the load, as the PSP could get * properly initialized).
*/ if (qmr == 0xffffffff) {
dev_notice(dev, "ccp: unable to access the device: you might be running a broken BIOS.\n"); return 1;
}
for (i = 0; (i < MAX_HW_QUEUES) && (ccp->cmd_q_count < ccp->max_q_count); i++) { if (!(qmr & (1 << i))) continue;
/* Allocate a dma pool for this queue */
snprintf(dma_pool_name, sizeof(dma_pool_name), "%s_q%d",
ccp->name, i);
dma_pool = dma_pool_create(dma_pool_name, dev,
CCP_DMAPOOL_MAX_SIZE,
CCP_DMAPOOL_ALIGN, 0); if (!dma_pool) {
dev_err(dev, "unable to allocate dma pool\n");
ret = -ENOMEM; goto e_pool;
}
if (ccp->cmd_q_count == 0) {
dev_notice(dev, "no command queues available\n");
ret = 1; goto e_pool;
}
/* Turn off the queues and disable interrupts until ready */
ccp5_disable_queue_interrupts(ccp); for (i = 0; i < ccp->cmd_q_count; i++) {
cmd_q = &ccp->cmd_q[i];
cmd_q->qcontrol = 0; /* Start with nothing */
iowrite32(cmd_q->qcontrol, cmd_q->reg_control);
/* Clear the interrupt status */
iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status);
}
dev_dbg(dev, "Requesting an IRQ...\n"); /* Request an irq */
ret = sp_request_ccp_irq(ccp->sp, ccp5_irq_handler, ccp->name, ccp); if (ret) {
dev_err(dev, "unable to allocate an IRQ\n"); goto e_pool;
} /* Initialize the ISR tasklet */ if (ccp->use_tasklet)
tasklet_init(&ccp->irq_tasklet, ccp5_irq_bh,
(unsignedlong)ccp);
dev_dbg(dev, "Loading LSB map...\n"); /* Copy the private LSB mask to the public registers */
status_lo = ioread32(ccp->io_regs + LSB_PRIVATE_MASK_LO_OFFSET);
status_hi = ioread32(ccp->io_regs + LSB_PRIVATE_MASK_HI_OFFSET);
iowrite32(status_lo, ccp->io_regs + LSB_PUBLIC_MASK_LO_OFFSET);
iowrite32(status_hi, ccp->io_regs + LSB_PUBLIC_MASK_HI_OFFSET);
status = ((u64)status_hi<<30) | (u64)status_lo;
dev_dbg(dev, "Configuring virtual queues...\n"); /* Configure size of each virtual queue accessible to host */ for (i = 0; i < ccp->cmd_q_count; i++) {
u32 dma_addr_lo;
u32 dma_addr_hi;
/* Unregister the DMA engine */
ccp_dmaengine_unregister(ccp);
/* Unregister the RNG */
ccp_unregister_rng(ccp);
/* Remove this device from the list of available units first */
ccp_del_device(ccp);
#ifdef CONFIG_CRYPTO_DEV_CCP_DEBUGFS /* We're in the process of tearing down the entire driver; * when all the devices are gone clean up debugfs
*/ if (ccp_present())
ccp5_debugfs_destroy(); #endif
/* Disable and clear interrupts */
ccp5_disable_queue_interrupts(ccp); for (i = 0; i < ccp->cmd_q_count; i++) {
cmd_q = &ccp->cmd_q[i];
/* Turn off the run bit */
iowrite32(cmd_q->qcontrol & ~CMD5_Q_RUN, cmd_q->reg_control);
/* Clear the interrupt status */
iowrite32(SUPPORTED_INTERRUPTS, cmd_q->reg_interrupt_status);
ioread32(cmd_q->reg_int_status);
ioread32(cmd_q->reg_status);
}
/* Stop the queue kthreads */ for (i = 0; i < ccp->cmd_q_count; i++) if (ccp->cmd_q[i].kthread)
kthread_stop(ccp->cmd_q[i].kthread);
sp_free_ccp_irq(ccp->sp, ccp);
/* Flush the cmd and backlog queue */ while (!list_empty(&ccp->cmd)) { /* Invoke the callback directly with an error code */
cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry);
list_del(&cmd->entry);
cmd->callback(cmd->data, -ENODEV);
} while (!list_empty(&ccp->backlog)) { /* Invoke the callback directly with an error code */
cmd = list_first_entry(&ccp->backlog, struct ccp_cmd, entry);
list_del(&cmd->entry);
cmd->callback(cmd->data, -ENODEV);
}
}
staticvoid ccp5_config(struct ccp_device *ccp)
{ /* Public side */
iowrite32(0x0, ccp->io_regs + CMD5_REQID_CONFIG_OFFSET);
}
staticvoid ccp5other_config(struct ccp_device *ccp)
{ int i;
u32 rnd;
/* We own all of the queues on the NTB CCP */
iowrite32(0x00012D57, ccp->io_regs + CMD5_TRNG_CTL_OFFSET);
iowrite32(0x00000003, ccp->io_regs + CMD5_CONFIG_0_OFFSET); for (i = 0; i < 12; i++) {
rnd = ioread32(ccp->io_regs + TRNG_OUT_REG);
iowrite32(rnd, ccp->io_regs + CMD5_AES_MASK_OFFSET);
}
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.