drivers/soc/ti/knav_qmss_acc.c

Source file repositories/reference/linux-study-clean/drivers/soc/ti/knav_qmss_acc.c

File Facts

System
Linux kernel
Corpus path
drivers/soc/ti/knav_qmss_acc.c
Extension
.c
Size
15721 bytes
Lines
585
Domain
Driver Families
Bucket
drivers/soc
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (inst->notify_needed) {
				inst->notify_needed = 0;
				dev_dbg(kdev->dev, "acc-irq: notifying %d\n",
					range_base + queue);
				knav_queue_notify(inst);
			}
		}
	} else {
		queue = acc->channel - range->acc_info.start_channel;
		inst = knav_range_offset_to_inst(kdev, range, queue);
		dev_dbg(kdev->dev, "acc-irq: notifying %d\n",
			range_base + queue);
		knav_queue_notify(inst);
	}
}

static int knav_acc_set_notify(struct knav_range_info *range,
				struct knav_queue_inst *kq,
				bool enabled)
{
	struct knav_pdsp_info *pdsp = range->acc_info.pdsp;
	struct knav_device *kdev = range->kdev;
	u32 mask, offset;

	/*
	 * when enabling, we need to re-trigger an interrupt if we
	 * have descriptors pending
	 */
	if (!enabled || atomic_read(&kq->desc_count) <= 0)
		return 0;

	kq->notify_needed = 1;
	atomic_inc(&kq->acc->retrigger_count);
	mask = BIT(kq->acc->channel % 32);
	offset = ACC_INTD_OFFSET_STATUS(kq->acc->channel);
	dev_dbg(kdev->dev, "setup-notify: re-triggering irq for %s\n",
		kq->acc->name);
	writel_relaxed(mask, pdsp->intd + offset);
	return 0;
}

static irqreturn_t knav_acc_int_handler(int irq, void *_instdata)
{
	struct knav_acc_channel *acc;
	struct knav_queue_inst *kq = NULL;
	struct knav_range_info *range;
	struct knav_pdsp_info *pdsp;
	struct knav_acc_info *info;
	struct knav_device *kdev;

	u32 *list, *list_cpu, val, idx, notifies;
	int range_base, channel, queue = 0;
	dma_addr_t list_dma;

	range = _instdata;
	info  = &range->acc_info;
	kdev  = range->kdev;
	pdsp  = range->acc_info.pdsp;
	acc   = range->acc;

	range_base = kdev->base_id + range->queue_base;
	if ((range->flags & RANGE_MULTI_QUEUE) == 0) {
		for (queue = 0; queue < range->num_irqs; queue++)
			if (range->irqs[queue].irq == irq)
				break;
		kq = knav_range_offset_to_inst(kdev, range, queue);
		acc += queue;
	}

	channel = acc->channel;
	list_dma = acc->list_dma[acc->list_index];
	list_cpu = acc->list_cpu[acc->list_index];
	dev_dbg(kdev->dev, "acc-irq: channel %d, list %d, virt %p, dma %pad\n",
		channel, acc->list_index, list_cpu, &list_dma);
	if (atomic_read(&acc->retrigger_count)) {
		atomic_dec(&acc->retrigger_count);
		__knav_acc_notify(range, acc);
		writel_relaxed(1, pdsp->intd + ACC_INTD_OFFSET_COUNT(channel));
		/* ack the interrupt */
		writel_relaxed(ACC_CHANNEL_INT_BASE + channel,
			       pdsp->intd + ACC_INTD_OFFSET_EOI);

		return IRQ_HANDLED;
	}

	notifies = readl_relaxed(pdsp->intd + ACC_INTD_OFFSET_COUNT(channel));
	WARN_ON(!notifies);
	dma_sync_single_for_cpu(kdev->dev, list_dma, info->list_size,
				DMA_FROM_DEVICE);

Annotation

Implementation Notes