in ti/k3-udma.c [4614:4816]
static int bcdma_setup_resources(struct udma_dev *ud)
{
int ret, i, j;
struct device *dev = ud->dev;
struct ti_sci_resource *rm_res, irq_res;
struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
const struct udma_oes_offsets *oes = &ud->soc_data->oes;
u32 cap;
/* Set up the throughput level start indexes */
cap = udma_read(ud->mmrs[MMR_GCFG], 0x2c);
if (BCDMA_CAP3_UBCHAN_CNT(cap)) {
ud->bchan_tpl.levels = 3;
ud->bchan_tpl.start_idx[1] = BCDMA_CAP3_UBCHAN_CNT(cap);
ud->bchan_tpl.start_idx[0] = BCDMA_CAP3_HBCHAN_CNT(cap);
} else if (BCDMA_CAP3_HBCHAN_CNT(cap)) {
ud->bchan_tpl.levels = 2;
ud->bchan_tpl.start_idx[0] = BCDMA_CAP3_HBCHAN_CNT(cap);
} else {
ud->bchan_tpl.levels = 1;
}
cap = udma_read(ud->mmrs[MMR_GCFG], 0x30);
if (BCDMA_CAP4_URCHAN_CNT(cap)) {
ud->rchan_tpl.levels = 3;
ud->rchan_tpl.start_idx[1] = BCDMA_CAP4_URCHAN_CNT(cap);
ud->rchan_tpl.start_idx[0] = BCDMA_CAP4_HRCHAN_CNT(cap);
} else if (BCDMA_CAP4_HRCHAN_CNT(cap)) {
ud->rchan_tpl.levels = 2;
ud->rchan_tpl.start_idx[0] = BCDMA_CAP4_HRCHAN_CNT(cap);
} else {
ud->rchan_tpl.levels = 1;
}
if (BCDMA_CAP4_UTCHAN_CNT(cap)) {
ud->tchan_tpl.levels = 3;
ud->tchan_tpl.start_idx[1] = BCDMA_CAP4_UTCHAN_CNT(cap);
ud->tchan_tpl.start_idx[0] = BCDMA_CAP4_HTCHAN_CNT(cap);
} else if (BCDMA_CAP4_HTCHAN_CNT(cap)) {
ud->tchan_tpl.levels = 2;
ud->tchan_tpl.start_idx[0] = BCDMA_CAP4_HTCHAN_CNT(cap);
} else {
ud->tchan_tpl.levels = 1;
}
ud->bchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->bchan_cnt),
sizeof(unsigned long), GFP_KERNEL);
ud->bchans = devm_kcalloc(dev, ud->bchan_cnt, sizeof(*ud->bchans),
GFP_KERNEL);
ud->tchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->tchan_cnt),
sizeof(unsigned long), GFP_KERNEL);
ud->tchans = devm_kcalloc(dev, ud->tchan_cnt, sizeof(*ud->tchans),
GFP_KERNEL);
ud->rchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->rchan_cnt),
sizeof(unsigned long), GFP_KERNEL);
ud->rchans = devm_kcalloc(dev, ud->rchan_cnt, sizeof(*ud->rchans),
GFP_KERNEL);
/* BCDMA do not really have flows, but the driver expect it */
ud->rflow_in_use = devm_kcalloc(dev, BITS_TO_LONGS(ud->rchan_cnt),
sizeof(unsigned long),
GFP_KERNEL);
ud->rflows = devm_kcalloc(dev, ud->rchan_cnt, sizeof(*ud->rflows),
GFP_KERNEL);
if (!ud->bchan_map || !ud->tchan_map || !ud->rchan_map ||
!ud->rflow_in_use || !ud->bchans || !ud->tchans || !ud->rchans ||
!ud->rflows)
return -ENOMEM;
/* Get resource ranges from tisci */
for (i = 0; i < RM_RANGE_LAST; i++) {
if (i == RM_RANGE_RFLOW || i == RM_RANGE_TFLOW)
continue;
if (i == RM_RANGE_BCHAN && ud->bchan_cnt == 0)
continue;
if (i == RM_RANGE_TCHAN && ud->tchan_cnt == 0)
continue;
if (i == RM_RANGE_RCHAN && ud->rchan_cnt == 0)
continue;
tisci_rm->rm_ranges[i] =
devm_ti_sci_get_of_resource(tisci_rm->tisci, dev,
tisci_rm->tisci_dev_id,
(char *)range_names[i]);
}
irq_res.sets = 0;
/* bchan ranges */
if (ud->bchan_cnt) {
rm_res = tisci_rm->rm_ranges[RM_RANGE_BCHAN];
if (IS_ERR(rm_res)) {
bitmap_zero(ud->bchan_map, ud->bchan_cnt);
irq_res.sets++;
} else {
bitmap_fill(ud->bchan_map, ud->bchan_cnt);
for (i = 0; i < rm_res->sets; i++)
udma_mark_resource_ranges(ud, ud->bchan_map,
&rm_res->desc[i],
"bchan");
irq_res.sets += rm_res->sets;
}
}
/* tchan ranges */
if (ud->tchan_cnt) {
rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
if (IS_ERR(rm_res)) {
bitmap_zero(ud->tchan_map, ud->tchan_cnt);
irq_res.sets += 2;
} else {
bitmap_fill(ud->tchan_map, ud->tchan_cnt);
for (i = 0; i < rm_res->sets; i++)
udma_mark_resource_ranges(ud, ud->tchan_map,
&rm_res->desc[i],
"tchan");
irq_res.sets += rm_res->sets * 2;
}
}
/* rchan ranges */
if (ud->rchan_cnt) {
rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN];
if (IS_ERR(rm_res)) {
bitmap_zero(ud->rchan_map, ud->rchan_cnt);
irq_res.sets += 2;
} else {
bitmap_fill(ud->rchan_map, ud->rchan_cnt);
for (i = 0; i < rm_res->sets; i++)
udma_mark_resource_ranges(ud, ud->rchan_map,
&rm_res->desc[i],
"rchan");
irq_res.sets += rm_res->sets * 2;
}
}
irq_res.desc = kcalloc(irq_res.sets, sizeof(*irq_res.desc), GFP_KERNEL);
if (!irq_res.desc)
return -ENOMEM;
if (ud->bchan_cnt) {
rm_res = tisci_rm->rm_ranges[RM_RANGE_BCHAN];
if (IS_ERR(rm_res)) {
irq_res.desc[0].start = oes->bcdma_bchan_ring;
irq_res.desc[0].num = ud->bchan_cnt;
i = 1;
} else {
for (i = 0; i < rm_res->sets; i++) {
irq_res.desc[i].start = rm_res->desc[i].start +
oes->bcdma_bchan_ring;
irq_res.desc[i].num = rm_res->desc[i].num;
}
}
}
if (ud->tchan_cnt) {
rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
if (IS_ERR(rm_res)) {
irq_res.desc[i].start = oes->bcdma_tchan_data;
irq_res.desc[i].num = ud->tchan_cnt;
irq_res.desc[i + 1].start = oes->bcdma_tchan_ring;
irq_res.desc[i + 1].num = ud->tchan_cnt;
i += 2;
} else {
for (j = 0; j < rm_res->sets; j++, i += 2) {
irq_res.desc[i].start = rm_res->desc[j].start +
oes->bcdma_tchan_data;
irq_res.desc[i].num = rm_res->desc[j].num;
irq_res.desc[i + 1].start = rm_res->desc[j].start +
oes->bcdma_tchan_ring;
irq_res.desc[i + 1].num = rm_res->desc[j].num;
}
}
}
if (ud->rchan_cnt) {
rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN];
if (IS_ERR(rm_res)) {
irq_res.desc[i].start = oes->bcdma_rchan_data;
irq_res.desc[i].num = ud->rchan_cnt;
irq_res.desc[i + 1].start = oes->bcdma_rchan_ring;
irq_res.desc[i + 1].num = ud->rchan_cnt;
i += 2;
} else {
for (j = 0; j < rm_res->sets; j++, i += 2) {
irq_res.desc[i].start = rm_res->desc[j].start +
oes->bcdma_rchan_data;
irq_res.desc[i].num = rm_res->desc[j].num;
irq_res.desc[i + 1].start = rm_res->desc[j].start +
oes->bcdma_rchan_ring;
irq_res.desc[i + 1].num = rm_res->desc[j].num;
}
}
}
ret = ti_sci_inta_msi_domain_alloc_irqs(ud->dev, &irq_res);
kfree(irq_res.desc);
if (ret) {
dev_err(ud->dev, "Failed to allocate MSI interrupts\n");
return ret;
}
return 0;
}