static int knav_setup_queue_range()

in ti/knav_qmss_queue.c [1211:1306]


static int knav_setup_queue_range(struct knav_device *kdev,
					struct device_node *node)
{
	struct device *dev = kdev->dev;
	struct knav_range_info *range;
	struct knav_qmgr_info *qmgr;
	u32 temp[2], start, end, id, index;
	int ret, i;

	range = devm_kzalloc(dev, sizeof(*range), GFP_KERNEL);
	if (!range) {
		dev_err(dev, "out of memory allocating range\n");
		return -ENOMEM;
	}

	range->kdev = kdev;
	range->name = knav_queue_find_name(node);
	ret = of_property_read_u32_array(node, "qrange", temp, 2);
	if (!ret) {
		range->queue_base = temp[0] - kdev->base_id;
		range->num_queues = temp[1];
	} else {
		dev_err(dev, "invalid queue range %s\n", range->name);
		devm_kfree(dev, range);
		return -EINVAL;
	}

	for (i = 0; i < RANGE_MAX_IRQS; i++) {
		struct of_phandle_args oirq;

		if (of_irq_parse_one(node, i, &oirq))
			break;

		range->irqs[i].irq = irq_create_of_mapping(&oirq);
		if (range->irqs[i].irq == IRQ_NONE)
			break;

		range->num_irqs++;

		if (IS_ENABLED(CONFIG_SMP) && oirq.args_count == 3) {
			unsigned long mask;
			int bit;

			range->irqs[i].cpu_mask = devm_kzalloc(dev,
							       cpumask_size(), GFP_KERNEL);
			if (!range->irqs[i].cpu_mask)
				return -ENOMEM;

			mask = (oirq.args[2] & 0x0000ff00) >> 8;
			for_each_set_bit(bit, &mask, BITS_PER_LONG)
				cpumask_set_cpu(bit, range->irqs[i].cpu_mask);
		}
	}

	range->num_irqs = min(range->num_irqs, range->num_queues);
	if (range->num_irqs)
		range->flags |= RANGE_HAS_IRQ;

	if (of_get_property(node, "qalloc-by-id", NULL))
		range->flags |= RANGE_RESERVED;

	if (of_get_property(node, "accumulator", NULL)) {
		ret = knav_init_acc_range(kdev, node, range);
		if (ret < 0) {
			devm_kfree(dev, range);
			return ret;
		}
	} else {
		range->ops = &knav_gp_range_ops;
	}

	/* set threshold to 1, and flush out the queues */
	for_each_qmgr(kdev, qmgr) {
		start = max(qmgr->start_queue, range->queue_base);
		end   = min(qmgr->start_queue + qmgr->num_queues,
			    range->queue_base + range->num_queues);
		for (id = start; id < end; id++) {
			index = id - qmgr->start_queue;
			writel_relaxed(THRESH_GTE | 1,
				       &qmgr->reg_peek[index].ptr_size_thresh);
			writel_relaxed(0,
				       &qmgr->reg_push[index].ptr_size_thresh);
		}
	}

	list_add_tail(&range->list, &kdev->queue_ranges);
	dev_dbg(dev, "added range %s: %d-%d, %d irqs%s%s%s\n",
		range->name, range->queue_base,
		range->queue_base + range->num_queues - 1,
		range->num_irqs,
		(range->flags & RANGE_HAS_IRQ) ? ", has irq" : "",
		(range->flags & RANGE_RESERVED) ? ", reserved" : "",
		(range->flags & RANGE_HAS_ACCUMULATOR) ? ", acc" : "");
	kdev->num_queues_in_use += range->num_queues;
	return 0;
}