/* * Copyright IBM Corp. 2012 * * Author(s): * Jan Glauber */ #include #include #include #include #include #include #include #include static struct kmem_cache *dma_region_table_cache; static struct kmem_cache *dma_page_table_cache; static int s390_iommu_strict; static int zpci_refresh_global(struct zpci_dev *zdev) { return zpci_refresh_trans((u64) zdev->fh << 32, zdev->start_dma, zdev->iommu_pages * PAGE_SIZE); } unsigned long *dma_alloc_cpu_table(void) { unsigned long *table, *entry; table = kmem_cache_alloc(dma_region_table_cache, GFP_ATOMIC); if (!table) return NULL; for (entry = table; entry < table + ZPCI_TABLE_ENTRIES; entry++) *entry = ZPCI_TABLE_INVALID; return table; } static void dma_free_cpu_table(void *table) { kmem_cache_free(dma_region_table_cache, table); } static unsigned long *dma_alloc_page_table(void) { unsigned long *table, *entry; table = kmem_cache_alloc(dma_page_table_cache, GFP_ATOMIC); if (!table) return NULL; for (entry = table; entry < table + ZPCI_PT_ENTRIES; entry++) *entry = ZPCI_PTE_INVALID; return table; } static void dma_free_page_table(void *table) { kmem_cache_free(dma_page_table_cache, table); } static unsigned long *dma_get_seg_table_origin(unsigned long *entry) { unsigned long *sto; if (reg_entry_isvalid(*entry)) sto = get_rt_sto(*entry); else { sto = dma_alloc_cpu_table(); if (!sto) return NULL; set_rt_sto(entry, sto); validate_rt_entry(entry); entry_clr_protected(entry); } return sto; } static unsigned long *dma_get_page_table_origin(unsigned long *entry) { unsigned long *pto; if (reg_entry_isvalid(*entry)) pto = get_st_pto(*entry); else { pto = dma_alloc_page_table(); if (!pto) return NULL; set_st_pto(entry, pto); validate_st_entry(entry); entry_clr_protected(entry); } return pto; } unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr) { unsigned long *sto, *pto; unsigned int rtx, sx, px; rtx = calc_rtx(dma_addr); sto = dma_get_seg_table_origin(&rto[rtx]); if (!sto) return NULL; sx = calc_sx(dma_addr); pto = dma_get_page_table_origin(&sto[sx]); if (!pto) return NULL; px = calc_px(dma_addr); return &pto[px]; } void dma_update_cpu_trans(unsigned long *entry, void *page_addr, int flags) { if (flags & ZPCI_PTE_INVALID) { invalidate_pt_entry(entry); } else { set_pt_pfaa(entry, page_addr); validate_pt_entry(entry); } if (flags & ZPCI_TABLE_PROTECTED) entry_set_protected(entry); else entry_clr_protected(entry); } static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa, dma_addr_t dma_addr, size_t size, int flags) { unsigned int nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; u8 *page_addr = (u8 *) (pa & PAGE_MASK); dma_addr_t start_dma_addr = dma_addr; unsigned long irq_flags; unsigned long *entry; int i, rc = 0; if (!nr_pages) return -EINVAL; spin_lock_irqsave(&zdev->dma_table_lock, irq_flags); if (!zdev->dma_table) { rc = -EINVAL; goto no_refresh; } for (i = 0; i < nr_pages; i++) { entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr); if (!entry) { rc = -ENOMEM; goto undo_cpu_trans; } dma_update_cpu_trans(entry, page_addr, flags); page_addr += PAGE_SIZE; dma_addr += PAGE_SIZE; } /* * With zdev->tlb_refresh == 0, rpcit is not required to establish new * translations when previously invalid translation-table entries are * validated. With lazy unmap, it also is skipped for previously valid * entries, but a global rpcit is then required before any address can * be re-used, i.e. after each iommu bitmap wrap-around. */ if (!zdev->tlb_refresh && (!s390_iommu_strict || ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID))) goto no_refresh; rc = zpci_refresh_trans((u64) zdev->fh << 32, start_dma_addr, nr_pages * PAGE_SIZE); undo_cpu_trans: if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) { flags = ZPCI_PTE_INVALID; while (i-- > 0) { page_addr -= PAGE_SIZE; dma_addr -= PAGE_SIZE; entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr); if (!entry) break; dma_update_cpu_trans(entry, page_addr, flags); } } no_refresh: spin_unlock_irqrestore(&zdev->dma_table_lock, irq_flags); return rc; } void dma_free_seg_table(unsigned long entry) { unsigned long *sto = get_rt_sto(entry); int sx; for (sx = 0; sx < ZPCI_TABLE_ENTRIES; sx++) if (reg_entry_isvalid(sto[sx])) dma_free_page_table(get_st_pto(sto[sx])); dma_free_cpu_table(sto); } void dma_cleanup_tables(unsigned long *table) { int rtx; if (!table) return; for (rtx = 0; rtx < ZPCI_TABLE_ENTRIES; rtx++) if (reg_entry_isvalid(table[rtx])) dma_free_seg_table(table[rtx]); dma_free_cpu_table(table); } static unsigned long __dma_alloc_iommu(struct zpci_dev *zdev, unsigned long start, int size) { unsigned long boundary_size; boundary_size = ALIGN(dma_get_seg_boundary(&zdev->pdev->dev) + 1, PAGE_SIZE) >> PAGE_SHIFT; return iommu_area_alloc(zdev->iommu_bitmap, zdev->iommu_pages, start, size, 0, boundary_size, 0); } static unsigned long dma_alloc_iommu(struct zpci_dev *zdev, int size) { unsigned long offset, flags; int wrap = 0; spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags); offset = __dma_alloc_iommu(zdev, zdev->next_bit, size); if (offset == -1) { /* wrap-around */ offset = __dma_alloc_iommu(zdev, 0, size); wrap = 1; } if (offset != -1) { zdev->next_bit = offset + size; if (!zdev->tlb_refresh && !s390_iommu_strict && wrap) /* global flush after wrap-around with lazy unmap */ zpci_refresh_global(zdev); } spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags); return offset; } static void dma_free_iommu(struct zpci_dev *zdev, unsigned long offset, int size) { unsigned long flags; spin_lock_irqsave(&zdev->iommu_bitmap_lock, flags); if (!zdev->iommu_bitmap) goto out; bitmap_clear(zdev->iommu_bitmap, offset, size); /* * Lazy flush for unmap: need to move next_bit to avoid address re-use * until wrap-around. */ if (!s390_iommu_strict && offset >= zdev->next_bit) zdev->next_bit = offset + size; out: spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags); } static inline void zpci_err_dma(unsigned long rc, unsigned long addr) { str
var http        = require('http');
var express		= require('express');
var fs			= require('fs');
var io			= require('socket.io');
var crypto		= require('crypto');

var app       	= express();
var staticDir 	= express.static;
var server    	= http.createServer(app);

io = io(server);

var opts = {
	port: process.env.PORT || 1948,
	baseDir : __dirname + '/../../