in irq-crossbar.c [195:331]
static int __init crossbar_of_init(struct device_node *node)
{
u32 max = 0, entry, reg_size;
int i, size, reserved = 0;
const __be32 *irqsr;
int ret = -ENOMEM;
cb = kzalloc(sizeof(*cb), GFP_KERNEL);
if (!cb)
return ret;
cb->crossbar_base = of_iomap(node, 0);
if (!cb->crossbar_base)
goto err_cb;
of_property_read_u32(node, "ti,max-crossbar-sources",
&cb->max_crossbar_sources);
if (!cb->max_crossbar_sources) {
pr_err("missing 'ti,max-crossbar-sources' property\n");
ret = -EINVAL;
goto err_base;
}
of_property_read_u32(node, "ti,max-irqs", &max);
if (!max) {
pr_err("missing 'ti,max-irqs' property\n");
ret = -EINVAL;
goto err_base;
}
cb->irq_map = kcalloc(max, sizeof(int), GFP_KERNEL);
if (!cb->irq_map)
goto err_base;
cb->int_max = max;
for (i = 0; i < max; i++)
cb->irq_map[i] = IRQ_FREE;
/* Get and mark reserved irqs */
irqsr = of_get_property(node, "ti,irqs-reserved", &size);
if (irqsr) {
size /= sizeof(__be32);
for (i = 0; i < size; i++) {
of_property_read_u32_index(node,
"ti,irqs-reserved",
i, &entry);
if (entry >= max) {
pr_err("Invalid reserved entry\n");
ret = -EINVAL;
goto err_irq_map;
}
cb->irq_map[entry] = IRQ_RESERVED;
}
}
/* Skip irqs hardwired to bypass the crossbar */
irqsr = of_get_property(node, "ti,irqs-skip", &size);
if (irqsr) {
size /= sizeof(__be32);
for (i = 0; i < size; i++) {
of_property_read_u32_index(node,
"ti,irqs-skip",
i, &entry);
if (entry >= max) {
pr_err("Invalid skip entry\n");
ret = -EINVAL;
goto err_irq_map;
}
cb->irq_map[entry] = IRQ_SKIP;
}
}
cb->register_offsets = kcalloc(max, sizeof(int), GFP_KERNEL);
if (!cb->register_offsets)
goto err_irq_map;
of_property_read_u32(node, "ti,reg-size", ®_size);
switch (reg_size) {
case 1:
cb->write = crossbar_writeb;
break;
case 2:
cb->write = crossbar_writew;
break;
case 4:
cb->write = crossbar_writel;
break;
default:
pr_err("Invalid reg-size property\n");
ret = -EINVAL;
goto err_reg_offset;
break;
}
/*
* Register offsets are not linear because of the
* reserved irqs. so find and store the offsets once.
*/
for (i = 0; i < max; i++) {
if (cb->irq_map[i] == IRQ_RESERVED)
continue;
cb->register_offsets[i] = reserved;
reserved += reg_size;
}
of_property_read_u32(node, "ti,irqs-safe-map", &cb->safe_map);
/* Initialize the crossbar with safe map to start with */
for (i = 0; i < max; i++) {
if (cb->irq_map[i] == IRQ_RESERVED ||
cb->irq_map[i] == IRQ_SKIP)
continue;
cb->write(i, cb->safe_map);
}
raw_spin_lock_init(&cb->lock);
return 0;
err_reg_offset:
kfree(cb->register_offsets);
err_irq_map:
kfree(cb->irq_map);
err_base:
iounmap(cb->crossbar_base);
err_cb:
kfree(cb);
cb = NULL;
return ret;
}