linux-cvs-patches
[Top] [All Lists]

CVS Update@linux-mips.org: linux

To: linux-cvs-patches@linux-mips.org
Subject: CVS Update@linux-mips.org: linux
From: ths@linux-mips.org
Date: Wed, 12 Jan 2005 00:10:48 +0000
Reply-to: linux-mips@linux-mips.org
Sender: linux-cvs-patches-bounce@linux-mips.org
CVSROOT:        /home/cvs
Module name:    linux
Changes by:     ths@ftp.linux-mips.org  05/01/12 00:10:42

Modified files:
        arch/mips/mm   : Makefile 
        arch/mips/sgi-ip32: Makefile ip32-setup.c crime.c 
        include/asm-mips/ip32: crime.h 
        include/asm-mips/mach-ip32: spaces.h 
        arch/mips      : Kconfig 
Added files:
        arch/mips/mm   : dma-ip32.c 
        arch/mips/sgi-ip32: ip32-memory.c 
        include/asm-mips/mach-ip32: cpu-feature-overrides.h 

Log message:
        Support for ip32 large memory, thanks to Ilya A. Volynets-Evenbakh.

diff -urN linux/arch/mips/mm/dma-ip32.c linux/arch/mips/mm/dma-ip32.c
--- linux/arch/mips/mm/dma-ip32.c       1970/01/01 00:00:00
+++ linux/arch/mips/mm/dma-ip32.c       Wed Jan 12 00:10:42 2005        1.1
@@ -0,0 +1,383 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000  Ani Joshi <ajoshi@unixbox.com>
+ * Copyright (C) 2000, 2001  Ralf Baechle <ralf@gnu.org>
+ * Copyright (C) 2005 Ilya A. Volynets-Evenbakh <ilya@total-knowledge.com>
+ * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
+ * IP32 changes by Ilya.
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/ip32/crime.h>
+
+/*
+ * Warning on the terminology - Linux calls an uncached area coherent;
+ * MIPS terminology calls memory areas with hardware maintained coherency
+ * coherent.
+ */
+
+/*
+ * Few notes.
+ * 1. CPU sees memory as two chunks: 0-256M@0x0, and the rest @0x40000000+256M
+ * 2. PCI sees memory as one big chunk @0x0 (or we couls use 0x40000000 for 
native-endian)
+ * 3. All other devices see memory as one big chunk at 0x40000000
+ * 4. Non-PCI devices will pass NULL as struct device*
+ * Thus we translate differently, depending on device.
+ */
+
+#define RAM_OFFSET_MASK        0x3fffffff
+
+void *dma_alloc_noncoherent(struct device *dev, size_t size,
+       dma_addr_t * dma_handle, int gfp)
+{
+       void *ret;
+       /* ignore region specifiers */
+       gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+       if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
+               gfp |= GFP_DMA;
+       ret = (void *) __get_free_pages(gfp, get_order(size));
+
+       if (ret != NULL) {
+               unsigned long addr = virt_to_phys(ret)&RAM_OFFSET_MASK;
+               memset(ret, 0, size);
+               if(dev==NULL)
+                   addr+= CRIME_HI_MEM_BASE;
+               *dma_handle = addr;
+       }
+
+       return ret;
+}
+
+EXPORT_SYMBOL(dma_alloc_noncoherent);
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+       dma_addr_t * dma_handle, int gfp)
+{
+       void *ret;
+
+       ret = dma_alloc_noncoherent(dev, size, dma_handle, gfp);
+       if (ret) {
+               dma_cache_wback_inv((unsigned long) ret, size);
+               ret = UNCAC_ADDR(ret);
+       }
+
+       return ret;
+}
+
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr,
+       dma_addr_t dma_handle)
+{
+       free_pages((unsigned long) vaddr, get_order(size));
+}
+
+EXPORT_SYMBOL(dma_free_noncoherent);
+
+void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+       dma_addr_t dma_handle)
+{
+       unsigned long addr = (unsigned long) vaddr;
+
+       addr = CAC_ADDR(addr);
+       free_pages(addr, get_order(size));
+}
+
+EXPORT_SYMBOL(dma_free_coherent);
+
+static inline void __dma_sync(unsigned long addr, size_t size,
+       enum dma_data_direction direction)
+{
+       switch (direction) {
+       case DMA_TO_DEVICE:
+               dma_cache_wback(addr, size);
+               break;
+
+       case DMA_FROM_DEVICE:
+               dma_cache_inv(addr, size);
+               break;
+
+       case DMA_BIDIRECTIONAL:
+               dma_cache_wback_inv(addr, size);
+               break;
+
+       default:
+               BUG();
+       }
+}
+
+dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
+       enum dma_data_direction direction)
+{
+       unsigned long addr = (unsigned long) ptr;
+
+       switch (direction) {
+       case DMA_TO_DEVICE:
+               dma_cache_wback(addr, size);
+               break;
+
+       case DMA_FROM_DEVICE:
+               dma_cache_inv(addr, size);
+               break;
+
+       case DMA_BIDIRECTIONAL:
+               dma_cache_wback_inv(addr, size);
+               break;
+
+       default:
+               BUG();
+       }
+
+       addr = virt_to_phys(ptr)&RAM_OFFSET_MASK;;
+       if(dev == NULL)
+           addr+=CRIME_HI_MEM_BASE;
+       return (dma_addr_t)addr;
+}
+
+EXPORT_SYMBOL(dma_map_single);
+
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+       enum dma_data_direction direction)
+{
+       switch (direction) {
+       case DMA_TO_DEVICE:
+               break;
+
+       case DMA_FROM_DEVICE:
+               break;
+
+       case DMA_BIDIRECTIONAL:
+               break;
+
+       default:
+               BUG();
+       }
+}
+
+EXPORT_SYMBOL(dma_unmap_single);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+       enum dma_data_direction direction)
+{
+       int i;
+
+       BUG_ON(direction == DMA_NONE);
+
+       for (i = 0; i < nents; i++, sg++) {
+               unsigned long addr;
+ 
+               addr = (unsigned long) page_address(sg->page)+sg->offset;
+               if (addr)
+                       __dma_sync(addr, sg->length, direction);
+               addr = __pa(addr)&RAM_OFFSET_MASK;;
+               if(dev == NULL)
+                       addr +=  CRIME_HI_MEM_BASE;
+               sg->dma_address = (dma_addr_t)addr;
+       }
+
+       return nents;
+}
+
+EXPORT_SYMBOL(dma_map_sg);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+       unsigned long offset, size_t size, enum dma_data_direction direction)
+{
+       unsigned long addr;
+
+       BUG_ON(direction == DMA_NONE);
+
+       addr = (unsigned long) page_address(page) + offset;
+       dma_cache_wback_inv(addr, size);
+       addr = __pa(addr)&RAM_OFFSET_MASK;;
+       if(dev == NULL)
+               addr +=  CRIME_HI_MEM_BASE;
+
+       return (dma_addr_t)addr;
+}
+
+EXPORT_SYMBOL(dma_map_page);
+
+void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+       enum dma_data_direction direction)
+{
+       BUG_ON(direction == DMA_NONE);
+
+       if (direction != DMA_TO_DEVICE) {
+               unsigned long addr;
+
+               dma_address&=RAM_OFFSET_MASK;
+               addr = dma_address + PAGE_OFFSET;
+               if(dma_address>=256*1024*1024)
+                       addr+=CRIME_HI_MEM_BASE;
+               dma_cache_wback_inv(addr, size);
+       }
+}
+
+EXPORT_SYMBOL(dma_unmap_page);
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+       enum dma_data_direction direction)
+{
+       unsigned long addr;
+       int i;
+
+       BUG_ON(direction == DMA_NONE);
+
+       if (direction == DMA_TO_DEVICE)
+               return;
+
+       for (i = 0; i < nhwentries; i++, sg++) {
+               addr = (unsigned long) page_address(sg->page);
+               if (!addr)
+                       continue;
+               dma_cache_wback_inv(addr + sg->offset, sg->length);
+       }
+}
+
+EXPORT_SYMBOL(dma_unmap_sg);
+
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+       size_t size, enum dma_data_direction direction)
+{
+       unsigned long addr;
+ 
+       BUG_ON(direction == DMA_NONE);
+ 
+       dma_handle&=RAM_OFFSET_MASK;
+       addr = dma_handle + PAGE_OFFSET;
+       if(dma_handle>=256*1024*1024)
+           addr+=CRIME_HI_MEM_BASE;
+       __dma_sync(addr, size, direction);
+}
+
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
+
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+       size_t size, enum dma_data_direction direction)
+{
+       unsigned long addr;
+
+       BUG_ON(direction == DMA_NONE);
+
+       dma_handle&=RAM_OFFSET_MASK;
+       addr = dma_handle + PAGE_OFFSET;
+       if(dma_handle>=256*1024*1024)
+           addr+=CRIME_HI_MEM_BASE;
+       __dma_sync(addr, size, direction);
+}
+
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+       unsigned long offset, size_t size, enum dma_data_direction direction)
+{
+       unsigned long addr;
+
+       BUG_ON(direction == DMA_NONE);
+
+       dma_handle&=RAM_OFFSET_MASK;
+       addr = dma_handle + offset + PAGE_OFFSET;
+       if(dma_handle>=256*1024*1024)
+           addr+=CRIME_HI_MEM_BASE;
+       __dma_sync(addr, size, direction);
+}
+
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev, dma_addr_t 
dma_handle,
+       unsigned long offset, size_t size, enum dma_data_direction direction)
+{
+       unsigned long addr;
+
+       BUG_ON(direction == DMA_NONE);
+
+       dma_handle&=RAM_OFFSET_MASK;
+       addr = dma_handle + offset + PAGE_OFFSET;
+       if(dma_handle>=256*1024*1024)
+           addr+=CRIME_HI_MEM_BASE;
+       __dma_sync(addr, size, direction);
+}
+
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
+
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int 
nelems,
+       enum dma_data_direction direction)
+{
+       int i;
+ 
+       BUG_ON(direction == DMA_NONE);
+ 
+       /* Make sure that gcc doesn't leave the empty loop body.  */
+       for (i = 0; i < nelems; i++, sg++)
+               __dma_sync((unsigned long)page_address(sg->page),
+                          sg->length, direction);
+}
+
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int 
nelems,
+       enum dma_data_direction direction)
+{
+       int i;
+
+       BUG_ON(direction == DMA_NONE);
+
+       /* Make sure that gcc doesn't leave the empty loop body.  */
+       for (i = 0; i < nelems; i++, sg++)
+               __dma_sync((unsigned long)page_address(sg->page),
+                          sg->length, direction);
+}
+
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+int dma_mapping_error(dma_addr_t dma_addr)
+{
+       return 0;
+}
+
+EXPORT_SYMBOL(dma_mapping_error);
+
+int dma_supported(struct device *dev, u64 mask)
+{
+       /*
+        * we fall back to GFP_DMA when the mask isn't all 1s,
+        * so we can't guarantee allocations that must be
+        * within a tighter range than GFP_DMA..
+        */
+       if (mask < 0x00ffffff)
+               return 0;
+
+       return 1;
+}
+
+EXPORT_SYMBOL(dma_supported);
+
+int dma_is_consistent(dma_addr_t dma_addr)
+{
+       return 1;
+}
+
+EXPORT_SYMBOL(dma_is_consistent);
+
+void dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction 
direction)
+{
+       if (direction == DMA_NONE)
+               return;
+
+       dma_cache_wback_inv((unsigned long)vaddr, size);
+}
+
+EXPORT_SYMBOL(dma_cache_sync);
+
diff -urN linux/arch/mips/mm/Makefile linux/arch/mips/mm/Makefile
--- linux/arch/mips/mm/Makefile 2005/01/07 18:58:34     1.74
+++ linux/arch/mips/mm/Makefile 2005/01/12 00:10:42     1.75
@@ -34,8 +34,11 @@
 #
 # Choose one DMA coherency model
 #
