lkml.org 
[lkml]   [1997]   [Mar]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: Mapping non-prefetchable memory [patch included]

On Sun, 23 Mar 1997, Rakesh Dubey wrote:

> I have some questions about mapping PCI device memory in Linux
> 2.0.x. My device requires that the memory be mapped non-prefetchable
> (i.e. non-cached). I am using the vremap(phyAddr, size) to get the
> virtual address but is this memory cached or non-cached? There does
> not seem to be any options to control this.

hmm, looks like we should add 'flags' to ioremap(phys,size). Flags like:

------------------------------------------------------------------->
#define IOREMAP_NOCACHING 0x0001
#define IOREMAP_WT_CACHING 0x0002
#define IOREMAP_WB_CACHING 0x0004
#define IOREMAP_UNORDERED_CACHING 0x0008

#define IOREMAP_USE_BIGPAGES 0x0010

#define IOREMAP_IO (IOREMAP_NOCACHING|IOREMAP_USE_BIGPAGES)
#define IOREMAP_VIDEO (IOREMAP_UNORDERED_CACHING|IOREMAP_USE_BIGPAGES)
<-------------------------------------------------------------------

It would be up to the platform specific code what's done with the flags?

anyways, here is a quick hack that implements ioremap_nocache() for x86
(without breaking the generic interface). It compiles but is untested
otherwise (tell me if it works). It's against 2.1.29, but should be fairly
easy to port back to 2.0.

if this is the way to go then i will hack up largepage support for ioremap
as well. [it will be nice for the ring 0 process XFree86 server i'm
hacking on ... but nice for frame grabbers and other bigbuffer PCI
devices too]

-- mingo

--- arch/i386/mm/ioremap.c.original Sun Mar 23 11:41:51 1997
+++ arch/i386/mm/ioremap.c Sun Mar 23 11:40:18 1997
@@ -11,9 +11,10 @@
#include <linux/vmalloc.h>

#include <asm/io.h>
+#include <asm/pgtable.h>

static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
- unsigned long phys_addr)
+ unsigned long phys_addr, unsigned long flags)
{
unsigned long end;

@@ -24,7 +25,8 @@
do {
if (!pte_none(*pte))
printk("remap_area_pte: page already exists\n");
- set_pte(pte, mk_pte_phys(phys_addr, PAGE_KERNEL));
+ set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | _PAGE_RW |
+ _PAGE_DIRTY | _PAGE_ACCESSED | flags)));
address += PAGE_SIZE;
phys_addr += PAGE_SIZE;
pte++;
@@ -32,7 +34,7 @@
}

static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr)
+ unsigned long phys_addr, unsigned long flags)
{
unsigned long end;

@@ -45,14 +47,15 @@
pte_t * pte = pte_alloc_kernel(pmd, address);
if (!pte)
return -ENOMEM;
- remap_area_pte(pte, address, end - address, address + phys_addr);
+ remap_area_pte(pte, address, end - address, address + phys_addr, flags);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
return 0;
}

-static int remap_area_pages(unsigned long address, unsigned long phys_addr, unsigned long size)
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+ unsigned long size, unsigned long flags)
{
pgd_t * dir;
unsigned long end = address + size;
@@ -64,7 +67,8 @@
pmd_t *pmd = pmd_alloc_kernel(dir, address);
if (!pmd)
return -ENOMEM;
- if (remap_area_pmd(pmd, address, end - address, phys_addr + address))
+ if (remap_area_pmd(pmd, address, end - address,
+ phys_addr + address, flags))
return -ENOMEM;
set_pgdir(address, *dir);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
@@ -75,11 +79,15 @@
}

/*
+ * Generic mapping function (not visible outside):
+ */
+
+/*
* Remap an arbitrary physical address space into the kernel virtual
* address space. Needed when the kernel wants to access high addresses
* directly.
*/
-void * ioremap(unsigned long phys_addr, unsigned long size)
+static void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
{
void * addr;
struct vm_struct * area;
@@ -95,11 +103,25 @@
if (!area)
return NULL;
addr = area->addr;
- if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size)) {
+ if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
vfree(addr);
return NULL;
}
return addr;
+}
+
+/*
+ * Wrappers using the generic function:
+ */
+
+void * ioremap(unsigned long phys_addr, unsigned long size)
+{
+ return __ioremap(phys_addr, size, 0);
+}
+
+void * ioremap_nocache(unsigned long phys_addr, unsigned long size)
+{
+ return __ioremap(phys_addr, size, _PAGE_PCD);
}

void iounmap(void *addr)



\
 
 \ /
  Last update: 2005-03-22 13:39    [W:0.039 / U:0.548 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site