diff options
author | Jacob Pan <jacob.jun.pan@linux.intel.com> | 2019-01-11 00:04:57 -0500 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2019-01-11 07:10:03 -0500 |
commit | 5b438f4ba315db4f8c1489d175656798d58c014f (patch) | |
tree | 1938ea40fb86a382601a1bc174e03a0c7f220f68 | |
parent | bfeffd155283772bbe78c6a05dec7c0128ee500c (diff) |
iommu/vt-d: Support page request in scalable mode
VT-d Rev3.0 has made a few changes to the page request interface,
1. widened PRQ descriptor from 128 bits to 256 bits;
2. removed streaming response type;
3. introduced private data that requires page response even the
request is not last request in group (LPIG).
This is a supplement to commit 1c4f88b7f1f92 ("iommu/vt-d: Shared
virtual address in scalable mode") and makes the svm code compliant
with VT-d Rev3.0.
Cc: Ashok Raj <ashok.raj@intel.com>
Cc: Liu Yi L <yi.l.liu@intel.com>
Cc: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
Fixes: 1c4f88b7f1f92 ("iommu/vt-d: Shared virtual address in scalable mode")
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r-- | drivers/iommu/intel-svm.c | 77 | ||||
-rw-r--r-- | include/linux/intel-iommu.h | 21 | ||||
-rw-r--r-- | include/linux/intel-svm.h | 2 |
3 files changed, 55 insertions, 45 deletions
diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index a2a2aa4439aa..79add5716552 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c | |||
@@ -470,20 +470,31 @@ EXPORT_SYMBOL_GPL(intel_svm_is_pasid_valid); | |||
470 | 470 | ||
471 | /* Page request queue descriptor */ | 471 | /* Page request queue descriptor */ |
472 | struct page_req_dsc { | 472 | struct page_req_dsc { |
473 | u64 srr:1; | 473 | union { |
474 | u64 bof:1; | 474 | struct { |
475 | u64 pasid_present:1; | 475 | u64 type:8; |
476 | u64 lpig:1; | 476 | u64 pasid_present:1; |
477 | u64 pasid:20; | 477 | u64 priv_data_present:1; |
478 | u64 bus:8; | 478 | u64 rsvd:6; |
479 | u64 private:23; | 479 | u64 rid:16; |
480 | u64 prg_index:9; | 480 | u64 pasid:20; |
481 | u64 rd_req:1; | 481 | u64 exe_req:1; |
482 | u64 wr_req:1; | 482 | u64 pm_req:1; |
483 | u64 exe_req:1; | 483 | u64 rsvd2:10; |
484 | u64 priv_req:1; | 484 | }; |
485 | u64 devfn:8; | 485 | u64 qw_0; |
486 | u64 addr:52; | 486 | }; |
487 | union { | ||
488 | struct { | ||
489 | u64 rd_req:1; | ||
490 | u64 wr_req:1; | ||
491 | u64 lpig:1; | ||
492 | u64 prg_index:9; | ||
493 | u64 addr:52; | ||
494 | }; | ||
495 | u64 qw_1; | ||
496 | }; | ||
497 | u64 priv_data[2]; | ||
487 | }; | 498 | }; |
488 | 499 | ||
489 | #define PRQ_RING_MASK ((0x1000 << PRQ_ORDER) - 0x10) | 500 | #define PRQ_RING_MASK ((0x1000 << PRQ_ORDER) - 0x10) |
@@ -596,7 +607,7 @@ static irqreturn_t prq_event_thread(int irq, void *d) | |||
596 | /* Accounting for major/minor faults? */ | 607 | /* Accounting for major/minor faults? */ |
597 | rcu_read_lock(); | 608 | rcu_read_lock(); |
598 | list_for_each_entry_rcu(sdev, &svm->devs, list) { | 609 | list_for_each_entry_rcu(sdev, &svm->devs, list) { |
599 | if (sdev->sid == PCI_DEVID(req->bus, req->devfn)) | 610 | if (sdev->sid == req->rid) |
600 | break; | 611 | break; |
601 | } | 612 | } |
602 | /* Other devices can go away, but the drivers are not permitted | 613 | /* Other devices can go away, but the drivers are not permitted |
@@ -609,33 +620,35 @@ static irqreturn_t prq_event_thread(int irq, void *d) | |||
609 | 620 | ||
610 | if (sdev && sdev->ops && sdev->ops->fault_cb) { | 621 | if (sdev && sdev->ops && sdev->ops->fault_cb) { |
611 | int rwxp = (req->rd_req << 3) | (req->wr_req << 2) | | 622 | int rwxp = (req->rd_req << 3) | (req->wr_req << 2) | |
612 | (req->exe_req << 1) | (req->priv_req); | 623 | (req->exe_req << 1) | (req->pm_req); |
613 | sdev->ops->fault_cb(sdev->dev, req->pasid, req->addr, req->private, rwxp, result); | 624 | sdev->ops->fault_cb(sdev->dev, req->pasid, req->addr, |
625 | req->priv_data, rwxp, result); | ||
614 | } | 626 | } |
615 | /* We get here in the error case where the PASID lookup failed, | 627 | /* We get here in the error case where the PASID lookup failed, |
616 | and these can be NULL. Do not use them below this point! */ | 628 | and these can be NULL. Do not use them below this point! */ |
617 | sdev = NULL; | 629 | sdev = NULL; |
618 | svm = NULL; | 630 | svm = NULL; |
619 | no_pasid: | 631 | no_pasid: |
620 | if (req->lpig) { | 632 | if (req->lpig || req->priv_data_present) { |
621 | /* Page Group Response */ | 633 | /* |
634 | * Per VT-d spec. v3.0 ch7.7, system software must | ||
635 | * respond with page group response if private data | ||
636 | * is present (PDP) or last page in group (LPIG) bit | ||
637 | * is set. This is an additional VT-d feature beyond | ||
638 | * PCI ATS spec. | ||
639 | */ | ||
622 | resp.qw0 = QI_PGRP_PASID(req->pasid) | | 640 | resp.qw0 = QI_PGRP_PASID(req->pasid) | |
623 | QI_PGRP_DID((req->bus << 8) | req->devfn) | | 641 | QI_PGRP_DID(req->rid) | |
624 | QI_PGRP_PASID_P(req->pasid_present) | | 642 | QI_PGRP_PASID_P(req->pasid_present) | |
643 | QI_PGRP_PDP(req->pasid_present) | | ||
644 | QI_PGRP_RESP_CODE(result) | | ||
625 | QI_PGRP_RESP_TYPE; | 645 | QI_PGRP_RESP_TYPE; |
626 | resp.qw1 = QI_PGRP_IDX(req->prg_index) | | 646 | resp.qw1 = QI_PGRP_IDX(req->prg_index) | |
627 | QI_PGRP_PRIV(req->private) | | 647 | QI_PGRP_LPIG(req->lpig); |
628 | QI_PGRP_RESP_CODE(result); | 648 | |
629 | } else if (req->srr) { | 649 | if (req->priv_data_present) |
630 | /* Page Stream Response */ | 650 | memcpy(&resp.qw2, req->priv_data, |
631 | resp.qw0 = QI_PSTRM_IDX(req->prg_index) | | 651 | sizeof(req->priv_data)); |
632 | QI_PSTRM_PRIV(req->private) | | ||
633 | QI_PSTRM_BUS(req->bus) | | ||
634 | QI_PSTRM_PASID(req->pasid) | | ||
635 | QI_PSTRM_RESP_TYPE; | ||
636 | resp.qw1 = QI_PSTRM_ADDR(address) | | ||
637 | QI_PSTRM_DEVFN(req->devfn) | | ||
638 | QI_PSTRM_RESP_CODE(result); | ||
639 | } | 652 | } |
640 | resp.qw2 = 0; | 653 | resp.qw2 = 0; |
641 | resp.qw3 = 0; | 654 | resp.qw3 = 0; |
diff --git a/include/linux/intel-iommu.h b/include/linux/intel-iommu.h index 0605f3bf6e79..fa364de9db18 100644 --- a/include/linux/intel-iommu.h +++ b/include/linux/intel-iommu.h | |||
@@ -374,20 +374,17 @@ enum { | |||
374 | #define QI_DEV_EIOTLB_PFSID(pfsid) (((u64)(pfsid & 0xf) << 12) | ((u64)(pfsid & 0xfff) << 52)) | 374 | #define QI_DEV_EIOTLB_PFSID(pfsid) (((u64)(pfsid & 0xf) << 12) | ((u64)(pfsid & 0xfff) << 52)) |
375 | #define QI_DEV_EIOTLB_MAX_INVS 32 | 375 | #define QI_DEV_EIOTLB_MAX_INVS 32 |
376 | 376 | ||
377 | #define QI_PGRP_IDX(idx) (((u64)(idx)) << 55) | 377 | /* Page group response descriptor QW0 */ |
378 | #define QI_PGRP_PRIV(priv) (((u64)(priv)) << 32) | ||
379 | #define QI_PGRP_RESP_CODE(res) ((u64)(res)) | ||
380 | #define QI_PGRP_PASID(pasid) (((u64)(pasid)) << 32) | ||
381 | #define QI_PGRP_DID(did) (((u64)(did)) << 16) | ||
382 | #define QI_PGRP_PASID_P(p) (((u64)(p)) << 4) | 378 | #define QI_PGRP_PASID_P(p) (((u64)(p)) << 4) |
379 | #define QI_PGRP_PDP(p) (((u64)(p)) << 5) | ||
380 | #define QI_PGRP_RESP_CODE(res) (((u64)(res)) << 12) | ||
381 | #define QI_PGRP_DID(rid) (((u64)(rid)) << 16) | ||
382 | #define QI_PGRP_PASID(pasid) (((u64)(pasid)) << 32) | ||
383 | |||
384 | /* Page group response descriptor QW1 */ | ||
385 | #define QI_PGRP_LPIG(x) (((u64)(x)) << 2) | ||
386 | #define QI_PGRP_IDX(idx) (((u64)(idx)) << 3) | ||
383 | 387 | ||
384 | #define QI_PSTRM_ADDR(addr) (((u64)(addr)) & VTD_PAGE_MASK) | ||
385 | #define QI_PSTRM_DEVFN(devfn) (((u64)(devfn)) << 4) | ||
386 | #define QI_PSTRM_RESP_CODE(res) ((u64)(res)) | ||
387 | #define QI_PSTRM_IDX(idx) (((u64)(idx)) << 55) | ||
388 | #define QI_PSTRM_PRIV(priv) (((u64)(priv)) << 32) | ||
389 | #define QI_PSTRM_BUS(bus) (((u64)(bus)) << 24) | ||
390 | #define QI_PSTRM_PASID(pasid) (((u64)(pasid)) << 4) | ||
391 | 388 | ||
392 | #define QI_RESP_SUCCESS 0x0 | 389 | #define QI_RESP_SUCCESS 0x0 |
393 | #define QI_RESP_INVALID 0x1 | 390 | #define QI_RESP_INVALID 0x1 |
diff --git a/include/linux/intel-svm.h b/include/linux/intel-svm.h index 99bc5b3ae26e..e3f76315ca4d 100644 --- a/include/linux/intel-svm.h +++ b/include/linux/intel-svm.h | |||
@@ -20,7 +20,7 @@ struct device; | |||
20 | 20 | ||
21 | struct svm_dev_ops { | 21 | struct svm_dev_ops { |
22 | void (*fault_cb)(struct device *dev, int pasid, u64 address, | 22 | void (*fault_cb)(struct device *dev, int pasid, u64 address, |
23 | u32 private, int rwxp, int response); | 23 | void *private, int rwxp, int response); |
24 | }; | 24 | }; |
25 | 25 | ||
26 | /* Values for rxwp in fault_cb callback */ | 26 | /* Values for rxwp in fault_cb callback */ |