+ifndef CONFIG_OWN_DMA
 obj-$(CONFIG_DMA_COHERENT)     += dma-coherent.o
 obj-$(CONFIG_DMA_NONCOHERENT)  += dma-noncoherent.o
+endif
 obj-$(CONFIG_DMA_IP27)         += dma-ip27.o
+obj-$(CONFIG_DMA_IP32)         += dma-ip32.o
 
 EXTRA_AFLAGS := $(CFLAGS)
diff -urN linux/arch/mips/sgi-ip32/ip32-memory.c 
linux/arch/mips/sgi-ip32/ip32-memory.c
--- linux/arch/mips/sgi-ip32/ip32-memory.c      1970/01/01 00:00:00
+++ linux/arch/mips/sgi-ip32/ip32-memory.c      Wed Jan 12 00:10:42 2005        
1.1
@@ -0,0 +1,49 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Keith M Wesolowski
+ * Copyright (C) 2005 Ilya A. Volynets (Total Knowledge)
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include <asm/ip32/crime.h>
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+
+extern void crime_init(void);
+
+void __init prom_meminit (void)
+{
+       u64 base, size;
+       int bank;
+
+       crime_init();
+
+       for (bank=0; bank < CRIME_MAXBANKS; bank++) {
+               u64 bankctl = crime->bank_ctrl[bank];
+               base = (bankctl & CRIME_MEM_BANK_CONTROL_ADDR) << 25;
+               if (bank != 0 && base == 0)
+                       continue;
+               size = (bankctl & CRIME_MEM_BANK_CONTROL_SDRAM_SIZE) ? 128 : 32;
+               size <<= 20;
+               if (base + size > (256 << 20))
+                       base += CRIME_HI_MEM_BASE;
+
+               printk("CRIME MC: bank %u base 0x%016lx size %luMB\n",
+                       bank, base, size);
+               add_memory_region (base, size, BOOT_MEM_RAM);
+       }
+}
+
+
+unsigned long __init prom_free_prom_memory (void)
+{
+       return 0;
+}
diff -urN linux/arch/mips/sgi-ip32/Makefile linux/arch/mips/sgi-ip32/Makefile
--- linux/arch/mips/sgi-ip32/Makefile   2004/02/26 09:09:09     1.9
+++ linux/arch/mips/sgi-ip32/Makefile   2005/01/12 00:10:42     1.10
@@ -4,6 +4,6 @@
 #
 
 obj-y  += ip32-berr.o ip32-irq.o ip32-irq-glue.o ip32-setup.o ip32-reset.o \
