iommu: add support for iotlb shootdowns and write-buffer flushing
authorAditya Basu <mitthu@google.com>
Sat, 17 Aug 2019 01:00:03 +0000 (21:00 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 19 Aug 2019 16:39:09 +0000 (12:39 -0400)
* Add fields to struct iommu which are set during initialization
* Add the necessary functions
* Will also need another function to perform global iotlb flushes
* Also look into Queue Invalidation (QI) for device IOTLBs. Currently we
  do not allow device IOTLBs to be populated. For device IOTLBs we need
  to set the TRANS_TYPE to 0x01.

Signed-off-by: Aditya Basu <mitthu@google.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/intel-iommu.h
kern/drivers/dev/iommu.c

index 008adf8..4706fdc 100644 (file)
@@ -53,7 +53,11 @@ struct iommu {
        TAILQ_ENTRY(iommu) iommu_link;
        struct proc_list procs; // unused
        bool supported;
+       bool device_iotlb;
+       bool rwbf;
 
+       uint16_t iotlb_cmd_offset;
+       uint16_t iotlb_addr_offset;
        void __iomem *regio;
        uint64_t rba; /* for unique assertion */
        uint64_t num_assigned_devs;
index a761795..9ae50fb 100644 (file)
@@ -56,6 +56,46 @@ static struct dirtab iommudir[] = {
        {"power",               {Qpower, 0, QTFILE}, 0, 0755},
 };
 
+/* this is might be necessary when updating mapping structures: context-cache,
+ * IOTLB or IEC. */
+static inline void write_buffer_flush(struct iommu *iommu)
+{
+       uint32_t cmd, status;
+
+       if (!iommu->rwbf)
+               return;
+
+       cmd = read32(iommu->regio + DMAR_GCMD_REG) | DMA_GCMD_WBF;
+       write32(cmd, iommu->regio + DMAR_GCMD_REG);
+
+       /* read status */
+       do {
+               status = read32(iommu->regio + DMAR_GSTS_REG);
+       } while (status & DMA_GSTS_WBFS);
+}
+
+/* this is necessary when caching mode is supported.
+ * ASSUMES: No pending flush requests. This is a problem only if other function
+ * is used to perform the flush. */
+static inline void iotlb_flush(struct iommu *iommu, uint16_t did)
+{
+       uint64_t cmd, status;
+
+       cmd = 0x0
+       | DMA_TLB_IVT        /* issue the flush command */
+       | DMA_TLB_DSI_FLUSH  /* DID specific shootdown */
+       | DMA_TLB_READ_DRAIN
+       | DMA_TLB_WRITE_DRAIN
+       | DMA_TLB_DID(did);
+       write64(cmd, iommu->regio + iommu->iotlb_cmd_offset);
+
+       /* read status */
+       do {
+               status = read64(iommu->regio + iommu->iotlb_cmd_offset);
+               status >>= 63; /* bit 64 (IVT): gets cleared on completion */
+       } while (status);
+}
+
 static inline struct root_entry *get_root_entry(physaddr_t paddr)
 {
        return (struct root_entry *) KADDR(paddr);