iommu/amd: Implement function to send PPR completions
Joerg Roedel [Mon, 21 Nov 2011 17:19:25 +0000 (18:19 +0100)]
To send completions for PPR requests this patch adds a
function which can be used by the IOMMUv2 driver.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>

drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_proto.h
drivers/iommu/amd_iommu_types.h

index d513ff5..64638df 100644 (file)
@@ -754,6 +754,22 @@ static void build_inv_iotlb_pasid(struct iommu_cmd *cmd, u16 devid, int pasid,
        CMD_SET_TYPE(cmd, CMD_INV_IOTLB_PAGES);
 }
 
+static void build_complete_ppr(struct iommu_cmd *cmd, u16 devid, int pasid,
+                              int status, int tag, bool gn)
+{
+       memset(cmd, 0, sizeof(*cmd));
+
+       cmd->data[0]  = devid;
+       if (gn) {
+               cmd->data[1]  = pasid & PASID_MASK;
+               cmd->data[2]  = CMD_INV_IOMMU_PAGES_GN_MASK;
+       }
+       cmd->data[3]  = tag & 0x1ff;
+       cmd->data[3] |= (status & PPR_STATUS_MASK) << PPR_STATUS_SHIFT;
+
+       CMD_SET_TYPE(cmd, CMD_COMPLETE_PPR);
+}
+
 static void build_inv_all(struct iommu_cmd *cmd)
 {
        memset(cmd, 0, sizeof(*cmd));
@@ -1968,6 +1984,23 @@ out_err:
        return ret;
 }
 
+/* FIXME: Move this to PCI code */
+#define PCI_PRI_TLP_OFF                (1 << 2)
+
+bool pci_pri_tlp_required(struct pci_dev *pdev)
+{
+       u16 control;
+       int pos;
+
+       pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
+       if (!pos)
+               return false;
+
+       pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
+
+       return (control & PCI_PRI_TLP_OFF) ? true : false;
+}
+
 /*
  * If a device is not yet associated with a domain, this function does
  * assigns it visible for the hardware
@@ -1991,6 +2024,7 @@ static int attach_device(struct device *dev,
 
                dev_data->ats.enabled = true;
                dev_data->ats.qdep    = pci_ats_queue_depth(pdev);
+               dev_data->pri_tlp     = pci_pri_tlp_required(pdev);
        } else if (amd_iommu_iotlb_sup &&
                   pci_enable_ats(pdev, PAGE_SHIFT) == 0) {
                dev_data->ats.enabled = true;
@@ -3449,3 +3483,20 @@ int amd_iommu_domain_clear_gcr3(struct iommu_domain *dom, int pasid)
        return ret;
 }
 EXPORT_SYMBOL(amd_iommu_domain_clear_gcr3);
+
+int amd_iommu_complete_ppr(struct pci_dev *pdev, int pasid,
+                          int status, int tag)
+{
+       struct iommu_dev_data *dev_data;
+       struct amd_iommu *iommu;
+       struct iommu_cmd cmd;
+
+       dev_data = get_dev_data(&pdev->dev);
+       iommu    = amd_iommu_rlookup_table[dev_data->devid];
+
+       build_complete_ppr(&cmd, dev_data->devid, pasid, status,
+                          tag, dev_data->pri_tlp);
+
+       return iommu_queue_command(iommu, &cmd);
+}
+EXPORT_SYMBOL(amd_iommu_complete_ppr);
index a951a70..bb5ecfe 100644 (file)
@@ -47,6 +47,12 @@ extern int amd_iommu_domain_set_gcr3(struct iommu_domain *dom, int pasid,
                                     unsigned long cr3);
 extern int amd_iommu_domain_clear_gcr3(struct iommu_domain *dom, int pasid);
 
+#define PPR_SUCCESS                    0x0
+#define PPR_INVALID                    0x1
+#define PPR_FAILURE                    0xf
+
+extern int amd_iommu_complete_ppr(struct pci_dev *pdev, int pasid,
+                                 int status, int tag);
 
 #ifndef CONFIG_AMD_IOMMU_STATS
 
index 060724e..8e1a646 100644 (file)
 #define CMD_INV_DEV_ENTRY       0x02
 #define CMD_INV_IOMMU_PAGES    0x03
 #define CMD_INV_IOTLB_PAGES    0x04
+#define CMD_COMPLETE_PPR       0x07
 #define CMD_INV_ALL            0x08
 
 #define CMD_COMPL_WAIT_STORE_MASK      0x01
 #define CMD_INV_IOMMU_PAGES_PDE_MASK   0x02
 #define CMD_INV_IOMMU_PAGES_GN_MASK    0x04
 
+#define PPR_STATUS_MASK                        0xf
+#define PPR_STATUS_SHIFT               12
+
 #define CMD_INV_IOMMU_ALL_PAGES_ADDRESS        0x7fffffffffffffffULL
 
 /* macros and definitions for device table entries */
@@ -394,6 +398,8 @@ struct iommu_dev_data {
                bool enabled;
                int qdep;
        } ats;                            /* ATS state */
+       bool pri_tlp;                     /* PASID TLB required for
+                                            PPR completions */
 };
 
 /*