-          crime.o
+          crime.o ip32-memory.o
 
 EXTRA_AFLAGS := $(CFLAGS)
diff -urN linux/arch/mips/sgi-ip32/ip32-setup.c 
linux/arch/mips/sgi-ip32/ip32-setup.c
--- linux/arch/mips/sgi-ip32/ip32-setup.c       2004/08/31 16:49:32     1.22
+++ linux/arch/mips/sgi-ip32/ip32-setup.c       2005/01/12 00:10:42     1.23
@@ -94,10 +94,6 @@
 
 static int __init ip32_setup(void)
 {
-       set_io_port_base((unsigned long) ioremap(MACEPCI_LOW_IO, 0x2000000));
-
-       crime_init();
-
        board_be_init = ip32_be_init;
 
        rtc_get_time = mc146818_get_cmos_time;
diff -urN linux/arch/mips/sgi-ip32/crime.c linux/arch/mips/sgi-ip32/crime.c
--- linux/arch/mips/sgi-ip32/crime.c    2004/08/31 16:49:32     1.6
+++ linux/arch/mips/sgi-ip32/crime.c    2005/01/12 00:10:42     1.7
@@ -4,6 +4,7 @@
  * for more details.
  *
  * Copyright (C) 2001, 2003 Keith M Wesolowski
+ * Copyright (C) 2005 Ilya A. Volynets <ilya@total-knowledge.com>
  */
 #include <linux/types.h>
 #include <linux/init.h>
@@ -24,7 +25,8 @@
 {
        unsigned int id, rev;
        const int field = 2 * sizeof(unsigned long);
-       
+
+       set_io_port_base((unsigned long) ioremap(MACEPCI_LOW_IO, 0x2000000));   
        crime = ioremap(CRIME_BASE, sizeof(struct sgi_crime));
        mace = ioremap(MACE_BASE, sizeof(struct sgi_mace));
 
diff -urN linux/include/asm-mips/ip32/crime.h 
linux/include/asm-mips/ip32/crime.h
--- linux/include/asm-mips/ip32/crime.h 2004/12/04 18:16:09     1.6
+++ linux/include/asm-mips/ip32/crime.h 2005/01/12 00:10:42     1.7
@@ -156,4 +156,6 @@
 
 extern struct sgi_crime *crime;
 
+#define CRIME_HI_MEM_BASE      0x40000000      /* this is where whole 1G of 
RAM is mapped */
+
 #endif /* __ASM_CRIME_H__ */
diff -urN linux/include/asm-mips/mach-ip32/cpu-feature-overrides.h 
linux/include/asm-mips/mach-ip32/cpu-feature-overrides.h
--- linux/include/asm-mips/mach-ip32/cpu-feature-overrides.h    1970/01/01 
00:00:00
+++ linux/include/asm-mips/mach-ip32/cpu-feature-overrides.h    Wed Jan 12 
00:10:42 2005        1.1
@@ -0,0 +1,22 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2005 Ilya A. Volynets-Evenbakh
+ */
+#ifndef __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H
+
+/*
+ * R5000 has an interesting "restriction":  ll(d)/sc(d)
+ * instructions to XKPHYS region simply do uncached bus
+ * requests. This breaks all the atomic bitops functions.
+ * so, for 64bit IP32 kernel we just don't use ll/sc.
+ * This does not affect luserland.
+ */
+#if defined(CONFIG_CPU_R5000) && defined(CONFIG_MIPS64)
+#define cpu_has_llsc   0
+#endif
+
+#endif /* __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H */
diff -urN linux/include/asm-mips/mach-ip32/spaces.h 
linux/include/asm-mips/mach-ip32/spaces.h
--- linux/include/asm-mips/mach-ip32/spaces.h   2004/10/15 02:09:12     1.1
+++ linux/include/asm-mips/mach-ip32/spaces.h   2005/01/12 00:10:42     1.2
@@ -12,10 +12,6 @@
 
 #include <linux/config.h>
 
-/*
- * This handles the memory map.
- */
-#define PAGE_OFFSET            0xffffffff80000000
 
 /*
  * Memory above this physical address will be considered highmem.
@@ -26,11 +22,7 @@
 #define HIGHMEM_START          (1UL << 59UL)
 #endif
 
-#ifdef CONFIG_DMA_NONCOHERENT
 #define CAC_BASE               0x9800000000000000
-#else
-#define CAC_BASE               0xa800000000000000
-#endif
 #define IO_BASE                        0x9000000000000000
 #define UNCAC_BASE             0x9000000000000000
 #define MAP_BASE               0xc000000000000000
@@ -39,4 +31,9 @@
 #define TO_CAC(x)              (CAC_BASE   | ((x) & TO_PHYS_MASK))
 #define TO_UNCAC(x)            (UNCAC_BASE | ((x) & TO_PHYS_MASK))
 
+/*
+ * This handles the memory map.
+ */
+#define PAGE_OFFSET            CAC_BASE
+
 #endif /* __ASM_MACH_IP32_SPACES_H */
diff -urN linux/arch/mips/Kconfig linux/arch/mips/Kconfig
--- linux/arch/mips/Kconfig     2004/12/27 18:23:53     1.126
+++ linux/arch/mips/Kconfig     2005/01/12 00:10:42     1.127
@@ -541,6 +541,8 @@
        select ARC
        select ARC32
        select BOOT_ELF32
+       select OWN_DMA
+       select DMA_IP32
        select DMA_NONCOHERENT
        select HW_HAS_PCI
        select R5000_CPU_SCACHE
@@ -926,6 +928,12 @@
 config DMA_IP27
        bool
 
+config DMA_IP32
+       bool
+
+config OWN_DMA
+       bool
+
 config DMA_NONCOHERENT
        bool
 

<Prev in Thread] Current Thread [Next in Thread>