diff options
author | Magnus Damm <damm+renesas@opensource.se> | 2017-10-16 08:30:18 -0400 |
---|---|---|
committer | Alex Williamson <alex.williamson@redhat.com> | 2017-11-06 12:29:39 -0500 |
commit | d574893aee991efa67fefa849347c49de5df8108 (patch) | |
tree | a3f7280771139668021b51b0c6a18f67dfb5671a /drivers/iommu | |
parent | 1c894225bf5b1cdffac0c6ef935b61273203d7d5 (diff) |
iommu/ipmmu-vmsa: Write IMCTR twice
Write IMCTR both in the root device and the leaf node.
To allow access of IMCTR introduce the following function:
- ipmmu_ctx_write_all()
While at it also rename context functions:
- ipmmu_ctx_read() -> ipmmu_ctx_read_root()
- ipmmu_ctx_write() -> ipmmu_ctx_write_root()
Signed-off-by: Magnus Damm <damm+renesas@opensource.se>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/ipmmu-vmsa.c | 56 |
1 files changed, 35 insertions, 21 deletions
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index 6b74ec62f4b4..7587017972b0 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c | |||
@@ -248,19 +248,31 @@ static void ipmmu_write(struct ipmmu_vmsa_device *mmu, unsigned int offset, | |||
248 | iowrite32(data, mmu->base + offset); | 248 | iowrite32(data, mmu->base + offset); |
249 | } | 249 | } |
250 | 250 | ||
251 | static u32 ipmmu_ctx_read(struct ipmmu_vmsa_domain *domain, unsigned int reg) | 251 | static u32 ipmmu_ctx_read_root(struct ipmmu_vmsa_domain *domain, |
252 | unsigned int reg) | ||
252 | { | 253 | { |
253 | return ipmmu_read(domain->mmu->root, | 254 | return ipmmu_read(domain->mmu->root, |
254 | domain->context_id * IM_CTX_SIZE + reg); | 255 | domain->context_id * IM_CTX_SIZE + reg); |
255 | } | 256 | } |
256 | 257 | ||
257 | static void ipmmu_ctx_write(struct ipmmu_vmsa_domain *domain, unsigned int reg, | 258 | static void ipmmu_ctx_write_root(struct ipmmu_vmsa_domain *domain, |
258 | u32 data) | 259 | unsigned int reg, u32 data) |
259 | { | 260 | { |
260 | ipmmu_write(domain->mmu->root, | 261 | ipmmu_write(domain->mmu->root, |
261 | domain->context_id * IM_CTX_SIZE + reg, data); | 262 | domain->context_id * IM_CTX_SIZE + reg, data); |
262 | } | 263 | } |
263 | 264 | ||
265 | static void ipmmu_ctx_write_all(struct ipmmu_vmsa_domain *domain, | ||
266 | unsigned int reg, u32 data) | ||
267 | { | ||
268 | if (domain->mmu != domain->mmu->root) | ||
269 | ipmmu_write(domain->mmu, | ||
270 | domain->context_id * IM_CTX_SIZE + reg, data); | ||
271 | |||
272 | ipmmu_write(domain->mmu->root, | ||
273 | domain->context_id * IM_CTX_SIZE + reg, data); | ||
274 | } | ||
275 | |||
264 | /* ----------------------------------------------------------------------------- | 276 | /* ----------------------------------------------------------------------------- |
265 | * TLB and microTLB Management | 277 | * TLB and microTLB Management |
266 | */ | 278 | */ |
@@ -270,7 +282,7 @@ static void ipmmu_tlb_sync(struct ipmmu_vmsa_domain *domain) | |||
270 | { | 282 | { |
271 | unsigned int count = 0; | 283 | unsigned int count = 0; |
272 | 284 | ||
273 | while (ipmmu_ctx_read(domain, IMCTR) & IMCTR_FLUSH) { | 285 | while (ipmmu_ctx_read_root(domain, IMCTR) & IMCTR_FLUSH) { |
274 | cpu_relax(); | 286 | cpu_relax(); |
275 | if (++count == TLB_LOOP_TIMEOUT) { | 287 | if (++count == TLB_LOOP_TIMEOUT) { |
276 | dev_err_ratelimited(domain->mmu->dev, | 288 | dev_err_ratelimited(domain->mmu->dev, |
@@ -285,9 +297,9 @@ static void ipmmu_tlb_invalidate(struct ipmmu_vmsa_domain *domain) | |||
285 | { | 297 | { |
286 | u32 reg; | 298 | u32 reg; |
287 | 299 | ||
288 | reg = ipmmu_ctx_read(domain, IMCTR); | 300 | reg = ipmmu_ctx_read_root(domain, IMCTR); |
289 | reg |= IMCTR_FLUSH; | 301 | reg |= IMCTR_FLUSH; |
290 | ipmmu_ctx_write(domain, IMCTR, reg); | 302 | ipmmu_ctx_write_all(domain, IMCTR, reg); |
291 | 303 | ||
292 | ipmmu_tlb_sync(domain); | 304 | ipmmu_tlb_sync(domain); |
293 | } | 305 | } |
@@ -428,31 +440,32 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) | |||
428 | 440 | ||
429 | /* TTBR0 */ | 441 | /* TTBR0 */ |
430 | ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0]; | 442 | ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0]; |
431 | ipmmu_ctx_write(domain, IMTTLBR0, ttbr); | 443 | ipmmu_ctx_write_root(domain, IMTTLBR0, ttbr); |
432 | ipmmu_ctx_write(domain, IMTTUBR0, ttbr >> 32); | 444 | ipmmu_ctx_write_root(domain, IMTTUBR0, ttbr >> 32); |
433 | 445 | ||
434 | /* | 446 | /* |
435 | * TTBCR | 447 | * TTBCR |
436 | * We use long descriptors with inner-shareable WBWA tables and allocate | 448 | * We use long descriptors with inner-shareable WBWA tables and allocate |
437 | * the whole 32-bit VA space to TTBR0. | 449 | * the whole 32-bit VA space to TTBR0. |
438 | */ | 450 | */ |
439 | ipmmu_ctx_write(domain, IMTTBCR, IMTTBCR_EAE | | 451 | ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE | |
440 | IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | | 452 | IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA | |
441 | IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1); | 453 | IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1); |
442 | 454 | ||
443 | /* MAIR0 */ | 455 | /* MAIR0 */ |
444 | ipmmu_ctx_write(domain, IMMAIR0, domain->cfg.arm_lpae_s1_cfg.mair[0]); | 456 | ipmmu_ctx_write_root(domain, IMMAIR0, |
457 | domain->cfg.arm_lpae_s1_cfg.mair[0]); | ||
445 | 458 | ||
446 | /* IMBUSCR */ | 459 | /* IMBUSCR */ |
447 | ipmmu_ctx_write(domain, IMBUSCR, | 460 | ipmmu_ctx_write_root(domain, IMBUSCR, |
448 | ipmmu_ctx_read(domain, IMBUSCR) & | 461 | ipmmu_ctx_read_root(domain, IMBUSCR) & |
449 | ~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); | 462 | ~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK)); |
450 | 463 | ||
451 | /* | 464 | /* |
452 | * IMSTR | 465 | * IMSTR |
453 | * Clear all interrupt flags. | 466 | * Clear all interrupt flags. |
454 | */ | 467 | */ |
455 | ipmmu_ctx_write(domain, IMSTR, ipmmu_ctx_read(domain, IMSTR)); | 468 | ipmmu_ctx_write_root(domain, IMSTR, ipmmu_ctx_read_root(domain, IMSTR)); |
456 | 469 | ||
457 | /* | 470 | /* |
458 | * IMCTR | 471 | * IMCTR |
@@ -461,7 +474,8 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) | |||
461 | * software management as we have no use for it. Flush the TLB as | 474 | * software management as we have no use for it. Flush the TLB as |
462 | * required when modifying the context registers. | 475 | * required when modifying the context registers. |
463 | */ | 476 | */ |
464 | ipmmu_ctx_write(domain, IMCTR, IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN); | 477 | ipmmu_ctx_write_all(domain, IMCTR, |
478 | IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN); | ||
465 | 479 | ||
466 | return 0; | 480 | return 0; |
467 | } | 481 | } |
@@ -474,7 +488,7 @@ static void ipmmu_domain_destroy_context(struct ipmmu_vmsa_domain *domain) | |||
474 | * | 488 | * |
475 | * TODO: Is TLB flush really needed ? | 489 | * TODO: Is TLB flush really needed ? |
476 | */ | 490 | */ |
477 | ipmmu_ctx_write(domain, IMCTR, IMCTR_FLUSH); | 491 | ipmmu_ctx_write_all(domain, IMCTR, IMCTR_FLUSH); |
478 | ipmmu_tlb_sync(domain); | 492 | ipmmu_tlb_sync(domain); |
479 | ipmmu_domain_free_context(domain->mmu->root, domain->context_id); | 493 | ipmmu_domain_free_context(domain->mmu->root, domain->context_id); |
480 | } | 494 | } |
@@ -490,11 +504,11 @@ static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain) | |||
490 | u32 status; | 504 | u32 status; |
491 | u32 iova; | 505 | u32 iova; |
492 | 506 | ||
493 | status = ipmmu_ctx_read(domain, IMSTR); | 507 | status = ipmmu_ctx_read_root(domain, IMSTR); |
494 | if (!(status & err_mask)) | 508 | if (!(status & err_mask)) |
495 | return IRQ_NONE; | 509 | return IRQ_NONE; |
496 | 510 | ||
497 | iova = ipmmu_ctx_read(domain, IMEAR); | 511 | iova = ipmmu_ctx_read_root(domain, IMEAR); |
498 | 512 | ||
499 | /* | 513 | /* |
500 | * Clear the error status flags. Unlike traditional interrupt flag | 514 | * Clear the error status flags. Unlike traditional interrupt flag |
@@ -502,7 +516,7 @@ static irqreturn_t ipmmu_domain_irq(struct ipmmu_vmsa_domain *domain) | |||
502 | * seems to require 0. The error address register must be read before, | 516 | * seems to require 0. The error address register must be read before, |
503 | * otherwise its value will be 0. | 517 | * otherwise its value will be 0. |
504 | */ | 518 | */ |
505 | ipmmu_ctx_write(domain, IMSTR, 0); | 519 | ipmmu_ctx_write_root(domain, IMSTR, 0); |
506 | 520 | ||
507 | /* Log fatal errors. */ | 521 | /* Log fatal errors. */ |
508 | if (status & IMSTR_MHIT) | 522 | if (status & IMSTR_MHIT) |