linux/arch/xtensa/kernel/pci-dma.c
<<
>>
Prefs
   1/*
   2 * arch/xtensa/kernel/pci-dma.c
   3 *
   4 * DMA coherent memory allocation.
   5 *
   6 * This program is free software; you can redistribute  it and/or modify it
   7 * under  the terms of  the GNU General  Public License as published by the
   8 * Free Software Foundation;  either version 2 of the  License, or (at your
   9 * option) any later version.
  10 *
  11 * Copyright (C) 2002 - 2005 Tensilica Inc.
  12 *
  13 * Based on version for i386.
  14 *
  15 * Chris Zankel <chris@zankel.net>
  16 * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
  17 */
  18
  19#include <linux/types.h>
  20#include <linux/mm.h>
  21#include <linux/string.h>
  22#include <linux/pci.h>
  23#include <asm/io.h>
  24#include <asm/cacheflush.h>
  25
  26/*
  27 * Note: We assume that the full memory space is always mapped to 'kseg'
  28 *       Otherwise we have to use page attributes (not implemented).
  29 */
  30
  31void *
  32dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *handle,gfp_t flag)
  33{
  34        unsigned long ret;
  35        unsigned long uncached = 0;
  36
  37        /* ignore region speicifiers */
  38
  39        flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
  40
  41        if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
  42                flag |= GFP_DMA;
  43        ret = (unsigned long)__get_free_pages(flag, get_order(size));
  44
  45        if (ret == 0)
  46                return NULL;
  47
  48        /* We currently don't support coherent memory outside KSEG */
  49
  50        if (ret < XCHAL_KSEG_CACHED_VADDR
  51            || ret >= XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE)
  52                BUG();
  53
  54
  55        if (ret != 0) {
  56                memset((void*) ret, 0, size);
  57                uncached = ret+XCHAL_KSEG_BYPASS_VADDR-XCHAL_KSEG_CACHED_VADDR;
  58                *handle = virt_to_bus((void*)ret);
  59                __flush_invalidate_dcache_range(ret, size);
  60        }
  61
  62        return (void*)uncached;
  63}
  64
  65void dma_free_coherent(struct device *hwdev, size_t size,
  66                         void *vaddr, dma_addr_t dma_handle)
  67{
  68        long addr=(long)vaddr+XCHAL_KSEG_CACHED_VADDR-XCHAL_KSEG_BYPASS_VADDR;
  69
  70        if (addr < 0 || addr >= XCHAL_KSEG_SIZE)
  71                BUG();
  72
  73        free_pages(addr, get_order(size));
  74}
  75
  76
  77void consistent_sync(void *vaddr, size_t size, int direction)
  78{
  79        switch (direction) {
  80        case PCI_DMA_NONE:
  81                BUG();
  82        case PCI_DMA_FROMDEVICE:        /* invalidate only */
  83                __invalidate_dcache_range((unsigned long)vaddr,
  84                                          (unsigned long)size);
  85                break;
  86
  87        case PCI_DMA_TODEVICE:          /* writeback only */
  88        case PCI_DMA_BIDIRECTIONAL:     /* writeback and invalidate */
  89                __flush_invalidate_dcache_range((unsigned long)vaddr,
  90                                                (unsigned long)size);
  91                break;
  92        }
  93}
  94