* [PATCH 1] Delete unused file common/dlmalloc.src.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
@ 2010-12-20 22:40 ` Krzysztof Halasa
2010-12-21 9:34 ` Sascha Hauer
2010-12-20 22:42 ` [PATCH 2] Remove unused eth_get_name() prototype Krzysztof Halasa
` (15 subsequent siblings)
16 siblings, 1 reply; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 22:40 UTC (permalink / raw)
To: barebox
Delete unused file common/dlmalloc.src.
Or is there any reason to have it here?
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/common/dlmalloc.src b/common/dlmalloc.src
deleted file mode 100644
index 32a38bc..0000000
--- a/common/dlmalloc.src
+++ /dev/null
@@ -1,3265 +0,0 @@
-/* ---------- To make a malloc.h, start cutting here ------------ */
-
-/*
- A version of malloc/free/realloc written by Doug Lea and released to the
- public domain. Send questions/comments/complaints/performance data
- to dl@cs.oswego.edu
-
-* VERSION 2.6.6 Sun Mar 5 19:10:03 2000 Doug Lea (dl at gee)
-
- Note: There may be an updated version of this malloc obtainable at
- ftp://g.oswego.edu/pub/misc/malloc.c
- Check before installing!
-
-* Why use this malloc?
-
- This is not the fastest, most space-conserving, most portable, or
- most tunable malloc ever written. However it is among the fastest
- while also being among the most space-conserving, portable and tunable.
- Consistent balance across these factors results in a good general-purpose
- allocator. For a high-level description, see
- http://g.oswego.edu/dl/html/malloc.html
-
-* Synopsis of public routines
-
- (Much fuller descriptions are contained in the program documentation below.)
-
- malloc(size_t n);
- Return a pointer to a newly allocated chunk of at least n bytes, or null
- if no space is available.
- free(Void_t* p);
- Release the chunk of memory pointed to by p, or no effect if p is null.
- realloc(Void_t* p, size_t n);
- Return a pointer to a chunk of size n that contains the same data
- as does chunk p up to the minimum of (n, p's size) bytes, or null
- if no space is available. The returned pointer may or may not be
- the same as p. If p is null, equivalent to malloc. Unless the
- #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
- size argument of zero (re)allocates a minimum-sized chunk.
- memalign(size_t alignment, size_t n);
- Return a pointer to a newly allocated chunk of n bytes, aligned
- in accord with the alignment argument, which must be a power of
- two.
- valloc(size_t n);
- Equivalent to memalign(pagesize, n), where pagesize is the page
- size of the system (or as near to this as can be figured out from
- all the includes/defines below.)
- pvalloc(size_t n);
- Equivalent to valloc(minimum-page-that-holds(n)), that is,
- round up n to nearest pagesize.
- calloc(size_t unit, size_t quantity);
- Returns a pointer to quantity * unit bytes, with all locations
- set to zero.
- cfree(Void_t* p);
- Equivalent to free(p).
- malloc_trim(size_t pad);
- Release all but pad bytes of freed top-most memory back
- to the system. Return 1 if successful, else 0.
- malloc_usable_size(Void_t* p);
- Report the number usable allocated bytes associated with allocated
- chunk p. This may or may not report more bytes than were requested,
- due to alignment and minimum size constraints.
- malloc_stats();
- Prints brief summary statistics on stderr.
- mallinfo()
- Returns (by copy) a struct containing various summary statistics.
- mallopt(int parameter_number, int parameter_value)
- Changes one of the tunable parameters described below. Returns
- 1 if successful in changing the parameter, else 0.
-
-* Vital statistics:
-
- Alignment: 8-byte
- 8 byte alignment is currently hardwired into the design. This
- seems to suffice for all current machines and C compilers.
-
- Assumed pointer representation: 4 or 8 bytes
- Code for 8-byte pointers is untested by me but has worked
- reliably by Wolfram Gloger, who contributed most of the
- changes supporting this.
-
- Assumed size_t representation: 4 or 8 bytes
- Note that size_t is allowed to be 4 bytes even if pointers are 8.
-
- Minimum overhead per allocated chunk: 4 or 8 bytes
- Each malloced chunk has a hidden overhead of 4 bytes holding size
- and status information.
-
- Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
- 8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
-
- When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
- ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
- needed; 4 (8) for a trailing size field
- and 8 (16) bytes for free list pointers. Thus, the minimum
- allocatable size is 16/24/32 bytes.
-
- Even a request for zero bytes (i.e., malloc(0)) returns a
- pointer to something of the minimum allocatable size.
-
- Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes
- 8-byte size_t: 2^63 - 16 bytes
-
- It is assumed that (possibly signed) size_t bit values suffice to
- represent chunk sizes. `Possibly signed' is due to the fact
- that `size_t' may be defined on a system as either a signed or
- an unsigned type. To be conservative, values that would appear
- as negative numbers are avoided.
- Requests for sizes with a negative sign bit when the request
- size is treaded as a long will return null.
-
- Maximum overhead wastage per allocated chunk: normally 15 bytes
-
- Alignnment demands, plus the minimum allocatable size restriction
- make the normal worst-case wastage 15 bytes (i.e., up to 15
- more bytes will be allocated than were requested in malloc), with
- two exceptions:
- 1. Because requests for zero bytes allocate non-zero space,
- the worst case wastage for a request of zero bytes is 24 bytes.
- 2. For requests >= mmap_threshold that are serviced via
- mmap(), the worst case wastage is 8 bytes plus the remainder
- from a system page (the minimal mmap unit); typically 4096 bytes.
-
-* Limitations
-
- Here are some features that are NOT currently supported
-
- * No user-definable hooks for callbacks and the like.
- * No automated mechanism for fully checking that all accesses
- to malloced memory stay within their bounds.
- * No support for compaction.
-
-* Synopsis of compile-time options:
-
- People have reported using previous versions of this malloc on all
- versions of Unix, sometimes by tweaking some of the defines
- below. It has been tested most extensively on Solaris and
- Linux. It is also reported to work on WIN32 platforms.
- People have also reported adapting this malloc for use in
- stand-alone embedded systems.
-
- The implementation is in straight, hand-tuned ANSI C. Among other
- consequences, it uses a lot of macros. Because of this, to be at
- all usable, this code should be compiled using an optimizing compiler
- (for example gcc -O2) that can simplify expressions and control
- paths.
-
- __STD_C (default: derived from C compiler defines)
- Nonzero if using ANSI-standard C compiler, a C++ compiler, or
- a C compiler sufficiently close to ANSI to get away with it.
- DEBUG (default: NOT defined)
- Define to enable debugging. Adds fairly extensive assertion-based
- checking to help track down memory errors, but noticeably slows down
- execution.
- REALLOC_ZERO_BYTES_FREES (default: NOT defined)
- Define this if you think that realloc(p, 0) should be equivalent
- to free(p). Otherwise, since malloc returns a unique pointer for
- malloc(0), so does realloc(p, 0).
- HAVE_MEMCPY (default: defined)
- Define if you are not otherwise using ANSI STD C, but still
- have memcpy and memset in your C library and want to use them.
- Otherwise, simple internal versions are supplied.
- USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise)
- Define as 1 if you want the C library versions of memset and
- memcpy called in realloc and calloc (otherwise macro versions are used).
- At least on some platforms, the simple macro versions usually
- outperform libc versions.
- HAVE_MMAP (default: defined as 1)
- Define to non-zero to optionally make malloc() use mmap() to
- allocate very large blocks.
- HAVE_MREMAP (default: defined as 0 unless Linux libc set)
- Define to non-zero to optionally make realloc() use mremap() to
- reallocate very large blocks.
- malloc_getpagesize (default: derived from system #includes)
- Either a constant or routine call returning the system page size.
- HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined)
- Optionally define if you are on a system with a /usr/include/malloc.h
- that declares struct mallinfo. It is not at all necessary to
- define this even if you do, but will ensure consistency.
- INTERNAL_SIZE_T (default: size_t)
- Define to a 32-bit type (probably `unsigned int') if you are on a
- 64-bit machine, yet do not want or need to allow malloc requests of
- greater than 2^31 to be handled. This saves space, especially for
- very small chunks.
- INTERNAL_LINUX_C_LIB (default: NOT defined)
- Defined only when compiled as part of Linux libc.
- Also note that there is some odd internal name-mangling via defines
- (for example, internally, `malloc' is named `mALLOc') needed
- when compiling in this case. These look funny but don't otherwise
- affect anything.
- WIN32 (default: undefined)
- Define this on MS win (95, nt) platforms to compile in sbrk emulation.
- LACKS_UNISTD_H (default: undefined if not WIN32)
- Define this if your system does not have a <unistd.h>.
- LACKS_SYS_PARAM_H (default: undefined if not WIN32)
- Define this if your system does not have a <sys/param.h>.
- MORECORE (default: sbrk)
- The name of the routine to call to obtain more memory from the system.
- MORECORE_FAILURE (default: -1)
- The value returned upon failure of MORECORE.
- MORECORE_CLEARS (default 1)
- True (1) if the routine mapped to MORECORE zeroes out memory (which
- holds for sbrk).
- DEFAULT_TRIM_THRESHOLD
- DEFAULT_TOP_PAD
- DEFAULT_MMAP_THRESHOLD
- DEFAULT_MMAP_MAX
- Default values of tunable parameters (described in detail below)
- controlling interaction with host system routines (sbrk, mmap, etc).
- These values may also be changed dynamically via mallopt(). The
- preset defaults are those that give best performance for typical
- programs/systems.
- USE_DL_PREFIX (default: undefined)
- Prefix all public routines with the string 'dl'. Useful to
- quickly avoid procedure declaration conflicts and linker symbol
- conflicts with existing memory allocation routines.
-
-
-*/
-
-\f
-
-
-/* Preliminaries */
-
-#ifndef __STD_C
-#ifdef __STDC__
-#define __STD_C 1
-#else
-#if __cplusplus
-#define __STD_C 1
-#else
-#define __STD_C 0
-#endif /*__cplusplus*/
-#endif /*__STDC__*/
-#endif /*__STD_C*/
-
-#ifndef Void_t
-#if (__STD_C || defined(WIN32))
-#define Void_t void
-#else
-#define Void_t char
-#endif
-#endif /*Void_t*/
-
-#if __STD_C
-#include <stddef.h> /* for size_t */
-#else
-#include <sys/types.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdio.h> /* needed for malloc_stats */
-
-
-/*
- Compile-time options
-*/
-
-
-/*
- Debugging:
-
- Because freed chunks may be overwritten with link fields, this
- malloc will often die when freed memory is overwritten by user
- programs. This can be very effective (albeit in an annoying way)
- in helping track down dangling pointers.
-
- If you compile with -DDEBUG, a number of assertion checks are
- enabled that will catch more memory errors. You probably won't be
- able to make much sense of the actual assertion errors, but they
- should help you locate incorrectly overwritten memory. The
- checking is fairly extensive, and will slow down execution
- noticeably. Calling malloc_stats or mallinfo with DEBUG set will
- attempt to check every non-mmapped allocated and free chunk in the
- course of computing the summmaries. (By nature, mmapped regions
- cannot be checked very much automatically.)
-
- Setting DEBUG may also be helpful if you are trying to modify
- this code. The assertions in the check routines spell out in more
- detail the assumptions and invariants underlying the algorithms.
-
-*/
-
-#if DEBUG
-#include <assert.h>
-#else
-#define assert(x) ((void)0)
-#endif
-
-
-/*
- INTERNAL_SIZE_T is the word-size used for internal bookkeeping
- of chunk sizes. On a 64-bit machine, you can reduce malloc
- overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
- at the expense of not being able to handle requests greater than
- 2^31. This limitation is hardly ever a concern; you are encouraged
- to set this. However, the default version is the same as size_t.
-*/
-
-#ifndef INTERNAL_SIZE_T
-#define INTERNAL_SIZE_T size_t
-#endif
-
-/*
- REALLOC_ZERO_BYTES_FREES should be set if a call to
- realloc with zero bytes should be the same as a call to free.
- Some people think it should. Otherwise, since this malloc
- returns a unique pointer for malloc(0), so does realloc(p, 0).
-*/
-
-
-/* #define REALLOC_ZERO_BYTES_FREES */
-
-
-/*
- WIN32 causes an emulation of sbrk to be compiled in
- mmap-based options are not currently supported in WIN32.
-*/
-
-/* #define WIN32 */
-#ifdef WIN32
-#define MORECORE wsbrk
-#define HAVE_MMAP 0
-
-#define LACKS_UNISTD_H
-#define LACKS_SYS_PARAM_H
-
-/*
- Include 'windows.h' to get the necessary declarations for the
- Microsoft Visual C++ data structures and routines used in the 'sbrk'
- emulation.
-
- Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft
- Visual C++ header files are included.
-*/
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#endif
-
-
-/*
- HAVE_MEMCPY should be defined if you are not otherwise using
- ANSI STD C, but still have memcpy and memset in your C library
- and want to use them in calloc and realloc. Otherwise simple
- macro versions are defined here.
-
- USE_MEMCPY should be defined as 1 if you actually want to
- have memset and memcpy called. People report that the macro
- versions are often enough faster than libc versions on many
- systems that it is better to use them.
-
-*/
-
-#define HAVE_MEMCPY
-
-#ifndef USE_MEMCPY
-#ifdef HAVE_MEMCPY
-#define USE_MEMCPY 1
-#else
-#define USE_MEMCPY 0
-#endif
-#endif
-
-#if (__STD_C || defined(HAVE_MEMCPY))
-
-#if __STD_C
-void* memset(void*, int, size_t);
-void* memcpy(void*, const void*, size_t);
-#else
-#ifdef WIN32
-/* On Win32 platforms, 'memset()' and 'memcpy()' are already declared in */
-/* 'windows.h' */
-#else
-Void_t* memset();
-Void_t* memcpy();
-#endif
-#endif
-#endif
-
-#if USE_MEMCPY
-
-/* The following macros are only invoked with (2n+1)-multiples of
- INTERNAL_SIZE_T units, with a positive integer n. This is exploited
- for fast inline execution when n is small. */
-
-#define MALLOC_ZERO(charp, nbytes) \
-do { \
- INTERNAL_SIZE_T mzsz = (nbytes); \
- if(mzsz <= 9*sizeof(mzsz)) { \
- INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \
- if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \
- *mz++ = 0; \
- if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \
- *mz++ = 0; \
- if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \
- *mz++ = 0; }}} \
- *mz++ = 0; \
- *mz++ = 0; \
- *mz = 0; \
- } else memset((charp), 0, mzsz); \
-} while(0)
-
-#define MALLOC_COPY(dest,src,nbytes) \
-do { \
- INTERNAL_SIZE_T mcsz = (nbytes); \
- if(mcsz <= 9*sizeof(mcsz)) { \
- INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \
- INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \
- if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
- *mcdst++ = *mcsrc++; \
- if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
- *mcdst++ = *mcsrc++; \
- if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
- *mcdst++ = *mcsrc++; }}} \
- *mcdst++ = *mcsrc++; \
- *mcdst++ = *mcsrc++; \
- *mcdst = *mcsrc ; \
- } else memcpy(dest, src, mcsz); \
-} while(0)
-
-#else /* !USE_MEMCPY */
-
-/* Use Duff's device for good zeroing/copying performance. */
-
-#define MALLOC_ZERO(charp, nbytes) \
-do { \
- INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \
- long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
- if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
- switch (mctmp) { \
- case 0: for(;;) { *mzp++ = 0; \
- case 7: *mzp++ = 0; \
- case 6: *mzp++ = 0; \
- case 5: *mzp++ = 0; \
- case 4: *mzp++ = 0; \
- case 3: *mzp++ = 0; \
- case 2: *mzp++ = 0; \
- case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
- } \
-} while(0)
-
-#define MALLOC_COPY(dest,src,nbytes) \
-do { \
- INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \
- INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \
- long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
- if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
- switch (mctmp) { \
- case 0: for(;;) { *mcdst++ = *mcsrc++; \
- case 7: *mcdst++ = *mcsrc++; \
- case 6: *mcdst++ = *mcsrc++; \
- case 5: *mcdst++ = *mcsrc++; \
- case 4: *mcdst++ = *mcsrc++; \
- case 3: *mcdst++ = *mcsrc++; \
- case 2: *mcdst++ = *mcsrc++; \
- case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
- } \
-} while(0)
-
-#endif
-
-
-/*
- Define HAVE_MMAP to optionally make malloc() use mmap() to
- allocate very large blocks. These will be returned to the
- operating system immediately after a free().
-*/
-
-#ifndef HAVE_MMAP
-#define HAVE_MMAP 1
-#endif
-
-/*
- Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
- large blocks. This is currently only possible on Linux with
- kernel versions newer than 1.3.77.
-*/
-
-#ifndef HAVE_MREMAP
-#ifdef INTERNAL_LINUX_C_LIB
-#define HAVE_MREMAP 1
-#else
-#define HAVE_MREMAP 0
-#endif
-#endif
-
-#if HAVE_MMAP
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-
-#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-
-#endif /* HAVE_MMAP */
-
-/*
- Access to system page size. To the extent possible, this malloc
- manages memory from the system in page-size units.
-
- The following mechanics for getpagesize were adapted from
- bsd/gnu getpagesize.h
-*/
-
-#ifndef LACKS_UNISTD_H
-# include <unistd.h>
-#endif
-
-#ifndef malloc_getpagesize
-# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
-# ifndef _SC_PAGE_SIZE
-# define _SC_PAGE_SIZE _SC_PAGESIZE
-# endif
-# endif
-# ifdef _SC_PAGE_SIZE
-# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
-# else
-# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
- extern size_t getpagesize();
-# define malloc_getpagesize getpagesize()
-# else
-# ifdef WIN32
-# define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */
-# else
-# ifndef LACKS_SYS_PARAM_H
-# include <sys/param.h>
-# endif
-# ifdef EXEC_PAGESIZE
-# define malloc_getpagesize EXEC_PAGESIZE
-# else
-# ifdef NBPG
-# ifndef CLSIZE
-# define malloc_getpagesize NBPG
-# else
-# define malloc_getpagesize (NBPG * CLSIZE)
-# endif
-# else
-# ifdef NBPC
-# define malloc_getpagesize NBPC
-# else
-# ifdef PAGESIZE
-# define malloc_getpagesize PAGESIZE
-# else
-# define malloc_getpagesize (4096) /* just guess */
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-#endif
-
-
-/*
-
- This version of malloc supports the standard SVID/XPG mallinfo
- routine that returns a struct containing the same kind of
- information you can get from malloc_stats. It should work on
- any SVID/XPG compliant system that has a /usr/include/malloc.h
- defining struct mallinfo. (If you'd like to install such a thing
- yourself, cut out the preliminary declarations as described above
- and below and save them in a malloc.h file. But there's no
- compelling reason to bother to do this.)
-
- The main declaration needed is the mallinfo struct that is returned
- (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a
- bunch of fields, most of which are not even meaningful in this
- version of malloc. Some of these fields are are instead filled by
- mallinfo() with other numbers that might possibly be of interest.
-
- HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
- /usr/include/malloc.h file that includes a declaration of struct
- mallinfo. If so, it is included; else an SVID2/XPG2 compliant
- version is declared below. These must be precisely the same for
- mallinfo() to work.
-
-*/
-
-/* #define HAVE_USR_INCLUDE_MALLOC_H */
-
-#if HAVE_USR_INCLUDE_MALLOC_H
-#include "/usr/include/malloc.h"
-#else
-
-/* SVID2/XPG mallinfo structure */
-
-struct mallinfo {
- int arena; /* total space allocated from system */
- int ordblks; /* number of non-inuse chunks */
- int smblks; /* unused -- always zero */
- int hblks; /* number of mmapped regions */
- int hblkhd; /* total space in mmapped regions */
- int usmblks; /* unused -- always zero */
- int fsmblks; /* unused -- always zero */
- int uordblks; /* total allocated space */
- int fordblks; /* total non-inuse space */
- int keepcost; /* top-most, releasable (via malloc_trim) space */
-};
-
-/* SVID2/XPG mallopt options */
-
-#define M_MXFAST 1 /* UNUSED in this malloc */
-#define M_NLBLKS 2 /* UNUSED in this malloc */
-#define M_GRAIN 3 /* UNUSED in this malloc */
-#define M_KEEP 4 /* UNUSED in this malloc */
-
-#endif
-
-/* mallopt options that actually do something */
-
-#define M_TRIM_THRESHOLD -1
-#define M_TOP_PAD -2
-#define M_MMAP_THRESHOLD -3
-#define M_MMAP_MAX -4
-
-
-#ifndef DEFAULT_TRIM_THRESHOLD
-#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
-#endif
-
-/*
- M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
- to keep before releasing via malloc_trim in free().
-
- Automatic trimming is mainly useful in long-lived programs.
- Because trimming via sbrk can be slow on some systems, and can
- sometimes be wasteful (in cases where programs immediately
- afterward allocate more large chunks) the value should be high
- enough so that your overall system performance would improve by
- releasing.
-
- The trim threshold and the mmap control parameters (see below)
- can be traded off with one another. Trimming and mmapping are
- two different ways of releasing unused memory back to the
- system. Between these two, it is often possible to keep
- system-level demands of a long-lived program down to a bare
- minimum. For example, in one test suite of sessions measuring
- the XF86 X server on Linux, using a trim threshold of 128K and a
- mmap threshold of 192K led to near-minimal long term resource
- consumption.
-
- If you are using this malloc in a long-lived program, it should
- pay to experiment with these values. As a rough guide, you
- might set to a value close to the average size of a process
- (program) running on your system. Releasing this much memory
- would allow such a process to run in memory. Generally, it's
- worth it to tune for trimming rather tham memory mapping when a
- program undergoes phases where several large chunks are
- allocated and released in ways that can reuse each other's
- storage, perhaps mixed with phases where there are no such
- chunks at all. And in well-behaved long-lived programs,
- controlling release of large blocks via trimming versus mapping
- is usually faster.
-
- However, in most programs, these parameters serve mainly as
- protection against the system-level effects of carrying around
- massive amounts of unneeded memory. Since frequent calls to
- sbrk, mmap, and munmap otherwise degrade performance, the default
- parameters are set to relatively high values that serve only as
- safeguards.
-
- The default trim value is high enough to cause trimming only in
- fairly extreme (by current memory consumption standards) cases.
- It must be greater than page size to have any useful effect. To
- disable trimming completely, you can set to (unsigned long)(-1);
-
-
-*/
-
-
-#ifndef DEFAULT_TOP_PAD
-#define DEFAULT_TOP_PAD (0)
-#endif
-
-/*
- M_TOP_PAD is the amount of extra `padding' space to allocate or
- retain whenever sbrk is called. It is used in two ways internally:
-
- * When sbrk is called to extend the top of the arena to satisfy
- a new malloc request, this much padding is added to the sbrk
- request.
-
- * When malloc_trim is called automatically from free(),
- it is used as the `pad' argument.
-
- In both cases, the actual amount of padding is rounded
- so that the end of the arena is always a system page boundary.
-
- The main reason for using padding is to avoid calling sbrk so
- often. Having even a small pad greatly reduces the likelihood
- that nearly every malloc request during program start-up (or
- after trimming) will invoke sbrk, which needlessly wastes
- time.
-
- Automatic rounding-up to page-size units is normally sufficient
- to avoid measurable overhead, so the default is 0. However, in
- systems where sbrk is relatively slow, it can pay to increase
- this value, at the expense of carrying around more memory than
- the program needs.
-
-*/
-
-
-#ifndef DEFAULT_MMAP_THRESHOLD
-#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
-#endif
-
-/*
-
- M_MMAP_THRESHOLD is the request size threshold for using mmap()
- to service a request. Requests of at least this size that cannot
- be allocated using already-existing space will be serviced via mmap.
- (If enough normal freed space already exists it is used instead.)
-
- Using mmap segregates relatively large chunks of memory so that
- they can be individually obtained and released from the host
- system. A request serviced through mmap is never reused by any
- other request (at least not directly; the system may just so
- happen to remap successive requests to the same locations).
-
- Segregating space in this way has the benefit that mmapped space
- can ALWAYS be individually released back to the system, which
- helps keep the system level memory demands of a long-lived
- program low. Mapped memory can never become `locked' between
- other chunks, as can happen with normally allocated chunks, which
- menas that even trimming via malloc_trim would not release them.
-
- However, it has the disadvantages that:
-
- 1. The space cannot be reclaimed, consolidated, and then
- used to service later requests, as happens with normal chunks.
- 2. It can lead to more wastage because of mmap page alignment
- requirements
- 3. It causes malloc performance to be more dependent on host
- system memory management support routines which may vary in
- implementation quality and may impose arbitrary
- limitations. Generally, servicing a request via normal
- malloc steps is faster than going through a system's mmap.
-
- All together, these considerations should lead you to use mmap
- only for relatively large requests.
-
-
-*/
-
-
-#ifndef DEFAULT_MMAP_MAX
-#if HAVE_MMAP
-#define DEFAULT_MMAP_MAX (64)
-#else
-#define DEFAULT_MMAP_MAX (0)
-#endif
-#endif
-
-/*
- M_MMAP_MAX is the maximum number of requests to simultaneously
- service using mmap. This parameter exists because:
-
- 1. Some systems have a limited number of internal tables for
- use by mmap.
- 2. In most systems, overreliance on mmap can degrade overall
- performance.
- 3. If a program allocates many large regions, it is probably
- better off using normal sbrk-based allocation routines that
- can reclaim and reallocate normal heap memory. Using a
- small value allows transition into this mode after the
- first few allocations.
-
- Setting to 0 disables all use of mmap. If HAVE_MMAP is not set,
- the default value is 0, and attempts to set it to non-zero values
- in mallopt will fail.
-*/
-
-
-/*
- USE_DL_PREFIX will prefix all public routines with the string 'dl'.
- Useful to quickly avoid procedure declaration conflicts and linker
- symbol conflicts with existing memory allocation routines.
-
-*/
-
-/* #define USE_DL_PREFIX */
-
-
-/*
-
- Special defines for linux libc
-
- Except when compiled using these special defines for Linux libc
- using weak aliases, this malloc is NOT designed to work in
- multithreaded applications. No semaphores or other concurrency
- control are provided to ensure that multiple malloc or free calls
- don't run at the same time, which could be disasterous. A single
- semaphore could be used across malloc, realloc, and free (which is
- essentially the effect of the linux weak alias approach). It would
- be hard to obtain finer granularity.
-
-*/
-
-
-#ifdef INTERNAL_LINUX_C_LIB
-
-#if __STD_C
-
-Void_t * __default_morecore_init (ptrdiff_t);
-Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
-
-#else
-
-Void_t * __default_morecore_init ();
-Void_t *(*__morecore)() = __default_morecore_init;
-
-#endif
-
-#define MORECORE (*__morecore)
-#define MORECORE_FAILURE 0
-#define MORECORE_CLEARS 1
-
-#else /* INTERNAL_LINUX_C_LIB */
-
-#if __STD_C
-extern Void_t* sbrk(ptrdiff_t);
-#else
-extern Void_t* sbrk();
-#endif
-
-#ifndef MORECORE
-#define MORECORE sbrk
-#endif
-
-#ifndef MORECORE_FAILURE
-#define MORECORE_FAILURE -1
-#endif
-
-#ifndef MORECORE_CLEARS
-#define MORECORE_CLEARS 1
-#endif
-
-#endif /* INTERNAL_LINUX_C_LIB */
-
-#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
-
-#define cALLOc __libc_calloc
-#define fREe __libc_free
-#define mALLOc __libc_malloc
-#define mEMALIGn __libc_memalign
-#define rEALLOc __libc_realloc
-#define vALLOc __libc_valloc
-#define pvALLOc __libc_pvalloc
-#define mALLINFo __libc_mallinfo
-#define mALLOPt __libc_mallopt
-
-#pragma weak calloc = __libc_calloc
-#pragma weak free = __libc_free
-#pragma weak cfree = __libc_free
-#pragma weak malloc = __libc_malloc
-#pragma weak memalign = __libc_memalign
-#pragma weak realloc = __libc_realloc
-#pragma weak valloc = __libc_valloc
-#pragma weak pvalloc = __libc_pvalloc
-#pragma weak mallinfo = __libc_mallinfo
-#pragma weak mallopt = __libc_mallopt
-
-#else
-
-#ifdef USE_DL_PREFIX
-#define cALLOc dlcalloc
-#define fREe dlfree
-#define mALLOc dlmalloc
-#define mEMALIGn dlmemalign
-#define rEALLOc dlrealloc
-#define vALLOc dlvalloc
-#define pvALLOc dlpvalloc
-#define mALLINFo dlmallinfo
-#define mALLOPt dlmallopt
-#else /* USE_DL_PREFIX */
-#define cALLOc calloc
-#define fREe free
-#define mALLOc malloc
-#define mEMALIGn memalign
-#define rEALLOc realloc
-#define vALLOc valloc
-#define pvALLOc pvalloc
-#define mALLINFo mallinfo
-#define mALLOPt mallopt
-#endif /* USE_DL_PREFIX */
-
-#endif
-
-/* Public routines */
-
-#if __STD_C
-
-Void_t* mALLOc(size_t);
-void fREe(Void_t*);
-Void_t* rEALLOc(Void_t*, size_t);
-Void_t* mEMALIGn(size_t, size_t);
-Void_t* vALLOc(size_t);
-Void_t* pvALLOc(size_t);
-Void_t* cALLOc(size_t, size_t);
-void cfree(Void_t*);
-int malloc_trim(size_t);
-size_t malloc_usable_size(Void_t*);
-void malloc_stats();
-int mALLOPt(int, int);
-struct mallinfo mALLINFo(void);
-#else
-Void_t* mALLOc();
-void fREe();
-Void_t* rEALLOc();
-Void_t* mEMALIGn();
-Void_t* vALLOc();
-Void_t* pvALLOc();
-Void_t* cALLOc();
-void cfree();
-int malloc_trim();
-size_t malloc_usable_size();
-void malloc_stats();
-int mALLOPt();
-struct mallinfo mALLINFo();
-#endif
-
-
-#ifdef __cplusplus
-}; /* end of extern "C" */
-#endif
-
-/* ---------- To make a malloc.h, end cutting here ------------ */
-
-
-/*
- Emulation of sbrk for WIN32
- All code within the ifdef WIN32 is untested by me.
-
- Thanks to Martin Fong and others for supplying this.
-*/
-
-
-#ifdef WIN32
-
-#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \
-~(malloc_getpagesize-1))
-#define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1))
-
-/* resrve 64MB to insure large contiguous space */
-#define RESERVED_SIZE (1024*1024*64)
-#define NEXT_SIZE (2048*1024)
-#define TOP_MEMORY ((unsigned long)2*1024*1024*1024)
-
-struct GmListElement;
-typedef struct GmListElement GmListElement;
-
-struct GmListElement
-{
- GmListElement* next;
- void* base;
-};
-
-static GmListElement* head = 0;
-static unsigned int gNextAddress = 0;
-static unsigned int gAddressBase = 0;
-static unsigned int gAllocatedSize = 0;
-
-static
-GmListElement* makeGmListElement (void* bas)
-{
- GmListElement* this;
- this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement));
- assert (this);
- if (this)
- {
- this->base = bas;
- this->next = head;
- head = this;
- }
- return this;
-}
-
-void gcleanup ()
-{
- BOOL rval;
- assert ( (head == NULL) || (head->base == (void*)gAddressBase));
- if (gAddressBase && (gNextAddress - gAddressBase))
- {
- rval = VirtualFree ((void*)gAddressBase,
- gNextAddress - gAddressBase,
- MEM_DECOMMIT);
- assert (rval);
- }
- while (head)
- {
- GmListElement* next = head->next;
- rval = VirtualFree (head->base, 0, MEM_RELEASE);
- assert (rval);
- LocalFree (head);
- head = next;
- }
-}
-
-static
-void* findRegion (void* start_address, unsigned long size)
-{
- MEMORY_BASIC_INFORMATION info;
- if (size >= TOP_MEMORY) return NULL;
-
- while ((unsigned long)start_address + size < TOP_MEMORY)
- {
- VirtualQuery (start_address, &info, sizeof (info));
- if ((info.State == MEM_FREE) && (info.RegionSize >= size))
- return start_address;
- else
- {
- /* Requested region is not available so see if the */
- /* next region is available. Set 'start_address' */
- /* to the next region and call 'VirtualQuery()' */
- /* again. */
-
- start_address = (char*)info.BaseAddress + info.RegionSize;
-
- /* Make sure we start looking for the next region */
- /* on the *next* 64K boundary. Otherwise, even if */
- /* the new region is free according to */
- /* 'VirtualQuery()', the subsequent call to */
- /* 'VirtualAlloc()' (which follows the call to */
- /* this routine in 'wsbrk()') will round *down* */
- /* the requested address to a 64K boundary which */
- /* we already know is an address in the */
- /* unavailable region. Thus, the subsequent call */
- /* to 'VirtualAlloc()' will fail and bring us back */
- /* here, causing us to go into an infinite loop. */
-
- start_address =
- (void *) AlignPage64K((unsigned long) start_address);
- }
- }
- return NULL;
-
-}
-
-
-void* wsbrk (long size)
-{
- void* tmp;
- if (size > 0)
- {
- if (gAddressBase == 0)
- {
- gAllocatedSize = max (RESERVED_SIZE, AlignPage (size));
- gNextAddress = gAddressBase =
- (unsigned int)VirtualAlloc (NULL, gAllocatedSize,
- MEM_RESERVE, PAGE_NOACCESS);
- } else if (AlignPage (gNextAddress + size) > (gAddressBase +
-gAllocatedSize))
- {
- long new_size = max (NEXT_SIZE, AlignPage (size));
- void* new_address = (void*)(gAddressBase+gAllocatedSize);
- do
- {
- new_address = findRegion (new_address, new_size);
-
- if (new_address == 0)
- return (void*)-1;
-
- gAddressBase = gNextAddress =
- (unsigned int)VirtualAlloc (new_address, new_size,
- MEM_RESERVE, PAGE_NOACCESS);
- /* repeat in case of race condition */
- /* The region that we found has been snagged */
- /* by another thread */
- }
- while (gAddressBase == 0);
-
- assert (new_address == (void*)gAddressBase);
-
- gAllocatedSize = new_size;
-
- if (!makeGmListElement ((void*)gAddressBase))
- return (void*)-1;
- }
- if ((size + gNextAddress) > AlignPage (gNextAddress))
- {
- void* res;
- res = VirtualAlloc ((void*)AlignPage (gNextAddress),
- (size + gNextAddress -
- AlignPage (gNextAddress)),
- MEM_COMMIT, PAGE_READWRITE);
- if (res == 0)
- return (void*)-1;
- }
- tmp = (void*)gNextAddress;
- gNextAddress = (unsigned int)tmp + size;
- return tmp;
- }
- else if (size < 0)
- {
- unsigned int alignedGoal = AlignPage (gNextAddress + size);
- /* Trim by releasing the virtual memory */
- if (alignedGoal >= gAddressBase)
- {
- VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal,
- MEM_DECOMMIT);
- gNextAddress = gNextAddress + size;
- return (void*)gNextAddress;
- }
- else
- {
- VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase,
- MEM_DECOMMIT);
- gNextAddress = gAddressBase;
- return (void*)-1;
- }
- }
- else
- {
- return (void*)gNextAddress;
- }
-}
-
-#endif
-
-\f
-
-/*
- Type declarations
-*/
-
-
-struct malloc_chunk
-{
- INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
- INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
- struct malloc_chunk* fd; /* double links -- used only if free. */
- struct malloc_chunk* bk;
-};
-
-typedef struct malloc_chunk* mchunkptr;
-
-/*
-
- malloc_chunk details:
-
- (The following includes lightly edited explanations by Colin Plumb.)
-
- Chunks of memory are maintained using a `boundary tag' method as
- described in e.g., Knuth or Standish. (See the paper by Paul
- Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
- survey of such techniques.) Sizes of free chunks are stored both
- in the front of each chunk and at the end. This makes
- consolidating fragmented chunks into bigger chunks very fast. The
- size fields also hold bits representing whether chunks are free or
- in use.
-
- An allocated chunk looks like this:
-
-
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of previous chunk, if allocated | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of chunk, in bytes |P|
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | User data starts here... .
- . .
- . (malloc_usable_space() bytes) .
- . |
-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of chunk |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-
- Where "chunk" is the front of the chunk for the purpose of most of
- the malloc code, but "mem" is the pointer that is returned to the
- user. "Nextchunk" is the beginning of the next contiguous chunk.
-
- Chunks always begin on even word boundries, so the mem portion
- (which is returned to the user) is also on an even word boundary, and
- thus double-word aligned.
-
- Free chunks are stored in circular doubly-linked lists, and look like this:
-
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of previous chunk |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- `head:' | Size of chunk, in bytes |P|
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Forward pointer to next chunk in list |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Back pointer to previous chunk in list |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Unused space (may be 0 bytes long) .
- . .
- . |
-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- `foot:' | Size of chunk, in bytes |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- The P (PREV_INUSE) bit, stored in the unused low-order bit of the
- chunk size (which is always a multiple of two words), is an in-use
- bit for the *previous* chunk. If that bit is *clear*, then the
- word before the current chunk size contains the previous chunk
- size, and can be used to find the front of the previous chunk.
- (The very first chunk allocated always has this bit set,
- preventing access to non-existent (or non-owned) memory.)
-
- Note that the `foot' of the current chunk is actually represented
- as the prev_size of the NEXT chunk. (This makes it easier to
- deal with alignments etc).
-
- The two exceptions to all this are
-
- 1. The special chunk `top', which doesn't bother using the
- trailing size field since there is no
- next contiguous chunk that would have to index off it. (After
- initialization, `top' is forced to always exist. If it would
- become less than MINSIZE bytes long, it is replenished via
- malloc_extend_top.)
-
- 2. Chunks allocated via mmap, which have the second-lowest-order
- bit (IS_MMAPPED) set in their size fields. Because they are
- never merged or traversed from any other chunk, they have no
- foot size or inuse information.
-
- Available chunks are kept in any of several places (all declared below):
-
- * `av': An array of chunks serving as bin headers for consolidated
- chunks. Each bin is doubly linked. The bins are approximately
- proportionally (log) spaced. There are a lot of these bins
- (128). This may look excessive, but works very well in
- practice. All procedures maintain the invariant that no
- consolidated chunk physically borders another one. Chunks in
- bins are kept in size order, with ties going to the
- approximately least recently used chunk.
-
- The chunks in each bin are maintained in decreasing sorted order by
- size. This is irrelevant for the small bins, which all contain
- the same-sized chunks, but facilitates best-fit allocation for
- larger chunks. (These lists are just sequential. Keeping them in
- order almost never requires enough traversal to warrant using
- fancier ordered data structures.) Chunks of the same size are
- linked with the most recently freed at the front, and allocations
- are taken from the back. This results in LRU or FIFO allocation
- order, which tends to give each chunk an equal opportunity to be
- consolidated with adjacent freed chunks, resulting in larger free
- chunks and less fragmentation.
-
- * `top': The top-most available chunk (i.e., the one bordering the
- end of available memory) is treated specially. It is never
- included in any bin, is used only if no other chunk is
- available, and is released back to the system if it is very
- large (see M_TRIM_THRESHOLD).
-
- * `last_remainder': A bin holding only the remainder of the
- most recently split (non-top) chunk. This bin is checked
- before other non-fitting chunks, so as to provide better
- locality for runs of sequentially allocated chunks.
-
- * Implicitly, through the host system's memory mapping tables.
- If supported, requests greater than a threshold are usually
- serviced via calls to mmap, and then later released via munmap.
-
-*/
-
-
-\f
-
-
-/* sizes, alignments */
-
-#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
-#define MALLOC_ALIGNMENT (SIZE_SZ + SIZE_SZ)
-#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
-#define MINSIZE (sizeof(struct malloc_chunk))
-
-/* conversion from malloc headers to user pointers, and back */
-
-#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ))
-#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
-
-/* pad request bytes into a usable size */
-
-#define request2size(req) \
- (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
- (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \
- (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
-
-/* Check if m has acceptable alignment */
-
-#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
-
-
-\f
-
-/*
- Physical chunk operations
-*/
-
-
-/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
-
-#define PREV_INUSE 0x1
-
-/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
-
-#define IS_MMAPPED 0x2
-
-/* Bits to mask off when extracting size */
-
-#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
-
-
-/* Ptr to next physical malloc_chunk. */
-
-#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
-
-/* Ptr to previous physical malloc_chunk */
-
-#define prev_chunk(p)\
- ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
-
-
-/* Treat space at ptr + offset as a chunk */
-
-#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
-
-
-\f
-
-/*
- Dealing with use bits
-*/
-
-/* extract p's inuse bit */
-
-#define inuse(p)\
-((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
-
-/* extract inuse bit of previous chunk */
-
-#define prev_inuse(p) ((p)->size & PREV_INUSE)
-
-/* check for mmap()'ed chunk */
-
-#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
-
-/* set/clear chunk as in use without otherwise disturbing */
-
-#define set_inuse(p)\
-((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
-
-#define clear_inuse(p)\
-((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
-
-/* check/set/clear inuse bits in known places */
-
-#define inuse_bit_at_offset(p, s)\
- (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
-
-#define set_inuse_bit_at_offset(p, s)\
- (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
-
-#define clear_inuse_bit_at_offset(p, s)\
- (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
-
-
-\f
-
-/*
- Dealing with size fields
-*/
-
-/* Get size, ignoring use bits */
-
-#define chunksize(p) ((p)->size & ~(SIZE_BITS))
-
-/* Set size at head, without disturbing its use bit */
-
-#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
-
-/* Set size/use ignoring previous bits in header */
-
-#define set_head(p, s) ((p)->size = (s))
-
-/* Set size at footer (only when chunk is not in use) */
-
-#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
-
-
-\f
-
-
-/*
- Bins
-
- The bins, `av_' are an array of pairs of pointers serving as the
- heads of (initially empty) doubly-linked lists of chunks, laid out
- in a way so that each pair can be treated as if it were in a
- malloc_chunk. (This way, the fd/bk offsets for linking bin heads
- and chunks are the same).
-
- Bins for sizes < 512 bytes contain chunks of all the same size, spaced
- 8 bytes apart. Larger bins are approximately logarithmically
- spaced. (See the table below.) The `av_' array is never mentioned
- directly in the code, but instead via bin access macros.
-
- Bin layout:
-
- 64 bins of size 8
- 32 bins of size 64
- 16 bins of size 512
- 8 bins of size 4096
- 4 bins of size 32768
- 2 bins of size 262144
- 1 bin of size what's left
-
- There is actually a little bit of slop in the numbers in bin_index
- for the sake of speed. This makes no difference elsewhere.
-
- The special chunks `top' and `last_remainder' get their own bins,
- (this is implemented via yet more trickery with the av_ array),
- although `top' is never properly linked to its bin since it is
- always handled specially.
-
-*/
-
-#define NAV 128 /* number of bins */
-
-typedef struct malloc_chunk* mbinptr;
-
-/* access macros */
-
-#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
-#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
-#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
-
-/*
- The first 2 bins are never indexed. The corresponding av_ cells are instead
- used for bookkeeping. This is not to save space, but to simplify
- indexing, maintain locality, and avoid some initialization tests.
-*/
-
-#define top (bin_at(0)->fd) /* The topmost chunk */
-#define last_remainder (bin_at(1)) /* remainder from last split */
-
-
-/*
- Because top initially points to its own bin with initial
- zero size, thus forcing extension on the first malloc request,
- we avoid having any special code in malloc to check whether
- it even exists yet. But we still need to in malloc_extend_top.
-*/
-
-#define initial_top ((mchunkptr)(bin_at(0)))
-
-/* Helper macro to initialize bins */
-
-#define IAV(i) bin_at(i), bin_at(i)
-
-static mbinptr av_[NAV * 2 + 2] = {
- 0, 0,
- IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7),
- IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15),
- IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23),
- IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31),
- IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39),
- IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47),
- IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55),
- IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63),
- IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71),
- IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79),
- IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87),
- IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95),
- IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103),
- IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
- IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
- IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
-};
-
-\f
-
-/* field-extraction macros */
-
-#define first(b) ((b)->fd)
-#define last(b) ((b)->bk)
-
-/*
- Indexing into bins
-*/
-
-#define bin_index(sz) \
-(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \
- ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \
- ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \
- ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \
- ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \
- ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
- 126)
-/*
- bins for chunks < 512 are all spaced 8 bytes apart, and hold
- identically sized chunks. This is exploited in malloc.
-*/
-
-#define MAX_SMALLBIN 63
-#define MAX_SMALLBIN_SIZE 512
-#define SMALLBIN_WIDTH 8
-
-#define smallbin_index(sz) (((unsigned long)(sz)) >> 3)
-
-/*
- Requests are `small' if both the corresponding and the next bin are small
-*/
-
-#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
-
-\f
-
-/*
- To help compensate for the large number of bins, a one-level index
- structure is used for bin-by-bin searching. `binblocks' is a
- one-word bitvector recording whether groups of BINBLOCKWIDTH bins
- have any (possibly) non-empty bins, so they can be skipped over
- all at once during during traversals. The bits are NOT always
- cleared as soon as all bins in a block are empty, but instead only
- when all are noticed to be empty during traversal in malloc.
-*/
-
-#define BINBLOCKWIDTH 4 /* bins per block */
-
-#define binblocks (bin_at(0)->size) /* bitvector of nonempty blocks */
-
-/* bin<->block macros */
-
-#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH))
-#define mark_binblock(ii) (binblocks |= idx2binblock(ii))
-#define clear_binblock(ii) (binblocks &= ~(idx2binblock(ii)))
-
-
-\f
-
-
-/* Other static bookkeeping data */
-
-/* variables holding tunable values */
-
-static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD;
-static unsigned long top_pad = DEFAULT_TOP_PAD;
-static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX;
-static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD;
-
-/* The first value returned from sbrk */
-static char* sbrk_base = (char*)(-1);
-
-/* The maximum memory obtained from system via sbrk */
-static unsigned long max_sbrked_mem = 0;
-
-/* The maximum via either sbrk or mmap */
-static unsigned long max_total_mem = 0;
-
-/* internal working copy of mallinfo */
-static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
-/* The total memory obtained from system via sbrk */
-#define sbrked_mem (current_mallinfo.arena)
-
-/* Tracking mmaps */
-
-static unsigned int n_mmaps = 0;
-static unsigned int max_n_mmaps = 0;
-static unsigned long mmapped_mem = 0;
-static unsigned long max_mmapped_mem = 0;
-
-\f
-
-/*
- Debugging support
-*/
-
-#if DEBUG
-
-
-/*
- These routines make a number of assertions about the states
- of data structures that should be true at all times. If any
- are not true, it's very likely that a user program has somehow
- trashed memory. (It's also possible that there is a coding error
- in malloc. In which case, please report it!)
-*/
-
-#if __STD_C
-static void do_check_chunk(mchunkptr p)
-#else
-static void do_check_chunk(p) mchunkptr p;
-#endif
-{
- INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
-
- /* No checkable chunk is mmapped */
- assert(!chunk_is_mmapped(p));
-
- /* Check for legal address ... */
- assert((char*)p >= sbrk_base);
- if (p != top)
- assert((char*)p + sz <= (char*)top);
- else
- assert((char*)p + sz <= sbrk_base + sbrked_mem);
-
-}
-
-
-#if __STD_C
-static void do_check_free_chunk(mchunkptr p)
-#else
-static void do_check_free_chunk(p) mchunkptr p;
-#endif
-{
- INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
- mchunkptr next = chunk_at_offset(p, sz);
-
- do_check_chunk(p);
-
- /* Check whether it claims to be free ... */
- assert(!inuse(p));
-
- /* Unless a special marker, must have OK fields */
- if ((long)sz >= (long)MINSIZE)
- {
- assert((sz & MALLOC_ALIGN_MASK) == 0);
- assert(aligned_OK(chunk2mem(p)));
- /* ... matching footer field */
- assert(next->prev_size == sz);
- /* ... and is fully consolidated */
- assert(prev_inuse(p));
- assert (next == top || inuse(next));
-
- /* ... and has minimally sane links */
- assert(p->fd->bk == p);
- assert(p->bk->fd == p);
- }
- else /* markers are always of size SIZE_SZ */
- assert(sz == SIZE_SZ);
-}
-
-#if __STD_C
-static void do_check_inuse_chunk(mchunkptr p)
-#else
-static void do_check_inuse_chunk(p) mchunkptr p;
-#endif
-{
- mchunkptr next = next_chunk(p);
- do_check_chunk(p);
-
- /* Check whether it claims to be in use ... */
- assert(inuse(p));
-
- /* ... and is surrounded by OK chunks.
- Since more things can be checked with free chunks than inuse ones,
- if an inuse chunk borders them and debug is on, it's worth doing them.
- */
- if (!prev_inuse(p))
- {
- mchunkptr prv = prev_chunk(p);
- assert(next_chunk(prv) == p);
- do_check_free_chunk(prv);
- }
- if (next == top)
- {
- assert(prev_inuse(next));
- assert(chunksize(next) >= MINSIZE);
- }
- else if (!inuse(next))
- do_check_free_chunk(next);
-
-}
-
-#if __STD_C
-static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
-#else
-static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
-#endif
-{
- INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
- long room = sz - s;
-
- do_check_inuse_chunk(p);
-
- /* Legal size ... */
- assert((long)sz >= (long)MINSIZE);
- assert((sz & MALLOC_ALIGN_MASK) == 0);
- assert(room >= 0);
- assert(room < (long)MINSIZE);
-
- /* ... and alignment */
- assert(aligned_OK(chunk2mem(p)));
-
-
- /* ... and was allocated at front of an available chunk */
- assert(prev_inuse(p));
-
-}
-
-
-#define check_free_chunk(P) do_check_free_chunk(P)
-#define check_inuse_chunk(P) do_check_inuse_chunk(P)
-#define check_chunk(P) do_check_chunk(P)
-#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
-#else
-#define check_free_chunk(P)
-#define check_inuse_chunk(P)
-#define check_chunk(P)
-#define check_malloced_chunk(P,N)
-#endif
-
-\f
-
-/*
- Macro-based internal utilities
-*/
-
-
-/*
- Linking chunks in bin lists.
- Call these only with variables, not arbitrary expressions, as arguments.
-*/
-
-/*
- Place chunk p of size s in its bin, in size order,
- putting it ahead of others of same size.
-*/
-
-
-#define frontlink(P, S, IDX, BK, FD) \
-{ \
- if (S < MAX_SMALLBIN_SIZE) \
- { \
- IDX = smallbin_index(S); \
- mark_binblock(IDX); \
- BK = bin_at(IDX); \
- FD = BK->fd; \
- P->bk = BK; \
- P->fd = FD; \
- FD->bk = BK->fd = P; \
- } \
- else \
- { \
- IDX = bin_index(S); \
- BK = bin_at(IDX); \
- FD = BK->fd; \
- if (FD == BK) mark_binblock(IDX); \
- else \
- { \
- while (FD != BK && S < chunksize(FD)) FD = FD->fd; \
- BK = FD->bk; \
- } \
- P->bk = BK; \
- P->fd = FD; \
- FD->bk = BK->fd = P; \
- } \
-}
-
-
-/* take a chunk off a list */
-
-#define unlink(P, BK, FD) \
-{ \
- BK = P->bk; \
- FD = P->fd; \
- FD->bk = BK; \
- BK->fd = FD; \
-} \
-
-/* Place p as the last remainder */
-
-#define link_last_remainder(P) \
-{ \
- last_remainder->fd = last_remainder->bk = P; \
- P->fd = P->bk = last_remainder; \
-}
-
-/* Clear the last_remainder bin */
-
-#define clear_last_remainder \
- (last_remainder->fd = last_remainder->bk = last_remainder)
-
-
-\f
-
-
-/* Routines dealing with mmap(). */
-
-#if HAVE_MMAP
-
-#if __STD_C
-static mchunkptr mmap_chunk(size_t size)
-#else
-static mchunkptr mmap_chunk(size) size_t size;
-#endif
-{
- size_t page_mask = malloc_getpagesize - 1;
- mchunkptr p;
-
-#ifndef MAP_ANONYMOUS
- static int fd = -1;
-#endif
-
- if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
-
- /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because
- * there is no following chunk whose prev_size field could be used.
- */
- size = (size + SIZE_SZ + page_mask) & ~page_mask;
-
-#ifdef MAP_ANONYMOUS
- p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
-#else /* !MAP_ANONYMOUS */
- if (fd < 0)
- {
- fd = open("/dev/zero", O_RDWR);
- if(fd < 0) return 0;
- }
- p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
-#endif
-
- if(p == (mchunkptr)-1) return 0;
-
- n_mmaps++;
- if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
-
- /* We demand that eight bytes into a page must be 8-byte aligned. */
- assert(aligned_OK(chunk2mem(p)));
-
- /* The offset to the start of the mmapped region is stored
- * in the prev_size field of the chunk; normally it is zero,
- * but that can be changed in memalign().
- */
- p->prev_size = 0;
- set_head(p, size|IS_MMAPPED);
-
- mmapped_mem += size;
- if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
- max_mmapped_mem = mmapped_mem;
- if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
- max_total_mem = mmapped_mem + sbrked_mem;
- return p;
-}
-
-#if __STD_C
-static void munmap_chunk(mchunkptr p)
-#else
-static void munmap_chunk(p) mchunkptr p;
-#endif
-{
- INTERNAL_SIZE_T size = chunksize(p);
- int ret;
-
- assert (chunk_is_mmapped(p));
- assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
- assert((n_mmaps > 0));
- assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
-
- n_mmaps--;
- mmapped_mem -= (size + p->prev_size);
-
- ret = munmap((char *)p - p->prev_size, size + p->prev_size);
-
- /* munmap returns non-zero on failure */
- assert(ret == 0);
-}
-
-#if HAVE_MREMAP
-
-#if __STD_C
-static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
-#else
-static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
-#endif
-{
- size_t page_mask = malloc_getpagesize - 1;
- INTERNAL_SIZE_T offset = p->prev_size;
- INTERNAL_SIZE_T size = chunksize(p);
- char *cp;
-
- assert (chunk_is_mmapped(p));
- assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
- assert((n_mmaps > 0));
- assert(((size + offset) & (malloc_getpagesize-1)) == 0);
-
- /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
- new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask;
-
- cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
-
- if (cp == (char *)-1) return 0;
-
- p = (mchunkptr)(cp + offset);
-
- assert(aligned_OK(chunk2mem(p)));
-
- assert((p->prev_size == offset));
- set_head(p, (new_size - offset)|IS_MMAPPED);
-
- mmapped_mem -= size + offset;
- mmapped_mem += new_size;
- if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
- max_mmapped_mem = mmapped_mem;
- if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
- max_total_mem = mmapped_mem + sbrked_mem;
- return p;
-}
-
-#endif /* HAVE_MREMAP */
-
-#endif /* HAVE_MMAP */
-
-
-\f
-
-/*
- Extend the top-most chunk by obtaining memory from system.
- Main interface to sbrk (but see also malloc_trim).
-*/
-
-#if __STD_C
-static void malloc_extend_top(INTERNAL_SIZE_T nb)
-#else
-static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
-#endif
-{
- char* brk; /* return value from sbrk */
- INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
- INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */
- char* new_brk; /* return of 2nd sbrk call */
- INTERNAL_SIZE_T top_size; /* new size of top chunk */
-
- mchunkptr old_top = top; /* Record state of old top */
- INTERNAL_SIZE_T old_top_size = chunksize(old_top);
- char* old_end = (char*)(chunk_at_offset(old_top, old_top_size));
-
- /* Pad request with top_pad plus minimal overhead */
-
- INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE;
- unsigned long pagesz = malloc_getpagesize;
-
- /* If not the first time through, round to preserve page boundary */
- /* Otherwise, we need to correct to a page size below anyway. */
- /* (We also correct below if an intervening foreign sbrk call.) */
-
- if (sbrk_base != (char*)(-1))
- sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
-
- brk = (char*)(MORECORE (sbrk_size));
-
- /* Fail if sbrk failed or if a foreign sbrk call killed our space */
- if (brk == (char*)(MORECORE_FAILURE) ||
- (brk < old_end && old_top != initial_top))
- return;
-
- sbrked_mem += sbrk_size;
-
- if (brk == old_end) /* can just add bytes to current top */
- {
- top_size = sbrk_size + old_top_size;
- set_head(top, top_size | PREV_INUSE);
- }
- else
- {
- if (sbrk_base == (char*)(-1)) /* First time through. Record base */
- sbrk_base = brk;
- else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */
- sbrked_mem += brk - (char*)old_end;
-
- /* Guarantee alignment of first new chunk made from this space */
- front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
- if (front_misalign > 0)
- {
- correction = (MALLOC_ALIGNMENT) - front_misalign;
- brk += correction;
- }
- else
- correction = 0;
-
- /* Guarantee the next brk will be at a page boundary */
-
- correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) &
- ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size));
-
- /* Allocate correction */
- new_brk = (char*)(MORECORE (correction));
- if (new_brk == (char*)(MORECORE_FAILURE)) return;
-
- sbrked_mem += correction;
-
- top = (mchunkptr)brk;
- top_size = new_brk - brk + correction;
- set_head(top, top_size | PREV_INUSE);
-
- if (old_top != initial_top)
- {
-
- /* There must have been an intervening foreign sbrk call. */
- /* A double fencepost is necessary to prevent consolidation */
-
- /* If not enough space to do this, then user did something very wrong */
- if (old_top_size < MINSIZE)
- {
- set_head(top, PREV_INUSE); /* will force null return from malloc */
- return;
- }
-
- /* Also keep size a multiple of MALLOC_ALIGNMENT */
- old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
- set_head_size(old_top, old_top_size);
- chunk_at_offset(old_top, old_top_size )->size =
- SIZE_SZ|PREV_INUSE;
- chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
- SIZE_SZ|PREV_INUSE;
- /* If possible, release the rest. */
- if (old_top_size >= MINSIZE)
- fREe(chunk2mem(old_top));
- }
- }
-
- if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
- max_sbrked_mem = sbrked_mem;
- if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
- max_total_mem = mmapped_mem + sbrked_mem;
-
- /* We always land on a page boundary */
- assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
-}
-
-
-\f
-
-/* Main public routines */
-
-
-/*
- Malloc Algorthim:
-
- The requested size is first converted into a usable form, `nb'.
- This currently means to add 4 bytes overhead plus possibly more to
- obtain 8-byte alignment and/or to obtain a size of at least
- MINSIZE (currently 16 bytes), the smallest allocatable size.
- (All fits are considered `exact' if they are within MINSIZE bytes.)
-
- From there, the first successful of the following steps is taken:
-
- 1. The bin corresponding to the request size is scanned, and if
- a chunk of exactly the right size is found, it is taken.
-
- 2. The most recently remaindered chunk is used if it is big
- enough. This is a form of (roving) first fit, used only in
- the absence of exact fits. Runs of consecutive requests use
- the remainder of the chunk used for the previous such request
- whenever possible. This limited use of a first-fit style
- allocation strategy tends to give contiguous chunks
- coextensive lifetimes, which improves locality and can reduce
- fragmentation in the long run.
-
- 3. Other bins are scanned in increasing size order, using a
- chunk big enough to fulfill the request, and splitting off
- any remainder. This search is strictly by best-fit; i.e.,
- the smallest (with ties going to approximately the least
- recently used) chunk that fits is selected.
-
- 4. If large enough, the chunk bordering the end of memory
- (`top') is split off. (This use of `top' is in accord with
- the best-fit search rule. In effect, `top' is treated as
- larger (and thus less well fitting) than any other available
- chunk since it can be extended to be as large as necessary
- (up to system limitations).
-
- 5. If the request size meets the mmap threshold and the
- system supports mmap, and there are few enough currently
- allocated mmapped regions, and a call to mmap succeeds,
- the request is allocated via direct memory mapping.
-
- 6. Otherwise, the top of memory is extended by
- obtaining more space from the system (normally using sbrk,
- but definable to anything else via the MORECORE macro).
- Memory is gathered from the system (in system page-sized
- units) in a way that allows chunks obtained across different
- sbrk calls to be consolidated, but does not require
- contiguous memory. Thus, it should be safe to intersperse
- mallocs with other sbrk calls.
-
-
- All allocations are made from the the `lowest' part of any found
- chunk. (The implementation invariant is that prev_inuse is
- always true of any allocated chunk; i.e., that each allocated
- chunk borders either a previously allocated and still in-use chunk,
- or the base of its memory arena.)
-
-*/
-
-#if __STD_C
-Void_t* mALLOc(size_t bytes)
-#else
-Void_t* mALLOc(bytes) size_t bytes;
-#endif
-{
- mchunkptr victim; /* inspected/selected chunk */
- INTERNAL_SIZE_T victim_size; /* its size */
- int idx; /* index for bin traversal */
- mbinptr bin; /* associated bin */
- mchunkptr remainder; /* remainder from a split */
- long remainder_size; /* its size */
- int remainder_index; /* its bin index */
- unsigned long block; /* block traverser bit */
- int startidx; /* first bin of a traversed block */
- mchunkptr fwd; /* misc temp for linking */
- mchunkptr bck; /* misc temp for linking */
- mbinptr q; /* misc temp */
-
- INTERNAL_SIZE_T nb;
-
- if ((long)bytes < 0) return 0;
-
- nb = request2size(bytes); /* padded request size; */
-
- /* Check for exact match in a bin */
-
- if (is_small_request(nb)) /* Faster version for small requests */
- {
- idx = smallbin_index(nb);
-
- /* No traversal or size check necessary for small bins. */
-
- q = bin_at(idx);
- victim = last(q);
-
- /* Also scan the next one, since it would have a remainder < MINSIZE */
- if (victim == q)
- {
- q = next_bin(q);
- victim = last(q);
- }
- if (victim != q)
- {
- victim_size = chunksize(victim);
- unlink(victim, bck, fwd);
- set_inuse_bit_at_offset(victim, victim_size);
- check_malloced_chunk(victim, nb);
- return chunk2mem(victim);
- }
-
- idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
-
- }
- else
- {
- idx = bin_index(nb);
- bin = bin_at(idx);
-
- for (victim = last(bin); victim != bin; victim = victim->bk)
- {
- victim_size = chunksize(victim);
- remainder_size = victim_size - nb;
-
- if (remainder_size >= (long)MINSIZE) /* too big */
- {
- --idx; /* adjust to rescan below after checking last remainder */
- break;
- }
-
- else if (remainder_size >= 0) /* exact fit */
- {
- unlink(victim, bck, fwd);
- set_inuse_bit_at_offset(victim, victim_size);
- check_malloced_chunk(victim, nb);
- return chunk2mem(victim);
- }
- }
-
- ++idx;
-
- }
-
- /* Try to use the last split-off remainder */
-
- if ( (victim = last_remainder->fd) != last_remainder)
- {
- victim_size = chunksize(victim);
- remainder_size = victim_size - nb;
-
- if (remainder_size >= (long)MINSIZE) /* re-split */
- {
- remainder = chunk_at_offset(victim, nb);
- set_head(victim, nb | PREV_INUSE);
- link_last_remainder(remainder);
- set_head(remainder, remainder_size | PREV_INUSE);
- set_foot(remainder, remainder_size);
- check_malloced_chunk(victim, nb);
- return chunk2mem(victim);
- }
-
- clear_last_remainder;
-
- if (remainder_size >= 0) /* exhaust */
- {
- set_inuse_bit_at_offset(victim, victim_size);
- check_malloced_chunk(victim, nb);
- return chunk2mem(victim);
- }
-
- /* Else place in bin */
-
- frontlink(victim, victim_size, remainder_index, bck, fwd);
- }
-
- /*
- If there are any possibly nonempty big-enough blocks,
- search for best fitting chunk by scanning bins in blockwidth units.
- */
-
- if ( (block = idx2binblock(idx)) <= binblocks)
- {
-
- /* Get to the first marked block */
-
- if ( (block & binblocks) == 0)
- {
- /* force to an even block boundary */
- idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
- block <<= 1;
- while ((block & binblocks) == 0)
- {
- idx += BINBLOCKWIDTH;
- block <<= 1;
- }
- }
-
- /* For each possibly nonempty block ... */
- for (;;)
- {
- startidx = idx; /* (track incomplete blocks) */
- q = bin = bin_at(idx);
-
- /* For each bin in this block ... */
- do
- {
- /* Find and use first big enough chunk ... */
-
- for (victim = last(bin); victim != bin; victim = victim->bk)
- {
- victim_size = chunksize(victim);
- remainder_size = victim_size - nb;
-
- if (remainder_size >= (long)MINSIZE) /* split */
- {
- remainder = chunk_at_offset(victim, nb);
- set_head(victim, nb | PREV_INUSE);
- unlink(victim, bck, fwd);
- link_last_remainder(remainder);
- set_head(remainder, remainder_size | PREV_INUSE);
- set_foot(remainder, remainder_size);
- check_malloced_chunk(victim, nb);
- return chunk2mem(victim);
- }
-
- else if (remainder_size >= 0) /* take */
- {
- set_inuse_bit_at_offset(victim, victim_size);
- unlink(victim, bck, fwd);
- check_malloced_chunk(victim, nb);
- return chunk2mem(victim);
- }
-
- }
-
- bin = next_bin(bin);
-
- } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
-
- /* Clear out the block bit. */
-
- do /* Possibly backtrack to try to clear a partial block */
- {
- if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
- {
- binblocks &= ~block;
- break;
- }
- --startidx;
- q = prev_bin(q);
- } while (first(q) == q);
-
- /* Get to the next possibly nonempty block */
-
- if ( (block <<= 1) <= binblocks && (block != 0) )
- {
- while ((block & binblocks) == 0)
- {
- idx += BINBLOCKWIDTH;
- block <<= 1;
- }
- }
- else
- break;
- }
- }
-
-
- /* Try to use top chunk */
-
- /* Require that there be a remainder, ensuring top always exists */
- if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
- {
-
-#if HAVE_MMAP
- /* If big and would otherwise need to extend, try to use mmap instead */
- if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
- (victim = mmap_chunk(nb)) != 0)
- return chunk2mem(victim);
-#endif
-
- /* Try to extend */
- malloc_extend_top(nb);
- if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
- return 0; /* propagate failure */
- }
-
- victim = top;
- set_head(victim, nb | PREV_INUSE);
- top = chunk_at_offset(victim, nb);
- set_head(top, remainder_size | PREV_INUSE);
- check_malloced_chunk(victim, nb);
- return chunk2mem(victim);
-
-}
-
-
-\f
-
-/*
-
- free() algorithm :
-
- cases:
-
- 1. free(0) has no effect.
-
- 2. If the chunk was allocated via mmap, it is release via munmap().
-
- 3. If a returned chunk borders the current high end of memory,
- it is consolidated into the top, and if the total unused
- topmost memory exceeds the trim threshold, malloc_trim is
- called.
-
- 4. Other chunks are consolidated as they arrive, and
- placed in corresponding bins. (This includes the case of
- consolidating with the current `last_remainder').
-
-*/
-
-
-#if __STD_C
-void fREe(Void_t* mem)
-#else
-void fREe(mem) Void_t* mem;
-#endif
-{
- mchunkptr p; /* chunk corresponding to mem */
- INTERNAL_SIZE_T hd; /* its head field */
- INTERNAL_SIZE_T sz; /* its size */
- int idx; /* its bin index */
- mchunkptr next; /* next contiguous chunk */
- INTERNAL_SIZE_T nextsz; /* its size */
- INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
- mchunkptr bck; /* misc temp for linking */
- mchunkptr fwd; /* misc temp for linking */
- int islr; /* track whether merging with last_remainder */
-
- if (mem == 0) /* free(0) has no effect */
- return;
-
- p = mem2chunk(mem);
- hd = p->size;
-
-#if HAVE_MMAP
- if (hd & IS_MMAPPED) /* release mmapped memory. */
- {
- munmap_chunk(p);
- return;
- }
-#endif
-
- check_inuse_chunk(p);
-
- sz = hd & ~PREV_INUSE;
- next = chunk_at_offset(p, sz);
- nextsz = chunksize(next);
-
- if (next == top) /* merge with top */
- {
- sz += nextsz;
-
- if (!(hd & PREV_INUSE)) /* consolidate backward */
- {
- prevsz = p->prev_size;
- p = chunk_at_offset(p, -((long) prevsz));
- sz += prevsz;
- unlink(p, bck, fwd);
- }
-
- set_head(p, sz | PREV_INUSE);
- top = p;
- if ((unsigned long)(sz) >= (unsigned long)trim_threshold)
- malloc_trim(top_pad);
- return;
- }
-
- set_head(next, nextsz); /* clear inuse bit */
-
- islr = 0;
-
- if (!(hd & PREV_INUSE)) /* consolidate backward */
- {
- prevsz = p->prev_size;
- p = chunk_at_offset(p, -((long) prevsz));
- sz += prevsz;
-
- if (p->fd == last_remainder) /* keep as last_remainder */
- islr = 1;
- else
- unlink(p, bck, fwd);
- }
-
- if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */
- {
- sz += nextsz;
-
- if (!islr && next->fd == last_remainder) /* re-insert last_remainder */
- {
- islr = 1;
- link_last_remainder(p);
- }
- else
- unlink(next, bck, fwd);
- }
-
-
- set_head(p, sz | PREV_INUSE);
- set_foot(p, sz);
- if (!islr)
- frontlink(p, sz, idx, bck, fwd);
-}
-
-
-\f
-
-
-/*
-
- Realloc algorithm:
-
- Chunks that were obtained via mmap cannot be extended or shrunk
- unless HAVE_MREMAP is defined, in which case mremap is used.
- Otherwise, if their reallocation is for additional space, they are
- copied. If for less, they are just left alone.
-
- Otherwise, if the reallocation is for additional space, and the
- chunk can be extended, it is, else a malloc-copy-free sequence is
- taken. There are several different ways that a chunk could be
- extended. All are tried:
-
- * Extending forward into following adjacent free chunk.
- * Shifting backwards, joining preceding adjacent space
- * Both shifting backwards and extending forward.
- * Extending into newly sbrked space
-
- Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a
- size argument of zero (re)allocates a minimum-sized chunk.
-
- If the reallocation is for less space, and the new request is for
- a `small' (<512 bytes) size, then the newly unused space is lopped
- off and freed.
-
- The old unix realloc convention of allowing the last-free'd chunk
- to be used as an argument to realloc is no longer supported.
- I don't know of any programs still relying on this feature,
- and allowing it would also allow too many other incorrect
- usages of realloc to be sensible.
-
-
-*/
-
-
-#if __STD_C
-Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
-#else
-Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
-#endif
-{
- INTERNAL_SIZE_T nb; /* padded request size */
-
- mchunkptr oldp; /* chunk corresponding to oldmem */
- INTERNAL_SIZE_T oldsize; /* its size */
-
- mchunkptr newp; /* chunk to return */
- INTERNAL_SIZE_T newsize; /* its size */
- Void_t* newmem; /* corresponding user mem */
-
- mchunkptr next; /* next contiguous chunk after oldp */
- INTERNAL_SIZE_T nextsize; /* its size */
-
- mchunkptr prev; /* previous contiguous chunk before oldp */
- INTERNAL_SIZE_T prevsize; /* its size */
-
- mchunkptr remainder; /* holds split off extra space from newp */
- INTERNAL_SIZE_T remainder_size; /* its size */
-
- mchunkptr bck; /* misc temp for linking */
- mchunkptr fwd; /* misc temp for linking */
-
-#ifdef REALLOC_ZERO_BYTES_FREES
- if (bytes == 0) { fREe(oldmem); return 0; }
-#endif
-
- if ((long)bytes < 0) return 0;
-
- /* realloc of null is supposed to be same as malloc */
- if (oldmem == 0) return mALLOc(bytes);
-
- newp = oldp = mem2chunk(oldmem);
- newsize = oldsize = chunksize(oldp);
-
-
- nb = request2size(bytes);
-
-#if HAVE_MMAP
- if (chunk_is_mmapped(oldp))
- {
-#if HAVE_MREMAP
- newp = mremap_chunk(oldp, nb);
- if(newp) return chunk2mem(newp);
-#endif
- /* Note the extra SIZE_SZ overhead. */
- if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
- /* Must alloc, copy, free. */
- newmem = mALLOc(bytes);
- if (newmem == 0) return 0; /* propagate failure */
- MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
- munmap_chunk(oldp);
- return newmem;
- }
-#endif
-
- check_inuse_chunk(oldp);
-
- if ((long)(oldsize) < (long)(nb))
- {
-
- /* Try expanding forward */
-
- next = chunk_at_offset(oldp, oldsize);
- if (next == top || !inuse(next))
- {
- nextsize = chunksize(next);
-
- /* Forward into top only if a remainder */
- if (next == top)
- {
- if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
- {
- newsize += nextsize;
- top = chunk_at_offset(oldp, nb);
- set_head(top, (newsize - nb) | PREV_INUSE);
- set_head_size(oldp, nb);
- return chunk2mem(oldp);
- }
- }
-
- /* Forward into next chunk */
- else if (((long)(nextsize + newsize) >= (long)(nb)))
- {
- unlink(next, bck, fwd);
- newsize += nextsize;
- goto split;
- }
- }
- else
- {
- next = 0;
- nextsize = 0;
- }
-
- /* Try shifting backwards. */
-
- if (!prev_inuse(oldp))
- {
- prev = prev_chunk(oldp);
- prevsize = chunksize(prev);
-
- /* try forward + backward first to save a later consolidation */
-
- if (next != 0)
- {
- /* into top */
- if (next == top)
- {
- if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
- {
- unlink(prev, bck, fwd);
- newp = prev;
- newsize += prevsize + nextsize;
- newmem = chunk2mem(newp);
- MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
- top = chunk_at_offset(newp, nb);
- set_head(top, (newsize - nb) | PREV_INUSE);
- set_head_size(newp, nb);
- return newmem;
- }
- }
-
- /* into next chunk */
- else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
- {
- unlink(next, bck, fwd);
- unlink(prev, bck, fwd);
- newp = prev;
- newsize += nextsize + prevsize;
- newmem = chunk2mem(newp);
- MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
- goto split;
- }
- }
-
- /* backward only */
- if (prev != 0 && (long)(prevsize + newsize) >= (long)nb)
- {
- unlink(prev, bck, fwd);
- newp = prev;
- newsize += prevsize;
- newmem = chunk2mem(newp);
- MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
- goto split;
- }
- }
-
- /* Must allocate */
-
- newmem = mALLOc (bytes);
-
- if (newmem == 0) /* propagate failure */
- return 0;
-
- /* Avoid copy if newp is next chunk after oldp. */
- /* (This can only happen when new chunk is sbrk'ed.) */
-
- if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
- {
- newsize += chunksize(newp);
- newp = oldp;
- goto split;
- }
-
- /* Otherwise copy, free, and exit */
- MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
- fREe(oldmem);
- return newmem;
- }
-
-
- split: /* split off extra room in old or expanded chunk */
-
- if (newsize - nb >= MINSIZE) /* split off remainder */
- {
- remainder = chunk_at_offset(newp, nb);
- remainder_size = newsize - nb;
- set_head_size(newp, nb);
- set_head(remainder, remainder_size | PREV_INUSE);
- set_inuse_bit_at_offset(remainder, remainder_size);
- fREe(chunk2mem(remainder)); /* let free() deal with it */
- }
- else
- {
- set_head_size(newp, newsize);
- set_inuse_bit_at_offset(newp, newsize);
- }
-
- check_inuse_chunk(newp);
- return chunk2mem(newp);
-}
-
-
-\f
-
-/*
-
- memalign algorithm:
-
- memalign requests more than enough space from malloc, finds a spot
- within that chunk that meets the alignment request, and then
- possibly frees the leading and trailing space.
-
- The alignment argument must be a power of two. This property is not
- checked by memalign, so misuse may result in random runtime errors.
-
- 8-byte alignment is guaranteed by normal malloc calls, so don't
- bother calling memalign with an argument of 8 or less.
-
- Overreliance on memalign is a sure way to fragment space.
-
-*/
-
-
-#if __STD_C
-Void_t* mEMALIGn(size_t alignment, size_t bytes)
-#else
-Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
-#endif
-{
- INTERNAL_SIZE_T nb; /* padded request size */
- char* m; /* memory returned by malloc call */
- mchunkptr p; /* corresponding chunk */
- char* brk; /* alignment point within p */
- mchunkptr newp; /* chunk to return */
- INTERNAL_SIZE_T newsize; /* its size */
- INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */
- mchunkptr remainder; /* spare room at end to split off */
- long remainder_size; /* its size */
-
- if ((long)bytes < 0) return 0;
-
- /* If need less alignment than we give anyway, just relay to malloc */
-
- if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
-
- /* Otherwise, ensure that it is at least a minimum chunk size */
-
- if (alignment < MINSIZE) alignment = MINSIZE;
-
- /* Call malloc with worst case padding to hit alignment. */
-
- nb = request2size(bytes);
- m = (char*)(mALLOc(nb + alignment + MINSIZE));
-
- if (m == 0) return 0; /* propagate failure */
-
- p = mem2chunk(m);
-
- if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
- {
-#if HAVE_MMAP
- if(chunk_is_mmapped(p))
- return chunk2mem(p); /* nothing more to do */
-#endif
- }
- else /* misaligned */
- {
- /*
- Find an aligned spot inside chunk.
- Since we need to give back leading space in a chunk of at
- least MINSIZE, if the first calculation places us at
- a spot with less than MINSIZE leader, we can move to the
- next aligned spot -- we've allocated enough total room so that
- this is always possible.
- */
-
- brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment));
- if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment;
-
- newp = (mchunkptr)brk;
- leadsize = brk - (char*)(p);
- newsize = chunksize(p) - leadsize;
-
-#if HAVE_MMAP
- if(chunk_is_mmapped(p))
- {
- newp->prev_size = p->prev_size + leadsize;
- set_head(newp, newsize|IS_MMAPPED);
- return chunk2mem(newp);
- }
-#endif
-
- /* give back leader, use the rest */
-
- set_head(newp, newsize | PREV_INUSE);
- set_inuse_bit_at_offset(newp, newsize);
- set_head_size(p, leadsize);
- fREe(chunk2mem(p));
- p = newp;
-
- assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
- }
-
- /* Also give back spare room at the end */
-
- remainder_size = chunksize(p) - nb;
-
- if (remainder_size >= (long)MINSIZE)
- {
- remainder = chunk_at_offset(p, nb);
- set_head(remainder, remainder_size | PREV_INUSE);
- set_head_size(p, nb);
- fREe(chunk2mem(remainder));
- }
-
- check_inuse_chunk(p);
- return chunk2mem(p);
-
-}
-
-\f
-
-
-/*
- valloc just invokes memalign with alignment argument equal
- to the page size of the system (or as near to this as can
- be figured out from all the includes/defines above.)
-*/
-
-#if __STD_C
-Void_t* vALLOc(size_t bytes)
-#else
-Void_t* vALLOc(bytes) size_t bytes;
-#endif
-{
- return mEMALIGn (malloc_getpagesize, bytes);
-}
-
-/*
- pvalloc just invokes valloc for the nearest pagesize
- that will accommodate request
-*/
-
-
-#if __STD_C
-Void_t* pvALLOc(size_t bytes)
-#else
-Void_t* pvALLOc(bytes) size_t bytes;
-#endif
-{
- size_t pagesize = malloc_getpagesize;
- return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
-}
-
-/*
-
- calloc calls malloc, then zeroes out the allocated chunk.
-
-*/
-
-#if __STD_C
-Void_t* cALLOc(size_t n, size_t elem_size)
-#else
-Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
-#endif
-{
- mchunkptr p;
- INTERNAL_SIZE_T csz;
-
- INTERNAL_SIZE_T sz = n * elem_size;
-
-
- /* check if expand_top called, in which case don't need to clear */
-#if MORECORE_CLEARS
- mchunkptr oldtop = top;
- INTERNAL_SIZE_T oldtopsize = chunksize(top);
-#endif
- Void_t* mem = mALLOc (sz);
-
- if ((long)n < 0) return 0;
-
- if (mem == 0)
- return 0;
- else
- {
- p = mem2chunk(mem);
-
- /* Two optional cases in which clearing not necessary */
-
-
-#if HAVE_MMAP
- if (chunk_is_mmapped(p)) return mem;
-#endif
-
- csz = chunksize(p);
-
-#if MORECORE_CLEARS
- if (p == oldtop && csz > oldtopsize)
- {
- /* clear only the bytes from non-freshly-sbrked memory */
- csz = oldtopsize;
- }
-#endif
-
- MALLOC_ZERO(mem, csz - SIZE_SZ);
- return mem;
- }
-}
-
-/*
-
- cfree just calls free. It is needed/defined on some systems
- that pair it with calloc, presumably for odd historical reasons.
-
-*/
-
-#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__)
-#if __STD_C
-void cfree(Void_t *mem)
-#else
-void cfree(mem) Void_t *mem;
-#endif
-{
- fREe(mem);
-}
-#endif
-
-\f
-
-/*
-
- Malloc_trim gives memory back to the system (via negative
- arguments to sbrk) if there is unused memory at the `high' end of
- the malloc pool. You can call this after freeing large blocks of
- memory to potentially reduce the system-level memory requirements
- of a program. However, it cannot guarantee to reduce memory. Under
- some allocation patterns, some large free blocks of memory will be
- locked between two used chunks, so they cannot be given back to
- the system.
-
- The `pad' argument to malloc_trim represents the amount of free
- trailing space to leave untrimmed. If this argument is zero,
- only the minimum amount of memory to maintain internal data
- structures will be left (one page or less). Non-zero arguments
- can be supplied to maintain enough trailing space to service
- future expected allocations without having to re-obtain memory
- from the system.
-
- Malloc_trim returns 1 if it actually released any memory, else 0.
-
-*/
-
-#if __STD_C
-int malloc_trim(size_t pad)
-#else
-int malloc_trim(pad) size_t pad;
-#endif
-{
- long top_size; /* Amount of top-most memory */
- long extra; /* Amount to release */
- char* current_brk; /* address returned by pre-check sbrk call */
- char* new_brk; /* address returned by negative sbrk call */
-
- unsigned long pagesz = malloc_getpagesize;
-
- top_size = chunksize(top);
- extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
-
- if (extra < (long)pagesz) /* Not enough memory to release */
- return 0;
-
- else
- {
- /* Test to make sure no one else called sbrk */
- current_brk = (char*)(MORECORE (0));
- if (current_brk != (char*)(top) + top_size)
- return 0; /* Apparently we don't own memory; must fail */
-
- else
- {
- new_brk = (char*)(MORECORE (-extra));
-
- if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
- {
- /* Try to figure out what we have */
- current_brk = (char*)(MORECORE (0));
- top_size = current_brk - (char*)top;
- if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
- {
- sbrked_mem = current_brk - sbrk_base;
- set_head(top, top_size | PREV_INUSE);
- }
- check_chunk(top);
- return 0;
- }
-
- else
- {
- /* Success. Adjust top accordingly. */
- set_head(top, (top_size - extra) | PREV_INUSE);
- sbrked_mem -= extra;
- check_chunk(top);
- return 1;
- }
- }
- }
-}
-
-\f
-
-/*
- malloc_usable_size:
-
- This routine tells you how many bytes you can actually use in an
- allocated chunk, which may be more than you requested (although
- often not). You can use this many bytes without worrying about
- overwriting other allocated objects. Not a particularly great
- programming practice, but still sometimes useful.
-
-*/
-
-#if __STD_C
-size_t malloc_usable_size(Void_t* mem)
-#else
-size_t malloc_usable_size(mem) Void_t* mem;
-#endif
-{
- mchunkptr p;
- if (mem == 0)
- return 0;
- else
- {
- p = mem2chunk(mem);
- if(!chunk_is_mmapped(p))
- {
- if (!inuse(p)) return 0;
- check_inuse_chunk(p);
- return chunksize(p) - SIZE_SZ;
- }
- return chunksize(p) - 2*SIZE_SZ;
- }
-}
-
-
-\f
-
-/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
-
-static void malloc_update_mallinfo()
-{
- int i;
- mbinptr b;
- mchunkptr p;
-#if DEBUG
- mchunkptr q;
-#endif
-
- INTERNAL_SIZE_T avail = chunksize(top);
- int navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0;
-
- for (i = 1; i < NAV; ++i)
- {
- b = bin_at(i);
- for (p = last(b); p != b; p = p->bk)
- {
-#if DEBUG
- check_free_chunk(p);
- for (q = next_chunk(p);
- q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE;
- q = next_chunk(q))
- check_inuse_chunk(q);
-#endif
- avail += chunksize(p);
- navail++;
- }
- }
-
- current_mallinfo.ordblks = navail;
- current_mallinfo.uordblks = sbrked_mem - avail;
- current_mallinfo.fordblks = avail;
- current_mallinfo.hblks = n_mmaps;
- current_mallinfo.hblkhd = mmapped_mem;
- current_mallinfo.keepcost = chunksize(top);
-
-}
-
-\f
-
-/*
-
- malloc_stats:
-
- Prints on stderr the amount of space obtain from the system (both
- via sbrk and mmap), the maximum amount (which may be more than
- current if malloc_trim and/or munmap got called), the maximum
- number of simultaneous mmap regions used, and the current number
- of bytes allocated via malloc (or realloc, etc) but not yet
- freed. (Note that this is the number of bytes allocated, not the
- number requested. It will be larger than the number requested
- because of alignment and bookkeeping overhead.)
-
-*/
-
-void malloc_stats()
-{
- malloc_update_mallinfo();
- fprintf(stderr, "max system bytes = %10u\n",
- (unsigned int)(max_total_mem));
- fprintf(stderr, "system bytes = %10u\n",
- (unsigned int)(sbrked_mem + mmapped_mem));
- fprintf(stderr, "in use bytes = %10u\n",
- (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
-#if HAVE_MMAP
- fprintf(stderr, "max mmap regions = %10u\n",
- (unsigned int)max_n_mmaps);
-#endif
-}
-
-/*
- mallinfo returns a copy of updated current mallinfo.
-*/
-
-struct mallinfo mALLINFo()
-{
- malloc_update_mallinfo();
- return current_mallinfo;
-}
-
-
-\f
-
-/*
- mallopt:
-
- mallopt is the general SVID/XPG interface to tunable parameters.
- The format is to provide a (parameter-number, parameter-value) pair.
- mallopt then sets the corresponding parameter to the argument
- value if it can (i.e., so long as the value is meaningful),
- and returns 1 if successful else 0.
-
- See descriptions of tunable parameters above.
-
-*/
-
-#if __STD_C
-int mALLOPt(int param_number, int value)
-#else
-int mALLOPt(param_number, value) int param_number; int value;
-#endif
-{
- switch(param_number)
- {
- case M_TRIM_THRESHOLD:
- trim_threshold = value; return 1;
- case M_TOP_PAD:
- top_pad = value; return 1;
- case M_MMAP_THRESHOLD:
- mmap_threshold = value; return 1;
- case M_MMAP_MAX:
-#if HAVE_MMAP
- n_mmaps_max = value; return 1;
-#else
- if (value != 0) return 0; else n_mmaps_max = value; return 1;
-#endif
-
- default:
- return 0;
- }
-}
-
-/*
-
-History:
-
- V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
- * return null for negative arguments
- * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com>
- * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
- (e.g. WIN32 platforms)
- * Cleanup up header file inclusion for WIN32 platforms
- * Cleanup code to avoid Microsoft Visual C++ compiler complaints
- * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
- memory allocation routines
- * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
- * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
- usage of 'assert' in non-WIN32 code
- * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
- avoid infinite loop
- * Always call 'fREe()' rather than 'free()'
-
- V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
- * Fixed ordering problem with boundary-stamping
-
- V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
- * Added pvalloc, as recommended by H.J. Liu
- * Added 64bit pointer support mainly from Wolfram Gloger
- * Added anonymously donated WIN32 sbrk emulation
- * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
- * malloc_extend_top: fix mask error that caused wastage after
- foreign sbrks
- * Add linux mremap support code from HJ Liu
-
- V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
- * Integrated most documentation with the code.
- * Add support for mmap, with help from
- Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
- * Use last_remainder in more cases.
- * Pack bins using idea from colin@nyx10.cs.du.edu
- * Use ordered bins instead of best-fit threshhold
- * Eliminate block-local decls to simplify tracing and debugging.
- * Support another case of realloc via move into top
- * Fix error occuring when initial sbrk_base not word-aligned.
- * Rely on page size for units instead of SBRK_UNIT to
- avoid surprises about sbrk alignment conventions.
- * Add mallinfo, mallopt. Thanks to Raymond Nijssen
- (raymond@es.ele.tue.nl) for the suggestion.
- * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
- * More precautions for cases where other routines call sbrk,
- courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
- * Added macros etc., allowing use in linux libc from
- H.J. Lu (hjl@gnu.ai.mit.edu)
- * Inverted this history list
-
- V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
- * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
- * Removed all preallocation code since under current scheme
- the work required to undo bad preallocations exceeds
- the work saved in good cases for most test programs.
- * No longer use return list or unconsolidated bins since
- no scheme using them consistently outperforms those that don't
- given above changes.
- * Use best fit for very large chunks to prevent some worst-cases.
- * Added some support for debugging
-
- V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
- * Removed footers when chunks are in use. Thanks to
- Paul Wilson (wilson@cs.texas.edu) for the suggestion.
-
- V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
- * Added malloc_trim, with help from Wolfram Gloger
- (wmglo@Dent.MED.Uni-Muenchen.DE).
-
- V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
-
- V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
- * realloc: try to expand in both directions
- * malloc: swap order of clean-bin strategy;
- * realloc: only conditionally expand backwards
- * Try not to scavenge used bins
- * Use bin counts as a guide to preallocation
- * Occasionally bin return list chunks in first scan
- * Add a few optimizations from colin@nyx10.cs.du.edu
-
- V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
- * faster bin computation & slightly different binning
- * merged all consolidations to one part of malloc proper
- (eliminating old malloc_find_space & malloc_clean_bin)
- * Scan 2 returns chunks (not just 1)
- * Propagate failure in realloc if malloc returns 0
- * Add stuff to allow compilation on non-ANSI compilers
- from kpv@research.att.com
-
- V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
- * removed potential for odd address access in prev_chunk
- * removed dependency on getpagesize.h
- * misc cosmetics and a bit more internal documentation
- * anticosmetics: mangled names in macros to evade debugger strangeness
- * tested on sparc, hp-700, dec-mips, rs6000
- with gcc & native cc (hp, dec only) allowing
- Detlefs & Zorn comparison study (in SIGPLAN Notices.)
-
- Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
- * Based loosely on libg++-1.2X malloc. (It retains some of the overall
- structure of old version, but most details differ.)
-
-*/
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 1] Delete unused file common/dlmalloc.src.
2010-12-20 22:40 ` [PATCH 1] Delete unused file common/dlmalloc.src Krzysztof Halasa
@ 2010-12-21 9:34 ` Sascha Hauer
0 siblings, 0 replies; 41+ messages in thread
From: Sascha Hauer @ 2010-12-21 9:34 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
On Mon, Dec 20, 2010 at 11:40:44PM +0100, Krzysztof Halasa wrote:
> Delete unused file common/dlmalloc.src.
> Or is there any reason to have it here?
The reason probably is to keep the original code the implementation is
derived from around. I agree that we can remove it though, we have our
history in git and even this file can be restored from the history.
Sascha
>
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
>
> diff --git a/common/dlmalloc.src b/common/dlmalloc.src
> deleted file mode 100644
> index 32a38bc..0000000
> --- a/common/dlmalloc.src
> +++ /dev/null
> @@ -1,3265 +0,0 @@
> -/* ---------- To make a malloc.h, start cutting here ------------ */
> -
> -/*
> - A version of malloc/free/realloc written by Doug Lea and released to the
> - public domain. Send questions/comments/complaints/performance data
> - to dl@cs.oswego.edu
> -
> -* VERSION 2.6.6 Sun Mar 5 19:10:03 2000 Doug Lea (dl at gee)
> -
> - Note: There may be an updated version of this malloc obtainable at
> - ftp://g.oswego.edu/pub/misc/malloc.c
> - Check before installing!
> -
> -* Why use this malloc?
> -
> - This is not the fastest, most space-conserving, most portable, or
> - most tunable malloc ever written. However it is among the fastest
> - while also being among the most space-conserving, portable and tunable.
> - Consistent balance across these factors results in a good general-purpose
> - allocator. For a high-level description, see
> - http://g.oswego.edu/dl/html/malloc.html
> -
> -* Synopsis of public routines
> -
> - (Much fuller descriptions are contained in the program documentation below.)
> -
> - malloc(size_t n);
> - Return a pointer to a newly allocated chunk of at least n bytes, or null
> - if no space is available.
> - free(Void_t* p);
> - Release the chunk of memory pointed to by p, or no effect if p is null.
> - realloc(Void_t* p, size_t n);
> - Return a pointer to a chunk of size n that contains the same data
> - as does chunk p up to the minimum of (n, p's size) bytes, or null
> - if no space is available. The returned pointer may or may not be
> - the same as p. If p is null, equivalent to malloc. Unless the
> - #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
> - size argument of zero (re)allocates a minimum-sized chunk.
> - memalign(size_t alignment, size_t n);
> - Return a pointer to a newly allocated chunk of n bytes, aligned
> - in accord with the alignment argument, which must be a power of
> - two.
> - valloc(size_t n);
> - Equivalent to memalign(pagesize, n), where pagesize is the page
> - size of the system (or as near to this as can be figured out from
> - all the includes/defines below.)
> - pvalloc(size_t n);
> - Equivalent to valloc(minimum-page-that-holds(n)), that is,
> - round up n to nearest pagesize.
> - calloc(size_t unit, size_t quantity);
> - Returns a pointer to quantity * unit bytes, with all locations
> - set to zero.
> - cfree(Void_t* p);
> - Equivalent to free(p).
> - malloc_trim(size_t pad);
> - Release all but pad bytes of freed top-most memory back
> - to the system. Return 1 if successful, else 0.
> - malloc_usable_size(Void_t* p);
> - Report the number usable allocated bytes associated with allocated
> - chunk p. This may or may not report more bytes than were requested,
> - due to alignment and minimum size constraints.
> - malloc_stats();
> - Prints brief summary statistics on stderr.
> - mallinfo()
> - Returns (by copy) a struct containing various summary statistics.
> - mallopt(int parameter_number, int parameter_value)
> - Changes one of the tunable parameters described below. Returns
> - 1 if successful in changing the parameter, else 0.
> -
> -* Vital statistics:
> -
> - Alignment: 8-byte
> - 8 byte alignment is currently hardwired into the design. This
> - seems to suffice for all current machines and C compilers.
> -
> - Assumed pointer representation: 4 or 8 bytes
> - Code for 8-byte pointers is untested by me but has worked
> - reliably by Wolfram Gloger, who contributed most of the
> - changes supporting this.
> -
> - Assumed size_t representation: 4 or 8 bytes
> - Note that size_t is allowed to be 4 bytes even if pointers are 8.
> -
> - Minimum overhead per allocated chunk: 4 or 8 bytes
> - Each malloced chunk has a hidden overhead of 4 bytes holding size
> - and status information.
> -
> - Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead)
> - 8-byte ptrs: 24/32 bytes (including, 4/8 overhead)
> -
> - When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
> - ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
> - needed; 4 (8) for a trailing size field
> - and 8 (16) bytes for free list pointers. Thus, the minimum
> - allocatable size is 16/24/32 bytes.
> -
> - Even a request for zero bytes (i.e., malloc(0)) returns a
> - pointer to something of the minimum allocatable size.
> -
> - Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes
> - 8-byte size_t: 2^63 - 16 bytes
> -
> - It is assumed that (possibly signed) size_t bit values suffice to
> - represent chunk sizes. `Possibly signed' is due to the fact
> - that `size_t' may be defined on a system as either a signed or
> - an unsigned type. To be conservative, values that would appear
> - as negative numbers are avoided.
> - Requests for sizes with a negative sign bit when the request
> - size is treaded as a long will return null.
> -
> - Maximum overhead wastage per allocated chunk: normally 15 bytes
> -
> - Alignnment demands, plus the minimum allocatable size restriction
> - make the normal worst-case wastage 15 bytes (i.e., up to 15
> - more bytes will be allocated than were requested in malloc), with
> - two exceptions:
> - 1. Because requests for zero bytes allocate non-zero space,
> - the worst case wastage for a request of zero bytes is 24 bytes.
> - 2. For requests >= mmap_threshold that are serviced via
> - mmap(), the worst case wastage is 8 bytes plus the remainder
> - from a system page (the minimal mmap unit); typically 4096 bytes.
> -
> -* Limitations
> -
> - Here are some features that are NOT currently supported
> -
> - * No user-definable hooks for callbacks and the like.
> - * No automated mechanism for fully checking that all accesses
> - to malloced memory stay within their bounds.
> - * No support for compaction.
> -
> -* Synopsis of compile-time options:
> -
> - People have reported using previous versions of this malloc on all
> - versions of Unix, sometimes by tweaking some of the defines
> - below. It has been tested most extensively on Solaris and
> - Linux. It is also reported to work on WIN32 platforms.
> - People have also reported adapting this malloc for use in
> - stand-alone embedded systems.
> -
> - The implementation is in straight, hand-tuned ANSI C. Among other
> - consequences, it uses a lot of macros. Because of this, to be at
> - all usable, this code should be compiled using an optimizing compiler
> - (for example gcc -O2) that can simplify expressions and control
> - paths.
> -
> - __STD_C (default: derived from C compiler defines)
> - Nonzero if using ANSI-standard C compiler, a C++ compiler, or
> - a C compiler sufficiently close to ANSI to get away with it.
> - DEBUG (default: NOT defined)
> - Define to enable debugging. Adds fairly extensive assertion-based
> - checking to help track down memory errors, but noticeably slows down
> - execution.
> - REALLOC_ZERO_BYTES_FREES (default: NOT defined)
> - Define this if you think that realloc(p, 0) should be equivalent
> - to free(p). Otherwise, since malloc returns a unique pointer for
> - malloc(0), so does realloc(p, 0).
> - HAVE_MEMCPY (default: defined)
> - Define if you are not otherwise using ANSI STD C, but still
> - have memcpy and memset in your C library and want to use them.
> - Otherwise, simple internal versions are supplied.
> - USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise)
> - Define as 1 if you want the C library versions of memset and
> - memcpy called in realloc and calloc (otherwise macro versions are used).
> - At least on some platforms, the simple macro versions usually
> - outperform libc versions.
> - HAVE_MMAP (default: defined as 1)
> - Define to non-zero to optionally make malloc() use mmap() to
> - allocate very large blocks.
> - HAVE_MREMAP (default: defined as 0 unless Linux libc set)
> - Define to non-zero to optionally make realloc() use mremap() to
> - reallocate very large blocks.
> - malloc_getpagesize (default: derived from system #includes)
> - Either a constant or routine call returning the system page size.
> - HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined)
> - Optionally define if you are on a system with a /usr/include/malloc.h
> - that declares struct mallinfo. It is not at all necessary to
> - define this even if you do, but will ensure consistency.
> - INTERNAL_SIZE_T (default: size_t)
> - Define to a 32-bit type (probably `unsigned int') if you are on a
> - 64-bit machine, yet do not want or need to allow malloc requests of
> - greater than 2^31 to be handled. This saves space, especially for
> - very small chunks.
> - INTERNAL_LINUX_C_LIB (default: NOT defined)
> - Defined only when compiled as part of Linux libc.
> - Also note that there is some odd internal name-mangling via defines
> - (for example, internally, `malloc' is named `mALLOc') needed
> - when compiling in this case. These look funny but don't otherwise
> - affect anything.
> - WIN32 (default: undefined)
> - Define this on MS win (95, nt) platforms to compile in sbrk emulation.
> - LACKS_UNISTD_H (default: undefined if not WIN32)
> - Define this if your system does not have a <unistd.h>.
> - LACKS_SYS_PARAM_H (default: undefined if not WIN32)
> - Define this if your system does not have a <sys/param.h>.
> - MORECORE (default: sbrk)
> - The name of the routine to call to obtain more memory from the system.
> - MORECORE_FAILURE (default: -1)
> - The value returned upon failure of MORECORE.
> - MORECORE_CLEARS (default 1)
> - True (1) if the routine mapped to MORECORE zeroes out memory (which
> - holds for sbrk).
> - DEFAULT_TRIM_THRESHOLD
> - DEFAULT_TOP_PAD
> - DEFAULT_MMAP_THRESHOLD
> - DEFAULT_MMAP_MAX
> - Default values of tunable parameters (described in detail below)
> - controlling interaction with host system routines (sbrk, mmap, etc).
> - These values may also be changed dynamically via mallopt(). The
> - preset defaults are those that give best performance for typical
> - programs/systems.
> - USE_DL_PREFIX (default: undefined)
> - Prefix all public routines with the string 'dl'. Useful to
> - quickly avoid procedure declaration conflicts and linker symbol
> - conflicts with existing memory allocation routines.
> -
> -
> -*/
> -
> -\f
> -
> -
> -/* Preliminaries */
> -
> -#ifndef __STD_C
> -#ifdef __STDC__
> -#define __STD_C 1
> -#else
> -#if __cplusplus
> -#define __STD_C 1
> -#else
> -#define __STD_C 0
> -#endif /*__cplusplus*/
> -#endif /*__STDC__*/
> -#endif /*__STD_C*/
> -
> -#ifndef Void_t
> -#if (__STD_C || defined(WIN32))
> -#define Void_t void
> -#else
> -#define Void_t char
> -#endif
> -#endif /*Void_t*/
> -
> -#if __STD_C
> -#include <stddef.h> /* for size_t */
> -#else
> -#include <sys/types.h>
> -#endif
> -
> -#ifdef __cplusplus
> -extern "C" {
> -#endif
> -
> -#include <stdio.h> /* needed for malloc_stats */
> -
> -
> -/*
> - Compile-time options
> -*/
> -
> -
> -/*
> - Debugging:
> -
> - Because freed chunks may be overwritten with link fields, this
> - malloc will often die when freed memory is overwritten by user
> - programs. This can be very effective (albeit in an annoying way)
> - in helping track down dangling pointers.
> -
> - If you compile with -DDEBUG, a number of assertion checks are
> - enabled that will catch more memory errors. You probably won't be
> - able to make much sense of the actual assertion errors, but they
> - should help you locate incorrectly overwritten memory. The
> - checking is fairly extensive, and will slow down execution
> - noticeably. Calling malloc_stats or mallinfo with DEBUG set will
> - attempt to check every non-mmapped allocated and free chunk in the
> - course of computing the summmaries. (By nature, mmapped regions
> - cannot be checked very much automatically.)
> -
> - Setting DEBUG may also be helpful if you are trying to modify
> - this code. The assertions in the check routines spell out in more
> - detail the assumptions and invariants underlying the algorithms.
> -
> -*/
> -
> -#if DEBUG
> -#include <assert.h>
> -#else
> -#define assert(x) ((void)0)
> -#endif
> -
> -
> -/*
> - INTERNAL_SIZE_T is the word-size used for internal bookkeeping
> - of chunk sizes. On a 64-bit machine, you can reduce malloc
> - overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int'
> - at the expense of not being able to handle requests greater than
> - 2^31. This limitation is hardly ever a concern; you are encouraged
> - to set this. However, the default version is the same as size_t.
> -*/
> -
> -#ifndef INTERNAL_SIZE_T
> -#define INTERNAL_SIZE_T size_t
> -#endif
> -
> -/*
> - REALLOC_ZERO_BYTES_FREES should be set if a call to
> - realloc with zero bytes should be the same as a call to free.
> - Some people think it should. Otherwise, since this malloc
> - returns a unique pointer for malloc(0), so does realloc(p, 0).
> -*/
> -
> -
> -/* #define REALLOC_ZERO_BYTES_FREES */
> -
> -
> -/*
> - WIN32 causes an emulation of sbrk to be compiled in
> - mmap-based options are not currently supported in WIN32.
> -*/
> -
> -/* #define WIN32 */
> -#ifdef WIN32
> -#define MORECORE wsbrk
> -#define HAVE_MMAP 0
> -
> -#define LACKS_UNISTD_H
> -#define LACKS_SYS_PARAM_H
> -
> -/*
> - Include 'windows.h' to get the necessary declarations for the
> - Microsoft Visual C++ data structures and routines used in the 'sbrk'
> - emulation.
> -
> - Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft
> - Visual C++ header files are included.
> -*/
> -#define WIN32_LEAN_AND_MEAN
> -#include <windows.h>
> -#endif
> -
> -
> -/*
> - HAVE_MEMCPY should be defined if you are not otherwise using
> - ANSI STD C, but still have memcpy and memset in your C library
> - and want to use them in calloc and realloc. Otherwise simple
> - macro versions are defined here.
> -
> - USE_MEMCPY should be defined as 1 if you actually want to
> - have memset and memcpy called. People report that the macro
> - versions are often enough faster than libc versions on many
> - systems that it is better to use them.
> -
> -*/
> -
> -#define HAVE_MEMCPY
> -
> -#ifndef USE_MEMCPY
> -#ifdef HAVE_MEMCPY
> -#define USE_MEMCPY 1
> -#else
> -#define USE_MEMCPY 0
> -#endif
> -#endif
> -
> -#if (__STD_C || defined(HAVE_MEMCPY))
> -
> -#if __STD_C
> -void* memset(void*, int, size_t);
> -void* memcpy(void*, const void*, size_t);
> -#else
> -#ifdef WIN32
> -/* On Win32 platforms, 'memset()' and 'memcpy()' are already declared in */
> -/* 'windows.h' */
> -#else
> -Void_t* memset();
> -Void_t* memcpy();
> -#endif
> -#endif
> -#endif
> -
> -#if USE_MEMCPY
> -
> -/* The following macros are only invoked with (2n+1)-multiples of
> - INTERNAL_SIZE_T units, with a positive integer n. This is exploited
> - for fast inline execution when n is small. */
> -
> -#define MALLOC_ZERO(charp, nbytes) \
> -do { \
> - INTERNAL_SIZE_T mzsz = (nbytes); \
> - if(mzsz <= 9*sizeof(mzsz)) { \
> - INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \
> - if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \
> - *mz++ = 0; \
> - if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \
> - *mz++ = 0; \
> - if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \
> - *mz++ = 0; }}} \
> - *mz++ = 0; \
> - *mz++ = 0; \
> - *mz = 0; \
> - } else memset((charp), 0, mzsz); \
> -} while(0)
> -
> -#define MALLOC_COPY(dest,src,nbytes) \
> -do { \
> - INTERNAL_SIZE_T mcsz = (nbytes); \
> - if(mcsz <= 9*sizeof(mcsz)) { \
> - INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \
> - INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \
> - if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
> - *mcdst++ = *mcsrc++; \
> - if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
> - *mcdst++ = *mcsrc++; \
> - if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \
> - *mcdst++ = *mcsrc++; }}} \
> - *mcdst++ = *mcsrc++; \
> - *mcdst++ = *mcsrc++; \
> - *mcdst = *mcsrc ; \
> - } else memcpy(dest, src, mcsz); \
> -} while(0)
> -
> -#else /* !USE_MEMCPY */
> -
> -/* Use Duff's device for good zeroing/copying performance. */
> -
> -#define MALLOC_ZERO(charp, nbytes) \
> -do { \
> - INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \
> - long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
> - if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
> - switch (mctmp) { \
> - case 0: for(;;) { *mzp++ = 0; \
> - case 7: *mzp++ = 0; \
> - case 6: *mzp++ = 0; \
> - case 5: *mzp++ = 0; \
> - case 4: *mzp++ = 0; \
> - case 3: *mzp++ = 0; \
> - case 2: *mzp++ = 0; \
> - case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
> - } \
> -} while(0)
> -
> -#define MALLOC_COPY(dest,src,nbytes) \
> -do { \
> - INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \
> - INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \
> - long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \
> - if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \
> - switch (mctmp) { \
> - case 0: for(;;) { *mcdst++ = *mcsrc++; \
> - case 7: *mcdst++ = *mcsrc++; \
> - case 6: *mcdst++ = *mcsrc++; \
> - case 5: *mcdst++ = *mcsrc++; \
> - case 4: *mcdst++ = *mcsrc++; \
> - case 3: *mcdst++ = *mcsrc++; \
> - case 2: *mcdst++ = *mcsrc++; \
> - case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
> - } \
> -} while(0)
> -
> -#endif
> -
> -
> -/*
> - Define HAVE_MMAP to optionally make malloc() use mmap() to
> - allocate very large blocks. These will be returned to the
> - operating system immediately after a free().
> -*/
> -
> -#ifndef HAVE_MMAP
> -#define HAVE_MMAP 1
> -#endif
> -
> -/*
> - Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
> - large blocks. This is currently only possible on Linux with
> - kernel versions newer than 1.3.77.
> -*/
> -
> -#ifndef HAVE_MREMAP
> -#ifdef INTERNAL_LINUX_C_LIB
> -#define HAVE_MREMAP 1
> -#else
> -#define HAVE_MREMAP 0
> -#endif
> -#endif
> -
> -#if HAVE_MMAP
> -
> -#include <unistd.h>
> -#include <fcntl.h>
> -#include <sys/mman.h>
> -
> -#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
> -#define MAP_ANONYMOUS MAP_ANON
> -#endif
> -
> -#endif /* HAVE_MMAP */
> -
> -/*
> - Access to system page size. To the extent possible, this malloc
> - manages memory from the system in page-size units.
> -
> - The following mechanics for getpagesize were adapted from
> - bsd/gnu getpagesize.h
> -*/
> -
> -#ifndef LACKS_UNISTD_H
> -# include <unistd.h>
> -#endif
> -
> -#ifndef malloc_getpagesize
> -# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
> -# ifndef _SC_PAGE_SIZE
> -# define _SC_PAGE_SIZE _SC_PAGESIZE
> -# endif
> -# endif
> -# ifdef _SC_PAGE_SIZE
> -# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
> -# else
> -# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
> - extern size_t getpagesize();
> -# define malloc_getpagesize getpagesize()
> -# else
> -# ifdef WIN32
> -# define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */
> -# else
> -# ifndef LACKS_SYS_PARAM_H
> -# include <sys/param.h>
> -# endif
> -# ifdef EXEC_PAGESIZE
> -# define malloc_getpagesize EXEC_PAGESIZE
> -# else
> -# ifdef NBPG
> -# ifndef CLSIZE
> -# define malloc_getpagesize NBPG
> -# else
> -# define malloc_getpagesize (NBPG * CLSIZE)
> -# endif
> -# else
> -# ifdef NBPC
> -# define malloc_getpagesize NBPC
> -# else
> -# ifdef PAGESIZE
> -# define malloc_getpagesize PAGESIZE
> -# else
> -# define malloc_getpagesize (4096) /* just guess */
> -# endif
> -# endif
> -# endif
> -# endif
> -# endif
> -# endif
> -# endif
> -#endif
> -
> -
> -/*
> -
> - This version of malloc supports the standard SVID/XPG mallinfo
> - routine that returns a struct containing the same kind of
> - information you can get from malloc_stats. It should work on
> - any SVID/XPG compliant system that has a /usr/include/malloc.h
> - defining struct mallinfo. (If you'd like to install such a thing
> - yourself, cut out the preliminary declarations as described above
> - and below and save them in a malloc.h file. But there's no
> - compelling reason to bother to do this.)
> -
> - The main declaration needed is the mallinfo struct that is returned
> - (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a
> - bunch of fields, most of which are not even meaningful in this
> - version of malloc. Some of these fields are are instead filled by
> - mallinfo() with other numbers that might possibly be of interest.
> -
> - HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
> - /usr/include/malloc.h file that includes a declaration of struct
> - mallinfo. If so, it is included; else an SVID2/XPG2 compliant
> - version is declared below. These must be precisely the same for
> - mallinfo() to work.
> -
> -*/
> -
> -/* #define HAVE_USR_INCLUDE_MALLOC_H */
> -
> -#if HAVE_USR_INCLUDE_MALLOC_H
> -#include "/usr/include/malloc.h"
> -#else
> -
> -/* SVID2/XPG mallinfo structure */
> -
> -struct mallinfo {
> - int arena; /* total space allocated from system */
> - int ordblks; /* number of non-inuse chunks */
> - int smblks; /* unused -- always zero */
> - int hblks; /* number of mmapped regions */
> - int hblkhd; /* total space in mmapped regions */
> - int usmblks; /* unused -- always zero */
> - int fsmblks; /* unused -- always zero */
> - int uordblks; /* total allocated space */
> - int fordblks; /* total non-inuse space */
> - int keepcost; /* top-most, releasable (via malloc_trim) space */
> -};
> -
> -/* SVID2/XPG mallopt options */
> -
> -#define M_MXFAST 1 /* UNUSED in this malloc */
> -#define M_NLBLKS 2 /* UNUSED in this malloc */
> -#define M_GRAIN 3 /* UNUSED in this malloc */
> -#define M_KEEP 4 /* UNUSED in this malloc */
> -
> -#endif
> -
> -/* mallopt options that actually do something */
> -
> -#define M_TRIM_THRESHOLD -1
> -#define M_TOP_PAD -2
> -#define M_MMAP_THRESHOLD -3
> -#define M_MMAP_MAX -4
> -
> -
> -#ifndef DEFAULT_TRIM_THRESHOLD
> -#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
> -#endif
> -
> -/*
> - M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
> - to keep before releasing via malloc_trim in free().
> -
> - Automatic trimming is mainly useful in long-lived programs.
> - Because trimming via sbrk can be slow on some systems, and can
> - sometimes be wasteful (in cases where programs immediately
> - afterward allocate more large chunks) the value should be high
> - enough so that your overall system performance would improve by
> - releasing.
> -
> - The trim threshold and the mmap control parameters (see below)
> - can be traded off with one another. Trimming and mmapping are
> - two different ways of releasing unused memory back to the
> - system. Between these two, it is often possible to keep
> - system-level demands of a long-lived program down to a bare
> - minimum. For example, in one test suite of sessions measuring
> - the XF86 X server on Linux, using a trim threshold of 128K and a
> - mmap threshold of 192K led to near-minimal long term resource
> - consumption.
> -
> - If you are using this malloc in a long-lived program, it should
> - pay to experiment with these values. As a rough guide, you
> - might set to a value close to the average size of a process
> - (program) running on your system. Releasing this much memory
> - would allow such a process to run in memory. Generally, it's
> - worth it to tune for trimming rather tham memory mapping when a
> - program undergoes phases where several large chunks are
> - allocated and released in ways that can reuse each other's
> - storage, perhaps mixed with phases where there are no such
> - chunks at all. And in well-behaved long-lived programs,
> - controlling release of large blocks via trimming versus mapping
> - is usually faster.
> -
> - However, in most programs, these parameters serve mainly as
> - protection against the system-level effects of carrying around
> - massive amounts of unneeded memory. Since frequent calls to
> - sbrk, mmap, and munmap otherwise degrade performance, the default
> - parameters are set to relatively high values that serve only as
> - safeguards.
> -
> - The default trim value is high enough to cause trimming only in
> - fairly extreme (by current memory consumption standards) cases.
> - It must be greater than page size to have any useful effect. To
> - disable trimming completely, you can set to (unsigned long)(-1);
> -
> -
> -*/
> -
> -
> -#ifndef DEFAULT_TOP_PAD
> -#define DEFAULT_TOP_PAD (0)
> -#endif
> -
> -/*
> - M_TOP_PAD is the amount of extra `padding' space to allocate or
> - retain whenever sbrk is called. It is used in two ways internally:
> -
> - * When sbrk is called to extend the top of the arena to satisfy
> - a new malloc request, this much padding is added to the sbrk
> - request.
> -
> - * When malloc_trim is called automatically from free(),
> - it is used as the `pad' argument.
> -
> - In both cases, the actual amount of padding is rounded
> - so that the end of the arena is always a system page boundary.
> -
> - The main reason for using padding is to avoid calling sbrk so
> - often. Having even a small pad greatly reduces the likelihood
> - that nearly every malloc request during program start-up (or
> - after trimming) will invoke sbrk, which needlessly wastes
> - time.
> -
> - Automatic rounding-up to page-size units is normally sufficient
> - to avoid measurable overhead, so the default is 0. However, in
> - systems where sbrk is relatively slow, it can pay to increase
> - this value, at the expense of carrying around more memory than
> - the program needs.
> -
> -*/
> -
> -
> -#ifndef DEFAULT_MMAP_THRESHOLD
> -#define DEFAULT_MMAP_THRESHOLD (128 * 1024)
> -#endif
> -
> -/*
> -
> - M_MMAP_THRESHOLD is the request size threshold for using mmap()
> - to service a request. Requests of at least this size that cannot
> - be allocated using already-existing space will be serviced via mmap.
> - (If enough normal freed space already exists it is used instead.)
> -
> - Using mmap segregates relatively large chunks of memory so that
> - they can be individually obtained and released from the host
> - system. A request serviced through mmap is never reused by any
> - other request (at least not directly; the system may just so
> - happen to remap successive requests to the same locations).
> -
> - Segregating space in this way has the benefit that mmapped space
> - can ALWAYS be individually released back to the system, which
> - helps keep the system level memory demands of a long-lived
> - program low. Mapped memory can never become `locked' between
> - other chunks, as can happen with normally allocated chunks, which
> - menas that even trimming via malloc_trim would not release them.
> -
> - However, it has the disadvantages that:
> -
> - 1. The space cannot be reclaimed, consolidated, and then
> - used to service later requests, as happens with normal chunks.
> - 2. It can lead to more wastage because of mmap page alignment
> - requirements
> - 3. It causes malloc performance to be more dependent on host
> - system memory management support routines which may vary in
> - implementation quality and may impose arbitrary
> - limitations. Generally, servicing a request via normal
> - malloc steps is faster than going through a system's mmap.
> -
> - All together, these considerations should lead you to use mmap
> - only for relatively large requests.
> -
> -
> -*/
> -
> -
> -#ifndef DEFAULT_MMAP_MAX
> -#if HAVE_MMAP
> -#define DEFAULT_MMAP_MAX (64)
> -#else
> -#define DEFAULT_MMAP_MAX (0)
> -#endif
> -#endif
> -
> -/*
> - M_MMAP_MAX is the maximum number of requests to simultaneously
> - service using mmap. This parameter exists because:
> -
> - 1. Some systems have a limited number of internal tables for
> - use by mmap.
> - 2. In most systems, overreliance on mmap can degrade overall
> - performance.
> - 3. If a program allocates many large regions, it is probably
> - better off using normal sbrk-based allocation routines that
> - can reclaim and reallocate normal heap memory. Using a
> - small value allows transition into this mode after the
> - first few allocations.
> -
> - Setting to 0 disables all use of mmap. If HAVE_MMAP is not set,
> - the default value is 0, and attempts to set it to non-zero values
> - in mallopt will fail.
> -*/
> -
> -
> -/*
> - USE_DL_PREFIX will prefix all public routines with the string 'dl'.
> - Useful to quickly avoid procedure declaration conflicts and linker
> - symbol conflicts with existing memory allocation routines.
> -
> -*/
> -
> -/* #define USE_DL_PREFIX */
> -
> -
> -/*
> -
> - Special defines for linux libc
> -
> - Except when compiled using these special defines for Linux libc
> - using weak aliases, this malloc is NOT designed to work in
> - multithreaded applications. No semaphores or other concurrency
> - control are provided to ensure that multiple malloc or free calls
> - don't run at the same time, which could be disasterous. A single
> - semaphore could be used across malloc, realloc, and free (which is
> - essentially the effect of the linux weak alias approach). It would
> - be hard to obtain finer granularity.
> -
> -*/
> -
> -
> -#ifdef INTERNAL_LINUX_C_LIB
> -
> -#if __STD_C
> -
> -Void_t * __default_morecore_init (ptrdiff_t);
> -Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init;
> -
> -#else
> -
> -Void_t * __default_morecore_init ();
> -Void_t *(*__morecore)() = __default_morecore_init;
> -
> -#endif
> -
> -#define MORECORE (*__morecore)
> -#define MORECORE_FAILURE 0
> -#define MORECORE_CLEARS 1
> -
> -#else /* INTERNAL_LINUX_C_LIB */
> -
> -#if __STD_C
> -extern Void_t* sbrk(ptrdiff_t);
> -#else
> -extern Void_t* sbrk();
> -#endif
> -
> -#ifndef MORECORE
> -#define MORECORE sbrk
> -#endif
> -
> -#ifndef MORECORE_FAILURE
> -#define MORECORE_FAILURE -1
> -#endif
> -
> -#ifndef MORECORE_CLEARS
> -#define MORECORE_CLEARS 1
> -#endif
> -
> -#endif /* INTERNAL_LINUX_C_LIB */
> -
> -#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__)
> -
> -#define cALLOc __libc_calloc
> -#define fREe __libc_free
> -#define mALLOc __libc_malloc
> -#define mEMALIGn __libc_memalign
> -#define rEALLOc __libc_realloc
> -#define vALLOc __libc_valloc
> -#define pvALLOc __libc_pvalloc
> -#define mALLINFo __libc_mallinfo
> -#define mALLOPt __libc_mallopt
> -
> -#pragma weak calloc = __libc_calloc
> -#pragma weak free = __libc_free
> -#pragma weak cfree = __libc_free
> -#pragma weak malloc = __libc_malloc
> -#pragma weak memalign = __libc_memalign
> -#pragma weak realloc = __libc_realloc
> -#pragma weak valloc = __libc_valloc
> -#pragma weak pvalloc = __libc_pvalloc
> -#pragma weak mallinfo = __libc_mallinfo
> -#pragma weak mallopt = __libc_mallopt
> -
> -#else
> -
> -#ifdef USE_DL_PREFIX
> -#define cALLOc dlcalloc
> -#define fREe dlfree
> -#define mALLOc dlmalloc
> -#define mEMALIGn dlmemalign
> -#define rEALLOc dlrealloc
> -#define vALLOc dlvalloc
> -#define pvALLOc dlpvalloc
> -#define mALLINFo dlmallinfo
> -#define mALLOPt dlmallopt
> -#else /* USE_DL_PREFIX */
> -#define cALLOc calloc
> -#define fREe free
> -#define mALLOc malloc
> -#define mEMALIGn memalign
> -#define rEALLOc realloc
> -#define vALLOc valloc
> -#define pvALLOc pvalloc
> -#define mALLINFo mallinfo
> -#define mALLOPt mallopt
> -#endif /* USE_DL_PREFIX */
> -
> -#endif
> -
> -/* Public routines */
> -
> -#if __STD_C
> -
> -Void_t* mALLOc(size_t);
> -void fREe(Void_t*);
> -Void_t* rEALLOc(Void_t*, size_t);
> -Void_t* mEMALIGn(size_t, size_t);
> -Void_t* vALLOc(size_t);
> -Void_t* pvALLOc(size_t);
> -Void_t* cALLOc(size_t, size_t);
> -void cfree(Void_t*);
> -int malloc_trim(size_t);
> -size_t malloc_usable_size(Void_t*);
> -void malloc_stats();
> -int mALLOPt(int, int);
> -struct mallinfo mALLINFo(void);
> -#else
> -Void_t* mALLOc();
> -void fREe();
> -Void_t* rEALLOc();
> -Void_t* mEMALIGn();
> -Void_t* vALLOc();
> -Void_t* pvALLOc();
> -Void_t* cALLOc();
> -void cfree();
> -int malloc_trim();
> -size_t malloc_usable_size();
> -void malloc_stats();
> -int mALLOPt();
> -struct mallinfo mALLINFo();
> -#endif
> -
> -
> -#ifdef __cplusplus
> -}; /* end of extern "C" */
> -#endif
> -
> -/* ---------- To make a malloc.h, end cutting here ------------ */
> -
> -
> -/*
> - Emulation of sbrk for WIN32
> - All code within the ifdef WIN32 is untested by me.
> -
> - Thanks to Martin Fong and others for supplying this.
> -*/
> -
> -
> -#ifdef WIN32
> -
> -#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \
> -~(malloc_getpagesize-1))
> -#define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1))
> -
> -/* resrve 64MB to insure large contiguous space */
> -#define RESERVED_SIZE (1024*1024*64)
> -#define NEXT_SIZE (2048*1024)
> -#define TOP_MEMORY ((unsigned long)2*1024*1024*1024)
> -
> -struct GmListElement;
> -typedef struct GmListElement GmListElement;
> -
> -struct GmListElement
> -{
> - GmListElement* next;
> - void* base;
> -};
> -
> -static GmListElement* head = 0;
> -static unsigned int gNextAddress = 0;
> -static unsigned int gAddressBase = 0;
> -static unsigned int gAllocatedSize = 0;
> -
> -static
> -GmListElement* makeGmListElement (void* bas)
> -{
> - GmListElement* this;
> - this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement));
> - assert (this);
> - if (this)
> - {
> - this->base = bas;
> - this->next = head;
> - head = this;
> - }
> - return this;
> -}
> -
> -void gcleanup ()
> -{
> - BOOL rval;
> - assert ( (head == NULL) || (head->base == (void*)gAddressBase));
> - if (gAddressBase && (gNextAddress - gAddressBase))
> - {
> - rval = VirtualFree ((void*)gAddressBase,
> - gNextAddress - gAddressBase,
> - MEM_DECOMMIT);
> - assert (rval);
> - }
> - while (head)
> - {
> - GmListElement* next = head->next;
> - rval = VirtualFree (head->base, 0, MEM_RELEASE);
> - assert (rval);
> - LocalFree (head);
> - head = next;
> - }
> -}
> -
> -static
> -void* findRegion (void* start_address, unsigned long size)
> -{
> - MEMORY_BASIC_INFORMATION info;
> - if (size >= TOP_MEMORY) return NULL;
> -
> - while ((unsigned long)start_address + size < TOP_MEMORY)
> - {
> - VirtualQuery (start_address, &info, sizeof (info));
> - if ((info.State == MEM_FREE) && (info.RegionSize >= size))
> - return start_address;
> - else
> - {
> - /* Requested region is not available so see if the */
> - /* next region is available. Set 'start_address' */
> - /* to the next region and call 'VirtualQuery()' */
> - /* again. */
> -
> - start_address = (char*)info.BaseAddress + info.RegionSize;
> -
> - /* Make sure we start looking for the next region */
> - /* on the *next* 64K boundary. Otherwise, even if */
> - /* the new region is free according to */
> - /* 'VirtualQuery()', the subsequent call to */
> - /* 'VirtualAlloc()' (which follows the call to */
> - /* this routine in 'wsbrk()') will round *down* */
> - /* the requested address to a 64K boundary which */
> - /* we already know is an address in the */
> - /* unavailable region. Thus, the subsequent call */
> - /* to 'VirtualAlloc()' will fail and bring us back */
> - /* here, causing us to go into an infinite loop. */
> -
> - start_address =
> - (void *) AlignPage64K((unsigned long) start_address);
> - }
> - }
> - return NULL;
> -
> -}
> -
> -
> -void* wsbrk (long size)
> -{
> - void* tmp;
> - if (size > 0)
> - {
> - if (gAddressBase == 0)
> - {
> - gAllocatedSize = max (RESERVED_SIZE, AlignPage (size));
> - gNextAddress = gAddressBase =
> - (unsigned int)VirtualAlloc (NULL, gAllocatedSize,
> - MEM_RESERVE, PAGE_NOACCESS);
> - } else if (AlignPage (gNextAddress + size) > (gAddressBase +
> -gAllocatedSize))
> - {
> - long new_size = max (NEXT_SIZE, AlignPage (size));
> - void* new_address = (void*)(gAddressBase+gAllocatedSize);
> - do
> - {
> - new_address = findRegion (new_address, new_size);
> -
> - if (new_address == 0)
> - return (void*)-1;
> -
> - gAddressBase = gNextAddress =
> - (unsigned int)VirtualAlloc (new_address, new_size,
> - MEM_RESERVE, PAGE_NOACCESS);
> - /* repeat in case of race condition */
> - /* The region that we found has been snagged */
> - /* by another thread */
> - }
> - while (gAddressBase == 0);
> -
> - assert (new_address == (void*)gAddressBase);
> -
> - gAllocatedSize = new_size;
> -
> - if (!makeGmListElement ((void*)gAddressBase))
> - return (void*)-1;
> - }
> - if ((size + gNextAddress) > AlignPage (gNextAddress))
> - {
> - void* res;
> - res = VirtualAlloc ((void*)AlignPage (gNextAddress),
> - (size + gNextAddress -
> - AlignPage (gNextAddress)),
> - MEM_COMMIT, PAGE_READWRITE);
> - if (res == 0)
> - return (void*)-1;
> - }
> - tmp = (void*)gNextAddress;
> - gNextAddress = (unsigned int)tmp + size;
> - return tmp;
> - }
> - else if (size < 0)
> - {
> - unsigned int alignedGoal = AlignPage (gNextAddress + size);
> - /* Trim by releasing the virtual memory */
> - if (alignedGoal >= gAddressBase)
> - {
> - VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal,
> - MEM_DECOMMIT);
> - gNextAddress = gNextAddress + size;
> - return (void*)gNextAddress;
> - }
> - else
> - {
> - VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase,
> - MEM_DECOMMIT);
> - gNextAddress = gAddressBase;
> - return (void*)-1;
> - }
> - }
> - else
> - {
> - return (void*)gNextAddress;
> - }
> -}
> -
> -#endif
> -
> -\f
> -
> -/*
> - Type declarations
> -*/
> -
> -
> -struct malloc_chunk
> -{
> - INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
> - INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
> - struct malloc_chunk* fd; /* double links -- used only if free. */
> - struct malloc_chunk* bk;
> -};
> -
> -typedef struct malloc_chunk* mchunkptr;
> -
> -/*
> -
> - malloc_chunk details:
> -
> - (The following includes lightly edited explanations by Colin Plumb.)
> -
> - Chunks of memory are maintained using a `boundary tag' method as
> - described in e.g., Knuth or Standish. (See the paper by Paul
> - Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
> - survey of such techniques.) Sizes of free chunks are stored both
> - in the front of each chunk and at the end. This makes
> - consolidating fragmented chunks into bigger chunks very fast. The
> - size fields also hold bits representing whether chunks are free or
> - in use.
> -
> - An allocated chunk looks like this:
> -
> -
> - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> - | Size of previous chunk, if allocated | |
> - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> - | Size of chunk, in bytes |P|
> - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> - | User data starts here... .
> - . .
> - . (malloc_usable_space() bytes) .
> - . |
> -nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> - | Size of chunk |
> - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> -
> -
> - Where "chunk" is the front of the chunk for the purpose of most of
> - the malloc code, but "mem" is the pointer that is returned to the
> - user. "Nextchunk" is the beginning of the next contiguous chunk.
> -
> - Chunks always begin on even word boundries, so the mem portion
> - (which is returned to the user) is also on an even word boundary, and
> - thus double-word aligned.
> -
> - Free chunks are stored in circular doubly-linked lists, and look like this:
> -
> - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> - | Size of previous chunk |
> - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> - `head:' | Size of chunk, in bytes |P|
> - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> - | Forward pointer to next chunk in list |
> - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> - | Back pointer to previous chunk in list |
> - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> - | Unused space (may be 0 bytes long) .
> - . .
> - . |
> -nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> - `foot:' | Size of chunk, in bytes |
> - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> -
> - The P (PREV_INUSE) bit, stored in the unused low-order bit of the
> - chunk size (which is always a multiple of two words), is an in-use
> - bit for the *previous* chunk. If that bit is *clear*, then the
> - word before the current chunk size contains the previous chunk
> - size, and can be used to find the front of the previous chunk.
> - (The very first chunk allocated always has this bit set,
> - preventing access to non-existent (or non-owned) memory.)
> -
> - Note that the `foot' of the current chunk is actually represented
> - as the prev_size of the NEXT chunk. (This makes it easier to
> - deal with alignments etc).
> -
> - The two exceptions to all this are
> -
> - 1. The special chunk `top', which doesn't bother using the
> - trailing size field since there is no
> - next contiguous chunk that would have to index off it. (After
> - initialization, `top' is forced to always exist. If it would
> - become less than MINSIZE bytes long, it is replenished via
> - malloc_extend_top.)
> -
> - 2. Chunks allocated via mmap, which have the second-lowest-order
> - bit (IS_MMAPPED) set in their size fields. Because they are
> - never merged or traversed from any other chunk, they have no
> - foot size or inuse information.
> -
> - Available chunks are kept in any of several places (all declared below):
> -
> - * `av': An array of chunks serving as bin headers for consolidated
> - chunks. Each bin is doubly linked. The bins are approximately
> - proportionally (log) spaced. There are a lot of these bins
> - (128). This may look excessive, but works very well in
> - practice. All procedures maintain the invariant that no
> - consolidated chunk physically borders another one. Chunks in
> - bins are kept in size order, with ties going to the
> - approximately least recently used chunk.
> -
> - The chunks in each bin are maintained in decreasing sorted order by
> - size. This is irrelevant for the small bins, which all contain
> - the same-sized chunks, but facilitates best-fit allocation for
> - larger chunks. (These lists are just sequential. Keeping them in
> - order almost never requires enough traversal to warrant using
> - fancier ordered data structures.) Chunks of the same size are
> - linked with the most recently freed at the front, and allocations
> - are taken from the back. This results in LRU or FIFO allocation
> - order, which tends to give each chunk an equal opportunity to be
> - consolidated with adjacent freed chunks, resulting in larger free
> - chunks and less fragmentation.
> -
> - * `top': The top-most available chunk (i.e., the one bordering the
> - end of available memory) is treated specially. It is never
> - included in any bin, is used only if no other chunk is
> - available, and is released back to the system if it is very
> - large (see M_TRIM_THRESHOLD).
> -
> - * `last_remainder': A bin holding only the remainder of the
> - most recently split (non-top) chunk. This bin is checked
> - before other non-fitting chunks, so as to provide better
> - locality for runs of sequentially allocated chunks.
> -
> - * Implicitly, through the host system's memory mapping tables.
> - If supported, requests greater than a threshold are usually
> - serviced via calls to mmap, and then later released via munmap.
> -
> -*/
> -
> -
> -\f
> -
> -
> -/* sizes, alignments */
> -
> -#define SIZE_SZ (sizeof(INTERNAL_SIZE_T))
> -#define MALLOC_ALIGNMENT (SIZE_SZ + SIZE_SZ)
> -#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
> -#define MINSIZE (sizeof(struct malloc_chunk))
> -
> -/* conversion from malloc headers to user pointers, and back */
> -
> -#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ))
> -#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
> -
> -/* pad request bytes into a usable size */
> -
> -#define request2size(req) \
> - (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \
> - (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \
> - (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK)))
> -
> -/* Check if m has acceptable alignment */
> -
> -#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0)
> -
> -
> -\f
> -
> -/*
> - Physical chunk operations
> -*/
> -
> -
> -/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
> -
> -#define PREV_INUSE 0x1
> -
> -/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
> -
> -#define IS_MMAPPED 0x2
> -
> -/* Bits to mask off when extracting size */
> -
> -#define SIZE_BITS (PREV_INUSE|IS_MMAPPED)
> -
> -
> -/* Ptr to next physical malloc_chunk. */
> -
> -#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) ))
> -
> -/* Ptr to previous physical malloc_chunk */
> -
> -#define prev_chunk(p)\
> - ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) ))
> -
> -
> -/* Treat space at ptr + offset as a chunk */
> -
> -#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
> -
> -
> -\f
> -
> -/*
> - Dealing with use bits
> -*/
> -
> -/* extract p's inuse bit */
> -
> -#define inuse(p)\
> -((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE)
> -
> -/* extract inuse bit of previous chunk */
> -
> -#define prev_inuse(p) ((p)->size & PREV_INUSE)
> -
> -/* check for mmap()'ed chunk */
> -
> -#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
> -
> -/* set/clear chunk as in use without otherwise disturbing */
> -
> -#define set_inuse(p)\
> -((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE
> -
> -#define clear_inuse(p)\
> -((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE)
> -
> -/* check/set/clear inuse bits in known places */
> -
> -#define inuse_bit_at_offset(p, s)\
> - (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE)
> -
> -#define set_inuse_bit_at_offset(p, s)\
> - (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE)
> -
> -#define clear_inuse_bit_at_offset(p, s)\
> - (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE))
> -
> -
> -\f
> -
> -/*
> - Dealing with size fields
> -*/
> -
> -/* Get size, ignoring use bits */
> -
> -#define chunksize(p) ((p)->size & ~(SIZE_BITS))
> -
> -/* Set size at head, without disturbing its use bit */
> -
> -#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s)))
> -
> -/* Set size/use ignoring previous bits in header */
> -
> -#define set_head(p, s) ((p)->size = (s))
> -
> -/* Set size at footer (only when chunk is not in use) */
> -
> -#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s))
> -
> -
> -\f
> -
> -
> -/*
> - Bins
> -
> - The bins, `av_' are an array of pairs of pointers serving as the
> - heads of (initially empty) doubly-linked lists of chunks, laid out
> - in a way so that each pair can be treated as if it were in a
> - malloc_chunk. (This way, the fd/bk offsets for linking bin heads
> - and chunks are the same).
> -
> - Bins for sizes < 512 bytes contain chunks of all the same size, spaced
> - 8 bytes apart. Larger bins are approximately logarithmically
> - spaced. (See the table below.) The `av_' array is never mentioned
> - directly in the code, but instead via bin access macros.
> -
> - Bin layout:
> -
> - 64 bins of size 8
> - 32 bins of size 64
> - 16 bins of size 512
> - 8 bins of size 4096
> - 4 bins of size 32768
> - 2 bins of size 262144
> - 1 bin of size what's left
> -
> - There is actually a little bit of slop in the numbers in bin_index
> - for the sake of speed. This makes no difference elsewhere.
> -
> - The special chunks `top' and `last_remainder' get their own bins,
> - (this is implemented via yet more trickery with the av_ array),
> - although `top' is never properly linked to its bin since it is
> - always handled specially.
> -
> -*/
> -
> -#define NAV 128 /* number of bins */
> -
> -typedef struct malloc_chunk* mbinptr;
> -
> -/* access macros */
> -
> -#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ))
> -#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr)))
> -#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr)))
> -
> -/*
> - The first 2 bins are never indexed. The corresponding av_ cells are instead
> - used for bookkeeping. This is not to save space, but to simplify
> - indexing, maintain locality, and avoid some initialization tests.
> -*/
> -
> -#define top (bin_at(0)->fd) /* The topmost chunk */
> -#define last_remainder (bin_at(1)) /* remainder from last split */
> -
> -
> -/*
> - Because top initially points to its own bin with initial
> - zero size, thus forcing extension on the first malloc request,
> - we avoid having any special code in malloc to check whether
> - it even exists yet. But we still need to in malloc_extend_top.
> -*/
> -
> -#define initial_top ((mchunkptr)(bin_at(0)))
> -
> -/* Helper macro to initialize bins */
> -
> -#define IAV(i) bin_at(i), bin_at(i)
> -
> -static mbinptr av_[NAV * 2 + 2] = {
> - 0, 0,
> - IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7),
> - IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15),
> - IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23),
> - IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31),
> - IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39),
> - IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47),
> - IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55),
> - IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63),
> - IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71),
> - IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79),
> - IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87),
> - IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95),
> - IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103),
> - IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111),
> - IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119),
> - IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127)
> -};
> -
> -\f
> -
> -/* field-extraction macros */
> -
> -#define first(b) ((b)->fd)
> -#define last(b) ((b)->bk)
> -
> -/*
> - Indexing into bins
> -*/
> -
> -#define bin_index(sz) \
> -(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \
> - ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \
> - ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \
> - ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \
> - ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \
> - ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \
> - 126)
> -/*
> - bins for chunks < 512 are all spaced 8 bytes apart, and hold
> - identically sized chunks. This is exploited in malloc.
> -*/
> -
> -#define MAX_SMALLBIN 63
> -#define MAX_SMALLBIN_SIZE 512
> -#define SMALLBIN_WIDTH 8
> -
> -#define smallbin_index(sz) (((unsigned long)(sz)) >> 3)
> -
> -/*
> - Requests are `small' if both the corresponding and the next bin are small
> -*/
> -
> -#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH)
> -
> -\f
> -
> -/*
> - To help compensate for the large number of bins, a one-level index
> - structure is used for bin-by-bin searching. `binblocks' is a
> - one-word bitvector recording whether groups of BINBLOCKWIDTH bins
> - have any (possibly) non-empty bins, so they can be skipped over
> - all at once during during traversals. The bits are NOT always
> - cleared as soon as all bins in a block are empty, but instead only
> - when all are noticed to be empty during traversal in malloc.
> -*/
> -
> -#define BINBLOCKWIDTH 4 /* bins per block */
> -
> -#define binblocks (bin_at(0)->size) /* bitvector of nonempty blocks */
> -
> -/* bin<->block macros */
> -
> -#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH))
> -#define mark_binblock(ii) (binblocks |= idx2binblock(ii))
> -#define clear_binblock(ii) (binblocks &= ~(idx2binblock(ii)))
> -
> -
> -\f
> -
> -
> -/* Other static bookkeeping data */
> -
> -/* variables holding tunable values */
> -
> -static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD;
> -static unsigned long top_pad = DEFAULT_TOP_PAD;
> -static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX;
> -static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD;
> -
> -/* The first value returned from sbrk */
> -static char* sbrk_base = (char*)(-1);
> -
> -/* The maximum memory obtained from system via sbrk */
> -static unsigned long max_sbrked_mem = 0;
> -
> -/* The maximum via either sbrk or mmap */
> -static unsigned long max_total_mem = 0;
> -
> -/* internal working copy of mallinfo */
> -static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> -
> -/* The total memory obtained from system via sbrk */
> -#define sbrked_mem (current_mallinfo.arena)
> -
> -/* Tracking mmaps */
> -
> -static unsigned int n_mmaps = 0;
> -static unsigned int max_n_mmaps = 0;
> -static unsigned long mmapped_mem = 0;
> -static unsigned long max_mmapped_mem = 0;
> -
> -\f
> -
> -/*
> - Debugging support
> -*/
> -
> -#if DEBUG
> -
> -
> -/*
> - These routines make a number of assertions about the states
> - of data structures that should be true at all times. If any
> - are not true, it's very likely that a user program has somehow
> - trashed memory. (It's also possible that there is a coding error
> - in malloc. In which case, please report it!)
> -*/
> -
> -#if __STD_C
> -static void do_check_chunk(mchunkptr p)
> -#else
> -static void do_check_chunk(p) mchunkptr p;
> -#endif
> -{
> - INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
> -
> - /* No checkable chunk is mmapped */
> - assert(!chunk_is_mmapped(p));
> -
> - /* Check for legal address ... */
> - assert((char*)p >= sbrk_base);
> - if (p != top)
> - assert((char*)p + sz <= (char*)top);
> - else
> - assert((char*)p + sz <= sbrk_base + sbrked_mem);
> -
> -}
> -
> -
> -#if __STD_C
> -static void do_check_free_chunk(mchunkptr p)
> -#else
> -static void do_check_free_chunk(p) mchunkptr p;
> -#endif
> -{
> - INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
> - mchunkptr next = chunk_at_offset(p, sz);
> -
> - do_check_chunk(p);
> -
> - /* Check whether it claims to be free ... */
> - assert(!inuse(p));
> -
> - /* Unless a special marker, must have OK fields */
> - if ((long)sz >= (long)MINSIZE)
> - {
> - assert((sz & MALLOC_ALIGN_MASK) == 0);
> - assert(aligned_OK(chunk2mem(p)));
> - /* ... matching footer field */
> - assert(next->prev_size == sz);
> - /* ... and is fully consolidated */
> - assert(prev_inuse(p));
> - assert (next == top || inuse(next));
> -
> - /* ... and has minimally sane links */
> - assert(p->fd->bk == p);
> - assert(p->bk->fd == p);
> - }
> - else /* markers are always of size SIZE_SZ */
> - assert(sz == SIZE_SZ);
> -}
> -
> -#if __STD_C
> -static void do_check_inuse_chunk(mchunkptr p)
> -#else
> -static void do_check_inuse_chunk(p) mchunkptr p;
> -#endif
> -{
> - mchunkptr next = next_chunk(p);
> - do_check_chunk(p);
> -
> - /* Check whether it claims to be in use ... */
> - assert(inuse(p));
> -
> - /* ... and is surrounded by OK chunks.
> - Since more things can be checked with free chunks than inuse ones,
> - if an inuse chunk borders them and debug is on, it's worth doing them.
> - */
> - if (!prev_inuse(p))
> - {
> - mchunkptr prv = prev_chunk(p);
> - assert(next_chunk(prv) == p);
> - do_check_free_chunk(prv);
> - }
> - if (next == top)
> - {
> - assert(prev_inuse(next));
> - assert(chunksize(next) >= MINSIZE);
> - }
> - else if (!inuse(next))
> - do_check_free_chunk(next);
> -
> -}
> -
> -#if __STD_C
> -static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s)
> -#else
> -static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s;
> -#endif
> -{
> - INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE;
> - long room = sz - s;
> -
> - do_check_inuse_chunk(p);
> -
> - /* Legal size ... */
> - assert((long)sz >= (long)MINSIZE);
> - assert((sz & MALLOC_ALIGN_MASK) == 0);
> - assert(room >= 0);
> - assert(room < (long)MINSIZE);
> -
> - /* ... and alignment */
> - assert(aligned_OK(chunk2mem(p)));
> -
> -
> - /* ... and was allocated at front of an available chunk */
> - assert(prev_inuse(p));
> -
> -}
> -
> -
> -#define check_free_chunk(P) do_check_free_chunk(P)
> -#define check_inuse_chunk(P) do_check_inuse_chunk(P)
> -#define check_chunk(P) do_check_chunk(P)
> -#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N)
> -#else
> -#define check_free_chunk(P)
> -#define check_inuse_chunk(P)
> -#define check_chunk(P)
> -#define check_malloced_chunk(P,N)
> -#endif
> -
> -\f
> -
> -/*
> - Macro-based internal utilities
> -*/
> -
> -
> -/*
> - Linking chunks in bin lists.
> - Call these only with variables, not arbitrary expressions, as arguments.
> -*/
> -
> -/*
> - Place chunk p of size s in its bin, in size order,
> - putting it ahead of others of same size.
> -*/
> -
> -
> -#define frontlink(P, S, IDX, BK, FD) \
> -{ \
> - if (S < MAX_SMALLBIN_SIZE) \
> - { \
> - IDX = smallbin_index(S); \
> - mark_binblock(IDX); \
> - BK = bin_at(IDX); \
> - FD = BK->fd; \
> - P->bk = BK; \
> - P->fd = FD; \
> - FD->bk = BK->fd = P; \
> - } \
> - else \
> - { \
> - IDX = bin_index(S); \
> - BK = bin_at(IDX); \
> - FD = BK->fd; \
> - if (FD == BK) mark_binblock(IDX); \
> - else \
> - { \
> - while (FD != BK && S < chunksize(FD)) FD = FD->fd; \
> - BK = FD->bk; \
> - } \
> - P->bk = BK; \
> - P->fd = FD; \
> - FD->bk = BK->fd = P; \
> - } \
> -}
> -
> -
> -/* take a chunk off a list */
> -
> -#define unlink(P, BK, FD) \
> -{ \
> - BK = P->bk; \
> - FD = P->fd; \
> - FD->bk = BK; \
> - BK->fd = FD; \
> -} \
> -
> -/* Place p as the last remainder */
> -
> -#define link_last_remainder(P) \
> -{ \
> - last_remainder->fd = last_remainder->bk = P; \
> - P->fd = P->bk = last_remainder; \
> -}
> -
> -/* Clear the last_remainder bin */
> -
> -#define clear_last_remainder \
> - (last_remainder->fd = last_remainder->bk = last_remainder)
> -
> -
> -\f
> -
> -
> -/* Routines dealing with mmap(). */
> -
> -#if HAVE_MMAP
> -
> -#if __STD_C
> -static mchunkptr mmap_chunk(size_t size)
> -#else
> -static mchunkptr mmap_chunk(size) size_t size;
> -#endif
> -{
> - size_t page_mask = malloc_getpagesize - 1;
> - mchunkptr p;
> -
> -#ifndef MAP_ANONYMOUS
> - static int fd = -1;
> -#endif
> -
> - if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */
> -
> - /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because
> - * there is no following chunk whose prev_size field could be used.
> - */
> - size = (size + SIZE_SZ + page_mask) & ~page_mask;
> -
> -#ifdef MAP_ANONYMOUS
> - p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE,
> - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
> -#else /* !MAP_ANONYMOUS */
> - if (fd < 0)
> - {
> - fd = open("/dev/zero", O_RDWR);
> - if(fd < 0) return 0;
> - }
> - p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
> -#endif
> -
> - if(p == (mchunkptr)-1) return 0;
> -
> - n_mmaps++;
> - if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps;
> -
> - /* We demand that eight bytes into a page must be 8-byte aligned. */
> - assert(aligned_OK(chunk2mem(p)));
> -
> - /* The offset to the start of the mmapped region is stored
> - * in the prev_size field of the chunk; normally it is zero,
> - * but that can be changed in memalign().
> - */
> - p->prev_size = 0;
> - set_head(p, size|IS_MMAPPED);
> -
> - mmapped_mem += size;
> - if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
> - max_mmapped_mem = mmapped_mem;
> - if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
> - max_total_mem = mmapped_mem + sbrked_mem;
> - return p;
> -}
> -
> -#if __STD_C
> -static void munmap_chunk(mchunkptr p)
> -#else
> -static void munmap_chunk(p) mchunkptr p;
> -#endif
> -{
> - INTERNAL_SIZE_T size = chunksize(p);
> - int ret;
> -
> - assert (chunk_is_mmapped(p));
> - assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
> - assert((n_mmaps > 0));
> - assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0);
> -
> - n_mmaps--;
> - mmapped_mem -= (size + p->prev_size);
> -
> - ret = munmap((char *)p - p->prev_size, size + p->prev_size);
> -
> - /* munmap returns non-zero on failure */
> - assert(ret == 0);
> -}
> -
> -#if HAVE_MREMAP
> -
> -#if __STD_C
> -static mchunkptr mremap_chunk(mchunkptr p, size_t new_size)
> -#else
> -static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size;
> -#endif
> -{
> - size_t page_mask = malloc_getpagesize - 1;
> - INTERNAL_SIZE_T offset = p->prev_size;
> - INTERNAL_SIZE_T size = chunksize(p);
> - char *cp;
> -
> - assert (chunk_is_mmapped(p));
> - assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem));
> - assert((n_mmaps > 0));
> - assert(((size + offset) & (malloc_getpagesize-1)) == 0);
> -
> - /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
> - new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask;
> -
> - cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1);
> -
> - if (cp == (char *)-1) return 0;
> -
> - p = (mchunkptr)(cp + offset);
> -
> - assert(aligned_OK(chunk2mem(p)));
> -
> - assert((p->prev_size == offset));
> - set_head(p, (new_size - offset)|IS_MMAPPED);
> -
> - mmapped_mem -= size + offset;
> - mmapped_mem += new_size;
> - if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem)
> - max_mmapped_mem = mmapped_mem;
> - if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
> - max_total_mem = mmapped_mem + sbrked_mem;
> - return p;
> -}
> -
> -#endif /* HAVE_MREMAP */
> -
> -#endif /* HAVE_MMAP */
> -
> -
> -\f
> -
> -/*
> - Extend the top-most chunk by obtaining memory from system.
> - Main interface to sbrk (but see also malloc_trim).
> -*/
> -
> -#if __STD_C
> -static void malloc_extend_top(INTERNAL_SIZE_T nb)
> -#else
> -static void malloc_extend_top(nb) INTERNAL_SIZE_T nb;
> -#endif
> -{
> - char* brk; /* return value from sbrk */
> - INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */
> - INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */
> - char* new_brk; /* return of 2nd sbrk call */
> - INTERNAL_SIZE_T top_size; /* new size of top chunk */
> -
> - mchunkptr old_top = top; /* Record state of old top */
> - INTERNAL_SIZE_T old_top_size = chunksize(old_top);
> - char* old_end = (char*)(chunk_at_offset(old_top, old_top_size));
> -
> - /* Pad request with top_pad plus minimal overhead */
> -
> - INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE;
> - unsigned long pagesz = malloc_getpagesize;
> -
> - /* If not the first time through, round to preserve page boundary */
> - /* Otherwise, we need to correct to a page size below anyway. */
> - /* (We also correct below if an intervening foreign sbrk call.) */
> -
> - if (sbrk_base != (char*)(-1))
> - sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1);
> -
> - brk = (char*)(MORECORE (sbrk_size));
> -
> - /* Fail if sbrk failed or if a foreign sbrk call killed our space */
> - if (brk == (char*)(MORECORE_FAILURE) ||
> - (brk < old_end && old_top != initial_top))
> - return;
> -
> - sbrked_mem += sbrk_size;
> -
> - if (brk == old_end) /* can just add bytes to current top */
> - {
> - top_size = sbrk_size + old_top_size;
> - set_head(top, top_size | PREV_INUSE);
> - }
> - else
> - {
> - if (sbrk_base == (char*)(-1)) /* First time through. Record base */
> - sbrk_base = brk;
> - else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */
> - sbrked_mem += brk - (char*)old_end;
> -
> - /* Guarantee alignment of first new chunk made from this space */
> - front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
> - if (front_misalign > 0)
> - {
> - correction = (MALLOC_ALIGNMENT) - front_misalign;
> - brk += correction;
> - }
> - else
> - correction = 0;
> -
> - /* Guarantee the next brk will be at a page boundary */
> -
> - correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) &
> - ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size));
> -
> - /* Allocate correction */
> - new_brk = (char*)(MORECORE (correction));
> - if (new_brk == (char*)(MORECORE_FAILURE)) return;
> -
> - sbrked_mem += correction;
> -
> - top = (mchunkptr)brk;
> - top_size = new_brk - brk + correction;
> - set_head(top, top_size | PREV_INUSE);
> -
> - if (old_top != initial_top)
> - {
> -
> - /* There must have been an intervening foreign sbrk call. */
> - /* A double fencepost is necessary to prevent consolidation */
> -
> - /* If not enough space to do this, then user did something very wrong */
> - if (old_top_size < MINSIZE)
> - {
> - set_head(top, PREV_INUSE); /* will force null return from malloc */
> - return;
> - }
> -
> - /* Also keep size a multiple of MALLOC_ALIGNMENT */
> - old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK;
> - set_head_size(old_top, old_top_size);
> - chunk_at_offset(old_top, old_top_size )->size =
> - SIZE_SZ|PREV_INUSE;
> - chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size =
> - SIZE_SZ|PREV_INUSE;
> - /* If possible, release the rest. */
> - if (old_top_size >= MINSIZE)
> - fREe(chunk2mem(old_top));
> - }
> - }
> -
> - if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem)
> - max_sbrked_mem = sbrked_mem;
> - if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem)
> - max_total_mem = mmapped_mem + sbrked_mem;
> -
> - /* We always land on a page boundary */
> - assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0);
> -}
> -
> -
> -\f
> -
> -/* Main public routines */
> -
> -
> -/*
> - Malloc Algorthim:
> -
> - The requested size is first converted into a usable form, `nb'.
> - This currently means to add 4 bytes overhead plus possibly more to
> - obtain 8-byte alignment and/or to obtain a size of at least
> - MINSIZE (currently 16 bytes), the smallest allocatable size.
> - (All fits are considered `exact' if they are within MINSIZE bytes.)
> -
> - From there, the first successful of the following steps is taken:
> -
> - 1. The bin corresponding to the request size is scanned, and if
> - a chunk of exactly the right size is found, it is taken.
> -
> - 2. The most recently remaindered chunk is used if it is big
> - enough. This is a form of (roving) first fit, used only in
> - the absence of exact fits. Runs of consecutive requests use
> - the remainder of the chunk used for the previous such request
> - whenever possible. This limited use of a first-fit style
> - allocation strategy tends to give contiguous chunks
> - coextensive lifetimes, which improves locality and can reduce
> - fragmentation in the long run.
> -
> - 3. Other bins are scanned in increasing size order, using a
> - chunk big enough to fulfill the request, and splitting off
> - any remainder. This search is strictly by best-fit; i.e.,
> - the smallest (with ties going to approximately the least
> - recently used) chunk that fits is selected.
> -
> - 4. If large enough, the chunk bordering the end of memory
> - (`top') is split off. (This use of `top' is in accord with
> - the best-fit search rule. In effect, `top' is treated as
> - larger (and thus less well fitting) than any other available
> - chunk since it can be extended to be as large as necessary
> - (up to system limitations).
> -
> - 5. If the request size meets the mmap threshold and the
> - system supports mmap, and there are few enough currently
> - allocated mmapped regions, and a call to mmap succeeds,
> - the request is allocated via direct memory mapping.
> -
> - 6. Otherwise, the top of memory is extended by
> - obtaining more space from the system (normally using sbrk,
> - but definable to anything else via the MORECORE macro).
> - Memory is gathered from the system (in system page-sized
> - units) in a way that allows chunks obtained across different
> - sbrk calls to be consolidated, but does not require
> - contiguous memory. Thus, it should be safe to intersperse
> - mallocs with other sbrk calls.
> -
> -
> - All allocations are made from the the `lowest' part of any found
> - chunk. (The implementation invariant is that prev_inuse is
> - always true of any allocated chunk; i.e., that each allocated
> - chunk borders either a previously allocated and still in-use chunk,
> - or the base of its memory arena.)
> -
> -*/
> -
> -#if __STD_C
> -Void_t* mALLOc(size_t bytes)
> -#else
> -Void_t* mALLOc(bytes) size_t bytes;
> -#endif
> -{
> - mchunkptr victim; /* inspected/selected chunk */
> - INTERNAL_SIZE_T victim_size; /* its size */
> - int idx; /* index for bin traversal */
> - mbinptr bin; /* associated bin */
> - mchunkptr remainder; /* remainder from a split */
> - long remainder_size; /* its size */
> - int remainder_index; /* its bin index */
> - unsigned long block; /* block traverser bit */
> - int startidx; /* first bin of a traversed block */
> - mchunkptr fwd; /* misc temp for linking */
> - mchunkptr bck; /* misc temp for linking */
> - mbinptr q; /* misc temp */
> -
> - INTERNAL_SIZE_T nb;
> -
> - if ((long)bytes < 0) return 0;
> -
> - nb = request2size(bytes); /* padded request size; */
> -
> - /* Check for exact match in a bin */
> -
> - if (is_small_request(nb)) /* Faster version for small requests */
> - {
> - idx = smallbin_index(nb);
> -
> - /* No traversal or size check necessary for small bins. */
> -
> - q = bin_at(idx);
> - victim = last(q);
> -
> - /* Also scan the next one, since it would have a remainder < MINSIZE */
> - if (victim == q)
> - {
> - q = next_bin(q);
> - victim = last(q);
> - }
> - if (victim != q)
> - {
> - victim_size = chunksize(victim);
> - unlink(victim, bck, fwd);
> - set_inuse_bit_at_offset(victim, victim_size);
> - check_malloced_chunk(victim, nb);
> - return chunk2mem(victim);
> - }
> -
> - idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */
> -
> - }
> - else
> - {
> - idx = bin_index(nb);
> - bin = bin_at(idx);
> -
> - for (victim = last(bin); victim != bin; victim = victim->bk)
> - {
> - victim_size = chunksize(victim);
> - remainder_size = victim_size - nb;
> -
> - if (remainder_size >= (long)MINSIZE) /* too big */
> - {
> - --idx; /* adjust to rescan below after checking last remainder */
> - break;
> - }
> -
> - else if (remainder_size >= 0) /* exact fit */
> - {
> - unlink(victim, bck, fwd);
> - set_inuse_bit_at_offset(victim, victim_size);
> - check_malloced_chunk(victim, nb);
> - return chunk2mem(victim);
> - }
> - }
> -
> - ++idx;
> -
> - }
> -
> - /* Try to use the last split-off remainder */
> -
> - if ( (victim = last_remainder->fd) != last_remainder)
> - {
> - victim_size = chunksize(victim);
> - remainder_size = victim_size - nb;
> -
> - if (remainder_size >= (long)MINSIZE) /* re-split */
> - {
> - remainder = chunk_at_offset(victim, nb);
> - set_head(victim, nb | PREV_INUSE);
> - link_last_remainder(remainder);
> - set_head(remainder, remainder_size | PREV_INUSE);
> - set_foot(remainder, remainder_size);
> - check_malloced_chunk(victim, nb);
> - return chunk2mem(victim);
> - }
> -
> - clear_last_remainder;
> -
> - if (remainder_size >= 0) /* exhaust */
> - {
> - set_inuse_bit_at_offset(victim, victim_size);
> - check_malloced_chunk(victim, nb);
> - return chunk2mem(victim);
> - }
> -
> - /* Else place in bin */
> -
> - frontlink(victim, victim_size, remainder_index, bck, fwd);
> - }
> -
> - /*
> - If there are any possibly nonempty big-enough blocks,
> - search for best fitting chunk by scanning bins in blockwidth units.
> - */
> -
> - if ( (block = idx2binblock(idx)) <= binblocks)
> - {
> -
> - /* Get to the first marked block */
> -
> - if ( (block & binblocks) == 0)
> - {
> - /* force to an even block boundary */
> - idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
> - block <<= 1;
> - while ((block & binblocks) == 0)
> - {
> - idx += BINBLOCKWIDTH;
> - block <<= 1;
> - }
> - }
> -
> - /* For each possibly nonempty block ... */
> - for (;;)
> - {
> - startidx = idx; /* (track incomplete blocks) */
> - q = bin = bin_at(idx);
> -
> - /* For each bin in this block ... */
> - do
> - {
> - /* Find and use first big enough chunk ... */
> -
> - for (victim = last(bin); victim != bin; victim = victim->bk)
> - {
> - victim_size = chunksize(victim);
> - remainder_size = victim_size - nb;
> -
> - if (remainder_size >= (long)MINSIZE) /* split */
> - {
> - remainder = chunk_at_offset(victim, nb);
> - set_head(victim, nb | PREV_INUSE);
> - unlink(victim, bck, fwd);
> - link_last_remainder(remainder);
> - set_head(remainder, remainder_size | PREV_INUSE);
> - set_foot(remainder, remainder_size);
> - check_malloced_chunk(victim, nb);
> - return chunk2mem(victim);
> - }
> -
> - else if (remainder_size >= 0) /* take */
> - {
> - set_inuse_bit_at_offset(victim, victim_size);
> - unlink(victim, bck, fwd);
> - check_malloced_chunk(victim, nb);
> - return chunk2mem(victim);
> - }
> -
> - }
> -
> - bin = next_bin(bin);
> -
> - } while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
> -
> - /* Clear out the block bit. */
> -
> - do /* Possibly backtrack to try to clear a partial block */
> - {
> - if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
> - {
> - binblocks &= ~block;
> - break;
> - }
> - --startidx;
> - q = prev_bin(q);
> - } while (first(q) == q);
> -
> - /* Get to the next possibly nonempty block */
> -
> - if ( (block <<= 1) <= binblocks && (block != 0) )
> - {
> - while ((block & binblocks) == 0)
> - {
> - idx += BINBLOCKWIDTH;
> - block <<= 1;
> - }
> - }
> - else
> - break;
> - }
> - }
> -
> -
> - /* Try to use top chunk */
> -
> - /* Require that there be a remainder, ensuring top always exists */
> - if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
> - {
> -
> -#if HAVE_MMAP
> - /* If big and would otherwise need to extend, try to use mmap instead */
> - if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
> - (victim = mmap_chunk(nb)) != 0)
> - return chunk2mem(victim);
> -#endif
> -
> - /* Try to extend */
> - malloc_extend_top(nb);
> - if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE)
> - return 0; /* propagate failure */
> - }
> -
> - victim = top;
> - set_head(victim, nb | PREV_INUSE);
> - top = chunk_at_offset(victim, nb);
> - set_head(top, remainder_size | PREV_INUSE);
> - check_malloced_chunk(victim, nb);
> - return chunk2mem(victim);
> -
> -}
> -
> -
> -\f
> -
> -/*
> -
> - free() algorithm :
> -
> - cases:
> -
> - 1. free(0) has no effect.
> -
> - 2. If the chunk was allocated via mmap, it is release via munmap().
> -
> - 3. If a returned chunk borders the current high end of memory,
> - it is consolidated into the top, and if the total unused
> - topmost memory exceeds the trim threshold, malloc_trim is
> - called.
> -
> - 4. Other chunks are consolidated as they arrive, and
> - placed in corresponding bins. (This includes the case of
> - consolidating with the current `last_remainder').
> -
> -*/
> -
> -
> -#if __STD_C
> -void fREe(Void_t* mem)
> -#else
> -void fREe(mem) Void_t* mem;
> -#endif
> -{
> - mchunkptr p; /* chunk corresponding to mem */
> - INTERNAL_SIZE_T hd; /* its head field */
> - INTERNAL_SIZE_T sz; /* its size */
> - int idx; /* its bin index */
> - mchunkptr next; /* next contiguous chunk */
> - INTERNAL_SIZE_T nextsz; /* its size */
> - INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */
> - mchunkptr bck; /* misc temp for linking */
> - mchunkptr fwd; /* misc temp for linking */
> - int islr; /* track whether merging with last_remainder */
> -
> - if (mem == 0) /* free(0) has no effect */
> - return;
> -
> - p = mem2chunk(mem);
> - hd = p->size;
> -
> -#if HAVE_MMAP
> - if (hd & IS_MMAPPED) /* release mmapped memory. */
> - {
> - munmap_chunk(p);
> - return;
> - }
> -#endif
> -
> - check_inuse_chunk(p);
> -
> - sz = hd & ~PREV_INUSE;
> - next = chunk_at_offset(p, sz);
> - nextsz = chunksize(next);
> -
> - if (next == top) /* merge with top */
> - {
> - sz += nextsz;
> -
> - if (!(hd & PREV_INUSE)) /* consolidate backward */
> - {
> - prevsz = p->prev_size;
> - p = chunk_at_offset(p, -((long) prevsz));
> - sz += prevsz;
> - unlink(p, bck, fwd);
> - }
> -
> - set_head(p, sz | PREV_INUSE);
> - top = p;
> - if ((unsigned long)(sz) >= (unsigned long)trim_threshold)
> - malloc_trim(top_pad);
> - return;
> - }
> -
> - set_head(next, nextsz); /* clear inuse bit */
> -
> - islr = 0;
> -
> - if (!(hd & PREV_INUSE)) /* consolidate backward */
> - {
> - prevsz = p->prev_size;
> - p = chunk_at_offset(p, -((long) prevsz));
> - sz += prevsz;
> -
> - if (p->fd == last_remainder) /* keep as last_remainder */
> - islr = 1;
> - else
> - unlink(p, bck, fwd);
> - }
> -
> - if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */
> - {
> - sz += nextsz;
> -
> - if (!islr && next->fd == last_remainder) /* re-insert last_remainder */
> - {
> - islr = 1;
> - link_last_remainder(p);
> - }
> - else
> - unlink(next, bck, fwd);
> - }
> -
> -
> - set_head(p, sz | PREV_INUSE);
> - set_foot(p, sz);
> - if (!islr)
> - frontlink(p, sz, idx, bck, fwd);
> -}
> -
> -
> -\f
> -
> -
> -/*
> -
> - Realloc algorithm:
> -
> - Chunks that were obtained via mmap cannot be extended or shrunk
> - unless HAVE_MREMAP is defined, in which case mremap is used.
> - Otherwise, if their reallocation is for additional space, they are
> - copied. If for less, they are just left alone.
> -
> - Otherwise, if the reallocation is for additional space, and the
> - chunk can be extended, it is, else a malloc-copy-free sequence is
> - taken. There are several different ways that a chunk could be
> - extended. All are tried:
> -
> - * Extending forward into following adjacent free chunk.
> - * Shifting backwards, joining preceding adjacent space
> - * Both shifting backwards and extending forward.
> - * Extending into newly sbrked space
> -
> - Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a
> - size argument of zero (re)allocates a minimum-sized chunk.
> -
> - If the reallocation is for less space, and the new request is for
> - a `small' (<512 bytes) size, then the newly unused space is lopped
> - off and freed.
> -
> - The old unix realloc convention of allowing the last-free'd chunk
> - to be used as an argument to realloc is no longer supported.
> - I don't know of any programs still relying on this feature,
> - and allowing it would also allow too many other incorrect
> - usages of realloc to be sensible.
> -
> -
> -*/
> -
> -
> -#if __STD_C
> -Void_t* rEALLOc(Void_t* oldmem, size_t bytes)
> -#else
> -Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
> -#endif
> -{
> - INTERNAL_SIZE_T nb; /* padded request size */
> -
> - mchunkptr oldp; /* chunk corresponding to oldmem */
> - INTERNAL_SIZE_T oldsize; /* its size */
> -
> - mchunkptr newp; /* chunk to return */
> - INTERNAL_SIZE_T newsize; /* its size */
> - Void_t* newmem; /* corresponding user mem */
> -
> - mchunkptr next; /* next contiguous chunk after oldp */
> - INTERNAL_SIZE_T nextsize; /* its size */
> -
> - mchunkptr prev; /* previous contiguous chunk before oldp */
> - INTERNAL_SIZE_T prevsize; /* its size */
> -
> - mchunkptr remainder; /* holds split off extra space from newp */
> - INTERNAL_SIZE_T remainder_size; /* its size */
> -
> - mchunkptr bck; /* misc temp for linking */
> - mchunkptr fwd; /* misc temp for linking */
> -
> -#ifdef REALLOC_ZERO_BYTES_FREES
> - if (bytes == 0) { fREe(oldmem); return 0; }
> -#endif
> -
> - if ((long)bytes < 0) return 0;
> -
> - /* realloc of null is supposed to be same as malloc */
> - if (oldmem == 0) return mALLOc(bytes);
> -
> - newp = oldp = mem2chunk(oldmem);
> - newsize = oldsize = chunksize(oldp);
> -
> -
> - nb = request2size(bytes);
> -
> -#if HAVE_MMAP
> - if (chunk_is_mmapped(oldp))
> - {
> -#if HAVE_MREMAP
> - newp = mremap_chunk(oldp, nb);
> - if(newp) return chunk2mem(newp);
> -#endif
> - /* Note the extra SIZE_SZ overhead. */
> - if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
> - /* Must alloc, copy, free. */
> - newmem = mALLOc(bytes);
> - if (newmem == 0) return 0; /* propagate failure */
> - MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
> - munmap_chunk(oldp);
> - return newmem;
> - }
> -#endif
> -
> - check_inuse_chunk(oldp);
> -
> - if ((long)(oldsize) < (long)(nb))
> - {
> -
> - /* Try expanding forward */
> -
> - next = chunk_at_offset(oldp, oldsize);
> - if (next == top || !inuse(next))
> - {
> - nextsize = chunksize(next);
> -
> - /* Forward into top only if a remainder */
> - if (next == top)
> - {
> - if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE))
> - {
> - newsize += nextsize;
> - top = chunk_at_offset(oldp, nb);
> - set_head(top, (newsize - nb) | PREV_INUSE);
> - set_head_size(oldp, nb);
> - return chunk2mem(oldp);
> - }
> - }
> -
> - /* Forward into next chunk */
> - else if (((long)(nextsize + newsize) >= (long)(nb)))
> - {
> - unlink(next, bck, fwd);
> - newsize += nextsize;
> - goto split;
> - }
> - }
> - else
> - {
> - next = 0;
> - nextsize = 0;
> - }
> -
> - /* Try shifting backwards. */
> -
> - if (!prev_inuse(oldp))
> - {
> - prev = prev_chunk(oldp);
> - prevsize = chunksize(prev);
> -
> - /* try forward + backward first to save a later consolidation */
> -
> - if (next != 0)
> - {
> - /* into top */
> - if (next == top)
> - {
> - if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE))
> - {
> - unlink(prev, bck, fwd);
> - newp = prev;
> - newsize += prevsize + nextsize;
> - newmem = chunk2mem(newp);
> - MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
> - top = chunk_at_offset(newp, nb);
> - set_head(top, (newsize - nb) | PREV_INUSE);
> - set_head_size(newp, nb);
> - return newmem;
> - }
> - }
> -
> - /* into next chunk */
> - else if (((long)(nextsize + prevsize + newsize) >= (long)(nb)))
> - {
> - unlink(next, bck, fwd);
> - unlink(prev, bck, fwd);
> - newp = prev;
> - newsize += nextsize + prevsize;
> - newmem = chunk2mem(newp);
> - MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
> - goto split;
> - }
> - }
> -
> - /* backward only */
> - if (prev != 0 && (long)(prevsize + newsize) >= (long)nb)
> - {
> - unlink(prev, bck, fwd);
> - newp = prev;
> - newsize += prevsize;
> - newmem = chunk2mem(newp);
> - MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
> - goto split;
> - }
> - }
> -
> - /* Must allocate */
> -
> - newmem = mALLOc (bytes);
> -
> - if (newmem == 0) /* propagate failure */
> - return 0;
> -
> - /* Avoid copy if newp is next chunk after oldp. */
> - /* (This can only happen when new chunk is sbrk'ed.) */
> -
> - if ( (newp = mem2chunk(newmem)) == next_chunk(oldp))
> - {
> - newsize += chunksize(newp);
> - newp = oldp;
> - goto split;
> - }
> -
> - /* Otherwise copy, free, and exit */
> - MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
> - fREe(oldmem);
> - return newmem;
> - }
> -
> -
> - split: /* split off extra room in old or expanded chunk */
> -
> - if (newsize - nb >= MINSIZE) /* split off remainder */
> - {
> - remainder = chunk_at_offset(newp, nb);
> - remainder_size = newsize - nb;
> - set_head_size(newp, nb);
> - set_head(remainder, remainder_size | PREV_INUSE);
> - set_inuse_bit_at_offset(remainder, remainder_size);
> - fREe(chunk2mem(remainder)); /* let free() deal with it */
> - }
> - else
> - {
> - set_head_size(newp, newsize);
> - set_inuse_bit_at_offset(newp, newsize);
> - }
> -
> - check_inuse_chunk(newp);
> - return chunk2mem(newp);
> -}
> -
> -
> -\f
> -
> -/*
> -
> - memalign algorithm:
> -
> - memalign requests more than enough space from malloc, finds a spot
> - within that chunk that meets the alignment request, and then
> - possibly frees the leading and trailing space.
> -
> - The alignment argument must be a power of two. This property is not
> - checked by memalign, so misuse may result in random runtime errors.
> -
> - 8-byte alignment is guaranteed by normal malloc calls, so don't
> - bother calling memalign with an argument of 8 or less.
> -
> - Overreliance on memalign is a sure way to fragment space.
> -
> -*/
> -
> -
> -#if __STD_C
> -Void_t* mEMALIGn(size_t alignment, size_t bytes)
> -#else
> -Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
> -#endif
> -{
> - INTERNAL_SIZE_T nb; /* padded request size */
> - char* m; /* memory returned by malloc call */
> - mchunkptr p; /* corresponding chunk */
> - char* brk; /* alignment point within p */
> - mchunkptr newp; /* chunk to return */
> - INTERNAL_SIZE_T newsize; /* its size */
> - INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */
> - mchunkptr remainder; /* spare room at end to split off */
> - long remainder_size; /* its size */
> -
> - if ((long)bytes < 0) return 0;
> -
> - /* If need less alignment than we give anyway, just relay to malloc */
> -
> - if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes);
> -
> - /* Otherwise, ensure that it is at least a minimum chunk size */
> -
> - if (alignment < MINSIZE) alignment = MINSIZE;
> -
> - /* Call malloc with worst case padding to hit alignment. */
> -
> - nb = request2size(bytes);
> - m = (char*)(mALLOc(nb + alignment + MINSIZE));
> -
> - if (m == 0) return 0; /* propagate failure */
> -
> - p = mem2chunk(m);
> -
> - if ((((unsigned long)(m)) % alignment) == 0) /* aligned */
> - {
> -#if HAVE_MMAP
> - if(chunk_is_mmapped(p))
> - return chunk2mem(p); /* nothing more to do */
> -#endif
> - }
> - else /* misaligned */
> - {
> - /*
> - Find an aligned spot inside chunk.
> - Since we need to give back leading space in a chunk of at
> - least MINSIZE, if the first calculation places us at
> - a spot with less than MINSIZE leader, we can move to the
> - next aligned spot -- we've allocated enough total room so that
> - this is always possible.
> - */
> -
> - brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment));
> - if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment;
> -
> - newp = (mchunkptr)brk;
> - leadsize = brk - (char*)(p);
> - newsize = chunksize(p) - leadsize;
> -
> -#if HAVE_MMAP
> - if(chunk_is_mmapped(p))
> - {
> - newp->prev_size = p->prev_size + leadsize;
> - set_head(newp, newsize|IS_MMAPPED);
> - return chunk2mem(newp);
> - }
> -#endif
> -
> - /* give back leader, use the rest */
> -
> - set_head(newp, newsize | PREV_INUSE);
> - set_inuse_bit_at_offset(newp, newsize);
> - set_head_size(p, leadsize);
> - fREe(chunk2mem(p));
> - p = newp;
> -
> - assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
> - }
> -
> - /* Also give back spare room at the end */
> -
> - remainder_size = chunksize(p) - nb;
> -
> - if (remainder_size >= (long)MINSIZE)
> - {
> - remainder = chunk_at_offset(p, nb);
> - set_head(remainder, remainder_size | PREV_INUSE);
> - set_head_size(p, nb);
> - fREe(chunk2mem(remainder));
> - }
> -
> - check_inuse_chunk(p);
> - return chunk2mem(p);
> -
> -}
> -
> -\f
> -
> -
> -/*
> - valloc just invokes memalign with alignment argument equal
> - to the page size of the system (or as near to this as can
> - be figured out from all the includes/defines above.)
> -*/
> -
> -#if __STD_C
> -Void_t* vALLOc(size_t bytes)
> -#else
> -Void_t* vALLOc(bytes) size_t bytes;
> -#endif
> -{
> - return mEMALIGn (malloc_getpagesize, bytes);
> -}
> -
> -/*
> - pvalloc just invokes valloc for the nearest pagesize
> - that will accommodate request
> -*/
> -
> -
> -#if __STD_C
> -Void_t* pvALLOc(size_t bytes)
> -#else
> -Void_t* pvALLOc(bytes) size_t bytes;
> -#endif
> -{
> - size_t pagesize = malloc_getpagesize;
> - return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
> -}
> -
> -/*
> -
> - calloc calls malloc, then zeroes out the allocated chunk.
> -
> -*/
> -
> -#if __STD_C
> -Void_t* cALLOc(size_t n, size_t elem_size)
> -#else
> -Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
> -#endif
> -{
> - mchunkptr p;
> - INTERNAL_SIZE_T csz;
> -
> - INTERNAL_SIZE_T sz = n * elem_size;
> -
> -
> - /* check if expand_top called, in which case don't need to clear */
> -#if MORECORE_CLEARS
> - mchunkptr oldtop = top;
> - INTERNAL_SIZE_T oldtopsize = chunksize(top);
> -#endif
> - Void_t* mem = mALLOc (sz);
> -
> - if ((long)n < 0) return 0;
> -
> - if (mem == 0)
> - return 0;
> - else
> - {
> - p = mem2chunk(mem);
> -
> - /* Two optional cases in which clearing not necessary */
> -
> -
> -#if HAVE_MMAP
> - if (chunk_is_mmapped(p)) return mem;
> -#endif
> -
> - csz = chunksize(p);
> -
> -#if MORECORE_CLEARS
> - if (p == oldtop && csz > oldtopsize)
> - {
> - /* clear only the bytes from non-freshly-sbrked memory */
> - csz = oldtopsize;
> - }
> -#endif
> -
> - MALLOC_ZERO(mem, csz - SIZE_SZ);
> - return mem;
> - }
> -}
> -
> -/*
> -
> - cfree just calls free. It is needed/defined on some systems
> - that pair it with calloc, presumably for odd historical reasons.
> -
> -*/
> -
> -#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__)
> -#if __STD_C
> -void cfree(Void_t *mem)
> -#else
> -void cfree(mem) Void_t *mem;
> -#endif
> -{
> - fREe(mem);
> -}
> -#endif
> -
> -\f
> -
> -/*
> -
> - Malloc_trim gives memory back to the system (via negative
> - arguments to sbrk) if there is unused memory at the `high' end of
> - the malloc pool. You can call this after freeing large blocks of
> - memory to potentially reduce the system-level memory requirements
> - of a program. However, it cannot guarantee to reduce memory. Under
> - some allocation patterns, some large free blocks of memory will be
> - locked between two used chunks, so they cannot be given back to
> - the system.
> -
> - The `pad' argument to malloc_trim represents the amount of free
> - trailing space to leave untrimmed. If this argument is zero,
> - only the minimum amount of memory to maintain internal data
> - structures will be left (one page or less). Non-zero arguments
> - can be supplied to maintain enough trailing space to service
> - future expected allocations without having to re-obtain memory
> - from the system.
> -
> - Malloc_trim returns 1 if it actually released any memory, else 0.
> -
> -*/
> -
> -#if __STD_C
> -int malloc_trim(size_t pad)
> -#else
> -int malloc_trim(pad) size_t pad;
> -#endif
> -{
> - long top_size; /* Amount of top-most memory */
> - long extra; /* Amount to release */
> - char* current_brk; /* address returned by pre-check sbrk call */
> - char* new_brk; /* address returned by negative sbrk call */
> -
> - unsigned long pagesz = malloc_getpagesize;
> -
> - top_size = chunksize(top);
> - extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz;
> -
> - if (extra < (long)pagesz) /* Not enough memory to release */
> - return 0;
> -
> - else
> - {
> - /* Test to make sure no one else called sbrk */
> - current_brk = (char*)(MORECORE (0));
> - if (current_brk != (char*)(top) + top_size)
> - return 0; /* Apparently we don't own memory; must fail */
> -
> - else
> - {
> - new_brk = (char*)(MORECORE (-extra));
> -
> - if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */
> - {
> - /* Try to figure out what we have */
> - current_brk = (char*)(MORECORE (0));
> - top_size = current_brk - (char*)top;
> - if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */
> - {
> - sbrked_mem = current_brk - sbrk_base;
> - set_head(top, top_size | PREV_INUSE);
> - }
> - check_chunk(top);
> - return 0;
> - }
> -
> - else
> - {
> - /* Success. Adjust top accordingly. */
> - set_head(top, (top_size - extra) | PREV_INUSE);
> - sbrked_mem -= extra;
> - check_chunk(top);
> - return 1;
> - }
> - }
> - }
> -}
> -
> -\f
> -
> -/*
> - malloc_usable_size:
> -
> - This routine tells you how many bytes you can actually use in an
> - allocated chunk, which may be more than you requested (although
> - often not). You can use this many bytes without worrying about
> - overwriting other allocated objects. Not a particularly great
> - programming practice, but still sometimes useful.
> -
> -*/
> -
> -#if __STD_C
> -size_t malloc_usable_size(Void_t* mem)
> -#else
> -size_t malloc_usable_size(mem) Void_t* mem;
> -#endif
> -{
> - mchunkptr p;
> - if (mem == 0)
> - return 0;
> - else
> - {
> - p = mem2chunk(mem);
> - if(!chunk_is_mmapped(p))
> - {
> - if (!inuse(p)) return 0;
> - check_inuse_chunk(p);
> - return chunksize(p) - SIZE_SZ;
> - }
> - return chunksize(p) - 2*SIZE_SZ;
> - }
> -}
> -
> -
> -\f
> -
> -/* Utility to update current_mallinfo for malloc_stats and mallinfo() */
> -
> -static void malloc_update_mallinfo()
> -{
> - int i;
> - mbinptr b;
> - mchunkptr p;
> -#if DEBUG
> - mchunkptr q;
> -#endif
> -
> - INTERNAL_SIZE_T avail = chunksize(top);
> - int navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0;
> -
> - for (i = 1; i < NAV; ++i)
> - {
> - b = bin_at(i);
> - for (p = last(b); p != b; p = p->bk)
> - {
> -#if DEBUG
> - check_free_chunk(p);
> - for (q = next_chunk(p);
> - q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE;
> - q = next_chunk(q))
> - check_inuse_chunk(q);
> -#endif
> - avail += chunksize(p);
> - navail++;
> - }
> - }
> -
> - current_mallinfo.ordblks = navail;
> - current_mallinfo.uordblks = sbrked_mem - avail;
> - current_mallinfo.fordblks = avail;
> - current_mallinfo.hblks = n_mmaps;
> - current_mallinfo.hblkhd = mmapped_mem;
> - current_mallinfo.keepcost = chunksize(top);
> -
> -}
> -
> -\f
> -
> -/*
> -
> - malloc_stats:
> -
> - Prints on stderr the amount of space obtain from the system (both
> - via sbrk and mmap), the maximum amount (which may be more than
> - current if malloc_trim and/or munmap got called), the maximum
> - number of simultaneous mmap regions used, and the current number
> - of bytes allocated via malloc (or realloc, etc) but not yet
> - freed. (Note that this is the number of bytes allocated, not the
> - number requested. It will be larger than the number requested
> - because of alignment and bookkeeping overhead.)
> -
> -*/
> -
> -void malloc_stats()
> -{
> - malloc_update_mallinfo();
> - fprintf(stderr, "max system bytes = %10u\n",
> - (unsigned int)(max_total_mem));
> - fprintf(stderr, "system bytes = %10u\n",
> - (unsigned int)(sbrked_mem + mmapped_mem));
> - fprintf(stderr, "in use bytes = %10u\n",
> - (unsigned int)(current_mallinfo.uordblks + mmapped_mem));
> -#if HAVE_MMAP
> - fprintf(stderr, "max mmap regions = %10u\n",
> - (unsigned int)max_n_mmaps);
> -#endif
> -}
> -
> -/*
> - mallinfo returns a copy of updated current mallinfo.
> -*/
> -
> -struct mallinfo mALLINFo()
> -{
> - malloc_update_mallinfo();
> - return current_mallinfo;
> -}
> -
> -
> -\f
> -
> -/*
> - mallopt:
> -
> - mallopt is the general SVID/XPG interface to tunable parameters.
> - The format is to provide a (parameter-number, parameter-value) pair.
> - mallopt then sets the corresponding parameter to the argument
> - value if it can (i.e., so long as the value is meaningful),
> - and returns 1 if successful else 0.
> -
> - See descriptions of tunable parameters above.
> -
> -*/
> -
> -#if __STD_C
> -int mALLOPt(int param_number, int value)
> -#else
> -int mALLOPt(param_number, value) int param_number; int value;
> -#endif
> -{
> - switch(param_number)
> - {
> - case M_TRIM_THRESHOLD:
> - trim_threshold = value; return 1;
> - case M_TOP_PAD:
> - top_pad = value; return 1;
> - case M_MMAP_THRESHOLD:
> - mmap_threshold = value; return 1;
> - case M_MMAP_MAX:
> -#if HAVE_MMAP
> - n_mmaps_max = value; return 1;
> -#else
> - if (value != 0) return 0; else n_mmaps_max = value; return 1;
> -#endif
> -
> - default:
> - return 0;
> - }
> -}
> -
> -/*
> -
> -History:
> -
> - V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
> - * return null for negative arguments
> - * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com>
> - * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
> - (e.g. WIN32 platforms)
> - * Cleanup up header file inclusion for WIN32 platforms
> - * Cleanup code to avoid Microsoft Visual C++ compiler complaints
> - * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
> - memory allocation routines
> - * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
> - * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
> - usage of 'assert' in non-WIN32 code
> - * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
> - avoid infinite loop
> - * Always call 'fREe()' rather than 'free()'
> -
> - V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
> - * Fixed ordering problem with boundary-stamping
> -
> - V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
> - * Added pvalloc, as recommended by H.J. Liu
> - * Added 64bit pointer support mainly from Wolfram Gloger
> - * Added anonymously donated WIN32 sbrk emulation
> - * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
> - * malloc_extend_top: fix mask error that caused wastage after
> - foreign sbrks
> - * Add linux mremap support code from HJ Liu
> -
> - V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
> - * Integrated most documentation with the code.
> - * Add support for mmap, with help from
> - Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
> - * Use last_remainder in more cases.
> - * Pack bins using idea from colin@nyx10.cs.du.edu
> - * Use ordered bins instead of best-fit threshhold
> - * Eliminate block-local decls to simplify tracing and debugging.
> - * Support another case of realloc via move into top
> - * Fix error occuring when initial sbrk_base not word-aligned.
> - * Rely on page size for units instead of SBRK_UNIT to
> - avoid surprises about sbrk alignment conventions.
> - * Add mallinfo, mallopt. Thanks to Raymond Nijssen
> - (raymond@es.ele.tue.nl) for the suggestion.
> - * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
> - * More precautions for cases where other routines call sbrk,
> - courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
> - * Added macros etc., allowing use in linux libc from
> - H.J. Lu (hjl@gnu.ai.mit.edu)
> - * Inverted this history list
> -
> - V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
> - * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
> - * Removed all preallocation code since under current scheme
> - the work required to undo bad preallocations exceeds
> - the work saved in good cases for most test programs.
> - * No longer use return list or unconsolidated bins since
> - no scheme using them consistently outperforms those that don't
> - given above changes.
> - * Use best fit for very large chunks to prevent some worst-cases.
> - * Added some support for debugging
> -
> - V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
> - * Removed footers when chunks are in use. Thanks to
> - Paul Wilson (wilson@cs.texas.edu) for the suggestion.
> -
> - V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
> - * Added malloc_trim, with help from Wolfram Gloger
> - (wmglo@Dent.MED.Uni-Muenchen.DE).
> -
> - V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
> -
> - V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
> - * realloc: try to expand in both directions
> - * malloc: swap order of clean-bin strategy;
> - * realloc: only conditionally expand backwards
> - * Try not to scavenge used bins
> - * Use bin counts as a guide to preallocation
> - * Occasionally bin return list chunks in first scan
> - * Add a few optimizations from colin@nyx10.cs.du.edu
> -
> - V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
> - * faster bin computation & slightly different binning
> - * merged all consolidations to one part of malloc proper
> - (eliminating old malloc_find_space & malloc_clean_bin)
> - * Scan 2 returns chunks (not just 1)
> - * Propagate failure in realloc if malloc returns 0
> - * Add stuff to allow compilation on non-ANSI compilers
> - from kpv@research.att.com
> -
> - V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
> - * removed potential for odd address access in prev_chunk
> - * removed dependency on getpagesize.h
> - * misc cosmetics and a bit more internal documentation
> - * anticosmetics: mangled names in macros to evade debugger strangeness
> - * tested on sparc, hp-700, dec-mips, rs6000
> - with gcc & native cc (hp, dec only) allowing
> - Detlefs & Zorn comparison study (in SIGPLAN Notices.)
> -
> - Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
> - * Based loosely on libg++-1.2X malloc. (It retains some of the overall
> - structure of old version, but most details differ.)
> -
> -*/
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 2] Remove unused eth_get_name() prototype.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
2010-12-20 22:40 ` [PATCH 1] Delete unused file common/dlmalloc.src Krzysztof Halasa
@ 2010-12-20 22:42 ` Krzysztof Halasa
2010-12-20 22:44 ` [PATCH 3] Flash CFI: removed unused 'size' variable Krzysztof Halasa
` (14 subsequent siblings)
16 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 22:42 UTC (permalink / raw)
To: barebox
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/include/net.h b/include/net.h
index c695e5f..75088b8 100644
--- a/include/net.h
+++ b/include/net.h
@@ -55,7 +55,6 @@ int eth_open(void); /* open the device */
int eth_send(void *packet, int length); /* Send a packet */
int eth_rx(void); /* Check for received packets */
void eth_halt(void); /* stop SCC */
-char *eth_get_name(void); /* get name of current device */
/*
* Ethernet header
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 3] Flash CFI: removed unused 'size' variable.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
2010-12-20 22:40 ` [PATCH 1] Delete unused file common/dlmalloc.src Krzysztof Halasa
2010-12-20 22:42 ` [PATCH 2] Remove unused eth_get_name() prototype Krzysztof Halasa
@ 2010-12-20 22:44 ` Krzysztof Halasa
2010-12-20 22:45 ` [PATCH 4] Fix help text for "loadb" and "loady" commands Krzysztof Halasa
` (13 subsequent siblings)
16 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 22:44 UTC (permalink / raw)
To: barebox
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/drivers/nor/cfi_flash.c b/drivers/nor/cfi_flash.c
index 2fa2c6b..4af0370 100644
--- a/drivers/nor/cfi_flash.c
+++ b/drivers/nor/cfi_flash.c
@@ -995,7 +995,6 @@ static void cfi_init_mtd(struct flash_info *info)
static int cfi_probe (struct device_d *dev)
{
- unsigned long size = 0;
struct flash_info *info = xzalloc(sizeof(*info));
dev->priv = (void *)info;
@@ -1004,7 +1003,7 @@ static int cfi_probe (struct device_d *dev)
/* Init: no FLASHes known */
info->flash_id = FLASH_UNKNOWN;
- size += info->size = flash_get_size(info, dev->map_base);
+ info->size = flash_get_size(info, dev->map_base);
info->base = (void __iomem *)dev->map_base;
if (dev->size == 0) {
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 4] Fix help text for "loadb" and "loady" commands.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (2 preceding siblings ...)
2010-12-20 22:44 ` [PATCH 3] Flash CFI: removed unused 'size' variable Krzysztof Halasa
@ 2010-12-20 22:45 ` Krzysztof Halasa
2010-12-20 22:54 ` [PATCH 5] Fix error handling with malloc, memalign etc. Memalign() can't fail now Krzysztof Halasa
` (12 subsequent siblings)
16 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 22:45 UTC (permalink / raw)
To: barebox
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/commands/loadb.c b/commands/loadb.c
index faf4a97..dc0e517 100644
--- a/commands/loadb.c
+++ b/commands/loadb.c
@@ -802,7 +802,7 @@ static const __maybe_unused char cmd_loadb_help[] =
" -f file - where to download to - defaults to " DEF_FILE "\n"
" -o offset - what offset to download - defaults to 0\n"
" -b baud - baudrate at which to download - defaults to "
- "console baudrate"
+ "console baudrate\n"
" -c - Create file if it is not present - default disabled";
#ifdef CONFIG_CMD_LOADB
BAREBOX_CMD_START(loadb)
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 5] Fix error handling with malloc, memalign etc. Memalign() can't fail now.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (3 preceding siblings ...)
2010-12-20 22:45 ` [PATCH 4] Fix help text for "loadb" and "loady" commands Krzysztof Halasa
@ 2010-12-20 22:54 ` Krzysztof Halasa
2010-12-21 8:58 ` Sascha Hauer
2010-12-22 0:58 ` Jean-Christophe PLAGNIOL-VILLARD
2010-12-20 22:58 ` [PATCH 6] ARM: support big/little endian switching in "bootz" Krzysztof Halasa
` (11 subsequent siblings)
16 siblings, 2 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 22:54 UTC (permalink / raw)
To: barebox
Fix error handling with malloc, memalign etc. Memalign() can't fail now.
The idea is to panic() when there is no memory available for normal
operation. Exception: code which can consume arbitrary amount of RAM
(example: files allocated in ramfs) must report error instead of
panic().
This patch also fixes code which didn't check for NULL from malloc()
etc.
Usage: malloc() returns NULL when out of RAM.
xmalloc(), memalign() always return non-NULL or panic().
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu.c
index 08a57ce..fbaf627 100644
--- a/arch/arm/cpu/mmu.c
+++ b/arch/arm/cpu/mmu.c
@@ -95,13 +95,7 @@ void setup_dma_coherent(unsigned long offset)
void *dma_alloc_coherent(size_t size)
{
- void *mem;
-
- mem = memalign(4096, size);
- if (mem)
- return mem + dma_coherent_offset;
-
- return NULL;
+ return memalign(4096, size) + dma_coherent_offset;
}
unsigned long virt_to_phys(void *virt)
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index fdd23b5..7789cc9 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -28,7 +28,7 @@ void *phys_to_virt(unsigned long phys);
#else
static inline void *dma_alloc_coherent(size_t size)
{
- return malloc(size);
+ return xmalloc(size);
}
static inline void dma_free_coherent(void *mem)
diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c
index 287be0d..8409ca8 100644
--- a/arch/sandbox/os/common.c
+++ b/arch/sandbox/os/common.c
@@ -223,10 +223,7 @@ static int add_image(char *str, char *name)
struct stat s;
char *opt;
int fd, ret;
- struct hf_platform_data *hf = malloc(sizeof(struct hf_platform_data));
-
- if (!hf)
- return -1;
+ struct hf_platform_data *hf = xmalloc(sizeof(struct hf_platform_data));
file = strtok(str, ",");
while ((opt = strtok(NULL, ","))) {
@@ -285,11 +282,7 @@ int main(int argc, char *argv[])
char str[6];
int fdno = 0, envno = 0;
- ram = malloc(malloc_size);
- if (!ram) {
- printf("unable to get malloc space\n");
- exit(1);
- }
+ ram = xmalloc(malloc_size);
mem_malloc_init(ram, ram + malloc_size);
while (1) {
diff --git a/commands/edit.c b/commands/edit.c
index ca40d59..3519b09 100644
--- a/commands/edit.c
+++ b/commands/edit.c
@@ -184,10 +184,8 @@ static struct line *line_realloc(int len, struct line *line)
{
int size = 32;
- if (!line) {
+ if (!line)
line = xzalloc(sizeof(struct line));
- line->data = malloc(32);
- }
while (size < len)
size <<= 1;
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index ff63fbe..383c1d8 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -1,9 +1,9 @@
-
+#include <common.h>
#include <config.h>
#include <malloc.h>
#include <string.h>
#include <mem_malloc.h>
-
+#include <xfuncs.h>
#include <stdio.h>
#include <module.h>
@@ -1696,12 +1696,12 @@ void *memalign(size_t alignment, size_t bytes)
long remainder_size; /* its size */
if ((long) bytes < 0)
- return NULL;
+ panic("memalign: requested %i bytes\n", bytes);
/* If need less alignment than we give anyway, just relay to malloc */
if (alignment <= MALLOC_ALIGNMENT)
- return malloc(bytes);
+ return xmalloc(bytes);
/* Otherwise, ensure that it is at least a minimum chunk size */
@@ -1711,10 +1711,7 @@ void *memalign(size_t alignment, size_t bytes)
/* Call malloc with worst case padding to hit alignment. */
nb = request2size(bytes);
- m = (char*)(malloc (nb + alignment + MINSIZE));
-
- if (!m)
- return NULL; /* propagate failure */
+ m = (char*)(xmalloc(nb + alignment + MINSIZE));
p = mem2chunk(m);
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 717fea5..9d52beb 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -116,9 +116,7 @@ struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
{
struct clk_lookup_alloc *cla;
- cla = kzalloc(sizeof(*cla), GFP_KERNEL);
- if (!cla)
- return NULL;
+ cla = xzalloc(sizeof(*cla), GFP_KERNEL);
cla->cl.clk = clk;
if (con_id) {
@@ -150,8 +148,6 @@ int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
l = clkdev_alloc(r, alias, alias_dev_name);
clk_put(r);
- if (!l)
- return -ENODEV;
clkdev_add(l);
return 0;
}
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 04a1e4c..f1bfba7 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1334,9 +1334,6 @@ static struct driver_d mci_driver = {
static int mci_init(void)
{
sector_buf = memalign(32, 512);
- if (!sector_buf)
- return -ENOMEM;
-
return register_driver(&mci_driver);
}
diff --git a/drivers/net/at91_ether.c b/drivers/net/at91_ether.c
index 4563ff3..d5e26a1 100644
--- a/drivers/net/at91_ether.c
+++ b/drivers/net/at91_ether.c
@@ -263,7 +263,7 @@ static int at91rm9200_eth_init (struct device_d *dev)
struct eth_device *edev;
int i;
- edev = malloc(sizeof(struct eth_device));
+ edev = xmalloc(sizeof(struct eth_device));
dev->priv = edev;
edev->open = at91rm9200_eth_open;
diff --git a/drivers/net/cs8900.c b/drivers/net/cs8900.c
index 8120877..187c0fb 100644
--- a/drivers/net/cs8900.c
+++ b/drivers/net/cs8900.c
@@ -440,14 +440,14 @@ static int cs8900_probe(struct device_d *dev)
debug("cs8900_init()\n");
- priv = (struct cs8900_priv *)malloc(sizeof(*priv));
+ priv = (struct cs8900_priv *)xmalloc(sizeof(*priv));
priv->regs = (u16 *)dev->map_base;
if (cs8900_check_id(priv)) {
free(priv);
return -1;
}
- edev = (struct eth_device *)malloc(sizeof(struct eth_device));
+ edev = (struct eth_device *)xmalloc(sizeof(struct eth_device));
dev->type_data = edev;
edev->priv = priv;
diff --git a/drivers/net/fec_mpc5200.c b/drivers/net/fec_mpc5200.c
index 8b2cb4d..7528316 100644
--- a/drivers/net/fec_mpc5200.c
+++ b/drivers/net/fec_mpc5200.c
@@ -661,9 +661,9 @@ int mpc5xxx_fec_probe(struct device_d *dev)
struct eth_device *edev;
mpc5xxx_fec_priv *fec;
- edev = (struct eth_device *)malloc(sizeof(struct eth_device));
+ edev = (struct eth_device *)xmalloc(sizeof(struct eth_device));
dev->type_data = edev;
- fec = (mpc5xxx_fec_priv *)malloc(sizeof(*fec));
+ fec = (mpc5xxx_fec_priv *)xmalloc(sizeof(*fec));
edev->priv = fec;
edev->open = mpc5xxx_fec_open,
edev->init = mpc5xxx_fec_init,
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 522a9f1..a30a9c8 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -79,7 +79,7 @@ int tap_probe(struct device_d *dev)
struct tap_priv *priv;
int ret = 0;
- priv = malloc(sizeof(struct tap_priv));
+ priv = xmalloc(sizeof(struct tap_priv));
priv->name = "barebox";
priv->fd = tap_alloc(priv->name);
@@ -88,7 +88,7 @@ int tap_probe(struct device_d *dev)
goto out;
}
- edev = malloc(sizeof(struct eth_device));
+ edev = xmalloc(sizeof(struct eth_device));
dev->type_data = edev;
edev->priv = priv;
diff --git a/drivers/nor/cfi_flash.c b/drivers/nor/cfi_flash.c
index 4af0370..f7eeb2a 100644
--- a/drivers/nor/cfi_flash.c
+++ b/drivers/nor/cfi_flash.c
@@ -326,7 +326,7 @@ static ulong flash_get_size (struct flash_info *info, ulong base)
#endif
/* first only malloc space for the first sector */
- info->start = malloc(sizeof(ulong));
+ info->start = xmalloc(sizeof(ulong));
info->start[0] = base;
info->protect = 0;
@@ -415,8 +415,8 @@ static ulong flash_get_size (struct flash_info *info, ulong base)
cur_offset += erase_region_size * erase_region_count;
/* increase the space malloced for the sector start addresses */
- info->start = realloc(info->start, sizeof(ulong) * (erase_region_count + sect_cnt));
- info->protect = realloc(info->protect, sizeof(uchar) * (erase_region_count + sect_cnt));
+ info->start = xrealloc(info->start, sizeof(ulong) * (erase_region_count + sect_cnt));
+ info->protect = xrealloc(info->protect, sizeof(uchar) * (erase_region_count + sect_cnt));
for (j = 0; j < erase_region_count; j++) {
info->start[sect_cnt] = sector;
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index bc9b0de..442dbc4 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -157,8 +157,7 @@ static int pl011_probe(struct device_d *dev)
struct amba_uart_port *uart;
struct console_device *cdev;
- uart = malloc(sizeof(struct amba_uart_port));
-
+ uart = xmalloc(sizeof(struct amba_uart_port));
uart->clk = clk_get(dev, NULL);
if (IS_ERR(uart->clk))
diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c
index b99ec4d..1098952 100644
--- a/drivers/serial/atmel.c
+++ b/drivers/serial/atmel.c
@@ -398,8 +398,7 @@ static int atmel_serial_probe(struct device_d *dev)
struct atmel_uart_port *uart;
struct console_device *cdev;
- uart = malloc(sizeof(struct atmel_uart_port));
-
+ uart = xmalloc(sizeof(struct atmel_uart_port));
cdev = &uart->uart;
dev->type_data = cdev;
cdev->dev = dev;
diff --git a/drivers/serial/serial_blackfin.c b/drivers/serial/serial_blackfin.c
index 2101b7e..59b2fbb 100644
--- a/drivers/serial/serial_blackfin.c
+++ b/drivers/serial/serial_blackfin.c
@@ -115,7 +115,7 @@ static int blackfin_serial_probe(struct device_d *dev)
{
struct console_device *cdev;
- cdev = malloc(sizeof(struct console_device));
+ cdev = xmalloc(sizeof(struct console_device));
dev->type_data = cdev;
cdev->dev = dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c
index a7562f9..984d7f2 100644
--- a/drivers/serial/serial_imx.c
+++ b/drivers/serial/serial_imx.c
@@ -319,7 +319,7 @@ static int imx_serial_probe(struct device_d *dev)
struct imx_serial_priv *priv;
uint32_t val;
- priv = malloc(sizeof(*priv));
+ priv = xmalloc(sizeof(*priv));
cdev = &priv->cdev;
priv->regs = (void __force __iomem *)dev->map_base;
diff --git a/drivers/serial/serial_netx.c b/drivers/serial/serial_netx.c
index 7c09519..9d4b29e 100644
--- a/drivers/serial/serial_netx.c
+++ b/drivers/serial/serial_netx.c
@@ -140,7 +140,7 @@ static int netx_serial_probe(struct device_d *dev)
{
struct console_device *cdev;
- cdev = malloc(sizeof(struct console_device));
+ cdev = xmalloc(sizeof(struct console_device));
dev->type_data = cdev;
cdev->dev = dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
diff --git a/drivers/serial/serial_pl010.c b/drivers/serial/serial_pl010.c
index 1a6366f..7923ebb 100644
--- a/drivers/serial/serial_pl010.c
+++ b/drivers/serial/serial_pl010.c
@@ -141,7 +141,7 @@ static int pl010_probe(struct device_d *dev)
{
struct console_device *cdev;
- cdev = malloc(sizeof(struct console_device));
+ cdev = xmalloc(sizeof(struct console_device));
dev->type_data = cdev;
cdev->dev = dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c
index d7eac8f..0a17967 100644
--- a/drivers/serial/serial_s3c24x0.c
+++ b/drivers/serial/serial_s3c24x0.c
@@ -121,8 +121,7 @@ static int s3c24x0_serial_probe(struct device_d *dev)
{
struct console_device *cdev;
- cdev = malloc(sizeof(struct console_device));
-
+ cdev = xmalloc(sizeof(struct console_device));
dev->type_data = cdev;
cdev->dev = dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 978fdd1..fd70e62 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -903,9 +903,6 @@ static int __init composite_bind(struct usb_gadget *gadget)
int status = -ENOMEM;
cdev = xzalloc(sizeof *cdev);
- if (!cdev)
- return status;
-
cdev->gadget = gadget;
set_gadget_data(gadget, cdev);
INIT_LIST_HEAD(&cdev->configs);
diff --git a/drivers/usb/gadget/fsl_udc.c b/drivers/usb/gadget/fsl_udc.c
index 48fd0b5..20a5064 100644
--- a/drivers/usb/gadget/fsl_udc.c
+++ b/drivers/usb/gadget/fsl_udc.c
@@ -1016,8 +1016,6 @@ fsl_alloc_request(struct usb_ep *_ep)
struct fsl_req *req;
req = xzalloc(sizeof *req);
- if (!req)
- return NULL;
INIT_LIST_HEAD(&req->queue);
@@ -2095,7 +2093,7 @@ static int struct_udc_setup(struct fsl_udc *udc,
udc->status_req = container_of(fsl_alloc_request(NULL),
struct fsl_req, req);
/* allocate a small amount of memory to get valid address */
- udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
+ udc->status_req->req.buf = xmalloc(8);
udc->resume_state = USB_STATE_NOTATTACHED;
udc->usb_state = USB_STATE_POWERED;
udc->ep0_dir = 0;
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index cb65b19..edcb3f2 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -206,10 +206,6 @@ gs_alloc_req(struct usb_ep *ep, unsigned len)
if (req != NULL) {
req->length = len;
req->buf = memalign(32, len);
- if (req->buf == NULL) {
- usb_ep_free_request(ep, req);
- return NULL;
- }
}
return req;
diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c
index 0d4f5e7..9f6535d 100644
--- a/scripts/basic/docproc.c
+++ b/scripts/basic/docproc.c
@@ -122,8 +122,11 @@ int symfilecnt = 0;
void add_new_symbol(struct symfile *sym, char * symname)
{
- sym->symbollist =
- realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
+ sym->symbollist = realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
+ if (!sym->symbollist) {
+ fprintf(stderr, "docproc: out of memory\n");
+ exit(1);
+ }
sym->symbollist[sym->symbolcnt++].name = strdup(symname);
}
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 4075c35..08b75b6 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1317,7 +1317,7 @@ void buf_write(struct buffer *buf, const char *s, int len)
{
if (buf->size - buf->pos < len) {
buf->size += len + SZ;
- buf->p = realloc(buf->p, buf->size);
+ buf->p = NOFAIL(realloc(buf->p, buf->size));
}
strncpy(buf->p + buf->pos, s, len);
buf->pos += len;
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 5] Fix error handling with malloc, memalign etc. Memalign() can't fail now.
2010-12-20 22:54 ` [PATCH 5] Fix error handling with malloc, memalign etc. Memalign() can't fail now Krzysztof Halasa
@ 2010-12-21 8:58 ` Sascha Hauer
2010-12-22 0:58 ` Jean-Christophe PLAGNIOL-VILLARD
1 sibling, 0 replies; 41+ messages in thread
From: Sascha Hauer @ 2010-12-21 8:58 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
On Mon, Dec 20, 2010 at 11:54:49PM +0100, Krzysztof Halasa wrote:
> Fix error handling with malloc, memalign etc. Memalign() can't fail now.
>
> The idea is to panic() when there is no memory available for normal
> operation. Exception: code which can consume arbitrary amount of RAM
> (example: files allocated in ramfs) must report error instead of
> panic().
>
> This patch also fixes code which didn't check for NULL from malloc()
> etc.
>
> Usage: malloc() returns NULL when out of RAM.
> xmalloc(), memalign() always return non-NULL or panic().
>
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
>
> diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c
> index 287be0d..8409ca8 100644
> --- a/arch/sandbox/os/common.c
> +++ b/arch/sandbox/os/common.c
> @@ -223,10 +223,7 @@ static int add_image(char *str, char *name)
> struct stat s;
> char *opt;
> int fd, ret;
> - struct hf_platform_data *hf = malloc(sizeof(struct hf_platform_data));
> -
> - if (!hf)
> - return -1;
> + struct hf_platform_data *hf = xmalloc(sizeof(struct hf_platform_data));
>
> file = strtok(str, ",");
> while ((opt = strtok(NULL, ","))) {
> @@ -285,11 +282,7 @@ int main(int argc, char *argv[])
> char str[6];
> int fdno = 0, envno = 0;
>
> - ram = malloc(malloc_size);
> - if (!ram) {
> - printf("unable to get malloc space\n");
> - exit(1);
> - }
> + ram = xmalloc(malloc_size);
> mem_malloc_init(ram, ram + malloc_size);
>
> while (1) {
Don't change these. This is the file which connects barebox to the host
on sandbox. This is not the barebox malloc but the glibc malloc which is
called here.
> --- a/common/dlmalloc.c
> +++ b/common/dlmalloc.c
> @@ -1,9 +1,9 @@
> -
> +#include <common.h>
> #include <config.h>
> #include <malloc.h>
> #include <string.h>
> #include <mem_malloc.h>
> -
> +#include <xfuncs.h>
> #include <stdio.h>
> #include <module.h>
>
> @@ -1696,12 +1696,12 @@ void *memalign(size_t alignment, size_t bytes)
> long remainder_size; /* its size */
>
> if ((long) bytes < 0)
> - return NULL;
> + panic("memalign: requested %i bytes\n", bytes);
>
> /* If need less alignment than we give anyway, just relay to malloc */
>
> if (alignment <= MALLOC_ALIGNMENT)
> - return malloc(bytes);
> + return xmalloc(bytes);
>
> /* Otherwise, ensure that it is at least a minimum chunk size */
>
> @@ -1711,10 +1711,7 @@ void *memalign(size_t alignment, size_t bytes)
> /* Call malloc with worst case padding to hit alignment. */
>
> nb = request2size(bytes);
> - m = (char*)(malloc (nb + alignment + MINSIZE));
> -
> - if (!m)
> - return NULL; /* propagate failure */
> + m = (char*)(xmalloc(nb + alignment + MINSIZE));
>
> p = mem2chunk(m);
>
I think we shouldn't touch memalign but introduce a xmemalign function
instead. The x in the name stresses that the return value doesn't have
to be checked. Also it gives the user a chance explicitely call memalign
if he wishes to.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 5] Fix error handling with malloc, memalign etc. Memalign() can't fail now.
2010-12-20 22:54 ` [PATCH 5] Fix error handling with malloc, memalign etc. Memalign() can't fail now Krzysztof Halasa
2010-12-21 8:58 ` Sascha Hauer
@ 2010-12-22 0:58 ` Jean-Christophe PLAGNIOL-VILLARD
2010-12-22 19:00 ` Krzysztof Halasa
2010-12-23 10:36 ` Sascha Hauer
1 sibling, 2 replies; 41+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-12-22 0:58 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
> diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
> index 717fea5..9d52beb 100644
> --- a/drivers/clk/clkdev.c
> +++ b/drivers/clk/clkdev.c
please do not modify it I want to keep it as in the kernel
> @@ -116,9 +116,7 @@ struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
> {
> struct clk_lookup_alloc *cla;
>
> - cla = kzalloc(sizeof(*cla), GFP_KERNEL);
> - if (!cla)
> - return NULL;
> + cla = xzalloc(sizeof(*cla), GFP_KERNEL);
>
> cla->cl.clk = clk;
> if (con_id) {
> @@ -150,8 +148,6 @@ int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
>
> l = clkdev_alloc(r, alias, alias_dev_name);
> clk_put(r);
> - if (!l)
> - return -ENODEV;
> clkdev_add(l);
> return 0;
> }
Best Regards,
J.
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 5] Fix error handling with malloc, memalign etc. Memalign() can't fail now.
2010-12-22 0:58 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2010-12-22 19:00 ` Krzysztof Halasa
2010-12-23 11:25 ` Krzysztof Halasa
2010-12-23 10:36 ` Sascha Hauer
1 sibling, 1 reply; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-22 19:00 UTC (permalink / raw)
To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox
Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> writes:
>> --- a/drivers/clk/clkdev.c
>> +++ b/drivers/clk/clkdev.c
> please do not modify it I want to keep it as in the kernel
As you wish.
What's the rationale BTW?
--
Krzysztof Halasa
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 5] Fix error handling with malloc, memalign etc. Memalign() can't fail now.
2010-12-22 0:58 ` Jean-Christophe PLAGNIOL-VILLARD
2010-12-22 19:00 ` Krzysztof Halasa
@ 2010-12-23 10:36 ` Sascha Hauer
1 sibling, 0 replies; 41+ messages in thread
From: Sascha Hauer @ 2010-12-23 10:36 UTC (permalink / raw)
To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox, Krzysztof Halasa
On Wed, Dec 22, 2010 at 01:58:29AM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
>
> > diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
> > index 717fea5..9d52beb 100644
> > --- a/drivers/clk/clkdev.c
> > +++ b/drivers/clk/clkdev.c
> please do not modify it I want to keep it as in the kernel
That's not a good reason to not change it. Keeping it in sync with the kernel
should not be the showstopper for reasonable changes.
I agree that it's sometimes useful to not needlessly change complex
frameworks like UBI or mtd(-nand) to be able to apply later bugfixes or
features from the kernel, but this doesn't match for these trivial
changes in a simple framework.
Sascha
> > @@ -116,9 +116,7 @@ struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
> > {
> > struct clk_lookup_alloc *cla;
> >
> > - cla = kzalloc(sizeof(*cla), GFP_KERNEL);
> > - if (!cla)
> > - return NULL;
> > + cla = xzalloc(sizeof(*cla), GFP_KERNEL);
> >
> > cla->cl.clk = clk;
> > if (con_id) {
> > @@ -150,8 +148,6 @@ int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
> >
> > l = clkdev_alloc(r, alias, alias_dev_name);
> > clk_put(r);
> > - if (!l)
> > - return -ENODEV;
> > clkdev_add(l);
> > return 0;
> > }
>
> Best Regards,
> J.
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 6] ARM: support big/little endian switching in "bootz".
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (4 preceding siblings ...)
2010-12-20 22:54 ` [PATCH 5] Fix error handling with malloc, memalign etc. Memalign() can't fail now Krzysztof Halasa
@ 2010-12-20 22:58 ` Krzysztof Halasa
2010-12-21 7:41 ` Sascha Hauer
2010-12-22 1:00 ` Jean-Christophe PLAGNIOL-VILLARD
2010-12-20 23:01 ` [PATCH 7] Fix top-level Makefile to work with GNU make 3.82 Krzysztof Halasa
` (10 subsequent siblings)
16 siblings, 2 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 22:58 UTC (permalink / raw)
To: barebox
ARM: support big/little endian switching in "bootz".
Perhaps one should make this conditional? Mostly for big-endian
Barebox loading little-endian (e.g. armel Debian) Linux.
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/arch/arm/lib/armlinux.c b/arch/arm/lib/armlinux.c
index f826da6..4d1c757 100644
--- a/arch/arm/lib/armlinux.c
+++ b/arch/arm/lib/armlinux.c
@@ -41,6 +41,7 @@
#include <asm/setup.h>
#include <asm/barebox-arm.h>
#include <asm/armlinux.h>
+#include <asm/system.h>
static struct tag *params;
static int armlinux_architecture = 0;
@@ -85,9 +86,10 @@ static void setup_memory_tags(void)
}
}
-static void setup_commandline_tag(const char *commandline)
+static void setup_commandline_tag(const char *commandline, int swap)
{
const char *p;
+ size_t words;
if (!commandline)
return;
@@ -102,12 +104,18 @@ static void setup_commandline_tag(const char *commandline)
if (*p == '\0')
return;
+ words = (strlen(p) + 1 /* NUL */ + 3 /* round up */) >> 2;
params->hdr.tag = ATAG_CMDLINE;
- params->hdr.size =
- (sizeof (struct tag_header) + strlen(p) + 1 + 4) >> 2;
+ params->hdr.size = (sizeof(struct tag_header) >> 2) + words;
strcpy(params->u.cmdline.cmdline, p);
+ if (swap) {
+ u32 *cmd = (u32 *)params->u.cmdline.cmdline;
+ while (words--)
+ cmd[words] = swab32(cmd[words]);
+ }
+
params = tag_next(params);
}
@@ -156,13 +164,13 @@ static void setup_end_tag (void)
params->hdr.size = 0;
}
-static void setup_tags(struct image_data *data)
+static void setup_tags(struct image_data *data, int swap)
{
const char *commandline = getenv("bootargs");
setup_start_tag();
setup_memory_tags();
- setup_commandline_tag(commandline);
+ setup_commandline_tag(commandline, swap);
if (data && data->initrd)
setup_initrd_tag (&data->initrd->header);
@@ -231,7 +239,7 @@ static int do_bootm_linux(struct image_data *data)
debug("## Transferring control to Linux (at address 0x%p) ...\n",
theKernel);
- setup_tags(data);
+ setup_tags(data, 0);
if (relocate_image(data->os, (void *)image_get_load(os_header)))
return -1;
@@ -290,18 +298,21 @@ late_initcall(armlinux_register_image_handler);
#ifdef CONFIG_CMD_BOOTZ
struct zimage_header {
- u32 unsused[9];
+ u32 unused[9];
u32 magic;
u32 start;
u32 end;
};
+#define ZIMAGE_MAGIC 0x016F2818
+
static int do_bootz(struct command *cmdtp, int argc, char *argv[])
{
void (*theKernel)(int zero, int arch, void *params);
- int fd, ret;
+ int fd, ret, swap = 0;
struct zimage_header header;
void *zimage;
+ u32 end;
if (argc != 2) {
barebox_cmd_usage(cmdtp);
@@ -320,27 +331,51 @@ static int do_bootz(struct command *cmdtp, int argc, char *argv[])
goto err_out;
}
- if (header.magic != 0x016f2818) {
+ switch (header.magic) {
+ case swab32(ZIMAGE_MAGIC):
+ swap = 1;
+ /* fall through */
+ case ZIMAGE_MAGIC:
+ break;
+ default:
printf("invalid magic 0x%08x\n", header.magic);
goto err_out;
}
- zimage = xmalloc(header.end);
+ end = header.end;
+
+ if (swap)
+ end = swab32(end);
+
+ zimage = xmalloc(end);
memcpy(zimage, &header, sizeof(header));
- ret = read(fd, zimage + sizeof(header), header.end - sizeof(header));
- if (ret < header.end - sizeof(header)) {
+ ret = read(fd, zimage + sizeof(header), end - sizeof(header));
+ if (ret < end - sizeof(header)) {
printf("could not read %s\n", argv[1]);
goto err_out1;
}
+ if (swap) {
+ void *ptr;
+ for (ptr = zimage; ptr < zimage + end; ptr += 4)
+ *(u32 *)ptr = swab32(*(u32 *)ptr);
+ }
+
theKernel = zimage;
- printf("loaded zImage from %s with size %d\n", argv[1], header.end);
+ printf("loaded zImage from %s with size %d\n", argv[1], end);
- setup_tags(NULL);
+ setup_tags(NULL, swap);
shutdown_barebox();
+ if (swap) {
+ u32 reg;
+ __asm__ __volatile__("mrc p15, 0, %0, c1, c0" : "=r" (reg));
+ reg ^= CR_B; /* swap big-endian flag */
+ __asm__ __volatile__("mcr p15, 0, %0, c1, c0" :: "r" (reg));
+ }
+
theKernel(0, armlinux_architecture, armlinux_bootparams);
return 0;
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 6] ARM: support big/little endian switching in "bootz".
2010-12-20 22:58 ` [PATCH 6] ARM: support big/little endian switching in "bootz" Krzysztof Halasa
@ 2010-12-21 7:41 ` Sascha Hauer
2010-12-22 1:00 ` Jean-Christophe PLAGNIOL-VILLARD
1 sibling, 0 replies; 41+ messages in thread
From: Sascha Hauer @ 2010-12-21 7:41 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
Hi Krzysztof,
On Mon, Dec 20, 2010 at 11:58:11PM +0100, Krzysztof Halasa wrote:
> ARM: support big/little endian switching in "bootz".
> Perhaps one should make this conditional? Mostly for big-endian
> Barebox loading little-endian (e.g. armel Debian) Linux.
Making it conditional could require a lot of ifdefs, maybe you could
just do...
>
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
>
> diff --git a/arch/arm/lib/armlinux.c b/arch/arm/lib/armlinux.c
> index f826da6..4d1c757 100644
> --- a/arch/arm/lib/armlinux.c
> +++ b/arch/arm/lib/armlinux.c
> @@ -41,6 +41,7 @@
> #include <asm/setup.h>
> #include <asm/barebox-arm.h>
> #include <asm/armlinux.h>
> +#include <asm/system.h>
>
> static struct tag *params;
> static int armlinux_architecture = 0;
> @@ -85,9 +86,10 @@ static void setup_memory_tags(void)
> }
> }
>
> -static void setup_commandline_tag(const char *commandline)
> +static void setup_commandline_tag(const char *commandline, int swap)
> {
> const char *p;
> + size_t words;
>
> if (!commandline)
> return;
> @@ -102,12 +104,18 @@ static void setup_commandline_tag(const char *commandline)
> if (*p == '\0')
> return;
>
> + words = (strlen(p) + 1 /* NUL */ + 3 /* round up */) >> 2;
> params->hdr.tag = ATAG_CMDLINE;
> - params->hdr.size =
> - (sizeof (struct tag_header) + strlen(p) + 1 + 4) >> 2;
> + params->hdr.size = (sizeof(struct tag_header) >> 2) + words;
>
> strcpy(params->u.cmdline.cmdline, p);
>
> + if (swap) {
> + u32 *cmd = (u32 *)params->u.cmdline.cmdline;
> + while (words--)
> + cmd[words] = swab32(cmd[words]);
> + }
> +
> params = tag_next(params);
> }
>
> @@ -156,13 +164,13 @@ static void setup_end_tag (void)
> params->hdr.size = 0;
> }
>
> -static void setup_tags(struct image_data *data)
> +static void setup_tags(struct image_data *data, int swap)
> {
> const char *commandline = getenv("bootargs");
>
> setup_start_tag();
> setup_memory_tags();
> - setup_commandline_tag(commandline);
> + setup_commandline_tag(commandline, swap);
>
> if (data && data->initrd)
> setup_initrd_tag (&data->initrd->header);
> @@ -231,7 +239,7 @@ static int do_bootm_linux(struct image_data *data)
> debug("## Transferring control to Linux (at address 0x%p) ...\n",
> theKernel);
>
> - setup_tags(data);
> + setup_tags(data, 0);
>
> if (relocate_image(data->os, (void *)image_get_load(os_header)))
> return -1;
> @@ -290,18 +298,21 @@ late_initcall(armlinux_register_image_handler);
>
> #ifdef CONFIG_CMD_BOOTZ
> struct zimage_header {
> - u32 unsused[9];
> + u32 unused[9];
> u32 magic;
> u32 start;
> u32 end;
> };
>
> +#define ZIMAGE_MAGIC 0x016F2818
> +
> static int do_bootz(struct command *cmdtp, int argc, char *argv[])
> {
> void (*theKernel)(int zero, int arch, void *params);
> - int fd, ret;
> + int fd, ret, swap = 0;
> struct zimage_header header;
> void *zimage;
> + u32 end;
#ifdef CONFIG_BOOTZ_ENDIANESS_SWAP
int enable_swap = 1;
#else
int enable_swap = 0;
#endif
>
> if (argc != 2) {
> barebox_cmd_usage(cmdtp);
> @@ -320,27 +331,51 @@ static int do_bootz(struct command *cmdtp, int argc, char *argv[])
> goto err_out;
> }
>
> - if (header.magic != 0x016f2818) {
> + switch (header.magic) {
> + case swab32(ZIMAGE_MAGIC):
> + swap = 1;
swap = enable_swap;
This should be enough for the compiler to throw away most overhead.
> + /* fall through */
> + case ZIMAGE_MAGIC:
> + break;
> + default:
> printf("invalid magic 0x%08x\n", header.magic);
> goto err_out;
> }
>
> - zimage = xmalloc(header.end);
> + end = header.end;
> +
> + if (swap)
> + end = swab32(end);
> +
> + zimage = xmalloc(end);
> memcpy(zimage, &header, sizeof(header));
>
> - ret = read(fd, zimage + sizeof(header), header.end - sizeof(header));
> - if (ret < header.end - sizeof(header)) {
> + ret = read(fd, zimage + sizeof(header), end - sizeof(header));
> + if (ret < end - sizeof(header)) {
> printf("could not read %s\n", argv[1]);
> goto err_out1;
> }
>
> + if (swap) {
> + void *ptr;
> + for (ptr = zimage; ptr < zimage + end; ptr += 4)
> + *(u32 *)ptr = swab32(*(u32 *)ptr);
> + }
> +
> theKernel = zimage;
>
> - printf("loaded zImage from %s with size %d\n", argv[1], header.end);
> + printf("loaded zImage from %s with size %d\n", argv[1], end);
>
> - setup_tags(NULL);
> + setup_tags(NULL, swap);
>
> shutdown_barebox();
> + if (swap) {
> + u32 reg;
> + __asm__ __volatile__("mrc p15, 0, %0, c1, c0" : "=r" (reg));
> + reg ^= CR_B; /* swap big-endian flag */
> + __asm__ __volatile__("mcr p15, 0, %0, c1, c0" :: "r" (reg));
> + }
> +
> theKernel(0, armlinux_architecture, armlinux_bootparams);
>
> return 0;
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 6] ARM: support big/little endian switching in "bootz".
2010-12-20 22:58 ` [PATCH 6] ARM: support big/little endian switching in "bootz" Krzysztof Halasa
2010-12-21 7:41 ` Sascha Hauer
@ 2010-12-22 1:00 ` Jean-Christophe PLAGNIOL-VILLARD
2010-12-22 18:55 ` Krzysztof Halasa
1 sibling, 1 reply; 41+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-12-22 1:00 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
On 23:58 Mon 20 Dec , Krzysztof Halasa wrote:
> ARM: support big/little endian switching in "bootz".
> Perhaps one should make this conditional? Mostly for big-endian
> Barebox loading little-endian (e.g. armel Debian) Linux.
>
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
don't we need to update bootm and bootu too?
Best Regards,
J.
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 6] ARM: support big/little endian switching in "bootz".
2010-12-22 1:00 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2010-12-22 18:55 ` Krzysztof Halasa
2010-12-23 10:47 ` Sascha Hauer
0 siblings, 1 reply; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-22 18:55 UTC (permalink / raw)
To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox
Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> writes:
>> ARM: support big/little endian switching in "bootz".
> don't we need to update bootm and bootu too?
Probably. I've never used bootu, so it would be best if someone familiar
with it made the change (or at least tested it). Bootm - I will look at
it sometime (not using it at this time, but I think it's the only
command which can run Linux with external initramfs, I will need
something like that).
--
Krzysztof Halasa
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 6] ARM: support big/little endian switching in "bootz".
2010-12-22 18:55 ` Krzysztof Halasa
@ 2010-12-23 10:47 ` Sascha Hauer
0 siblings, 0 replies; 41+ messages in thread
From: Sascha Hauer @ 2010-12-23 10:47 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
On Wed, Dec 22, 2010 at 07:55:54PM +0100, Krzysztof Halasa wrote:
> Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> writes:
>
> >> ARM: support big/little endian switching in "bootz".
>
> > don't we need to update bootm and bootu too?
>
> Probably. I've never used bootu, so it would be best if someone familiar
> with it made the change (or at least tested it).
For bootu there will be no simple way to recognize the endianess. The
image started here is a raw binary image without any header information.
We'll probably need a command line switch to switch the endianess
manually.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 7] Fix top-level Makefile to work with GNU make 3.82.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (5 preceding siblings ...)
2010-12-20 22:58 ` [PATCH 6] ARM: support big/little endian switching in "bootz" Krzysztof Halasa
@ 2010-12-20 23:01 ` Krzysztof Halasa
2010-12-20 23:02 ` [PATCH 8] Cosmetic fixes, including format attributes for printf() and friends Krzysztof Halasa
` (9 subsequent siblings)
16 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 23:01 UTC (permalink / raw)
To: barebox
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/Makefile b/Makefile
index e0a7ed0..4e207cd 100644
--- a/Makefile
+++ b/Makefile
@@ -389,7 +389,11 @@ ifeq ($(config-targets),1)
include $(srctree)/arch/$(ARCH)/Makefile
export KBUILD_DEFCONFIG
-config %config: scripts_basic outputmakefile FORCE
+config: scripts_basic outputmakefile FORCE
+ $(Q)mkdir -p include/linux include/config
+ $(Q)$(MAKE) $(build)=scripts/kconfig $@
+
+%config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
@@ -1251,7 +1255,7 @@ target-dir = $(dir $@)
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
# Modules
-/ %/: prepare scripts FORCE
+%/: prepare scripts FORCE
$(Q)$(MAKE) $(build)=$(build-dir)
%.ko: prepare scripts FORCE
$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 8] Cosmetic fixes, including format attributes for printf() and friends.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (6 preceding siblings ...)
2010-12-20 23:01 ` [PATCH 7] Fix top-level Makefile to work with GNU make 3.82 Krzysztof Halasa
@ 2010-12-20 23:02 ` Krzysztof Halasa
2010-12-20 23:04 ` [PATCH 9] ARM: support big-endian processors Krzysztof Halasa
` (8 subsequent siblings)
16 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 23:02 UTC (permalink / raw)
To: barebox
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/commands/crc.c b/commands/crc.c
index 0873a1c..993074c 100644
--- a/commands/crc.c
+++ b/commands/crc.c
@@ -134,7 +134,7 @@ static int do_crc(struct command *cmdtp, int argc, char *argv[])
#endif
if (verify && crc != vcrc) {
- printf(" != 0x%08x ** ERROR **", vcrc);
+ printf(" != 0x%08lx ** ERROR **", vcrc);
err = 1;
}
diff --git a/commands/flash.c b/commands/flash.c
index 9a0eb50..a3f3508 100644
--- a/commands/flash.c
+++ b/commands/flash.c
@@ -63,7 +63,7 @@ static int do_flerase(struct command *cmdtp, int argc, char *argv[])
fd = open(filename, O_WRONLY);
if (fd < 0) {
- printf("open %s:", filename, errno_str());
+ printf("open %s: %s", filename, errno_str());
return 1;
}
@@ -139,7 +139,7 @@ static int do_protect(struct command *cmdtp, int argc, char *argv[])
fd = open(filename, O_WRONLY);
if (fd < 0) {
- printf("open %s:", filename, errno_str());
+ printf("open %s: %s", filename, errno_str());
return 1;
}
diff --git a/commands/go.c b/commands/go.c
index 0262940..6082fe5 100644
--- a/commands/go.c
+++ b/commands/go.c
@@ -55,7 +55,7 @@ static int do_go(struct command *cmdtp, int argc, char *argv[])
} else
addr = (void *)simple_strtoul(argv[1], NULL, 16);
- printf("## Starting application at 0x%08lX ...\n", addr);
+ printf("## Starting application at 0x%p ...\n", addr);
console_flush();
diff --git a/commands/loadb.c b/commands/loadb.c
index dc0e517..439a83a 100644
--- a/commands/loadb.c
+++ b/commands/loadb.c
@@ -625,7 +625,6 @@ static ulong load_serial_ymodem(void)
int res, wr;
connection_info_t info;
char ymodemBuf[1024];
- ulong store_addr = ~0;
ulong addr = 0;
size = 0;
diff --git a/commands/ls.c b/commands/ls.c
index 4f9c408..278a8bc 100644
--- a/commands/ls.c
+++ b/commands/ls.c
@@ -32,10 +32,10 @@
static void ls_one(const char *path, struct stat *s)
{
char modestr[11];
- unsigned long namelen = strlen(path);
+ unsigned int namelen = strlen(path);
mkmodestr(s->st_mode, modestr);
- printf("%s %10u %*.*s\n", modestr, s->st_size, namelen, namelen, path);
+ printf("%s %10lu %*.*s\n", modestr, s->st_size, namelen, namelen, path);
}
int ls(const char *path, ulong flags)
diff --git a/commands/menu.c b/commands/menu.c
index b9d6699..c3e0901 100644
--- a/commands/menu.c
+++ b/commands/menu.c
@@ -119,7 +119,7 @@ static int do_menu_entry_remove(struct cmd_menu *cm)
me = menu_entry_get_by_num(m, cm->num);
if (!me) {
- eprintf("Entry '%s' not found\n", cm->num);
+ eprintf("Entry '%i' not found\n", cm->num);
return -EINVAL;
}
diff --git a/drivers/net/netx_eth.c b/drivers/net/netx_eth.c
index 7d55a61..fd40f62 100644
--- a/drivers/net/netx_eth.c
+++ b/drivers/net/netx_eth.c
@@ -7,7 +7,6 @@
#include <mach/netx-eth.h>
#include <mach/netx-regs.h>
#include <xfuncs.h>
-#include <miidev.h>
#include <init.h>
#include <driver.h>
diff --git a/drivers/nor/cfi_flash.c b/drivers/nor/cfi_flash.c
index f7eeb2a..677a59d 100644
--- a/drivers/nor/cfi_flash.c
+++ b/drivers/nor/cfi_flash.c
@@ -485,7 +485,7 @@ static int __cfi_erase(struct cdev *cdev, size_t count, unsigned long offset,
unsigned long start, end;
int i, ret = 0;
- debug("%s: erase 0x%08x (size %d)\n", __func__, offset, count);
+ debug("%s: erase 0x%08lx (size %d)\n", __func__, offset, count);
start = find_sector(finfo, cdev->dev->map_base + offset);
end = find_sector(finfo, cdev->dev->map_base + offset + count - 1);
@@ -651,8 +651,8 @@ static int cfi_protect(struct cdev *cdev, size_t count, unsigned long offset, in
int i, ret = 0;
const char *action = (prot? "protect" : "unprotect");
- printf("%s: %s 0x%08x (size %d)\n", __FUNCTION__,
- action, cdev->dev->map_base + offset, count);
+ printf("%s: %s 0x%08lx (size %d)\n", __FUNCTION__,
+ action, cdev->dev->map_base + offset, count);
start = find_sector(finfo, cdev->dev->map_base + offset);
end = find_sector(finfo, cdev->dev->map_base + offset + count - 1);
@@ -1007,7 +1007,7 @@ static int cfi_probe (struct device_d *dev)
info->base = (void __iomem *)dev->map_base;
if (dev->size == 0) {
- printf("cfi_probe: size : 0x%08x\n", info->size);
+ printf("cfi_probe: size : 0x%08lx\n", info->size);
dev->size = info->size;
}
diff --git a/include/stdio.h b/include/stdio.h
index 8bc45fa..c824764 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -9,7 +9,7 @@
*/
/* serial stuff */
-void serial_printf (const char *fmt, ...);
+void serial_printf(const char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
/* stdin */
int tstc(void);
@@ -20,20 +20,22 @@ int getc(void);
void console_puts(unsigned int ch, const char *s);
void console_flush(void);
-static inline void puts(const char *s) {
+static inline void puts(const char *s)
+{
console_puts(CONSOLE_STDOUT, s);
}
-static inline void putchar(char c) {
+static inline void putchar(char c)
+{
console_putc(CONSOLE_STDOUT, c);
}
-int printf(const char *fmt, ...);
+int printf(const char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
int vprintf(const char *fmt, va_list args);
-int sprintf(char * buf, const char *fmt, ...);
-int snprintf(char *buf, size_t size, const char *fmt, ...);
+int sprintf(char *buf, const char *fmt, ...) __attribute__ ((format(printf, 2, 3)));
+int snprintf(char *buf, size_t size, const char *fmt, ...) __attribute__ ((format(printf, 3, 4)));
int vsprintf(char *buf, const char *fmt, va_list args);
-char *asprintf(const char *fmt, ...);
+char *asprintf(const char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
char *vasprintf(const char *fmt, va_list ap);
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
@@ -52,7 +54,7 @@ int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
#define stderr 2
#define MAX_FILES 128
-void fprintf(int file, const char *fmt, ...);
+void fprintf(int file, const char *fmt, ...) __attribute__ ((format(printf, 2, 3)));
int fputs(int file, const char *s);
int fputc(int file, const char c);
int ftstc(int file);
diff --git a/net/tftp.c b/net/tftp.c
index 6be8b8f..0f38b6b 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -218,7 +218,7 @@ static void tftp_handler(char *packet, unsigned len)
tftp_last_block = 0;
if (tftp_block != 1) { /* Assertion */
- printf("error: First block is not block 1 (%ld)\n",
+ printf("error: First block is not block 1 (%d)\n",
tftp_block);
tftp_err = -EINVAL;
tftp_state = STATE_DONE;
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 9] ARM: support big-endian processors.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (7 preceding siblings ...)
2010-12-20 23:02 ` [PATCH 8] Cosmetic fixes, including format attributes for printf() and friends Krzysztof Halasa
@ 2010-12-20 23:04 ` Krzysztof Halasa
2010-12-20 23:06 ` [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Krzysztof Halasa
` (7 subsequent siblings)
16 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 23:04 UTC (permalink / raw)
To: barebox
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/arch/arm/cpu/Kconfig b/arch/arm/cpu/Kconfig
index 7e17f9d..3572a1f 100644
--- a/arch/arm/cpu/Kconfig
+++ b/arch/arm/cpu/Kconfig
@@ -61,6 +61,9 @@ config CPU_32v7
comment "processor features"
+config ARCH_SUPPORTS_BIG_ENDIAN
+ bool
+
config CPU_BIG_ENDIAN
bool "Build big-endian kernel"
depends on ARCH_SUPPORTS_BIG_ENDIAN
diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c
index 53d7ac1..b55df5d 100644
--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -70,6 +70,9 @@ void __naked __bare_init reset(void)
r = get_cr();
r &= ~(CR_M | CR_C | CR_B | CR_S | CR_R | CR_V);
r |= CR_A | CR_I;
+#ifdef __ARMEB__
+ r |= CR_B;
+#endif
set_cr(r);
#ifdef CONFIG_MACH_DO_LOWLEVEL_INIT
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (8 preceding siblings ...)
2010-12-20 23:04 ` [PATCH 9] ARM: support big-endian processors Krzysztof Halasa
@ 2010-12-20 23:06 ` Krzysztof Halasa
2010-12-21 7:42 ` Belisko Marek
` (2 more replies)
2010-12-20 23:08 ` [PATCH 11] Silence few warnings Krzysztof Halasa
` (6 subsequent siblings)
16 siblings, 3 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 23:06 UTC (permalink / raw)
To: barebox
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8cb86cb..56b5a0d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -39,6 +39,13 @@ config ARCH_IMX
bool "Freescale iMX-based"
select GENERIC_GPIO
+config ARCH_IXP4XX
+ bool "Intel IXP4xx-based"
+ select CPU_32v5
+ select ARCH_SUPPORTS_BIG_ENDIAN
+ select CPU_BIG_ENDIAN
+ select ARCH_HAS_LOWLEVEL_INIT
+
config ARCH_STM
bool "SigmaTel/FSL iMX-based"
select GENERIC_GPIO
@@ -67,6 +74,7 @@ source arch/arm/cpu/Kconfig
source arch/arm/mach-at91/Kconfig
source arch/arm/mach-ep93xx/Kconfig
source arch/arm/mach-imx/Kconfig
+source arch/arm/mach-ixp4xx/Kconfig
source arch/arm/mach-stm/Kconfig
source arch/arm/mach-netx/Kconfig
source arch/arm/mach-nomadik/Kconfig
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 9729c23..2e9f99d 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -41,6 +41,7 @@ CPPFLAGS += $(CFLAGS_ABI) $(arch-y) $(tune-y)
machine-$(CONFIG_ARCH_AT91) := at91
machine-$(CONFIG_ARCH_EP93XX) := ep93xx
machine-$(CONFIG_ARCH_IMX) := imx
+machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx
machine-$(CONFIG_ARCH_STM) := stm
machine-$(CONFIG_ARCH_NOMADIK) := nomadik
machine-$(CONFIG_ARCH_NETX) := netx
@@ -73,6 +74,7 @@ board-$(CONFIG_MACH_FREESCALE_MX35_3STACK) := freescale-mx35-3-stack
board-$(CONFIG_MACH_IMX21ADS) := imx21ads
board-$(CONFIG_MACH_IMX27ADS) := imx27ads
board-$(CONFIG_MACH_MMCCPU) := mmccpu
+board-$(CONFIG_MACH_MULTILINK) := multilink
board-$(CONFIG_MACH_MX1ADS) := mx1ads
board-$(CONFIG_MACH_NOMADIK_8815NHK) := nhk8815
board-$(CONFIG_MACH_NXDB500) := netx
diff --git a/arch/arm/boards/multilink/Makefile b/arch/arm/boards/multilink/Makefile
new file mode 100644
index 0000000..d5a8bbc
--- /dev/null
+++ b/arch/arm/boards/multilink/Makefile
@@ -0,0 +1 @@
+obj-y += lowlevel_init.o multilink.o
diff --git a/arch/arm/boards/multilink/config.h b/arch/arm/boards/multilink/config.h
new file mode 100644
index 0000000..e69de29
diff --git a/arch/arm/boards/multilink/lowlevel_init.S b/arch/arm/boards/multilink/lowlevel_init.S
new file mode 100644
index 0000000..970ef72
--- /dev/null
+++ b/arch/arm/boards/multilink/lowlevel_init.S
@@ -0,0 +1,64 @@
+#include <mach/ixp4xx-regs.h>
+
+ .section ".text_bare_init", "ax"
+ .balign 0x40
+ .space 0x40 /* configuration block at 0x40 */
+
+ .macro DELAY_FOR cycles, reg0
+ ldr \reg0, =\cycles
+ subs \reg0, \reg0, #1
+ subne pc, pc, #0xc
+ .endm
+
+#define CFG_SDRAM_SIZE 0x50 /* u32 */
+#define CFG_SDRAM_CONF 0x54 /* u32 */
+#define CFG_SDRAM_MODE 0x58 /* u32 */
+#define CFG_SDRAM_REFRESH 0x5C /* u32 */
+
+.globl board_init_lowlevel
+board_init_lowlevel:
+ mov r8, #IXP4XX_EXP_BASE(0)
+ ldr r1, [r8, #CFG_SDRAM_CONF]
+ ldr r2, =IXP4XX_SDRAM_CONFIG
+ str r1, [r2]
+
+ /* disable refresh cycles */
+ mov r1, #0
+ add r2, r2, #4 /* r2 = IXP4XX_SDRAM_REFRESH */
+ str r1, [r2]
+
+ /* send NOP command */
+ mov r1, #3
+ add r3, r2, #4 /* r3 = IXP4XX_SDRAM_IR */
+ str r1, [r3]
+ DELAY_FOR 0x4000, r0
+
+ /* set SDRAM internal refresh */
+ ldr r1, [r8, #CFG_SDRAM_REFRESH]
+ str r1, [r2]
+ DELAY_FOR 0x4000, r0
+
+ /* send precharge-all command to close all open banks */
+ mov r1, #2
+ str r1, [r3]
+ DELAY_FOR 0x4000, r0
+
+ /* provide 8 auto-refresh cycles */
+ mov r1, #4
+ mov r4, #8
+1: str r1, [r3]
+ DELAY_FOR 0x100, r0
+ subs r4, r4, #1
+ bne 1b
+
+ /* set mode register in SDRAM */
+ ldr r1, [r8, #CFG_SDRAM_MODE]
+ str r1, [r3]
+ DELAY_FOR 0x4000, r0
+
+ /* send normal operation command */
+ mov r1, #6
+ str r1, [r3]
+ DELAY_FOR 0x4000, r0
+
+ mov pc, lr
diff --git a/arch/arm/boards/multilink/multilink.c b/arch/arm/boards/multilink/multilink.c
new file mode 100644
index 0000000..f2fb8f4
--- /dev/null
+++ b/arch/arm/boards/multilink/multilink.c
@@ -0,0 +1,144 @@
+//#define DEBUG
+#include <common.h>
+#include <errno.h>
+#include <init.h>
+#include <linux/types.h>
+#include <asm/armlinux.h>
+#include <asm/io.h>
+#include <generated/mach-types.h>
+#include <mach/ixp4xx-regs.h>
+#include <mach/platform.h>
+
+/* offsets from start of flash ROM = 0x50000000 */
+#define CFG_ETH0_ADDRESS 0x40 /* 6 bytes */
+#define CFG_ETH1_ADDRESS 0x46 /* 6 bytes */
+#define CFG_REV 0x4C /* u32 */
+#define CFG_SDRAM_SIZE 0x50 /* u32 */
+#define CFG_SDRAM_CONF 0x54 /* u32 */
+#define CFG_SDRAM_MODE 0x58 /* u32 */
+#define CFG_SDRAM_REFRESH 0x5C /* u32 */
+
+#define CFG_HW_BITS 0x60 /* u32 */
+#define CFG_HW_USB_PORTS 0x00000007 /* 0 = no NEC chip, 1-5 = ports # */
+#define CFG_HW_HAS_PCI_SLOT 0x00000008
+#define CFG_HW_HAS_ETH0 0x00000010
+#define CFG_HW_HAS_ETH1 0x00000020
+#define CFG_HW_HAS_HSS0 0x00000040
+#define CFG_HW_HAS_HSS1 0x00000080
+#define CFG_HW_HAS_UART0 0x00000100
+#define CFG_HW_HAS_UART1 0x00000200
+#define CFG_HW_HAS_EEPROM 0x00000400
+
+#define ETH_ALEN 6
+
+#define BAREBOX_START 0x00000
+#define BAREBOX_LENGTH 0x34000
+#define NPE_A_START (BAREBOX_START + BAREBOX_LENGTH)
+#define NPE_A_LENGTH 0x05000
+#define NPE_B_START (NPE_A_START + NPE_A_LENGTH)
+#define NPE_B_LENGTH 0x03000
+#define NPE_C_START (NPE_B_START + NPE_B_LENGTH)
+#define NPE_C_LENGTH 0x04000
+#define NPE_ENV0_START (NPE_C_START + NPE_C_LENGTH)
+#define NPE_ENV0_LENGTH 0x20000
+
+static struct device_d cfi_dev = {
+ .name = "cfi_flash",
+ .map_base = IXP4XX_EXP_BASE(0),
+ .size = 16 * 1024 * 1024,
+};
+
+static struct eth_plat_info eth_pinfo[2] = {
+ {
+ .regs = IXP4XX_EthB_BASE,
+ .npe = 1,
+ .phy = 0,
+ .rxq = 20,
+ .txreadyq = 29,
+ }, {
+ .regs = IXP4XX_EthC_BASE,
+ .npe = 2,
+ .phy = 1,
+ .rxq = 21,
+ .txreadyq = 30,
+ }
+};
+
+static struct device_d eth_dev[2] = {
+ {
+ .name = "ixp4xx_eth",
+ .platform_data = ð_pinfo[0],
+ }, {
+ .id = 1,
+ .name = "ixp4xx_eth",
+ .platform_data = ð_pinfo[1],
+ }
+};
+
+static struct memory_platform_data ram_pdata = {
+ .name = "ram0",
+ .flags = DEVFS_RDWR,
+};
+
+struct device_d sdram_dev = {
+ .id = -1,
+ .name = "mem",
+ .map_base = 0x00000000,
+ .size = 32 * 1024 * 1024,
+ .platform_data = &ram_pdata,
+};
+
+static inline u8 __init flash_readb(u32 addr)
+{
+ return __raw_readb(IXP4XX_EXP_BASE(0) + addr);
+}
+
+static int __init gml_devices_init(void)
+{
+ u32 hw_bits;
+ int i;
+
+ IXP4XX_EXP_CS0 = IXP4XX_EXP_EN | IXP4XX_EXP_INTEL |
+ IXP4XX_EXP_BITS(24) | IXP4XX_EXP_WR_EN | IXP4XX_EXP_BYTE_RD16;
+ i = register_device(&cfi_dev);
+ if (i)
+ goto out;
+
+ devfs_add_partition("nor0", BAREBOX_START, BAREBOX_LENGTH,
+ DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "barebox");
+ devfs_add_partition("nor0", NPE_A_START, NPE_A_LENGTH,
+ DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-A");
+ devfs_add_partition("nor0", NPE_B_START, NPE_B_LENGTH,
+ DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-B");
+ devfs_add_partition("nor0", NPE_C_START, NPE_C_LENGTH,
+ DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-C");
+ devfs_add_partition("nor0", NPE_ENV0_START, NPE_ENV0_LENGTH,
+ DEVFS_PARTITION_FIXED, "env0");
+
+ hw_bits = __raw_readl(IXP4XX_EXP_BASE(0) + CFG_HW_BITS);
+
+ if (hw_bits & CFG_HW_HAS_ETH0) {
+ for (i = 0; i < ETH_ALEN; i++)
+ eth_pinfo[0].hwaddr[i] = flash_readb(CFG_ETH0_ADDRESS + i);
+ register_device(ð_dev[0]);
+ }
+
+ if (hw_bits & CFG_HW_HAS_ETH1) {
+ for (i = 0; i < ETH_ALEN; i++)
+ eth_pinfo[1].hwaddr[i] = flash_readb(CFG_ETH1_ADDRESS + i);
+ register_device(ð_dev[1]);
+ }
+
+ sdram_dev.size = __raw_readl(IXP4XX_EXP_BASE(0) + CFG_SDRAM_SIZE);
+ i = register_device(&sdram_dev);
+ if (i)
+ goto out;
+
+ armlinux_add_dram(&sdram_dev);
+ armlinux_set_bootparams((void *)(0x00000100));
+ armlinux_set_architecture(MACH_TYPE_GORAMO_MLR);
+
+out:
+ return i;
+}
+device_initcall(gml_devices_init);
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
new file mode 100644
index 0000000..f5e4b41
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -0,0 +1,26 @@
+if ARCH_IXP4XX
+
+choice
+ prompt "IXP4xx Board Type"
+
+config MACH_MULTILINK
+ bool "Goramo MultiLink"
+ select MACH_HAS_LOWLEVEL_INIT
+endchoice
+
+config BOARDINFO
+ default "Goramo MultiLink" if MACH_MULTILINK
+
+config IXP4XX_QMGR
+ tristate "IXP4xx Queue Manager support"
+ help
+ This driver supports IXP4xx built-in hardware queue manager
+ and is required by the Ethernet driver.
+
+config IXP4XX_NPE
+ tristate "IXP4xx Network Processor Engine support"
+ help
+ This driver supports IXP4xx built-in network coprocessors
+ and is required by the Ethernet driver.
+
+endif
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
new file mode 100644
index 0000000..aa38991
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -0,0 +1,3 @@
+obj-y += lowlevel_init.o generic.o
+obj-$(CONFIG_IXP4XX_QMGR) += qmgr.o
+obj-$(CONFIG_IXP4XX_NPE) += npe.o
diff --git a/arch/arm/mach-ixp4xx/generic.c b/arch/arm/mach-ixp4xx/generic.c
new file mode 100644
index 0000000..02394a4
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/generic.c
@@ -0,0 +1,120 @@
+#include <common.h>
+#include <init.h>
+#include <ns16550.h>
+#include <asm/armlinux.h>
+#include <asm/io.h>
+#include <mach/ixp4xx-regs.h>
+
+#define OSTS_FREQUENCY 66666000
+
+void reset_cpu(ulong addr)
+{
+ /* Use on-chip reset capability */
+ /* This may not work on IXP425 rev. A0 */
+
+ IXP4XX_OSWK = IXP4XX_WDT_KEY;
+ IXP4XX_OSWT = 0; /* request immediate reset */
+ IXP4XX_OSWE = IXP4XX_WDT_RESET_ENABLE | IXP4XX_WDT_COUNT_ENABLE;
+ while (1)
+ ;
+}
+
+#include <clock.h>
+
+/**
+ * @brief Provide a simple clock read
+ *
+ * Nothing is simpler.. read direct from clock and provide it
+ * to the caller.
+ *
+ * @return clock counter
+ */
+static uint64_t ixp4xx_clocksource_read(void)
+{
+ return IXP4XX_OSTS;
+}
+
+static struct clocksource cs = {
+ .read = ixp4xx_clocksource_read,
+ .mask = 0xffffffff,
+ .shift = 10,
+};
+
+/**
+ * @brief Initialize the Clock
+ *
+ * We use the Time-Stamp Timer
+ *
+ * @return result of @ref init_clock
+ */
+static int ixp4xx_clocksource_init(void)
+{
+ cs.mult = clocksource_hz2mult(OSTS_FREQUENCY, cs.shift);
+
+ return init_clock(&cs);
+}
+
+/* Run me at boot time */
+core_initcall(ixp4xx_clocksource_init);
+
+
+#ifdef CONFIG_DRIVER_SERIAL_NS16550
+
+/**
+ * @brief UART port register read function for IXP4XX
+ *
+ * @param base base address of UART
+ * @param reg_idx register index
+ *
+ * @return character read from register
+ */
+unsigned int ixp4xx_uart_read(unsigned long base, unsigned char reg_idx)
+{
+ return readb(4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
+}
+EXPORT_SYMBOL(ixp4xx_uart_read);
+
+/**
+ * @brief UART port register write function for IXP4XX
+ *
+ * @param val value to write
+ * @param base base address of UART
+ * @param reg_idx register index
+ *
+ * @return void
+ */
+void ixp4xx_uart_write(unsigned int val, unsigned long base, unsigned char reg_idx)
+{
+ writeb(val, 4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
+}
+EXPORT_SYMBOL(ixp4xx_uart_write);
+
+
+static struct NS16550_plat serial_plat = {
+ .clock = 14745600,
+ .f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR,
+ .reg_read = ixp4xx_uart_read,
+ .reg_write = ixp4xx_uart_write,
+};
+
+static struct device_d ixp4xx_serial_device = {
+ .name = "serial_ns16550",
+ .map_base = (u32)IXP4XX_UART1_BASE,
+ .size = 1024,
+ .platform_data = (void *)&serial_plat,
+};
+
+/**
+ * @brief UART serial port initialization
+ *
+ * @return result of device registration
+ */
+static int ixp4xx_console_init(void)
+{
+ /* Register the serial port */
+ return register_device(&ixp4xx_serial_device);
+}
+
+console_initcall(ixp4xx_console_init);
+
+#endif /* CONFIG_DRIVER_SERIAL_NS16550 */
diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h
new file mode 100644
index 0000000..3de021e
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/mach-ixp4xx/include/mach/cpu.h
+ *
+ * IXP4XX cpu type detection
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ASM_ARCH_CPU_H__
+#define __ASM_ARCH_CPU_H__
+
+#include <linux/types.h>
+
+/* Processor id value in CP15 Register 0 */
+#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */
+#define IXP42X_PROCESSOR_ID_MASK 0xffffffc0
+
+#define IXP43X_PROCESSOR_ID_VALUE 0x69054040
+#define IXP43X_PROCESSOR_ID_MASK 0xfffffff0
+
+#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */
+#define IXP46X_PROCESSOR_ID_MASK 0xfffffff0
+
+#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
+ IXP42X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
+ IXP42X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \
+ IXP43X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \
+ IXP46X_PROCESSOR_ID_VALUE)
+
+/*
+ * The CPU ID never changes at run time, so we might as well tell the
+ * compiler that it's constant. Use this function to read the CPU ID
+ * rather than directly reading processor_id or read_cpuid() directly.
+ */
+static inline u32 __attribute_const__ read_cpuid_id(void)
+{
+ u32 val;
+ asm("mrc p15, 0, %0, c0, c0, 0" : "=r" (val) : : "cc");
+
+ return val;
+}
+
+static inline u32 ixp4xx_read_feature_bits(void)
+{
+ u32 val = ~IXP4XX_EXP_CFG2;
+
+ if (cpu_is_ixp42x_rev_a0())
+ return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
+ IXP4XX_FEATURE_AES);
+ if (cpu_is_ixp42x())
+ return val & IXP42X_FEATURE_MASK;
+ if (cpu_is_ixp43x())
+ return val & IXP43X_FEATURE_MASK;
+ return val & IXP46X_FEATURE_MASK;
+}
+
+static inline void ixp4xx_write_feature_bits(u32 value)
+{
+ IXP4XX_EXP_CFG2 = ~value;
+}
+
+#endif /* _ASM_ARCH_CPU_H */
diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
new file mode 100644
index 0000000..da4dc8a
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
@@ -0,0 +1,365 @@
+/*
+ * Register definitions for IXP4xx chipset.
+ *
+ * Copyright (C) 2002 Intel Corporation.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _ASM_ARM_IXP4XX_H_
+#define _ASM_ARM_IXP4XX_H_
+
+#ifdef __ASSEMBLER__
+#define IXP4XX_REG(reg) (reg)
+#else
+#define IXP4XX_REG(reg) (*(volatile u32 *)(reg))
+#define IXP4XX_BASE(reg) ((u32*)(reg))
+#endif
+
+/* Expansion Bus region */
+
+/* Queue Manager */
+#define IXP4XX_QMGR_BASE (0x60000000)
+#define IXP4XX_QMGR_REGION_SIZE (0x00004000)
+
+
+/* PCI Config registers */
+#define IXP4XX_PCI_CFG_BASE (0xC0000000)
+#define IXP4XX_PCI_CFG_REGION_SIZE (0x00001000)
+
+/* Peripheral space */
+#define IXP4XX_PERIPHERAL_BASE (0xC8000000)
+#define IXP4XX_PERIPHERAL_REGION_SIZE (0x00013000)
+
+/*
+ * Debug UART
+ *
+ * This is basically a remap of UART1 into a region that is section
+ * aligned so that it can be used with the low-level debug code.
+ */
+#define IXP4XX_DEBUG_UART_BASE (0xC8000000)
+#define IXP4XX_DEBUG_UART_REGION_SIZE (0x00001000)
+
+/* Expansion Bus Controller registers. */
+#define IXP4XX_EXP_CS0 IXP4XX_REG(0xC4000000)
+#define IXP4XX_EXP_CS1 IXP4XX_REG(0xC4000004)
+#define IXP4XX_EXP_CS2 IXP4XX_REG(0xC4000008)
+#define IXP4XX_EXP_CS3 IXP4XX_REG(0xC400000C)
+#define IXP4XX_EXP_CS4 IXP4XX_REG(0xC4000010)
+#define IXP4XX_EXP_CS5 IXP4XX_REG(0xC4000014)
+#define IXP4XX_EXP_CS6 IXP4XX_REG(0xC4000018)
+#define IXP4XX_EXP_CS7 IXP4XX_REG(0xC400001C)
+
+#define IXP4XX_EXP_BASE(n) (0x50000000 + (n) * 1000000)
+
+#define IXP4XX_EXP_EN 0x80000000
+#define IXP4XX_EXP_T1(n) (0x10000000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T2(n) (0x04000000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T3(n) (0x00400000 * (n)) /* valid: 0 - 15 */
+#define IXP4XX_EXP_T4(n) (0x00100000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T5(n) (0x00010000 * (n)) /* valid: 0 - 15 */
+#define IXP4XX_EXP_INTEL 0x00000000
+#define IXP4XX_EXP_MOTO 0x00004000
+#define IXP4XX_EXP_HPI 0x00008000
+#define IXP4XX_EXP_BITS(n) (0x00000400 * ((n) - 9)) /* valid: 9 - 24 */
+#define IXP4XX_EXP_BYTE_RD16 0x00000040
+#define IXP4XX_EXP_HRDY_POL 0x00000020
+#define IXP4XX_EXP_MUX_EN 0x00000010
+#define IXP4XX_EXP_SPLT_EN 0x00000008
+#define IXP4XX_EXP_WR_EN 0x00000002
+#define IXP4XX_EXP_BYTE_EN 0x00000001
+
+#define IXP4XX_EXP_CFG0 IXP4XX_REG(0xC4000020)
+#define IXP4XX_EXP_CFG1 IXP4XX_REG(0xC4000024)
+#define IXP4XX_EXP_CFG2 IXP4XX_REG(0xC4000028)
+#define IXP4XX_EXP_CFG3 IXP4XX_REG(0xC400002C)
+
+
+/* Peripheral Space Register Region Base Addresses */
+#define IXP4XX_UART1_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x0000)
+#define IXP4XX_UART2_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x1000)
+#define IXP4XX_PMU_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x2000)
+#define IXP4XX_INTC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x3000)
+#define IXP4XX_GPIO_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x4000)
+#define IXP4XX_NPEA_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x6000)
+#define IXP4XX_NPEB_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x7000)
+#define IXP4XX_NPEC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x8000)
+#define IXP4XX_EthB_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x9000)
+#define IXP4XX_EthC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xA000)
+#define IXP4XX_USB_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xB000)
+/* IXP46x only */
+#define IXP4XX_EthA_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xC000)
+#define IXP4XX_EthB1_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xD000)
+#define IXP4XX_EthB2_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xE000)
+#define IXP4XX_EthB3_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xF000)
+#define IXP4XX_TIMESYNC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x10000)
+#define IXP4XX_I2C_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x11000)
+#define IXP4XX_SSP_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x12000)
+
+/*
+ Constants to make it easy to access Interrupt Controller registers
+ */
+#define IXP4XX_ICPR_OFFSET 0x00 /* Interrupt Status */
+#define IXP4XX_ICMR_OFFSET 0x04 /* Interrupt Enable */
+#define IXP4XX_ICLR_OFFSET 0x08 /* Interrupt IRQ/FIQ Select */
+#define IXP4XX_ICIP_OFFSET 0x0C /* IRQ Status */
+#define IXP4XX_ICFP_OFFSET 0x10 /* FIQ Status */
+#define IXP4XX_ICHR_OFFSET 0x14 /* Interrupt Priority */
+#define IXP4XX_ICIH_OFFSET 0x18 /* IRQ Highest Pri Int */
+#define IXP4XX_ICFH_OFFSET 0x1C /* FIQ Highest Pri Int */
+
+/* IXP465-only */
+#define IXP4XX_ICPR2_OFFSET 0x20 /* Interrupt Status 2 */
+#define IXP4XX_ICMR2_OFFSET 0x24 /* Interrupt Enable 2 */
+#define IXP4XX_ICLR2_OFFSET 0x28 /* Interrupt IRQ/FIQ Select 2 */
+#define IXP4XX_ICIP2_OFFSET 0x2C /* IRQ Status */
+#define IXP4XX_ICFP2_OFFSET 0x30 /* FIQ Status */
+#define IXP4XX_ICEEN_OFFSET 0x34 /* Error High Pri Enable */
+
+
+/* Interrupt Controller Register Definitions. */
+#define IXP4XX_INTC_REG(x) ((volatile u32 *)(IXP4XX_INTC_BASE + (x)))
+
+#define IXP4XX_ICPR IXP4XX_INTC_REG(IXP4XX_ICPR_OFFSET)
+#define IXP4XX_ICMR IXP4XX_INTC_REG(IXP4XX_ICMR_OFFSET)
+#define IXP4XX_ICLR IXP4XX_INTC_REG(IXP4XX_ICLR_OFFSET)
+#define IXP4XX_ICIP IXP4XX_INTC_REG(IXP4XX_ICIP_OFFSET)
+#define IXP4XX_ICFP IXP4XX_INTC_REG(IXP4XX_ICFP_OFFSET)
+#define IXP4XX_ICHR IXP4XX_INTC_REG(IXP4XX_ICHR_OFFSET)
+#define IXP4XX_ICIH IXP4XX_INTC_REG(IXP4XX_ICIH_OFFSET)
+#define IXP4XX_ICFH IXP4XX_INTC_REG(IXP4XX_ICFH_OFFSET)
+#define IXP4XX_ICPR2 IXP4XX_INTC_REG(IXP4XX_ICPR2_OFFSET)
+#define IXP4XX_ICMR2 IXP4XX_INTC_REG(IXP4XX_ICMR2_OFFSET)
+#define IXP4XX_ICLR2 IXP4XX_INTC_REG(IXP4XX_ICLR2_OFFSET)
+#define IXP4XX_ICIP2 IXP4XX_INTC_REG(IXP4XX_ICIP2_OFFSET)
+#define IXP4XX_ICFP2 IXP4XX_INTC_REG(IXP4XX_ICFP2_OFFSET)
+#define IXP4XX_ICEEN IXP4XX_INTC_REG(IXP4XX_ICEEN_OFFSET)
+
+/* Constants to make it easy to access GPIO registers */
+#define IXP4XX_GPIO_GPOUTR_OFFSET 0x00
+#define IXP4XX_GPIO_GPOER_OFFSET 0x04
+#define IXP4XX_GPIO_GPINR_OFFSET 0x08
+#define IXP4XX_GPIO_GPISR_OFFSET 0x0C
+#define IXP4XX_GPIO_GPIT1R_OFFSET 0x10
+#define IXP4XX_GPIO_GPIT2R_OFFSET 0x14
+#define IXP4XX_GPIO_GPCLKR_OFFSET 0x18
+#define IXP4XX_GPIO_GPDBSELR_OFFSET 0x1C
+
+/* GPIO Register Definitions - perform only 32-bit reads/writes */
+#define IXP4XX_GPIO_REG(x) ((volatile u32 *)(IXP4XX_GPIO_BASE + (x)))
+
+#define IXP4XX_GPIO_GPOUTR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOUTR_OFFSET)
+#define IXP4XX_GPIO_GPOER IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOER_OFFSET)
+#define IXP4XX_GPIO_GPINR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPINR_OFFSET)
+#define IXP4XX_GPIO_GPISR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPISR_OFFSET)
+#define IXP4XX_GPIO_GPIT1R IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT1R_OFFSET)
+#define IXP4XX_GPIO_GPIT2R IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT2R_OFFSET)
+#define IXP4XX_GPIO_GPCLKR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPCLKR_OFFSET)
+#define IXP4XX_GPIO_GPDBSELR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPDBSELR_OFFSET)
+
+/* GPIO register bit definitions */
+
+/* Interrupt styles */
+#define IXP4XX_GPIO_STYLE_ACTIVE_HIGH 0x0
+#define IXP4XX_GPIO_STYLE_ACTIVE_LOW 0x1
+#define IXP4XX_GPIO_STYLE_RISING_EDGE 0x2
+#define IXP4XX_GPIO_STYLE_FALLING_EDGE 0x3
+#define IXP4XX_GPIO_STYLE_TRANSITIONAL 0x4
+
+/* Mask used to clear interrupt styles */
+#define IXP4XX_GPIO_STYLE_CLEAR 0x7
+#define IXP4XX_GPIO_STYLE_SIZE 3
+
+/* Operating System Timer Register Definitions. */
+#define IXP4XX_OSTS IXP4XX_REG(0xC8005000) /* Continious TimeStamp */
+#define IXP4XX_OST1 IXP4XX_REG(0xC8005004) /* Timer 1 Timestamp */
+#define IXP4XX_OSRT1 IXP4XX_REG(0xC8005008) /* Timer 1 Reload */
+#define IXP4XX_OST2 IXP4XX_REG(0xC800500C) /* Timer 2 Timestamp */
+#define IXP4XX_OSRT2 IXP4XX_REG(0xC8005010) /* Timer 2 Reload */
+#define IXP4XX_OSWT IXP4XX_REG(0xC8005014) /* Watchdog Timer */
+#define IXP4XX_OSWE IXP4XX_REG(0xC8005018) /* Watchdog Enable */
+#define IXP4XX_OSWK IXP4XX_REG(0xC800501C) /* Watchdog Key */
+#define IXP4XX_OSST IXP4XX_REG(0xC8005020) /* Timer Status */
+
+/* Timer register values and bit definitions */
+#define IXP4XX_OST_ENABLE 0x00000001
+#define IXP4XX_OST_ONE_SHOT 0x00000002
+/* Low order bits of reload value ignored */
+#define IXP4XX_OST_RELOAD_MASK 0x00000003
+#define IXP4XX_OST_DISABLED 0x00000000
+#define IXP4XX_OSST_TIMER_1_PEND 0x00000001
+#define IXP4XX_OSST_TIMER_2_PEND 0x00000002
+#define IXP4XX_OSST_TIMER_TS_PEND 0x00000004
+#define IXP4XX_OSST_TIMER_WDOG_PEND 0x00000008
+#define IXP4XX_OSST_TIMER_WARM_RESET 0x00000010
+
+#define IXP4XX_WDT_KEY 0x0000482E
+
+#define IXP4XX_WDT_RESET_ENABLE 0x00000001
+#define IXP4XX_WDT_IRQ_ENABLE 0x00000002
+#define IXP4XX_WDT_COUNT_ENABLE 0x00000004
+
+
+/* Constants to make it easy to access PCI Control/Status registers */
+#define PCI_NP_AD_OFFSET 0x00
+#define PCI_NP_CBE_OFFSET 0x04
+#define PCI_NP_WDATA_OFFSET 0x08
+#define PCI_NP_RDATA_OFFSET 0x0c
+#define PCI_CRP_AD_CBE_OFFSET 0x10
+#define PCI_CRP_WDATA_OFFSET 0x14
+#define PCI_CRP_RDATA_OFFSET 0x18
+#define PCI_CSR_OFFSET 0x1c
+#define PCI_ISR_OFFSET 0x20
+#define PCI_INTEN_OFFSET 0x24
+#define PCI_DMACTRL_OFFSET 0x28
+#define PCI_AHBMEMBASE_OFFSET 0x2c
+#define PCI_AHBIOBASE_OFFSET 0x30
+#define PCI_PCIMEMBASE_OFFSET 0x34
+#define PCI_AHBDOORBELL_OFFSET 0x38
+#define PCI_PCIDOORBELL_OFFSET 0x3C
+#define PCI_ATPDMA0_AHBADDR_OFFSET 0x40
+#define PCI_ATPDMA0_PCIADDR_OFFSET 0x44
+#define PCI_ATPDMA0_LENADDR_OFFSET 0x48
+#define PCI_ATPDMA1_AHBADDR_OFFSET 0x4C
+#define PCI_ATPDMA1_PCIADDR_OFFSET 0x50
+#define PCI_ATPDMA1_LENADDR_OFFSET 0x54
+
+/* PCI Control/Status Registers */
+#define IXP4XX_PCI_CSR(x) ((volatile u32 *)(IXP4XX_PCI_CFG_BASE + (x)))
+
+#define PCI_NP_AD IXP4XX_PCI_CSR(PCI_NP_AD_OFFSET)
+#define PCI_NP_CBE IXP4XX_PCI_CSR(PCI_NP_CBE_OFFSET)
+#define PCI_NP_WDATA IXP4XX_PCI_CSR(PCI_NP_WDATA_OFFSET)
+#define PCI_NP_RDATA IXP4XX_PCI_CSR(PCI_NP_RDATA_OFFSET)
+#define PCI_CRP_AD_CBE IXP4XX_PCI_CSR(PCI_CRP_AD_CBE_OFFSET)
+#define PCI_CRP_WDATA IXP4XX_PCI_CSR(PCI_CRP_WDATA_OFFSET)
+#define PCI_CRP_RDATA IXP4XX_PCI_CSR(PCI_CRP_RDATA_OFFSET)
+#define PCI_CSR IXP4XX_PCI_CSR(PCI_CSR_OFFSET)
+#define PCI_ISR IXP4XX_PCI_CSR(PCI_ISR_OFFSET)
+#define PCI_INTEN IXP4XX_PCI_CSR(PCI_INTEN_OFFSET)
+#define PCI_DMACTRL IXP4XX_PCI_CSR(PCI_DMACTRL_OFFSET)
+#define PCI_AHBMEMBASE IXP4XX_PCI_CSR(PCI_AHBMEMBASE_OFFSET)
+#define PCI_AHBIOBASE IXP4XX_PCI_CSR(PCI_AHBIOBASE_OFFSET)
+#define PCI_PCIMEMBASE IXP4XX_PCI_CSR(PCI_PCIMEMBASE_OFFSET)
+#define PCI_AHBDOORBELL IXP4XX_PCI_CSR(PCI_AHBDOORBELL_OFFSET)
+#define PCI_PCIDOORBELL IXP4XX_PCI_CSR(PCI_PCIDOORBELL_OFFSET)
+#define PCI_ATPDMA0_AHBADDR IXP4XX_PCI_CSR(PCI_ATPDMA0_AHBADDR_OFFSET)
+#define PCI_ATPDMA0_PCIADDR IXP4XX_PCI_CSR(PCI_ATPDMA0_PCIADDR_OFFSET)
+#define PCI_ATPDMA0_LENADDR IXP4XX_PCI_CSR(PCI_ATPDMA0_LENADDR_OFFSET)
+#define PCI_ATPDMA1_AHBADDR IXP4XX_PCI_CSR(PCI_ATPDMA1_AHBADDR_OFFSET)
+#define PCI_ATPDMA1_PCIADDR IXP4XX_PCI_CSR(PCI_ATPDMA1_PCIADDR_OFFSET)
+#define PCI_ATPDMA1_LENADDR IXP4XX_PCI_CSR(PCI_ATPDMA1_LENADDR_OFFSET)
+
+/* PCI register values and bit definitions */
+
+/* CSR bit definitions */
+#define PCI_CSR_HOST 0x00000001
+#define PCI_CSR_ARBEN 0x00000002
+#define PCI_CSR_ADS 0x00000004
+#define PCI_CSR_PDS 0x00000008
+#define PCI_CSR_ABE 0x00000010
+#define PCI_CSR_DBT 0x00000020
+#define PCI_CSR_ASE 0x00000100
+#define PCI_CSR_IC 0x00008000
+
+/* ISR (Interrupt status) Register bit definitions */
+#define PCI_ISR_PSE 0x00000001
+#define PCI_ISR_PFE 0x00000002
+#define PCI_ISR_PPE 0x00000004
+#define PCI_ISR_AHBE 0x00000008
+#define PCI_ISR_APDC 0x00000010
+#define PCI_ISR_PADC 0x00000020
+#define PCI_ISR_ADB 0x00000040
+#define PCI_ISR_PDB 0x00000080
+
+/* INTEN (Interrupt Enable) Register bit definitions */
+#define PCI_INTEN_PSE 0x00000001
+#define PCI_INTEN_PFE 0x00000002
+#define PCI_INTEN_PPE 0x00000004
+#define PCI_INTEN_AHBE 0x00000008
+#define PCI_INTEN_APDC 0x00000010
+#define PCI_INTEN_PADC 0x00000020
+#define PCI_INTEN_ADB 0x00000040
+#define PCI_INTEN_PDB 0x00000080
+
+/* Shift value for byte enable on NP cmd/byte enable register */
+#define IXP4XX_PCI_NP_CBE_BESL 4
+
+/* PCI commands supported by NP access unit */
+#define NP_CMD_IOREAD 0x2
+#define NP_CMD_IOWRITE 0x3
+#define NP_CMD_CONFIGREAD 0xA
+#define NP_CMD_CONFIGWRITE 0xB
+#define NP_CMD_MEMREAD 0x6
+#define NP_CMD_MEMWRITE 0x7
+
+/* Constants for CRP access into local config space */
+#define CRP_AD_CBE_BESL 20
+#define CRP_AD_CBE_WRITE 0x00010000
+
+/* USB Device Controller */
+# define IXP4XX_USB_REG(x) (*((volatile u32 *)(x)))
+
+/* SDRAM Controller registers. */
+#define IXP4XX_SDRAM_CONFIG IXP4XX_REG(0xCC000000)
+#define IXP4XX_SDRAM_REFRESH IXP4XX_REG(0xCC000004)
+#define IXP4XX_SDRAM_IR IXP4XX_REG(0xCC000008)
+
+/* "fuse" bits of IXP_EXP_CFG2 */
+/* All IXP4xx CPUs */
+#define IXP4XX_FEATURE_RCOMP (1 << 0)
+#define IXP4XX_FEATURE_USB_DEVICE (1 << 1)
+#define IXP4XX_FEATURE_HASH (1 << 2)
+#define IXP4XX_FEATURE_AES (1 << 3)
+#define IXP4XX_FEATURE_DES (1 << 4)
+#define IXP4XX_FEATURE_HDLC (1 << 5)
+#define IXP4XX_FEATURE_AAL (1 << 6)
+#define IXP4XX_FEATURE_HSS (1 << 7)
+#define IXP4XX_FEATURE_UTOPIA (1 << 8)
+#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9)
+#define IXP4XX_FEATURE_NPEC_ETH (1 << 10)
+#define IXP4XX_FEATURE_RESET_NPEA (1 << 11)
+#define IXP4XX_FEATURE_RESET_NPEB (1 << 12)
+#define IXP4XX_FEATURE_RESET_NPEC (1 << 13)
+#define IXP4XX_FEATURE_PCI (1 << 14)
+#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16)
+#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22)
+#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP | \
+ IXP4XX_FEATURE_USB_DEVICE | \
+ IXP4XX_FEATURE_HASH | \
+ IXP4XX_FEATURE_AES | \
+ IXP4XX_FEATURE_DES | \
+ IXP4XX_FEATURE_HDLC | \
+ IXP4XX_FEATURE_AAL | \
+ IXP4XX_FEATURE_HSS | \
+ IXP4XX_FEATURE_UTOPIA | \
+ IXP4XX_FEATURE_NPEB_ETH0 | \
+ IXP4XX_FEATURE_NPEC_ETH | \
+ IXP4XX_FEATURE_RESET_NPEA | \
+ IXP4XX_FEATURE_RESET_NPEB | \
+ IXP4XX_FEATURE_RESET_NPEC | \
+ IXP4XX_FEATURE_PCI | \
+ IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \
+ IXP4XX_FEATURE_XSCALE_MAX_FREQ)
+
+/* IXP43x/46x CPUs */
+#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15)
+#define IXP4XX_FEATURE_USB_HOST (1 << 18)
+#define IXP4XX_FEATURE_NPEA_ETH (1 << 19)
+#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK | \
+ IXP4XX_FEATURE_ECC_TIMESYNC | \
+ IXP4XX_FEATURE_USB_HOST | \
+ IXP4XX_FEATURE_NPEA_ETH)
+
+/* IXP46x CPU (including IXP455) only */
+#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20)
+#define IXP4XX_FEATURE_RSA (1 << 21)
+#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK | \
+ IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \
+ IXP4XX_FEATURE_RSA)
+
+#endif
diff --git a/arch/arm/mach-ixp4xx/include/mach/npe.h b/arch/arm/mach-ixp4xx/include/mach/npe.h
new file mode 100644
index 0000000..18bd01b
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/npe.h
@@ -0,0 +1,30 @@
+#ifndef __IXP4XX_NPE_H
+#define __IXP4XX_NPE_H
+
+#include <common.h>
+
+#define NPE_NAME_LENGTH 5
+
+struct npe_regs {
+ u32 exec_addr, exec_data, exec_status_cmd, exec_count;
+ u32 action_points[4];
+ u32 watchpoint_fifo, watch_count;
+ u32 profile_count;
+ u32 messaging_status, messaging_control;
+ u32 mailbox_status, /*messaging_*/ in_out_fifo;
+};
+
+struct npe {
+ struct npe_regs *regs;
+ int id, valid;
+ const char name[NPE_NAME_LENGTH + 1];
+};
+
+int npe_running(struct npe *npe);
+int npe_send_message(struct npe *npe, const void *msg, const char *what);
+int npe_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_load_firmware(struct npe *npe);
+struct npe *npe_request(int id);
+
+#endif /* __IXP4XX_NPE_H */
diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h
new file mode 100644
index 0000000..1df4aa4
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
@@ -0,0 +1,15 @@
+#include <asm/types.h>
+
+#define IXP4XX_ETH_NPEA 0x00
+#define IXP4XX_ETH_NPEB 0x10
+#define IXP4XX_ETH_NPEC 0x20
+
+/* Information about built-in Ethernet MAC interfaces */
+struct eth_plat_info {
+ void *regs;
+ u8 npe;
+ u8 phy; /* MII PHY ID, 0 - 31 */
+ u8 rxq; /* configurable, currently 0 - 31 only */
+ u8 txreadyq;
+ u8 hwaddr[6];
+};
diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
new file mode 100644
index 0000000..4e9b8d4
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef IXP4XX_QMGR_H
+#define IXP4XX_QMGR_H
+
+#include <common.h>
+#include <mach/ixp4xx-regs.h>
+#include <asm/io.h>
+
+#define DEBUG_QMGR 0
+
+#define HALF_QUEUES 32
+#define QUEUES 64
+#define MAX_QUEUE_LENGTH 4 /* in dwords */
+
+#define QUEUE_STAT1_EMPTY 1 /* queue status bits */
+#define QUEUE_STAT1_NEARLY_EMPTY 2
+#define QUEUE_STAT1_NEARLY_FULL 4
+#define QUEUE_STAT1_FULL 8
+#define QUEUE_STAT2_UNDERFLOW 1
+#define QUEUE_STAT2_OVERFLOW 2
+
+#define QUEUE_WATERMARK_0_ENTRIES 0
+#define QUEUE_WATERMARK_1_ENTRY 1
+#define QUEUE_WATERMARK_2_ENTRIES 2
+#define QUEUE_WATERMARK_4_ENTRIES 3
+#define QUEUE_WATERMARK_8_ENTRIES 4
+#define QUEUE_WATERMARK_16_ENTRIES 5
+#define QUEUE_WATERMARK_32_ENTRIES 6
+#define QUEUE_WATERMARK_64_ENTRIES 7
+
+/* queue interrupt request conditions */
+#define QUEUE_IRQ_SRC_EMPTY 0
+#define QUEUE_IRQ_SRC_NEARLY_EMPTY 1
+#define QUEUE_IRQ_SRC_NEARLY_FULL 2
+#define QUEUE_IRQ_SRC_FULL 3
+#define QUEUE_IRQ_SRC_NOT_EMPTY 4
+#define QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY 5
+#define QUEUE_IRQ_SRC_NOT_NEARLY_FULL 6
+#define QUEUE_IRQ_SRC_NOT_FULL 7
+
+struct qmgr_regs {
+ u32 acc[QUEUES][MAX_QUEUE_LENGTH]; /* 0x000 - 0x3FF */
+ u32 stat1[4]; /* 0x400 - 0x40F */
+ u32 stat2[2]; /* 0x410 - 0x417 */
+ u32 statne_h; /* 0x418 - queue nearly empty */
+ u32 statf_h; /* 0x41C - queue full */
+ u32 irqsrc[4]; /* 0x420 - 0x42F IRC source */
+ u32 irqen[2]; /* 0x430 - 0x437 IRQ enabled */
+ u32 irqstat[2]; /* 0x438 - 0x43F - IRQ access only */
+ u32 reserved[1776];
+ u32 sram[2048]; /* 0x2000 - 0x3FFF - config and buffer */
+};
+
+static const struct qmgr_regs *qmgr_regs = (struct qmgr_regs *)IXP4XX_QMGR_BASE;
+
+void qmgr_set_irq(unsigned int queue, int src,
+ void (*handler)(void *pdev), void *pdev);
+void qmgr_enable_irq(unsigned int queue);
+void qmgr_disable_irq(unsigned int queue);
+
+/* request_ and release_queue() must be called from non-IRQ context */
+
+#if DEBUG_QMGR
+extern char qmgr_queue_descs[HALF_QUEUES][32];
+
+void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+ unsigned int nearly_empty_watermark,
+ unsigned int nearly_full_watermark,
+ const char *desc_format, const char* name);
+#else
+void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+ unsigned int nearly_empty_watermark,
+ unsigned int nearly_full_watermark);
+#define qmgr_request_queue(queue, len, nearly_empty_watermark, \
+ nearly_full_watermark, desc_format, name) \
+ __qmgr_request_queue(queue, len, nearly_empty_watermark, \
+ nearly_full_watermark)
+#endif
+
+void qmgr_release_queue(unsigned int queue);
+
+
+static inline void qmgr_put_entry(unsigned int queue, u32 val)
+{
+#if DEBUG_QMGR
+ BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+ fprintf(stderr, "Queue %s(%i) put %X\n",
+ qmgr_queue_descs[queue], queue, val);
+#endif
+ __raw_writel(val, &qmgr_regs->acc[queue][0]);
+}
+
+static inline u32 qmgr_get_entry(unsigned int queue)
+{
+ u32 val;
+ val = __raw_readl(&qmgr_regs->acc[queue][0]);
+#if DEBUG_QMGR
+ BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+ fprintf(stderr, "Queue %s(%i) get %X\n",
+ qmgr_queue_descs[queue], queue, val);
+#endif
+ return val;
+}
+
+static inline int __qmgr_get_stat1(unsigned int queue)
+{
+ return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
+ >> ((queue & 7) << 2)) & 0xF;
+}
+
+/**
+ * qmgr_stat_empty() - checks if a hardware queue is empty
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is empty.
+ */
+static inline int qmgr_stat_empty(unsigned int queue)
+{
+ return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY;
+}
+
+/**
+ * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is below low watermark.
+ */
+static inline int qmgr_stat_below_low_watermark(unsigned int queue)
+{
+ return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY;
+}
+
+/**
+ * qmgr_stat_above_high_watermark() - checks if a queue is above high watermark
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is above high watermark
+ */
+static inline int qmgr_stat_above_high_watermark(unsigned int queue)
+{
+ return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL;
+}
+
+/**
+ * qmgr_stat_full() - checks if a hardware queue is full
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is full.
+ */
+static inline int qmgr_stat_full(unsigned int queue)
+{
+ return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL;
+}
+
+#endif
diff --git a/arch/arm/mach-ixp4xx/lowlevel_init.S b/arch/arm/mach-ixp4xx/lowlevel_init.S
new file mode 100644
index 0000000..a4e93ef
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/lowlevel_init.S
@@ -0,0 +1,17 @@
+#include <mach/ixp4xx-regs.h>
+
+ .section ".text_bare_init", "ax"
+
+ .globl arch_init_lowlevel
+arch_init_lowlevel:
+ ldr r0, cfg
+ ldr r1, [r0]
+ and r1, r1, #~0x80000000 /* unmap EXP bus from 0x0 */
+ str r1, [r0]
+
+ /* return to ROM */
+ orr lr, #0x50000000
+ mov pc, lr
+
+cfg:
+ .word IXP4XX_EXP_CFG0
diff --git a/arch/arm/mach-ixp4xx/npe.c b/arch/arm/mach-ixp4xx/npe.c
new file mode 100644
index 0000000..a8ddd5a
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/npe.c
@@ -0,0 +1,668 @@
+/*
+ * Intel IXP4xx Network Processor Engine driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <fs.h>
+#include <init.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <mach/ixp4xx-regs.h>
+#include <mach/cpu.h>
+#include <mach/npe.h>
+
+#define DEBUG_MSG 0
+#define DEBUG_FW 0
+
+#define NPE_COUNT 3
+#define MAX_RETRIES 1000 /* microseconds */
+#define NPE_42X_DATA_SIZE 0x800 /* in dwords */
+#define NPE_46X_DATA_SIZE 0x1000
+#define NPE_A_42X_INSTR_SIZE 0x1000
+#define NPE_B_AND_C_42X_INSTR_SIZE 0x800
+#define NPE_46X_INSTR_SIZE 0x1000
+#define REGS_SIZE 0x1000
+
+#define NPE_PHYS_REG 32
+
+#define FW_MAGIC 0xFEEDF00D
+#define FW_BLOCK_TYPE_INSTR 0x0
+#define FW_BLOCK_TYPE_DATA 0x1
+#define FW_BLOCK_TYPE_EOF 0xF
+
+/* NPE exec status (read) and command (write) */
+#define CMD_NPE_STEP 0x01
+#define CMD_NPE_START 0x02
+#define CMD_NPE_STOP 0x03
+#define CMD_NPE_CLR_PIPE 0x04
+#define CMD_CLR_PROFILE_CNT 0x0C
+#define CMD_RD_INS_MEM 0x10 /* instruction memory */
+#define CMD_WR_INS_MEM 0x11
+#define CMD_RD_DATA_MEM 0x12 /* data memory */
+#define CMD_WR_DATA_MEM 0x13
+#define CMD_RD_ECS_REG 0x14 /* exec access register */
+#define CMD_WR_ECS_REG 0x15
+
+#define STAT_RUN 0x80000000
+#define STAT_STOP 0x40000000
+#define STAT_CLEAR 0x20000000
+#define STAT_ECS_K 0x00800000 /* pipeline clean */
+
+#define NPE_STEVT 0x1B
+#define NPE_STARTPC 0x1C
+#define NPE_REGMAP 0x1E
+#define NPE_CINDEX 0x1F
+
+#define INSTR_WR_REG_SHORT 0x0000C000
+#define INSTR_WR_REG_BYTE 0x00004000
+#define INSTR_RD_FIFO 0x0F888220
+#define INSTR_RESET_MBOX 0x0FAC8210
+
+#define ECS_BG_CTXT_REG_0 0x00 /* Background Executing Context */
+#define ECS_BG_CTXT_REG_1 0x01 /* Stack level */
+#define ECS_BG_CTXT_REG_2 0x02
+#define ECS_PRI_1_CTXT_REG_0 0x04 /* Priority 1 Executing Context */
+#define ECS_PRI_1_CTXT_REG_1 0x05 /* Stack level */
+#define ECS_PRI_1_CTXT_REG_2 0x06
+#define ECS_PRI_2_CTXT_REG_0 0x08 /* Priority 2 Executing Context */
+#define ECS_PRI_2_CTXT_REG_1 0x09 /* Stack level */
+#define ECS_PRI_2_CTXT_REG_2 0x0A
+#define ECS_DBG_CTXT_REG_0 0x0C /* Debug Executing Context */
+#define ECS_DBG_CTXT_REG_1 0x0D /* Stack level */
+#define ECS_DBG_CTXT_REG_2 0x0E
+#define ECS_INSTRUCT_REG 0x11 /* NPE Instruction Register */
+
+#define ECS_REG_0_ACTIVE 0x80000000 /* all levels */
+#define ECS_REG_0_NEXTPC_MASK 0x1FFF0000 /* BG/PRI1/PRI2 levels */
+#define ECS_REG_0_LDUR_BITS 8
+#define ECS_REG_0_LDUR_MASK 0x00000700 /* all levels */
+#define ECS_REG_1_CCTXT_BITS 16
+#define ECS_REG_1_CCTXT_MASK 0x000F0000 /* all levels */
+#define ECS_REG_1_SELCTXT_BITS 0
+#define ECS_REG_1_SELCTXT_MASK 0x0000000F /* all levels */
+#define ECS_DBG_REG_2_IF 0x00100000 /* debug level */
+#define ECS_DBG_REG_2_IE 0x00080000 /* debug level */
+
+/* NPE watchpoint_fifo register bit */
+#define WFIFO_VALID 0x80000000
+
+/* NPE messaging_status register bit definitions */
+#define MSGSTAT_OFNE 0x00010000 /* OutFifoNotEmpty */
+#define MSGSTAT_IFNF 0x00020000 /* InFifoNotFull */
+#define MSGSTAT_OFNF 0x00040000 /* OutFifoNotFull */
+#define MSGSTAT_IFNE 0x00080000 /* InFifoNotEmpty */
+#define MSGSTAT_MBINT 0x00100000 /* Mailbox interrupt */
+#define MSGSTAT_IFINT 0x00200000 /* InFifo interrupt */
+#define MSGSTAT_OFINT 0x00400000 /* OutFifo interrupt */
+#define MSGSTAT_WFINT 0x00800000 /* WatchFifo interrupt */
+
+/* NPE messaging_control register bit definitions */
+#define MSGCTL_OUT_FIFO 0x00010000 /* enable output FIFO */
+#define MSGCTL_IN_FIFO 0x00020000 /* enable input FIFO */
+#define MSGCTL_OUT_FIFO_WRITE 0x01000000 /* enable FIFO + WRITE */
+#define MSGCTL_IN_FIFO_WRITE 0x02000000
+
+/* NPE mailbox_status value for reset */
+#define RESET_MBOX_STAT 0x0000F0F0
+
+#define print_npe(npe, fmt, ...) fprintf(stderr, "%s: " fmt, npe->name, ## __VA_ARGS__)
+
+#if DEBUG_MSG
+#define debug_msg(npe, fmt, ...) print_npe(npe, fmt, ## __VA_ARGS__)
+#else
+#define debug_msg(npe, fmt, ...)
+#endif
+
+static struct {
+ u32 reg, val;
+} ecs_reset[] = {
+ {ECS_BG_CTXT_REG_0, 0xA0000000},
+ {ECS_BG_CTXT_REG_1, 0x01000000},
+ {ECS_BG_CTXT_REG_2, 0x00008000},
+ {ECS_PRI_1_CTXT_REG_0, 0x20000080},
+ {ECS_PRI_1_CTXT_REG_1, 0x01000000},
+ {ECS_PRI_1_CTXT_REG_2, 0x00008000},
+ {ECS_PRI_2_CTXT_REG_0, 0x20000080},
+ {ECS_PRI_2_CTXT_REG_1, 0x01000000},
+ {ECS_PRI_2_CTXT_REG_2, 0x00008000},
+ {ECS_DBG_CTXT_REG_0, 0x20000000},
+ {ECS_DBG_CTXT_REG_1, 0x00000000},
+ {ECS_DBG_CTXT_REG_2, 0x001E0000},
+ {ECS_INSTRUCT_REG, 0x1003C00F},
+};
+
+static struct npe npe_tab[NPE_COUNT] = {
+ {
+ .regs = (struct npe_regs *)IXP4XX_NPEA_BASE,
+ .id = 0,
+ .name = "NPE-A",
+ }, {
+ .regs = (struct npe_regs *)IXP4XX_NPEB_BASE,
+ .id = 1,
+ .name = "NPE-B",
+ }, {
+ .regs = (struct npe_regs *)IXP4XX_NPEC_BASE,
+ .id = 2,
+ .name = "NPE-C",
+ }
+};
+
+int npe_running(struct npe *npe)
+{
+ return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;
+}
+
+static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)
+{
+ __raw_writel(data, &npe->regs->exec_data);
+ __raw_writel(addr, &npe->regs->exec_addr);
+ __raw_writel(cmd, &npe->regs->exec_status_cmd);
+}
+
+static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
+{
+ __raw_writel(addr, &npe->regs->exec_addr);
+ __raw_writel(cmd, &npe->regs->exec_status_cmd);
+ /* Iintroduce extra read cycles after issuing read command to NPE
+ so that we read the register after the NPE has updated it.
+ This is to overcome race condition between XScale and NPE */
+ __raw_readl(&npe->regs->exec_data);
+ __raw_readl(&npe->regs->exec_data);
+ return __raw_readl(&npe->regs->exec_data);
+}
+
+static void npe_clear_active(struct npe *npe, u32 reg)
+{
+ u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
+ npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
+}
+
+static void npe_start(struct npe *npe)
+{
+ /* ensure only Background Context Stack Level is active */
+ npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
+ npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
+ npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
+
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+ __raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);
+}
+
+static void npe_stop(struct npe *npe)
+{
+ __raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/
+}
+
+static int npe_debug_instr(struct npe *npe, u32 instr, u32 ctx, u32 ldur)
+{
+ u32 wc;
+ int i;
+
+ /* set the Active bit, and the LDUR, in the debug level */
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
+ ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
+
+ /* set CCTXT at ECS DEBUG L3 to specify in which context to execute
+ the instruction, and set SELCTXT at ECS DEBUG Level to specify
+ which context store to access.
+ Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
+ */
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
+ (ctx << ECS_REG_1_CCTXT_BITS) |
+ (ctx << ECS_REG_1_SELCTXT_BITS));
+
+ /* clear the pipeline */
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+
+ /* load NPE instruction into the instruction register */
+ npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
+
+ /* we need this value later to wait for completion of NPE execution
+ step */
+ wc = __raw_readl(&npe->regs->watch_count);
+
+ /* issue a Step One command via the Execution Control register */
+ __raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
+
+ /* Watch Count register increments when NPE completes an instruction */
+ for (i = 0; i < MAX_RETRIES; i++) {
+ if (wc != __raw_readl(&npe->regs->watch_count))
+ return 0;
+ udelay(1);
+ }
+
+ print_npe(npe, "reset: npe_debug_instr(): timeout\n");
+ return -ETIMEDOUT;
+}
+
+static int npe_logical_reg_write8(struct npe *npe, u32 addr, u8 val, u32 ctx)
+{
+ /* here we build the NPE assembler instruction: mov8 d0, #0 */
+ u32 instr = INSTR_WR_REG_BYTE | /* OpCode */
+ addr << 9 | /* base Operand */
+ (val & 0x1F) << 4 | /* lower 5 bits to immediate data */
+ (val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */
+ return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int npe_logical_reg_write16(struct npe *npe, u32 addr, u16 val, u32 ctx)
+{
+ /* here we build the NPE assembler instruction: mov16 d0, #0 */
+ u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
+ addr << 9 | /* base Operand */
+ (val & 0x1F) << 4 | /* lower 5 bits to immediate data */
+ (val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */
+ return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int npe_logical_reg_write32(struct npe *npe, u32 addr, u32 val, u32 ctx)
+{
+ /* write in 16 bit steps first the high and then the low value */
+ if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))
+ return -ETIMEDOUT;
+ return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
+}
+
+static int npe_reset(struct npe *npe)
+{
+ u32 val, ctl, exec_count, ctx_reg2;
+ int i;
+
+ ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &
+ 0x3F3FFFFF;
+
+ /* disable parity interrupt */
+ __raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);
+
+ /* pre exec - debug instruction */
+ /* turn off the halt bit by clearing Execution Count register. */
+ exec_count = __raw_readl(&npe->regs->exec_count);
+ __raw_writel(0, &npe->regs->exec_count);
+ /* ensure that IF and IE are on (temporarily), so that we don't end up
+ stepping forever */
+ ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
+ ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
+
+ /* clear the FIFOs */
+ while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
+ ;
+ while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)
+ /* read from the outFIFO until empty */
+ print_npe(npe, "npe_reset: read FIFO = 0x%X\n",
+ __raw_readl(&npe->regs->in_out_fifo));
+
+ while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)
+ /* step execution of the NPE intruction to read inFIFO using
+ the Debug Executing Context stack */
+ if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))
+ return -ETIMEDOUT;
+
+ /* reset the mailbox reg from the XScale side */
+ __raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);
+ /* from NPE side */
+ if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))
+ return -ETIMEDOUT;
+
+ /* Reset the physical registers in the NPE register file */
+ for (val = 0; val < NPE_PHYS_REG; val++) {
+ if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))
+ return -ETIMEDOUT;
+ /* address is either 0 or 4 */
+ if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))
+ return -ETIMEDOUT;
+ }
+
+ /* Reset the context store = each context's Context Store registers */
+
+ /* Context 0 has no STARTPC. Instead, this value is used to set NextPC
+ for Background ECS, to set where NPE starts executing code */
+ val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
+ val &= ~ECS_REG_0_NEXTPC_MASK;
+ val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
+ npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
+
+ for (i = 0; i < 16; i++) {
+ if (i) { /* Context 0 has no STEVT nor STARTPC */
+ /* STEVT = off, 0x80 */
+ if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))
+ return -ETIMEDOUT;
+ if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))
+ return -ETIMEDOUT;
+ }
+ /* REGMAP = d0->p0, d8->p2, d16->p4 */
+ if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))
+ return -ETIMEDOUT;
+ if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))
+ return -ETIMEDOUT;
+ }
+
+ /* post exec */
+ /* clear active bit in debug level */
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);
+ /* clear the pipeline */
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+ /* restore previous values */
+ __raw_writel(exec_count, &npe->regs->exec_count);
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
+
+ /* write reset values to Execution Context Stack registers */
+ for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
+ npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
+ ecs_reset[val].val);
+
+ /* clear the profile counter */
+ __raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
+
+ __raw_writel(0, &npe->regs->exec_count);
+ __raw_writel(0, &npe->regs->action_points[0]);
+ __raw_writel(0, &npe->regs->action_points[1]);
+ __raw_writel(0, &npe->regs->action_points[2]);
+ __raw_writel(0, &npe->regs->action_points[3]);
+ __raw_writel(0, &npe->regs->watch_count);
+
+ val = ixp4xx_read_feature_bits();
+ /* reset the NPE */
+ ixp4xx_write_feature_bits(val &
+ ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
+ /* deassert reset */
+ ixp4xx_write_feature_bits(val |
+ (IXP4XX_FEATURE_RESET_NPEA << npe->id));
+ for (i = 0; i < MAX_RETRIES; i++) {
+ if (ixp4xx_read_feature_bits() &
+ (IXP4XX_FEATURE_RESET_NPEA << npe->id))
+ break; /* NPE is back alive */
+ udelay(1);
+ }
+ if (i == MAX_RETRIES)
+ return -ETIMEDOUT;
+
+ npe_stop(npe);
+
+ /* restore NPE configuration bus Control Register - parity settings */
+ __raw_writel(ctl, &npe->regs->messaging_control);
+ return 0;
+}
+
+
+int npe_send_message(struct npe *npe, const void *msg, const char *what)
+{
+ const u32 *send = msg;
+ int cycles = 0;
+
+ debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
+ what, send[0], send[1]);
+
+ if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
+ debug_msg(npe, "NPE input FIFO not empty\n");
+ return -EIO;
+ }
+
+ __raw_writel(send[0], &npe->regs->in_out_fifo);
+
+ if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {
+ debug_msg(npe, "NPE input FIFO full\n");
+ return -EIO;
+ }
+
+ __raw_writel(send[1], &npe->regs->in_out_fifo);
+
+ while ((cycles < MAX_RETRIES) &&
+ (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {
+ udelay(1);
+ cycles++;
+ }
+
+ if (cycles == MAX_RETRIES) {
+ debug_msg(npe, "Timeout sending message\n");
+ return -ETIMEDOUT;
+ }
+
+#if DEBUG_MSG > 1
+ debug_msg(npe, "Sending a message took %i cycles\n", cycles);
+#endif
+ return 0;
+}
+
+int npe_recv_message(struct npe *npe, void *msg, const char *what)
+{
+ u32 *recv = msg;
+ int cycles = 0, cnt = 0;
+
+ debug_msg(npe, "Trying to receive message %s\n", what);
+
+ while (cycles < MAX_RETRIES) {
+ if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {
+ recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);
+ if (cnt == 2)
+ break;
+ } else {
+ udelay(1);
+ cycles++;
+ }
+ }
+
+ switch(cnt) {
+ case 1:
+ debug_msg(npe, "Received [%08X]\n", recv[0]);
+ break;
+ case 2:
+ debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);
+ break;
+ }
+
+ if (cycles == MAX_RETRIES) {
+ debug_msg(npe, "Timeout waiting for message\n");
+ return -ETIMEDOUT;
+ }
+
+#if DEBUG_MSG > 1
+ debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
+#endif
+ return 0;
+}
+
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what)
+{
+ int result;
+ u32 *send = msg, recv[2];
+
+ if ((result = npe_send_message(npe, msg, what)) != 0)
+ return result;
+ if ((result = npe_recv_message(npe, recv, what)) != 0)
+ return result;
+
+ if ((recv[0] != send[0]) || (recv[1] != send[1])) {
+ debug_msg(npe, "Message %s: unexpected message received\n",
+ what);
+ return -EIO;
+ }
+ return 0;
+}
+
+
+int npe_load_firmware(struct npe *npe)
+{
+ struct dl_block {
+ u32 type;
+ u32 offset;
+ } *blk;
+
+ struct dl_image {
+ u32 magic;
+ u32 id;
+ u32 size;
+ union {
+ u32 data[0];
+ struct dl_block blocks[0];
+ };
+ } *image;
+
+ struct dl_codeblock {
+ u32 npe_addr;
+ u32 size;
+ u32 data[0];
+ } *cb;
+
+ int i, j, err, data_size, instr_size, blocks, table_end;
+ u32 cmd;
+ char name[5 /* "/dev/" */ + NPE_NAME_LENGTH + 1 /* NUL */];
+ size_t image_size;
+
+ sprintf(name, "/dev/%s", npe->name);
+ if (!(image = read_file(name, &image_size))) {
+ print_npe(npe, "bad or missing microcode file %s", name);
+ return -EIO;
+ }
+
+ err = -EINVAL;
+ if (image_size < sizeof(struct dl_image)) {
+ print_npe(npe, "incomplete microcode file %s\n", name);
+ goto err;
+ }
+
+#if DEBUG_FW
+ print_npe(npe, "microcode: %08X %08X %08X (0x%X bytes)\n",
+ image->magic, image->id, image->size, image->size * 4);
+#endif
+
+ if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
+ image->id = swab32(image->id);
+ image->size = swab32(image->size);
+ } else if (image->magic != FW_MAGIC) {
+ print_npe(npe, "bad microcode file %s magic: 0x%X\n", name, image->magic);
+ goto err;
+ }
+ if ((image->size * 4 + sizeof(struct dl_image)) > image_size) {
+ print_npe(npe, "incomplete microcode file %s\n", name);
+ goto err;
+ }
+ if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
+ print_npe(npe, "NPE ID mismatch in microcode file %s\n", name);
+ goto err;
+ }
+ if (image->magic == swab32(FW_MAGIC))
+ for (i = 0; i < image->size; i++)
+ image->data[i] = swab32(image->data[i]);
+
+ if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) {
+ print_npe(npe, "IXP43x/IXP46x microcode ignored on IXP42x\n");
+ goto err;
+ }
+
+ if (npe_running(npe)) {
+ print_npe(npe, "unable to load microcode file %s, NPE is already running\n", name);
+ err = -EBUSY;
+ goto err;
+ }
+
+ if (cpu_is_ixp42x()) {
+ if (!npe->id)
+ instr_size = NPE_A_42X_INSTR_SIZE;
+ else
+ instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
+ data_size = NPE_42X_DATA_SIZE;
+ } else {
+ instr_size = NPE_46X_INSTR_SIZE;
+ data_size = NPE_46X_DATA_SIZE;
+ }
+
+ for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
+ blocks++)
+ if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
+ break;
+ if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
+ print_npe(npe, "microcode EOF block marker not found\n");
+ goto err;
+ }
+
+#if DEBUG_FW
+ print_npe(npe, "%i microcode blocks found\n", blocks);
+#endif
+
+ table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
+ for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
+ if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
+ || blk->offset < table_end) {
+ print_npe(npe, "invalid offset 0x%X of "
+ "microcode block #%i\n", blk->offset, i);
+ goto err;
+ }
+
+ cb = (struct dl_codeblock*)&image->data[blk->offset];
+ if (blk->type == FW_BLOCK_TYPE_INSTR) {
+ if (cb->npe_addr + cb->size > instr_size)
+ goto too_big;
+ cmd = CMD_WR_INS_MEM;
+ } else if (blk->type == FW_BLOCK_TYPE_DATA) {
+ if (cb->npe_addr + cb->size > data_size)
+ goto too_big;
+ cmd = CMD_WR_DATA_MEM;
+ } else {
+ print_npe(npe, "invalid microcode block #%i type 0x%X\n",
+ i, blk->type);
+ goto err;
+ }
+ if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
+ print_npe(npe, "microcode block #%i doesn't "
+ "fit in microcode image: type %c, start 0x%X,"
+ " length 0x%X\n", i,
+ blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+ cb->npe_addr, cb->size);
+ goto err;
+ }
+
+ for (j = 0; j < cb->size; j++)
+ npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
+ }
+
+ npe_start(npe);
+ if (!npe_running(npe))
+ print_npe(npe, "unable to start\n");
+ free(image);
+ return 0;
+
+too_big:
+ print_npe(npe, "microcode block #%i doesn't fit in NPE "
+ "memory: type %c, start 0x%X, length 0x%X\n", i,
+ blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+ cb->npe_addr, cb->size);
+err:
+ free(image);
+ return err;
+}
+
+
+struct npe *npe_request(int id)
+{
+ if (id < NPE_COUNT)
+ if (npe_tab[id].valid)
+ return &npe_tab[id];
+ return NULL;
+}
+
+static int __init npe_init(void)
+{
+ int i;
+
+ for (i = 0; i < NPE_COUNT; i++) {
+ struct npe *npe = &npe_tab[i];
+ if (!(ixp4xx_read_feature_bits() & (IXP4XX_FEATURE_RESET_NPEA << i)))
+ continue; /* NPE already disabled or not present */
+ if (npe_reset(npe))
+ continue;
+ npe->valid = 1;
+ }
+ return 0;
+}
+
+coredevice_initcall(npe_init);
diff --git a/arch/arm/mach-ixp4xx/qmgr.c b/arch/arm/mach-ixp4xx/qmgr.c
new file mode 100644
index 0000000..49cba60
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/qmgr.c
@@ -0,0 +1,269 @@
+/*
+ * Intel IXP4xx Queue Manager driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <init.h>
+#include <errno.h>
+#include <mach/qmgr.h>
+
+static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
+
+#if DEBUG_QMGR
+char qmgr_queue_descs[HALF_QUEUES][32];
+#endif
+
+#ifdef CONFIG_USE_IRQ
+
+static void (*irq_handlers[HALF_QUEUES])(void *pdev);
+static void *irq_pdevs[HALF_QUEUES];
+
+#undef fls
+static inline int fls(int x)
+{
+ int ret;
+ asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
+ ret = 32 - ret;
+ return ret;
+}
+
+
+void qmgr_set_irq(unsigned int queue, int src,
+ void (*handler)(void *pdev), void *pdev)
+{
+ const u32 *reg;
+ int bit;
+ BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL);
+ reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */
+ bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
+ __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
+
+ irq_handlers[queue] = handler;
+ irq_pdevs[queue] = pdev;
+}
+
+
+static void qmgr_irq1_a0(void *data)
+{
+ int i;
+ u32 en_bitmap, src, stat;
+
+ /* ACK - it may clear any bits so don't rely on it */
+ __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]);
+
+ en_bitmap = qmgr_regs->irqen[0];
+ while (en_bitmap) {
+ i = fls(en_bitmap) - 1; /* number of the last "low" queue */
+ en_bitmap &= ~BIT(i);
+ src = qmgr_regs->irqsrc[i >> 3];
+ stat = qmgr_regs->stat1[i >> 3];
+ if (src & 4) /* the IRQ condition is inverted */
+ stat = ~stat;
+ if (stat & BIT(src & 3))
+ irq_handlers[i](irq_pdevs[i]);
+ }
+}
+
+
+static void qmgr_irq1(void *data)
+{
+ int i;
+ u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[0]);
+
+ if (!req_bitmap)
+ return;
+ __raw_writel(req_bitmap, &qmgr_regs->irqstat[0]); /* ACK */
+
+ while (req_bitmap) {
+ i = fls(req_bitmap) - 1; /* number of the last queue */
+ req_bitmap &= ~BIT(i);
+ irq_handlers[i](irq_pdevs[i]);
+ }
+}
+
+
+void qmgr_enable_irq(unsigned int queue)
+{
+ u32 mask = 1 << queue;
+
+ __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | mask,
+ &qmgr_regs->irqen[0]);
+}
+
+void qmgr_disable_irq(unsigned int queue)
+{
+ u32 mask = 1 << queue;
+
+ __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~mask,
+ &qmgr_regs->irqen[0]);
+ __raw_writel(mask, &qmgr_regs->irqstat[0]); /* clear */
+}
+
+#endif /* CONFIG_USE_IRQ */
+
+static inline void shift_mask(u32 *mask)
+{
+ mask[3] = mask[3] << 1 | mask[2] >> 31;
+ mask[2] = mask[2] << 1 | mask[1] >> 31;
+ mask[1] = mask[1] << 1 | mask[0] >> 31;
+ mask[0] <<= 1;
+}
+
+#if DEBUG_QMGR
+void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+ unsigned int nearly_empty_watermark,
+ unsigned int nearly_full_watermark,
+ const char *desc_format, const char* name)
+#else
+void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+ unsigned int nearly_empty_watermark,
+ unsigned int nearly_full_watermark)
+#endif
+{
+ u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
+
+ BUG_ON(queue >= HALF_QUEUES);
+ BUG_ON((nearly_empty_watermark | nearly_full_watermark) & ~7);
+
+ switch (len) {
+ case 16:
+ cfg = 0 << 24;
+ mask[0] = 0x1;
+ break;
+ case 32:
+ cfg = 1 << 24;
+ mask[0] = 0x3;
+ break;
+ case 64:
+ cfg = 2 << 24;
+ mask[0] = 0xF;
+ break;
+ case 128:
+ cfg = 3 << 24;
+ mask[0] = 0xFF;
+ break;
+ default:
+ BUG();
+ }
+
+ cfg |= nearly_empty_watermark << 26;
+ cfg |= nearly_full_watermark << 29;
+ len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */
+ mask[1] = mask[2] = mask[3] = 0;
+
+ BUG_ON(__raw_readl(&qmgr_regs->sram[queue]));
+
+ while (1) {
+ if (!(used_sram_bitmap[0] & mask[0]) &&
+ !(used_sram_bitmap[1] & mask[1]) &&
+ !(used_sram_bitmap[2] & mask[2]) &&
+ !(used_sram_bitmap[3] & mask[3]))
+ break; /* found free space */
+
+ addr++;
+ shift_mask(mask);
+ if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
+ fprintf(stderr, "qmgr: no free SRAM space for"
+ " queue %i\n", queue);
+ BUG();
+ }
+ }
+
+ used_sram_bitmap[0] |= mask[0];
+ used_sram_bitmap[1] |= mask[1];
+ used_sram_bitmap[2] |= mask[2];
+ used_sram_bitmap[3] |= mask[3];
+ __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
+#if DEBUG_QMGR
+ /* no snprintf() */
+ sprintf(qmgr_queue_descs[queue], desc_format, name);
+ fprintf(stderr, "qmgr: requested queue %s(%i) addr = 0x%02X\n",
+ qmgr_queue_descs[queue], queue, addr);
+#endif
+}
+
+void qmgr_release_queue(unsigned int queue)
+{
+ u32 cfg, addr, mask[4];
+
+ BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
+
+ cfg = __raw_readl(&qmgr_regs->sram[queue]);
+ addr = (cfg >> 14) & 0xFF;
+
+ BUG_ON(!addr); /* not requested */
+
+ switch ((cfg >> 24) & 3) {
+ case 0: mask[0] = 0x1; break;
+ case 1: mask[0] = 0x3; break;
+ case 2: mask[0] = 0xF; break;
+ case 3: mask[0] = 0xFF; break;
+ }
+
+ mask[1] = mask[2] = mask[3] = 0;
+
+ while (addr--)
+ shift_mask(mask);
+
+#if DEBUG_QMGR
+ fprintf(stderr, "qmgr: releasing queue %s(%i)\n",
+ qmgr_queue_descs[queue], queue);
+ qmgr_queue_descs[queue][0] = '\x0';
+#endif
+ __raw_writel(0, &qmgr_regs->sram[queue]);
+
+ used_sram_bitmap[0] &= ~mask[0];
+ used_sram_bitmap[1] &= ~mask[1];
+ used_sram_bitmap[2] &= ~mask[2];
+ used_sram_bitmap[3] &= ~mask[3];
+#ifdef CONFIG_USE_IRQ
+ irq_handlers[queue] = NULL; /* catch IRQ bugs */
+#endif
+
+ while ((addr = qmgr_get_entry(queue)))
+ fprintf(stderr, "qmgr: released queue %i not empty: 0x%08X\n",
+ queue, addr);
+}
+
+static int __init qmgr_init(void)
+{
+ int i;
+#ifdef CONFIG_USE_IRQ
+ interrupt_handler_t *handler;
+#endif
+
+ /* reset qmgr registers */
+ for (i = 0; i < 4; i++) {
+ __raw_writel(0x33333333, &qmgr_regs->stat1[i]);
+ __raw_writel(0, &qmgr_regs->irqsrc[i]);
+ }
+ for (i = 0; i < 2; i++) {
+ __raw_writel(0, &qmgr_regs->stat2[i]);
+ __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
+ __raw_writel(0, &qmgr_regs->irqen[i]);
+ }
+
+ __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h);
+ __raw_writel(0, &qmgr_regs->statf_h);
+
+ for (i = 0; i < QUEUES; i++)
+ __raw_writel(0, &qmgr_regs->sram[i]);
+
+#ifdef CONFIG_USE_IRQ
+ if (cpu_is_ixp42x_rev_a0())
+ handler = qmgr_irq1_a0;
+ else
+ handler = qmgr_irq1;
+
+ irq_install_handler(IXP425_QM1_IRQ, handler, NULL);
+#endif
+ used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
+ return 0;
+}
+
+coredevice_initcall(qmgr_init);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 69f3352..df6e42c 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -77,6 +77,14 @@ config DRIVER_NET_MACB
depends on HAS_MACB
select MIIDEV
+config DRIVER_NET_IXP4XX_ETH
+ tristate "Intel IXP4xx Ethernet support"
+ depends on ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
+ select MIIDEV
+ help
+ Say Y here if you want to use built-in Ethernet ports
+ on IXP4xx processor.
+
config DRIVER_NET_TAP
bool "tap Ethernet driver"
depends on LINUX
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 96d3d32..97cb44b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_DRIVER_NET_MACB) += macb.o
obj-$(CONFIG_DRIVER_NET_TAP) += tap.o
obj-$(CONFIG_MIIDEV) += miidev.o
obj-$(CONFIG_NET_USB) += usb/
+obj-$(CONFIG_DRIVER_NET_IXP4XX_ETH) += ixp4xx_eth.o
diff --git a/drivers/net/ixp4xx_eth.c b/drivers/net/ixp4xx_eth.c
new file mode 100644
index 0000000..71e6d92
--- /dev/null
+++ b/drivers/net/ixp4xx_eth.c
@@ -0,0 +1,763 @@
+/*
+ * Intel IXP4xx Ethernet driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * Ethernet port config (0x00 is not present on IXP42X):
+ *
+ * logical port 0x00 0x10 0x20
+ * NPE 0 (NPE-A) 1 (NPE-B) 2 (NPE-C)
+ * physical port 2 0 1
+ * RX queue (variable) 20 21 22
+ * TX queue 23 24 25
+ * RX-free queue 26 27 28
+ * TX-done queue is always 31, per-port RX queue is configurable
+ *
+ *
+ * Queue entries:
+ * bits 0 -> 1 - NPE ID (RX and TX-done)
+ * bits 0 -> 2 - priority (TX, per 802.1D)
+ * bits 3 -> 4 - port ID (user-set?)
+ * bits 5 -> 31 - physical descriptor address
+ */
+
+#include <common.h>
+#include <init.h>
+#include <malloc.h>
+#include <miidev.h>
+#include <net.h>
+#include <errno.h>
+#include <mach/ixp4xx-regs.h>
+#include <mach/platform.h>
+#include <mach/cpu.h>
+#include <mach/npe.h>
+#include <mach/qmgr.h>
+
+#define DEBUG_DESC 0
+#define DEBUG_RX 0
+#define DEBUG_TX 0
+#define DEBUG_PKT_BYTES 0
+#define DEBUG_MDIO 0
+#define DEBUG_OPEN 0
+#define DEBUG_CLOSE 0
+
+#define RX_DESCS 16 /* also length of all RX queues */
+#define TX_DESCS 16 /* also length of all TX queues */
+#define TXDONE_QUEUE_LEN 16 /* dwords */
+
+#define MAX_MRU 1536 /* 0x600 */
+#define RX_BUFF_SIZE MAX_MRU
+
+#define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */
+#define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */
+#define ETH_ALEN 6
+
+#define PHYSICAL_ID(port) (((port)->npe->id + 2) % 3)
+#define LOGICAL_ID(port) ((port)->npe->id << 4)
+#define RX_QUEUE(port) ((port)->npe->id + 20) /* can be changed */
+#define TX_QUEUE(port) ((port)->npe->id + 23)
+#define RXFREE_QUEUE(port) ((port)->npe->id + 26)
+#define TXDONE_QUEUE 31
+
+/* TX Control Registers */
+#define TX_CNTRL0_TX_EN 0x01
+#define TX_CNTRL0_HALFDUPLEX 0x02
+#define TX_CNTRL0_RETRY 0x04
+#define TX_CNTRL0_PAD_EN 0x08
+#define TX_CNTRL0_APPEND_FCS 0x10
+#define TX_CNTRL0_2DEFER 0x20
+#define TX_CNTRL0_RMII 0x40 /* reduced MII */
+#define TX_CNTRL1_RETRIES 0x0F /* 4 bits */
+
+/* RX Control Registers */
+#define RX_CNTRL0_RX_EN 0x01
+#define RX_CNTRL0_PADSTRIP_EN 0x02
+#define RX_CNTRL0_SEND_FCS 0x04
+#define RX_CNTRL0_PAUSE_EN 0x08
+#define RX_CNTRL0_LOOP_EN 0x10
+#define RX_CNTRL0_ADDR_FLTR_EN 0x20
+#define RX_CNTRL0_RX_RUNT_EN 0x40
+#define RX_CNTRL0_BCAST_DIS 0x80
+#define RX_CNTRL1_DEFER_EN 0x01
+
+/* Core Control Register */
+#define CORE_RESET 0x01
+#define CORE_RX_FIFO_FLUSH 0x02
+#define CORE_TX_FIFO_FLUSH 0x04
+#define CORE_SEND_JAM 0x08
+#define CORE_MDC_EN 0x10 /* MDIO using NPE-B ETH-0 only */
+
+#define DEFAULT_TX_CNTRL0 (TX_CNTRL0_TX_EN | TX_CNTRL0_RETRY | \
+ TX_CNTRL0_PAD_EN | TX_CNTRL0_APPEND_FCS | \
+ TX_CNTRL0_2DEFER)
+#define DEFAULT_RX_CNTRL0 RX_CNTRL0_RX_EN
+#define DEFAULT_CORE_CNTRL CORE_MDC_EN
+
+
+/* NPE message codes */
+#define NPE_GETSTATUS 0x00
+#define NPE_EDB_SETPORTADDRESS 0x01
+#define NPE_EDB_GETMACADDRESSDATABASE 0x02
+#define NPE_EDB_SETMACADDRESSSDATABASE 0x03
+#define NPE_GETSTATS 0x04
+#define NPE_RESETSTATS 0x05
+#define NPE_SETMAXFRAMELENGTHS 0x06
+#define NPE_VLAN_SETRXTAGMODE 0x07
+#define NPE_VLAN_SETDEFAULTRXVID 0x08
+#define NPE_VLAN_SETPORTVLANTABLEENTRY 0x09
+#define NPE_VLAN_SETPORTVLANTABLERANGE 0x0A
+#define NPE_VLAN_SETRXQOSENTRY 0x0B
+#define NPE_VLAN_SETPORTIDEXTRACTIONMODE 0x0C
+#define NPE_STP_SETBLOCKINGSTATE 0x0D
+#define NPE_FW_SETFIREWALLMODE 0x0E
+#define NPE_PC_SETFRAMECONTROLDURATIONID 0x0F
+#define NPE_PC_SETAPMACTABLE 0x11
+#define NPE_SETLOOPBACK_MODE 0x12
+#define NPE_PC_SETBSSIDTABLE 0x13
+#define NPE_ADDRESS_FILTER_CONFIG 0x14
+#define NPE_APPENDFCSCONFIG 0x15
+#define NPE_NOTIFY_MAC_RECOVERY_DONE 0x16
+#define NPE_MAC_RECOVERY_START 0x17
+
+struct eth_regs {
+ u32 tx_control[2], __res1[2]; /* 000 */
+ u32 rx_control[2], __res2[2]; /* 010 */
+ u32 random_seed, __res3[3]; /* 020 */
+ u32 partial_empty_threshold, __res4; /* 030 */
+ u32 partial_full_threshold, __res5; /* 038 */
+ u32 tx_start_bytes, __res6[3]; /* 040 */
+ u32 tx_deferral, rx_deferral, __res7[2]; /* 050 */
+ u32 tx_2part_deferral[2], __res8[2]; /* 060 */
+ u32 slot_time, __res9[3]; /* 070 */
+ u32 mdio_command[4]; /* 080 */
+ u32 mdio_status[4]; /* 090 */
+ u32 mcast_mask[6], __res10[2]; /* 0A0 */
+ u32 mcast_addr[6], __res11[2]; /* 0C0 */
+ u32 int_clock_threshold, __res12[3]; /* 0E0 */
+ u32 hw_addr[6], __res13[61]; /* 0F0 */
+ u32 core_control; /* 1FC */
+};
+
+/* NPE message structure */
+struct msg {
+ u8 cmd, eth_id, params[6];
+};
+
+/* Ethernet packet descriptor, 32 bytes */
+struct desc {
+ u8 *next; /* pointer to next buffer, unused */
+
+ u16 buf_len; /* buffer length */
+ u16 pkt_len; /* packet length */
+ u8 *data; /* pointer to data buffer in RAM */
+ u8 dest_id;
+ u8 src_id;
+ u16 flags;
+ u8 qos;
+ u8 padlen;
+ u16 vlan_tci;
+
+ u8 dst_mac[ETH_ALEN], src_mac[ETH_ALEN];
+};
+
+struct port {
+ struct desc rx_desc_tab[RX_DESCS]; /* alignment: 0x10 */
+ struct desc tx_desc_tab[TX_DESCS];
+ u8 *buff_tab;
+ struct eth_regs *regs;
+ struct npe *npe;
+ u8 firmware[4];
+ struct eth_plat_info *pinfo;
+ struct mii_device miidev;
+ struct eth_device eth;
+};
+
+#define rx_buff(port, n) ((port)->buff_tab + MAX_MRU * (n))
+#define tx_buff(port, n) ((port)->buff_tab + MAX_MRU * (RX_DESCS + (n)))
+
+static struct eth_regs *mdio_regs; /* mdio command and status only */
+
+static int ixp4xx_mdio_cmd(int write, const struct device_d *dev, unsigned char phy_id,
+ unsigned char location, unsigned short value)
+{
+ int cycles = 0;
+
+ if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {
+ fprintf(stderr, "%s%d: MII not ready to transmit\n", dev->name, dev->id);
+ return -1;
+ }
+
+ if (write) {
+ __raw_writel(value & 0xFF, &mdio_regs->mdio_command[0]);
+ __raw_writel(value >> 8, &mdio_regs->mdio_command[1]);
+ }
+ __raw_writel(((phy_id << 5) | location) & 0xFF,
+ &mdio_regs->mdio_command[2]);
+ __raw_writel((phy_id >> 3) | (write << 2) | 0x80 /* GO */,
+ &mdio_regs->mdio_command[3]);
+
+ while ((cycles < MAX_MDIO_RETRIES) &&
+ (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80)) {
+ udelay(1);
+ cycles++;
+ }
+
+ if (cycles == MAX_MDIO_RETRIES) {
+ fprintf(stderr, "%s%d: MII write failed\n", dev->name, dev->id);
+ return -1;
+ }
+
+#if DEBUG_MDIO
+ fprintf(stderr, "%s%d: mdio_%s() took %i cycles\n", dev->name, dev->id,
+ write ? "write" : "read", cycles);
+#endif
+
+ if (write)
+ return 0;
+
+ if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {
+#if DEBUG_MDIO
+ fprintf(stderr, "%s%d: MII read failed\n", dev->name, dev->id);
+#endif
+ return -1;
+ }
+
+ value = (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |
+ ((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8);
+#if DEBUG_MDIO
+ fprintf(stderr, "%s%d: MII read [%i] -> 0x%X\n", dev->name, dev->id, location, value);
+#endif
+
+ return value;
+}
+
+static int ixp4xx_mdio_read(struct mii_device *mii, int phy_id, int location)
+{
+ int ret = ixp4xx_mdio_cmd(0, &mii->dev, phy_id, location, 0);
+ return ret;
+}
+
+static int ixp4xx_mdio_write(struct mii_device *mii, int phy_id, int location, int value)
+{
+ int ret = ixp4xx_mdio_cmd(1, &mii->dev, phy_id, location, value);
+#if DEBUG_MDIO
+ fprintf(stderr, "%s%d: MII write [%i] <- 0x%X, err = %i\n",
+ mii->dev.name, mii->dev.id, location, value, ret);
+#endif
+ return ret;
+}
+
+static int ixp4xx_adjust_link(struct eth_device *dev)
+{
+ struct port *port = dev->priv;
+ int reg, speed, duplex;
+
+ miidev_wait_aneg(&port->miidev);
+
+ reg = mii_read(&port->miidev, port->miidev.address, MII_BMSR);
+ if (reg < 0)
+ goto err_out;
+ if (!(reg & BMSR_LSTATUS)) {
+ printf("%s%d: Link is down", dev->dev.name, dev->dev.id);
+ return -1;
+ }
+
+ reg = mii_read(&port->miidev, port->miidev.address, MII_BMCR);
+ if (reg < 0)
+ goto err_out;
+
+ if (reg & BMCR_ANENABLE) {
+ reg = mii_read(&port->miidev, port->miidev.address, MII_LPA);
+ if (reg < 0)
+ goto err_out;
+ duplex = reg & LPA_DUPLEX;
+ speed = reg & LPA_100 ? 100 : 10;
+ } else {
+ duplex = reg & BMCR_FULLDPLX;
+ speed = reg & BMCR_SPEED100 ? 100 : 10;
+ }
+
+ if (duplex)
+ __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+ else
+ __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+
+ fprintf(stderr, "%s%d: link up, speed %u Mb/s, %s duplex\n",
+ dev->dev.name, dev->dev.id, speed, duplex ? "full" : "half");
+ return 0;
+
+err_out:
+ printf("%s%d: failed to read MII data\n", dev->dev.name, dev->dev.id);
+ return -EIO;
+}
+
+static inline void debug_pkt(struct eth_device *dev, const char *func,
+ u8 *data, int len)
+{
+#if DEBUG_PKT_BYTES
+ int i;
+
+ fprintf(stderr, "%s%d: %s(%4i) ", dev->dev.name, dev->dev.id, func, len);
+ for (i = 0; i < len; i++) {
+ if (i >= DEBUG_PKT_BYTES)
+ break;
+ fprintf(stderr, "%s%02X",
+ ((i == 6) || (i == 12) || (i >= 14)) ? " " : "",
+ data[i]);
+ }
+ fprintf(stderr, "\n");
+#endif
+}
+
+
+static inline void debug_desc(struct desc *desc)
+{
+#if DEBUG_DESC
+ fprintf(stderr, "%07X: %X %3X %3X %07X %2X < %2X %4X %X"
+ " %X %X %02X%02X%02X%02X%02X%02X < %02X%02X%02X%02X%02X%02X\n",
+ (u32)desc, (u32)desc->next, desc->buf_len, desc->pkt_len,
+ (u32)desc->data, desc->dest_id, desc->src_id, desc->flags,
+ desc->qos, desc->padlen, desc->vlan_tci,
+ desc->dst_mac[0], desc->dst_mac[1], desc->dst_mac[2],
+ desc->dst_mac[3], desc->dst_mac[4], desc->dst_mac[5],
+ desc->src_mac[0], desc->src_mac[1], desc->src_mac[2],
+ desc->src_mac[3], desc->src_mac[4], desc->src_mac[5]);
+#endif
+}
+
+static inline int queue_get_desc(unsigned int queue, struct port *port,
+ int is_tx)
+{
+ u32 addr, n;
+ struct desc *tab;
+
+ if (!(addr = qmgr_get_entry(queue)))
+ return -1;
+
+ addr &= ~0x1F; /* mask out non-address bits */
+ tab = is_tx ? port->tx_desc_tab : port->rx_desc_tab;
+ n = (addr - (u32)tab) / sizeof(struct desc);
+ BUG_ON(n >= (is_tx ? TX_DESCS : RX_DESCS));
+ debug_desc((struct desc*)addr);
+ BUG_ON(tab[n].next);
+ return n;
+}
+
+static inline void queue_put_desc(unsigned int queue, struct desc *desc)
+{
+ debug_desc(desc);
+ BUG_ON(((u32)desc) & 0x1F);
+ qmgr_put_entry(queue, (u32)desc);
+ /* Don't check for queue overflow here, we've allocated sufficient
+ length and queues >= 32 don't support this check anyway. */
+}
+
+
+static int ixp4xx_eth_poll(struct eth_device *dev)
+{
+ struct port *port = dev->priv;
+ struct desc *desc;
+ u8 *buff;
+ int n, len;
+
+#if DEBUG_RX
+ fprintf(stderr, "%s%d: eth_poll\n", dev->dev.name, dev->dev.id);
+#endif
+
+ if ((n = queue_get_desc(RX_QUEUE(port), port, 0)) < 0) {
+#if DEBUG_RX
+ fprintf(stderr, "%s%d: eth_poll = no packet received\n", dev->dev.name, dev->dev.id);
+#endif
+ return 0;
+ }
+
+ barrier();
+ desc = &port->rx_desc_tab[n];
+ buff = rx_buff(port, n);
+ len = desc->pkt_len;
+ /* process received frame */
+ memcpy((void *)NetRxPackets[0], buff, len);
+ debug_pkt(dev, "RX", desc->data, len);
+
+ /* put the new buffer on RX-free queue */
+ desc->buf_len = MAX_MRU;
+ desc->pkt_len = 0;
+ queue_put_desc(RXFREE_QUEUE(port), desc);
+
+ net_receive(NetRxPackets[0], len);
+
+#if DEBUG_RX
+ fprintf(stderr, "%s%d: eth_poll end\n", dev->dev.name, dev->dev.id);
+#endif
+ return 0;
+}
+
+
+static int ixp4xx_eth_xmit(struct eth_device *dev, void *data, int len)
+{
+ struct port *port = dev->priv;
+ int n;
+ struct desc *desc;
+
+#if DEBUG_TX
+ fprintf(stderr, "%s%d: eth_xmit\n", dev->dev.name, dev->dev.id);
+#endif
+
+ if (unlikely(len > 1500))
+ return -1;
+
+ debug_pkt(dev, "TX", data, len);
+
+ if ((n = queue_get_desc(TXDONE_QUEUE, port, 1)) < 0)
+ return -1; /* no free buffers */
+ desc = &port->tx_desc_tab[n];
+ desc->data = tx_buff(port, n);
+ desc->buf_len = desc->pkt_len = len;
+ memcpy(desc->data, data, len);
+
+ /* NPE firmware pads short frames with zeros internally */
+ // wmb();
+ barrier();
+ queue_put_desc(TX_QUEUE(port), desc);
+
+#if DEBUG_TX
+ fprintf(stderr, "%s%d: eth_xmit end\n", dev->dev.name, dev->dev.id);
+#endif
+ return 0;
+}
+
+static void request_queues(struct port *port, struct eth_device *dev)
+{
+ qmgr_request_queue(RXFREE_QUEUE(port), RX_DESCS, 0, 0, "%s:RX-free", dev->dev.name);
+ qmgr_request_queue(RX_QUEUE(port), RX_DESCS, 0, 0, "%s:RX", dev->dev.name);
+ qmgr_request_queue(TX_QUEUE(port), TX_DESCS, 0, 0, "%s:TX", dev->dev.name);
+
+ /* Common TX-done queue handles buffers sent out by the NPEs */
+ qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0,
+ "%s:TX-done", dev->dev.name);
+}
+
+static void release_queues(struct port *port)
+{
+ qmgr_release_queue(RXFREE_QUEUE(port));
+ qmgr_release_queue(RX_QUEUE(port));
+ qmgr_release_queue(TX_QUEUE(port));
+ qmgr_release_queue(TXDONE_QUEUE);
+}
+
+static void init_queues(struct port *port)
+{
+ int i;
+
+ memset(port->tx_desc_tab, 0, sizeof(port->tx_desc_tab)); /* descs */
+ memset(port->rx_desc_tab, 0, sizeof(port->rx_desc_tab));
+
+ /* Setup RX buffers */
+ for (i = 0; i < RX_DESCS; i++) {
+ struct desc *desc = &port->rx_desc_tab[i];
+ desc->buf_len = MAX_MRU;
+ desc->data = rx_buff(port, i);
+ }
+}
+
+static int ixp4xx_eth_open(struct eth_device *dev)
+{
+ struct port *port = dev->priv;
+ struct npe *npe = port->npe;
+ struct msg msg;
+ int i, err;
+
+#if DEBUG_OPEN
+ fprintf(stderr, "%s%d: opening %p\n", dev->dev.name, dev->dev.id, dev);
+#endif
+
+ if (!npe_running(npe)) {
+ err = npe_load_firmware(npe);
+ if (err)
+ return err;
+
+ if (npe_recv_message(npe, &msg, "ETH_GET_STATUS")) {
+ fprintf(stderr, "%s%d: %s not responding\n", dev->dev.name, dev->dev.id, npe->name);
+ return -EIO;
+ }
+ memcpy(port->firmware, msg.params + 2, 4);
+ }
+
+ if (ixp4xx_adjust_link(dev))
+ return -ENOLINK;
+
+ port->buff_tab = xmalloc((RX_DESCS + TX_DESCS) * MAX_MRU);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_VLAN_SETRXQOSENTRY;
+ msg.eth_id = LOGICAL_ID(port);
+ msg.params[3] = RX_QUEUE(port) | 0x80;
+ msg.params[4] = RX_QUEUE(port) >> 4; /* MSB of offset */
+ msg.params[5] = RX_QUEUE(port) << 4; /* LSB of offset */
+ for (i = 0; i < 8; i++) {
+ msg.params[1] = i;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_RXQ")) {
+ err = -EIO;
+ goto out;
+ }
+ }
+
+ msg.cmd = NPE_EDB_SETPORTADDRESS;
+ msg.eth_id = PHYSICAL_ID(port);
+ memcpy(msg.params, port->pinfo->hwaddr, ETH_ALEN);
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAC")) {
+ err = -EIO;
+ goto out;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_FW_SETFIREWALLMODE;
+ msg.eth_id = LOGICAL_ID(port);
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE")) {
+ err = -EIO;
+ goto out;
+ }
+
+ request_queues(port, dev);
+ init_queues(port);
+
+ for (i = 0; i < ETH_ALEN; i++)
+ __raw_writel(port->pinfo->hwaddr[i], &port->regs->hw_addr[i]);
+ __raw_writel(0x08, &port->regs->random_seed);
+ __raw_writel(0x12, &port->regs->partial_empty_threshold);
+ __raw_writel(0x30, &port->regs->partial_full_threshold);
+ __raw_writel(0x08, &port->regs->tx_start_bytes);
+ __raw_writel(0x15, &port->regs->tx_deferral);
+ __raw_writel(0x08, &port->regs->tx_2part_deferral[0]);
+ __raw_writel(0x07, &port->regs->tx_2part_deferral[1]);
+ __raw_writel(0x80, &port->regs->slot_time);
+ __raw_writel(0x01, &port->regs->int_clock_threshold);
+
+ /* Populate queues with buffers, no failure after this point */
+ for (i = 0; i < TX_DESCS; i++)
+ queue_put_desc(TXDONE_QUEUE, &port->tx_desc_tab[i]);
+
+ for (i = 0; i < RX_DESCS; i++)
+ queue_put_desc(RXFREE_QUEUE(port), &port->rx_desc_tab[i]);
+
+ __raw_writel(TX_CNTRL1_RETRIES, &port->regs->tx_control[1]);
+ __raw_writel(DEFAULT_TX_CNTRL0, &port->regs->tx_control[0]);
+ __raw_writel(0, &port->regs->rx_control[1]);
+ __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);
+
+#if 0
+ qmgr_set_irq(RX_QUEUE(port), QUEUE_IRQ_SRC_NOT_EMPTY,
+ eth_rx_irq, dev);
+ qmgr_set_irq(TXDONE_QUEUE, QUEUE_IRQ_SRC_NOT_EMPTY,
+ eth_txdone_irq, NULL);
+ qmgr_enable_irq(TXDONE_QUEUE);
+#endif
+ memset(&msg, 0, sizeof(msg));
+#if DEBUG_OPEN
+ fprintf(stderr, "%s%d opened\n", dev->dev.name, dev->dev.id);
+#endif
+ return 0;
+out:
+ free(port->buff_tab);
+ port->buff_tab = NULL;
+#if DEBUG_OPEN
+ fprintf(stderr, "%s%d open failed (%i)\n", dev->dev.name, dev->dev.id, err);
+#endif
+ return err;
+}
+
+static void ixp4xx_eth_close(struct eth_device *dev)
+{
+ struct port *port = dev->priv;
+ struct msg msg;
+ int buffs = RX_DESCS; /* allocated RX buffers */
+ int i;
+
+#if DEBUG_CLOSE
+ fprintf(stderr, "%s%d: closing\n", dev->dev.name, dev->dev.id);
+#endif
+#if 0
+ qmgr_disable_irq(RX_QUEUE(port));
+#endif
+
+ if (!port->buff_tab)
+ return; /* already closed */
+
+ while (queue_get_desc(RXFREE_QUEUE(port), port, 0) >= 0)
+ buffs--;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_SETLOOPBACK_MODE;
+ msg.eth_id = LOGICAL_ID(port);
+ msg.params[1] = 1;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_ENABLE_LOOPBACK"))
+ fprintf(stderr, "%s%d: unable to enable loopback\n", dev->dev.name, dev->dev.id);
+
+#if DEBUG_CLOSE
+ fprintf(stderr, "%s%d: draining RX queue\n", dev->dev.name, dev->dev.id);
+#endif
+ i = 0;
+ do { /* drain RX buffers */
+ while (queue_get_desc(RX_QUEUE(port), port, 0) >= 0)
+ buffs--;
+ if (!buffs)
+ break;
+ if (qmgr_stat_full(TXDONE_QUEUE) && !(i % 10)) {
+ /* we have to inject some packet */
+ struct desc *desc;
+ int n = queue_get_desc(TXDONE_QUEUE, port, 1);
+ BUG_ON(n < 0);
+ desc = &port->tx_desc_tab[n];
+ desc->buf_len = desc->pkt_len = 1;
+ //wmb();
+ barrier();
+ queue_put_desc(TX_QUEUE(port), desc);
+ }
+ udelay(1);
+ } while (++i < MAX_CLOSE_WAIT);
+
+ if (buffs)
+ fprintf(stderr, "%s%d: unable to drain RX queue, %i buffer(s) left in NPE\n",
+ dev->dev.name, dev->dev.id, buffs);
+#if DEBUG_CLOSE
+ if (!buffs)
+ fprintf(stderr, "%s%d: draining RX queue took %i cycles\n", dev->dev.name, dev->dev.id, i);
+#endif
+
+ buffs = TX_DESCS;
+ while (queue_get_desc(TX_QUEUE(port), port, 1) >= 0)
+ buffs--; /* cancel TX */
+
+ i = 0;
+ do {
+ while (queue_get_desc(TXDONE_QUEUE, port, 1) >= 0)
+ buffs--;
+ if (!buffs)
+ break;
+ } while (++i < MAX_CLOSE_WAIT);
+
+ if (buffs)
+ fprintf(stderr, "%s%d: unable to drain TX queue, %i buffer(s) left in NPE\n",
+ dev->dev.name, dev->dev.id, buffs);
+#if DEBUG_CLOSE
+ if (!buffs)
+ fprintf(stderr, "%s%d: draining TX queues took %i cycles\n", dev->dev.name, dev->dev.id, i);
+#endif
+
+ msg.params[1] = 0;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_DISABLE_LOOPBACK"))
+ fprintf(stderr, "%s%d: unable to disable loopback\n", dev->dev.name, dev->dev.id);
+
+#if 0
+ qmgr_disable_irq(TXDONE_QUEUE);
+#endif
+ release_queues(port);
+ free(port->buff_tab);
+ port->buff_tab = NULL;
+#if DEBUG_CLOSE
+ fprintf(stderr, "%s%d: closed\n", dev->dev.name, dev->dev.id);
+#endif
+}
+
+static int ixp4xx_eth_get_hwaddr(struct eth_device *eth, unsigned char *addr)
+{
+ struct port *port = eth->priv;
+ memcpy(addr, port->pinfo->hwaddr, 6);
+ return 0;
+}
+
+static int ixp4xx_eth_set_hwaddr(struct eth_device *eth, unsigned char *addr)
+{
+ struct port *port = eth->priv;
+ memcpy(port->pinfo->hwaddr, addr, 6);
+ return 0;
+}
+
+static int ixp4xx_eth_init(struct eth_device *eth)
+{
+ struct port *port = eth->priv;
+
+ __raw_writel(DEFAULT_CORE_CNTRL | CORE_RESET,
+ &port->regs->core_control);
+ udelay(50);
+ __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
+ udelay(50);
+
+ miidev_restart_aneg(&port->miidev);
+ return 0;
+}
+
+static int ixp4xx_eth_probe(struct device_d *dev)
+{
+ struct npe *npe;
+ struct port *port;
+ struct eth_plat_info *pinfo = dev->platform_data;
+
+ if (!pinfo) {
+ fprintf(stderr, "ixp4xx_eth: no platform information\n");
+ return -ENODEV;
+ }
+
+ if (!(npe = npe_request(pinfo->npe))) {
+ fprintf(stderr, "ixp4xx_eth: unable to acquire NPE\n");
+ return -ENODEV;
+ }
+
+ port = memalign(0x20, sizeof(*port));
+ memset(port, 0, sizeof(*port));
+
+ port->regs = pinfo->regs;
+ port->npe = npe;
+ port->pinfo = pinfo;
+ port->eth.dev.id = -1;
+ port->eth.priv = port;
+ port->eth.init = ixp4xx_eth_init;
+ port->eth.open = ixp4xx_eth_open;
+ port->eth.halt = ixp4xx_eth_close;
+ port->eth.send = ixp4xx_eth_xmit;
+ port->eth.recv = ixp4xx_eth_poll;
+ port->eth.get_ethaddr = ixp4xx_eth_get_hwaddr;
+ port->eth.set_ethaddr = ixp4xx_eth_set_hwaddr;
+
+ port->miidev.dev.id = -1;
+ port->miidev.read = ixp4xx_mdio_read;
+ port->miidev.write = ixp4xx_mdio_write;
+ port->miidev.address = pinfo->phy;
+ port->miidev.edev = &port->eth;
+ mii_register(&port->miidev);
+ eth_register(&port->eth);
+ return 0;
+}
+
+static struct driver_d ixp4xx_eth_driver = {
+ .name = "ixp4xx_eth",
+ .probe = ixp4xx_eth_probe,
+};
+
+static int __init ixp4xx_eth_module_init(void)
+{
+ if (cpu_is_ixp43x()) {
+ /* IXP43x lacks NPE-B and uses NPE-C for MII PHY access */
+ if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEC_ETH))
+ return -ENOSYS;
+ mdio_regs = (struct eth_regs *)IXP4XX_EthC_BASE;
+ } else {
+ /* All MII PHY accesses use NPE-B Ethernet registers */
+ if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
+ return -ENOSYS;
+ mdio_regs = (struct eth_regs *)IXP4XX_EthB_BASE;
+ }
+
+ __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
+
+ register_driver(&ixp4xx_eth_driver);
+ return 0;
+}
+
+device_initcall(ixp4xx_eth_module_init);
diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
index 290619f..0f25ceb 100644
--- a/drivers/serial/serial_ns16550.c
+++ b/drivers/serial/serial_ns16550.c
@@ -102,7 +102,11 @@ static void ns16550_serial_init_port(struct console_device *cdev)
baud_divisor = ns16550_calc_divisor(cdev, CONFIG_BAUDRATE);
/* initializing the device for the first time */
+#ifdef CONFIG_ARCH_IXP4XX
+ plat->reg_write(IER_UUE, base, ier); /* Enable UART operation */
+#else
plat->reg_write(0x00, base, ier);
+#endif
#ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
plat->reg_write(0x07, base, mdr1); /* Disable */
#endif
@@ -181,7 +185,11 @@ static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate)
cdev->dev->platform_data;
unsigned long base = cdev->dev->map_base;
unsigned int baud_divisor = ns16550_calc_divisor(cdev, baud_rate);
+#ifdef CONFIG_ARCH_IXP4XX
+ plat->reg_write(IER_UUE, base, ier); /* Enable UART operation */
+#else
plat->reg_write(0x00, base, ier);
+#endif
plat->reg_write(LCR_BKSE, base, lcr);
plat->reg_write(baud_divisor & 0xff, base, dll);
plat->reg_write((baud_divisor >> 8) & 0xff, base, dlm);
diff --git a/drivers/serial/serial_ns16550.h b/drivers/serial/serial_ns16550.h
index eb2fd10..ba20a6f 100644
--- a/drivers/serial/serial_ns16550.h
+++ b/drivers/serial/serial_ns16550.h
@@ -50,6 +50,8 @@
#define dll rbr
#define dlm ier
+#define IER_UUE 0x40 /* UART Unit Enable (XScale) */
+
#define FCR_FIFO_EN 0x01 /* Fifo enable */
#define FCR_RXSR 0x02 /* Receiver soft reset */
#define FCR_TXSR 0x04 /* Transmitter soft reset */
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-20 23:06 ` [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Krzysztof Halasa
@ 2010-12-21 7:42 ` Belisko Marek
2010-12-21 9:25 ` Sascha Hauer
2010-12-21 9:30 ` Juergen Beisert
2010-12-21 8:35 ` Sascha Hauer
2010-12-22 0:57 ` Jean-Christophe PLAGNIOL-VILLARD
2 siblings, 2 replies; 41+ messages in thread
From: Belisko Marek @ 2010-12-21 7:42 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
Hi,
On Tue, Dec 21, 2010 at 12:06 AM, Krzysztof Halasa <khc@pm.waw.pl> wrote:
> Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 8cb86cb..56b5a0d 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -39,6 +39,13 @@ config ARCH_IMX
> bool "Freescale iMX-based"
> select GENERIC_GPIO
>
> +config ARCH_IXP4XX
> + bool "Intel IXP4xx-based"
> + select CPU_32v5
> + select ARCH_SUPPORTS_BIG_ENDIAN
> + select CPU_BIG_ENDIAN
> + select ARCH_HAS_LOWLEVEL_INIT
> +
Should go to different Kconfig. This is ARM related and you have
intel cpu which is possibly x86. Also in other patches you stick to ARM
but your CPU doesn't have ARM core.
> config ARCH_STM
> bool "SigmaTel/FSL iMX-based"
> select GENERIC_GPIO
> @@ -67,6 +74,7 @@ source arch/arm/cpu/Kconfig
> source arch/arm/mach-at91/Kconfig
> source arch/arm/mach-ep93xx/Kconfig
> source arch/arm/mach-imx/Kconfig
> +source arch/arm/mach-ixp4xx/Kconfig
> source arch/arm/mach-stm/Kconfig
> source arch/arm/mach-netx/Kconfig
> source arch/arm/mach-nomadik/Kconfig
> diff --git a/arch/arm/Makefile b/arch/arm/Makefile
> index 9729c23..2e9f99d 100644
> --- a/arch/arm/Makefile
> +++ b/arch/arm/Makefile
> @@ -41,6 +41,7 @@ CPPFLAGS += $(CFLAGS_ABI) $(arch-y) $(tune-y)
> machine-$(CONFIG_ARCH_AT91) := at91
> machine-$(CONFIG_ARCH_EP93XX) := ep93xx
> machine-$(CONFIG_ARCH_IMX) := imx
> +machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx
> machine-$(CONFIG_ARCH_STM) := stm
> machine-$(CONFIG_ARCH_NOMADIK) := nomadik
> machine-$(CONFIG_ARCH_NETX) := netx
> @@ -73,6 +74,7 @@ board-$(CONFIG_MACH_FREESCALE_MX35_3STACK) := freescale-mx35-3-stack
> board-$(CONFIG_MACH_IMX21ADS) := imx21ads
> board-$(CONFIG_MACH_IMX27ADS) := imx27ads
> board-$(CONFIG_MACH_MMCCPU) := mmccpu
> +board-$(CONFIG_MACH_MULTILINK) := multilink
> board-$(CONFIG_MACH_MX1ADS) := mx1ads
> board-$(CONFIG_MACH_NOMADIK_8815NHK) := nhk8815
> board-$(CONFIG_MACH_NXDB500) := netx
> diff --git a/arch/arm/boards/multilink/Makefile b/arch/arm/boards/multilink/Makefile
> new file mode 100644
> index 0000000..d5a8bbc
> --- /dev/null
> +++ b/arch/arm/boards/multilink/Makefile
> @@ -0,0 +1 @@
> +obj-y += lowlevel_init.o multilink.o
> diff --git a/arch/arm/boards/multilink/config.h b/arch/arm/boards/multilink/config.h
> new file mode 100644
> index 0000000..e69de29
> diff --git a/arch/arm/boards/multilink/lowlevel_init.S b/arch/arm/boards/multilink/lowlevel_init.S
> new file mode 100644
> index 0000000..970ef72
> --- /dev/null
> +++ b/arch/arm/boards/multilink/lowlevel_init.S
> @@ -0,0 +1,64 @@
> +#include <mach/ixp4xx-regs.h>
> +
> + .section ".text_bare_init", "ax"
> + .balign 0x40
> + .space 0x40 /* configuration block at 0x40 */
> +
> + .macro DELAY_FOR cycles, reg0
> + ldr \reg0, =\cycles
> + subs \reg0, \reg0, #1
> + subne pc, pc, #0xc
> + .endm
> +
> +#define CFG_SDRAM_SIZE 0x50 /* u32 */
> +#define CFG_SDRAM_CONF 0x54 /* u32 */
> +#define CFG_SDRAM_MODE 0x58 /* u32 */
> +#define CFG_SDRAM_REFRESH 0x5C /* u32 */
> +
> +.globl board_init_lowlevel
> +board_init_lowlevel:
> + mov r8, #IXP4XX_EXP_BASE(0)
> + ldr r1, [r8, #CFG_SDRAM_CONF]
> + ldr r2, =IXP4XX_SDRAM_CONFIG
> + str r1, [r2]
> +
> + /* disable refresh cycles */
> + mov r1, #0
> + add r2, r2, #4 /* r2 = IXP4XX_SDRAM_REFRESH */
> + str r1, [r2]
> +
> + /* send NOP command */
> + mov r1, #3
> + add r3, r2, #4 /* r3 = IXP4XX_SDRAM_IR */
> + str r1, [r3]
> + DELAY_FOR 0x4000, r0
> +
> + /* set SDRAM internal refresh */
> + ldr r1, [r8, #CFG_SDRAM_REFRESH]
> + str r1, [r2]
> + DELAY_FOR 0x4000, r0
> +
> + /* send precharge-all command to close all open banks */
> + mov r1, #2
> + str r1, [r3]
> + DELAY_FOR 0x4000, r0
> +
> + /* provide 8 auto-refresh cycles */
> + mov r1, #4
> + mov r4, #8
> +1: str r1, [r3]
> + DELAY_FOR 0x100, r0
> + subs r4, r4, #1
> + bne 1b
> +
> + /* set mode register in SDRAM */
> + ldr r1, [r8, #CFG_SDRAM_MODE]
> + str r1, [r3]
> + DELAY_FOR 0x4000, r0
> +
> + /* send normal operation command */
> + mov r1, #6
> + str r1, [r3]
> + DELAY_FOR 0x4000, r0
> +
> + mov pc, lr
> diff --git a/arch/arm/boards/multilink/multilink.c b/arch/arm/boards/multilink/multilink.c
> new file mode 100644
> index 0000000..f2fb8f4
> --- /dev/null
> +++ b/arch/arm/boards/multilink/multilink.c
> @@ -0,0 +1,144 @@
> +//#define DEBUG
> +#include <common.h>
> +#include <errno.h>
> +#include <init.h>
> +#include <linux/types.h>
> +#include <asm/armlinux.h>
> +#include <asm/io.h>
> +#include <generated/mach-types.h>
> +#include <mach/ixp4xx-regs.h>
> +#include <mach/platform.h>
> +
> +/* offsets from start of flash ROM = 0x50000000 */
> +#define CFG_ETH0_ADDRESS 0x40 /* 6 bytes */
> +#define CFG_ETH1_ADDRESS 0x46 /* 6 bytes */
> +#define CFG_REV 0x4C /* u32 */
> +#define CFG_SDRAM_SIZE 0x50 /* u32 */
> +#define CFG_SDRAM_CONF 0x54 /* u32 */
> +#define CFG_SDRAM_MODE 0x58 /* u32 */
> +#define CFG_SDRAM_REFRESH 0x5C /* u32 */
> +
> +#define CFG_HW_BITS 0x60 /* u32 */
> +#define CFG_HW_USB_PORTS 0x00000007 /* 0 = no NEC chip, 1-5 = ports # */
> +#define CFG_HW_HAS_PCI_SLOT 0x00000008
> +#define CFG_HW_HAS_ETH0 0x00000010
> +#define CFG_HW_HAS_ETH1 0x00000020
> +#define CFG_HW_HAS_HSS0 0x00000040
> +#define CFG_HW_HAS_HSS1 0x00000080
> +#define CFG_HW_HAS_UART0 0x00000100
> +#define CFG_HW_HAS_UART1 0x00000200
> +#define CFG_HW_HAS_EEPROM 0x00000400
> +
> +#define ETH_ALEN 6
> +
> +#define BAREBOX_START 0x00000
> +#define BAREBOX_LENGTH 0x34000
> +#define NPE_A_START (BAREBOX_START + BAREBOX_LENGTH)
> +#define NPE_A_LENGTH 0x05000
> +#define NPE_B_START (NPE_A_START + NPE_A_LENGTH)
> +#define NPE_B_LENGTH 0x03000
> +#define NPE_C_START (NPE_B_START + NPE_B_LENGTH)
> +#define NPE_C_LENGTH 0x04000
> +#define NPE_ENV0_START (NPE_C_START + NPE_C_LENGTH)
> +#define NPE_ENV0_LENGTH 0x20000
> +
> +static struct device_d cfi_dev = {
> + .name = "cfi_flash",
> + .map_base = IXP4XX_EXP_BASE(0),
> + .size = 16 * 1024 * 1024,
> +};
> +
> +static struct eth_plat_info eth_pinfo[2] = {
> + {
> + .regs = IXP4XX_EthB_BASE,
> + .npe = 1,
> + .phy = 0,
> + .rxq = 20,
> + .txreadyq = 29,
> + }, {
> + .regs = IXP4XX_EthC_BASE,
> + .npe = 2,
> + .phy = 1,
> + .rxq = 21,
> + .txreadyq = 30,
> + }
> +};
> +
> +static struct device_d eth_dev[2] = {
> + {
> + .name = "ixp4xx_eth",
> + .platform_data = ð_pinfo[0],
> + }, {
> + .id = 1,
> + .name = "ixp4xx_eth",
> + .platform_data = ð_pinfo[1],
> + }
> +};
> +
> +static struct memory_platform_data ram_pdata = {
> + .name = "ram0",
> + .flags = DEVFS_RDWR,
> +};
> +
> +struct device_d sdram_dev = {
> + .id = -1,
> + .name = "mem",
> + .map_base = 0x00000000,
> + .size = 32 * 1024 * 1024,
> + .platform_data = &ram_pdata,
> +};
> +
> +static inline u8 __init flash_readb(u32 addr)
> +{
> + return __raw_readb(IXP4XX_EXP_BASE(0) + addr);
> +}
> +
> +static int __init gml_devices_init(void)
> +{
> + u32 hw_bits;
> + int i;
> +
> + IXP4XX_EXP_CS0 = IXP4XX_EXP_EN | IXP4XX_EXP_INTEL |
> + IXP4XX_EXP_BITS(24) | IXP4XX_EXP_WR_EN | IXP4XX_EXP_BYTE_RD16;
> + i = register_device(&cfi_dev);
> + if (i)
> + goto out;
> +
> + devfs_add_partition("nor0", BAREBOX_START, BAREBOX_LENGTH,
> + DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "barebox");
> + devfs_add_partition("nor0", NPE_A_START, NPE_A_LENGTH,
> + DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-A");
> + devfs_add_partition("nor0", NPE_B_START, NPE_B_LENGTH,
> + DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-B");
> + devfs_add_partition("nor0", NPE_C_START, NPE_C_LENGTH,
> + DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-C");
> + devfs_add_partition("nor0", NPE_ENV0_START, NPE_ENV0_LENGTH,
> + DEVFS_PARTITION_FIXED, "env0");
> +
> + hw_bits = __raw_readl(IXP4XX_EXP_BASE(0) + CFG_HW_BITS);
> +
> + if (hw_bits & CFG_HW_HAS_ETH0) {
> + for (i = 0; i < ETH_ALEN; i++)
> + eth_pinfo[0].hwaddr[i] = flash_readb(CFG_ETH0_ADDRESS + i);
> + register_device(ð_dev[0]);
> + }
> +
> + if (hw_bits & CFG_HW_HAS_ETH1) {
> + for (i = 0; i < ETH_ALEN; i++)
> + eth_pinfo[1].hwaddr[i] = flash_readb(CFG_ETH1_ADDRESS + i);
> + register_device(ð_dev[1]);
> + }
> +
> + sdram_dev.size = __raw_readl(IXP4XX_EXP_BASE(0) + CFG_SDRAM_SIZE);
> + i = register_device(&sdram_dev);
> + if (i)
> + goto out;
> +
> + armlinux_add_dram(&sdram_dev);
> + armlinux_set_bootparams((void *)(0x00000100));
> + armlinux_set_architecture(MACH_TYPE_GORAMO_MLR);
> +
> +out:
> + return i;
> +}
> +device_initcall(gml_devices_init);
> diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
> new file mode 100644
> index 0000000..f5e4b41
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/Kconfig
> @@ -0,0 +1,26 @@
> +if ARCH_IXP4XX
> +
> +choice
> + prompt "IXP4xx Board Type"
> +
> +config MACH_MULTILINK
> + bool "Goramo MultiLink"
> + select MACH_HAS_LOWLEVEL_INIT
> +endchoice
> +
> +config BOARDINFO
> + default "Goramo MultiLink" if MACH_MULTILINK
> +
> +config IXP4XX_QMGR
> + tristate "IXP4xx Queue Manager support"
> + help
> + This driver supports IXP4xx built-in hardware queue manager
> + and is required by the Ethernet driver.
> +
> +config IXP4XX_NPE
> + tristate "IXP4xx Network Processor Engine support"
> + help
> + This driver supports IXP4xx built-in network coprocessors
> + and is required by the Ethernet driver.
> +
> +endif
> diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
> new file mode 100644
> index 0000000..aa38991
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/Makefile
> @@ -0,0 +1,3 @@
> +obj-y += lowlevel_init.o generic.o
> +obj-$(CONFIG_IXP4XX_QMGR) += qmgr.o
> +obj-$(CONFIG_IXP4XX_NPE) += npe.o
> diff --git a/arch/arm/mach-ixp4xx/generic.c b/arch/arm/mach-ixp4xx/generic.c
> new file mode 100644
> index 0000000..02394a4
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/generic.c
> @@ -0,0 +1,120 @@
> +#include <common.h>
> +#include <init.h>
> +#include <ns16550.h>
> +#include <asm/armlinux.h>
> +#include <asm/io.h>
> +#include <mach/ixp4xx-regs.h>
> +
> +#define OSTS_FREQUENCY 66666000
> +
> +void reset_cpu(ulong addr)
> +{
> + /* Use on-chip reset capability */
> + /* This may not work on IXP425 rev. A0 */
> +
> + IXP4XX_OSWK = IXP4XX_WDT_KEY;
> + IXP4XX_OSWT = 0; /* request immediate reset */
> + IXP4XX_OSWE = IXP4XX_WDT_RESET_ENABLE | IXP4XX_WDT_COUNT_ENABLE;
> + while (1)
> + ;
> +}
> +
> +#include <clock.h>
> +
> +/**
> + * @brief Provide a simple clock read
> + *
> + * Nothing is simpler.. read direct from clock and provide it
> + * to the caller.
> + *
> + * @return clock counter
> + */
> +static uint64_t ixp4xx_clocksource_read(void)
> +{
> + return IXP4XX_OSTS;
> +}
> +
> +static struct clocksource cs = {
> + .read = ixp4xx_clocksource_read,
> + .mask = 0xffffffff,
> + .shift = 10,
> +};
> +
> +/**
> + * @brief Initialize the Clock
> + *
> + * We use the Time-Stamp Timer
> + *
> + * @return result of @ref init_clock
> + */
> +static int ixp4xx_clocksource_init(void)
> +{
> + cs.mult = clocksource_hz2mult(OSTS_FREQUENCY, cs.shift);
> +
> + return init_clock(&cs);
> +}
> +
> +/* Run me at boot time */
> +core_initcall(ixp4xx_clocksource_init);
> +
> +
> +#ifdef CONFIG_DRIVER_SERIAL_NS16550
> +
> +/**
> + * @brief UART port register read function for IXP4XX
> + *
> + * @param base base address of UART
> + * @param reg_idx register index
> + *
> + * @return character read from register
> + */
> +unsigned int ixp4xx_uart_read(unsigned long base, unsigned char reg_idx)
> +{
> + return readb(4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
> +}
> +EXPORT_SYMBOL(ixp4xx_uart_read);
> +
> +/**
> + * @brief UART port register write function for IXP4XX
> + *
> + * @param val value to write
> + * @param base base address of UART
> + * @param reg_idx register index
> + *
> + * @return void
> + */
> +void ixp4xx_uart_write(unsigned int val, unsigned long base, unsigned char reg_idx)
> +{
> + writeb(val, 4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
> +}
> +EXPORT_SYMBOL(ixp4xx_uart_write);
> +
> +
> +static struct NS16550_plat serial_plat = {
> + .clock = 14745600,
> + .f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR,
> + .reg_read = ixp4xx_uart_read,
> + .reg_write = ixp4xx_uart_write,
> +};
> +
> +static struct device_d ixp4xx_serial_device = {
> + .name = "serial_ns16550",
> + .map_base = (u32)IXP4XX_UART1_BASE,
> + .size = 1024,
> + .platform_data = (void *)&serial_plat,
> +};
> +
> +/**
> + * @brief UART serial port initialization
> + *
> + * @return result of device registration
> + */
> +static int ixp4xx_console_init(void)
> +{
> + /* Register the serial port */
> + return register_device(&ixp4xx_serial_device);
> +}
> +
> +console_initcall(ixp4xx_console_init);
> +
> +#endif /* CONFIG_DRIVER_SERIAL_NS16550 */
> diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h
> new file mode 100644
> index 0000000..3de021e
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h
> @@ -0,0 +1,70 @@
> +/*
> + * arch/arm/mach-ixp4xx/include/mach/cpu.h
> + *
> + * IXP4XX cpu type detection
> + *
> + * Copyright (C) 2007 MontaVista Software, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef __ASM_ARCH_CPU_H__
> +#define __ASM_ARCH_CPU_H__
> +
> +#include <linux/types.h>
> +
> +/* Processor id value in CP15 Register 0 */
> +#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */
> +#define IXP42X_PROCESSOR_ID_MASK 0xffffffc0
> +
> +#define IXP43X_PROCESSOR_ID_VALUE 0x69054040
> +#define IXP43X_PROCESSOR_ID_MASK 0xfffffff0
> +
> +#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */
> +#define IXP46X_PROCESSOR_ID_MASK 0xfffffff0
> +
> +#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
> + IXP42X_PROCESSOR_ID_VALUE)
> +#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
> + IXP42X_PROCESSOR_ID_VALUE)
> +#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \
> + IXP43X_PROCESSOR_ID_VALUE)
> +#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \
> + IXP46X_PROCESSOR_ID_VALUE)
> +
> +/*
> + * The CPU ID never changes at run time, so we might as well tell the
> + * compiler that it's constant. Use this function to read the CPU ID
> + * rather than directly reading processor_id or read_cpuid() directly.
> + */
> +static inline u32 __attribute_const__ read_cpuid_id(void)
> +{
> + u32 val;
> + asm("mrc p15, 0, %0, c0, c0, 0" : "=r" (val) : : "cc");
> +
> + return val;
> +}
> +
> +static inline u32 ixp4xx_read_feature_bits(void)
> +{
> + u32 val = ~IXP4XX_EXP_CFG2;
> +
> + if (cpu_is_ixp42x_rev_a0())
> + return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
> + IXP4XX_FEATURE_AES);
> + if (cpu_is_ixp42x())
> + return val & IXP42X_FEATURE_MASK;
> + if (cpu_is_ixp43x())
> + return val & IXP43X_FEATURE_MASK;
> + return val & IXP46X_FEATURE_MASK;
> +}
> +
> +static inline void ixp4xx_write_feature_bits(u32 value)
> +{
> + IXP4XX_EXP_CFG2 = ~value;
> +}
> +
> +#endif /* _ASM_ARCH_CPU_H */
> diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
> new file mode 100644
> index 0000000..da4dc8a
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
> @@ -0,0 +1,365 @@
> +/*
> + * Register definitions for IXP4xx chipset.
> + *
> + * Copyright (C) 2002 Intel Corporation.
> + * Copyright (C) 2003-2004 MontaVista Software, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef _ASM_ARM_IXP4XX_H_
> +#define _ASM_ARM_IXP4XX_H_
> +
> +#ifdef __ASSEMBLER__
> +#define IXP4XX_REG(reg) (reg)
> +#else
> +#define IXP4XX_REG(reg) (*(volatile u32 *)(reg))
> +#define IXP4XX_BASE(reg) ((u32*)(reg))
> +#endif
> +
> +/* Expansion Bus region */
> +
> +/* Queue Manager */
> +#define IXP4XX_QMGR_BASE (0x60000000)
> +#define IXP4XX_QMGR_REGION_SIZE (0x00004000)
> +
> +
> +/* PCI Config registers */
> +#define IXP4XX_PCI_CFG_BASE (0xC0000000)
> +#define IXP4XX_PCI_CFG_REGION_SIZE (0x00001000)
> +
> +/* Peripheral space */
> +#define IXP4XX_PERIPHERAL_BASE (0xC8000000)
> +#define IXP4XX_PERIPHERAL_REGION_SIZE (0x00013000)
> +
> +/*
> + * Debug UART
> + *
> + * This is basically a remap of UART1 into a region that is section
> + * aligned so that it can be used with the low-level debug code.
> + */
> +#define IXP4XX_DEBUG_UART_BASE (0xC8000000)
> +#define IXP4XX_DEBUG_UART_REGION_SIZE (0x00001000)
> +
> +/* Expansion Bus Controller registers. */
> +#define IXP4XX_EXP_CS0 IXP4XX_REG(0xC4000000)
> +#define IXP4XX_EXP_CS1 IXP4XX_REG(0xC4000004)
> +#define IXP4XX_EXP_CS2 IXP4XX_REG(0xC4000008)
> +#define IXP4XX_EXP_CS3 IXP4XX_REG(0xC400000C)
> +#define IXP4XX_EXP_CS4 IXP4XX_REG(0xC4000010)
> +#define IXP4XX_EXP_CS5 IXP4XX_REG(0xC4000014)
> +#define IXP4XX_EXP_CS6 IXP4XX_REG(0xC4000018)
> +#define IXP4XX_EXP_CS7 IXP4XX_REG(0xC400001C)
> +
> +#define IXP4XX_EXP_BASE(n) (0x50000000 + (n) * 1000000)
> +
> +#define IXP4XX_EXP_EN 0x80000000
> +#define IXP4XX_EXP_T1(n) (0x10000000 * (n)) /* valid: 0 - 3 */
> +#define IXP4XX_EXP_T2(n) (0x04000000 * (n)) /* valid: 0 - 3 */
> +#define IXP4XX_EXP_T3(n) (0x00400000 * (n)) /* valid: 0 - 15 */
> +#define IXP4XX_EXP_T4(n) (0x00100000 * (n)) /* valid: 0 - 3 */
> +#define IXP4XX_EXP_T5(n) (0x00010000 * (n)) /* valid: 0 - 15 */
> +#define IXP4XX_EXP_INTEL 0x00000000
> +#define IXP4XX_EXP_MOTO 0x00004000
> +#define IXP4XX_EXP_HPI 0x00008000
> +#define IXP4XX_EXP_BITS(n) (0x00000400 * ((n) - 9)) /* valid: 9 - 24 */
> +#define IXP4XX_EXP_BYTE_RD16 0x00000040
> +#define IXP4XX_EXP_HRDY_POL 0x00000020
> +#define IXP4XX_EXP_MUX_EN 0x00000010
> +#define IXP4XX_EXP_SPLT_EN 0x00000008
> +#define IXP4XX_EXP_WR_EN 0x00000002
> +#define IXP4XX_EXP_BYTE_EN 0x00000001
> +
> +#define IXP4XX_EXP_CFG0 IXP4XX_REG(0xC4000020)
> +#define IXP4XX_EXP_CFG1 IXP4XX_REG(0xC4000024)
> +#define IXP4XX_EXP_CFG2 IXP4XX_REG(0xC4000028)
> +#define IXP4XX_EXP_CFG3 IXP4XX_REG(0xC400002C)
> +
> +
> +/* Peripheral Space Register Region Base Addresses */
> +#define IXP4XX_UART1_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x0000)
> +#define IXP4XX_UART2_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x1000)
> +#define IXP4XX_PMU_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x2000)
> +#define IXP4XX_INTC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x3000)
> +#define IXP4XX_GPIO_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x4000)
> +#define IXP4XX_NPEA_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x6000)
> +#define IXP4XX_NPEB_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x7000)
> +#define IXP4XX_NPEC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x8000)
> +#define IXP4XX_EthB_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x9000)
> +#define IXP4XX_EthC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xA000)
> +#define IXP4XX_USB_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xB000)
> +/* IXP46x only */
> +#define IXP4XX_EthA_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xC000)
> +#define IXP4XX_EthB1_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xD000)
> +#define IXP4XX_EthB2_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xE000)
> +#define IXP4XX_EthB3_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xF000)
> +#define IXP4XX_TIMESYNC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x10000)
> +#define IXP4XX_I2C_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x11000)
> +#define IXP4XX_SSP_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x12000)
> +
> +/*
> + Constants to make it easy to access Interrupt Controller registers
> + */
> +#define IXP4XX_ICPR_OFFSET 0x00 /* Interrupt Status */
> +#define IXP4XX_ICMR_OFFSET 0x04 /* Interrupt Enable */
> +#define IXP4XX_ICLR_OFFSET 0x08 /* Interrupt IRQ/FIQ Select */
> +#define IXP4XX_ICIP_OFFSET 0x0C /* IRQ Status */
> +#define IXP4XX_ICFP_OFFSET 0x10 /* FIQ Status */
> +#define IXP4XX_ICHR_OFFSET 0x14 /* Interrupt Priority */
> +#define IXP4XX_ICIH_OFFSET 0x18 /* IRQ Highest Pri Int */
> +#define IXP4XX_ICFH_OFFSET 0x1C /* FIQ Highest Pri Int */
> +
> +/* IXP465-only */
> +#define IXP4XX_ICPR2_OFFSET 0x20 /* Interrupt Status 2 */
> +#define IXP4XX_ICMR2_OFFSET 0x24 /* Interrupt Enable 2 */
> +#define IXP4XX_ICLR2_OFFSET 0x28 /* Interrupt IRQ/FIQ Select 2 */
> +#define IXP4XX_ICIP2_OFFSET 0x2C /* IRQ Status */
> +#define IXP4XX_ICFP2_OFFSET 0x30 /* FIQ Status */
> +#define IXP4XX_ICEEN_OFFSET 0x34 /* Error High Pri Enable */
> +
> +
> +/* Interrupt Controller Register Definitions. */
> +#define IXP4XX_INTC_REG(x) ((volatile u32 *)(IXP4XX_INTC_BASE + (x)))
> +
> +#define IXP4XX_ICPR IXP4XX_INTC_REG(IXP4XX_ICPR_OFFSET)
> +#define IXP4XX_ICMR IXP4XX_INTC_REG(IXP4XX_ICMR_OFFSET)
> +#define IXP4XX_ICLR IXP4XX_INTC_REG(IXP4XX_ICLR_OFFSET)
> +#define IXP4XX_ICIP IXP4XX_INTC_REG(IXP4XX_ICIP_OFFSET)
> +#define IXP4XX_ICFP IXP4XX_INTC_REG(IXP4XX_ICFP_OFFSET)
> +#define IXP4XX_ICHR IXP4XX_INTC_REG(IXP4XX_ICHR_OFFSET)
> +#define IXP4XX_ICIH IXP4XX_INTC_REG(IXP4XX_ICIH_OFFSET)
> +#define IXP4XX_ICFH IXP4XX_INTC_REG(IXP4XX_ICFH_OFFSET)
> +#define IXP4XX_ICPR2 IXP4XX_INTC_REG(IXP4XX_ICPR2_OFFSET)
> +#define IXP4XX_ICMR2 IXP4XX_INTC_REG(IXP4XX_ICMR2_OFFSET)
> +#define IXP4XX_ICLR2 IXP4XX_INTC_REG(IXP4XX_ICLR2_OFFSET)
> +#define IXP4XX_ICIP2 IXP4XX_INTC_REG(IXP4XX_ICIP2_OFFSET)
> +#define IXP4XX_ICFP2 IXP4XX_INTC_REG(IXP4XX_ICFP2_OFFSET)
> +#define IXP4XX_ICEEN IXP4XX_INTC_REG(IXP4XX_ICEEN_OFFSET)
> +
> +/* Constants to make it easy to access GPIO registers */
> +#define IXP4XX_GPIO_GPOUTR_OFFSET 0x00
> +#define IXP4XX_GPIO_GPOER_OFFSET 0x04
> +#define IXP4XX_GPIO_GPINR_OFFSET 0x08
> +#define IXP4XX_GPIO_GPISR_OFFSET 0x0C
> +#define IXP4XX_GPIO_GPIT1R_OFFSET 0x10
> +#define IXP4XX_GPIO_GPIT2R_OFFSET 0x14
> +#define IXP4XX_GPIO_GPCLKR_OFFSET 0x18
> +#define IXP4XX_GPIO_GPDBSELR_OFFSET 0x1C
> +
> +/* GPIO Register Definitions - perform only 32-bit reads/writes */
> +#define IXP4XX_GPIO_REG(x) ((volatile u32 *)(IXP4XX_GPIO_BASE + (x)))
> +
> +#define IXP4XX_GPIO_GPOUTR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOUTR_OFFSET)
> +#define IXP4XX_GPIO_GPOER IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOER_OFFSET)
> +#define IXP4XX_GPIO_GPINR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPINR_OFFSET)
> +#define IXP4XX_GPIO_GPISR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPISR_OFFSET)
> +#define IXP4XX_GPIO_GPIT1R IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT1R_OFFSET)
> +#define IXP4XX_GPIO_GPIT2R IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT2R_OFFSET)
> +#define IXP4XX_GPIO_GPCLKR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPCLKR_OFFSET)
> +#define IXP4XX_GPIO_GPDBSELR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPDBSELR_OFFSET)
> +
> +/* GPIO register bit definitions */
> +
> +/* Interrupt styles */
> +#define IXP4XX_GPIO_STYLE_ACTIVE_HIGH 0x0
> +#define IXP4XX_GPIO_STYLE_ACTIVE_LOW 0x1
> +#define IXP4XX_GPIO_STYLE_RISING_EDGE 0x2
> +#define IXP4XX_GPIO_STYLE_FALLING_EDGE 0x3
> +#define IXP4XX_GPIO_STYLE_TRANSITIONAL 0x4
> +
> +/* Mask used to clear interrupt styles */
> +#define IXP4XX_GPIO_STYLE_CLEAR 0x7
> +#define IXP4XX_GPIO_STYLE_SIZE 3
> +
> +/* Operating System Timer Register Definitions. */
> +#define IXP4XX_OSTS IXP4XX_REG(0xC8005000) /* Continious TimeStamp */
> +#define IXP4XX_OST1 IXP4XX_REG(0xC8005004) /* Timer 1 Timestamp */
> +#define IXP4XX_OSRT1 IXP4XX_REG(0xC8005008) /* Timer 1 Reload */
> +#define IXP4XX_OST2 IXP4XX_REG(0xC800500C) /* Timer 2 Timestamp */
> +#define IXP4XX_OSRT2 IXP4XX_REG(0xC8005010) /* Timer 2 Reload */
> +#define IXP4XX_OSWT IXP4XX_REG(0xC8005014) /* Watchdog Timer */
> +#define IXP4XX_OSWE IXP4XX_REG(0xC8005018) /* Watchdog Enable */
> +#define IXP4XX_OSWK IXP4XX_REG(0xC800501C) /* Watchdog Key */
> +#define IXP4XX_OSST IXP4XX_REG(0xC8005020) /* Timer Status */
> +
> +/* Timer register values and bit definitions */
> +#define IXP4XX_OST_ENABLE 0x00000001
> +#define IXP4XX_OST_ONE_SHOT 0x00000002
> +/* Low order bits of reload value ignored */
> +#define IXP4XX_OST_RELOAD_MASK 0x00000003
> +#define IXP4XX_OST_DISABLED 0x00000000
> +#define IXP4XX_OSST_TIMER_1_PEND 0x00000001
> +#define IXP4XX_OSST_TIMER_2_PEND 0x00000002
> +#define IXP4XX_OSST_TIMER_TS_PEND 0x00000004
> +#define IXP4XX_OSST_TIMER_WDOG_PEND 0x00000008
> +#define IXP4XX_OSST_TIMER_WARM_RESET 0x00000010
> +
> +#define IXP4XX_WDT_KEY 0x0000482E
> +
> +#define IXP4XX_WDT_RESET_ENABLE 0x00000001
> +#define IXP4XX_WDT_IRQ_ENABLE 0x00000002
> +#define IXP4XX_WDT_COUNT_ENABLE 0x00000004
> +
> +
> +/* Constants to make it easy to access PCI Control/Status registers */
> +#define PCI_NP_AD_OFFSET 0x00
> +#define PCI_NP_CBE_OFFSET 0x04
> +#define PCI_NP_WDATA_OFFSET 0x08
> +#define PCI_NP_RDATA_OFFSET 0x0c
> +#define PCI_CRP_AD_CBE_OFFSET 0x10
> +#define PCI_CRP_WDATA_OFFSET 0x14
> +#define PCI_CRP_RDATA_OFFSET 0x18
> +#define PCI_CSR_OFFSET 0x1c
> +#define PCI_ISR_OFFSET 0x20
> +#define PCI_INTEN_OFFSET 0x24
> +#define PCI_DMACTRL_OFFSET 0x28
> +#define PCI_AHBMEMBASE_OFFSET 0x2c
> +#define PCI_AHBIOBASE_OFFSET 0x30
> +#define PCI_PCIMEMBASE_OFFSET 0x34
> +#define PCI_AHBDOORBELL_OFFSET 0x38
> +#define PCI_PCIDOORBELL_OFFSET 0x3C
> +#define PCI_ATPDMA0_AHBADDR_OFFSET 0x40
> +#define PCI_ATPDMA0_PCIADDR_OFFSET 0x44
> +#define PCI_ATPDMA0_LENADDR_OFFSET 0x48
> +#define PCI_ATPDMA1_AHBADDR_OFFSET 0x4C
> +#define PCI_ATPDMA1_PCIADDR_OFFSET 0x50
> +#define PCI_ATPDMA1_LENADDR_OFFSET 0x54
> +
> +/* PCI Control/Status Registers */
> +#define IXP4XX_PCI_CSR(x) ((volatile u32 *)(IXP4XX_PCI_CFG_BASE + (x)))
> +
> +#define PCI_NP_AD IXP4XX_PCI_CSR(PCI_NP_AD_OFFSET)
> +#define PCI_NP_CBE IXP4XX_PCI_CSR(PCI_NP_CBE_OFFSET)
> +#define PCI_NP_WDATA IXP4XX_PCI_CSR(PCI_NP_WDATA_OFFSET)
> +#define PCI_NP_RDATA IXP4XX_PCI_CSR(PCI_NP_RDATA_OFFSET)
> +#define PCI_CRP_AD_CBE IXP4XX_PCI_CSR(PCI_CRP_AD_CBE_OFFSET)
> +#define PCI_CRP_WDATA IXP4XX_PCI_CSR(PCI_CRP_WDATA_OFFSET)
> +#define PCI_CRP_RDATA IXP4XX_PCI_CSR(PCI_CRP_RDATA_OFFSET)
> +#define PCI_CSR IXP4XX_PCI_CSR(PCI_CSR_OFFSET)
> +#define PCI_ISR IXP4XX_PCI_CSR(PCI_ISR_OFFSET)
> +#define PCI_INTEN IXP4XX_PCI_CSR(PCI_INTEN_OFFSET)
> +#define PCI_DMACTRL IXP4XX_PCI_CSR(PCI_DMACTRL_OFFSET)
> +#define PCI_AHBMEMBASE IXP4XX_PCI_CSR(PCI_AHBMEMBASE_OFFSET)
> +#define PCI_AHBIOBASE IXP4XX_PCI_CSR(PCI_AHBIOBASE_OFFSET)
> +#define PCI_PCIMEMBASE IXP4XX_PCI_CSR(PCI_PCIMEMBASE_OFFSET)
> +#define PCI_AHBDOORBELL IXP4XX_PCI_CSR(PCI_AHBDOORBELL_OFFSET)
> +#define PCI_PCIDOORBELL IXP4XX_PCI_CSR(PCI_PCIDOORBELL_OFFSET)
> +#define PCI_ATPDMA0_AHBADDR IXP4XX_PCI_CSR(PCI_ATPDMA0_AHBADDR_OFFSET)
> +#define PCI_ATPDMA0_PCIADDR IXP4XX_PCI_CSR(PCI_ATPDMA0_PCIADDR_OFFSET)
> +#define PCI_ATPDMA0_LENADDR IXP4XX_PCI_CSR(PCI_ATPDMA0_LENADDR_OFFSET)
> +#define PCI_ATPDMA1_AHBADDR IXP4XX_PCI_CSR(PCI_ATPDMA1_AHBADDR_OFFSET)
> +#define PCI_ATPDMA1_PCIADDR IXP4XX_PCI_CSR(PCI_ATPDMA1_PCIADDR_OFFSET)
> +#define PCI_ATPDMA1_LENADDR IXP4XX_PCI_CSR(PCI_ATPDMA1_LENADDR_OFFSET)
> +
> +/* PCI register values and bit definitions */
> +
> +/* CSR bit definitions */
> +#define PCI_CSR_HOST 0x00000001
> +#define PCI_CSR_ARBEN 0x00000002
> +#define PCI_CSR_ADS 0x00000004
> +#define PCI_CSR_PDS 0x00000008
> +#define PCI_CSR_ABE 0x00000010
> +#define PCI_CSR_DBT 0x00000020
> +#define PCI_CSR_ASE 0x00000100
> +#define PCI_CSR_IC 0x00008000
> +
> +/* ISR (Interrupt status) Register bit definitions */
> +#define PCI_ISR_PSE 0x00000001
> +#define PCI_ISR_PFE 0x00000002
> +#define PCI_ISR_PPE 0x00000004
> +#define PCI_ISR_AHBE 0x00000008
> +#define PCI_ISR_APDC 0x00000010
> +#define PCI_ISR_PADC 0x00000020
> +#define PCI_ISR_ADB 0x00000040
> +#define PCI_ISR_PDB 0x00000080
> +
> +/* INTEN (Interrupt Enable) Register bit definitions */
> +#define PCI_INTEN_PSE 0x00000001
> +#define PCI_INTEN_PFE 0x00000002
> +#define PCI_INTEN_PPE 0x00000004
> +#define PCI_INTEN_AHBE 0x00000008
> +#define PCI_INTEN_APDC 0x00000010
> +#define PCI_INTEN_PADC 0x00000020
> +#define PCI_INTEN_ADB 0x00000040
> +#define PCI_INTEN_PDB 0x00000080
> +
> +/* Shift value for byte enable on NP cmd/byte enable register */
> +#define IXP4XX_PCI_NP_CBE_BESL 4
> +
> +/* PCI commands supported by NP access unit */
> +#define NP_CMD_IOREAD 0x2
> +#define NP_CMD_IOWRITE 0x3
> +#define NP_CMD_CONFIGREAD 0xA
> +#define NP_CMD_CONFIGWRITE 0xB
> +#define NP_CMD_MEMREAD 0x6
> +#define NP_CMD_MEMWRITE 0x7
> +
> +/* Constants for CRP access into local config space */
> +#define CRP_AD_CBE_BESL 20
> +#define CRP_AD_CBE_WRITE 0x00010000
> +
> +/* USB Device Controller */
> +# define IXP4XX_USB_REG(x) (*((volatile u32 *)(x)))
> +
> +/* SDRAM Controller registers. */
> +#define IXP4XX_SDRAM_CONFIG IXP4XX_REG(0xCC000000)
> +#define IXP4XX_SDRAM_REFRESH IXP4XX_REG(0xCC000004)
> +#define IXP4XX_SDRAM_IR IXP4XX_REG(0xCC000008)
> +
> +/* "fuse" bits of IXP_EXP_CFG2 */
> +/* All IXP4xx CPUs */
> +#define IXP4XX_FEATURE_RCOMP (1 << 0)
> +#define IXP4XX_FEATURE_USB_DEVICE (1 << 1)
> +#define IXP4XX_FEATURE_HASH (1 << 2)
> +#define IXP4XX_FEATURE_AES (1 << 3)
> +#define IXP4XX_FEATURE_DES (1 << 4)
> +#define IXP4XX_FEATURE_HDLC (1 << 5)
> +#define IXP4XX_FEATURE_AAL (1 << 6)
> +#define IXP4XX_FEATURE_HSS (1 << 7)
> +#define IXP4XX_FEATURE_UTOPIA (1 << 8)
> +#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9)
> +#define IXP4XX_FEATURE_NPEC_ETH (1 << 10)
> +#define IXP4XX_FEATURE_RESET_NPEA (1 << 11)
> +#define IXP4XX_FEATURE_RESET_NPEB (1 << 12)
> +#define IXP4XX_FEATURE_RESET_NPEC (1 << 13)
> +#define IXP4XX_FEATURE_PCI (1 << 14)
> +#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16)
> +#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22)
> +#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP | \
> + IXP4XX_FEATURE_USB_DEVICE | \
> + IXP4XX_FEATURE_HASH | \
> + IXP4XX_FEATURE_AES | \
> + IXP4XX_FEATURE_DES | \
> + IXP4XX_FEATURE_HDLC | \
> + IXP4XX_FEATURE_AAL | \
> + IXP4XX_FEATURE_HSS | \
> + IXP4XX_FEATURE_UTOPIA | \
> + IXP4XX_FEATURE_NPEB_ETH0 | \
> + IXP4XX_FEATURE_NPEC_ETH | \
> + IXP4XX_FEATURE_RESET_NPEA | \
> + IXP4XX_FEATURE_RESET_NPEB | \
> + IXP4XX_FEATURE_RESET_NPEC | \
> + IXP4XX_FEATURE_PCI | \
> + IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \
> + IXP4XX_FEATURE_XSCALE_MAX_FREQ)
> +
> +/* IXP43x/46x CPUs */
> +#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15)
> +#define IXP4XX_FEATURE_USB_HOST (1 << 18)
> +#define IXP4XX_FEATURE_NPEA_ETH (1 << 19)
> +#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK | \
> + IXP4XX_FEATURE_ECC_TIMESYNC | \
> + IXP4XX_FEATURE_USB_HOST | \
> + IXP4XX_FEATURE_NPEA_ETH)
> +
> +/* IXP46x CPU (including IXP455) only */
> +#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20)
> +#define IXP4XX_FEATURE_RSA (1 << 21)
> +#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK | \
> + IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \
> + IXP4XX_FEATURE_RSA)
> +
> +#endif
> diff --git a/arch/arm/mach-ixp4xx/include/mach/npe.h b/arch/arm/mach-ixp4xx/include/mach/npe.h
> new file mode 100644
> index 0000000..18bd01b
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/npe.h
> @@ -0,0 +1,30 @@
> +#ifndef __IXP4XX_NPE_H
> +#define __IXP4XX_NPE_H
> +
> +#include <common.h>
> +
> +#define NPE_NAME_LENGTH 5
> +
> +struct npe_regs {
> + u32 exec_addr, exec_data, exec_status_cmd, exec_count;
> + u32 action_points[4];
> + u32 watchpoint_fifo, watch_count;
> + u32 profile_count;
> + u32 messaging_status, messaging_control;
> + u32 mailbox_status, /*messaging_*/ in_out_fifo;
> +};
> +
> +struct npe {
> + struct npe_regs *regs;
> + int id, valid;
> + const char name[NPE_NAME_LENGTH + 1];
> +};
> +
> +int npe_running(struct npe *npe);
> +int npe_send_message(struct npe *npe, const void *msg, const char *what);
> +int npe_recv_message(struct npe *npe, void *msg, const char *what);
> +int npe_send_recv_message(struct npe *npe, void *msg, const char *what);
> +int npe_load_firmware(struct npe *npe);
> +struct npe *npe_request(int id);
> +
> +#endif /* __IXP4XX_NPE_H */
> diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h
> new file mode 100644
> index 0000000..1df4aa4
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
> @@ -0,0 +1,15 @@
> +#include <asm/types.h>
> +
> +#define IXP4XX_ETH_NPEA 0x00
> +#define IXP4XX_ETH_NPEB 0x10
> +#define IXP4XX_ETH_NPEC 0x20
> +
> +/* Information about built-in Ethernet MAC interfaces */
> +struct eth_plat_info {
> + void *regs;
> + u8 npe;
> + u8 phy; /* MII PHY ID, 0 - 31 */
> + u8 rxq; /* configurable, currently 0 - 31 only */
> + u8 txreadyq;
> + u8 hwaddr[6];
> +};
> diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
> new file mode 100644
> index 0000000..4e9b8d4
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
> @@ -0,0 +1,164 @@
> +/*
> + * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License
> + * as published by the Free Software Foundation.
> + */
> +
> +#ifndef IXP4XX_QMGR_H
> +#define IXP4XX_QMGR_H
> +
> +#include <common.h>
> +#include <mach/ixp4xx-regs.h>
> +#include <asm/io.h>
> +
> +#define DEBUG_QMGR 0
> +
> +#define HALF_QUEUES 32
> +#define QUEUES 64
> +#define MAX_QUEUE_LENGTH 4 /* in dwords */
> +
> +#define QUEUE_STAT1_EMPTY 1 /* queue status bits */
> +#define QUEUE_STAT1_NEARLY_EMPTY 2
> +#define QUEUE_STAT1_NEARLY_FULL 4
> +#define QUEUE_STAT1_FULL 8
> +#define QUEUE_STAT2_UNDERFLOW 1
> +#define QUEUE_STAT2_OVERFLOW 2
> +
> +#define QUEUE_WATERMARK_0_ENTRIES 0
> +#define QUEUE_WATERMARK_1_ENTRY 1
> +#define QUEUE_WATERMARK_2_ENTRIES 2
> +#define QUEUE_WATERMARK_4_ENTRIES 3
> +#define QUEUE_WATERMARK_8_ENTRIES 4
> +#define QUEUE_WATERMARK_16_ENTRIES 5
> +#define QUEUE_WATERMARK_32_ENTRIES 6
> +#define QUEUE_WATERMARK_64_ENTRIES 7
> +
> +/* queue interrupt request conditions */
> +#define QUEUE_IRQ_SRC_EMPTY 0
> +#define QUEUE_IRQ_SRC_NEARLY_EMPTY 1
> +#define QUEUE_IRQ_SRC_NEARLY_FULL 2
> +#define QUEUE_IRQ_SRC_FULL 3
> +#define QUEUE_IRQ_SRC_NOT_EMPTY 4
> +#define QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY 5
> +#define QUEUE_IRQ_SRC_NOT_NEARLY_FULL 6
> +#define QUEUE_IRQ_SRC_NOT_FULL 7
> +
> +struct qmgr_regs {
> + u32 acc[QUEUES][MAX_QUEUE_LENGTH]; /* 0x000 - 0x3FF */
> + u32 stat1[4]; /* 0x400 - 0x40F */
> + u32 stat2[2]; /* 0x410 - 0x417 */
> + u32 statne_h; /* 0x418 - queue nearly empty */
> + u32 statf_h; /* 0x41C - queue full */
> + u32 irqsrc[4]; /* 0x420 - 0x42F IRC source */
> + u32 irqen[2]; /* 0x430 - 0x437 IRQ enabled */
> + u32 irqstat[2]; /* 0x438 - 0x43F - IRQ access only */
> + u32 reserved[1776];
> + u32 sram[2048]; /* 0x2000 - 0x3FFF - config and buffer */
> +};
> +
> +static const struct qmgr_regs *qmgr_regs = (struct qmgr_regs *)IXP4XX_QMGR_BASE;
> +
> +void qmgr_set_irq(unsigned int queue, int src,
> + void (*handler)(void *pdev), void *pdev);
> +void qmgr_enable_irq(unsigned int queue);
> +void qmgr_disable_irq(unsigned int queue);
> +
> +/* request_ and release_queue() must be called from non-IRQ context */
> +
> +#if DEBUG_QMGR
> +extern char qmgr_queue_descs[HALF_QUEUES][32];
> +
> +void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
> + unsigned int nearly_empty_watermark,
> + unsigned int nearly_full_watermark,
> + const char *desc_format, const char* name);
> +#else
> +void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
> + unsigned int nearly_empty_watermark,
> + unsigned int nearly_full_watermark);
> +#define qmgr_request_queue(queue, len, nearly_empty_watermark, \
> + nearly_full_watermark, desc_format, name) \
> + __qmgr_request_queue(queue, len, nearly_empty_watermark, \
> + nearly_full_watermark)
> +#endif
> +
> +void qmgr_release_queue(unsigned int queue);
> +
> +
> +static inline void qmgr_put_entry(unsigned int queue, u32 val)
> +{
> +#if DEBUG_QMGR
> + BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
> +
> + fprintf(stderr, "Queue %s(%i) put %X\n",
> + qmgr_queue_descs[queue], queue, val);
> +#endif
> + __raw_writel(val, &qmgr_regs->acc[queue][0]);
> +}
> +
> +static inline u32 qmgr_get_entry(unsigned int queue)
> +{
> + u32 val;
> + val = __raw_readl(&qmgr_regs->acc[queue][0]);
> +#if DEBUG_QMGR
> + BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
> +
> + fprintf(stderr, "Queue %s(%i) get %X\n",
> + qmgr_queue_descs[queue], queue, val);
> +#endif
> + return val;
> +}
> +
> +static inline int __qmgr_get_stat1(unsigned int queue)
> +{
> + return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
> + >> ((queue & 7) << 2)) & 0xF;
> +}
> +
> +/**
> + * qmgr_stat_empty() - checks if a hardware queue is empty
> + * @queue: queue number
> + *
> + * Returns non-zero value if the queue is empty.
> + */
> +static inline int qmgr_stat_empty(unsigned int queue)
> +{
> + return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY;
> +}
> +
> +/**
> + * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark
> + * @queue: queue number
> + *
> + * Returns non-zero value if the queue is below low watermark.
> + */
> +static inline int qmgr_stat_below_low_watermark(unsigned int queue)
> +{
> + return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY;
> +}
> +
> +/**
> + * qmgr_stat_above_high_watermark() - checks if a queue is above high watermark
> + * @queue: queue number
> + *
> + * Returns non-zero value if the queue is above high watermark
> + */
> +static inline int qmgr_stat_above_high_watermark(unsigned int queue)
> +{
> + return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL;
> +}
> +
> +/**
> + * qmgr_stat_full() - checks if a hardware queue is full
> + * @queue: queue number
> + *
> + * Returns non-zero value if the queue is full.
> + */
> +static inline int qmgr_stat_full(unsigned int queue)
> +{
> + return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL;
> +}
> +
> +#endif
> diff --git a/arch/arm/mach-ixp4xx/lowlevel_init.S b/arch/arm/mach-ixp4xx/lowlevel_init.S
> new file mode 100644
> index 0000000..a4e93ef
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/lowlevel_init.S
> @@ -0,0 +1,17 @@
> +#include <mach/ixp4xx-regs.h>
> +
> + .section ".text_bare_init", "ax"
> +
> + .globl arch_init_lowlevel
> +arch_init_lowlevel:
> + ldr r0, cfg
> + ldr r1, [r0]
> + and r1, r1, #~0x80000000 /* unmap EXP bus from 0x0 */
> + str r1, [r0]
> +
> + /* return to ROM */
> + orr lr, #0x50000000
> + mov pc, lr
> +
> +cfg:
> + .word IXP4XX_EXP_CFG0
> diff --git a/arch/arm/mach-ixp4xx/npe.c b/arch/arm/mach-ixp4xx/npe.c
> new file mode 100644
> index 0000000..a8ddd5a
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/npe.c
> @@ -0,0 +1,668 @@
> +/*
> + * Intel IXP4xx Network Processor Engine driver for Linux
> + *
> + * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License
> + * as published by the Free Software Foundation.
> + */
> +
> +#include <common.h>
> +#include <errno.h>
> +#include <fs.h>
> +#include <init.h>
> +#include <malloc.h>
> +#include <asm/byteorder.h>
> +#include <asm/io.h>
> +#include <mach/ixp4xx-regs.h>
> +#include <mach/cpu.h>
> +#include <mach/npe.h>
> +
> +#define DEBUG_MSG 0
> +#define DEBUG_FW 0
> +
> +#define NPE_COUNT 3
> +#define MAX_RETRIES 1000 /* microseconds */
> +#define NPE_42X_DATA_SIZE 0x800 /* in dwords */
> +#define NPE_46X_DATA_SIZE 0x1000
> +#define NPE_A_42X_INSTR_SIZE 0x1000
> +#define NPE_B_AND_C_42X_INSTR_SIZE 0x800
> +#define NPE_46X_INSTR_SIZE 0x1000
> +#define REGS_SIZE 0x1000
> +
> +#define NPE_PHYS_REG 32
> +
> +#define FW_MAGIC 0xFEEDF00D
> +#define FW_BLOCK_TYPE_INSTR 0x0
> +#define FW_BLOCK_TYPE_DATA 0x1
> +#define FW_BLOCK_TYPE_EOF 0xF
> +
> +/* NPE exec status (read) and command (write) */
> +#define CMD_NPE_STEP 0x01
> +#define CMD_NPE_START 0x02
> +#define CMD_NPE_STOP 0x03
> +#define CMD_NPE_CLR_PIPE 0x04
> +#define CMD_CLR_PROFILE_CNT 0x0C
> +#define CMD_RD_INS_MEM 0x10 /* instruction memory */
> +#define CMD_WR_INS_MEM 0x11
> +#define CMD_RD_DATA_MEM 0x12 /* data memory */
> +#define CMD_WR_DATA_MEM 0x13
> +#define CMD_RD_ECS_REG 0x14 /* exec access register */
> +#define CMD_WR_ECS_REG 0x15
> +
> +#define STAT_RUN 0x80000000
> +#define STAT_STOP 0x40000000
> +#define STAT_CLEAR 0x20000000
> +#define STAT_ECS_K 0x00800000 /* pipeline clean */
> +
> +#define NPE_STEVT 0x1B
> +#define NPE_STARTPC 0x1C
> +#define NPE_REGMAP 0x1E
> +#define NPE_CINDEX 0x1F
> +
> +#define INSTR_WR_REG_SHORT 0x0000C000
> +#define INSTR_WR_REG_BYTE 0x00004000
> +#define INSTR_RD_FIFO 0x0F888220
> +#define INSTR_RESET_MBOX 0x0FAC8210
> +
> +#define ECS_BG_CTXT_REG_0 0x00 /* Background Executing Context */
> +#define ECS_BG_CTXT_REG_1 0x01 /* Stack level */
> +#define ECS_BG_CTXT_REG_2 0x02
> +#define ECS_PRI_1_CTXT_REG_0 0x04 /* Priority 1 Executing Context */
> +#define ECS_PRI_1_CTXT_REG_1 0x05 /* Stack level */
> +#define ECS_PRI_1_CTXT_REG_2 0x06
> +#define ECS_PRI_2_CTXT_REG_0 0x08 /* Priority 2 Executing Context */
> +#define ECS_PRI_2_CTXT_REG_1 0x09 /* Stack level */
> +#define ECS_PRI_2_CTXT_REG_2 0x0A
> +#define ECS_DBG_CTXT_REG_0 0x0C /* Debug Executing Context */
> +#define ECS_DBG_CTXT_REG_1 0x0D /* Stack level */
> +#define ECS_DBG_CTXT_REG_2 0x0E
> +#define ECS_INSTRUCT_REG 0x11 /* NPE Instruction Register */
> +
> +#define ECS_REG_0_ACTIVE 0x80000000 /* all levels */
> +#define ECS_REG_0_NEXTPC_MASK 0x1FFF0000 /* BG/PRI1/PRI2 levels */
> +#define ECS_REG_0_LDUR_BITS 8
> +#define ECS_REG_0_LDUR_MASK 0x00000700 /* all levels */
> +#define ECS_REG_1_CCTXT_BITS 16
> +#define ECS_REG_1_CCTXT_MASK 0x000F0000 /* all levels */
> +#define ECS_REG_1_SELCTXT_BITS 0
> +#define ECS_REG_1_SELCTXT_MASK 0x0000000F /* all levels */
> +#define ECS_DBG_REG_2_IF 0x00100000 /* debug level */
> +#define ECS_DBG_REG_2_IE 0x00080000 /* debug level */
> +
> +/* NPE watchpoint_fifo register bit */
> +#define WFIFO_VALID 0x80000000
> +
> +/* NPE messaging_status register bit definitions */
> +#define MSGSTAT_OFNE 0x00010000 /* OutFifoNotEmpty */
> +#define MSGSTAT_IFNF 0x00020000 /* InFifoNotFull */
> +#define MSGSTAT_OFNF 0x00040000 /* OutFifoNotFull */
> +#define MSGSTAT_IFNE 0x00080000 /* InFifoNotEmpty */
> +#define MSGSTAT_MBINT 0x00100000 /* Mailbox interrupt */
> +#define MSGSTAT_IFINT 0x00200000 /* InFifo interrupt */
> +#define MSGSTAT_OFINT 0x00400000 /* OutFifo interrupt */
> +#define MSGSTAT_WFINT 0x00800000 /* WatchFifo interrupt */
> +
> +/* NPE messaging_control register bit definitions */
> +#define MSGCTL_OUT_FIFO 0x00010000 /* enable output FIFO */
> +#define MSGCTL_IN_FIFO 0x00020000 /* enable input FIFO */
> +#define MSGCTL_OUT_FIFO_WRITE 0x01000000 /* enable FIFO + WRITE */
> +#define MSGCTL_IN_FIFO_WRITE 0x02000000
> +
> +/* NPE mailbox_status value for reset */
> +#define RESET_MBOX_STAT 0x0000F0F0
> +
> +#define print_npe(npe, fmt, ...) fprintf(stderr, "%s: " fmt, npe->name, ## __VA_ARGS__)
> +
> +#if DEBUG_MSG
> +#define debug_msg(npe, fmt, ...) print_npe(npe, fmt, ## __VA_ARGS__)
> +#else
> +#define debug_msg(npe, fmt, ...)
> +#endif
> +
> +static struct {
> + u32 reg, val;
> +} ecs_reset[] = {
> + {ECS_BG_CTXT_REG_0, 0xA0000000},
> + {ECS_BG_CTXT_REG_1, 0x01000000},
> + {ECS_BG_CTXT_REG_2, 0x00008000},
> + {ECS_PRI_1_CTXT_REG_0, 0x20000080},
> + {ECS_PRI_1_CTXT_REG_1, 0x01000000},
> + {ECS_PRI_1_CTXT_REG_2, 0x00008000},
> + {ECS_PRI_2_CTXT_REG_0, 0x20000080},
> + {ECS_PRI_2_CTXT_REG_1, 0x01000000},
> + {ECS_PRI_2_CTXT_REG_2, 0x00008000},
> + {ECS_DBG_CTXT_REG_0, 0x20000000},
> + {ECS_DBG_CTXT_REG_1, 0x00000000},
> + {ECS_DBG_CTXT_REG_2, 0x001E0000},
> + {ECS_INSTRUCT_REG, 0x1003C00F},
> +};
> +
> +static struct npe npe_tab[NPE_COUNT] = {
> + {
> + .regs = (struct npe_regs *)IXP4XX_NPEA_BASE,
> + .id = 0,
> + .name = "NPE-A",
> + }, {
> + .regs = (struct npe_regs *)IXP4XX_NPEB_BASE,
> + .id = 1,
> + .name = "NPE-B",
> + }, {
> + .regs = (struct npe_regs *)IXP4XX_NPEC_BASE,
> + .id = 2,
> + .name = "NPE-C",
> + }
> +};
> +
> +int npe_running(struct npe *npe)
> +{
> + return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;
> +}
> +
> +static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)
> +{
> + __raw_writel(data, &npe->regs->exec_data);
> + __raw_writel(addr, &npe->regs->exec_addr);
> + __raw_writel(cmd, &npe->regs->exec_status_cmd);
> +}
> +
> +static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
> +{
> + __raw_writel(addr, &npe->regs->exec_addr);
> + __raw_writel(cmd, &npe->regs->exec_status_cmd);
> + /* Iintroduce extra read cycles after issuing read command to NPE
> + so that we read the register after the NPE has updated it.
> + This is to overcome race condition between XScale and NPE */
> + __raw_readl(&npe->regs->exec_data);
> + __raw_readl(&npe->regs->exec_data);
> + return __raw_readl(&npe->regs->exec_data);
> +}
> +
> +static void npe_clear_active(struct npe *npe, u32 reg)
> +{
> + u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
> + npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
> +}
> +
> +static void npe_start(struct npe *npe)
> +{
> + /* ensure only Background Context Stack Level is active */
> + npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
> + npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
> + npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
> +
> + __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
> + __raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);
> +}
> +
> +static void npe_stop(struct npe *npe)
> +{
> + __raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);
> + __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/
> +}
> +
> +static int npe_debug_instr(struct npe *npe, u32 instr, u32 ctx, u32 ldur)
> +{
> + u32 wc;
> + int i;
> +
> + /* set the Active bit, and the LDUR, in the debug level */
> + npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
> + ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
> +
> + /* set CCTXT at ECS DEBUG L3 to specify in which context to execute
> + the instruction, and set SELCTXT at ECS DEBUG Level to specify
> + which context store to access.
> + Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
> + */
> + npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
> + (ctx << ECS_REG_1_CCTXT_BITS) |
> + (ctx << ECS_REG_1_SELCTXT_BITS));
> +
> + /* clear the pipeline */
> + __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
> +
> + /* load NPE instruction into the instruction register */
> + npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
> +
> + /* we need this value later to wait for completion of NPE execution
> + step */
> + wc = __raw_readl(&npe->regs->watch_count);
> +
> + /* issue a Step One command via the Execution Control register */
> + __raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
> +
> + /* Watch Count register increments when NPE completes an instruction */
> + for (i = 0; i < MAX_RETRIES; i++) {
> + if (wc != __raw_readl(&npe->regs->watch_count))
> + return 0;
> + udelay(1);
> + }
> +
> + print_npe(npe, "reset: npe_debug_instr(): timeout\n");
> + return -ETIMEDOUT;
> +}
> +
> +static int npe_logical_reg_write8(struct npe *npe, u32 addr, u8 val, u32 ctx)
> +{
> + /* here we build the NPE assembler instruction: mov8 d0, #0 */
> + u32 instr = INSTR_WR_REG_BYTE | /* OpCode */
> + addr << 9 | /* base Operand */
> + (val & 0x1F) << 4 | /* lower 5 bits to immediate data */
> + (val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */
> + return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
> +}
> +
> +static int npe_logical_reg_write16(struct npe *npe, u32 addr, u16 val, u32 ctx)
> +{
> + /* here we build the NPE assembler instruction: mov16 d0, #0 */
> + u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
> + addr << 9 | /* base Operand */
> + (val & 0x1F) << 4 | /* lower 5 bits to immediate data */
> + (val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */
> + return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
> +}
> +
> +static int npe_logical_reg_write32(struct npe *npe, u32 addr, u32 val, u32 ctx)
> +{
> + /* write in 16 bit steps first the high and then the low value */
> + if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))
> + return -ETIMEDOUT;
> + return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
> +}
> +
> +static int npe_reset(struct npe *npe)
> +{
> + u32 val, ctl, exec_count, ctx_reg2;
> + int i;
> +
> + ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &
> + 0x3F3FFFFF;
> +
> + /* disable parity interrupt */
> + __raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);
> +
> + /* pre exec - debug instruction */
> + /* turn off the halt bit by clearing Execution Count register. */
> + exec_count = __raw_readl(&npe->regs->exec_count);
> + __raw_writel(0, &npe->regs->exec_count);
> + /* ensure that IF and IE are on (temporarily), so that we don't end up
> + stepping forever */
> + ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
> + npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
> + ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
> +
> + /* clear the FIFOs */
> + while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
> + ;
> + while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)
> + /* read from the outFIFO until empty */
> + print_npe(npe, "npe_reset: read FIFO = 0x%X\n",
> + __raw_readl(&npe->regs->in_out_fifo));
> +
> + while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)
> + /* step execution of the NPE intruction to read inFIFO using
> + the Debug Executing Context stack */
> + if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))
> + return -ETIMEDOUT;
> +
> + /* reset the mailbox reg from the XScale side */
> + __raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);
> + /* from NPE side */
> + if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))
> + return -ETIMEDOUT;
> +
> + /* Reset the physical registers in the NPE register file */
> + for (val = 0; val < NPE_PHYS_REG; val++) {
> + if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))
> + return -ETIMEDOUT;
> + /* address is either 0 or 4 */
> + if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))
> + return -ETIMEDOUT;
> + }
> +
> + /* Reset the context store = each context's Context Store registers */
> +
> + /* Context 0 has no STARTPC. Instead, this value is used to set NextPC
> + for Background ECS, to set where NPE starts executing code */
> + val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
> + val &= ~ECS_REG_0_NEXTPC_MASK;
> + val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
> + npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
> +
> + for (i = 0; i < 16; i++) {
> + if (i) { /* Context 0 has no STEVT nor STARTPC */
> + /* STEVT = off, 0x80 */
> + if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))
> + return -ETIMEDOUT;
> + if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))
> + return -ETIMEDOUT;
> + }
> + /* REGMAP = d0->p0, d8->p2, d16->p4 */
> + if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))
> + return -ETIMEDOUT;
> + if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))
> + return -ETIMEDOUT;
> + }
> +
> + /* post exec */
> + /* clear active bit in debug level */
> + npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);
> + /* clear the pipeline */
> + __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
> + /* restore previous values */
> + __raw_writel(exec_count, &npe->regs->exec_count);
> + npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
> +
> + /* write reset values to Execution Context Stack registers */
> + for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
> + npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
> + ecs_reset[val].val);
> +
> + /* clear the profile counter */
> + __raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
> +
> + __raw_writel(0, &npe->regs->exec_count);
> + __raw_writel(0, &npe->regs->action_points[0]);
> + __raw_writel(0, &npe->regs->action_points[1]);
> + __raw_writel(0, &npe->regs->action_points[2]);
> + __raw_writel(0, &npe->regs->action_points[3]);
> + __raw_writel(0, &npe->regs->watch_count);
> +
> + val = ixp4xx_read_feature_bits();
> + /* reset the NPE */
> + ixp4xx_write_feature_bits(val &
> + ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
> + /* deassert reset */
> + ixp4xx_write_feature_bits(val |
> + (IXP4XX_FEATURE_RESET_NPEA << npe->id));
> + for (i = 0; i < MAX_RETRIES; i++) {
> + if (ixp4xx_read_feature_bits() &
> + (IXP4XX_FEATURE_RESET_NPEA << npe->id))
> + break; /* NPE is back alive */
> + udelay(1);
> + }
> + if (i == MAX_RETRIES)
> + return -ETIMEDOUT;
> +
> + npe_stop(npe);
> +
> + /* restore NPE configuration bus Control Register - parity settings */
> + __raw_writel(ctl, &npe->regs->messaging_control);
> + return 0;
> +}
> +
> +
> +int npe_send_message(struct npe *npe, const void *msg, const char *what)
> +{
> + const u32 *send = msg;
> + int cycles = 0;
> +
> + debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
> + what, send[0], send[1]);
> +
> + if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
> + debug_msg(npe, "NPE input FIFO not empty\n");
> + return -EIO;
> + }
> +
> + __raw_writel(send[0], &npe->regs->in_out_fifo);
> +
> + if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {
> + debug_msg(npe, "NPE input FIFO full\n");
> + return -EIO;
> + }
> +
> + __raw_writel(send[1], &npe->regs->in_out_fifo);
> +
> + while ((cycles < MAX_RETRIES) &&
> + (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {
> + udelay(1);
> + cycles++;
> + }
> +
> + if (cycles == MAX_RETRIES) {
> + debug_msg(npe, "Timeout sending message\n");
> + return -ETIMEDOUT;
> + }
> +
> +#if DEBUG_MSG > 1
> + debug_msg(npe, "Sending a message took %i cycles\n", cycles);
> +#endif
> + return 0;
> +}
> +
> +int npe_recv_message(struct npe *npe, void *msg, const char *what)
> +{
> + u32 *recv = msg;
> + int cycles = 0, cnt = 0;
> +
> + debug_msg(npe, "Trying to receive message %s\n", what);
> +
> + while (cycles < MAX_RETRIES) {
> + if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {
> + recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);
> + if (cnt == 2)
> + break;
> + } else {
> + udelay(1);
> + cycles++;
> + }
> + }
> +
> + switch(cnt) {
> + case 1:
> + debug_msg(npe, "Received [%08X]\n", recv[0]);
> + break;
> + case 2:
> + debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);
> + break;
> + }
> +
> + if (cycles == MAX_RETRIES) {
> + debug_msg(npe, "Timeout waiting for message\n");
> + return -ETIMEDOUT;
> + }
> +
> +#if DEBUG_MSG > 1
> + debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
> +#endif
> + return 0;
> +}
> +
> +int npe_send_recv_message(struct npe *npe, void *msg, const char *what)
> +{
> + int result;
> + u32 *send = msg, recv[2];
> +
> + if ((result = npe_send_message(npe, msg, what)) != 0)
> + return result;
> + if ((result = npe_recv_message(npe, recv, what)) != 0)
> + return result;
> +
> + if ((recv[0] != send[0]) || (recv[1] != send[1])) {
> + debug_msg(npe, "Message %s: unexpected message received\n",
> + what);
> + return -EIO;
> + }
> + return 0;
> +}
> +
> +
> +int npe_load_firmware(struct npe *npe)
> +{
> + struct dl_block {
> + u32 type;
> + u32 offset;
> + } *blk;
> +
> + struct dl_image {
> + u32 magic;
> + u32 id;
> + u32 size;
> + union {
> + u32 data[0];
> + struct dl_block blocks[0];
> + };
> + } *image;
> +
> + struct dl_codeblock {
> + u32 npe_addr;
> + u32 size;
> + u32 data[0];
> + } *cb;
> +
> + int i, j, err, data_size, instr_size, blocks, table_end;
> + u32 cmd;
> + char name[5 /* "/dev/" */ + NPE_NAME_LENGTH + 1 /* NUL */];
> + size_t image_size;
> +
> + sprintf(name, "/dev/%s", npe->name);
> + if (!(image = read_file(name, &image_size))) {
> + print_npe(npe, "bad or missing microcode file %s", name);
> + return -EIO;
> + }
> +
> + err = -EINVAL;
> + if (image_size < sizeof(struct dl_image)) {
> + print_npe(npe, "incomplete microcode file %s\n", name);
> + goto err;
> + }
> +
> +#if DEBUG_FW
> + print_npe(npe, "microcode: %08X %08X %08X (0x%X bytes)\n",
> + image->magic, image->id, image->size, image->size * 4);
> +#endif
> +
> + if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
> + image->id = swab32(image->id);
> + image->size = swab32(image->size);
> + } else if (image->magic != FW_MAGIC) {
> + print_npe(npe, "bad microcode file %s magic: 0x%X\n", name, image->magic);
> + goto err;
> + }
> + if ((image->size * 4 + sizeof(struct dl_image)) > image_size) {
> + print_npe(npe, "incomplete microcode file %s\n", name);
> + goto err;
> + }
> + if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
> + print_npe(npe, "NPE ID mismatch in microcode file %s\n", name);
> + goto err;
> + }
> + if (image->magic == swab32(FW_MAGIC))
> + for (i = 0; i < image->size; i++)
> + image->data[i] = swab32(image->data[i]);
> +
> + if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) {
> + print_npe(npe, "IXP43x/IXP46x microcode ignored on IXP42x\n");
> + goto err;
> + }
> +
> + if (npe_running(npe)) {
> + print_npe(npe, "unable to load microcode file %s, NPE is already running\n", name);
> + err = -EBUSY;
> + goto err;
> + }
> +
> + if (cpu_is_ixp42x()) {
> + if (!npe->id)
> + instr_size = NPE_A_42X_INSTR_SIZE;
> + else
> + instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
> + data_size = NPE_42X_DATA_SIZE;
> + } else {
> + instr_size = NPE_46X_INSTR_SIZE;
> + data_size = NPE_46X_DATA_SIZE;
> + }
> +
> + for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
> + blocks++)
> + if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
> + break;
> + if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
> + print_npe(npe, "microcode EOF block marker not found\n");
> + goto err;
> + }
> +
> +#if DEBUG_FW
> + print_npe(npe, "%i microcode blocks found\n", blocks);
> +#endif
> +
> + table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
> + for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
> + if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
> + || blk->offset < table_end) {
> + print_npe(npe, "invalid offset 0x%X of "
> + "microcode block #%i\n", blk->offset, i);
> + goto err;
> + }
> +
> + cb = (struct dl_codeblock*)&image->data[blk->offset];
> + if (blk->type == FW_BLOCK_TYPE_INSTR) {
> + if (cb->npe_addr + cb->size > instr_size)
> + goto too_big;
> + cmd = CMD_WR_INS_MEM;
> + } else if (blk->type == FW_BLOCK_TYPE_DATA) {
> + if (cb->npe_addr + cb->size > data_size)
> + goto too_big;
> + cmd = CMD_WR_DATA_MEM;
> + } else {
> + print_npe(npe, "invalid microcode block #%i type 0x%X\n",
> + i, blk->type);
> + goto err;
> + }
> + if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
> + print_npe(npe, "microcode block #%i doesn't "
> + "fit in microcode image: type %c, start 0x%X,"
> + " length 0x%X\n", i,
> + blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
> + cb->npe_addr, cb->size);
> + goto err;
> + }
> +
> + for (j = 0; j < cb->size; j++)
> + npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
> + }
> +
> + npe_start(npe);
> + if (!npe_running(npe))
> + print_npe(npe, "unable to start\n");
> + free(image);
> + return 0;
> +
> +too_big:
> + print_npe(npe, "microcode block #%i doesn't fit in NPE "
> + "memory: type %c, start 0x%X, length 0x%X\n", i,
> + blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
> + cb->npe_addr, cb->size);
> +err:
> + free(image);
> + return err;
> +}
> +
> +
> +struct npe *npe_request(int id)
> +{
> + if (id < NPE_COUNT)
> + if (npe_tab[id].valid)
> + return &npe_tab[id];
> + return NULL;
> +}
> +
> +static int __init npe_init(void)
> +{
> + int i;
> +
> + for (i = 0; i < NPE_COUNT; i++) {
> + struct npe *npe = &npe_tab[i];
> + if (!(ixp4xx_read_feature_bits() & (IXP4XX_FEATURE_RESET_NPEA << i)))
> + continue; /* NPE already disabled or not present */
> + if (npe_reset(npe))
> + continue;
> + npe->valid = 1;
> + }
> + return 0;
> +}
> +
> +coredevice_initcall(npe_init);
> diff --git a/arch/arm/mach-ixp4xx/qmgr.c b/arch/arm/mach-ixp4xx/qmgr.c
> new file mode 100644
> index 0000000..49cba60
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/qmgr.c
> @@ -0,0 +1,269 @@
> +/*
> + * Intel IXP4xx Queue Manager driver for Linux
> + *
> + * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License
> + * as published by the Free Software Foundation.
> + */
> +
> +#include <init.h>
> +#include <errno.h>
> +#include <mach/qmgr.h>
> +
> +static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
> +
> +#if DEBUG_QMGR
> +char qmgr_queue_descs[HALF_QUEUES][32];
> +#endif
> +
> +#ifdef CONFIG_USE_IRQ
> +
> +static void (*irq_handlers[HALF_QUEUES])(void *pdev);
> +static void *irq_pdevs[HALF_QUEUES];
> +
> +#undef fls
> +static inline int fls(int x)
> +{
> + int ret;
> + asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
> + ret = 32 - ret;
> + return ret;
> +}
> +
> +
> +void qmgr_set_irq(unsigned int queue, int src,
> + void (*handler)(void *pdev), void *pdev)
> +{
> + const u32 *reg;
> + int bit;
> + BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL);
> + reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */
> + bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
> + __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
> +
> + irq_handlers[queue] = handler;
> + irq_pdevs[queue] = pdev;
> +}
> +
> +
> +static void qmgr_irq1_a0(void *data)
> +{
> + int i;
> + u32 en_bitmap, src, stat;
> +
> + /* ACK - it may clear any bits so don't rely on it */
> + __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]);
> +
> + en_bitmap = qmgr_regs->irqen[0];
> + while (en_bitmap) {
> + i = fls(en_bitmap) - 1; /* number of the last "low" queue */
> + en_bitmap &= ~BIT(i);
> + src = qmgr_regs->irqsrc[i >> 3];
> + stat = qmgr_regs->stat1[i >> 3];
> + if (src & 4) /* the IRQ condition is inverted */
> + stat = ~stat;
> + if (stat & BIT(src & 3))
> + irq_handlers[i](irq_pdevs[i]);
> + }
> +}
> +
> +
> +static void qmgr_irq1(void *data)
> +{
> + int i;
> + u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[0]);
> +
> + if (!req_bitmap)
> + return;
> + __raw_writel(req_bitmap, &qmgr_regs->irqstat[0]); /* ACK */
> +
> + while (req_bitmap) {
> + i = fls(req_bitmap) - 1; /* number of the last queue */
> + req_bitmap &= ~BIT(i);
> + irq_handlers[i](irq_pdevs[i]);
> + }
> +}
> +
> +
> +void qmgr_enable_irq(unsigned int queue)
> +{
> + u32 mask = 1 << queue;
> +
> + __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | mask,
> + &qmgr_regs->irqen[0]);
> +}
> +
> +void qmgr_disable_irq(unsigned int queue)
> +{
> + u32 mask = 1 << queue;
> +
> + __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~mask,
> + &qmgr_regs->irqen[0]);
> + __raw_writel(mask, &qmgr_regs->irqstat[0]); /* clear */
> +}
> +
> +#endif /* CONFIG_USE_IRQ */
> +
> +static inline void shift_mask(u32 *mask)
> +{
> + mask[3] = mask[3] << 1 | mask[2] >> 31;
> + mask[2] = mask[2] << 1 | mask[1] >> 31;
> + mask[1] = mask[1] << 1 | mask[0] >> 31;
> + mask[0] <<= 1;
> +}
> +
> +#if DEBUG_QMGR
> +void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
> + unsigned int nearly_empty_watermark,
> + unsigned int nearly_full_watermark,
> + const char *desc_format, const char* name)
> +#else
> +void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
> + unsigned int nearly_empty_watermark,
> + unsigned int nearly_full_watermark)
> +#endif
> +{
> + u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
> +
> + BUG_ON(queue >= HALF_QUEUES);
> + BUG_ON((nearly_empty_watermark | nearly_full_watermark) & ~7);
> +
> + switch (len) {
> + case 16:
> + cfg = 0 << 24;
> + mask[0] = 0x1;
> + break;
> + case 32:
> + cfg = 1 << 24;
> + mask[0] = 0x3;
> + break;
> + case 64:
> + cfg = 2 << 24;
> + mask[0] = 0xF;
> + break;
> + case 128:
> + cfg = 3 << 24;
> + mask[0] = 0xFF;
> + break;
> + default:
> + BUG();
> + }
> +
> + cfg |= nearly_empty_watermark << 26;
> + cfg |= nearly_full_watermark << 29;
> + len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */
> + mask[1] = mask[2] = mask[3] = 0;
> +
> + BUG_ON(__raw_readl(&qmgr_regs->sram[queue]));
> +
> + while (1) {
> + if (!(used_sram_bitmap[0] & mask[0]) &&
> + !(used_sram_bitmap[1] & mask[1]) &&
> + !(used_sram_bitmap[2] & mask[2]) &&
> + !(used_sram_bitmap[3] & mask[3]))
> + break; /* found free space */
> +
> + addr++;
> + shift_mask(mask);
> + if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
> + fprintf(stderr, "qmgr: no free SRAM space for"
> + " queue %i\n", queue);
> + BUG();
> + }
> + }
> +
> + used_sram_bitmap[0] |= mask[0];
> + used_sram_bitmap[1] |= mask[1];
> + used_sram_bitmap[2] |= mask[2];
> + used_sram_bitmap[3] |= mask[3];
> + __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
> +#if DEBUG_QMGR
> + /* no snprintf() */
> + sprintf(qmgr_queue_descs[queue], desc_format, name);
> + fprintf(stderr, "qmgr: requested queue %s(%i) addr = 0x%02X\n",
> + qmgr_queue_descs[queue], queue, addr);
> +#endif
> +}
> +
> +void qmgr_release_queue(unsigned int queue)
> +{
> + u32 cfg, addr, mask[4];
> +
> + BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
> +
> + cfg = __raw_readl(&qmgr_regs->sram[queue]);
> + addr = (cfg >> 14) & 0xFF;
> +
> + BUG_ON(!addr); /* not requested */
> +
> + switch ((cfg >> 24) & 3) {
> + case 0: mask[0] = 0x1; break;
> + case 1: mask[0] = 0x3; break;
> + case 2: mask[0] = 0xF; break;
> + case 3: mask[0] = 0xFF; break;
> + }
> +
> + mask[1] = mask[2] = mask[3] = 0;
> +
> + while (addr--)
> + shift_mask(mask);
> +
> +#if DEBUG_QMGR
> + fprintf(stderr, "qmgr: releasing queue %s(%i)\n",
> + qmgr_queue_descs[queue], queue);
> + qmgr_queue_descs[queue][0] = '\x0';
> +#endif
> + __raw_writel(0, &qmgr_regs->sram[queue]);
> +
> + used_sram_bitmap[0] &= ~mask[0];
> + used_sram_bitmap[1] &= ~mask[1];
> + used_sram_bitmap[2] &= ~mask[2];
> + used_sram_bitmap[3] &= ~mask[3];
> +#ifdef CONFIG_USE_IRQ
> + irq_handlers[queue] = NULL; /* catch IRQ bugs */
> +#endif
> +
> + while ((addr = qmgr_get_entry(queue)))
> + fprintf(stderr, "qmgr: released queue %i not empty: 0x%08X\n",
> + queue, addr);
> +}
> +
> +static int __init qmgr_init(void)
> +{
> + int i;
> +#ifdef CONFIG_USE_IRQ
> + interrupt_handler_t *handler;
> +#endif
> +
> + /* reset qmgr registers */
> + for (i = 0; i < 4; i++) {
> + __raw_writel(0x33333333, &qmgr_regs->stat1[i]);
> + __raw_writel(0, &qmgr_regs->irqsrc[i]);
> + }
> + for (i = 0; i < 2; i++) {
> + __raw_writel(0, &qmgr_regs->stat2[i]);
> + __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
> + __raw_writel(0, &qmgr_regs->irqen[i]);
> + }
> +
> + __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h);
> + __raw_writel(0, &qmgr_regs->statf_h);
> +
> + for (i = 0; i < QUEUES; i++)
> + __raw_writel(0, &qmgr_regs->sram[i]);
> +
> +#ifdef CONFIG_USE_IRQ
> + if (cpu_is_ixp42x_rev_a0())
> + handler = qmgr_irq1_a0;
> + else
> + handler = qmgr_irq1;
> +
> + irq_install_handler(IXP425_QM1_IRQ, handler, NULL);
> +#endif
> + used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
> + return 0;
> +}
> +
> +coredevice_initcall(qmgr_init);
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 69f3352..df6e42c 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -77,6 +77,14 @@ config DRIVER_NET_MACB
> depends on HAS_MACB
> select MIIDEV
>
> +config DRIVER_NET_IXP4XX_ETH
> + tristate "Intel IXP4xx Ethernet support"
> + depends on ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
> + select MIIDEV
> + help
> + Say Y here if you want to use built-in Ethernet ports
> + on IXP4xx processor.
> +
> config DRIVER_NET_TAP
> bool "tap Ethernet driver"
> depends on LINUX
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 96d3d32..97cb44b 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -11,3 +11,4 @@ obj-$(CONFIG_DRIVER_NET_MACB) += macb.o
> obj-$(CONFIG_DRIVER_NET_TAP) += tap.o
> obj-$(CONFIG_MIIDEV) += miidev.o
> obj-$(CONFIG_NET_USB) += usb/
> +obj-$(CONFIG_DRIVER_NET_IXP4XX_ETH) += ixp4xx_eth.o
> diff --git a/drivers/net/ixp4xx_eth.c b/drivers/net/ixp4xx_eth.c
> new file mode 100644
> index 0000000..71e6d92
> --- /dev/null
> +++ b/drivers/net/ixp4xx_eth.c
> @@ -0,0 +1,763 @@
> +/*
> + * Intel IXP4xx Ethernet driver for Linux
> + *
> + * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License
> + * as published by the Free Software Foundation.
> + *
> + * Ethernet port config (0x00 is not present on IXP42X):
> + *
> + * logical port 0x00 0x10 0x20
> + * NPE 0 (NPE-A) 1 (NPE-B) 2 (NPE-C)
> + * physical port 2 0 1
> + * RX queue (variable) 20 21 22
> + * TX queue 23 24 25
> + * RX-free queue 26 27 28
> + * TX-done queue is always 31, per-port RX queue is configurable
> + *
> + *
> + * Queue entries:
> + * bits 0 -> 1 - NPE ID (RX and TX-done)
> + * bits 0 -> 2 - priority (TX, per 802.1D)
> + * bits 3 -> 4 - port ID (user-set?)
> + * bits 5 -> 31 - physical descriptor address
> + */
> +
> +#include <common.h>
> +#include <init.h>
> +#include <malloc.h>
> +#include <miidev.h>
> +#include <net.h>
> +#include <errno.h>
> +#include <mach/ixp4xx-regs.h>
> +#include <mach/platform.h>
> +#include <mach/cpu.h>
> +#include <mach/npe.h>
> +#include <mach/qmgr.h>
> +
> +#define DEBUG_DESC 0
> +#define DEBUG_RX 0
> +#define DEBUG_TX 0
> +#define DEBUG_PKT_BYTES 0
> +#define DEBUG_MDIO 0
> +#define DEBUG_OPEN 0
> +#define DEBUG_CLOSE 0
> +
> +#define RX_DESCS 16 /* also length of all RX queues */
> +#define TX_DESCS 16 /* also length of all TX queues */
> +#define TXDONE_QUEUE_LEN 16 /* dwords */
> +
> +#define MAX_MRU 1536 /* 0x600 */
> +#define RX_BUFF_SIZE MAX_MRU
> +
> +#define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */
> +#define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */
> +#define ETH_ALEN 6
> +
> +#define PHYSICAL_ID(port) (((port)->npe->id + 2) % 3)
> +#define LOGICAL_ID(port) ((port)->npe->id << 4)
> +#define RX_QUEUE(port) ((port)->npe->id + 20) /* can be changed */
> +#define TX_QUEUE(port) ((port)->npe->id + 23)
> +#define RXFREE_QUEUE(port) ((port)->npe->id + 26)
> +#define TXDONE_QUEUE 31
> +
> +/* TX Control Registers */
> +#define TX_CNTRL0_TX_EN 0x01
> +#define TX_CNTRL0_HALFDUPLEX 0x02
> +#define TX_CNTRL0_RETRY 0x04
> +#define TX_CNTRL0_PAD_EN 0x08
> +#define TX_CNTRL0_APPEND_FCS 0x10
> +#define TX_CNTRL0_2DEFER 0x20
> +#define TX_CNTRL0_RMII 0x40 /* reduced MII */
> +#define TX_CNTRL1_RETRIES 0x0F /* 4 bits */
> +
> +/* RX Control Registers */
> +#define RX_CNTRL0_RX_EN 0x01
> +#define RX_CNTRL0_PADSTRIP_EN 0x02
> +#define RX_CNTRL0_SEND_FCS 0x04
> +#define RX_CNTRL0_PAUSE_EN 0x08
> +#define RX_CNTRL0_LOOP_EN 0x10
> +#define RX_CNTRL0_ADDR_FLTR_EN 0x20
> +#define RX_CNTRL0_RX_RUNT_EN 0x40
> +#define RX_CNTRL0_BCAST_DIS 0x80
> +#define RX_CNTRL1_DEFER_EN 0x01
> +
> +/* Core Control Register */
> +#define CORE_RESET 0x01
> +#define CORE_RX_FIFO_FLUSH 0x02
> +#define CORE_TX_FIFO_FLUSH 0x04
> +#define CORE_SEND_JAM 0x08
> +#define CORE_MDC_EN 0x10 /* MDIO using NPE-B ETH-0 only */
> +
> +#define DEFAULT_TX_CNTRL0 (TX_CNTRL0_TX_EN | TX_CNTRL0_RETRY | \
> + TX_CNTRL0_PAD_EN | TX_CNTRL0_APPEND_FCS | \
> + TX_CNTRL0_2DEFER)
> +#define DEFAULT_RX_CNTRL0 RX_CNTRL0_RX_EN
> +#define DEFAULT_CORE_CNTRL CORE_MDC_EN
> +
> +
> +/* NPE message codes */
> +#define NPE_GETSTATUS 0x00
> +#define NPE_EDB_SETPORTADDRESS 0x01
> +#define NPE_EDB_GETMACADDRESSDATABASE 0x02
> +#define NPE_EDB_SETMACADDRESSSDATABASE 0x03
> +#define NPE_GETSTATS 0x04
> +#define NPE_RESETSTATS 0x05
> +#define NPE_SETMAXFRAMELENGTHS 0x06
> +#define NPE_VLAN_SETRXTAGMODE 0x07
> +#define NPE_VLAN_SETDEFAULTRXVID 0x08
> +#define NPE_VLAN_SETPORTVLANTABLEENTRY 0x09
> +#define NPE_VLAN_SETPORTVLANTABLERANGE 0x0A
> +#define NPE_VLAN_SETRXQOSENTRY 0x0B
> +#define NPE_VLAN_SETPORTIDEXTRACTIONMODE 0x0C
> +#define NPE_STP_SETBLOCKINGSTATE 0x0D
> +#define NPE_FW_SETFIREWALLMODE 0x0E
> +#define NPE_PC_SETFRAMECONTROLDURATIONID 0x0F
> +#define NPE_PC_SETAPMACTABLE 0x11
> +#define NPE_SETLOOPBACK_MODE 0x12
> +#define NPE_PC_SETBSSIDTABLE 0x13
> +#define NPE_ADDRESS_FILTER_CONFIG 0x14
> +#define NPE_APPENDFCSCONFIG 0x15
> +#define NPE_NOTIFY_MAC_RECOVERY_DONE 0x16
> +#define NPE_MAC_RECOVERY_START 0x17
> +
> +struct eth_regs {
> + u32 tx_control[2], __res1[2]; /* 000 */
> + u32 rx_control[2], __res2[2]; /* 010 */
> + u32 random_seed, __res3[3]; /* 020 */
> + u32 partial_empty_threshold, __res4; /* 030 */
> + u32 partial_full_threshold, __res5; /* 038 */
> + u32 tx_start_bytes, __res6[3]; /* 040 */
> + u32 tx_deferral, rx_deferral, __res7[2]; /* 050 */
> + u32 tx_2part_deferral[2], __res8[2]; /* 060 */
> + u32 slot_time, __res9[3]; /* 070 */
> + u32 mdio_command[4]; /* 080 */
> + u32 mdio_status[4]; /* 090 */
> + u32 mcast_mask[6], __res10[2]; /* 0A0 */
> + u32 mcast_addr[6], __res11[2]; /* 0C0 */
> + u32 int_clock_threshold, __res12[3]; /* 0E0 */
> + u32 hw_addr[6], __res13[61]; /* 0F0 */
> + u32 core_control; /* 1FC */
> +};
> +
> +/* NPE message structure */
> +struct msg {
> + u8 cmd, eth_id, params[6];
> +};
> +
> +/* Ethernet packet descriptor, 32 bytes */
> +struct desc {
> + u8 *next; /* pointer to next buffer, unused */
> +
> + u16 buf_len; /* buffer length */
> + u16 pkt_len; /* packet length */
> + u8 *data; /* pointer to data buffer in RAM */
> + u8 dest_id;
> + u8 src_id;
> + u16 flags;
> + u8 qos;
> + u8 padlen;
> + u16 vlan_tci;
> +
> + u8 dst_mac[ETH_ALEN], src_mac[ETH_ALEN];
> +};
> +
> +struct port {
> + struct desc rx_desc_tab[RX_DESCS]; /* alignment: 0x10 */
> + struct desc tx_desc_tab[TX_DESCS];
> + u8 *buff_tab;
> + struct eth_regs *regs;
> + struct npe *npe;
> + u8 firmware[4];
> + struct eth_plat_info *pinfo;
> + struct mii_device miidev;
> + struct eth_device eth;
> +};
> +
> +#define rx_buff(port, n) ((port)->buff_tab + MAX_MRU * (n))
> +#define tx_buff(port, n) ((port)->buff_tab + MAX_MRU * (RX_DESCS + (n)))
> +
> +static struct eth_regs *mdio_regs; /* mdio command and status only */
> +
> +static int ixp4xx_mdio_cmd(int write, const struct device_d *dev, unsigned char phy_id,
> + unsigned char location, unsigned short value)
> +{
> + int cycles = 0;
> +
> + if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {
> + fprintf(stderr, "%s%d: MII not ready to transmit\n", dev->name, dev->id);
> + return -1;
> + }
> +
> + if (write) {
> + __raw_writel(value & 0xFF, &mdio_regs->mdio_command[0]);
> + __raw_writel(value >> 8, &mdio_regs->mdio_command[1]);
> + }
> + __raw_writel(((phy_id << 5) | location) & 0xFF,
> + &mdio_regs->mdio_command[2]);
> + __raw_writel((phy_id >> 3) | (write << 2) | 0x80 /* GO */,
> + &mdio_regs->mdio_command[3]);
> +
> + while ((cycles < MAX_MDIO_RETRIES) &&
> + (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80)) {
> + udelay(1);
> + cycles++;
> + }
> +
> + if (cycles == MAX_MDIO_RETRIES) {
> + fprintf(stderr, "%s%d: MII write failed\n", dev->name, dev->id);
> + return -1;
> + }
> +
> +#if DEBUG_MDIO
> + fprintf(stderr, "%s%d: mdio_%s() took %i cycles\n", dev->name, dev->id,
> + write ? "write" : "read", cycles);
> +#endif
> +
> + if (write)
> + return 0;
> +
> + if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {
> +#if DEBUG_MDIO
> + fprintf(stderr, "%s%d: MII read failed\n", dev->name, dev->id);
> +#endif
> + return -1;
> + }
> +
> + value = (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |
> + ((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8);
> +#if DEBUG_MDIO
> + fprintf(stderr, "%s%d: MII read [%i] -> 0x%X\n", dev->name, dev->id, location, value);
> +#endif
> +
> + return value;
> +}
> +
> +static int ixp4xx_mdio_read(struct mii_device *mii, int phy_id, int location)
> +{
> + int ret = ixp4xx_mdio_cmd(0, &mii->dev, phy_id, location, 0);
> + return ret;
> +}
> +
> +static int ixp4xx_mdio_write(struct mii_device *mii, int phy_id, int location, int value)
> +{
> + int ret = ixp4xx_mdio_cmd(1, &mii->dev, phy_id, location, value);
> +#if DEBUG_MDIO
> + fprintf(stderr, "%s%d: MII write [%i] <- 0x%X, err = %i\n",
> + mii->dev.name, mii->dev.id, location, value, ret);
> +#endif
> + return ret;
> +}
> +
> +static int ixp4xx_adjust_link(struct eth_device *dev)
> +{
> + struct port *port = dev->priv;
> + int reg, speed, duplex;
> +
> + miidev_wait_aneg(&port->miidev);
> +
> + reg = mii_read(&port->miidev, port->miidev.address, MII_BMSR);
> + if (reg < 0)
> + goto err_out;
> + if (!(reg & BMSR_LSTATUS)) {
> + printf("%s%d: Link is down", dev->dev.name, dev->dev.id);
> + return -1;
> + }
> +
> + reg = mii_read(&port->miidev, port->miidev.address, MII_BMCR);
> + if (reg < 0)
> + goto err_out;
> +
> + if (reg & BMCR_ANENABLE) {
> + reg = mii_read(&port->miidev, port->miidev.address, MII_LPA);
> + if (reg < 0)
> + goto err_out;
> + duplex = reg & LPA_DUPLEX;
> + speed = reg & LPA_100 ? 100 : 10;
> + } else {
> + duplex = reg & BMCR_FULLDPLX;
> + speed = reg & BMCR_SPEED100 ? 100 : 10;
> + }
> +
> + if (duplex)
> + __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
> + &port->regs->tx_control[0]);
> + else
> + __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
> + &port->regs->tx_control[0]);
> +
> + fprintf(stderr, "%s%d: link up, speed %u Mb/s, %s duplex\n",
> + dev->dev.name, dev->dev.id, speed, duplex ? "full" : "half");
> + return 0;
> +
> +err_out:
> + printf("%s%d: failed to read MII data\n", dev->dev.name, dev->dev.id);
> + return -EIO;
> +}
> +
> +static inline void debug_pkt(struct eth_device *dev, const char *func,
> + u8 *data, int len)
> +{
> +#if DEBUG_PKT_BYTES
> + int i;
> +
> + fprintf(stderr, "%s%d: %s(%4i) ", dev->dev.name, dev->dev.id, func, len);
> + for (i = 0; i < len; i++) {
> + if (i >= DEBUG_PKT_BYTES)
> + break;
> + fprintf(stderr, "%s%02X",
> + ((i == 6) || (i == 12) || (i >= 14)) ? " " : "",
> + data[i]);
> + }
> + fprintf(stderr, "\n");
> +#endif
> +}
> +
> +
> +static inline void debug_desc(struct desc *desc)
> +{
> +#if DEBUG_DESC
> + fprintf(stderr, "%07X: %X %3X %3X %07X %2X < %2X %4X %X"
> + " %X %X %02X%02X%02X%02X%02X%02X < %02X%02X%02X%02X%02X%02X\n",
> + (u32)desc, (u32)desc->next, desc->buf_len, desc->pkt_len,
> + (u32)desc->data, desc->dest_id, desc->src_id, desc->flags,
> + desc->qos, desc->padlen, desc->vlan_tci,
> + desc->dst_mac[0], desc->dst_mac[1], desc->dst_mac[2],
> + desc->dst_mac[3], desc->dst_mac[4], desc->dst_mac[5],
> + desc->src_mac[0], desc->src_mac[1], desc->src_mac[2],
> + desc->src_mac[3], desc->src_mac[4], desc->src_mac[5]);
> +#endif
> +}
> +
> +static inline int queue_get_desc(unsigned int queue, struct port *port,
> + int is_tx)
> +{
> + u32 addr, n;
> + struct desc *tab;
> +
> + if (!(addr = qmgr_get_entry(queue)))
> + return -1;
> +
> + addr &= ~0x1F; /* mask out non-address bits */
> + tab = is_tx ? port->tx_desc_tab : port->rx_desc_tab;
> + n = (addr - (u32)tab) / sizeof(struct desc);
> + BUG_ON(n >= (is_tx ? TX_DESCS : RX_DESCS));
> + debug_desc((struct desc*)addr);
> + BUG_ON(tab[n].next);
> + return n;
> +}
> +
> +static inline void queue_put_desc(unsigned int queue, struct desc *desc)
> +{
> + debug_desc(desc);
> + BUG_ON(((u32)desc) & 0x1F);
> + qmgr_put_entry(queue, (u32)desc);
> + /* Don't check for queue overflow here, we've allocated sufficient
> + length and queues >= 32 don't support this check anyway. */
> +}
> +
> +
> +static int ixp4xx_eth_poll(struct eth_device *dev)
> +{
> + struct port *port = dev->priv;
> + struct desc *desc;
> + u8 *buff;
> + int n, len;
> +
> +#if DEBUG_RX
> + fprintf(stderr, "%s%d: eth_poll\n", dev->dev.name, dev->dev.id);
> +#endif
> +
> + if ((n = queue_get_desc(RX_QUEUE(port), port, 0)) < 0) {
> +#if DEBUG_RX
> + fprintf(stderr, "%s%d: eth_poll = no packet received\n", dev->dev.name, dev->dev.id);
> +#endif
> + return 0;
> + }
> +
> + barrier();
> + desc = &port->rx_desc_tab[n];
> + buff = rx_buff(port, n);
> + len = desc->pkt_len;
> + /* process received frame */
> + memcpy((void *)NetRxPackets[0], buff, len);
> + debug_pkt(dev, "RX", desc->data, len);
> +
> + /* put the new buffer on RX-free queue */
> + desc->buf_len = MAX_MRU;
> + desc->pkt_len = 0;
> + queue_put_desc(RXFREE_QUEUE(port), desc);
> +
> + net_receive(NetRxPackets[0], len);
> +
> +#if DEBUG_RX
> + fprintf(stderr, "%s%d: eth_poll end\n", dev->dev.name, dev->dev.id);
> +#endif
> + return 0;
> +}
> +
> +
> +static int ixp4xx_eth_xmit(struct eth_device *dev, void *data, int len)
> +{
> + struct port *port = dev->priv;
> + int n;
> + struct desc *desc;
> +
> +#if DEBUG_TX
> + fprintf(stderr, "%s%d: eth_xmit\n", dev->dev.name, dev->dev.id);
> +#endif
> +
> + if (unlikely(len > 1500))
> + return -1;
> +
> + debug_pkt(dev, "TX", data, len);
> +
> + if ((n = queue_get_desc(TXDONE_QUEUE, port, 1)) < 0)
> + return -1; /* no free buffers */
> + desc = &port->tx_desc_tab[n];
> + desc->data = tx_buff(port, n);
> + desc->buf_len = desc->pkt_len = len;
> + memcpy(desc->data, data, len);
> +
> + /* NPE firmware pads short frames with zeros internally */
> + // wmb();
> + barrier();
> + queue_put_desc(TX_QUEUE(port), desc);
> +
> +#if DEBUG_TX
> + fprintf(stderr, "%s%d: eth_xmit end\n", dev->dev.name, dev->dev.id);
> +#endif
> + return 0;
> +}
> +
> +static void request_queues(struct port *port, struct eth_device *dev)
> +{
> + qmgr_request_queue(RXFREE_QUEUE(port), RX_DESCS, 0, 0, "%s:RX-free", dev->dev.name);
> + qmgr_request_queue(RX_QUEUE(port), RX_DESCS, 0, 0, "%s:RX", dev->dev.name);
> + qmgr_request_queue(TX_QUEUE(port), TX_DESCS, 0, 0, "%s:TX", dev->dev.name);
> +
> + /* Common TX-done queue handles buffers sent out by the NPEs */
> + qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0,
> + "%s:TX-done", dev->dev.name);
> +}
> +
> +static void release_queues(struct port *port)
> +{
> + qmgr_release_queue(RXFREE_QUEUE(port));
> + qmgr_release_queue(RX_QUEUE(port));
> + qmgr_release_queue(TX_QUEUE(port));
> + qmgr_release_queue(TXDONE_QUEUE);
> +}
> +
> +static void init_queues(struct port *port)
> +{
> + int i;
> +
> + memset(port->tx_desc_tab, 0, sizeof(port->tx_desc_tab)); /* descs */
> + memset(port->rx_desc_tab, 0, sizeof(port->rx_desc_tab));
> +
> + /* Setup RX buffers */
> + for (i = 0; i < RX_DESCS; i++) {
> + struct desc *desc = &port->rx_desc_tab[i];
> + desc->buf_len = MAX_MRU;
> + desc->data = rx_buff(port, i);
> + }
> +}
> +
> +static int ixp4xx_eth_open(struct eth_device *dev)
> +{
> + struct port *port = dev->priv;
> + struct npe *npe = port->npe;
> + struct msg msg;
> + int i, err;
> +
> +#if DEBUG_OPEN
> + fprintf(stderr, "%s%d: opening %p\n", dev->dev.name, dev->dev.id, dev);
> +#endif
> +
> + if (!npe_running(npe)) {
> + err = npe_load_firmware(npe);
> + if (err)
> + return err;
> +
> + if (npe_recv_message(npe, &msg, "ETH_GET_STATUS")) {
> + fprintf(stderr, "%s%d: %s not responding\n", dev->dev.name, dev->dev.id, npe->name);
> + return -EIO;
> + }
> + memcpy(port->firmware, msg.params + 2, 4);
> + }
> +
> + if (ixp4xx_adjust_link(dev))
> + return -ENOLINK;
> +
> + port->buff_tab = xmalloc((RX_DESCS + TX_DESCS) * MAX_MRU);
> +
> + memset(&msg, 0, sizeof(msg));
> + msg.cmd = NPE_VLAN_SETRXQOSENTRY;
> + msg.eth_id = LOGICAL_ID(port);
> + msg.params[3] = RX_QUEUE(port) | 0x80;
> + msg.params[4] = RX_QUEUE(port) >> 4; /* MSB of offset */
> + msg.params[5] = RX_QUEUE(port) << 4; /* LSB of offset */
> + for (i = 0; i < 8; i++) {
> + msg.params[1] = i;
> + if (npe_send_recv_message(port->npe, &msg, "ETH_SET_RXQ")) {
> + err = -EIO;
> + goto out;
> + }
> + }
> +
> + msg.cmd = NPE_EDB_SETPORTADDRESS;
> + msg.eth_id = PHYSICAL_ID(port);
> + memcpy(msg.params, port->pinfo->hwaddr, ETH_ALEN);
> + if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAC")) {
> + err = -EIO;
> + goto out;
> + }
> +
> + memset(&msg, 0, sizeof(msg));
> + msg.cmd = NPE_FW_SETFIREWALLMODE;
> + msg.eth_id = LOGICAL_ID(port);
> + if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE")) {
> + err = -EIO;
> + goto out;
> + }
> +
> + request_queues(port, dev);
> + init_queues(port);
> +
> + for (i = 0; i < ETH_ALEN; i++)
> + __raw_writel(port->pinfo->hwaddr[i], &port->regs->hw_addr[i]);
> + __raw_writel(0x08, &port->regs->random_seed);
> + __raw_writel(0x12, &port->regs->partial_empty_threshold);
> + __raw_writel(0x30, &port->regs->partial_full_threshold);
> + __raw_writel(0x08, &port->regs->tx_start_bytes);
> + __raw_writel(0x15, &port->regs->tx_deferral);
> + __raw_writel(0x08, &port->regs->tx_2part_deferral[0]);
> + __raw_writel(0x07, &port->regs->tx_2part_deferral[1]);
> + __raw_writel(0x80, &port->regs->slot_time);
> + __raw_writel(0x01, &port->regs->int_clock_threshold);
> +
> + /* Populate queues with buffers, no failure after this point */
> + for (i = 0; i < TX_DESCS; i++)
> + queue_put_desc(TXDONE_QUEUE, &port->tx_desc_tab[i]);
> +
> + for (i = 0; i < RX_DESCS; i++)
> + queue_put_desc(RXFREE_QUEUE(port), &port->rx_desc_tab[i]);
> +
> + __raw_writel(TX_CNTRL1_RETRIES, &port->regs->tx_control[1]);
> + __raw_writel(DEFAULT_TX_CNTRL0, &port->regs->tx_control[0]);
> + __raw_writel(0, &port->regs->rx_control[1]);
> + __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);
> +
> +#if 0
> + qmgr_set_irq(RX_QUEUE(port), QUEUE_IRQ_SRC_NOT_EMPTY,
> + eth_rx_irq, dev);
> + qmgr_set_irq(TXDONE_QUEUE, QUEUE_IRQ_SRC_NOT_EMPTY,
> + eth_txdone_irq, NULL);
> + qmgr_enable_irq(TXDONE_QUEUE);
> +#endif
> + memset(&msg, 0, sizeof(msg));
> +#if DEBUG_OPEN
> + fprintf(stderr, "%s%d opened\n", dev->dev.name, dev->dev.id);
> +#endif
> + return 0;
> +out:
> + free(port->buff_tab);
> + port->buff_tab = NULL;
> +#if DEBUG_OPEN
> + fprintf(stderr, "%s%d open failed (%i)\n", dev->dev.name, dev->dev.id, err);
> +#endif
> + return err;
> +}
> +
> +static void ixp4xx_eth_close(struct eth_device *dev)
> +{
> + struct port *port = dev->priv;
> + struct msg msg;
> + int buffs = RX_DESCS; /* allocated RX buffers */
> + int i;
> +
> +#if DEBUG_CLOSE
> + fprintf(stderr, "%s%d: closing\n", dev->dev.name, dev->dev.id);
> +#endif
> +#if 0
> + qmgr_disable_irq(RX_QUEUE(port));
> +#endif
> +
> + if (!port->buff_tab)
> + return; /* already closed */
> +
> + while (queue_get_desc(RXFREE_QUEUE(port), port, 0) >= 0)
> + buffs--;
> +
> + memset(&msg, 0, sizeof(msg));
> + msg.cmd = NPE_SETLOOPBACK_MODE;
> + msg.eth_id = LOGICAL_ID(port);
> + msg.params[1] = 1;
> + if (npe_send_recv_message(port->npe, &msg, "ETH_ENABLE_LOOPBACK"))
> + fprintf(stderr, "%s%d: unable to enable loopback\n", dev->dev.name, dev->dev.id);
> +
> +#if DEBUG_CLOSE
> + fprintf(stderr, "%s%d: draining RX queue\n", dev->dev.name, dev->dev.id);
> +#endif
> + i = 0;
> + do { /* drain RX buffers */
> + while (queue_get_desc(RX_QUEUE(port), port, 0) >= 0)
> + buffs--;
> + if (!buffs)
> + break;
> + if (qmgr_stat_full(TXDONE_QUEUE) && !(i % 10)) {
> + /* we have to inject some packet */
> + struct desc *desc;
> + int n = queue_get_desc(TXDONE_QUEUE, port, 1);
> + BUG_ON(n < 0);
> + desc = &port->tx_desc_tab[n];
> + desc->buf_len = desc->pkt_len = 1;
> + //wmb();
> + barrier();
> + queue_put_desc(TX_QUEUE(port), desc);
> + }
> + udelay(1);
> + } while (++i < MAX_CLOSE_WAIT);
> +
> + if (buffs)
> + fprintf(stderr, "%s%d: unable to drain RX queue, %i buffer(s) left in NPE\n",
> + dev->dev.name, dev->dev.id, buffs);
> +#if DEBUG_CLOSE
> + if (!buffs)
> + fprintf(stderr, "%s%d: draining RX queue took %i cycles\n", dev->dev.name, dev->dev.id, i);
> +#endif
> +
> + buffs = TX_DESCS;
> + while (queue_get_desc(TX_QUEUE(port), port, 1) >= 0)
> + buffs--; /* cancel TX */
> +
> + i = 0;
> + do {
> + while (queue_get_desc(TXDONE_QUEUE, port, 1) >= 0)
> + buffs--;
> + if (!buffs)
> + break;
> + } while (++i < MAX_CLOSE_WAIT);
> +
> + if (buffs)
> + fprintf(stderr, "%s%d: unable to drain TX queue, %i buffer(s) left in NPE\n",
> + dev->dev.name, dev->dev.id, buffs);
> +#if DEBUG_CLOSE
> + if (!buffs)
> + fprintf(stderr, "%s%d: draining TX queues took %i cycles\n", dev->dev.name, dev->dev.id, i);
> +#endif
> +
> + msg.params[1] = 0;
> + if (npe_send_recv_message(port->npe, &msg, "ETH_DISABLE_LOOPBACK"))
> + fprintf(stderr, "%s%d: unable to disable loopback\n", dev->dev.name, dev->dev.id);
> +
> +#if 0
> + qmgr_disable_irq(TXDONE_QUEUE);
> +#endif
> + release_queues(port);
> + free(port->buff_tab);
> + port->buff_tab = NULL;
> +#if DEBUG_CLOSE
> + fprintf(stderr, "%s%d: closed\n", dev->dev.name, dev->dev.id);
> +#endif
> +}
> +
> +static int ixp4xx_eth_get_hwaddr(struct eth_device *eth, unsigned char *addr)
> +{
> + struct port *port = eth->priv;
> + memcpy(addr, port->pinfo->hwaddr, 6);
> + return 0;
> +}
> +
> +static int ixp4xx_eth_set_hwaddr(struct eth_device *eth, unsigned char *addr)
> +{
> + struct port *port = eth->priv;
> + memcpy(port->pinfo->hwaddr, addr, 6);
> + return 0;
> +}
> +
> +static int ixp4xx_eth_init(struct eth_device *eth)
> +{
> + struct port *port = eth->priv;
> +
> + __raw_writel(DEFAULT_CORE_CNTRL | CORE_RESET,
> + &port->regs->core_control);
> + udelay(50);
> + __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
> + udelay(50);
> +
> + miidev_restart_aneg(&port->miidev);
> + return 0;
> +}
> +
> +static int ixp4xx_eth_probe(struct device_d *dev)
> +{
> + struct npe *npe;
> + struct port *port;
> + struct eth_plat_info *pinfo = dev->platform_data;
> +
> + if (!pinfo) {
> + fprintf(stderr, "ixp4xx_eth: no platform information\n");
> + return -ENODEV;
> + }
> +
> + if (!(npe = npe_request(pinfo->npe))) {
> + fprintf(stderr, "ixp4xx_eth: unable to acquire NPE\n");
> + return -ENODEV;
> + }
> +
> + port = memalign(0x20, sizeof(*port));
> + memset(port, 0, sizeof(*port));
> +
> + port->regs = pinfo->regs;
> + port->npe = npe;
> + port->pinfo = pinfo;
> + port->eth.dev.id = -1;
> + port->eth.priv = port;
> + port->eth.init = ixp4xx_eth_init;
> + port->eth.open = ixp4xx_eth_open;
> + port->eth.halt = ixp4xx_eth_close;
> + port->eth.send = ixp4xx_eth_xmit;
> + port->eth.recv = ixp4xx_eth_poll;
> + port->eth.get_ethaddr = ixp4xx_eth_get_hwaddr;
> + port->eth.set_ethaddr = ixp4xx_eth_set_hwaddr;
> +
> + port->miidev.dev.id = -1;
> + port->miidev.read = ixp4xx_mdio_read;
> + port->miidev.write = ixp4xx_mdio_write;
> + port->miidev.address = pinfo->phy;
> + port->miidev.edev = &port->eth;
> + mii_register(&port->miidev);
> + eth_register(&port->eth);
> + return 0;
> +}
> +
> +static struct driver_d ixp4xx_eth_driver = {
> + .name = "ixp4xx_eth",
> + .probe = ixp4xx_eth_probe,
> +};
> +
> +static int __init ixp4xx_eth_module_init(void)
> +{
> + if (cpu_is_ixp43x()) {
> + /* IXP43x lacks NPE-B and uses NPE-C for MII PHY access */
> + if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEC_ETH))
> + return -ENOSYS;
> + mdio_regs = (struct eth_regs *)IXP4XX_EthC_BASE;
> + } else {
> + /* All MII PHY accesses use NPE-B Ethernet registers */
> + if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
> + return -ENOSYS;
> + mdio_regs = (struct eth_regs *)IXP4XX_EthB_BASE;
> + }
> +
> + __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
> +
> + register_driver(&ixp4xx_eth_driver);
> + return 0;
> +}
> +
> +device_initcall(ixp4xx_eth_module_init);
> diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
> index 290619f..0f25ceb 100644
> --- a/drivers/serial/serial_ns16550.c
> +++ b/drivers/serial/serial_ns16550.c
> @@ -102,7 +102,11 @@ static void ns16550_serial_init_port(struct console_device *cdev)
> baud_divisor = ns16550_calc_divisor(cdev, CONFIG_BAUDRATE);
>
> /* initializing the device for the first time */
> +#ifdef CONFIG_ARCH_IXP4XX
> + plat->reg_write(IER_UUE, base, ier); /* Enable UART operation */
> +#else
> plat->reg_write(0x00, base, ier);
> +#endif
> #ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
> plat->reg_write(0x07, base, mdr1); /* Disable */
> #endif
> @@ -181,7 +185,11 @@ static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate)
> cdev->dev->platform_data;
> unsigned long base = cdev->dev->map_base;
> unsigned int baud_divisor = ns16550_calc_divisor(cdev, baud_rate);
> +#ifdef CONFIG_ARCH_IXP4XX
> + plat->reg_write(IER_UUE, base, ier); /* Enable UART operation */
> +#else
> plat->reg_write(0x00, base, ier);
> +#endif
> plat->reg_write(LCR_BKSE, base, lcr);
> plat->reg_write(baud_divisor & 0xff, base, dll);
> plat->reg_write((baud_divisor >> 8) & 0xff, base, dlm);
> diff --git a/drivers/serial/serial_ns16550.h b/drivers/serial/serial_ns16550.h
> index eb2fd10..ba20a6f 100644
> --- a/drivers/serial/serial_ns16550.h
> +++ b/drivers/serial/serial_ns16550.h
> @@ -50,6 +50,8 @@
> #define dll rbr
> #define dlm ier
>
> +#define IER_UUE 0x40 /* UART Unit Enable (XScale) */
> +
> #define FCR_FIFO_EN 0x01 /* Fifo enable */
> #define FCR_RXSR 0x02 /* Receiver soft reset */
> #define FCR_TXSR 0x04 /* Transmitter soft reset */
>
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
>
thanks,
marek
--
as simple and primitive as possible
-------------------------------------------------
Marek Belisko - OPEN-NANDRA
Freelance Developer
Ruska Nova Ves 219 | Presov, 08005 Slovak Republic
Tel: +421 915 052 184
skype: marekwhite
icq: 290551086
web: http://open-nandra.com
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-21 7:42 ` Belisko Marek
@ 2010-12-21 9:25 ` Sascha Hauer
2010-12-21 9:30 ` Juergen Beisert
1 sibling, 0 replies; 41+ messages in thread
From: Sascha Hauer @ 2010-12-21 9:25 UTC (permalink / raw)
To: Belisko Marek; +Cc: barebox, Krzysztof Halasa
On Tue, Dec 21, 2010 at 08:42:41AM +0100, Belisko Marek wrote:
> Hi,
>
> On Tue, Dec 21, 2010 at 12:06 AM, Krzysztof Halasa <khc@pm.waw.pl> wrote:
> > Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
> >
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 8cb86cb..56b5a0d 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -39,6 +39,13 @@ config ARCH_IMX
> > bool "Freescale iMX-based"
> > select GENERIC_GPIO
> >
> > +config ARCH_IXP4XX
> > + bool "Intel IXP4xx-based"
> > + select CPU_32v5
> > + select ARCH_SUPPORTS_BIG_ENDIAN
> > + select CPU_BIG_ENDIAN
> > + select ARCH_HAS_LOWLEVEL_INIT
> > +
> Should go to different Kconfig. This is ARM related and you have
> intel cpu which is possibly x86. Also in other patches you stick to ARM
> but your CPU doesn't have ARM core.
The ixp4xx actually is an ARM processor.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-21 7:42 ` Belisko Marek
2010-12-21 9:25 ` Sascha Hauer
@ 2010-12-21 9:30 ` Juergen Beisert
1 sibling, 0 replies; 41+ messages in thread
From: Juergen Beisert @ 2010-12-21 9:30 UTC (permalink / raw)
To: Belisko Marek; +Cc: barebox, Krzysztof Halasa
Belisko Marek wrote:
> On Tue, Dec 21, 2010 at 12:06 AM, Krzysztof Halasa <khc@pm.waw.pl> wrote:
> > Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
> >
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 8cb86cb..56b5a0d 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -39,6 +39,13 @@ config ARCH_IMX
> > bool "Freescale iMX-based"
> > select GENERIC_GPIO
> >
> > +config ARCH_IXP4XX
> > + bool "Intel IXP4xx-based"
> > + select CPU_32v5
> > + select ARCH_SUPPORTS_BIG_ENDIAN
> > + select CPU_BIG_ENDIAN
> > + select ARCH_HAS_LOWLEVEL_INIT
> > +
>
> Should go to different Kconfig. This is ARM related and you have
> intel cpu which is possibly x86. Also in other patches you stick to ARM
> but your CPU doesn't have ARM core.
Hmm, IPX4xx is ARM (AFAIK).
jbe
--
Pengutronix e.K. | Juergen Beisert |
Linux Solutions for Science and Industry | Phone: +49-8766-939 228 |
Vertretung Sued/Muenchen, Germany | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de/ |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-20 23:06 ` [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Krzysztof Halasa
2010-12-21 7:42 ` Belisko Marek
@ 2010-12-21 8:35 ` Sascha Hauer
2010-12-22 0:48 ` Krzysztof Halasa
2010-12-22 0:57 ` Jean-Christophe PLAGNIOL-VILLARD
2 siblings, 1 reply; 41+ messages in thread
From: Sascha Hauer @ 2010-12-21 8:35 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
Hi Krzysztof,
Nice series! I haven't got much to add.
On Tue, Dec 21, 2010 at 12:06:12AM +0100, Krzysztof Halasa wrote:
> +
> + devfs_add_partition("nor0", BAREBOX_START, BAREBOX_LENGTH,
> + DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "barebox");
> + devfs_add_partition("nor0", NPE_A_START, NPE_A_LENGTH,
> + DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-A");
> + devfs_add_partition("nor0", NPE_B_START, NPE_B_LENGTH,
> + DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-B");
> + devfs_add_partition("nor0", NPE_C_START, NPE_C_LENGTH,
> + DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-C");
> + devfs_add_partition("nor0", NPE_ENV0_START, NPE_ENV0_LENGTH,
> + DEVFS_PARTITION_FIXED, "env0");
These partitions are not on eraseblock boundaries, so I assume you use
some script to combine barebox and firmware into a single image. Can we
integrate this into the make system or at least add some instructions
how to generate this image?
> +
> +#ifdef CONFIG_USE_IRQ
> +
> +static void (*irq_handlers[HALF_QUEUES])(void *pdev);
> +static void *irq_pdevs[HALF_QUEUES];
> +
> +#undef fls
> +static inline int fls(int x)
> +{
> + int ret;
> + asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
> + ret = 32 - ret;
> + return ret;
> +}
fls is defined in a similar way in arch/arm/include/asm/bitops.h:
#define fls(x) \
(__builtin_constant_p(x) ? constant_fls(x) : \
({ int __r; asm("clz\t%0, %1" : "=r"(__r) : "r"(x) : "cc"); 32-__r; }))
Or am I missing something?
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-21 8:35 ` Sascha Hauer
@ 2010-12-22 0:48 ` Krzysztof Halasa
0 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-22 0:48 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox
Sascha Hauer <s.hauer@pengutronix.de> writes:
> These partitions are not on eraseblock boundaries, so I assume you use
> some script to combine barebox and firmware into a single image. Can we
> integrate this into the make system or at least add some instructions
> how to generate this image?
I patch them in flash with JTAG/OpenOCD, guess that's not what most
people will do. Added some instructions, it should be pretty clear now
(the NPE microcode files aren't going to change, Intel seems to have
finalized the IXP42x support at version 2.4).
>> +#ifdef CONFIG_USE_IRQ
>> +
>> +static void (*irq_handlers[HALF_QUEUES])(void *pdev);
>> +static void *irq_pdevs[HALF_QUEUES];
>> +
>> +#undef fls
>> +static inline int fls(int x)
>> +{
>> + int ret;
>> + asm("clz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
>> + ret = 32 - ret;
>> + return ret;
>> +}
>
> fls is defined in a similar way in arch/arm/include/asm/bitops.h:
>
> #define fls(x) \
> (__builtin_constant_p(x) ? constant_fls(x) : \
> ({ int __r; asm("clz\t%0, %1" : "=r"(__r) : "r"(x) : "cc"); 32-__r; }))
>
> Or am I missing something?
Looks like u-boot (v.1) doesn't have it, I was thinking of using u-boot
instead at first. Removed (I don't use CONFIG_USE_IRQ anyway).
WRT endianness switching, I added a couple of #ifdefs. It seems
gcc-4.4.x with EABI can optimize the unused "swap" parameter out, even
without actually inlining the function.
--
Krzysztof Halasa
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-20 23:06 ` [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Krzysztof Halasa
2010-12-21 7:42 ` Belisko Marek
2010-12-21 8:35 ` Sascha Hauer
@ 2010-12-22 0:57 ` Jean-Christophe PLAGNIOL-VILLARD
2010-12-22 12:46 ` Sascha Hauer
2010-12-22 19:13 ` Krzysztof Halasa
2 siblings, 2 replies; 41+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-12-22 0:57 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
> +
> +#define BAREBOX_START 0x00000
> +#define BAREBOX_LENGTH 0x34000
> +#define NPE_A_START (BAREBOX_START + BAREBOX_LENGTH)
> +#define NPE_A_LENGTH 0x05000
> +#define NPE_B_START (NPE_A_START + NPE_A_LENGTH)
> +#define NPE_B_LENGTH 0x03000
> +#define NPE_C_START (NPE_B_START + NPE_B_LENGTH)
> +#define NPE_C_LENGTH 0x04000
> +#define NPE_ENV0_START (NPE_C_START + NPE_C_LENGTH)
> +#define NPE_ENV0_LENGTH 0x20000
why not put the NPE firmware in the env?
btw you have a lots of whitespace please use tab for indent
Best Regards,
J.
> +
> +static struct clocksource cs = {
> + .read = ixp4xx_clocksource_read,
> + .mask = 0xffffffff,
please use CLOCKSOURCE_MASK
> + .shift = 10,
> +};
> diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
> index 290619f..0f25ceb 100644
> --- a/drivers/serial/serial_ns16550.c
> +++ b/drivers/serial/serial_ns16550.c
please do this in a seperate patch
> @@ -102,7 +102,11 @@ static void ns16550_serial_init_port(struct console_device *cdev)
> baud_divisor = ns16550_calc_divisor(cdev, CONFIG_BAUDRATE);
>
> /* initializing the device for the first time */
> +#ifdef CONFIG_ARCH_IXP4XX
> + plat->reg_write(IER_UUE, base, ier); /* Enable UART operation */
> +#else
> plat->reg_write(0x00, base, ier);
> +#endif
> #ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
> plat->reg_write(0x07, base, mdr1); /* Disable */
> #endif
> @@ -181,7 +185,11 @@ static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate)
> cdev->dev->platform_data;
> unsigned long base = cdev->dev->map_base;
> unsigned int baud_divisor = ns16550_calc_divisor(cdev, baud_rate);
> +#ifdef CONFIG_ARCH_IXP4XX
> + plat->reg_write(IER_UUE, base, ier); /* Enable UART operation */
> +#else
> plat->reg_write(0x00, base, ier);
> +#endif
> plat->reg_write(LCR_BKSE, base, lcr);
> plat->reg_write(baud_divisor & 0xff, base, dll);
> plat->reg_write((baud_divisor >> 8) & 0xff, base, dlm);
> diff --git a/drivers/serial/serial_ns16550.h b/drivers/serial/serial_ns16550.h
> index eb2fd10..ba20a6f 100644
> --- a/drivers/serial/serial_ns16550.h
> +++ b/drivers/serial/serial_ns16550.h
> @@ -50,6 +50,8 @@
> #define dll rbr
> #define dlm ier
>
> +#define IER_UUE 0x40 /* UART Unit Enable (XScale) */
> +
> #define FCR_FIFO_EN 0x01 /* Fifo enable */
> #define FCR_RXSR 0x02 /* Receiver soft reset */
> #define FCR_TXSR 0x04 /* Transmitter soft reset */
>
Best Regards,
J.
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-22 0:57 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2010-12-22 12:46 ` Sascha Hauer
2010-12-22 19:36 ` Krzysztof Halasa
2010-12-22 19:13 ` Krzysztof Halasa
1 sibling, 1 reply; 41+ messages in thread
From: Sascha Hauer @ 2010-12-22 12:46 UTC (permalink / raw)
To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox, Krzysztof Halasa
On Wed, Dec 22, 2010 at 01:57:22AM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > +
> > +#define BAREBOX_START 0x00000
> > +#define BAREBOX_LENGTH 0x34000
> > +#define NPE_A_START (BAREBOX_START + BAREBOX_LENGTH)
> > +#define NPE_A_LENGTH 0x05000
> > +#define NPE_B_START (NPE_A_START + NPE_A_LENGTH)
> > +#define NPE_B_LENGTH 0x03000
> > +#define NPE_C_START (NPE_B_START + NPE_B_LENGTH)
> > +#define NPE_C_LENGTH 0x04000
> > +#define NPE_ENV0_START (NPE_C_START + NPE_C_LENGTH)
> > +#define NPE_ENV0_LENGTH 0x20000
> why not put the NPE firmware in the env?
That's a good idea. This way we can tell the users to put the firmware
to arch/arm/boards/.../env/firmware before compilation and avoid
redistribution problems if there are any. Another plus is that the
barebox binary is not larger than it has to be.
The only downside is that the environment gets bigger as it duplicates
the firmware, but even this could be avoided if we add a second (non
environment) filesystem image.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-22 12:46 ` Sascha Hauer
@ 2010-12-22 19:36 ` Krzysztof Halasa
2010-12-23 3:26 ` Jean-Christophe PLAGNIOL-VILLARD
0 siblings, 1 reply; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-22 19:36 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox
Sascha Hauer <s.hauer@pengutronix.de> writes:
>> why not put the NPE firmware in the env?
>
> That's a good idea. This way we can tell the users to put the firmware
> to arch/arm/boards/.../env/firmware before compilation and avoid
> redistribution problems if there are any. Another plus is that the
> barebox binary is not larger than it has to be.
> The only downside is that the environment gets bigger as it duplicates
> the firmware, but even this could be avoided if we add a second (non
> environment) filesystem image.
Actually, there is more. There is plenty of free space in Barebox'
region (2 pages 128 KB each), and the microcode isn't likely to ever
change (unless Intel releases docs/sources, of course).
I don't want it in user-writable area since it could be incidentally
erased. Without the microcode Ethernet interfaces are not functional,
and I'm not sure all users would appreciate it if they had to download
it back with [XY]-modem (or another C-kermit) :-) Even TFTP is sometimes
black magic for some of them.
Obviously, the microcode is optional, and especially NPE-A one isn't at
all used by Barebox (Linux uses it for driving sync serial interfaces).
I don't consider the microcode a part of Barebox, like the
/lib/firmware/* blobs aren't part of Linux.
Also it's simpler to export the microcode to Linux when it's in fixed
well-aligned locations.
--
Krzysztof Halasa
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-22 19:36 ` Krzysztof Halasa
@ 2010-12-23 3:26 ` Jean-Christophe PLAGNIOL-VILLARD
2010-12-23 11:42 ` Krzysztof Halasa
0 siblings, 1 reply; 41+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-12-23 3:26 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
On 20:36 Wed 22 Dec , Krzysztof Halasa wrote:
> Sascha Hauer <s.hauer@pengutronix.de> writes:
>
> >> why not put the NPE firmware in the env?
> >
> > That's a good idea. This way we can tell the users to put the firmware
> > to arch/arm/boards/.../env/firmware before compilation and avoid
> > redistribution problems if there are any. Another plus is that the
> > barebox binary is not larger than it has to be.
> > The only downside is that the environment gets bigger as it duplicates
> > the firmware, but even this could be avoided if we add a second (non
> > environment) filesystem image.
>
> Actually, there is more. There is plenty of free space in Barebox'
> region (2 pages 128 KB each), and the microcode isn't likely to ever
> change (unless Intel releases docs/sources, of course).
>
> I don't want it in user-writable area since it could be incidentally
> erased. Without the microcode Ethernet interfaces are not functional,
> and I'm not sure all users would appreciate it if they had to download
> it back with [XY]-modem (or another C-kermit) :-) Even TFTP is sometimes
> black magic for some of them.
>
> Obviously, the microcode is optional, and especially NPE-A one isn't at
> all used by Barebox (Linux uses it for driving sync serial interfaces).
> I don't consider the microcode a part of Barebox, like the
> /lib/firmware/* blobs aren't part of Linux.
>
> Also it's simpler to export the microcode to Linux when it's in fixed
> well-aligned locations.
I'm working on a fs support in linux of the barebox env
so linux could get it easly also
but I prefer to be able to change my micro code as some of the people who work
on IXP have acess to it to modify it. So I think its a good option
so as linux it will be better to put it in a fs like /lib/firmware
Best Regards,
J.
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-23 3:26 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2010-12-23 11:42 ` Krzysztof Halasa
0 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-23 11:42 UTC (permalink / raw)
To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox
Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> writes:
> I'm working on a fs support in linux of the barebox env
>
> so linux could get it easly also
If I can put the original copy in RO blocks and use some sort of unionfs
to make it RW, and even better, to export it to Linux easily, then it
may be a way to go for me, too. Meanwhile I have to use what's already
available.
> but I prefer to be able to change my micro code as some of the people who work
> on IXP have acess to it to modify it. So I think its a good option
IOW you (and/or people you know) do have means to change the microcode?
E.g. some documentation, tools (assembler?) or something like that?
Is it something you could make available to me? I'd be interested in
hacking (at least) the NPE-A HSS microcode, though at present, without
any docs, the amount of work needed is prohibitive.
BTW different boards can supply the microcode using different means.
--
Krzysztof Halasa
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-22 0:57 ` Jean-Christophe PLAGNIOL-VILLARD
2010-12-22 12:46 ` Sascha Hauer
@ 2010-12-22 19:13 ` Krzysztof Halasa
1 sibling, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-22 19:13 UTC (permalink / raw)
To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox
Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> writes:
>> +#define BAREBOX_START 0x00000
>> +#define BAREBOX_LENGTH 0x34000
>> +#define NPE_A_START (BAREBOX_START + BAREBOX_LENGTH)
>> +#define NPE_A_LENGTH 0x05000
>> +#define NPE_B_START (NPE_A_START + NPE_A_LENGTH)
>> +#define NPE_B_LENGTH 0x03000
>> +#define NPE_C_START (NPE_B_START + NPE_B_LENGTH)
>> +#define NPE_C_LENGTH 0x04000
>> +#define NPE_ENV0_START (NPE_C_START + NPE_C_LENGTH)
>> +#define NPE_ENV0_LENGTH 0x20000
>
> btw you have a lots of whitespace please use tab for indent
Well, I try to use tabs for syntactic indentation exclusively.
I admit I haven't checked the patches for this, and some spaces could
have slipped through e.g. copy+paste. Will check.
OTOH I use spaces for visual alignment (as shown above) and I consider
it the right thing. It makes the text display correctly with any tab
length setting. This has been somehow agreed on linux-kernel (though
definitely not unanimously) and I think Barebox tries to duplicate Linux
coding style.
Not that it matters a lot, can change it all to tabs if that's what
Barebox needs.
--
Krzysztof Halasa
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 11] Silence few warnings.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (9 preceding siblings ...)
2010-12-20 23:06 ` [PATCH 10] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Krzysztof Halasa
@ 2010-12-20 23:08 ` Krzysztof Halasa
2010-12-20 23:10 ` [PATCH 12] Fix NOR CFI flash driver to work on big endian systems Krzysztof Halasa
` (5 subsequent siblings)
16 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 23:08 UTC (permalink / raw)
To: barebox
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/common/startup.c b/common/startup.c
index e8c0e7a..be70245 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -56,7 +56,7 @@ static void display_meminfo(void)
printf("Malloc space: 0x%08lx -> 0x%08lx (size %s)\n",
mstart, mend, size_human_readable(msize));
#ifdef CONFIG_ARM
- printf("Stack space : 0x%08lx -> 0x%08lx (size %s)\n",
+ printf("Stack space : 0x%08x -> 0x%08x (size %s)\n",
STACK_BASE, STACK_BASE + STACK_SIZE,
size_human_readable(STACK_SIZE));
#endif
diff --git a/lib/readline.c b/lib/readline.c
index b90de77..a3e1de9 100644
--- a/lib/readline.c
+++ b/lib/readline.c
@@ -140,7 +140,7 @@ static char* hist_next(void)
static void cread_add_char(char ichar, int insert, unsigned long *num,
unsigned long *eol_num, char *buf, unsigned long len)
{
- unsigned long wlen;
+ unsigned wlen;
/* room ??? */
if (insert || *num == *eol_num) {
@@ -177,7 +177,7 @@ int readline(const char *prompt, char *buf, int len)
unsigned long num = 0;
unsigned long eol_num = 0;
unsigned long rlen;
- unsigned long wlen;
+ unsigned wlen;
int ichar;
int insert = 1;
int rc = 0;
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 12] Fix NOR CFI flash driver to work on big endian systems.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (10 preceding siblings ...)
2010-12-20 23:08 ` [PATCH 11] Silence few warnings Krzysztof Halasa
@ 2010-12-20 23:10 ` Krzysztof Halasa
2010-12-22 1:01 ` Jean-Christophe PLAGNIOL-VILLARD
2010-12-20 23:14 ` [PATCH 13] Fix usage of __LITTLE_ENDIAN macro Krzysztof Halasa
` (4 subsequent siblings)
16 siblings, 1 reply; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 23:10 UTC (permalink / raw)
To: barebox
Fix NOR CFI flash driver to work on big endian systems.
Basically this transforms the u8/u16/u32/u64 union into
a single u64 value.
Not tested on LE platform. Apply with caution.
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/drivers/nor/cfi_flash.c b/drivers/nor/cfi_flash.c
index 90307d2..34031b0 100644
--- a/drivers/nor/cfi_flash.c
+++ b/drivers/nor/cfi_flash.c
@@ -77,59 +77,40 @@ static uint flash_offset_cfi[2]={FLASH_OFFSET_CFI,FLASH_OFFSET_CFI_ALT};
static void flash_add_byte (struct flash_info *info, cfiword_t * cword, uchar c)
{
-#if defined(__LITTLE_ENDIAN)
- unsigned short w;
- unsigned int l;
- unsigned long long ll;
-#endif
-
if (bankwidth_is_1(info)) {
- cword->c = c;
- } else if (bankwidth_is_2(info)) {
-#if defined(__LITTLE_ENDIAN)
- w = c;
- w <<= 8;
- cword->w = (cword->w >> 8) | w;
-#else
- cword->w = (cword->w << 8) | c;
-#endif
- } else if (bankwidth_is_4(info)) {
-#if defined(__LITTLE_ENDIAN)
- l = c;
- l <<= 24;
- cword->l = (cword->l >> 8) | l;
-#else
- cword->l = (cword->l << 8) | c;
-#endif
- } else if (bankwidth_is_8(info)) {
-#if defined(__LITTLE_ENDIAN)
- ll = c;
- ll <<= 56;
- cword->ll = (cword->ll >> 8) | ll;
+ *cword = c;
+ return;
+ }
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+ *cword = (*cword << 8) | c;
#else
- cword->ll = (cword->ll << 8) | c;
+
+ if (bankwidth_is_2(info))
+ *cword = (*cword >> 8) | (u16)c << 8;
+ else if (bankwidth_is_4(info))
+ *cword = (*cword >> 8) | (u32)c << 24;
+ else if (bankwidth_is_8(info))
+ *cword = (*cword >> 8) | (u64)c << 56;
#endif
- }
}
static int flash_write_cfiword (struct flash_info *info, ulong dest,
cfiword_t cword)
{
- void *dstaddr;
+ void *dstaddr = (void *)dest;
int flag;
- dstaddr = (uchar *) dest;
-
/* Check if Flash is (sufficiently) erased */
- if (bankwidth_is_1(info)) {
- flag = ((flash_read8(dstaddr) & cword.c) == cword.c);
- } else if (bankwidth_is_2(info)) {
- flag = ((flash_read16(dstaddr) & cword.w) == cword.w);
- } else if (bankwidth_is_4(info)) {
- flag = ((flash_read32(dstaddr) & cword.l) == cword.l);
- } else if (bankwidth_is_8(info)) {
- flag = ((flash_read64(dstaddr) & cword.ll) == cword.ll);
- } else
+ if (bankwidth_is_1(info))
+ flag = ((flash_read8(dstaddr) & cword) == cword);
+ else if (bankwidth_is_2(info))
+ flag = ((flash_read16(dstaddr) & cword) == cword);
+ else if (bankwidth_is_4(info))
+ flag = ((flash_read32(dstaddr) & cword) == cword);
+ else if (bankwidth_is_8(info))
+ flag = ((flash_read64(dstaddr) & cword) == cword);
+ else
return 2;
if (!flag)
@@ -185,10 +166,8 @@ static void flash_printqry (struct cfi_qry *qry)
*/
uchar flash_read_uchar (struct flash_info *info, uint offset)
{
- uchar *cp;
-
- cp = flash_make_addr (info, 0, offset);
-#if defined(__LITTLE_ENDIAN)
+ uchar *cp = flash_make_addr(info, 0, offset);
+#if __BYTE_ORDER == __LITTLE_ENDIAN
return flash_read8(cp);
#else
return flash_read8(cp + info->portwidth - 1);
@@ -216,7 +195,7 @@ static ulong flash_read_long (struct flash_info *info, flash_sect_t sect, uint o
debug ("addr[%x] = 0x%x\n", x, flash_read8(addr + x));
}
#endif
-#if defined(__LITTLE_ENDIAN)
+#if __BYTE_ORDER == __LITTLE_ENDIAN
retval = ((flash_read8(addr) << 16) |
(flash_read8(addr + info->portwidth) << 24) |
(flash_read8(addr + 2 * info->portwidth)) |
@@ -534,7 +513,7 @@ static int write_buff (struct flash_info *info, const uchar * src, ulong addr, u
/* handle unaligned start */
if ((aln = addr - wp) != 0) {
- cword.l = 0;
+ cword = 0;
p = (uchar*)wp;
for (i = 0; i < aln; ++i)
flash_add_byte (info, &cword, flash_read8(p + i));
@@ -560,7 +539,7 @@ static int write_buff (struct flash_info *info, const uchar * src, ulong addr, u
while (cnt >= info->portwidth) {
/* prohibit buffer write when buffer_size is 1 */
if (info->buffer_size == 1) {
- cword.l = 0;
+ cword = 0;
for (i = 0; i < info->portwidth; i++)
flash_add_byte (info, &cword, *src++);
if ((rc = flash_write_cfiword (info, wp, cword)) != 0)
@@ -583,7 +562,7 @@ static int write_buff (struct flash_info *info, const uchar * src, ulong addr, u
}
#else
while (cnt >= info->portwidth) {
- cword.l = 0;
+ cword = 0;
for (i = 0; i < info->portwidth; i++) {
flash_add_byte (info, &cword, *src++);
}
@@ -600,7 +579,7 @@ static int write_buff (struct flash_info *info, const uchar * src, ulong addr, u
/*
* handle unaligned tail bytes
*/
- cword.l = 0;
+ cword = 0;
p = (uchar*)wp;
for (i = 0; (i < info->portwidth) && (cnt > 0); ++i) {
flash_add_byte (info, &cword, *src++);
@@ -672,7 +651,7 @@ static ssize_t cfi_write(struct cdev *cdev, const void *buf, size_t count, unsig
struct flash_info *finfo = (struct flash_info *)cdev->priv;
int ret;
- debug("cfi_write: buf=0x%08x addr=0x%08x count=0x%08x\n",buf, cdev->dev->map_base + offset, count);
+ debug("cfi_write: buf=0x%p addr=0x%08lx count=0x%08x\n",buf, cdev->dev->map_base + offset, count);
ret = write_buff (finfo, buf, cdev->dev->map_base + offset, count);
return ret == 0 ? count : -1;
@@ -836,17 +815,14 @@ int flash_generic_status_check (struct flash_info *info, flash_sect_t sector,
/*
* make a proper sized command based on the port and chip widths
*/
-void flash_make_cmd (struct flash_info *info, uchar cmd, void *cmdbuf)
+void flash_make_cmd(struct flash_info *info, u8 cmd, cfiword_t *cmdbuf)
{
- int i;
- uchar *cp = (uchar *) cmdbuf;
+ cfiword_t result = 0;
+ int i = info->portwidth / info->chipwidth;
-#if defined(__LITTLE_ENDIAN)
- for (i = info->portwidth; i > 0; i--)
-#else
- for (i = 1; i <= info->portwidth; i++)
-#endif
- *cp++ = (i & (info->chipwidth - 1)) ? '\0' : cmd;
+ while (i--)
+ result = (result << (8 * info->chipwidth)) | cmd;
+ *cmdbuf = result;
}
/*
@@ -860,6 +836,7 @@ void flash_write_cmd (struct flash_info *info, flash_sect_t sect, uint offset, u
addr = flash_make_addr (info, sect, offset);
flash_make_cmd (info, cmd, &cword);
+ debug("%s: %p %lX %X => %p %llX\n", __FUNCTION__, info, sect, offset, addr, cword);
flash_write_word(info, cword, addr);
}
@@ -874,14 +851,14 @@ int flash_isequal (struct flash_info *info, flash_sect_t sect, uint offset, ucha
debug ("is= cmd %x(%c) addr %p ", cmd, cmd, addr);
if (bankwidth_is_1(info)) {
- debug ("is= %x %x\n", flash_read8(addr), cword.c);
- retval = (flash_read8(addr) == cword.c);
+ debug ("is= %x %x\n", flash_read8(addr), (u8)cword);
+ retval = (flash_read8(addr) == cword);
} else if (bankwidth_is_2(info)) {
- debug ("is= %4.4x %4.4x\n", flash_read16(addr), cword.w);
- retval = (flash_read16(addr) == cword.w);
+ debug ("is= %4.4x %4.4x\n", flash_read16(addr), (u16)cword);
+ retval = (flash_read16(addr) == cword);
} else if (bankwidth_is_4(info)) {
- debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), cword.l);
- retval = (flash_read32(addr) == cword.l);
+ debug ("is= %8.8lx %8.8lx\n", flash_read32(addr), (u32)cword);
+ retval = (flash_read32(addr) == cword);
} else if (bankwidth_is_8(info)) {
#ifdef DEBUG
{
@@ -889,11 +866,11 @@ int flash_isequal (struct flash_info *info, flash_sect_t sect, uint offset, ucha
char str2[20];
print_longlong (str1, flash_read32(addr));
- print_longlong (str2, cword.ll);
+ print_longlong (str2, cword);
debug ("is= %s %s\n", str1, str2);
}
#endif
- retval = (flash_read32(addr) == cword.ll);
+ retval = (flash_read64(addr) == cword);
} else
retval = 0;
@@ -902,20 +879,19 @@ int flash_isequal (struct flash_info *info, flash_sect_t sect, uint offset, ucha
int flash_isset (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd)
{
- void *addr;
+ void *addr = flash_make_addr (info, sect, offset);
cfiword_t cword;
int retval;
- addr = flash_make_addr (info, sect, offset);
flash_make_cmd (info, cmd, &cword);
if (bankwidth_is_1(info)) {
- retval = ((flash_read8(addr) & cword.c) == cword.c);
+ retval = ((flash_read8(addr) & cword) == cword);
} else if (bankwidth_is_2(info)) {
- retval = ((flash_read16(addr) & cword.w) == cword.w);
+ retval = ((flash_read16(addr) & cword) == cword);
} else if (bankwidth_is_4(info)) {
- retval = ((flash_read32(addr) & cword.l) == cword.l);
+ retval = ((flash_read32(addr) & cword) == cword);
} else if (bankwidth_is_8(info)) {
- retval = ((flash_read64(addr) & cword.ll) == cword.ll);
+ retval = ((flash_read64(addr) & cword) == cword);
} else
retval = 0;
@@ -1001,6 +977,7 @@ static int cfi_probe (struct device_d *dev)
/* Init: no FLASHes known */
info->flash_id = FLASH_UNKNOWN;
+ info->cmd_reset = FLASH_CMD_RESET;
info->size = flash_get_size(info, dev->map_base);
info->base = (void __iomem *)dev->map_base;
diff --git a/drivers/nor/cfi_flash.h b/drivers/nor/cfi_flash.h
index f9023dc..9098021 100644
--- a/drivers/nor/cfi_flash.h
+++ b/drivers/nor/cfi_flash.h
@@ -25,10 +25,12 @@
*/
#include <driver.h>
+#include <asm/byteorder.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
typedef unsigned long flash_sect_t;
+typedef u64 cfiword_t;
struct cfi_cmd_set;
/*-----------------------------------------------------------------------
@@ -238,7 +240,7 @@ int flash_generic_status_check (struct flash_info *info, flash_sect_t sector,
uint64_t tout, char *prompt);
int flash_isequal (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd);
-void flash_make_cmd (struct flash_info *info, uchar cmd, void *cmdbuf);
+void flash_make_cmd(struct flash_info *info, uchar cmd, cfiword_t *cmdbuf);
static inline void flash_write8(u8 value, void *addr)
{
@@ -316,26 +318,19 @@ u32 jedec_read_mfr(struct flash_info *info);
#define bankwidth_is_8(info) 0
#endif
-typedef union {
- unsigned char c;
- unsigned short w;
- unsigned long l;
- unsigned long long ll;
-} cfiword_t;
-
static inline void flash_write_word(struct flash_info *info, cfiword_t datum, void *addr)
{
if (bankwidth_is_1(info)) {
- debug("fw addr %p val %02x\n", addr, datum.c);
- flash_write8(datum.c, addr);
+ debug("fw addr %p val %02x\n", addr, (u8)datum);
+ flash_write8(datum, addr);
} else if (bankwidth_is_2(info)) {
- debug("fw addr %p val %04x\n", addr, datum.w);
- flash_write16(datum.w, addr);
+ debug("fw addr %p val %04x\n", addr, (u16)datum);
+ flash_write16(datum, addr);
} else if (bankwidth_is_4(info)) {
- debug("fw addr %p val %08x\n", addr, datum.l);
- flash_write32(datum.l, addr);
+ debug("fw addr %p val %08x\n", addr, (u32)datum);
+ flash_write32(datum, addr);
} else if (bankwidth_is_8(info)) {
- flash_write64(datum.ll, addr);
+ flash_write64(datum, addr);
}
}
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 12] Fix NOR CFI flash driver to work on big endian systems.
2010-12-20 23:10 ` [PATCH 12] Fix NOR CFI flash driver to work on big endian systems Krzysztof Halasa
@ 2010-12-22 1:01 ` Jean-Christophe PLAGNIOL-VILLARD
2010-12-22 12:48 ` Sascha Hauer
0 siblings, 1 reply; 41+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-12-22 1:01 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
On 00:10 Tue 21 Dec , Krzysztof Halasa wrote:
> Fix NOR CFI flash driver to work on big endian systems.
> Basically this transforms the u8/u16/u32/u64 union into
> a single u64 value.
>
> Not tested on LE platform. Apply with caution.
I'd like to test it a few this week can we wait a few before applying?
Best Regards,
J.
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PATCH 12] Fix NOR CFI flash driver to work on big endian systems.
2010-12-22 1:01 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2010-12-22 12:48 ` Sascha Hauer
0 siblings, 0 replies; 41+ messages in thread
From: Sascha Hauer @ 2010-12-22 12:48 UTC (permalink / raw)
To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox, Krzysztof Halasa
On Wed, Dec 22, 2010 at 02:01:30AM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 00:10 Tue 21 Dec , Krzysztof Halasa wrote:
> > Fix NOR CFI flash driver to work on big endian systems.
> > Basically this transforms the u8/u16/u32/u64 union into
> > a single u64 value.
> >
> > Not tested on LE platform. Apply with caution.
> I'd like to test it a few this week can we wait a few before applying?
I already applied it. I tested it on little endian and it works. Anyway,
if you find regressions we can still update the patch.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 13] Fix usage of __LITTLE_ENDIAN macro.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (11 preceding siblings ...)
2010-12-20 23:10 ` [PATCH 12] Fix NOR CFI flash driver to work on big endian systems Krzysztof Halasa
@ 2010-12-20 23:14 ` Krzysztof Halasa
2010-12-21 9:17 ` my IXP4xx-related and other patches Sascha Hauer
` (3 subsequent siblings)
16 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-20 23:14 UTC (permalink / raw)
To: barebox
Fix usage of __LITTLE_ENDIAN macro.
Both __LITTLE_ENDIAN and __BIG_ENDIAN are always defined by
include/linux/byteorder/generic.h, checking for their existence is
pointless.
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/include/cramfs/cramfs_fs.h b/include/cramfs/cramfs_fs.h
index 5bf72c3..3d3c56f 100644
--- a/include/cramfs/cramfs_fs.h
+++ b/include/cramfs/cramfs_fs.h
@@ -88,7 +88,7 @@ struct cramfs_super {
#error "No byte order defined in __BYTE_ORDER"
#endif
-#ifdef __LITTLE_ENDIAN
+#if __BYTE_ORDER == __LITTLE_ENDIAN
#define CRAMFS_16(x) (x)
#define CRAMFS_24(x) (x)
#define CRAMFS_32(x) (x)
@@ -96,7 +96,7 @@ struct cramfs_super {
#define CRAMFS_GET_OFFSET(x) ((x)->offset)
#define CRAMFS_SET_OFFSET(x,y) ((x)->offset = (y))
#define CRAMFS_SET_NAMELEN(x,y) ((x)->namelen = (y))
-#elif defined __BIG_ENDIAN
+#elif __BYTE_ORDER ==__BIG_ENDIAN
#ifdef __KERNEL__
#define CRAMFS_16(x) swab16(x)
#define CRAMFS_24(x) ((swab32(x)) >> 8)
diff --git a/include/usb/usb.h b/include/usb/usb.h
index 790d64d..1b936ec 100644
--- a/include/usb/usb.h
+++ b/include/usb/usb.h
@@ -267,7 +267,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate);
((x_ & 0xFF000000UL) >> 24)); \
})
-#ifdef __LITTLE_ENDIAN
+#if __BYTE_ORDER == __LITTLE_ENDIAN
# define swap_16(x) (x)
# define swap_32(x) (x)
#else
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: my IXP4xx-related and other patches
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (12 preceding siblings ...)
2010-12-20 23:14 ` [PATCH 13] Fix usage of __LITTLE_ENDIAN macro Krzysztof Halasa
@ 2010-12-21 9:17 ` Sascha Hauer
2010-12-22 0:51 ` [PATCH 5a] Fix error handling with malloc, memalign etc. Introduce xmemalign() Krzysztof Halasa
` (2 subsequent siblings)
16 siblings, 0 replies; 41+ messages in thread
From: Sascha Hauer @ 2010-12-21 9:17 UTC (permalink / raw)
To: Krzysztof Halasa; +Cc: barebox
Hi Krzysztof,
On Mon, Dec 20, 2010 at 11:30:03PM +0100, Krzysztof Halasa wrote:
> Hello,
>
> I've been working a bit on IXP4xx support lately and it seems I'm at the
> point I can now boot Barebox on a Goramo Multilink routers
> (IXP425-based). It requires several patches (will post them shortly) and
> NPE microcode files from Intel (or from elsewhere, the regular non-VLAN
> microcode v. 2.4 is needed, i.e., same as with Linux).
Nice ;)
I applied all patches except the malloc patch and the ixp4xx core patch
which need minor fixups.
>
> The binary microcode must be appended to Barebox at correct offsets for
> the NPE driver to find it, details are in board support file
> (arch/arm/boards/multilink/multilink.c):
>
> #define BAREBOX_START 0x00000
> #define BAREBOX_LENGTH 0x34000
> #define NPE_A_START (BAREBOX_START + BAREBOX_LENGTH)
> #define NPE_A_LENGTH 0x05000
> #define NPE_B_START (NPE_A_START + NPE_A_LENGTH)
> #define NPE_B_LENGTH 0x03000
> #define NPE_C_START (NPE_B_START + NPE_B_LENGTH)
> #define NPE_C_LENGTH 0x04000
> #define NPE_ENV0_START (NPE_C_START + NPE_C_LENGTH)
> #define NPE_ENV0_LENGTH 0x20000
>
> when passed to Linux:
> Creating XXX MTD partitions on "IXP4XX-Flash.0":
> 0x000000000000-0x000000034000 : "barebox"
> 0x000000034000-0x000000039000 : "NPE-A"
> 0x000000039000-0x00000003c000 : "NPE-B"
> 0x00000003c000-0x000000040000 : "NPE-C"
> 0x000000040000-0x000000060000 : "env0"
As said in the comment to patch, we need to at least document this.
>
> User-available flash area starts at 0x60000.
>
> All this IXP4xx code is big-endian only. Too much work with LE (NPE
> coprocessors would need buffer byte swapping, flash (EXP bus) would need
> 16-bit word swapping etc). Big-endian Barebox can load both LE and BE
> Linux anyway ("bootz" only at the moment).
Yes, big endian is enough for now. It's good to have a big endian ARM
machine in the tree.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 5a] Fix error handling with malloc, memalign etc. Introduce xmemalign().
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (13 preceding siblings ...)
2010-12-21 9:17 ` my IXP4xx-related and other patches Sascha Hauer
@ 2010-12-22 0:51 ` Krzysztof Halasa
2010-12-22 0:53 ` [PATCH 6a] ARM: support big/little endian switching in "bootz" Krzysztof Halasa
2010-12-22 0:55 ` [PATCH 10a] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Krzysztof Halasa
16 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-22 0:51 UTC (permalink / raw)
To: barebox
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu.c
index 08a57ce..df664f6 100644
--- a/arch/arm/cpu/mmu.c
+++ b/arch/arm/cpu/mmu.c
@@ -95,13 +95,7 @@ void setup_dma_coherent(unsigned long offset)
void *dma_alloc_coherent(size_t size)
{
- void *mem;
-
- mem = memalign(4096, size);
- if (mem)
- return mem + dma_coherent_offset;
-
- return NULL;
+ return xmemalign(4096, size) + dma_coherent_offset;
}
unsigned long virt_to_phys(void *virt)
diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h
index fdd23b5..7789cc9 100644
--- a/arch/arm/include/asm/mmu.h
+++ b/arch/arm/include/asm/mmu.h
@@ -28,7 +28,7 @@ void *phys_to_virt(unsigned long phys);
#else
static inline void *dma_alloc_coherent(size_t size)
{
- return malloc(size);
+ return xmalloc(size);
}
static inline void dma_free_coherent(void *mem)
diff --git a/commands/edit.c b/commands/edit.c
index ca40d59..3519b09 100644
--- a/commands/edit.c
+++ b/commands/edit.c
@@ -184,10 +184,8 @@ static struct line *line_realloc(int len, struct line *line)
{
int size = 32;
- if (!line) {
+ if (!line)
line = xzalloc(sizeof(struct line));
- line->data = malloc(32);
- }
while (size < len)
size <<= 1;
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 717fea5..9d52beb 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -116,9 +116,7 @@ struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
{
struct clk_lookup_alloc *cla;
- cla = kzalloc(sizeof(*cla), GFP_KERNEL);
- if (!cla)
- return NULL;
+ cla = xzalloc(sizeof(*cla), GFP_KERNEL);
cla->cl.clk = clk;
if (con_id) {
@@ -150,8 +148,6 @@ int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
l = clkdev_alloc(r, alias, alias_dev_name);
clk_put(r);
- if (!l)
- return -ENODEV;
clkdev_add(l);
return 0;
}
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 04a1e4c..c196185 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1333,10 +1333,7 @@ static struct driver_d mci_driver = {
static int mci_init(void)
{
- sector_buf = memalign(32, 512);
- if (!sector_buf)
- return -ENOMEM;
-
+ sector_buf = xmemalign(32, 512);
return register_driver(&mci_driver);
}
diff --git a/drivers/net/at91_ether.c b/drivers/net/at91_ether.c
index 4563ff3..d5e26a1 100644
--- a/drivers/net/at91_ether.c
+++ b/drivers/net/at91_ether.c
@@ -263,7 +263,7 @@ static int at91rm9200_eth_init (struct device_d *dev)
struct eth_device *edev;
int i;
- edev = malloc(sizeof(struct eth_device));
+ edev = xmalloc(sizeof(struct eth_device));
dev->priv = edev;
edev->open = at91rm9200_eth_open;
diff --git a/drivers/net/cs8900.c b/drivers/net/cs8900.c
index 8120877..187c0fb 100644
--- a/drivers/net/cs8900.c
+++ b/drivers/net/cs8900.c
@@ -440,14 +440,14 @@ static int cs8900_probe(struct device_d *dev)
debug("cs8900_init()\n");
- priv = (struct cs8900_priv *)malloc(sizeof(*priv));
+ priv = (struct cs8900_priv *)xmalloc(sizeof(*priv));
priv->regs = (u16 *)dev->map_base;
if (cs8900_check_id(priv)) {
free(priv);
return -1;
}
- edev = (struct eth_device *)malloc(sizeof(struct eth_device));
+ edev = (struct eth_device *)xmalloc(sizeof(struct eth_device));
dev->type_data = edev;
edev->priv = priv;
diff --git a/drivers/net/fec_mpc5200.c b/drivers/net/fec_mpc5200.c
index 8b2cb4d..7528316 100644
--- a/drivers/net/fec_mpc5200.c
+++ b/drivers/net/fec_mpc5200.c
@@ -661,9 +661,9 @@ int mpc5xxx_fec_probe(struct device_d *dev)
struct eth_device *edev;
mpc5xxx_fec_priv *fec;
- edev = (struct eth_device *)malloc(sizeof(struct eth_device));
+ edev = (struct eth_device *)xmalloc(sizeof(struct eth_device));
dev->type_data = edev;
- fec = (mpc5xxx_fec_priv *)malloc(sizeof(*fec));
+ fec = (mpc5xxx_fec_priv *)xmalloc(sizeof(*fec));
edev->priv = fec;
edev->open = mpc5xxx_fec_open,
edev->init = mpc5xxx_fec_init,
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 522a9f1..a30a9c8 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -79,7 +79,7 @@ int tap_probe(struct device_d *dev)
struct tap_priv *priv;
int ret = 0;
- priv = malloc(sizeof(struct tap_priv));
+ priv = xmalloc(sizeof(struct tap_priv));
priv->name = "barebox";
priv->fd = tap_alloc(priv->name);
@@ -88,7 +88,7 @@ int tap_probe(struct device_d *dev)
goto out;
}
- edev = malloc(sizeof(struct eth_device));
+ edev = xmalloc(sizeof(struct eth_device));
dev->type_data = edev;
edev->priv = priv;
diff --git a/drivers/nor/cfi_flash.c b/drivers/nor/cfi_flash.c
index efe8785..faf965a 100644
--- a/drivers/nor/cfi_flash.c
+++ b/drivers/nor/cfi_flash.c
@@ -305,7 +305,7 @@ static ulong flash_get_size (struct flash_info *info, ulong base)
#endif
/* first only malloc space for the first sector */
- info->start = malloc(sizeof(ulong));
+ info->start = xmalloc(sizeof(ulong));
info->start[0] = base;
info->protect = 0;
@@ -394,8 +394,8 @@ static ulong flash_get_size (struct flash_info *info, ulong base)
cur_offset += erase_region_size * erase_region_count;
/* increase the space malloced for the sector start addresses */
- info->start = realloc(info->start, sizeof(ulong) * (erase_region_count + sect_cnt));
- info->protect = realloc(info->protect, sizeof(uchar) * (erase_region_count + sect_cnt));
+ info->start = xrealloc(info->start, sizeof(ulong) * (erase_region_count + sect_cnt));
+ info->protect = xrealloc(info->protect, sizeof(uchar) * (erase_region_count + sect_cnt));
for (j = 0; j < erase_region_count; j++) {
info->start[sect_cnt] = sector;
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index bc9b0de..442dbc4 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -157,8 +157,7 @@ static int pl011_probe(struct device_d *dev)
struct amba_uart_port *uart;
struct console_device *cdev;
- uart = malloc(sizeof(struct amba_uart_port));
-
+ uart = xmalloc(sizeof(struct amba_uart_port));
uart->clk = clk_get(dev, NULL);
if (IS_ERR(uart->clk))
diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c
index b99ec4d..1098952 100644
--- a/drivers/serial/atmel.c
+++ b/drivers/serial/atmel.c
@@ -398,8 +398,7 @@ static int atmel_serial_probe(struct device_d *dev)
struct atmel_uart_port *uart;
struct console_device *cdev;
- uart = malloc(sizeof(struct atmel_uart_port));
-
+ uart = xmalloc(sizeof(struct atmel_uart_port));
cdev = &uart->uart;
dev->type_data = cdev;
cdev->dev = dev;
diff --git a/drivers/serial/serial_blackfin.c b/drivers/serial/serial_blackfin.c
index 2101b7e..59b2fbb 100644
--- a/drivers/serial/serial_blackfin.c
+++ b/drivers/serial/serial_blackfin.c
@@ -115,7 +115,7 @@ static int blackfin_serial_probe(struct device_d *dev)
{
struct console_device *cdev;
- cdev = malloc(sizeof(struct console_device));
+ cdev = xmalloc(sizeof(struct console_device));
dev->type_data = cdev;
cdev->dev = dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c
index a7562f9..984d7f2 100644
--- a/drivers/serial/serial_imx.c
+++ b/drivers/serial/serial_imx.c
@@ -319,7 +319,7 @@ static int imx_serial_probe(struct device_d *dev)
struct imx_serial_priv *priv;
uint32_t val;
- priv = malloc(sizeof(*priv));
+ priv = xmalloc(sizeof(*priv));
cdev = &priv->cdev;
priv->regs = (void __force __iomem *)dev->map_base;
diff --git a/drivers/serial/serial_netx.c b/drivers/serial/serial_netx.c
index 7c09519..9d4b29e 100644
--- a/drivers/serial/serial_netx.c
+++ b/drivers/serial/serial_netx.c
@@ -140,7 +140,7 @@ static int netx_serial_probe(struct device_d *dev)
{
struct console_device *cdev;
- cdev = malloc(sizeof(struct console_device));
+ cdev = xmalloc(sizeof(struct console_device));
dev->type_data = cdev;
cdev->dev = dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
diff --git a/drivers/serial/serial_pl010.c b/drivers/serial/serial_pl010.c
index 1a6366f..7923ebb 100644
--- a/drivers/serial/serial_pl010.c
+++ b/drivers/serial/serial_pl010.c
@@ -141,7 +141,7 @@ static int pl010_probe(struct device_d *dev)
{
struct console_device *cdev;
- cdev = malloc(sizeof(struct console_device));
+ cdev = xmalloc(sizeof(struct console_device));
dev->type_data = cdev;
cdev->dev = dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c
index d7eac8f..0a17967 100644
--- a/drivers/serial/serial_s3c24x0.c
+++ b/drivers/serial/serial_s3c24x0.c
@@ -121,8 +121,7 @@ static int s3c24x0_serial_probe(struct device_d *dev)
{
struct console_device *cdev;
- cdev = malloc(sizeof(struct console_device));
-
+ cdev = xmalloc(sizeof(struct console_device));
dev->type_data = cdev;
cdev->dev = dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 978fdd1..fd70e62 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -903,9 +903,6 @@ static int __init composite_bind(struct usb_gadget *gadget)
int status = -ENOMEM;
cdev = xzalloc(sizeof *cdev);
- if (!cdev)
- return status;
-
cdev->gadget = gadget;
set_gadget_data(gadget, cdev);
INIT_LIST_HEAD(&cdev->configs);
diff --git a/drivers/usb/gadget/fsl_udc.c b/drivers/usb/gadget/fsl_udc.c
index 48fd0b5..20a5064 100644
--- a/drivers/usb/gadget/fsl_udc.c
+++ b/drivers/usb/gadget/fsl_udc.c
@@ -1016,8 +1016,6 @@ fsl_alloc_request(struct usb_ep *_ep)
struct fsl_req *req;
req = xzalloc(sizeof *req);
- if (!req)
- return NULL;
INIT_LIST_HEAD(&req->queue);
@@ -2095,7 +2093,7 @@ static int struct_udc_setup(struct fsl_udc *udc,
udc->status_req = container_of(fsl_alloc_request(NULL),
struct fsl_req, req);
/* allocate a small amount of memory to get valid address */
- udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
+ udc->status_req->req.buf = xmalloc(8);
udc->resume_state = USB_STATE_NOTATTACHED;
udc->usb_state = USB_STATE_POWERED;
udc->ep0_dir = 0;
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index cb65b19..d3baed7 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -205,11 +205,7 @@ gs_alloc_req(struct usb_ep *ep, unsigned len)
if (req != NULL) {
req->length = len;
- req->buf = memalign(32, len);
- if (req->buf == NULL) {
- usb_ep_free_request(ep, req);
- return NULL;
- }
+ req->buf = xmemalign(32, len);
}
return req;
diff --git a/include/net.h b/include/net.h
index 2d28fee..33d8a32 100644
--- a/include/net.h
+++ b/include/net.h
@@ -392,7 +392,7 @@ struct net_connection {
static inline char *net_alloc_packet(void)
{
- return memalign(32, PKTSIZE);
+ return xmemalign(32, PKTSIZE);
}
struct net_connection *net_udp_new(IPaddr_t dest, uint16_t dport,
diff --git a/include/xfuncs.h b/include/xfuncs.h
index 222ea41..261aaa5 100644
--- a/include/xfuncs.h
+++ b/include/xfuncs.h
@@ -7,5 +7,6 @@ void *xmalloc(size_t size);
void *xrealloc(void *ptr, size_t size);
void *xzalloc(size_t size);
char *xstrdup(const char *s);
+void* xmemalign(size_t alignment, size_t bytes);
#endif /* __XFUNCS_H */
diff --git a/lib/xfuncs.c b/lib/xfuncs.c
index 01a64cf..71394ff 100644
--- a/lib/xfuncs.c
+++ b/lib/xfuncs.c
@@ -70,3 +70,11 @@ char *xstrdup(const char *s)
}
EXPORT_SYMBOL(xstrdup);
+void* xmemalign(size_t alignment, size_t bytes)
+{
+ void *p = memalign(alignment, bytes);
+ if (!p)
+ panic("ERROR: out of memory\n");
+ return p;
+}
+EXPORT_SYMBOL(xmemalign);
diff --git a/net/net.c b/net/net.c
index 9b4ab89..7495357 100644
--- a/net/net.c
+++ b/net/net.c
@@ -365,7 +365,7 @@ static struct net_connection *net_new(IPaddr_t dest, rx_handler_f *handler)
return ERR_PTR(-ENETDOWN);
con = xzalloc(sizeof(*con));
- con->packet = memalign(32, PKTSIZE);
+ con->packet = xmemalign(32, PKTSIZE);
memset(con->packet, 0, PKTSIZE);
con->et = (struct ethernet *)con->packet;
@@ -658,7 +658,7 @@ static int net_init(void)
int i;
for (i = 0; i < PKTBUFSRX; i++)
- NetRxPackets[i] = memalign(32, PKTSIZE);
+ NetRxPackets[i] = xmemalign(32, PKTSIZE);
return 0;
}
diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c
index 0d4f5e7..9f6535d 100644
--- a/scripts/basic/docproc.c
+++ b/scripts/basic/docproc.c
@@ -122,8 +122,11 @@ int symfilecnt = 0;
void add_new_symbol(struct symfile *sym, char * symname)
{
- sym->symbollist =
- realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
+ sym->symbollist = realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
+ if (!sym->symbollist) {
+ fprintf(stderr, "docproc: out of memory\n");
+ exit(1);
+ }
sym->symbollist[sym->symbolcnt++].name = strdup(symname);
}
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 4075c35..08b75b6 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1317,7 +1317,7 @@ void buf_write(struct buffer *buf, const char *s, int len)
{
if (buf->size - buf->pos < len) {
buf->size += len + SZ;
- buf->p = realloc(buf->p, buf->size);
+ buf->p = NOFAIL(realloc(buf->p, buf->size));
}
strncpy(buf->p + buf->pos, s, len);
buf->pos += len;
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 6a] ARM: support big/little endian switching in "bootz".
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (14 preceding siblings ...)
2010-12-22 0:51 ` [PATCH 5a] Fix error handling with malloc, memalign etc. Introduce xmemalign() Krzysztof Halasa
@ 2010-12-22 0:53 ` Krzysztof Halasa
2010-12-22 0:55 ` [PATCH 10a] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform Krzysztof Halasa
16 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-22 0:53 UTC (permalink / raw)
To: barebox
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/arch/arm/cpu/Kconfig b/arch/arm/cpu/Kconfig
index 3572a1f..73ee115 100644
--- a/arch/arm/cpu/Kconfig
+++ b/arch/arm/cpu/Kconfig
@@ -73,6 +73,15 @@ config CPU_BIG_ENDIAN
port must properly enable any big-endian related features
of your chipset/board/processor.
+config BOOTZ_ENDIANNESS_SWITCH
+ bool "Support switching of Linux kernel endianness"
+ help
+ Say Y here if you need to switch CPU endianness before running
+ Linux kernel, e.g. if you want big-endian Barebox to run
+ little-endian Linux.
+
+ Currently implemented only in "bootz" command.
+
config ARCH_HAS_L2X0
bool
diff --git a/arch/arm/lib/armlinux.c b/arch/arm/lib/armlinux.c
index f826da6..6462013 100644
--- a/arch/arm/lib/armlinux.c
+++ b/arch/arm/lib/armlinux.c
@@ -41,6 +41,7 @@
#include <asm/setup.h>
#include <asm/barebox-arm.h>
#include <asm/armlinux.h>
+#include <asm/system.h>
static struct tag *params;
static int armlinux_architecture = 0;
@@ -85,9 +86,10 @@ static void setup_memory_tags(void)
}
}
-static void setup_commandline_tag(const char *commandline)
+static void setup_commandline_tag(const char *commandline, int swap)
{
const char *p;
+ size_t words;
if (!commandline)
return;
@@ -102,12 +104,20 @@ static void setup_commandline_tag(const char *commandline)
if (*p == '\0')
return;
+ words = (strlen(p) + 1 /* NUL */ + 3 /* round up */) >> 2;
params->hdr.tag = ATAG_CMDLINE;
- params->hdr.size =
- (sizeof (struct tag_header) + strlen(p) + 1 + 4) >> 2;
+ params->hdr.size = (sizeof(struct tag_header) >> 2) + words;
strcpy(params->u.cmdline.cmdline, p);
+#ifdef CONFIG_BOOTZ_ENDIANNESS_SWITCH
+ if (swap) {
+ u32 *cmd = (u32 *)params->u.cmdline.cmdline;
+ while (words--)
+ cmd[words] = swab32(cmd[words]);
+ }
+#endif
+
params = tag_next(params);
}
@@ -156,13 +166,13 @@ static void setup_end_tag (void)
params->hdr.size = 0;
}
-static void setup_tags(struct image_data *data)
+static void setup_tags(struct image_data *data, int swap)
{
const char *commandline = getenv("bootargs");
setup_start_tag();
setup_memory_tags();
- setup_commandline_tag(commandline);
+ setup_commandline_tag(commandline, swap);
if (data && data->initrd)
setup_initrd_tag (&data->initrd->header);
@@ -231,7 +241,7 @@ static int do_bootm_linux(struct image_data *data)
debug("## Transferring control to Linux (at address 0x%p) ...\n",
theKernel);
- setup_tags(data);
+ setup_tags(data, 0);
if (relocate_image(data->os, (void *)image_get_load(os_header)))
return -1;
@@ -290,18 +300,21 @@ late_initcall(armlinux_register_image_handler);
#ifdef CONFIG_CMD_BOOTZ
struct zimage_header {
- u32 unsused[9];
+ u32 unused[9];
u32 magic;
u32 start;
u32 end;
};
+#define ZIMAGE_MAGIC 0x016F2818
+
static int do_bootz(struct command *cmdtp, int argc, char *argv[])
{
void (*theKernel)(int zero, int arch, void *params);
- int fd, ret;
+ int fd, ret, swap = 0;
struct zimage_header header;
void *zimage;
+ u32 end;
if (argc != 2) {
barebox_cmd_usage(cmdtp);
@@ -320,27 +333,53 @@ static int do_bootz(struct command *cmdtp, int argc, char *argv[])
goto err_out;
}
- if (header.magic != 0x016f2818) {
+ switch (header.magic) {
+#ifdef CONFIG_BOOTZ_ENDIANNESS_SWITCH
+ case swab32(ZIMAGE_MAGIC):
+ swap = 1;
+ /* fall through */
+#endif
+ case ZIMAGE_MAGIC:
+ break;
+ default:
printf("invalid magic 0x%08x\n", header.magic);
goto err_out;
}
- zimage = xmalloc(header.end);
+ end = header.end;
+
+ if (swap)
+ end = swab32(end);
+
+ zimage = xmalloc(end);
memcpy(zimage, &header, sizeof(header));
- ret = read(fd, zimage + sizeof(header), header.end - sizeof(header));
- if (ret < header.end - sizeof(header)) {
+ ret = read(fd, zimage + sizeof(header), end - sizeof(header));
+ if (ret < end - sizeof(header)) {
printf("could not read %s\n", argv[1]);
goto err_out1;
}
+ if (swap) {
+ void *ptr;
+ for (ptr = zimage; ptr < zimage + end; ptr += 4)
+ *(u32 *)ptr = swab32(*(u32 *)ptr);
+ }
+
theKernel = zimage;
- printf("loaded zImage from %s with size %d\n", argv[1], header.end);
+ printf("loaded zImage from %s with size %d\n", argv[1], end);
- setup_tags(NULL);
+ setup_tags(NULL, swap);
shutdown_barebox();
+ if (swap) {
+ u32 reg;
+ __asm__ __volatile__("mrc p15, 0, %0, c1, c0" : "=r" (reg));
+ reg ^= CR_B; /* swap big-endian flag */
+ __asm__ __volatile__("mcr p15, 0, %0, c1, c0" :: "r" (reg));
+ }
+
theKernel(0, armlinux_architecture, armlinux_bootparams);
return 0;
@@ -382,7 +421,7 @@ static int do_bootu(struct command *cmdtp, int argc, char *argv[])
if (!theKernel)
theKernel = (void *)simple_strtoul(argv[1], NULL, 0);
- setup_tags(NULL);
+ setup_tags(NULL, 0);
shutdown_barebox();
theKernel(0, armlinux_architecture, armlinux_bootparams);
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PATCH 10a] ARM: Add support for IXP4xx CPU and for Goramo Multilink router platform.
2010-12-20 22:30 my IXP4xx-related and other patches Krzysztof Halasa
` (15 preceding siblings ...)
2010-12-22 0:53 ` [PATCH 6a] ARM: support big/little endian switching in "bootz" Krzysztof Halasa
@ 2010-12-22 0:55 ` Krzysztof Halasa
16 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Halasa @ 2010-12-22 0:55 UTC (permalink / raw)
To: barebox
Signed-off-by: Krzysztof Hałasa <khc@pm.waw.pl>
diff --git a/Documentation/boards.dox b/Documentation/boards.dox
index 8087f01..8d8701f 100644
--- a/Documentation/boards.dox
+++ b/Documentation/boards.dox
@@ -20,6 +20,7 @@ ARM type:
@li @subpage board_babage
@li @subpage chumbyone
@li @subpage scb9328
+@li @subpage multilink
@li @subpage netx
@li @subpage dev_omap_arch
@li @subpage a9m2440
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c09d21b..2b33a07 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -39,6 +39,13 @@ config ARCH_IMX
bool "Freescale iMX-based"
select GENERIC_GPIO
+config ARCH_IXP4XX
+ bool "Intel IXP4xx-based"
+ select CPU_32v5
+ select ARCH_SUPPORTS_BIG_ENDIAN
+ select CPU_BIG_ENDIAN
+ select ARCH_HAS_LOWLEVEL_INIT
+
config ARCH_STM
bool "SigmaTel/FSL iMX-based"
@@ -70,6 +77,7 @@ source arch/arm/cpu/Kconfig
source arch/arm/mach-at91/Kconfig
source arch/arm/mach-ep93xx/Kconfig
source arch/arm/mach-imx/Kconfig
+source arch/arm/mach-ixp4xx/Kconfig
source arch/arm/mach-stm/Kconfig
source arch/arm/mach-netx/Kconfig
source arch/arm/mach-nomadik/Kconfig
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index c90960e..4cc0c0c 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -41,6 +41,7 @@ CPPFLAGS += $(CFLAGS_ABI) $(arch-y) $(tune-y)
machine-$(CONFIG_ARCH_AT91) := at91
machine-$(CONFIG_ARCH_EP93XX) := ep93xx
machine-$(CONFIG_ARCH_IMX) := imx
+machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx
machine-$(CONFIG_ARCH_STM) := stm
machine-$(CONFIG_ARCH_NOMADIK) := nomadik
machine-$(CONFIG_ARCH_NETX) := netx
@@ -74,6 +75,7 @@ board-$(CONFIG_MACH_FREESCALE_MX35_3STACK) := freescale-mx35-3-stack
board-$(CONFIG_MACH_IMX21ADS) := imx21ads
board-$(CONFIG_MACH_IMX27ADS) := imx27ads
board-$(CONFIG_MACH_MMCCPU) := mmccpu
+board-$(CONFIG_MACH_MULTILINK) := multilink
board-$(CONFIG_MACH_MX1ADS) := mx1ads
board-$(CONFIG_MACH_NOMADIK_8815NHK) := nhk8815
board-$(CONFIG_MACH_NXDB500) := netx
diff --git a/arch/arm/boards/multilink/Makefile b/arch/arm/boards/multilink/Makefile
new file mode 100644
index 0000000..d5a8bbc
--- /dev/null
+++ b/arch/arm/boards/multilink/Makefile
@@ -0,0 +1 @@
+obj-y += lowlevel_init.o multilink.o
diff --git a/arch/arm/boards/multilink/config.h b/arch/arm/boards/multilink/config.h
new file mode 100644
index 0000000..e69de29
diff --git a/arch/arm/boards/multilink/lowlevel_init.S b/arch/arm/boards/multilink/lowlevel_init.S
new file mode 100644
index 0000000..970ef72
--- /dev/null
+++ b/arch/arm/boards/multilink/lowlevel_init.S
@@ -0,0 +1,64 @@
+#include <mach/ixp4xx-regs.h>
+
+ .section ".text_bare_init", "ax"
+ .balign 0x40
+ .space 0x40 /* configuration block at 0x40 */
+
+ .macro DELAY_FOR cycles, reg0
+ ldr \reg0, =\cycles
+ subs \reg0, \reg0, #1
+ subne pc, pc, #0xc
+ .endm
+
+#define CFG_SDRAM_SIZE 0x50 /* u32 */
+#define CFG_SDRAM_CONF 0x54 /* u32 */
+#define CFG_SDRAM_MODE 0x58 /* u32 */
+#define CFG_SDRAM_REFRESH 0x5C /* u32 */
+
+.globl board_init_lowlevel
+board_init_lowlevel:
+ mov r8, #IXP4XX_EXP_BASE(0)
+ ldr r1, [r8, #CFG_SDRAM_CONF]
+ ldr r2, =IXP4XX_SDRAM_CONFIG
+ str r1, [r2]
+
+ /* disable refresh cycles */
+ mov r1, #0
+ add r2, r2, #4 /* r2 = IXP4XX_SDRAM_REFRESH */
+ str r1, [r2]
+
+ /* send NOP command */
+ mov r1, #3
+ add r3, r2, #4 /* r3 = IXP4XX_SDRAM_IR */
+ str r1, [r3]
+ DELAY_FOR 0x4000, r0
+
+ /* set SDRAM internal refresh */
+ ldr r1, [r8, #CFG_SDRAM_REFRESH]
+ str r1, [r2]
+ DELAY_FOR 0x4000, r0
+
+ /* send precharge-all command to close all open banks */
+ mov r1, #2
+ str r1, [r3]
+ DELAY_FOR 0x4000, r0
+
+ /* provide 8 auto-refresh cycles */
+ mov r1, #4
+ mov r4, #8
+1: str r1, [r3]
+ DELAY_FOR 0x100, r0
+ subs r4, r4, #1
+ bne 1b
+
+ /* set mode register in SDRAM */
+ ldr r1, [r8, #CFG_SDRAM_MODE]
+ str r1, [r3]
+ DELAY_FOR 0x4000, r0
+
+ /* send normal operation command */
+ mov r1, #6
+ str r1, [r3]
+ DELAY_FOR 0x4000, r0
+
+ mov pc, lr
diff --git a/arch/arm/boards/multilink/multilink.c b/arch/arm/boards/multilink/multilink.c
new file mode 100644
index 0000000..f2fb8f4
--- /dev/null
+++ b/arch/arm/boards/multilink/multilink.c
@@ -0,0 +1,144 @@
+//#define DEBUG
+#include <common.h>
+#include <errno.h>
+#include <init.h>
+#include <linux/types.h>
+#include <asm/armlinux.h>
+#include <asm/io.h>
+#include <generated/mach-types.h>
+#include <mach/ixp4xx-regs.h>
+#include <mach/platform.h>
+
+/* offsets from start of flash ROM = 0x50000000 */
+#define CFG_ETH0_ADDRESS 0x40 /* 6 bytes */
+#define CFG_ETH1_ADDRESS 0x46 /* 6 bytes */
+#define CFG_REV 0x4C /* u32 */
+#define CFG_SDRAM_SIZE 0x50 /* u32 */
+#define CFG_SDRAM_CONF 0x54 /* u32 */
+#define CFG_SDRAM_MODE 0x58 /* u32 */
+#define CFG_SDRAM_REFRESH 0x5C /* u32 */
+
+#define CFG_HW_BITS 0x60 /* u32 */
+#define CFG_HW_USB_PORTS 0x00000007 /* 0 = no NEC chip, 1-5 = ports # */
+#define CFG_HW_HAS_PCI_SLOT 0x00000008
+#define CFG_HW_HAS_ETH0 0x00000010
+#define CFG_HW_HAS_ETH1 0x00000020
+#define CFG_HW_HAS_HSS0 0x00000040
+#define CFG_HW_HAS_HSS1 0x00000080
+#define CFG_HW_HAS_UART0 0x00000100
+#define CFG_HW_HAS_UART1 0x00000200
+#define CFG_HW_HAS_EEPROM 0x00000400
+
+#define ETH_ALEN 6
+
+#define BAREBOX_START 0x00000
+#define BAREBOX_LENGTH 0x34000
+#define NPE_A_START (BAREBOX_START + BAREBOX_LENGTH)
+#define NPE_A_LENGTH 0x05000
+#define NPE_B_START (NPE_A_START + NPE_A_LENGTH)
+#define NPE_B_LENGTH 0x03000
+#define NPE_C_START (NPE_B_START + NPE_B_LENGTH)
+#define NPE_C_LENGTH 0x04000
+#define NPE_ENV0_START (NPE_C_START + NPE_C_LENGTH)
+#define NPE_ENV0_LENGTH 0x20000
+
+static struct device_d cfi_dev = {
+ .name = "cfi_flash",
+ .map_base = IXP4XX_EXP_BASE(0),
+ .size = 16 * 1024 * 1024,
+};
+
+static struct eth_plat_info eth_pinfo[2] = {
+ {
+ .regs = IXP4XX_EthB_BASE,
+ .npe = 1,
+ .phy = 0,
+ .rxq = 20,
+ .txreadyq = 29,
+ }, {
+ .regs = IXP4XX_EthC_BASE,
+ .npe = 2,
+ .phy = 1,
+ .rxq = 21,
+ .txreadyq = 30,
+ }
+};
+
+static struct device_d eth_dev[2] = {
+ {
+ .name = "ixp4xx_eth",
+ .platform_data = ð_pinfo[0],
+ }, {
+ .id = 1,
+ .name = "ixp4xx_eth",
+ .platform_data = ð_pinfo[1],
+ }
+};
+
+static struct memory_platform_data ram_pdata = {
+ .name = "ram0",
+ .flags = DEVFS_RDWR,
+};
+
+struct device_d sdram_dev = {
+ .id = -1,
+ .name = "mem",
+ .map_base = 0x00000000,
+ .size = 32 * 1024 * 1024,
+ .platform_data = &ram_pdata,
+};
+
+static inline u8 __init flash_readb(u32 addr)
+{
+ return __raw_readb(IXP4XX_EXP_BASE(0) + addr);
+}
+
+static int __init gml_devices_init(void)
+{
+ u32 hw_bits;
+ int i;
+
+ IXP4XX_EXP_CS0 = IXP4XX_EXP_EN | IXP4XX_EXP_INTEL |
+ IXP4XX_EXP_BITS(24) | IXP4XX_EXP_WR_EN | IXP4XX_EXP_BYTE_RD16;
+ i = register_device(&cfi_dev);
+ if (i)
+ goto out;
+
+ devfs_add_partition("nor0", BAREBOX_START, BAREBOX_LENGTH,
+ DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "barebox");
+ devfs_add_partition("nor0", NPE_A_START, NPE_A_LENGTH,
+ DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-A");
+ devfs_add_partition("nor0", NPE_B_START, NPE_B_LENGTH,
+ DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-B");
+ devfs_add_partition("nor0", NPE_C_START, NPE_C_LENGTH,
+ DEVFS_PARTITION_FIXED | DEVFS_PARTITION_READONLY, "NPE-C");
+ devfs_add_partition("nor0", NPE_ENV0_START, NPE_ENV0_LENGTH,
+ DEVFS_PARTITION_FIXED, "env0");
+
+ hw_bits = __raw_readl(IXP4XX_EXP_BASE(0) + CFG_HW_BITS);
+
+ if (hw_bits & CFG_HW_HAS_ETH0) {
+ for (i = 0; i < ETH_ALEN; i++)
+ eth_pinfo[0].hwaddr[i] = flash_readb(CFG_ETH0_ADDRESS + i);
+ register_device(ð_dev[0]);
+ }
+
+ if (hw_bits & CFG_HW_HAS_ETH1) {
+ for (i = 0; i < ETH_ALEN; i++)
+ eth_pinfo[1].hwaddr[i] = flash_readb(CFG_ETH1_ADDRESS + i);
+ register_device(ð_dev[1]);
+ }
+
+ sdram_dev.size = __raw_readl(IXP4XX_EXP_BASE(0) + CFG_SDRAM_SIZE);
+ i = register_device(&sdram_dev);
+ if (i)
+ goto out;
+
+ armlinux_add_dram(&sdram_dev);
+ armlinux_set_bootparams((void *)(0x00000100));
+ armlinux_set_architecture(MACH_TYPE_GORAMO_MLR);
+
+out:
+ return i;
+}
+device_initcall(gml_devices_init);
diff --git a/arch/arm/boards/multilink/multilink.dox b/arch/arm/boards/multilink/multilink.dox
new file mode 100644
index 0000000..eada1e1
--- /dev/null
+++ b/arch/arm/boards/multilink/multilink.dox
@@ -0,0 +1,36 @@
+/** @page multilink Goramo MultiLink
+
+These boards are based on Intel IXP42x CPU.
+
+Variants:
+
+MicroRouter module: IXP421 or IXP425 266 MHz CPU, 32 MiB SDRAM,
+ 1 or 2 Fast Ethernet ports, 2 sync serial ports, 1 RS-232 (console) port.
+
+MultiLink v.1: IXP425 266 or 533 MHz CPU, 64 - 256 MiB SDRAM,
+ 2 Fast Ethernet ports, 2 sync serial ports, 1 - 2 RS-232 ports,
+ a mini-PCI slot, 2 optional USB host connectors.
+
+MultiLink v.2: IXP425 266 or 533 MHz CPU, 64 - 256 MiB SDRAM,
+ 2 Fast Ethernet ports, 2 sync serial ports, 1 - 2 RS-232 ports,
+ 2 additional optional Fast or Gigabit Ethernet ports, a mini-PCI slot,
+ 4 optional USB host connectors, optional Real-Time Clock,
+ optional IDE connector.
+
+16 MiB Intel StrataFlash memory is partitioned as follows:
+
+0x00000-0x34000 : Barebox image
+0x34000-0x39000 : NPE-A microcode
+0x39000-0x3c000 : NPE-B microcode
+0x3c000-0x40000 : NPE-C microcode
+0x40000-0x60000 : env0
+
+There is a factory configuration region within Barebox image at locations
+0x40 - 0x7F. Details are in file multilink.c
+
+Barebox image and NPE microcode files are combined in first two blocks
+of flash memory. NPE-A microcode is not used by Barebox (but may be used
+by Linux HSS driver). NPE-B microcode is needed for eth0 and NPE-C for
+eth1. Barebox needs version 2.4 of regular non-VLAN-aware microcode files
+(with or without crypto support).
+*/
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
new file mode 100644
index 0000000..f5e4b41
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -0,0 +1,26 @@
+if ARCH_IXP4XX
+
+choice
+ prompt "IXP4xx Board Type"
+
+config MACH_MULTILINK
+ bool "Goramo MultiLink"
+ select MACH_HAS_LOWLEVEL_INIT
+endchoice
+
+config BOARDINFO
+ default "Goramo MultiLink" if MACH_MULTILINK
+
+config IXP4XX_QMGR
+ tristate "IXP4xx Queue Manager support"
+ help
+ This driver supports IXP4xx built-in hardware queue manager
+ and is required by the Ethernet driver.
+
+config IXP4XX_NPE
+ tristate "IXP4xx Network Processor Engine support"
+ help
+ This driver supports IXP4xx built-in network coprocessors
+ and is required by the Ethernet driver.
+
+endif
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
new file mode 100644
index 0000000..aa38991
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -0,0 +1,3 @@
+obj-y += lowlevel_init.o generic.o
+obj-$(CONFIG_IXP4XX_QMGR) += qmgr.o
+obj-$(CONFIG_IXP4XX_NPE) += npe.o
diff --git a/arch/arm/mach-ixp4xx/generic.c b/arch/arm/mach-ixp4xx/generic.c
new file mode 100644
index 0000000..02394a4
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/generic.c
@@ -0,0 +1,120 @@
+#include <common.h>
+#include <init.h>
+#include <ns16550.h>
+#include <asm/armlinux.h>
+#include <asm/io.h>
+#include <mach/ixp4xx-regs.h>
+
+#define OSTS_FREQUENCY 66666000
+
+void reset_cpu(ulong addr)
+{
+ /* Use on-chip reset capability */
+ /* This may not work on IXP425 rev. A0 */
+
+ IXP4XX_OSWK = IXP4XX_WDT_KEY;
+ IXP4XX_OSWT = 0; /* request immediate reset */
+ IXP4XX_OSWE = IXP4XX_WDT_RESET_ENABLE | IXP4XX_WDT_COUNT_ENABLE;
+ while (1)
+ ;
+}
+
+#include <clock.h>
+
+/**
+ * @brief Provide a simple clock read
+ *
+ * Nothing is simpler.. read direct from clock and provide it
+ * to the caller.
+ *
+ * @return clock counter
+ */
+static uint64_t ixp4xx_clocksource_read(void)
+{
+ return IXP4XX_OSTS;
+}
+
+static struct clocksource cs = {
+ .read = ixp4xx_clocksource_read,
+ .mask = 0xffffffff,
+ .shift = 10,
+};
+
+/**
+ * @brief Initialize the Clock
+ *
+ * We use the Time-Stamp Timer
+ *
+ * @return result of @ref init_clock
+ */
+static int ixp4xx_clocksource_init(void)
+{
+ cs.mult = clocksource_hz2mult(OSTS_FREQUENCY, cs.shift);
+
+ return init_clock(&cs);
+}
+
+/* Run me at boot time */
+core_initcall(ixp4xx_clocksource_init);
+
+
+#ifdef CONFIG_DRIVER_SERIAL_NS16550
+
+/**
+ * @brief UART port register read function for IXP4XX
+ *
+ * @param base base address of UART
+ * @param reg_idx register index
+ *
+ * @return character read from register
+ */
+unsigned int ixp4xx_uart_read(unsigned long base, unsigned char reg_idx)
+{
+ return readb(4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
+}
+EXPORT_SYMBOL(ixp4xx_uart_read);
+
+/**
+ * @brief UART port register write function for IXP4XX
+ *
+ * @param val value to write
+ * @param base base address of UART
+ * @param reg_idx register index
+ *
+ * @return void
+ */
+void ixp4xx_uart_write(unsigned int val, unsigned long base, unsigned char reg_idx)
+{
+ writeb(val, 4 * reg_idx + 3 /* big-endian */ + (uint8_t *)base);
+}
+EXPORT_SYMBOL(ixp4xx_uart_write);
+
+
+static struct NS16550_plat serial_plat = {
+ .clock = 14745600,
+ .f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR,
+ .reg_read = ixp4xx_uart_read,
+ .reg_write = ixp4xx_uart_write,
+};
+
+static struct device_d ixp4xx_serial_device = {
+ .name = "serial_ns16550",
+ .map_base = (u32)IXP4XX_UART1_BASE,
+ .size = 1024,
+ .platform_data = (void *)&serial_plat,
+};
+
+/**
+ * @brief UART serial port initialization
+ *
+ * @return result of device registration
+ */
+static int ixp4xx_console_init(void)
+{
+ /* Register the serial port */
+ return register_device(&ixp4xx_serial_device);
+}
+
+console_initcall(ixp4xx_console_init);
+
+#endif /* CONFIG_DRIVER_SERIAL_NS16550 */
diff --git a/arch/arm/mach-ixp4xx/include/mach/cpu.h b/arch/arm/mach-ixp4xx/include/mach/cpu.h
new file mode 100644
index 0000000..3de021e
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/mach-ixp4xx/include/mach/cpu.h
+ *
+ * IXP4XX cpu type detection
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ASM_ARCH_CPU_H__
+#define __ASM_ARCH_CPU_H__
+
+#include <linux/types.h>
+
+/* Processor id value in CP15 Register 0 */
+#define IXP42X_PROCESSOR_ID_VALUE 0x690541c0 /* including unused 0x690541Ex */
+#define IXP42X_PROCESSOR_ID_MASK 0xffffffc0
+
+#define IXP43X_PROCESSOR_ID_VALUE 0x69054040
+#define IXP43X_PROCESSOR_ID_MASK 0xfffffff0
+
+#define IXP46X_PROCESSOR_ID_VALUE 0x69054200 /* including IXP455 */
+#define IXP46X_PROCESSOR_ID_MASK 0xfffffff0
+
+#define cpu_is_ixp42x_rev_a0() ((read_cpuid_id() & (IXP42X_PROCESSOR_ID_MASK | 0xF)) == \
+ IXP42X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp42x() ((read_cpuid_id() & IXP42X_PROCESSOR_ID_MASK) == \
+ IXP42X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp43x() ((read_cpuid_id() & IXP43X_PROCESSOR_ID_MASK) == \
+ IXP43X_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp46x() ((read_cpuid_id() & IXP46X_PROCESSOR_ID_MASK) == \
+ IXP46X_PROCESSOR_ID_VALUE)
+
+/*
+ * The CPU ID never changes at run time, so we might as well tell the
+ * compiler that it's constant. Use this function to read the CPU ID
+ * rather than directly reading processor_id or read_cpuid() directly.
+ */
+static inline u32 __attribute_const__ read_cpuid_id(void)
+{
+ u32 val;
+ asm("mrc p15, 0, %0, c0, c0, 0" : "=r" (val) : : "cc");
+
+ return val;
+}
+
+static inline u32 ixp4xx_read_feature_bits(void)
+{
+ u32 val = ~IXP4XX_EXP_CFG2;
+
+ if (cpu_is_ixp42x_rev_a0())
+ return IXP42X_FEATURE_MASK & ~(IXP4XX_FEATURE_RCOMP |
+ IXP4XX_FEATURE_AES);
+ if (cpu_is_ixp42x())
+ return val & IXP42X_FEATURE_MASK;
+ if (cpu_is_ixp43x())
+ return val & IXP43X_FEATURE_MASK;
+ return val & IXP46X_FEATURE_MASK;
+}
+
+static inline void ixp4xx_write_feature_bits(u32 value)
+{
+ IXP4XX_EXP_CFG2 = ~value;
+}
+
+#endif /* _ASM_ARCH_CPU_H */
diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
new file mode 100644
index 0000000..da4dc8a
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
@@ -0,0 +1,365 @@
+/*
+ * Register definitions for IXP4xx chipset.
+ *
+ * Copyright (C) 2002 Intel Corporation.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _ASM_ARM_IXP4XX_H_
+#define _ASM_ARM_IXP4XX_H_
+
+#ifdef __ASSEMBLER__
+#define IXP4XX_REG(reg) (reg)
+#else
+#define IXP4XX_REG(reg) (*(volatile u32 *)(reg))
+#define IXP4XX_BASE(reg) ((u32*)(reg))
+#endif
+
+/* Expansion Bus region */
+
+/* Queue Manager */
+#define IXP4XX_QMGR_BASE (0x60000000)
+#define IXP4XX_QMGR_REGION_SIZE (0x00004000)
+
+
+/* PCI Config registers */
+#define IXP4XX_PCI_CFG_BASE (0xC0000000)
+#define IXP4XX_PCI_CFG_REGION_SIZE (0x00001000)
+
+/* Peripheral space */
+#define IXP4XX_PERIPHERAL_BASE (0xC8000000)
+#define IXP4XX_PERIPHERAL_REGION_SIZE (0x00013000)
+
+/*
+ * Debug UART
+ *
+ * This is basically a remap of UART1 into a region that is section
+ * aligned so that it can be used with the low-level debug code.
+ */
+#define IXP4XX_DEBUG_UART_BASE (0xC8000000)
+#define IXP4XX_DEBUG_UART_REGION_SIZE (0x00001000)
+
+/* Expansion Bus Controller registers. */
+#define IXP4XX_EXP_CS0 IXP4XX_REG(0xC4000000)
+#define IXP4XX_EXP_CS1 IXP4XX_REG(0xC4000004)
+#define IXP4XX_EXP_CS2 IXP4XX_REG(0xC4000008)
+#define IXP4XX_EXP_CS3 IXP4XX_REG(0xC400000C)
+#define IXP4XX_EXP_CS4 IXP4XX_REG(0xC4000010)
+#define IXP4XX_EXP_CS5 IXP4XX_REG(0xC4000014)
+#define IXP4XX_EXP_CS6 IXP4XX_REG(0xC4000018)
+#define IXP4XX_EXP_CS7 IXP4XX_REG(0xC400001C)
+
+#define IXP4XX_EXP_BASE(n) (0x50000000 + (n) * 1000000)
+
+#define IXP4XX_EXP_EN 0x80000000
+#define IXP4XX_EXP_T1(n) (0x10000000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T2(n) (0x04000000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T3(n) (0x00400000 * (n)) /* valid: 0 - 15 */
+#define IXP4XX_EXP_T4(n) (0x00100000 * (n)) /* valid: 0 - 3 */
+#define IXP4XX_EXP_T5(n) (0x00010000 * (n)) /* valid: 0 - 15 */
+#define IXP4XX_EXP_INTEL 0x00000000
+#define IXP4XX_EXP_MOTO 0x00004000
+#define IXP4XX_EXP_HPI 0x00008000
+#define IXP4XX_EXP_BITS(n) (0x00000400 * ((n) - 9)) /* valid: 9 - 24 */
+#define IXP4XX_EXP_BYTE_RD16 0x00000040
+#define IXP4XX_EXP_HRDY_POL 0x00000020
+#define IXP4XX_EXP_MUX_EN 0x00000010
+#define IXP4XX_EXP_SPLT_EN 0x00000008
+#define IXP4XX_EXP_WR_EN 0x00000002
+#define IXP4XX_EXP_BYTE_EN 0x00000001
+
+#define IXP4XX_EXP_CFG0 IXP4XX_REG(0xC4000020)
+#define IXP4XX_EXP_CFG1 IXP4XX_REG(0xC4000024)
+#define IXP4XX_EXP_CFG2 IXP4XX_REG(0xC4000028)
+#define IXP4XX_EXP_CFG3 IXP4XX_REG(0xC400002C)
+
+
+/* Peripheral Space Register Region Base Addresses */
+#define IXP4XX_UART1_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x0000)
+#define IXP4XX_UART2_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x1000)
+#define IXP4XX_PMU_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x2000)
+#define IXP4XX_INTC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x3000)
+#define IXP4XX_GPIO_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x4000)
+#define IXP4XX_NPEA_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x6000)
+#define IXP4XX_NPEB_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x7000)
+#define IXP4XX_NPEC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x8000)
+#define IXP4XX_EthB_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x9000)
+#define IXP4XX_EthC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xA000)
+#define IXP4XX_USB_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xB000)
+/* IXP46x only */
+#define IXP4XX_EthA_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xC000)
+#define IXP4XX_EthB1_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xD000)
+#define IXP4XX_EthB2_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xE000)
+#define IXP4XX_EthB3_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0xF000)
+#define IXP4XX_TIMESYNC_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x10000)
+#define IXP4XX_I2C_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x11000)
+#define IXP4XX_SSP_BASE IXP4XX_BASE(IXP4XX_PERIPHERAL_BASE + 0x12000)
+
+/*
+ Constants to make it easy to access Interrupt Controller registers
+ */
+#define IXP4XX_ICPR_OFFSET 0x00 /* Interrupt Status */
+#define IXP4XX_ICMR_OFFSET 0x04 /* Interrupt Enable */
+#define IXP4XX_ICLR_OFFSET 0x08 /* Interrupt IRQ/FIQ Select */
+#define IXP4XX_ICIP_OFFSET 0x0C /* IRQ Status */
+#define IXP4XX_ICFP_OFFSET 0x10 /* FIQ Status */
+#define IXP4XX_ICHR_OFFSET 0x14 /* Interrupt Priority */
+#define IXP4XX_ICIH_OFFSET 0x18 /* IRQ Highest Pri Int */
+#define IXP4XX_ICFH_OFFSET 0x1C /* FIQ Highest Pri Int */
+
+/* IXP465-only */
+#define IXP4XX_ICPR2_OFFSET 0x20 /* Interrupt Status 2 */
+#define IXP4XX_ICMR2_OFFSET 0x24 /* Interrupt Enable 2 */
+#define IXP4XX_ICLR2_OFFSET 0x28 /* Interrupt IRQ/FIQ Select 2 */
+#define IXP4XX_ICIP2_OFFSET 0x2C /* IRQ Status */
+#define IXP4XX_ICFP2_OFFSET 0x30 /* FIQ Status */
+#define IXP4XX_ICEEN_OFFSET 0x34 /* Error High Pri Enable */
+
+
+/* Interrupt Controller Register Definitions. */
+#define IXP4XX_INTC_REG(x) ((volatile u32 *)(IXP4XX_INTC_BASE + (x)))
+
+#define IXP4XX_ICPR IXP4XX_INTC_REG(IXP4XX_ICPR_OFFSET)
+#define IXP4XX_ICMR IXP4XX_INTC_REG(IXP4XX_ICMR_OFFSET)
+#define IXP4XX_ICLR IXP4XX_INTC_REG(IXP4XX_ICLR_OFFSET)
+#define IXP4XX_ICIP IXP4XX_INTC_REG(IXP4XX_ICIP_OFFSET)
+#define IXP4XX_ICFP IXP4XX_INTC_REG(IXP4XX_ICFP_OFFSET)
+#define IXP4XX_ICHR IXP4XX_INTC_REG(IXP4XX_ICHR_OFFSET)
+#define IXP4XX_ICIH IXP4XX_INTC_REG(IXP4XX_ICIH_OFFSET)
+#define IXP4XX_ICFH IXP4XX_INTC_REG(IXP4XX_ICFH_OFFSET)
+#define IXP4XX_ICPR2 IXP4XX_INTC_REG(IXP4XX_ICPR2_OFFSET)
+#define IXP4XX_ICMR2 IXP4XX_INTC_REG(IXP4XX_ICMR2_OFFSET)
+#define IXP4XX_ICLR2 IXP4XX_INTC_REG(IXP4XX_ICLR2_OFFSET)
+#define IXP4XX_ICIP2 IXP4XX_INTC_REG(IXP4XX_ICIP2_OFFSET)
+#define IXP4XX_ICFP2 IXP4XX_INTC_REG(IXP4XX_ICFP2_OFFSET)
+#define IXP4XX_ICEEN IXP4XX_INTC_REG(IXP4XX_ICEEN_OFFSET)
+
+/* Constants to make it easy to access GPIO registers */
+#define IXP4XX_GPIO_GPOUTR_OFFSET 0x00
+#define IXP4XX_GPIO_GPOER_OFFSET 0x04
+#define IXP4XX_GPIO_GPINR_OFFSET 0x08
+#define IXP4XX_GPIO_GPISR_OFFSET 0x0C
+#define IXP4XX_GPIO_GPIT1R_OFFSET 0x10
+#define IXP4XX_GPIO_GPIT2R_OFFSET 0x14
+#define IXP4XX_GPIO_GPCLKR_OFFSET 0x18
+#define IXP4XX_GPIO_GPDBSELR_OFFSET 0x1C
+
+/* GPIO Register Definitions - perform only 32-bit reads/writes */
+#define IXP4XX_GPIO_REG(x) ((volatile u32 *)(IXP4XX_GPIO_BASE + (x)))
+
+#define IXP4XX_GPIO_GPOUTR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOUTR_OFFSET)
+#define IXP4XX_GPIO_GPOER IXP4XX_GPIO_REG(IXP4XX_GPIO_GPOER_OFFSET)
+#define IXP4XX_GPIO_GPINR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPINR_OFFSET)
+#define IXP4XX_GPIO_GPISR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPISR_OFFSET)
+#define IXP4XX_GPIO_GPIT1R IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT1R_OFFSET)
+#define IXP4XX_GPIO_GPIT2R IXP4XX_GPIO_REG(IXP4XX_GPIO_GPIT2R_OFFSET)
+#define IXP4XX_GPIO_GPCLKR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPCLKR_OFFSET)
+#define IXP4XX_GPIO_GPDBSELR IXP4XX_GPIO_REG(IXP4XX_GPIO_GPDBSELR_OFFSET)
+
+/* GPIO register bit definitions */
+
+/* Interrupt styles */
+#define IXP4XX_GPIO_STYLE_ACTIVE_HIGH 0x0
+#define IXP4XX_GPIO_STYLE_ACTIVE_LOW 0x1
+#define IXP4XX_GPIO_STYLE_RISING_EDGE 0x2
+#define IXP4XX_GPIO_STYLE_FALLING_EDGE 0x3
+#define IXP4XX_GPIO_STYLE_TRANSITIONAL 0x4
+
+/* Mask used to clear interrupt styles */
+#define IXP4XX_GPIO_STYLE_CLEAR 0x7
+#define IXP4XX_GPIO_STYLE_SIZE 3
+
+/* Operating System Timer Register Definitions. */
+#define IXP4XX_OSTS IXP4XX_REG(0xC8005000) /* Continious TimeStamp */
+#define IXP4XX_OST1 IXP4XX_REG(0xC8005004) /* Timer 1 Timestamp */
+#define IXP4XX_OSRT1 IXP4XX_REG(0xC8005008) /* Timer 1 Reload */
+#define IXP4XX_OST2 IXP4XX_REG(0xC800500C) /* Timer 2 Timestamp */
+#define IXP4XX_OSRT2 IXP4XX_REG(0xC8005010) /* Timer 2 Reload */
+#define IXP4XX_OSWT IXP4XX_REG(0xC8005014) /* Watchdog Timer */
+#define IXP4XX_OSWE IXP4XX_REG(0xC8005018) /* Watchdog Enable */
+#define IXP4XX_OSWK IXP4XX_REG(0xC800501C) /* Watchdog Key */
+#define IXP4XX_OSST IXP4XX_REG(0xC8005020) /* Timer Status */
+
+/* Timer register values and bit definitions */
+#define IXP4XX_OST_ENABLE 0x00000001
+#define IXP4XX_OST_ONE_SHOT 0x00000002
+/* Low order bits of reload value ignored */
+#define IXP4XX_OST_RELOAD_MASK 0x00000003
+#define IXP4XX_OST_DISABLED 0x00000000
+#define IXP4XX_OSST_TIMER_1_PEND 0x00000001
+#define IXP4XX_OSST_TIMER_2_PEND 0x00000002
+#define IXP4XX_OSST_TIMER_TS_PEND 0x00000004
+#define IXP4XX_OSST_TIMER_WDOG_PEND 0x00000008
+#define IXP4XX_OSST_TIMER_WARM_RESET 0x00000010
+
+#define IXP4XX_WDT_KEY 0x0000482E
+
+#define IXP4XX_WDT_RESET_ENABLE 0x00000001
+#define IXP4XX_WDT_IRQ_ENABLE 0x00000002
+#define IXP4XX_WDT_COUNT_ENABLE 0x00000004
+
+
+/* Constants to make it easy to access PCI Control/Status registers */
+#define PCI_NP_AD_OFFSET 0x00
+#define PCI_NP_CBE_OFFSET 0x04
+#define PCI_NP_WDATA_OFFSET 0x08
+#define PCI_NP_RDATA_OFFSET 0x0c
+#define PCI_CRP_AD_CBE_OFFSET 0x10
+#define PCI_CRP_WDATA_OFFSET 0x14
+#define PCI_CRP_RDATA_OFFSET 0x18
+#define PCI_CSR_OFFSET 0x1c
+#define PCI_ISR_OFFSET 0x20
+#define PCI_INTEN_OFFSET 0x24
+#define PCI_DMACTRL_OFFSET 0x28
+#define PCI_AHBMEMBASE_OFFSET 0x2c
+#define PCI_AHBIOBASE_OFFSET 0x30
+#define PCI_PCIMEMBASE_OFFSET 0x34
+#define PCI_AHBDOORBELL_OFFSET 0x38
+#define PCI_PCIDOORBELL_OFFSET 0x3C
+#define PCI_ATPDMA0_AHBADDR_OFFSET 0x40
+#define PCI_ATPDMA0_PCIADDR_OFFSET 0x44
+#define PCI_ATPDMA0_LENADDR_OFFSET 0x48
+#define PCI_ATPDMA1_AHBADDR_OFFSET 0x4C
+#define PCI_ATPDMA1_PCIADDR_OFFSET 0x50
+#define PCI_ATPDMA1_LENADDR_OFFSET 0x54
+
+/* PCI Control/Status Registers */
+#define IXP4XX_PCI_CSR(x) ((volatile u32 *)(IXP4XX_PCI_CFG_BASE + (x)))
+
+#define PCI_NP_AD IXP4XX_PCI_CSR(PCI_NP_AD_OFFSET)
+#define PCI_NP_CBE IXP4XX_PCI_CSR(PCI_NP_CBE_OFFSET)
+#define PCI_NP_WDATA IXP4XX_PCI_CSR(PCI_NP_WDATA_OFFSET)
+#define PCI_NP_RDATA IXP4XX_PCI_CSR(PCI_NP_RDATA_OFFSET)
+#define PCI_CRP_AD_CBE IXP4XX_PCI_CSR(PCI_CRP_AD_CBE_OFFSET)
+#define PCI_CRP_WDATA IXP4XX_PCI_CSR(PCI_CRP_WDATA_OFFSET)
+#define PCI_CRP_RDATA IXP4XX_PCI_CSR(PCI_CRP_RDATA_OFFSET)
+#define PCI_CSR IXP4XX_PCI_CSR(PCI_CSR_OFFSET)
+#define PCI_ISR IXP4XX_PCI_CSR(PCI_ISR_OFFSET)
+#define PCI_INTEN IXP4XX_PCI_CSR(PCI_INTEN_OFFSET)
+#define PCI_DMACTRL IXP4XX_PCI_CSR(PCI_DMACTRL_OFFSET)
+#define PCI_AHBMEMBASE IXP4XX_PCI_CSR(PCI_AHBMEMBASE_OFFSET)
+#define PCI_AHBIOBASE IXP4XX_PCI_CSR(PCI_AHBIOBASE_OFFSET)
+#define PCI_PCIMEMBASE IXP4XX_PCI_CSR(PCI_PCIMEMBASE_OFFSET)
+#define PCI_AHBDOORBELL IXP4XX_PCI_CSR(PCI_AHBDOORBELL_OFFSET)
+#define PCI_PCIDOORBELL IXP4XX_PCI_CSR(PCI_PCIDOORBELL_OFFSET)
+#define PCI_ATPDMA0_AHBADDR IXP4XX_PCI_CSR(PCI_ATPDMA0_AHBADDR_OFFSET)
+#define PCI_ATPDMA0_PCIADDR IXP4XX_PCI_CSR(PCI_ATPDMA0_PCIADDR_OFFSET)
+#define PCI_ATPDMA0_LENADDR IXP4XX_PCI_CSR(PCI_ATPDMA0_LENADDR_OFFSET)
+#define PCI_ATPDMA1_AHBADDR IXP4XX_PCI_CSR(PCI_ATPDMA1_AHBADDR_OFFSET)
+#define PCI_ATPDMA1_PCIADDR IXP4XX_PCI_CSR(PCI_ATPDMA1_PCIADDR_OFFSET)
+#define PCI_ATPDMA1_LENADDR IXP4XX_PCI_CSR(PCI_ATPDMA1_LENADDR_OFFSET)
+
+/* PCI register values and bit definitions */
+
+/* CSR bit definitions */
+#define PCI_CSR_HOST 0x00000001
+#define PCI_CSR_ARBEN 0x00000002
+#define PCI_CSR_ADS 0x00000004
+#define PCI_CSR_PDS 0x00000008
+#define PCI_CSR_ABE 0x00000010
+#define PCI_CSR_DBT 0x00000020
+#define PCI_CSR_ASE 0x00000100
+#define PCI_CSR_IC 0x00008000
+
+/* ISR (Interrupt status) Register bit definitions */
+#define PCI_ISR_PSE 0x00000001
+#define PCI_ISR_PFE 0x00000002
+#define PCI_ISR_PPE 0x00000004
+#define PCI_ISR_AHBE 0x00000008
+#define PCI_ISR_APDC 0x00000010
+#define PCI_ISR_PADC 0x00000020
+#define PCI_ISR_ADB 0x00000040
+#define PCI_ISR_PDB 0x00000080
+
+/* INTEN (Interrupt Enable) Register bit definitions */
+#define PCI_INTEN_PSE 0x00000001
+#define PCI_INTEN_PFE 0x00000002
+#define PCI_INTEN_PPE 0x00000004
+#define PCI_INTEN_AHBE 0x00000008
+#define PCI_INTEN_APDC 0x00000010
+#define PCI_INTEN_PADC 0x00000020
+#define PCI_INTEN_ADB 0x00000040
+#define PCI_INTEN_PDB 0x00000080
+
+/* Shift value for byte enable on NP cmd/byte enable register */
+#define IXP4XX_PCI_NP_CBE_BESL 4
+
+/* PCI commands supported by NP access unit */
+#define NP_CMD_IOREAD 0x2
+#define NP_CMD_IOWRITE 0x3
+#define NP_CMD_CONFIGREAD 0xA
+#define NP_CMD_CONFIGWRITE 0xB
+#define NP_CMD_MEMREAD 0x6
+#define NP_CMD_MEMWRITE 0x7
+
+/* Constants for CRP access into local config space */
+#define CRP_AD_CBE_BESL 20
+#define CRP_AD_CBE_WRITE 0x00010000
+
+/* USB Device Controller */
+# define IXP4XX_USB_REG(x) (*((volatile u32 *)(x)))
+
+/* SDRAM Controller registers. */
+#define IXP4XX_SDRAM_CONFIG IXP4XX_REG(0xCC000000)
+#define IXP4XX_SDRAM_REFRESH IXP4XX_REG(0xCC000004)
+#define IXP4XX_SDRAM_IR IXP4XX_REG(0xCC000008)
+
+/* "fuse" bits of IXP_EXP_CFG2 */
+/* All IXP4xx CPUs */
+#define IXP4XX_FEATURE_RCOMP (1 << 0)
+#define IXP4XX_FEATURE_USB_DEVICE (1 << 1)
+#define IXP4XX_FEATURE_HASH (1 << 2)
+#define IXP4XX_FEATURE_AES (1 << 3)
+#define IXP4XX_FEATURE_DES (1 << 4)
+#define IXP4XX_FEATURE_HDLC (1 << 5)
+#define IXP4XX_FEATURE_AAL (1 << 6)
+#define IXP4XX_FEATURE_HSS (1 << 7)
+#define IXP4XX_FEATURE_UTOPIA (1 << 8)
+#define IXP4XX_FEATURE_NPEB_ETH0 (1 << 9)
+#define IXP4XX_FEATURE_NPEC_ETH (1 << 10)
+#define IXP4XX_FEATURE_RESET_NPEA (1 << 11)
+#define IXP4XX_FEATURE_RESET_NPEB (1 << 12)
+#define IXP4XX_FEATURE_RESET_NPEC (1 << 13)
+#define IXP4XX_FEATURE_PCI (1 << 14)
+#define IXP4XX_FEATURE_UTOPIA_PHY_LIMIT (3 << 16)
+#define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22)
+#define IXP42X_FEATURE_MASK (IXP4XX_FEATURE_RCOMP | \
+ IXP4XX_FEATURE_USB_DEVICE | \
+ IXP4XX_FEATURE_HASH | \
+ IXP4XX_FEATURE_AES | \
+ IXP4XX_FEATURE_DES | \
+ IXP4XX_FEATURE_HDLC | \
+ IXP4XX_FEATURE_AAL | \
+ IXP4XX_FEATURE_HSS | \
+ IXP4XX_FEATURE_UTOPIA | \
+ IXP4XX_FEATURE_NPEB_ETH0 | \
+ IXP4XX_FEATURE_NPEC_ETH | \
+ IXP4XX_FEATURE_RESET_NPEA | \
+ IXP4XX_FEATURE_RESET_NPEB | \
+ IXP4XX_FEATURE_RESET_NPEC | \
+ IXP4XX_FEATURE_PCI | \
+ IXP4XX_FEATURE_UTOPIA_PHY_LIMIT | \
+ IXP4XX_FEATURE_XSCALE_MAX_FREQ)
+
+/* IXP43x/46x CPUs */
+#define IXP4XX_FEATURE_ECC_TIMESYNC (1 << 15)
+#define IXP4XX_FEATURE_USB_HOST (1 << 18)
+#define IXP4XX_FEATURE_NPEA_ETH (1 << 19)
+#define IXP43X_FEATURE_MASK (IXP42X_FEATURE_MASK | \
+ IXP4XX_FEATURE_ECC_TIMESYNC | \
+ IXP4XX_FEATURE_USB_HOST | \
+ IXP4XX_FEATURE_NPEA_ETH)
+
+/* IXP46x CPU (including IXP455) only */
+#define IXP4XX_FEATURE_NPEB_ETH_1_TO_3 (1 << 20)
+#define IXP4XX_FEATURE_RSA (1 << 21)
+#define IXP46X_FEATURE_MASK (IXP43X_FEATURE_MASK | \
+ IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \
+ IXP4XX_FEATURE_RSA)
+
+#endif
diff --git a/arch/arm/mach-ixp4xx/include/mach/npe.h b/arch/arm/mach-ixp4xx/include/mach/npe.h
new file mode 100644
index 0000000..18bd01b
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/npe.h
@@ -0,0 +1,30 @@
+#ifndef __IXP4XX_NPE_H
+#define __IXP4XX_NPE_H
+
+#include <common.h>
+
+#define NPE_NAME_LENGTH 5
+
+struct npe_regs {
+ u32 exec_addr, exec_data, exec_status_cmd, exec_count;
+ u32 action_points[4];
+ u32 watchpoint_fifo, watch_count;
+ u32 profile_count;
+ u32 messaging_status, messaging_control;
+ u32 mailbox_status, /*messaging_*/ in_out_fifo;
+};
+
+struct npe {
+ struct npe_regs *regs;
+ int id, valid;
+ const char name[NPE_NAME_LENGTH + 1];
+};
+
+int npe_running(struct npe *npe);
+int npe_send_message(struct npe *npe, const void *msg, const char *what);
+int npe_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what);
+int npe_load_firmware(struct npe *npe);
+struct npe *npe_request(int id);
+
+#endif /* __IXP4XX_NPE_H */
diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h
new file mode 100644
index 0000000..1df4aa4
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
@@ -0,0 +1,15 @@
+#include <asm/types.h>
+
+#define IXP4XX_ETH_NPEA 0x00
+#define IXP4XX_ETH_NPEB 0x10
+#define IXP4XX_ETH_NPEC 0x20
+
+/* Information about built-in Ethernet MAC interfaces */
+struct eth_plat_info {
+ void *regs;
+ u8 npe;
+ u8 phy; /* MII PHY ID, 0 - 31 */
+ u8 rxq; /* configurable, currently 0 - 31 only */
+ u8 txreadyq;
+ u8 hwaddr[6];
+};
diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
new file mode 100644
index 0000000..4e9b8d4
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef IXP4XX_QMGR_H
+#define IXP4XX_QMGR_H
+
+#include <common.h>
+#include <mach/ixp4xx-regs.h>
+#include <asm/io.h>
+
+#define DEBUG_QMGR 0
+
+#define HALF_QUEUES 32
+#define QUEUES 64
+#define MAX_QUEUE_LENGTH 4 /* in dwords */
+
+#define QUEUE_STAT1_EMPTY 1 /* queue status bits */
+#define QUEUE_STAT1_NEARLY_EMPTY 2
+#define QUEUE_STAT1_NEARLY_FULL 4
+#define QUEUE_STAT1_FULL 8
+#define QUEUE_STAT2_UNDERFLOW 1
+#define QUEUE_STAT2_OVERFLOW 2
+
+#define QUEUE_WATERMARK_0_ENTRIES 0
+#define QUEUE_WATERMARK_1_ENTRY 1
+#define QUEUE_WATERMARK_2_ENTRIES 2
+#define QUEUE_WATERMARK_4_ENTRIES 3
+#define QUEUE_WATERMARK_8_ENTRIES 4
+#define QUEUE_WATERMARK_16_ENTRIES 5
+#define QUEUE_WATERMARK_32_ENTRIES 6
+#define QUEUE_WATERMARK_64_ENTRIES 7
+
+/* queue interrupt request conditions */
+#define QUEUE_IRQ_SRC_EMPTY 0
+#define QUEUE_IRQ_SRC_NEARLY_EMPTY 1
+#define QUEUE_IRQ_SRC_NEARLY_FULL 2
+#define QUEUE_IRQ_SRC_FULL 3
+#define QUEUE_IRQ_SRC_NOT_EMPTY 4
+#define QUEUE_IRQ_SRC_NOT_NEARLY_EMPTY 5
+#define QUEUE_IRQ_SRC_NOT_NEARLY_FULL 6
+#define QUEUE_IRQ_SRC_NOT_FULL 7
+
+struct qmgr_regs {
+ u32 acc[QUEUES][MAX_QUEUE_LENGTH]; /* 0x000 - 0x3FF */
+ u32 stat1[4]; /* 0x400 - 0x40F */
+ u32 stat2[2]; /* 0x410 - 0x417 */
+ u32 statne_h; /* 0x418 - queue nearly empty */
+ u32 statf_h; /* 0x41C - queue full */
+ u32 irqsrc[4]; /* 0x420 - 0x42F IRC source */
+ u32 irqen[2]; /* 0x430 - 0x437 IRQ enabled */
+ u32 irqstat[2]; /* 0x438 - 0x43F - IRQ access only */
+ u32 reserved[1776];
+ u32 sram[2048]; /* 0x2000 - 0x3FFF - config and buffer */
+};
+
+static const struct qmgr_regs *qmgr_regs = (struct qmgr_regs *)IXP4XX_QMGR_BASE;
+
+void qmgr_set_irq(unsigned int queue, int src,
+ void (*handler)(void *pdev), void *pdev);
+void qmgr_enable_irq(unsigned int queue);
+void qmgr_disable_irq(unsigned int queue);
+
+/* request_ and release_queue() must be called from non-IRQ context */
+
+#if DEBUG_QMGR
+extern char qmgr_queue_descs[HALF_QUEUES][32];
+
+void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+ unsigned int nearly_empty_watermark,
+ unsigned int nearly_full_watermark,
+ const char *desc_format, const char* name);
+#else
+void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+ unsigned int nearly_empty_watermark,
+ unsigned int nearly_full_watermark);
+#define qmgr_request_queue(queue, len, nearly_empty_watermark, \
+ nearly_full_watermark, desc_format, name) \
+ __qmgr_request_queue(queue, len, nearly_empty_watermark, \
+ nearly_full_watermark)
+#endif
+
+void qmgr_release_queue(unsigned int queue);
+
+
+static inline void qmgr_put_entry(unsigned int queue, u32 val)
+{
+#if DEBUG_QMGR
+ BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+ fprintf(stderr, "Queue %s(%i) put %X\n",
+ qmgr_queue_descs[queue], queue, val);
+#endif
+ __raw_writel(val, &qmgr_regs->acc[queue][0]);
+}
+
+static inline u32 qmgr_get_entry(unsigned int queue)
+{
+ u32 val;
+ val = __raw_readl(&qmgr_regs->acc[queue][0]);
+#if DEBUG_QMGR
+ BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
+
+ fprintf(stderr, "Queue %s(%i) get %X\n",
+ qmgr_queue_descs[queue], queue, val);
+#endif
+ return val;
+}
+
+static inline int __qmgr_get_stat1(unsigned int queue)
+{
+ return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
+ >> ((queue & 7) << 2)) & 0xF;
+}
+
+/**
+ * qmgr_stat_empty() - checks if a hardware queue is empty
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is empty.
+ */
+static inline int qmgr_stat_empty(unsigned int queue)
+{
+ return __qmgr_get_stat1(queue) & QUEUE_STAT1_EMPTY;
+}
+
+/**
+ * qmgr_stat_below_low_watermark() - checks if a queue is below low watermark
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is below low watermark.
+ */
+static inline int qmgr_stat_below_low_watermark(unsigned int queue)
+{
+ return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_EMPTY;
+}
+
+/**
+ * qmgr_stat_above_high_watermark() - checks if a queue is above high watermark
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is above high watermark
+ */
+static inline int qmgr_stat_above_high_watermark(unsigned int queue)
+{
+ return __qmgr_get_stat1(queue) & QUEUE_STAT1_NEARLY_FULL;
+}
+
+/**
+ * qmgr_stat_full() - checks if a hardware queue is full
+ * @queue: queue number
+ *
+ * Returns non-zero value if the queue is full.
+ */
+static inline int qmgr_stat_full(unsigned int queue)
+{
+ return __qmgr_get_stat1(queue) & QUEUE_STAT1_FULL;
+}
+
+#endif
diff --git a/arch/arm/mach-ixp4xx/lowlevel_init.S b/arch/arm/mach-ixp4xx/lowlevel_init.S
new file mode 100644
index 0000000..a4e93ef
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/lowlevel_init.S
@@ -0,0 +1,17 @@
+#include <mach/ixp4xx-regs.h>
+
+ .section ".text_bare_init", "ax"
+
+ .globl arch_init_lowlevel
+arch_init_lowlevel:
+ ldr r0, cfg
+ ldr r1, [r0]
+ and r1, r1, #~0x80000000 /* unmap EXP bus from 0x0 */
+ str r1, [r0]
+
+ /* return to ROM */
+ orr lr, #0x50000000
+ mov pc, lr
+
+cfg:
+ .word IXP4XX_EXP_CFG0
diff --git a/arch/arm/mach-ixp4xx/npe.c b/arch/arm/mach-ixp4xx/npe.c
new file mode 100644
index 0000000..a8ddd5a
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/npe.c
@@ -0,0 +1,668 @@
+/*
+ * Intel IXP4xx Network Processor Engine driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <fs.h>
+#include <init.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <mach/ixp4xx-regs.h>
+#include <mach/cpu.h>
+#include <mach/npe.h>
+
+#define DEBUG_MSG 0
+#define DEBUG_FW 0
+
+#define NPE_COUNT 3
+#define MAX_RETRIES 1000 /* microseconds */
+#define NPE_42X_DATA_SIZE 0x800 /* in dwords */
+#define NPE_46X_DATA_SIZE 0x1000
+#define NPE_A_42X_INSTR_SIZE 0x1000
+#define NPE_B_AND_C_42X_INSTR_SIZE 0x800
+#define NPE_46X_INSTR_SIZE 0x1000
+#define REGS_SIZE 0x1000
+
+#define NPE_PHYS_REG 32
+
+#define FW_MAGIC 0xFEEDF00D
+#define FW_BLOCK_TYPE_INSTR 0x0
+#define FW_BLOCK_TYPE_DATA 0x1
+#define FW_BLOCK_TYPE_EOF 0xF
+
+/* NPE exec status (read) and command (write) */
+#define CMD_NPE_STEP 0x01
+#define CMD_NPE_START 0x02
+#define CMD_NPE_STOP 0x03
+#define CMD_NPE_CLR_PIPE 0x04
+#define CMD_CLR_PROFILE_CNT 0x0C
+#define CMD_RD_INS_MEM 0x10 /* instruction memory */
+#define CMD_WR_INS_MEM 0x11
+#define CMD_RD_DATA_MEM 0x12 /* data memory */
+#define CMD_WR_DATA_MEM 0x13
+#define CMD_RD_ECS_REG 0x14 /* exec access register */
+#define CMD_WR_ECS_REG 0x15
+
+#define STAT_RUN 0x80000000
+#define STAT_STOP 0x40000000
+#define STAT_CLEAR 0x20000000
+#define STAT_ECS_K 0x00800000 /* pipeline clean */
+
+#define NPE_STEVT 0x1B
+#define NPE_STARTPC 0x1C
+#define NPE_REGMAP 0x1E
+#define NPE_CINDEX 0x1F
+
+#define INSTR_WR_REG_SHORT 0x0000C000
+#define INSTR_WR_REG_BYTE 0x00004000
+#define INSTR_RD_FIFO 0x0F888220
+#define INSTR_RESET_MBOX 0x0FAC8210
+
+#define ECS_BG_CTXT_REG_0 0x00 /* Background Executing Context */
+#define ECS_BG_CTXT_REG_1 0x01 /* Stack level */
+#define ECS_BG_CTXT_REG_2 0x02
+#define ECS_PRI_1_CTXT_REG_0 0x04 /* Priority 1 Executing Context */
+#define ECS_PRI_1_CTXT_REG_1 0x05 /* Stack level */
+#define ECS_PRI_1_CTXT_REG_2 0x06
+#define ECS_PRI_2_CTXT_REG_0 0x08 /* Priority 2 Executing Context */
+#define ECS_PRI_2_CTXT_REG_1 0x09 /* Stack level */
+#define ECS_PRI_2_CTXT_REG_2 0x0A
+#define ECS_DBG_CTXT_REG_0 0x0C /* Debug Executing Context */
+#define ECS_DBG_CTXT_REG_1 0x0D /* Stack level */
+#define ECS_DBG_CTXT_REG_2 0x0E
+#define ECS_INSTRUCT_REG 0x11 /* NPE Instruction Register */
+
+#define ECS_REG_0_ACTIVE 0x80000000 /* all levels */
+#define ECS_REG_0_NEXTPC_MASK 0x1FFF0000 /* BG/PRI1/PRI2 levels */
+#define ECS_REG_0_LDUR_BITS 8
+#define ECS_REG_0_LDUR_MASK 0x00000700 /* all levels */
+#define ECS_REG_1_CCTXT_BITS 16
+#define ECS_REG_1_CCTXT_MASK 0x000F0000 /* all levels */
+#define ECS_REG_1_SELCTXT_BITS 0
+#define ECS_REG_1_SELCTXT_MASK 0x0000000F /* all levels */
+#define ECS_DBG_REG_2_IF 0x00100000 /* debug level */
+#define ECS_DBG_REG_2_IE 0x00080000 /* debug level */
+
+/* NPE watchpoint_fifo register bit */
+#define WFIFO_VALID 0x80000000
+
+/* NPE messaging_status register bit definitions */
+#define MSGSTAT_OFNE 0x00010000 /* OutFifoNotEmpty */
+#define MSGSTAT_IFNF 0x00020000 /* InFifoNotFull */
+#define MSGSTAT_OFNF 0x00040000 /* OutFifoNotFull */
+#define MSGSTAT_IFNE 0x00080000 /* InFifoNotEmpty */
+#define MSGSTAT_MBINT 0x00100000 /* Mailbox interrupt */
+#define MSGSTAT_IFINT 0x00200000 /* InFifo interrupt */
+#define MSGSTAT_OFINT 0x00400000 /* OutFifo interrupt */
+#define MSGSTAT_WFINT 0x00800000 /* WatchFifo interrupt */
+
+/* NPE messaging_control register bit definitions */
+#define MSGCTL_OUT_FIFO 0x00010000 /* enable output FIFO */
+#define MSGCTL_IN_FIFO 0x00020000 /* enable input FIFO */
+#define MSGCTL_OUT_FIFO_WRITE 0x01000000 /* enable FIFO + WRITE */
+#define MSGCTL_IN_FIFO_WRITE 0x02000000
+
+/* NPE mailbox_status value for reset */
+#define RESET_MBOX_STAT 0x0000F0F0
+
+#define print_npe(npe, fmt, ...) fprintf(stderr, "%s: " fmt, npe->name, ## __VA_ARGS__)
+
+#if DEBUG_MSG
+#define debug_msg(npe, fmt, ...) print_npe(npe, fmt, ## __VA_ARGS__)
+#else
+#define debug_msg(npe, fmt, ...)
+#endif
+
+static struct {
+ u32 reg, val;
+} ecs_reset[] = {
+ {ECS_BG_CTXT_REG_0, 0xA0000000},
+ {ECS_BG_CTXT_REG_1, 0x01000000},
+ {ECS_BG_CTXT_REG_2, 0x00008000},
+ {ECS_PRI_1_CTXT_REG_0, 0x20000080},
+ {ECS_PRI_1_CTXT_REG_1, 0x01000000},
+ {ECS_PRI_1_CTXT_REG_2, 0x00008000},
+ {ECS_PRI_2_CTXT_REG_0, 0x20000080},
+ {ECS_PRI_2_CTXT_REG_1, 0x01000000},
+ {ECS_PRI_2_CTXT_REG_2, 0x00008000},
+ {ECS_DBG_CTXT_REG_0, 0x20000000},
+ {ECS_DBG_CTXT_REG_1, 0x00000000},
+ {ECS_DBG_CTXT_REG_2, 0x001E0000},
+ {ECS_INSTRUCT_REG, 0x1003C00F},
+};
+
+static struct npe npe_tab[NPE_COUNT] = {
+ {
+ .regs = (struct npe_regs *)IXP4XX_NPEA_BASE,
+ .id = 0,
+ .name = "NPE-A",
+ }, {
+ .regs = (struct npe_regs *)IXP4XX_NPEB_BASE,
+ .id = 1,
+ .name = "NPE-B",
+ }, {
+ .regs = (struct npe_regs *)IXP4XX_NPEC_BASE,
+ .id = 2,
+ .name = "NPE-C",
+ }
+};
+
+int npe_running(struct npe *npe)
+{
+ return (__raw_readl(&npe->regs->exec_status_cmd) & STAT_RUN) != 0;
+}
+
+static void npe_cmd_write(struct npe *npe, u32 addr, int cmd, u32 data)
+{
+ __raw_writel(data, &npe->regs->exec_data);
+ __raw_writel(addr, &npe->regs->exec_addr);
+ __raw_writel(cmd, &npe->regs->exec_status_cmd);
+}
+
+static u32 npe_cmd_read(struct npe *npe, u32 addr, int cmd)
+{
+ __raw_writel(addr, &npe->regs->exec_addr);
+ __raw_writel(cmd, &npe->regs->exec_status_cmd);
+ /* Iintroduce extra read cycles after issuing read command to NPE
+ so that we read the register after the NPE has updated it.
+ This is to overcome race condition between XScale and NPE */
+ __raw_readl(&npe->regs->exec_data);
+ __raw_readl(&npe->regs->exec_data);
+ return __raw_readl(&npe->regs->exec_data);
+}
+
+static void npe_clear_active(struct npe *npe, u32 reg)
+{
+ u32 val = npe_cmd_read(npe, reg, CMD_RD_ECS_REG);
+ npe_cmd_write(npe, reg, CMD_WR_ECS_REG, val & ~ECS_REG_0_ACTIVE);
+}
+
+static void npe_start(struct npe *npe)
+{
+ /* ensure only Background Context Stack Level is active */
+ npe_clear_active(npe, ECS_PRI_1_CTXT_REG_0);
+ npe_clear_active(npe, ECS_PRI_2_CTXT_REG_0);
+ npe_clear_active(npe, ECS_DBG_CTXT_REG_0);
+
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+ __raw_writel(CMD_NPE_START, &npe->regs->exec_status_cmd);
+}
+
+static void npe_stop(struct npe *npe)
+{
+ __raw_writel(CMD_NPE_STOP, &npe->regs->exec_status_cmd);
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd); /*FIXME?*/
+}
+
+static int npe_debug_instr(struct npe *npe, u32 instr, u32 ctx, u32 ldur)
+{
+ u32 wc;
+ int i;
+
+ /* set the Active bit, and the LDUR, in the debug level */
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG,
+ ECS_REG_0_ACTIVE | (ldur << ECS_REG_0_LDUR_BITS));
+
+ /* set CCTXT at ECS DEBUG L3 to specify in which context to execute
+ the instruction, and set SELCTXT at ECS DEBUG Level to specify
+ which context store to access.
+ Debug ECS Level Reg 1 has form 0x000n000n, where n = context number
+ */
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_1, CMD_WR_ECS_REG,
+ (ctx << ECS_REG_1_CCTXT_BITS) |
+ (ctx << ECS_REG_1_SELCTXT_BITS));
+
+ /* clear the pipeline */
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+
+ /* load NPE instruction into the instruction register */
+ npe_cmd_write(npe, ECS_INSTRUCT_REG, CMD_WR_ECS_REG, instr);
+
+ /* we need this value later to wait for completion of NPE execution
+ step */
+ wc = __raw_readl(&npe->regs->watch_count);
+
+ /* issue a Step One command via the Execution Control register */
+ __raw_writel(CMD_NPE_STEP, &npe->regs->exec_status_cmd);
+
+ /* Watch Count register increments when NPE completes an instruction */
+ for (i = 0; i < MAX_RETRIES; i++) {
+ if (wc != __raw_readl(&npe->regs->watch_count))
+ return 0;
+ udelay(1);
+ }
+
+ print_npe(npe, "reset: npe_debug_instr(): timeout\n");
+ return -ETIMEDOUT;
+}
+
+static int npe_logical_reg_write8(struct npe *npe, u32 addr, u8 val, u32 ctx)
+{
+ /* here we build the NPE assembler instruction: mov8 d0, #0 */
+ u32 instr = INSTR_WR_REG_BYTE | /* OpCode */
+ addr << 9 | /* base Operand */
+ (val & 0x1F) << 4 | /* lower 5 bits to immediate data */
+ (val & ~0x1F) << (18 - 5);/* higher 3 bits to CoProc instr. */
+ return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int npe_logical_reg_write16(struct npe *npe, u32 addr, u16 val, u32 ctx)
+{
+ /* here we build the NPE assembler instruction: mov16 d0, #0 */
+ u32 instr = INSTR_WR_REG_SHORT | /* OpCode */
+ addr << 9 | /* base Operand */
+ (val & 0x1F) << 4 | /* lower 5 bits to immediate data */
+ (val & ~0x1F) << (18 - 5);/* higher 11 bits to CoProc instr. */
+ return npe_debug_instr(npe, instr, ctx, 1); /* execute it */
+}
+
+static int npe_logical_reg_write32(struct npe *npe, u32 addr, u32 val, u32 ctx)
+{
+ /* write in 16 bit steps first the high and then the low value */
+ if (npe_logical_reg_write16(npe, addr, val >> 16, ctx))
+ return -ETIMEDOUT;
+ return npe_logical_reg_write16(npe, addr + 2, val & 0xFFFF, ctx);
+}
+
+static int npe_reset(struct npe *npe)
+{
+ u32 val, ctl, exec_count, ctx_reg2;
+ int i;
+
+ ctl = (__raw_readl(&npe->regs->messaging_control) | 0x3F000000) &
+ 0x3F3FFFFF;
+
+ /* disable parity interrupt */
+ __raw_writel(ctl & 0x3F00FFFF, &npe->regs->messaging_control);
+
+ /* pre exec - debug instruction */
+ /* turn off the halt bit by clearing Execution Count register. */
+ exec_count = __raw_readl(&npe->regs->exec_count);
+ __raw_writel(0, &npe->regs->exec_count);
+ /* ensure that IF and IE are on (temporarily), so that we don't end up
+ stepping forever */
+ ctx_reg2 = npe_cmd_read(npe, ECS_DBG_CTXT_REG_2, CMD_RD_ECS_REG);
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2 |
+ ECS_DBG_REG_2_IF | ECS_DBG_REG_2_IE);
+
+ /* clear the FIFOs */
+ while (__raw_readl(&npe->regs->watchpoint_fifo) & WFIFO_VALID)
+ ;
+ while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE)
+ /* read from the outFIFO until empty */
+ print_npe(npe, "npe_reset: read FIFO = 0x%X\n",
+ __raw_readl(&npe->regs->in_out_fifo));
+
+ while (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)
+ /* step execution of the NPE intruction to read inFIFO using
+ the Debug Executing Context stack */
+ if (npe_debug_instr(npe, INSTR_RD_FIFO, 0, 0))
+ return -ETIMEDOUT;
+
+ /* reset the mailbox reg from the XScale side */
+ __raw_writel(RESET_MBOX_STAT, &npe->regs->mailbox_status);
+ /* from NPE side */
+ if (npe_debug_instr(npe, INSTR_RESET_MBOX, 0, 0))
+ return -ETIMEDOUT;
+
+ /* Reset the physical registers in the NPE register file */
+ for (val = 0; val < NPE_PHYS_REG; val++) {
+ if (npe_logical_reg_write16(npe, NPE_REGMAP, val >> 1, 0))
+ return -ETIMEDOUT;
+ /* address is either 0 or 4 */
+ if (npe_logical_reg_write32(npe, (val & 1) * 4, 0, 0))
+ return -ETIMEDOUT;
+ }
+
+ /* Reset the context store = each context's Context Store registers */
+
+ /* Context 0 has no STARTPC. Instead, this value is used to set NextPC
+ for Background ECS, to set where NPE starts executing code */
+ val = npe_cmd_read(npe, ECS_BG_CTXT_REG_0, CMD_RD_ECS_REG);
+ val &= ~ECS_REG_0_NEXTPC_MASK;
+ val |= (0 /* NextPC */ << 16) & ECS_REG_0_NEXTPC_MASK;
+ npe_cmd_write(npe, ECS_BG_CTXT_REG_0, CMD_WR_ECS_REG, val);
+
+ for (i = 0; i < 16; i++) {
+ if (i) { /* Context 0 has no STEVT nor STARTPC */
+ /* STEVT = off, 0x80 */
+ if (npe_logical_reg_write8(npe, NPE_STEVT, 0x80, i))
+ return -ETIMEDOUT;
+ if (npe_logical_reg_write16(npe, NPE_STARTPC, 0, i))
+ return -ETIMEDOUT;
+ }
+ /* REGMAP = d0->p0, d8->p2, d16->p4 */
+ if (npe_logical_reg_write16(npe, NPE_REGMAP, 0x820, i))
+ return -ETIMEDOUT;
+ if (npe_logical_reg_write8(npe, NPE_CINDEX, 0, i))
+ return -ETIMEDOUT;
+ }
+
+ /* post exec */
+ /* clear active bit in debug level */
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_0, CMD_WR_ECS_REG, 0);
+ /* clear the pipeline */
+ __raw_writel(CMD_NPE_CLR_PIPE, &npe->regs->exec_status_cmd);
+ /* restore previous values */
+ __raw_writel(exec_count, &npe->regs->exec_count);
+ npe_cmd_write(npe, ECS_DBG_CTXT_REG_2, CMD_WR_ECS_REG, ctx_reg2);
+
+ /* write reset values to Execution Context Stack registers */
+ for (val = 0; val < ARRAY_SIZE(ecs_reset); val++)
+ npe_cmd_write(npe, ecs_reset[val].reg, CMD_WR_ECS_REG,
+ ecs_reset[val].val);
+
+ /* clear the profile counter */
+ __raw_writel(CMD_CLR_PROFILE_CNT, &npe->regs->exec_status_cmd);
+
+ __raw_writel(0, &npe->regs->exec_count);
+ __raw_writel(0, &npe->regs->action_points[0]);
+ __raw_writel(0, &npe->regs->action_points[1]);
+ __raw_writel(0, &npe->regs->action_points[2]);
+ __raw_writel(0, &npe->regs->action_points[3]);
+ __raw_writel(0, &npe->regs->watch_count);
+
+ val = ixp4xx_read_feature_bits();
+ /* reset the NPE */
+ ixp4xx_write_feature_bits(val &
+ ~(IXP4XX_FEATURE_RESET_NPEA << npe->id));
+ /* deassert reset */
+ ixp4xx_write_feature_bits(val |
+ (IXP4XX_FEATURE_RESET_NPEA << npe->id));
+ for (i = 0; i < MAX_RETRIES; i++) {
+ if (ixp4xx_read_feature_bits() &
+ (IXP4XX_FEATURE_RESET_NPEA << npe->id))
+ break; /* NPE is back alive */
+ udelay(1);
+ }
+ if (i == MAX_RETRIES)
+ return -ETIMEDOUT;
+
+ npe_stop(npe);
+
+ /* restore NPE configuration bus Control Register - parity settings */
+ __raw_writel(ctl, &npe->regs->messaging_control);
+ return 0;
+}
+
+
+int npe_send_message(struct npe *npe, const void *msg, const char *what)
+{
+ const u32 *send = msg;
+ int cycles = 0;
+
+ debug_msg(npe, "Trying to send message %s [%08X:%08X]\n",
+ what, send[0], send[1]);
+
+ if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE) {
+ debug_msg(npe, "NPE input FIFO not empty\n");
+ return -EIO;
+ }
+
+ __raw_writel(send[0], &npe->regs->in_out_fifo);
+
+ if (!(__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNF)) {
+ debug_msg(npe, "NPE input FIFO full\n");
+ return -EIO;
+ }
+
+ __raw_writel(send[1], &npe->regs->in_out_fifo);
+
+ while ((cycles < MAX_RETRIES) &&
+ (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_IFNE)) {
+ udelay(1);
+ cycles++;
+ }
+
+ if (cycles == MAX_RETRIES) {
+ debug_msg(npe, "Timeout sending message\n");
+ return -ETIMEDOUT;
+ }
+
+#if DEBUG_MSG > 1
+ debug_msg(npe, "Sending a message took %i cycles\n", cycles);
+#endif
+ return 0;
+}
+
+int npe_recv_message(struct npe *npe, void *msg, const char *what)
+{
+ u32 *recv = msg;
+ int cycles = 0, cnt = 0;
+
+ debug_msg(npe, "Trying to receive message %s\n", what);
+
+ while (cycles < MAX_RETRIES) {
+ if (__raw_readl(&npe->regs->messaging_status) & MSGSTAT_OFNE) {
+ recv[cnt++] = __raw_readl(&npe->regs->in_out_fifo);
+ if (cnt == 2)
+ break;
+ } else {
+ udelay(1);
+ cycles++;
+ }
+ }
+
+ switch(cnt) {
+ case 1:
+ debug_msg(npe, "Received [%08X]\n", recv[0]);
+ break;
+ case 2:
+ debug_msg(npe, "Received [%08X:%08X]\n", recv[0], recv[1]);
+ break;
+ }
+
+ if (cycles == MAX_RETRIES) {
+ debug_msg(npe, "Timeout waiting for message\n");
+ return -ETIMEDOUT;
+ }
+
+#if DEBUG_MSG > 1
+ debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
+#endif
+ return 0;
+}
+
+int npe_send_recv_message(struct npe *npe, void *msg, const char *what)
+{
+ int result;
+ u32 *send = msg, recv[2];
+
+ if ((result = npe_send_message(npe, msg, what)) != 0)
+ return result;
+ if ((result = npe_recv_message(npe, recv, what)) != 0)
+ return result;
+
+ if ((recv[0] != send[0]) || (recv[1] != send[1])) {
+ debug_msg(npe, "Message %s: unexpected message received\n",
+ what);
+ return -EIO;
+ }
+ return 0;
+}
+
+
+int npe_load_firmware(struct npe *npe)
+{
+ struct dl_block {
+ u32 type;
+ u32 offset;
+ } *blk;
+
+ struct dl_image {
+ u32 magic;
+ u32 id;
+ u32 size;
+ union {
+ u32 data[0];
+ struct dl_block blocks[0];
+ };
+ } *image;
+
+ struct dl_codeblock {
+ u32 npe_addr;
+ u32 size;
+ u32 data[0];
+ } *cb;
+
+ int i, j, err, data_size, instr_size, blocks, table_end;
+ u32 cmd;
+ char name[5 /* "/dev/" */ + NPE_NAME_LENGTH + 1 /* NUL */];
+ size_t image_size;
+
+ sprintf(name, "/dev/%s", npe->name);
+ if (!(image = read_file(name, &image_size))) {
+ print_npe(npe, "bad or missing microcode file %s", name);
+ return -EIO;
+ }
+
+ err = -EINVAL;
+ if (image_size < sizeof(struct dl_image)) {
+ print_npe(npe, "incomplete microcode file %s\n", name);
+ goto err;
+ }
+
+#if DEBUG_FW
+ print_npe(npe, "microcode: %08X %08X %08X (0x%X bytes)\n",
+ image->magic, image->id, image->size, image->size * 4);
+#endif
+
+ if (image->magic == swab32(FW_MAGIC)) { /* swapped file */
+ image->id = swab32(image->id);
+ image->size = swab32(image->size);
+ } else if (image->magic != FW_MAGIC) {
+ print_npe(npe, "bad microcode file %s magic: 0x%X\n", name, image->magic);
+ goto err;
+ }
+ if ((image->size * 4 + sizeof(struct dl_image)) > image_size) {
+ print_npe(npe, "incomplete microcode file %s\n", name);
+ goto err;
+ }
+ if (((image->id >> 24) & 0xF /* NPE ID */) != npe->id) {
+ print_npe(npe, "NPE ID mismatch in microcode file %s\n", name);
+ goto err;
+ }
+ if (image->magic == swab32(FW_MAGIC))
+ for (i = 0; i < image->size; i++)
+ image->data[i] = swab32(image->data[i]);
+
+ if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) {
+ print_npe(npe, "IXP43x/IXP46x microcode ignored on IXP42x\n");
+ goto err;
+ }
+
+ if (npe_running(npe)) {
+ print_npe(npe, "unable to load microcode file %s, NPE is already running\n", name);
+ err = -EBUSY;
+ goto err;
+ }
+
+ if (cpu_is_ixp42x()) {
+ if (!npe->id)
+ instr_size = NPE_A_42X_INSTR_SIZE;
+ else
+ instr_size = NPE_B_AND_C_42X_INSTR_SIZE;
+ data_size = NPE_42X_DATA_SIZE;
+ } else {
+ instr_size = NPE_46X_INSTR_SIZE;
+ data_size = NPE_46X_DATA_SIZE;
+ }
+
+ for (blocks = 0; blocks * sizeof(struct dl_block) / 4 < image->size;
+ blocks++)
+ if (image->blocks[blocks].type == FW_BLOCK_TYPE_EOF)
+ break;
+ if (blocks * sizeof(struct dl_block) / 4 >= image->size) {
+ print_npe(npe, "microcode EOF block marker not found\n");
+ goto err;
+ }
+
+#if DEBUG_FW
+ print_npe(npe, "%i microcode blocks found\n", blocks);
+#endif
+
+ table_end = blocks * sizeof(struct dl_block) / 4 + 1 /* EOF marker */;
+ for (i = 0, blk = image->blocks; i < blocks; i++, blk++) {
+ if (blk->offset > image->size - sizeof(struct dl_codeblock) / 4
+ || blk->offset < table_end) {
+ print_npe(npe, "invalid offset 0x%X of "
+ "microcode block #%i\n", blk->offset, i);
+ goto err;
+ }
+
+ cb = (struct dl_codeblock*)&image->data[blk->offset];
+ if (blk->type == FW_BLOCK_TYPE_INSTR) {
+ if (cb->npe_addr + cb->size > instr_size)
+ goto too_big;
+ cmd = CMD_WR_INS_MEM;
+ } else if (blk->type == FW_BLOCK_TYPE_DATA) {
+ if (cb->npe_addr + cb->size > data_size)
+ goto too_big;
+ cmd = CMD_WR_DATA_MEM;
+ } else {
+ print_npe(npe, "invalid microcode block #%i type 0x%X\n",
+ i, blk->type);
+ goto err;
+ }
+ if (blk->offset + sizeof(*cb) / 4 + cb->size > image->size) {
+ print_npe(npe, "microcode block #%i doesn't "
+ "fit in microcode image: type %c, start 0x%X,"
+ " length 0x%X\n", i,
+ blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+ cb->npe_addr, cb->size);
+ goto err;
+ }
+
+ for (j = 0; j < cb->size; j++)
+ npe_cmd_write(npe, cb->npe_addr + j, cmd, cb->data[j]);
+ }
+
+ npe_start(npe);
+ if (!npe_running(npe))
+ print_npe(npe, "unable to start\n");
+ free(image);
+ return 0;
+
+too_big:
+ print_npe(npe, "microcode block #%i doesn't fit in NPE "
+ "memory: type %c, start 0x%X, length 0x%X\n", i,
+ blk->type == FW_BLOCK_TYPE_INSTR ? 'I' : 'D',
+ cb->npe_addr, cb->size);
+err:
+ free(image);
+ return err;
+}
+
+
+struct npe *npe_request(int id)
+{
+ if (id < NPE_COUNT)
+ if (npe_tab[id].valid)
+ return &npe_tab[id];
+ return NULL;
+}
+
+static int __init npe_init(void)
+{
+ int i;
+
+ for (i = 0; i < NPE_COUNT; i++) {
+ struct npe *npe = &npe_tab[i];
+ if (!(ixp4xx_read_feature_bits() & (IXP4XX_FEATURE_RESET_NPEA << i)))
+ continue; /* NPE already disabled or not present */
+ if (npe_reset(npe))
+ continue;
+ npe->valid = 1;
+ }
+ return 0;
+}
+
+coredevice_initcall(npe_init);
diff --git a/arch/arm/mach-ixp4xx/qmgr.c b/arch/arm/mach-ixp4xx/qmgr.c
new file mode 100644
index 0000000..81b6522
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/qmgr.c
@@ -0,0 +1,259 @@
+/*
+ * Intel IXP4xx Queue Manager driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <init.h>
+#include <errno.h>
+#include <mach/qmgr.h>
+
+static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
+
+#if DEBUG_QMGR
+char qmgr_queue_descs[HALF_QUEUES][32];
+#endif
+
+#ifdef CONFIG_USE_IRQ
+
+static void (*irq_handlers[HALF_QUEUES])(void *pdev);
+static void *irq_pdevs[HALF_QUEUES];
+
+void qmgr_set_irq(unsigned int queue, int src,
+ void (*handler)(void *pdev), void *pdev)
+{
+ const u32 *reg;
+ int bit;
+ BUG_ON(src > QUEUE_IRQ_SRC_NOT_FULL);
+ reg = &qmgr_regs->irqsrc[queue >> 3]; /* 8 queues per u32 */
+ bit = (queue % 8) * 4; /* 3 bits + 1 reserved bit per queue */
+ __raw_writel((__raw_readl(reg) & ~(7 << bit)) | (src << bit), reg);
+
+ irq_handlers[queue] = handler;
+ irq_pdevs[queue] = pdev;
+}
+
+
+static void qmgr_irq1_a0(void *data)
+{
+ int i;
+ u32 en_bitmap, src, stat;
+
+ /* ACK - it may clear any bits so don't rely on it */
+ __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[0]);
+
+ en_bitmap = qmgr_regs->irqen[0];
+ while (en_bitmap) {
+ i = fls(en_bitmap) - 1; /* number of the last "low" queue */
+ en_bitmap &= ~BIT(i);
+ src = qmgr_regs->irqsrc[i >> 3];
+ stat = qmgr_regs->stat1[i >> 3];
+ if (src & 4) /* the IRQ condition is inverted */
+ stat = ~stat;
+ if (stat & BIT(src & 3))
+ irq_handlers[i](irq_pdevs[i]);
+ }
+}
+
+
+static void qmgr_irq1(void *data)
+{
+ int i;
+ u32 req_bitmap = __raw_readl(&qmgr_regs->irqstat[0]);
+
+ if (!req_bitmap)
+ return;
+ __raw_writel(req_bitmap, &qmgr_regs->irqstat[0]); /* ACK */
+
+ while (req_bitmap) {
+ i = fls(req_bitmap) - 1; /* number of the last queue */
+ req_bitmap &= ~BIT(i);
+ irq_handlers[i](irq_pdevs[i]);
+ }
+}
+
+
+void qmgr_enable_irq(unsigned int queue)
+{
+ u32 mask = 1 << queue;
+
+ __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) | mask,
+ &qmgr_regs->irqen[0]);
+}
+
+void qmgr_disable_irq(unsigned int queue)
+{
+ u32 mask = 1 << queue;
+
+ __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~mask,
+ &qmgr_regs->irqen[0]);
+ __raw_writel(mask, &qmgr_regs->irqstat[0]); /* clear */
+}
+
+#endif /* CONFIG_USE_IRQ */
+
+static inline void shift_mask(u32 *mask)
+{
+ mask[3] = mask[3] << 1 | mask[2] >> 31;
+ mask[2] = mask[2] << 1 | mask[1] >> 31;
+ mask[1] = mask[1] << 1 | mask[0] >> 31;
+ mask[0] <<= 1;
+}
+
+#if DEBUG_QMGR
+void qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+ unsigned int nearly_empty_watermark,
+ unsigned int nearly_full_watermark,
+ const char *desc_format, const char* name)
+#else
+void __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */,
+ unsigned int nearly_empty_watermark,
+ unsigned int nearly_full_watermark)
+#endif
+{
+ u32 cfg, addr = 0, mask[4]; /* in 16-dwords */
+
+ BUG_ON(queue >= HALF_QUEUES);
+ BUG_ON((nearly_empty_watermark | nearly_full_watermark) & ~7);
+
+ switch (len) {
+ case 16:
+ cfg = 0 << 24;
+ mask[0] = 0x1;
+ break;
+ case 32:
+ cfg = 1 << 24;
+ mask[0] = 0x3;
+ break;
+ case 64:
+ cfg = 2 << 24;
+ mask[0] = 0xF;
+ break;
+ case 128:
+ cfg = 3 << 24;
+ mask[0] = 0xFF;
+ break;
+ default:
+ BUG();
+ }
+
+ cfg |= nearly_empty_watermark << 26;
+ cfg |= nearly_full_watermark << 29;
+ len /= 16; /* in 16-dwords: 1, 2, 4 or 8 */
+ mask[1] = mask[2] = mask[3] = 0;
+
+ BUG_ON(__raw_readl(&qmgr_regs->sram[queue]));
+
+ while (1) {
+ if (!(used_sram_bitmap[0] & mask[0]) &&
+ !(used_sram_bitmap[1] & mask[1]) &&
+ !(used_sram_bitmap[2] & mask[2]) &&
+ !(used_sram_bitmap[3] & mask[3]))
+ break; /* found free space */
+
+ addr++;
+ shift_mask(mask);
+ if (addr + len > ARRAY_SIZE(qmgr_regs->sram)) {
+ fprintf(stderr, "qmgr: no free SRAM space for"
+ " queue %i\n", queue);
+ BUG();
+ }
+ }
+
+ used_sram_bitmap[0] |= mask[0];
+ used_sram_bitmap[1] |= mask[1];
+ used_sram_bitmap[2] |= mask[2];
+ used_sram_bitmap[3] |= mask[3];
+ __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]);
+#if DEBUG_QMGR
+ /* no snprintf() */
+ sprintf(qmgr_queue_descs[queue], desc_format, name);
+ fprintf(stderr, "qmgr: requested queue %s(%i) addr = 0x%02X\n",
+ qmgr_queue_descs[queue], queue, addr);
+#endif
+}
+
+void qmgr_release_queue(unsigned int queue)
+{
+ u32 cfg, addr, mask[4];
+
+ BUG_ON(queue >= HALF_QUEUES); /* not in valid range */
+
+ cfg = __raw_readl(&qmgr_regs->sram[queue]);
+ addr = (cfg >> 14) & 0xFF;
+
+ BUG_ON(!addr); /* not requested */
+
+ switch ((cfg >> 24) & 3) {
+ case 0: mask[0] = 0x1; break;
+ case 1: mask[0] = 0x3; break;
+ case 2: mask[0] = 0xF; break;
+ case 3: mask[0] = 0xFF; break;
+ }
+
+ mask[1] = mask[2] = mask[3] = 0;
+
+ while (addr--)
+ shift_mask(mask);
+
+#if DEBUG_QMGR
+ fprintf(stderr, "qmgr: releasing queue %s(%i)\n",
+ qmgr_queue_descs[queue], queue);
+ qmgr_queue_descs[queue][0] = '\x0';
+#endif
+ __raw_writel(0, &qmgr_regs->sram[queue]);
+
+ used_sram_bitmap[0] &= ~mask[0];
+ used_sram_bitmap[1] &= ~mask[1];
+ used_sram_bitmap[2] &= ~mask[2];
+ used_sram_bitmap[3] &= ~mask[3];
+#ifdef CONFIG_USE_IRQ
+ irq_handlers[queue] = NULL; /* catch IRQ bugs */
+#endif
+
+ while ((addr = qmgr_get_entry(queue)))
+ fprintf(stderr, "qmgr: released queue %i not empty: 0x%08X\n",
+ queue, addr);
+}
+
+static int __init qmgr_init(void)
+{
+ int i;
+#ifdef CONFIG_USE_IRQ
+ interrupt_handler_t *handler;
+#endif
+
+ /* reset qmgr registers */
+ for (i = 0; i < 4; i++) {
+ __raw_writel(0x33333333, &qmgr_regs->stat1[i]);
+ __raw_writel(0, &qmgr_regs->irqsrc[i]);
+ }
+ for (i = 0; i < 2; i++) {
+ __raw_writel(0, &qmgr_regs->stat2[i]);
+ __raw_writel(0xFFFFFFFF, &qmgr_regs->irqstat[i]); /* clear */
+ __raw_writel(0, &qmgr_regs->irqen[i]);
+ }
+
+ __raw_writel(0xFFFFFFFF, &qmgr_regs->statne_h);
+ __raw_writel(0, &qmgr_regs->statf_h);
+
+ for (i = 0; i < QUEUES; i++)
+ __raw_writel(0, &qmgr_regs->sram[i]);
+
+#ifdef CONFIG_USE_IRQ
+ if (cpu_is_ixp42x_rev_a0())
+ handler = qmgr_irq1_a0;
+ else
+ handler = qmgr_irq1;
+
+ irq_install_handler(IXP425_QM1_IRQ, handler, NULL);
+#endif
+ used_sram_bitmap[0] = 0xF; /* 4 first pages reserved for config */
+ return 0;
+}
+
+coredevice_initcall(qmgr_init);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 69f3352..df6e42c 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -77,6 +77,14 @@ config DRIVER_NET_MACB
depends on HAS_MACB
select MIIDEV
+config DRIVER_NET_IXP4XX_ETH
+ tristate "Intel IXP4xx Ethernet support"
+ depends on ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
+ select MIIDEV
+ help
+ Say Y here if you want to use built-in Ethernet ports
+ on IXP4xx processor.
+
config DRIVER_NET_TAP
bool "tap Ethernet driver"
depends on LINUX
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 96d3d32..97cb44b 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_DRIVER_NET_MACB) += macb.o
obj-$(CONFIG_DRIVER_NET_TAP) += tap.o
obj-$(CONFIG_MIIDEV) += miidev.o
obj-$(CONFIG_NET_USB) += usb/
+obj-$(CONFIG_DRIVER_NET_IXP4XX_ETH) += ixp4xx_eth.o
diff --git a/drivers/net/ixp4xx_eth.c b/drivers/net/ixp4xx_eth.c
new file mode 100644
index 0000000..71e6d92
--- /dev/null
+++ b/drivers/net/ixp4xx_eth.c
@@ -0,0 +1,763 @@
+/*
+ * Intel IXP4xx Ethernet driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * Ethernet port config (0x00 is not present on IXP42X):
+ *
+ * logical port 0x00 0x10 0x20
+ * NPE 0 (NPE-A) 1 (NPE-B) 2 (NPE-C)
+ * physical port 2 0 1
+ * RX queue (variable) 20 21 22
+ * TX queue 23 24 25
+ * RX-free queue 26 27 28
+ * TX-done queue is always 31, per-port RX queue is configurable
+ *
+ *
+ * Queue entries:
+ * bits 0 -> 1 - NPE ID (RX and TX-done)
+ * bits 0 -> 2 - priority (TX, per 802.1D)
+ * bits 3 -> 4 - port ID (user-set?)
+ * bits 5 -> 31 - physical descriptor address
+ */
+
+#include <common.h>
+#include <init.h>
+#include <malloc.h>
+#include <miidev.h>
+#include <net.h>
+#include <errno.h>
+#include <mach/ixp4xx-regs.h>
+#include <mach/platform.h>
+#include <mach/cpu.h>
+#include <mach/npe.h>
+#include <mach/qmgr.h>
+
+#define DEBUG_DESC 0
+#define DEBUG_RX 0
+#define DEBUG_TX 0
+#define DEBUG_PKT_BYTES 0
+#define DEBUG_MDIO 0
+#define DEBUG_OPEN 0
+#define DEBUG_CLOSE 0
+
+#define RX_DESCS 16 /* also length of all RX queues */
+#define TX_DESCS 16 /* also length of all TX queues */
+#define TXDONE_QUEUE_LEN 16 /* dwords */
+
+#define MAX_MRU 1536 /* 0x600 */
+#define RX_BUFF_SIZE MAX_MRU
+
+#define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */
+#define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */
+#define ETH_ALEN 6
+
+#define PHYSICAL_ID(port) (((port)->npe->id + 2) % 3)
+#define LOGICAL_ID(port) ((port)->npe->id << 4)
+#define RX_QUEUE(port) ((port)->npe->id + 20) /* can be changed */
+#define TX_QUEUE(port) ((port)->npe->id + 23)
+#define RXFREE_QUEUE(port) ((port)->npe->id + 26)
+#define TXDONE_QUEUE 31
+
+/* TX Control Registers */
+#define TX_CNTRL0_TX_EN 0x01
+#define TX_CNTRL0_HALFDUPLEX 0x02
+#define TX_CNTRL0_RETRY 0x04
+#define TX_CNTRL0_PAD_EN 0x08
+#define TX_CNTRL0_APPEND_FCS 0x10
+#define TX_CNTRL0_2DEFER 0x20
+#define TX_CNTRL0_RMII 0x40 /* reduced MII */
+#define TX_CNTRL1_RETRIES 0x0F /* 4 bits */
+
+/* RX Control Registers */
+#define RX_CNTRL0_RX_EN 0x01
+#define RX_CNTRL0_PADSTRIP_EN 0x02
+#define RX_CNTRL0_SEND_FCS 0x04
+#define RX_CNTRL0_PAUSE_EN 0x08
+#define RX_CNTRL0_LOOP_EN 0x10
+#define RX_CNTRL0_ADDR_FLTR_EN 0x20
+#define RX_CNTRL0_RX_RUNT_EN 0x40
+#define RX_CNTRL0_BCAST_DIS 0x80
+#define RX_CNTRL1_DEFER_EN 0x01
+
+/* Core Control Register */
+#define CORE_RESET 0x01
+#define CORE_RX_FIFO_FLUSH 0x02
+#define CORE_TX_FIFO_FLUSH 0x04
+#define CORE_SEND_JAM 0x08
+#define CORE_MDC_EN 0x10 /* MDIO using NPE-B ETH-0 only */
+
+#define DEFAULT_TX_CNTRL0 (TX_CNTRL0_TX_EN | TX_CNTRL0_RETRY | \
+ TX_CNTRL0_PAD_EN | TX_CNTRL0_APPEND_FCS | \
+ TX_CNTRL0_2DEFER)
+#define DEFAULT_RX_CNTRL0 RX_CNTRL0_RX_EN
+#define DEFAULT_CORE_CNTRL CORE_MDC_EN
+
+
+/* NPE message codes */
+#define NPE_GETSTATUS 0x00
+#define NPE_EDB_SETPORTADDRESS 0x01
+#define NPE_EDB_GETMACADDRESSDATABASE 0x02
+#define NPE_EDB_SETMACADDRESSSDATABASE 0x03
+#define NPE_GETSTATS 0x04
+#define NPE_RESETSTATS 0x05
+#define NPE_SETMAXFRAMELENGTHS 0x06
+#define NPE_VLAN_SETRXTAGMODE 0x07
+#define NPE_VLAN_SETDEFAULTRXVID 0x08
+#define NPE_VLAN_SETPORTVLANTABLEENTRY 0x09
+#define NPE_VLAN_SETPORTVLANTABLERANGE 0x0A
+#define NPE_VLAN_SETRXQOSENTRY 0x0B
+#define NPE_VLAN_SETPORTIDEXTRACTIONMODE 0x0C
+#define NPE_STP_SETBLOCKINGSTATE 0x0D
+#define NPE_FW_SETFIREWALLMODE 0x0E
+#define NPE_PC_SETFRAMECONTROLDURATIONID 0x0F
+#define NPE_PC_SETAPMACTABLE 0x11
+#define NPE_SETLOOPBACK_MODE 0x12
+#define NPE_PC_SETBSSIDTABLE 0x13
+#define NPE_ADDRESS_FILTER_CONFIG 0x14
+#define NPE_APPENDFCSCONFIG 0x15
+#define NPE_NOTIFY_MAC_RECOVERY_DONE 0x16
+#define NPE_MAC_RECOVERY_START 0x17
+
+struct eth_regs {
+ u32 tx_control[2], __res1[2]; /* 000 */
+ u32 rx_control[2], __res2[2]; /* 010 */
+ u32 random_seed, __res3[3]; /* 020 */
+ u32 partial_empty_threshold, __res4; /* 030 */
+ u32 partial_full_threshold, __res5; /* 038 */
+ u32 tx_start_bytes, __res6[3]; /* 040 */
+ u32 tx_deferral, rx_deferral, __res7[2]; /* 050 */
+ u32 tx_2part_deferral[2], __res8[2]; /* 060 */
+ u32 slot_time, __res9[3]; /* 070 */
+ u32 mdio_command[4]; /* 080 */
+ u32 mdio_status[4]; /* 090 */
+ u32 mcast_mask[6], __res10[2]; /* 0A0 */
+ u32 mcast_addr[6], __res11[2]; /* 0C0 */
+ u32 int_clock_threshold, __res12[3]; /* 0E0 */
+ u32 hw_addr[6], __res13[61]; /* 0F0 */
+ u32 core_control; /* 1FC */
+};
+
+/* NPE message structure */
+struct msg {
+ u8 cmd, eth_id, params[6];
+};
+
+/* Ethernet packet descriptor, 32 bytes */
+struct desc {
+ u8 *next; /* pointer to next buffer, unused */
+
+ u16 buf_len; /* buffer length */
+ u16 pkt_len; /* packet length */
+ u8 *data; /* pointer to data buffer in RAM */
+ u8 dest_id;
+ u8 src_id;
+ u16 flags;
+ u8 qos;
+ u8 padlen;
+ u16 vlan_tci;
+
+ u8 dst_mac[ETH_ALEN], src_mac[ETH_ALEN];
+};
+
+struct port {
+ struct desc rx_desc_tab[RX_DESCS]; /* alignment: 0x10 */
+ struct desc tx_desc_tab[TX_DESCS];
+ u8 *buff_tab;
+ struct eth_regs *regs;
+ struct npe *npe;
+ u8 firmware[4];
+ struct eth_plat_info *pinfo;
+ struct mii_device miidev;
+ struct eth_device eth;
+};
+
+#define rx_buff(port, n) ((port)->buff_tab + MAX_MRU * (n))
+#define tx_buff(port, n) ((port)->buff_tab + MAX_MRU * (RX_DESCS + (n)))
+
+static struct eth_regs *mdio_regs; /* mdio command and status only */
+
+static int ixp4xx_mdio_cmd(int write, const struct device_d *dev, unsigned char phy_id,
+ unsigned char location, unsigned short value)
+{
+ int cycles = 0;
+
+ if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {
+ fprintf(stderr, "%s%d: MII not ready to transmit\n", dev->name, dev->id);
+ return -1;
+ }
+
+ if (write) {
+ __raw_writel(value & 0xFF, &mdio_regs->mdio_command[0]);
+ __raw_writel(value >> 8, &mdio_regs->mdio_command[1]);
+ }
+ __raw_writel(((phy_id << 5) | location) & 0xFF,
+ &mdio_regs->mdio_command[2]);
+ __raw_writel((phy_id >> 3) | (write << 2) | 0x80 /* GO */,
+ &mdio_regs->mdio_command[3]);
+
+ while ((cycles < MAX_MDIO_RETRIES) &&
+ (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80)) {
+ udelay(1);
+ cycles++;
+ }
+
+ if (cycles == MAX_MDIO_RETRIES) {
+ fprintf(stderr, "%s%d: MII write failed\n", dev->name, dev->id);
+ return -1;
+ }
+
+#if DEBUG_MDIO
+ fprintf(stderr, "%s%d: mdio_%s() took %i cycles\n", dev->name, dev->id,
+ write ? "write" : "read", cycles);
+#endif
+
+ if (write)
+ return 0;
+
+ if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {
+#if DEBUG_MDIO
+ fprintf(stderr, "%s%d: MII read failed\n", dev->name, dev->id);
+#endif
+ return -1;
+ }
+
+ value = (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |
+ ((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8);
+#if DEBUG_MDIO
+ fprintf(stderr, "%s%d: MII read [%i] -> 0x%X\n", dev->name, dev->id, location, value);
+#endif
+
+ return value;
+}
+
+static int ixp4xx_mdio_read(struct mii_device *mii, int phy_id, int location)
+{
+ int ret = ixp4xx_mdio_cmd(0, &mii->dev, phy_id, location, 0);
+ return ret;
+}
+
+static int ixp4xx_mdio_write(struct mii_device *mii, int phy_id, int location, int value)
+{
+ int ret = ixp4xx_mdio_cmd(1, &mii->dev, phy_id, location, value);
+#if DEBUG_MDIO
+ fprintf(stderr, "%s%d: MII write [%i] <- 0x%X, err = %i\n",
+ mii->dev.name, mii->dev.id, location, value, ret);
+#endif
+ return ret;
+}
+
+static int ixp4xx_adjust_link(struct eth_device *dev)
+{
+ struct port *port = dev->priv;
+ int reg, speed, duplex;
+
+ miidev_wait_aneg(&port->miidev);
+
+ reg = mii_read(&port->miidev, port->miidev.address, MII_BMSR);
+ if (reg < 0)
+ goto err_out;
+ if (!(reg & BMSR_LSTATUS)) {
+ printf("%s%d: Link is down", dev->dev.name, dev->dev.id);
+ return -1;
+ }
+
+ reg = mii_read(&port->miidev, port->miidev.address, MII_BMCR);
+ if (reg < 0)
+ goto err_out;
+
+ if (reg & BMCR_ANENABLE) {
+ reg = mii_read(&port->miidev, port->miidev.address, MII_LPA);
+ if (reg < 0)
+ goto err_out;
+ duplex = reg & LPA_DUPLEX;
+ speed = reg & LPA_100 ? 100 : 10;
+ } else {
+ duplex = reg & BMCR_FULLDPLX;
+ speed = reg & BMCR_SPEED100 ? 100 : 10;
+ }
+
+ if (duplex)
+ __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+ else
+ __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+
+ fprintf(stderr, "%s%d: link up, speed %u Mb/s, %s duplex\n",
+ dev->dev.name, dev->dev.id, speed, duplex ? "full" : "half");
+ return 0;
+
+err_out:
+ printf("%s%d: failed to read MII data\n", dev->dev.name, dev->dev.id);
+ return -EIO;
+}
+
+static inline void debug_pkt(struct eth_device *dev, const char *func,
+ u8 *data, int len)
+{
+#if DEBUG_PKT_BYTES
+ int i;
+
+ fprintf(stderr, "%s%d: %s(%4i) ", dev->dev.name, dev->dev.id, func, len);
+ for (i = 0; i < len; i++) {
+ if (i >= DEBUG_PKT_BYTES)
+ break;
+ fprintf(stderr, "%s%02X",
+ ((i == 6) || (i == 12) || (i >= 14)) ? " " : "",
+ data[i]);
+ }
+ fprintf(stderr, "\n");
+#endif
+}
+
+
+static inline void debug_desc(struct desc *desc)
+{
+#if DEBUG_DESC
+ fprintf(stderr, "%07X: %X %3X %3X %07X %2X < %2X %4X %X"
+ " %X %X %02X%02X%02X%02X%02X%02X < %02X%02X%02X%02X%02X%02X\n",
+ (u32)desc, (u32)desc->next, desc->buf_len, desc->pkt_len,
+ (u32)desc->data, desc->dest_id, desc->src_id, desc->flags,
+ desc->qos, desc->padlen, desc->vlan_tci,
+ desc->dst_mac[0], desc->dst_mac[1], desc->dst_mac[2],
+ desc->dst_mac[3], desc->dst_mac[4], desc->dst_mac[5],
+ desc->src_mac[0], desc->src_mac[1], desc->src_mac[2],
+ desc->src_mac[3], desc->src_mac[4], desc->src_mac[5]);
+#endif
+}
+
+static inline int queue_get_desc(unsigned int queue, struct port *port,
+ int is_tx)
+{
+ u32 addr, n;
+ struct desc *tab;
+
+ if (!(addr = qmgr_get_entry(queue)))
+ return -1;
+
+ addr &= ~0x1F; /* mask out non-address bits */
+ tab = is_tx ? port->tx_desc_tab : port->rx_desc_tab;
+ n = (addr - (u32)tab) / sizeof(struct desc);
+ BUG_ON(n >= (is_tx ? TX_DESCS : RX_DESCS));
+ debug_desc((struct desc*)addr);
+ BUG_ON(tab[n].next);
+ return n;
+}
+
+static inline void queue_put_desc(unsigned int queue, struct desc *desc)
+{
+ debug_desc(desc);
+ BUG_ON(((u32)desc) & 0x1F);
+ qmgr_put_entry(queue, (u32)desc);
+ /* Don't check for queue overflow here, we've allocated sufficient
+ length and queues >= 32 don't support this check anyway. */
+}
+
+
+static int ixp4xx_eth_poll(struct eth_device *dev)
+{
+ struct port *port = dev->priv;
+ struct desc *desc;
+ u8 *buff;
+ int n, len;
+
+#if DEBUG_RX
+ fprintf(stderr, "%s%d: eth_poll\n", dev->dev.name, dev->dev.id);
+#endif
+
+ if ((n = queue_get_desc(RX_QUEUE(port), port, 0)) < 0) {
+#if DEBUG_RX
+ fprintf(stderr, "%s%d: eth_poll = no packet received\n", dev->dev.name, dev->dev.id);
+#endif
+ return 0;
+ }
+
+ barrier();
+ desc = &port->rx_desc_tab[n];
+ buff = rx_buff(port, n);
+ len = desc->pkt_len;
+ /* process received frame */
+ memcpy((void *)NetRxPackets[0], buff, len);
+ debug_pkt(dev, "RX", desc->data, len);
+
+ /* put the new buffer on RX-free queue */
+ desc->buf_len = MAX_MRU;
+ desc->pkt_len = 0;
+ queue_put_desc(RXFREE_QUEUE(port), desc);
+
+ net_receive(NetRxPackets[0], len);
+
+#if DEBUG_RX
+ fprintf(stderr, "%s%d: eth_poll end\n", dev->dev.name, dev->dev.id);
+#endif
+ return 0;
+}
+
+
+static int ixp4xx_eth_xmit(struct eth_device *dev, void *data, int len)
+{
+ struct port *port = dev->priv;
+ int n;
+ struct desc *desc;
+
+#if DEBUG_TX
+ fprintf(stderr, "%s%d: eth_xmit\n", dev->dev.name, dev->dev.id);
+#endif
+
+ if (unlikely(len > 1500))
+ return -1;
+
+ debug_pkt(dev, "TX", data, len);
+
+ if ((n = queue_get_desc(TXDONE_QUEUE, port, 1)) < 0)
+ return -1; /* no free buffers */
+ desc = &port->tx_desc_tab[n];
+ desc->data = tx_buff(port, n);
+ desc->buf_len = desc->pkt_len = len;
+ memcpy(desc->data, data, len);
+
+ /* NPE firmware pads short frames with zeros internally */
+ // wmb();
+ barrier();
+ queue_put_desc(TX_QUEUE(port), desc);
+
+#if DEBUG_TX
+ fprintf(stderr, "%s%d: eth_xmit end\n", dev->dev.name, dev->dev.id);
+#endif
+ return 0;
+}
+
+static void request_queues(struct port *port, struct eth_device *dev)
+{
+ qmgr_request_queue(RXFREE_QUEUE(port), RX_DESCS, 0, 0, "%s:RX-free", dev->dev.name);
+ qmgr_request_queue(RX_QUEUE(port), RX_DESCS, 0, 0, "%s:RX", dev->dev.name);
+ qmgr_request_queue(TX_QUEUE(port), TX_DESCS, 0, 0, "%s:TX", dev->dev.name);
+
+ /* Common TX-done queue handles buffers sent out by the NPEs */
+ qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0,
+ "%s:TX-done", dev->dev.name);
+}
+
+static void release_queues(struct port *port)
+{
+ qmgr_release_queue(RXFREE_QUEUE(port));
+ qmgr_release_queue(RX_QUEUE(port));
+ qmgr_release_queue(TX_QUEUE(port));
+ qmgr_release_queue(TXDONE_QUEUE);
+}
+
+static void init_queues(struct port *port)
+{
+ int i;
+
+ memset(port->tx_desc_tab, 0, sizeof(port->tx_desc_tab)); /* descs */
+ memset(port->rx_desc_tab, 0, sizeof(port->rx_desc_tab));
+
+ /* Setup RX buffers */
+ for (i = 0; i < RX_DESCS; i++) {
+ struct desc *desc = &port->rx_desc_tab[i];
+ desc->buf_len = MAX_MRU;
+ desc->data = rx_buff(port, i);
+ }
+}
+
+static int ixp4xx_eth_open(struct eth_device *dev)
+{
+ struct port *port = dev->priv;
+ struct npe *npe = port->npe;
+ struct msg msg;
+ int i, err;
+
+#if DEBUG_OPEN
+ fprintf(stderr, "%s%d: opening %p\n", dev->dev.name, dev->dev.id, dev);
+#endif
+
+ if (!npe_running(npe)) {
+ err = npe_load_firmware(npe);
+ if (err)
+ return err;
+
+ if (npe_recv_message(npe, &msg, "ETH_GET_STATUS")) {
+ fprintf(stderr, "%s%d: %s not responding\n", dev->dev.name, dev->dev.id, npe->name);
+ return -EIO;
+ }
+ memcpy(port->firmware, msg.params + 2, 4);
+ }
+
+ if (ixp4xx_adjust_link(dev))
+ return -ENOLINK;
+
+ port->buff_tab = xmalloc((RX_DESCS + TX_DESCS) * MAX_MRU);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_VLAN_SETRXQOSENTRY;
+ msg.eth_id = LOGICAL_ID(port);
+ msg.params[3] = RX_QUEUE(port) | 0x80;
+ msg.params[4] = RX_QUEUE(port) >> 4; /* MSB of offset */
+ msg.params[5] = RX_QUEUE(port) << 4; /* LSB of offset */
+ for (i = 0; i < 8; i++) {
+ msg.params[1] = i;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_RXQ")) {
+ err = -EIO;
+ goto out;
+ }
+ }
+
+ msg.cmd = NPE_EDB_SETPORTADDRESS;
+ msg.eth_id = PHYSICAL_ID(port);
+ memcpy(msg.params, port->pinfo->hwaddr, ETH_ALEN);
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAC")) {
+ err = -EIO;
+ goto out;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_FW_SETFIREWALLMODE;
+ msg.eth_id = LOGICAL_ID(port);
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE")) {
+ err = -EIO;
+ goto out;
+ }
+
+ request_queues(port, dev);
+ init_queues(port);
+
+ for (i = 0; i < ETH_ALEN; i++)
+ __raw_writel(port->pinfo->hwaddr[i], &port->regs->hw_addr[i]);
+ __raw_writel(0x08, &port->regs->random_seed);
+ __raw_writel(0x12, &port->regs->partial_empty_threshold);
+ __raw_writel(0x30, &port->regs->partial_full_threshold);
+ __raw_writel(0x08, &port->regs->tx_start_bytes);
+ __raw_writel(0x15, &port->regs->tx_deferral);
+ __raw_writel(0x08, &port->regs->tx_2part_deferral[0]);
+ __raw_writel(0x07, &port->regs->tx_2part_deferral[1]);
+ __raw_writel(0x80, &port->regs->slot_time);
+ __raw_writel(0x01, &port->regs->int_clock_threshold);
+
+ /* Populate queues with buffers, no failure after this point */
+ for (i = 0; i < TX_DESCS; i++)
+ queue_put_desc(TXDONE_QUEUE, &port->tx_desc_tab[i]);
+
+ for (i = 0; i < RX_DESCS; i++)
+ queue_put_desc(RXFREE_QUEUE(port), &port->rx_desc_tab[i]);
+
+ __raw_writel(TX_CNTRL1_RETRIES, &port->regs->tx_control[1]);
+ __raw_writel(DEFAULT_TX_CNTRL0, &port->regs->tx_control[0]);
+ __raw_writel(0, &port->regs->rx_control[1]);
+ __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);
+
+#if 0
+ qmgr_set_irq(RX_QUEUE(port), QUEUE_IRQ_SRC_NOT_EMPTY,
+ eth_rx_irq, dev);
+ qmgr_set_irq(TXDONE_QUEUE, QUEUE_IRQ_SRC_NOT_EMPTY,
+ eth_txdone_irq, NULL);
+ qmgr_enable_irq(TXDONE_QUEUE);
+#endif
+ memset(&msg, 0, sizeof(msg));
+#if DEBUG_OPEN
+ fprintf(stderr, "%s%d opened\n", dev->dev.name, dev->dev.id);
+#endif
+ return 0;
+out:
+ free(port->buff_tab);
+ port->buff_tab = NULL;
+#if DEBUG_OPEN
+ fprintf(stderr, "%s%d open failed (%i)\n", dev->dev.name, dev->dev.id, err);
+#endif
+ return err;
+}
+
+static void ixp4xx_eth_close(struct eth_device *dev)
+{
+ struct port *port = dev->priv;
+ struct msg msg;
+ int buffs = RX_DESCS; /* allocated RX buffers */
+ int i;
+
+#if DEBUG_CLOSE
+ fprintf(stderr, "%s%d: closing\n", dev->dev.name, dev->dev.id);
+#endif
+#if 0
+ qmgr_disable_irq(RX_QUEUE(port));
+#endif
+
+ if (!port->buff_tab)
+ return; /* already closed */
+
+ while (queue_get_desc(RXFREE_QUEUE(port), port, 0) >= 0)
+ buffs--;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_SETLOOPBACK_MODE;
+ msg.eth_id = LOGICAL_ID(port);
+ msg.params[1] = 1;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_ENABLE_LOOPBACK"))
+ fprintf(stderr, "%s%d: unable to enable loopback\n", dev->dev.name, dev->dev.id);
+
+#if DEBUG_CLOSE
+ fprintf(stderr, "%s%d: draining RX queue\n", dev->dev.name, dev->dev.id);
+#endif
+ i = 0;
+ do { /* drain RX buffers */
+ while (queue_get_desc(RX_QUEUE(port), port, 0) >= 0)
+ buffs--;
+ if (!buffs)
+ break;
+ if (qmgr_stat_full(TXDONE_QUEUE) && !(i % 10)) {
+ /* we have to inject some packet */
+ struct desc *desc;
+ int n = queue_get_desc(TXDONE_QUEUE, port, 1);
+ BUG_ON(n < 0);
+ desc = &port->tx_desc_tab[n];
+ desc->buf_len = desc->pkt_len = 1;
+ //wmb();
+ barrier();
+ queue_put_desc(TX_QUEUE(port), desc);
+ }
+ udelay(1);
+ } while (++i < MAX_CLOSE_WAIT);
+
+ if (buffs)
+ fprintf(stderr, "%s%d: unable to drain RX queue, %i buffer(s) left in NPE\n",
+ dev->dev.name, dev->dev.id, buffs);
+#if DEBUG_CLOSE
+ if (!buffs)
+ fprintf(stderr, "%s%d: draining RX queue took %i cycles\n", dev->dev.name, dev->dev.id, i);
+#endif
+
+ buffs = TX_DESCS;
+ while (queue_get_desc(TX_QUEUE(port), port, 1) >= 0)
+ buffs--; /* cancel TX */
+
+ i = 0;
+ do {
+ while (queue_get_desc(TXDONE_QUEUE, port, 1) >= 0)
+ buffs--;
+ if (!buffs)
+ break;
+ } while (++i < MAX_CLOSE_WAIT);
+
+ if (buffs)
+ fprintf(stderr, "%s%d: unable to drain TX queue, %i buffer(s) left in NPE\n",
+ dev->dev.name, dev->dev.id, buffs);
+#if DEBUG_CLOSE
+ if (!buffs)
+ fprintf(stderr, "%s%d: draining TX queues took %i cycles\n", dev->dev.name, dev->dev.id, i);
+#endif
+
+ msg.params[1] = 0;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_DISABLE_LOOPBACK"))
+ fprintf(stderr, "%s%d: unable to disable loopback\n", dev->dev.name, dev->dev.id);
+
+#if 0
+ qmgr_disable_irq(TXDONE_QUEUE);
+#endif
+ release_queues(port);
+ free(port->buff_tab);
+ port->buff_tab = NULL;
+#if DEBUG_CLOSE
+ fprintf(stderr, "%s%d: closed\n", dev->dev.name, dev->dev.id);
+#endif
+}
+
+static int ixp4xx_eth_get_hwaddr(struct eth_device *eth, unsigned char *addr)
+{
+ struct port *port = eth->priv;
+ memcpy(addr, port->pinfo->hwaddr, 6);
+ return 0;
+}
+
+static int ixp4xx_eth_set_hwaddr(struct eth_device *eth, unsigned char *addr)
+{
+ struct port *port = eth->priv;
+ memcpy(port->pinfo->hwaddr, addr, 6);
+ return 0;
+}
+
+static int ixp4xx_eth_init(struct eth_device *eth)
+{
+ struct port *port = eth->priv;
+
+ __raw_writel(DEFAULT_CORE_CNTRL | CORE_RESET,
+ &port->regs->core_control);
+ udelay(50);
+ __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
+ udelay(50);
+
+ miidev_restart_aneg(&port->miidev);
+ return 0;
+}
+
+static int ixp4xx_eth_probe(struct device_d *dev)
+{
+ struct npe *npe;
+ struct port *port;
+ struct eth_plat_info *pinfo = dev->platform_data;
+
+ if (!pinfo) {
+ fprintf(stderr, "ixp4xx_eth: no platform information\n");
+ return -ENODEV;
+ }
+
+ if (!(npe = npe_request(pinfo->npe))) {
+ fprintf(stderr, "ixp4xx_eth: unable to acquire NPE\n");
+ return -ENODEV;
+ }
+
+ port = memalign(0x20, sizeof(*port));
+ memset(port, 0, sizeof(*port));
+
+ port->regs = pinfo->regs;
+ port->npe = npe;
+ port->pinfo = pinfo;
+ port->eth.dev.id = -1;
+ port->eth.priv = port;
+ port->eth.init = ixp4xx_eth_init;
+ port->eth.open = ixp4xx_eth_open;
+ port->eth.halt = ixp4xx_eth_close;
+ port->eth.send = ixp4xx_eth_xmit;
+ port->eth.recv = ixp4xx_eth_poll;
+ port->eth.get_ethaddr = ixp4xx_eth_get_hwaddr;
+ port->eth.set_ethaddr = ixp4xx_eth_set_hwaddr;
+
+ port->miidev.dev.id = -1;
+ port->miidev.read = ixp4xx_mdio_read;
+ port->miidev.write = ixp4xx_mdio_write;
+ port->miidev.address = pinfo->phy;
+ port->miidev.edev = &port->eth;
+ mii_register(&port->miidev);
+ eth_register(&port->eth);
+ return 0;
+}
+
+static struct driver_d ixp4xx_eth_driver = {
+ .name = "ixp4xx_eth",
+ .probe = ixp4xx_eth_probe,
+};
+
+static int __init ixp4xx_eth_module_init(void)
+{
+ if (cpu_is_ixp43x()) {
+ /* IXP43x lacks NPE-B and uses NPE-C for MII PHY access */
+ if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEC_ETH))
+ return -ENOSYS;
+ mdio_regs = (struct eth_regs *)IXP4XX_EthC_BASE;
+ } else {
+ /* All MII PHY accesses use NPE-B Ethernet registers */
+ if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
+ return -ENOSYS;
+ mdio_regs = (struct eth_regs *)IXP4XX_EthB_BASE;
+ }
+
+ __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
+
+ register_driver(&ixp4xx_eth_driver);
+ return 0;
+}
+
+device_initcall(ixp4xx_eth_module_init);
diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
index 290619f..0f25ceb 100644
--- a/drivers/serial/serial_ns16550.c
+++ b/drivers/serial/serial_ns16550.c
@@ -102,7 +102,11 @@ static void ns16550_serial_init_port(struct console_device *cdev)
baud_divisor = ns16550_calc_divisor(cdev, CONFIG_BAUDRATE);
/* initializing the device for the first time */
+#ifdef CONFIG_ARCH_IXP4XX
+ plat->reg_write(IER_UUE, base, ier); /* Enable UART operation */
+#else
plat->reg_write(0x00, base, ier);
+#endif
#ifdef CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS
plat->reg_write(0x07, base, mdr1); /* Disable */
#endif
@@ -181,7 +185,11 @@ static int ns16550_setbaudrate(struct console_device *cdev, int baud_rate)
cdev->dev->platform_data;
unsigned long base = cdev->dev->map_base;
unsigned int baud_divisor = ns16550_calc_divisor(cdev, baud_rate);
+#ifdef CONFIG_ARCH_IXP4XX
+ plat->reg_write(IER_UUE, base, ier); /* Enable UART operation */
+#else
plat->reg_write(0x00, base, ier);
+#endif
plat->reg_write(LCR_BKSE, base, lcr);
plat->reg_write(baud_divisor & 0xff, base, dll);
plat->reg_write((baud_divisor >> 8) & 0xff, base, dlm);
diff --git a/drivers/serial/serial_ns16550.h b/drivers/serial/serial_ns16550.h
index eb2fd10..ba20a6f 100644
--- a/drivers/serial/serial_ns16550.h
+++ b/drivers/serial/serial_ns16550.h
@@ -50,6 +50,8 @@
#define dll rbr
#define dlm ier
+#define IER_UUE 0x40 /* UART Unit Enable (XScale) */
+
#define FCR_FIFO_EN 0x01 /* Fifo enable */
#define FCR_RXSR 0x02 /* Receiver soft reset */
#define FCR_TXSR 0x04 /* Transmitter soft reset */
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 41+ messages in thread