static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs, int num) { int i; struct iotlb_lock saved, l; struct cr_regs *p = crs; clk_enable(obj->clk); iotlb_lock_get(obj, &saved); memcpy(&l, &saved, sizeof(saved)); for (i = 0; i < num; i++) { struct cr_regs tmp; iotlb_lock_get(obj, &l); l.vict = i; iotlb_lock_set(obj, &l); iotlb_read_cr(obj, &tmp); if (!iotlb_cr_valid(&tmp)) continue; *p++ = tmp; } iotlb_lock_set(obj, &saved); clk_disable(obj->clk); return p - crs; }
/** * flush_iotlb_page - Clear an iommu tlb entry * @obj: target iommu * @da: iommu device virtual address * * Clear an iommu tlb entry which includes 'da' address. **/ void flush_iotlb_page(struct iommu *obj, u32 da) { struct iotlb_lock l; int i; clk_enable(obj->clk); for (i = 0; i < obj->nr_tlb_entries; i++) { struct cr_regs cr; u32 start; size_t bytes; iotlb_lock_get(obj, &l); l.vict = i; iotlb_lock_set(obj, &l); iotlb_read_cr(obj, &cr); if (!iotlb_cr_valid(&cr)) continue; start = iotlb_cr_to_virt(&cr); bytes = iopgsz_to_bytes(cr.cam & 3); if ((start <= da) && (da < start + bytes)) { dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n", __func__, start, da, bytes); iotlb_load_cr(obj, &cr); iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY); } } clk_disable(obj->clk); if (i == obj->nr_tlb_entries) dev_dbg(obj->dev, "%s: no page for %08x\n", __func__, da); }
/** * load_iotlb_entry - Set an iommu tlb entry * @obj: target iommu * @e: an iommu tlb entry info **/ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e) { int i; int err = 0; struct iotlb_lock l; struct cr_regs *cr; if (!obj || !obj->nr_tlb_entries || !e) return -EINVAL; clk_enable(obj->clk); for (i = 0; i < obj->nr_tlb_entries; i++) { struct cr_regs tmp; iotlb_lock_get(obj, &l); l.vict = i; iotlb_lock_set(obj, &l); iotlb_read_cr(obj, &tmp); if (!iotlb_cr_valid(&tmp)) break; } if (i == obj->nr_tlb_entries) { dev_dbg(obj->dev, "%s: full: no entry\n", __func__); err = -EBUSY; goto out; } cr = iotlb_alloc_cr(obj, e); if (IS_ERR(cr)) { clk_disable(obj->clk); return PTR_ERR(cr); } iotlb_load_cr(obj, cr); kfree(cr); /* increment victim for next tlb load */ if (++l.vict == obj->nr_tlb_entries) l.vict = 0; iotlb_lock_set(obj, &l); out: clk_disable(obj->clk); return err; }
/* only used in iotlb iteration for-loop */ static struct cr_regs __iotlb_read_cr(struct omap_iommu *obj, int n) { struct cr_regs cr; struct iotlb_lock l; iotlb_lock_get(obj, &l); l.vict = n; iotlb_lock_set(obj, &l); iotlb_read_cr(obj, &cr); return cr; }
/** * flush_iotlb_all - Clear all iommu tlb entries * @obj: target iommu **/ void flush_iotlb_all(struct iommu *obj) { struct iotlb_lock l; clk_enable(obj->clk); l.base = 0; l.vict = 0; iotlb_lock_set(obj, &l); iommu_write_reg(obj, 1, MMU_GFLUSH); clk_disable(obj->clk); }
static int __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num) { int i; struct iotlb_lock saved; struct cr_regs tmp; struct cr_regs *p = crs; pm_runtime_get_sync(obj->dev); iotlb_lock_get(obj, &saved); for_each_iotlb_cr(obj, num, i, tmp) { if (!iotlb_cr_valid(&tmp)) continue; *p++ = tmp; } iotlb_lock_set(obj, &saved); pm_runtime_put_sync(obj->dev); return p - crs; }
/** * load_iotlb_entry - Set an iommu tlb entry * @obj: target iommu * @e: an iommu tlb entry info **/ int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e) { int i; int err = 0; struct iotlb_lock l; struct cr_regs *cr; if (!obj || !obj->nr_tlb_entries || !e) return -EINVAL; if (!cpu_is_omap44xx()) clk_enable(obj->clk); iotlb_lock_get(obj, &l); if (l.base == obj->nr_tlb_entries) { dev_warn(obj->dev, "%s: preserve entries full\n", __func__); err = -EBUSY; goto out; } if (!e->prsvd) { for (i = l.base; i < obj->nr_tlb_entries; i++) { struct cr_regs tmp; iotlb_lock_get(obj, &l); l.vict = i; iotlb_lock_set(obj, &l); iotlb_read_cr(obj, &tmp); if (!iotlb_cr_valid(&tmp)) break; } if (i == obj->nr_tlb_entries) { dev_dbg(obj->dev, "%s: full: no entry\n", __func__); err = -EBUSY; goto out; } } else { l.vict = l.base; iotlb_lock_set(obj, &l); } cr = iotlb_alloc_cr(obj, e); if (IS_ERR(cr)) { if (!cpu_is_omap44xx()) clk_disable(obj->clk); return PTR_ERR(cr); } iotlb_load_cr(obj, cr); kfree(cr); /* Increment base number if preservation is set */ if (e->prsvd) l.base++; /* increment victim for next tlb load */ if (++l.vict == obj->nr_tlb_entries) { l.vict = l.base; goto out; } iotlb_lock_set(obj, &l); out: if (!cpu_is_omap44xx()) clk_disable(obj->clk); return err; }