aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSricharan R <sricharan@codeaurora.org>2016-06-13 07:36:02 -0400
committerJoerg Roedel <jroedel@suse.de>2016-06-21 07:56:00 -0400
commit109bd48ea2e1fb4e924712018397a51c7b2aaadd (patch)
tree334879f8576068e764c9d5657cc74438cf94111c
parent33688abb2802ff3a230bd2441f765477b94cc89e (diff)
iommu/msm: Add DT adaptation
The driver currently works based on platform data. Remove this and add support for DT. A single master can have multiple ports connected to more than one iommu. master | | | ------------------------ | | IOMMU0 IOMMU1 | | ctx0 ctx1 ctx0 ctx1 This association of master and iommus/contexts were previously represented by platform data parent/child device details. The client drivers were responsible for programming all of the iommus/contexts for the device. Now while adapting to generic DT bindings we maintain the list of iommus, contexts that each master domain is connected to and program all of them on attach/detach. Signed-off-by: Sricharan R <sricharan@codeaurora.org> Tested-by: Archit Taneja <architt@codeaurora.org> Tested-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r--drivers/iommu/msm_iommu.c252
-rw-r--r--drivers/iommu/msm_iommu.h73
-rw-r--r--drivers/iommu/msm_iommu_dev.c315
3 files changed, 237 insertions, 403 deletions
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index e321fa517a45..bc1a4e3a7042 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -48,6 +48,7 @@ __asm__ __volatile__ ( \
48static int msm_iommu_tex_class[4]; 48static int msm_iommu_tex_class[4];
49 49
50DEFINE_SPINLOCK(msm_iommu_lock); 50DEFINE_SPINLOCK(msm_iommu_lock);
51static LIST_HEAD(qcom_iommu_devices);
51 52
52struct msm_priv { 53struct msm_priv {
53 unsigned long *pgtable; 54 unsigned long *pgtable;
@@ -60,35 +61,37 @@ static struct msm_priv *to_msm_priv(struct iommu_domain *dom)
60 return container_of(dom, struct msm_priv, domain); 61 return container_of(dom, struct msm_priv, domain);
61} 62}
62 63
63static int __enable_clocks(struct msm_iommu_drvdata *drvdata) 64static int __enable_clocks(struct msm_iommu_dev *iommu)
64{ 65{
65 int ret; 66 int ret;
66 67
67 ret = clk_enable(drvdata->pclk); 68 ret = clk_enable(iommu->pclk);
68 if (ret) 69 if (ret)
69 goto fail; 70 goto fail;
70 71
71 if (drvdata->clk) { 72 if (iommu->clk) {
72 ret = clk_enable(drvdata->clk); 73 ret = clk_enable(iommu->clk);
73 if (ret) 74 if (ret)
74 clk_disable(drvdata->pclk); 75 clk_disable(iommu->pclk);
75 } 76 }
76fail: 77fail:
77 return ret; 78 return ret;
78} 79}
79 80
80static void __disable_clocks(struct msm_iommu_drvdata *drvdata) 81static void __disable_clocks(struct msm_iommu_dev *iommu)
81{ 82{
82 clk_disable(drvdata->clk); 83 if (iommu->clk)
83 clk_disable(drvdata->pclk); 84 clk_disable(iommu->clk);
85 clk_disable(iommu->pclk);
84} 86}
85 87
86static int __flush_iotlb(struct iommu_domain *domain) 88static int __flush_iotlb(struct iommu_domain *domain)
87{ 89{
88 struct msm_priv *priv = to_msm_priv(domain); 90 struct msm_priv *priv = to_msm_priv(domain);
89 struct msm_iommu_drvdata *iommu_drvdata; 91 struct msm_iommu_dev *iommu = NULL;
90 struct msm_iommu_ctx_drvdata *ctx_drvdata; 92 struct msm_iommu_ctx_dev *master;
91 int ret = 0; 93 int ret = 0;
94
92#ifndef CONFIG_IOMMU_PGTABLES_L2 95#ifndef CONFIG_IOMMU_PGTABLES_L2
93 unsigned long *fl_table = priv->pgtable; 96 unsigned long *fl_table = priv->pgtable;
94 int i; 97 int i;
@@ -105,24 +108,67 @@ static int __flush_iotlb(struct iommu_domain *domain)
105 } 108 }
106#endif 109#endif
107 110
108 list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) { 111 list_for_each_entry(iommu, &priv->list_attached, dom_node) {
109 112 ret = __enable_clocks(iommu);
110 BUG_ON(!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent);
111
112 iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
113 BUG_ON(!iommu_drvdata);
114
115 ret = __enable_clocks(iommu_drvdata);
116 if (ret) 113 if (ret)
117 goto fail; 114 goto fail;
118 115
119 SET_CTX_TLBIALL(iommu_drvdata->base, ctx_drvdata->num, 0); 116 list_for_each_entry(master, &iommu->ctx_list, list)
120 __disable_clocks(iommu_drvdata); 117 SET_CTX_TLBIALL(iommu->base, master->num, 0);
118
119 __disable_clocks(iommu);
121 } 120 }
122fail: 121fail:
123 return ret; 122 return ret;
124} 123}
125 124
125static int msm_iommu_alloc_ctx(unsigned long *map, int start, int end)
126{
127 int idx;
128
129 do {
130 idx = find_next_zero_bit(map, end, start);
131 if (idx == end)
132 return -ENOSPC;
133 } while (test_and_set_bit(idx, map));
134
135 return idx;
136}
137
138static void msm_iommu_free_ctx(unsigned long *map, int idx)
139{
140 clear_bit(idx, map);
141}
142
143static void config_mids(struct msm_iommu_dev *iommu,
144 struct msm_iommu_ctx_dev *master)
145{
146 int mid, ctx, i;
147
148 for (i = 0; i < master->num_mids; i++) {
149 mid = master->mids[i];
150 ctx = master->num;
151
152 SET_M2VCBR_N(iommu->base, mid, 0);
153 SET_CBACR_N(iommu->base, ctx, 0);
154
155 /* Set VMID = 0 */
156 SET_VMID(iommu->base, mid, 0);
157
158 /* Set the context number for that MID to this context */
159 SET_CBNDX(iommu->base, mid, ctx);
160
161 /* Set MID associated with this context bank to 0*/
162 SET_CBVMID(iommu->base, ctx, 0);
163
164 /* Set the ASID for TLB tagging for this context */
165 SET_CONTEXTIDR_ASID(iommu->base, ctx, ctx);
166
167 /* Set security bit override to be Non-secure */
168 SET_NSCFG(iommu->base, mid, 3);
169 }
170}
171
126static void __reset_context(void __iomem *base, int ctx) 172static void __reset_context(void __iomem *base, int ctx)
127{ 173{
128 SET_BPRCOSH(base, ctx, 0); 174 SET_BPRCOSH(base, ctx, 0);
@@ -272,94 +318,76 @@ static void msm_iommu_domain_free(struct iommu_domain *domain)
272 318
273static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) 319static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
274{ 320{
275 struct msm_priv *priv;
276 struct msm_iommu_ctx_dev *ctx_dev;
277 struct msm_iommu_drvdata *iommu_drvdata;
278 struct msm_iommu_ctx_drvdata *ctx_drvdata;
279 struct msm_iommu_ctx_drvdata *tmp_drvdata;
280 int ret = 0; 321 int ret = 0;
281 unsigned long flags; 322 unsigned long flags;
323 struct msm_iommu_dev *iommu;
324 struct msm_priv *priv = to_msm_priv(domain);
325 struct msm_iommu_ctx_dev *master;
282 326
283 spin_lock_irqsave(&msm_iommu_lock, flags); 327 spin_lock_irqsave(&msm_iommu_lock, flags);
284 328 list_for_each_entry(iommu, &qcom_iommu_devices, dev_node) {
285 priv = to_msm_priv(domain); 329 master = list_first_entry(&iommu->ctx_list,
286 330 struct msm_iommu_ctx_dev,
287 if (!dev) { 331 list);
288 ret = -EINVAL; 332 if (master->of_node == dev->of_node) {
289 goto fail; 333 ret = __enable_clocks(iommu);
290 } 334 if (ret)
291 335 goto fail;
292 iommu_drvdata = dev_get_drvdata(dev->parent); 336
293 ctx_drvdata = dev_get_drvdata(dev); 337 list_for_each_entry(master, &iommu->ctx_list, list) {
294 ctx_dev = dev->platform_data; 338 if (master->num) {
295 339 dev_err(dev, "domain already attached");
296 if (!iommu_drvdata || !ctx_drvdata || !ctx_dev) { 340 ret = -EEXIST;
297 ret = -EINVAL; 341 goto fail;
298 goto fail; 342 }
299 } 343 master->num =
300 344 msm_iommu_alloc_ctx(iommu->context_map,
301 if (!list_empty(&ctx_drvdata->attached_elm)) { 345 0, iommu->ncb);
302 ret = -EBUSY; 346 if (IS_ERR_VALUE(master->num)) {
303 goto fail; 347 ret = -ENODEV;
304 } 348 goto fail;
305 349 }
306 list_for_each_entry(tmp_drvdata, &priv->list_attached, attached_elm) 350 config_mids(iommu, master);
307 if (tmp_drvdata == ctx_drvdata) { 351 __program_context(iommu->base, master->num,
308 ret = -EBUSY; 352 __pa(priv->pgtable));
309 goto fail; 353 }
354 __disable_clocks(iommu);
355 list_add(&iommu->dom_node, &priv->list_attached);
310 } 356 }
357 }
311 358
312 ret = __enable_clocks(iommu_drvdata);
313 if (ret)
314 goto fail;
315
316 __program_context(iommu_drvdata->base, ctx_dev->num,
317 __pa(priv->pgtable));
318
319 __disable_clocks(iommu_drvdata);
320 list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
321 ret = __flush_iotlb(domain); 359 ret = __flush_iotlb(domain);
322
323fail: 360fail:
324 spin_unlock_irqrestore(&msm_iommu_lock, flags); 361 spin_unlock_irqrestore(&msm_iommu_lock, flags);
362
325 return ret; 363 return ret;
326} 364}
327 365
328static void msm_iommu_detach_dev(struct iommu_domain *domain, 366static void msm_iommu_detach_dev(struct iommu_domain *domain,
329 struct device *dev) 367 struct device *dev)
330{ 368{
331 struct msm_priv *priv; 369 struct msm_priv *priv = to_msm_priv(domain);
332 struct msm_iommu_ctx_dev *ctx_dev;
333 struct msm_iommu_drvdata *iommu_drvdata;
334 struct msm_iommu_ctx_drvdata *ctx_drvdata;
335 unsigned long flags; 370 unsigned long flags;
371 struct msm_iommu_dev *iommu;
372 struct msm_iommu_ctx_dev *master;
336 int ret; 373 int ret;
337 374
338 spin_lock_irqsave(&msm_iommu_lock, flags); 375 spin_lock_irqsave(&msm_iommu_lock, flags);
339 priv = to_msm_priv(domain);
340
341 if (!dev)
342 goto fail;
343
344 iommu_drvdata = dev_get_drvdata(dev->parent);
345 ctx_drvdata = dev_get_drvdata(dev);
346 ctx_dev = dev->platform_data;
347
348 if (!iommu_drvdata || !ctx_drvdata || !ctx_dev)
349 goto fail;
350
351 ret = __flush_iotlb(domain); 376 ret = __flush_iotlb(domain);
352 if (ret) 377 if (ret)
353 goto fail; 378 goto fail;
354 379
355 ret = __enable_clocks(iommu_drvdata); 380 list_for_each_entry(iommu, &priv->list_attached, dom_node) {
356 if (ret) 381 ret = __enable_clocks(iommu);
357 goto fail; 382 if (ret)
358 383 goto fail;
359 __reset_context(iommu_drvdata->base, ctx_dev->num);
360 __disable_clocks(iommu_drvdata);
361 list_del_init(&ctx_drvdata->attached_elm);
362 384
385 list_for_each_entry(master, &iommu->ctx_list, list) {
386 msm_iommu_free_ctx(iommu->context_map, master->num);
387 __reset_context(iommu->base, master->num);
388 }
389 __disable_clocks(iommu);
390 }
363fail: 391fail:
364 spin_unlock_irqrestore(&msm_iommu_lock, flags); 392 spin_unlock_irqrestore(&msm_iommu_lock, flags);
365} 393}
@@ -555,47 +583,46 @@ static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
555 dma_addr_t va) 583 dma_addr_t va)
556{ 584{
557 struct msm_priv *priv; 585 struct msm_priv *priv;
558 struct msm_iommu_drvdata *iommu_drvdata; 586 struct msm_iommu_dev *iommu;
559 struct msm_iommu_ctx_drvdata *ctx_drvdata; 587 struct msm_iommu_ctx_dev *master;
560 unsigned int par; 588 unsigned int par;
561 unsigned long flags; 589 unsigned long flags;
562 void __iomem *base;
563 phys_addr_t ret = 0; 590 phys_addr_t ret = 0;
564 int ctx;
565 591
566 spin_lock_irqsave(&msm_iommu_lock, flags); 592 spin_lock_irqsave(&msm_iommu_lock, flags);
567 593
568 priv = to_msm_priv(domain); 594 priv = to_msm_priv(domain);
569 if (list_empty(&priv->list_attached)) 595 iommu = list_first_entry(&priv->list_attached,
570 goto fail; 596 struct msm_iommu_dev, dom_node);
571 597
572 ctx_drvdata = list_entry(priv->list_attached.next, 598 if (list_empty(&iommu->ctx_list))
573 struct msm_iommu_ctx_drvdata, attached_elm); 599 goto fail;
574 iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
575 600
576 base = iommu_drvdata->base; 601 master = list_first_entry(&iommu->ctx_list,
577 ctx = ctx_drvdata->num; 602 struct msm_iommu_ctx_dev, list);
603 if (!master)
604 goto fail;
578 605
579 ret = __enable_clocks(iommu_drvdata); 606 ret = __enable_clocks(iommu);
580 if (ret) 607 if (ret)
581 goto fail; 608 goto fail;
582 609
583 /* Invalidate context TLB */ 610 /* Invalidate context TLB */
584 SET_CTX_TLBIALL(base, ctx, 0); 611 SET_CTX_TLBIALL(iommu->base, master->num, 0);
585 SET_V2PPR(base, ctx, va & V2Pxx_VA); 612 SET_V2PPR(iommu->base, master->num, va & V2Pxx_VA);
586 613
587 par = GET_PAR(base, ctx); 614 par = GET_PAR(iommu->base, master->num);
588 615
589 /* We are dealing with a supersection */ 616 /* We are dealing with a supersection */
590 if (GET_NOFAULT_SS(base, ctx)) 617 if (GET_NOFAULT_SS(iommu->base, master->num))
591 ret = (par & 0xFF000000) | (va & 0x00FFFFFF); 618 ret = (par & 0xFF000000) | (va & 0x00FFFFFF);
592 else /* Upper 20 bits from PAR, lower 12 from VA */ 619 else /* Upper 20 bits from PAR, lower 12 from VA */
593 ret = (par & 0xFFFFF000) | (va & 0x00000FFF); 620 ret = (par & 0xFFFFF000) | (va & 0x00000FFF);
594 621
595 if (GET_FAULT(base, ctx)) 622 if (GET_FAULT(iommu->base, master->num))
596 ret = 0; 623 ret = 0;
597 624
598 __disable_clocks(iommu_drvdata); 625 __disable_clocks(iommu);
599fail: 626fail:
600 spin_unlock_irqrestore(&msm_iommu_lock, flags); 627 spin_unlock_irqrestore(&msm_iommu_lock, flags);
601 return ret; 628 return ret;
@@ -635,37 +662,34 @@ static void print_ctx_regs(void __iomem *base, int ctx)
635 662
636irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id) 663irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
637{ 664{
638 struct msm_iommu_drvdata *drvdata = dev_id; 665 struct msm_iommu_dev *iommu = dev_id;
639 void __iomem *base;
640 unsigned int fsr; 666 unsigned int fsr;
641 int i, ret; 667 int i, ret;
642 668
643 spin_lock(&msm_iommu_lock); 669 spin_lock(&msm_iommu_lock);
644 670
645 if (!drvdata) { 671 if (!iommu) {
646 pr_err("Invalid device ID in context interrupt handler\n"); 672 pr_err("Invalid device ID in context interrupt handler\n");
647 goto fail; 673 goto fail;
648 } 674 }
649 675
650 base = drvdata->base;
651
652 pr_err("Unexpected IOMMU page fault!\n"); 676 pr_err("Unexpected IOMMU page fault!\n");
653 pr_err("base = %08x\n", (unsigned int) base); 677 pr_err("base = %08x\n", (unsigned int)iommu->base);
654 678
655 ret = __enable_clocks(drvdata); 679 ret = __enable_clocks(iommu);
656 if (ret) 680 if (ret)
657 goto fail; 681 goto fail;
658 682
659 for (i = 0; i < drvdata->ncb; i++) { 683 for (i = 0; i < iommu->ncb; i++) {
660 fsr = GET_FSR(base, i); 684 fsr = GET_FSR(iommu->base, i);
661 if (fsr) { 685 if (fsr) {
662 pr_err("Fault occurred in context %d.\n", i); 686 pr_err("Fault occurred in context %d.\n", i);
663 pr_err("Interesting registers:\n"); 687 pr_err("Interesting registers:\n");
664 print_ctx_regs(base, i); 688 print_ctx_regs(iommu->base, i);
665 SET_FSR(base, i, 0x4000000F); 689 SET_FSR(iommu->base, i, 0x4000000F);
666 } 690 }
667 } 691 }
668 __disable_clocks(drvdata); 692 __disable_clocks(iommu);
669fail: 693fail:
670 spin_unlock(&msm_iommu_lock); 694 spin_unlock(&msm_iommu_lock);
671 return 0; 695 return 0;
diff --git a/drivers/iommu/msm_iommu.h b/drivers/iommu/msm_iommu.h
index 5c7c955e6d25..4ca25d50d679 100644
--- a/drivers/iommu/msm_iommu.h
+++ b/drivers/iommu/msm_iommu.h
@@ -42,74 +42,53 @@
42 */ 42 */
43#define MAX_NUM_MIDS 32 43#define MAX_NUM_MIDS 32
44 44
45/* Maximum number of context banks that can be present in IOMMU */
46#define IOMMU_MAX_CBS 128
47
45/** 48/**
46 * struct msm_iommu_dev - a single IOMMU hardware instance 49 * struct msm_iommu_dev - a single IOMMU hardware instance
47 * name Human-readable name given to this IOMMU HW instance
48 * ncb Number of context banks present on this IOMMU HW instance 50 * ncb Number of context banks present on this IOMMU HW instance
51 * dev: IOMMU device
52 * irq: Interrupt number
53 * clk: The bus clock for this IOMMU hardware instance
54 * pclk: The clock for the IOMMU bus interconnect
55 * dev_node: list head in qcom_iommu_device_list
56 * dom_node: list head for domain
57 * ctx_list: list of 'struct msm_iommu_ctx_dev'
58 * context_map: Bitmap to track allocated context banks
49 */ 59 */
50struct msm_iommu_dev { 60struct msm_iommu_dev {
51 const char *name; 61 void __iomem *base;
52 int ncb; 62 int ncb;
63 struct device *dev;
64 int irq;
65 struct clk *clk;
66 struct clk *pclk;
67 struct list_head dev_node;
68 struct list_head dom_node;
69 struct list_head ctx_list;
70 DECLARE_BITMAP(context_map, IOMMU_MAX_CBS);
53}; 71};
54 72
55/** 73/**
56 * struct msm_iommu_ctx_dev - an IOMMU context bank instance 74 * struct msm_iommu_ctx_dev - an IOMMU context bank instance
57 * name Human-readable name given to this context bank 75 * of_node node ptr of client device
58 * num Index of this context bank within the hardware 76 * num Index of this context bank within the hardware
59 * mids List of Machine IDs that are to be mapped into this context 77 * mids List of Machine IDs that are to be mapped into this context
60 * bank, terminated by -1. The MID is a set of signals on the 78 * bank, terminated by -1. The MID is a set of signals on the
61 * AXI bus that identifies the function associated with a specific 79 * AXI bus that identifies the function associated with a specific
62 * memory request. (See ARM spec). 80 * memory request. (See ARM spec).
81 * num_mids Total number of mids
82 * node list head in ctx_list
63 */ 83 */
64struct msm_iommu_ctx_dev { 84struct msm_iommu_ctx_dev {
65 const char *name; 85 struct device_node *of_node;
66 int num; 86 int num;
67 int mids[MAX_NUM_MIDS]; 87 int mids[MAX_NUM_MIDS];
88 int num_mids;
89 struct list_head list;
68}; 90};
69 91
70
71/**
72 * struct msm_iommu_drvdata - A single IOMMU hardware instance
73 * @base: IOMMU config port base address (VA)
74 * @ncb The number of contexts on this IOMMU
75 * @irq: Interrupt number
76 * @clk: The bus clock for this IOMMU hardware instance
77 * @pclk: The clock for the IOMMU bus interconnect
78 *
79 * A msm_iommu_drvdata holds the global driver data about a single piece
80 * of an IOMMU hardware instance.
81 */
82struct msm_iommu_drvdata {
83 void __iomem *base;
84 int irq;
85 int ncb;
86 struct clk *clk;
87 struct clk *pclk;
88};
89
90/**
91 * struct msm_iommu_ctx_drvdata - an IOMMU context bank instance
92 * @num: Hardware context number of this context
93 * @pdev: Platform device associated wit this HW instance
94 * @attached_elm: List element for domains to track which devices are
95 * attached to them
96 *
97 * A msm_iommu_ctx_drvdata holds the driver data for a single context bank
98 * within each IOMMU hardware instance
99 */
100struct msm_iommu_ctx_drvdata {
101 int num;
102 struct platform_device *pdev;
103 struct list_head attached_elm;
104};
105
106/*
107 * Look up an IOMMU context device by its context name. NULL if none found.
108 * Useful for testing and drivers that do not yet fully have IOMMU stuff in
109 * their platform devices.
110 */
111struct device *msm_iommu_get_ctx(const char *ctx_name);
112
113/* 92/*
114 * Interrupt handler for the IOMMU context fault interrupt. Hooking the 93 * Interrupt handler for the IOMMU context fault interrupt. Hooking the
115 * interrupt is not supported in the API yet, but this will print an error 94 * interrupt is not supported in the API yet, but this will print an error
diff --git a/drivers/iommu/msm_iommu_dev.c b/drivers/iommu/msm_iommu_dev.c
index 4b09e815accf..be01cc47c285 100644
--- a/drivers/iommu/msm_iommu_dev.c
+++ b/drivers/iommu/msm_iommu_dev.c
@@ -30,60 +30,6 @@
30#include "msm_iommu_hw-8xxx.h" 30#include "msm_iommu_hw-8xxx.h"
31#include "msm_iommu.h" 31#include "msm_iommu.h"
32 32
33struct iommu_ctx_iter_data {
34 /* input */
35 const char *name;
36
37 /* output */
38 struct device *dev;
39};
40
41static struct platform_device *msm_iommu_root_dev;
42
43static int each_iommu_ctx(struct device *dev, void *data)
44{
45 struct iommu_ctx_iter_data *res = data;
46 struct msm_iommu_ctx_dev *c = dev->platform_data;
47
48 if (!res || !c || !c->name || !res->name)
49 return -EINVAL;
50
51 if (!strcmp(res->name, c->name)) {
52 res->dev = dev;
53 return 1;
54 }
55 return 0;
56}
57
58static int each_iommu(struct device *dev, void *data)
59{
60 return device_for_each_child(dev, data, each_iommu_ctx);
61}
62
63struct device *msm_iommu_get_ctx(const char *ctx_name)
64{
65 struct iommu_ctx_iter_data r;
66 int found;
67
68 if (!msm_iommu_root_dev) {
69 pr_err("No root IOMMU device.\n");
70 goto fail;
71 }
72
73 r.name = ctx_name;
74 found = device_for_each_child(&msm_iommu_root_dev->dev, &r, each_iommu);
75
76 if (!found) {
77 pr_err("Could not find context <%s>\n", ctx_name);
78 goto fail;
79 }
80
81 return r.dev;
82fail:
83 return NULL;
84}
85EXPORT_SYMBOL(msm_iommu_get_ctx);
86
87static void msm_iommu_reset(void __iomem *base, int ncb) 33static void msm_iommu_reset(void __iomem *base, int ncb)
88{ 34{
89 int ctx; 35 int ctx;
@@ -128,237 +74,122 @@ static void msm_iommu_reset(void __iomem *base, int ncb)
128static int msm_iommu_probe(struct platform_device *pdev) 74static int msm_iommu_probe(struct platform_device *pdev)
129{ 75{
130 struct resource *r; 76 struct resource *r;
131 struct clk *iommu_clk; 77 struct msm_iommu_dev *iommu;
132 struct clk *iommu_pclk; 78 int ret, par, val;
133 struct msm_iommu_drvdata *drvdata;
134 struct msm_iommu_dev *iommu_dev = dev_get_platdata(&pdev->dev);
135 void __iomem *regs_base;
136 int ret, irq, par;
137 79
138 if (pdev->id == -1) { 80 iommu = devm_kzalloc(&pdev->dev, sizeof(*iommu), GFP_KERNEL);
139 msm_iommu_root_dev = pdev; 81 if (!iommu)
140 return 0; 82 return -ENODEV;
141 }
142 83
143 drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL); 84 iommu->dev = &pdev->dev;
85 INIT_LIST_HEAD(&iommu->ctx_list);
144 86
145 if (!drvdata) { 87 iommu->pclk = devm_clk_get(iommu->dev, "smmu_pclk");
146 ret = -ENOMEM; 88 if (IS_ERR(iommu->pclk)) {
147 goto fail; 89 dev_err(iommu->dev, "could not get smmu_pclk\n");
90 return PTR_ERR(iommu->pclk);
148 } 91 }
149 92
150 if (!iommu_dev) { 93 ret = clk_prepare(iommu->pclk);
151 ret = -ENODEV; 94 if (ret) {
152 goto fail; 95 dev_err(iommu->dev, "could not prepare smmu_pclk\n");
96 return ret;
153 } 97 }
154 98
155 iommu_pclk = clk_get(NULL, "smmu_pclk"); 99 iommu->clk = devm_clk_get(iommu->dev, "iommu_clk");
156 if (IS_ERR(iommu_pclk)) { 100 if (IS_ERR(iommu->clk)) {
157 ret = -ENODEV; 101 dev_err(iommu->dev, "could not get iommu_clk\n");
158 goto fail; 102 clk_unprepare(iommu->pclk);
103 return PTR_ERR(iommu->clk);
159 } 104 }
160 105
161 ret = clk_prepare_enable(iommu_pclk); 106 ret = clk_prepare(iommu->clk);
162 if (ret) 107 if (ret) {
163 goto fail_enable; 108 dev_err(iommu->dev, "could not prepare iommu_clk\n");
164 109 clk_unprepare(iommu->pclk);
165 iommu_clk = clk_get(&pdev->dev, "iommu_clk"); 110 return ret;
166 111 }
167 if (!IS_ERR(iommu_clk)) {
168 if (clk_get_rate(iommu_clk) == 0)
169 clk_set_rate(iommu_clk, 1);
170
171 ret = clk_prepare_enable(iommu_clk);
172 if (ret) {
173 clk_put(iommu_clk);
174 goto fail_pclk;
175 }
176 } else
177 iommu_clk = NULL;
178 112
179 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "physbase"); 113 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
180 regs_base = devm_ioremap_resource(&pdev->dev, r); 114 iommu->base = devm_ioremap_resource(iommu->dev, r);
181 if (IS_ERR(regs_base)) { 115 if (IS_ERR(iommu->base)) {
182 ret = PTR_ERR(regs_base); 116 dev_err(iommu->dev, "could not get iommu base\n");
183 goto fail_clk; 117 ret = PTR_ERR(iommu->base);
118 goto fail;
184 } 119 }
185 120
186 irq = platform_get_irq_byname(pdev, "secure_irq"); 121 iommu->irq = platform_get_irq(pdev, 0);
187 if (irq < 0) { 122 if (iommu->irq < 0) {
123 dev_err(iommu->dev, "could not get iommu irq\n");
188 ret = -ENODEV; 124 ret = -ENODEV;
189 goto fail_clk; 125 goto fail;
190 } 126 }
191 127
192 msm_iommu_reset(regs_base, iommu_dev->ncb); 128 ret = of_property_read_u32(iommu->dev->of_node, "ncb", &val);
129 if (ret) {
130 dev_err(iommu->dev, "could not get ncb\n");
131 goto fail;
132 }
133 iommu->ncb = val;
193 134
194 SET_M(regs_base, 0, 1); 135 msm_iommu_reset(iommu->base, iommu->ncb);
195 SET_PAR(regs_base, 0, 0); 136 SET_M(iommu->base, 0, 1);
196 SET_V2PCFG(regs_base, 0, 1); 137 SET_PAR(iommu->base, 0, 0);
197 SET_V2PPR(regs_base, 0, 0); 138 SET_V2PCFG(iommu->base, 0, 1);
198 par = GET_PAR(regs_base, 0); 139 SET_V2PPR(iommu->base, 0, 0);
199 SET_V2PCFG(regs_base, 0, 0); 140 par = GET_PAR(iommu->base, 0);
200 SET_M(regs_base, 0, 0); 141 SET_V2PCFG(iommu->base, 0, 0);
142 SET_M(iommu->base, 0, 0);
201 143
202 if (!par) { 144 if (!par) {
203 pr_err("%s: Invalid PAR value detected\n", iommu_dev->name); 145 pr_err("Invalid PAR value detected\n");
204 ret = -ENODEV; 146 ret = -ENODEV;
205 goto fail_clk; 147 goto fail;
206 } 148 }
207 149
208 ret = request_irq(irq, msm_iommu_fault_handler, 0, 150 ret = devm_request_threaded_irq(iommu->dev, iommu->irq, NULL,
209 "msm_iommu_secure_irpt_handler", drvdata); 151 msm_iommu_fault_handler,
152 IRQF_ONESHOT | IRQF_SHARED,
153 "msm_iommu_secure_irpt_handler",
154 iommu);
210 if (ret) { 155 if (ret) {
211 pr_err("Request IRQ %d failed with ret=%d\n", irq, ret); 156 pr_err("Request IRQ %d failed with ret=%d\n", iommu->irq, ret);
212 goto fail_clk; 157 goto fail;
213 } 158 }
214 159
160 list_add(&iommu->dev_node, &qcom_iommu_devices);
215 161
216 drvdata->pclk = iommu_pclk; 162 pr_info("device mapped at %p, irq %d with %d ctx banks\n",
217 drvdata->clk = iommu_clk; 163 iommu->base, iommu->irq, iommu->ncb);
218 drvdata->base = regs_base;
219 drvdata->irq = irq;
220 drvdata->ncb = iommu_dev->ncb;
221
222 pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
223 iommu_dev->name, regs_base, irq, iommu_dev->ncb);
224
225 platform_set_drvdata(pdev, drvdata);
226
227 clk_disable(iommu_clk);
228
229 clk_disable(iommu_pclk);
230
231 return 0;
232fail_clk:
233 if (iommu_clk) {
234 clk_disable(iommu_clk);
235 clk_put(iommu_clk);
236 }
237fail_pclk:
238 clk_disable_unprepare(iommu_pclk);
239fail_enable:
240 clk_put(iommu_pclk);
241fail: 164fail:
242 kfree(drvdata); 165 clk_unprepare(iommu->clk);
166 clk_unprepare(iommu->pclk);
243 return ret; 167 return ret;
244} 168}
245 169
170static const struct of_device_id msm_iommu_dt_match[] = {
171 { .compatible = "qcom,apq8064-iommu" },
172 {}
173};
174
246static int msm_iommu_remove(struct platform_device *pdev) 175static int msm_iommu_remove(struct platform_device *pdev)
247{ 176{
248 struct msm_iommu_drvdata *drv = NULL; 177 struct msm_iommu_dev *iommu = platform_get_drvdata(pdev);
249 178
250 drv = platform_get_drvdata(pdev); 179 clk_unprepare(iommu->clk);
251 if (drv) { 180 clk_unprepare(iommu->pclk);
252 if (drv->clk) {
253 clk_unprepare(drv->clk);
254 clk_put(drv->clk);
255 }
256 clk_unprepare(drv->pclk);
257 clk_put(drv->pclk);
258 memset(drv, 0, sizeof(*drv));
259 kfree(drv);
260 }
261 return 0;
262}
263
264static int msm_iommu_ctx_probe(struct platform_device *pdev)
265{
266 struct msm_iommu_ctx_dev *c = dev_get_platdata(&pdev->dev);
267 struct msm_iommu_drvdata *drvdata;
268 struct msm_iommu_ctx_drvdata *ctx_drvdata;
269 int i, ret;
270
271 if (!c || !pdev->dev.parent)
272 return -EINVAL;
273
274 drvdata = dev_get_drvdata(pdev->dev.parent);
275 if (!drvdata)
276 return -ENODEV;
277
278 ctx_drvdata = kzalloc(sizeof(*ctx_drvdata), GFP_KERNEL);
279 if (!ctx_drvdata)
280 return -ENOMEM;
281
282 ctx_drvdata->num = c->num;
283 ctx_drvdata->pdev = pdev;
284
285 INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
286 platform_set_drvdata(pdev, ctx_drvdata);
287
288 ret = clk_prepare_enable(drvdata->pclk);
289 if (ret)
290 goto fail;
291
292 if (drvdata->clk) {
293 ret = clk_prepare_enable(drvdata->clk);
294 if (ret) {
295 clk_disable_unprepare(drvdata->pclk);
296 goto fail;
297 }
298 }
299
300 /* Program the M2V tables for this context */
301 for (i = 0; i < MAX_NUM_MIDS; i++) {
302 int mid = c->mids[i];
303 if (mid == -1)
304 break;
305
306 SET_M2VCBR_N(drvdata->base, mid, 0);
307 SET_CBACR_N(drvdata->base, c->num, 0);
308
309 /* Set VMID = 0 */
310 SET_VMID(drvdata->base, mid, 0);
311
312 /* Set the context number for that MID to this context */
313 SET_CBNDX(drvdata->base, mid, c->num);
314
315 /* Set MID associated with this context bank to 0*/
316 SET_CBVMID(drvdata->base, c->num, 0);
317
318 /* Set the ASID for TLB tagging for this context */
319 SET_CONTEXTIDR_ASID(drvdata->base, c->num, c->num);
320
321 /* Set security bit override to be Non-secure */
322 SET_NSCFG(drvdata->base, mid, 3);
323 }
324
325 clk_disable(drvdata->clk);
326 clk_disable(drvdata->pclk);
327
328 dev_info(&pdev->dev, "context %s using bank %d\n", c->name, c->num);
329 return 0;
330fail:
331 kfree(ctx_drvdata);
332 return ret;
333}
334
335static int msm_iommu_ctx_remove(struct platform_device *pdev)
336{
337 struct msm_iommu_ctx_drvdata *drv = NULL;
338 drv = platform_get_drvdata(pdev);
339 if (drv) {
340 memset(drv, 0, sizeof(struct msm_iommu_ctx_drvdata));
341 kfree(drv);
342 }
343 return 0; 181 return 0;
344} 182}
345 183
346static struct platform_driver msm_iommu_driver = { 184static struct platform_driver msm_iommu_driver = {
347 .driver = { 185 .driver = {
348 .name = "msm_iommu", 186 .name = "msm_iommu",
187 .of_match_table = msm_iommu_dt_match,
349 }, 188 },
350 .probe = msm_iommu_probe, 189 .probe = msm_iommu_probe,
351 .remove = msm_iommu_remove, 190 .remove = msm_iommu_remove,
352}; 191};
353 192
354static struct platform_driver msm_iommu_ctx_driver = {
355 .driver = {
356 .name = "msm_iommu_ctx",
357 },
358 .probe = msm_iommu_ctx_probe,
359 .remove = msm_iommu_ctx_remove,
360};
361
362static struct platform_driver * const drivers[] = { 193static struct platform_driver * const drivers[] = {
363 &msm_iommu_driver, 194 &msm_iommu_driver,
364 &msm_iommu_ctx_driver, 195 &msm_iommu_ctx_driver,