#include <asm/irq_remapping.h>
 
+#include "intel-pasid.h"
+
 struct tbl_walk {
        u16 bus;
        u16 devfn;
+       u32 pasid;
        struct root_entry *rt_entry;
        struct context_entry *ctx_entry;
+       struct pasid_entry *pasid_tbl_entry;
 };
 
 struct iommu_regset {
 {
        struct tbl_walk *tbl_wlk = m->private;
 
-       seq_printf(m, "%02x:%02x.%x\t0x%016llx:0x%016llx\t0x%016llx:0x%016llx\n",
+       seq_printf(m, "%02x:%02x.%x\t0x%016llx:0x%016llx\t0x%016llx:0x%016llx\t",
                   tbl_wlk->bus, PCI_SLOT(tbl_wlk->devfn),
                   PCI_FUNC(tbl_wlk->devfn), tbl_wlk->rt_entry->hi,
                   tbl_wlk->rt_entry->lo, tbl_wlk->ctx_entry->hi,
                   tbl_wlk->ctx_entry->lo);
+
+       /*
+        * A legacy mode DMAR doesn't support PASID, hence default it to -1
+        * indicating that it's invalid. Also, default all PASID related fields
+        * to 0.
+        */
+       if (!tbl_wlk->pasid_tbl_entry)
+               seq_printf(m, "%-6d\t0x%016llx:0x%016llx:0x%016llx\n", -1,
+                          (u64)0, (u64)0, (u64)0);
+       else
+               seq_printf(m, "%-6d\t0x%016llx:0x%016llx:0x%016llx\n",
+                          tbl_wlk->pasid, tbl_wlk->pasid_tbl_entry->val[0],
+                          tbl_wlk->pasid_tbl_entry->val[1],
+                          tbl_wlk->pasid_tbl_entry->val[2]);
+}
+
+static void pasid_tbl_walk(struct seq_file *m, struct pasid_entry *tbl_entry,
+                          u16 dir_idx)
+{
+       struct tbl_walk *tbl_wlk = m->private;
+       u8 tbl_idx;
+
+       for (tbl_idx = 0; tbl_idx < PASID_TBL_ENTRIES; tbl_idx++) {
+               if (pasid_pte_is_present(tbl_entry)) {
+                       tbl_wlk->pasid_tbl_entry = tbl_entry;
+                       tbl_wlk->pasid = (dir_idx << PASID_PDE_SHIFT) + tbl_idx;
+                       print_tbl_walk(m);
+               }
+
+               tbl_entry++;
+       }
+}
+
+static void pasid_dir_walk(struct seq_file *m, u64 pasid_dir_ptr,
+                          u16 pasid_dir_size)
+{
+       struct pasid_dir_entry *dir_entry = phys_to_virt(pasid_dir_ptr);
+       struct pasid_entry *pasid_tbl;
+       u16 dir_idx;
+
+       for (dir_idx = 0; dir_idx < pasid_dir_size; dir_idx++) {
+               pasid_tbl = get_pasid_table_from_pde(dir_entry);
+               if (pasid_tbl)
+                       pasid_tbl_walk(m, pasid_tbl, dir_idx);
+
+               dir_entry++;
+       }
 }
 
 static void ctx_tbl_walk(struct seq_file *m, struct intel_iommu *iommu, u16 bus)
 {
        struct context_entry *context;
-       u16 devfn;
+       u16 devfn, pasid_dir_size;
+       u64 pasid_dir_ptr;
 
        for (devfn = 0; devfn < 256; devfn++) {
                struct tbl_walk tbl_wlk = {0};
 
+               /*
+                * Scalable mode root entry points to upper scalable mode
+                * context table and lower scalable mode context table. Each
+                * scalable mode context table has 128 context entries where as
+                * legacy mode context table has 256 context entries. So in
+                * scalable mode, the context entries for former 128 devices are
+                * in the lower scalable mode context table, while the latter
+                * 128 devices are in the upper scalable mode context table.
+                * In scalable mode, when devfn > 127, iommu_context_addr()
+                * automatically refers to upper scalable mode context table and
+                * hence the caller doesn't have to worry about differences
+                * between scalable mode and non scalable mode.
+                */
                context = iommu_context_addr(iommu, bus, devfn, 0);
                if (!context)
                        return;
                tbl_wlk.ctx_entry = context;
                m->private = &tbl_wlk;
 
+               if (pasid_supported(iommu) && is_pasid_enabled(context)) {
+                       pasid_dir_ptr = context->lo & VTD_PAGE_MASK;
+                       pasid_dir_size = get_pasid_dir_size(context);
+                       pasid_dir_walk(m, pasid_dir_ptr, pasid_dir_size);
+                       continue;
+               }
+
                print_tbl_walk(m);
        }
 }
        spin_lock_irqsave(&iommu->lock, flags);
        seq_printf(m, "IOMMU %s: Root Table Address: 0x%llx\n", iommu->name,
                   (u64)virt_to_phys(iommu->root_entry));
-       seq_puts(m, "B.D.F\tRoot_entry\t\t\t\tContext_entry\n");
+       seq_puts(m, "B.D.F\tRoot_entry\t\t\t\tContext_entry\t\t\t\tPASID\tPASID_table_entry\n");
 
        /*
         * No need to check if the root entry is present or not because