|
8 | 8 | #include <linux/clk.h>
|
9 | 9 | #include <linux/component.h>
|
10 | 10 | #include <linux/device.h>
|
| 11 | +#include <linux/dma-direct.h> |
11 | 12 | #include <linux/dma-iommu.h>
|
12 | 13 | #include <linux/err.h>
|
13 | 14 | #include <linux/interrupt.h>
|
@@ -314,6 +315,36 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
|
314 | 315 | return IRQ_HANDLED;
|
315 | 316 | }
|
316 | 317 |
|
| 318 | +static int mtk_iommu_get_domain_id(struct device *dev, |
| 319 | + const struct mtk_iommu_plat_data *plat_data) |
| 320 | +{ |
| 321 | + const struct mtk_iommu_iova_region *rgn = plat_data->iova_region; |
| 322 | + const struct bus_dma_region *dma_rgn = dev->dma_range_map; |
| 323 | + int i, candidate = -1; |
| 324 | + dma_addr_t dma_end; |
| 325 | + |
| 326 | + if (!dma_rgn || plat_data->iova_region_nr == 1) |
| 327 | + return 0; |
| 328 | + |
| 329 | + dma_end = dma_rgn->dma_start + dma_rgn->size - 1; |
| 330 | + for (i = 0; i < plat_data->iova_region_nr; i++, rgn++) { |
| 331 | + /* Best fit. */ |
| 332 | + if (dma_rgn->dma_start == rgn->iova_base && |
| 333 | + dma_end == rgn->iova_base + rgn->size - 1) |
| 334 | + return i; |
| 335 | + /* ok if it is inside this region. */ |
| 336 | + if (dma_rgn->dma_start >= rgn->iova_base && |
| 337 | + dma_end < rgn->iova_base + rgn->size) |
| 338 | + candidate = i; |
| 339 | + } |
| 340 | + |
| 341 | + if (candidate >= 0) |
| 342 | + return candidate; |
| 343 | + dev_err(dev, "Can NOT find the iommu domain id(%pad 0x%llx).\n", |
| 344 | + &dma_rgn->dma_start, dma_rgn->size); |
| 345 | + return -EINVAL; |
| 346 | +} |
| 347 | + |
317 | 348 | static void mtk_iommu_config(struct mtk_iommu_data *data,
|
318 | 349 | struct device *dev, bool enable)
|
319 | 350 | {
|
@@ -400,11 +431,15 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain,
|
400 | 431 | struct mtk_iommu_data *data = dev_iommu_priv_get(dev);
|
401 | 432 | struct mtk_iommu_domain *dom = to_mtk_domain(domain);
|
402 | 433 | struct device *m4udev = data->dev;
|
403 |
| - int ret; |
| 434 | + int ret, domid; |
404 | 435 |
|
405 | 436 | if (!data)
|
406 | 437 | return -ENODEV;
|
407 | 438 |
|
| 439 | + domid = mtk_iommu_get_domain_id(dev, data->plat_data); |
| 440 | + if (domid < 0) |
| 441 | + return domid; |
| 442 | + |
408 | 443 | if (!dom->data) {
|
409 | 444 | if (mtk_iommu_domain_finalise(dom, data))
|
410 | 445 | return -ENODEV;
|
@@ -534,10 +569,15 @@ static void mtk_iommu_release_device(struct device *dev)
|
534 | 569 | static struct iommu_group *mtk_iommu_device_group(struct device *dev)
|
535 | 570 | {
|
536 | 571 | struct mtk_iommu_data *data = mtk_iommu_get_m4u_data();
|
| 572 | + int domid; |
537 | 573 |
|
538 | 574 | if (!data)
|
539 | 575 | return ERR_PTR(-ENODEV);
|
540 | 576 |
|
| 577 | + domid = mtk_iommu_get_domain_id(dev, data->plat_data); |
| 578 | + if (domid < 0) |
| 579 | + return ERR_PTR(domid); |
| 580 | + |
541 | 581 | /* All the client devices are in the same m4u iommu-group */
|
542 | 582 | if (!data->m4u_group) {
|
543 | 583 | data->m4u_group = iommu_group_alloc();
|
|
0 commit comments