Commit 7846fcff authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk

into home.transmeta.com:/home/torvalds/v2.5/linux
parents b4357f99 c9c39357
00-INDEX
- this file
Booting
- requirements for booting
Interrupts
- ARM Interrupt subsystem documentation
Netwinder
- Netwinder specific documentation
README
- General ARM documentation
SA1100
- SA1100 documentation
XScale
- XScale documentation
empeg
- Empeg documentation
mem_alignment
- alignment abort handler documentation
nwfpe
- NWFPE floating point emulator documentation
Booting ARM Linux
=================
Author: Russell King
Date : 18 May 2002
The following documentation is relevant to 2.4.18-rmk6 and beyond.
In order to boot ARM Linux, you require a boot loader, which is a small
program that runs before the main kernel. The boot loader is expected
to initialise various devices, and eventually call the Linux kernel,
passing information to the kernel.
Essentially, the boot loader should provide (as a minimum) the
following:
1. Setup and initialise the RAM.
2. Initialise one serial port.
3. Detect the machine type.
4. Setup the kernel tagged list.
5. Call the kernel image.
1. Setup and initialise RAM
---------------------------
Existing boot loaders: MANDATORY
New boot loaders: MANDATORY
The boot loader is expected to find and initialise all RAM that the
kernel will use for volatile data storage in the system. It performs
this in a machine dependent manner. (It may use internal algorithms
to automatically locate and size all RAM, or it may use knowledge of
the RAM in the machine, or any other method the boot loader designer
sees fit.)
2. Initialise one serial port
-----------------------------
Existing boot loaders: OPTIONAL, RECOMMENDED
New boot loaders: OPTIONAL, RECOMMENDED
The boot loader should initialise and enable one serial port on the
target. This allows the kernel serial driver to automatically detect
which serial port it should use for the kernel console (generally
used for debugging purposes, or communication with the target.)
As an alternative, the boot loader can pass the relevant 'console='
option to the kernel via the tagged lists specifing the port, and
serial format options as described in
linux/Documentation/kernel-parameters.txt.
3. Detect the machine type
--------------------------
Existing boot loaders: OPTIONAL
New boot loaders: MANDATORY
The boot loader should detect the machine type its running on by some
method. Whether this is a hard coded value or some algorithm that
looks at the connected hardware is beyond the scope of this document.
The boot loader must ultimately be able to provide a MACH_TYPE_xxx
value to the kernel. (see linux/arch/arm/tools/mach-types).
4. Setup the kernel tagged list
-------------------------------
Existing boot loaders: OPTIONAL, HIGHLY RECOMMENDED
New boot loaders: MANDATORY
The boot loader must create and initialise the kernel tagged list.
A valid tagged list starts with ATAG_CORE and ends with ATAG_NONE.
The ATAG_CORE tag may or may not be empty. An empty ATAG_CORE tag
has the size field set to '2' (0x00000002). The ATAG_NONE must set
the size field to zero.
Any number of tags can be placed in the list. It is undefined
whether a repeated tag appends to the information carried by the
previous tag, or whether it replaces the information in its
entirety; some tags behave as the former, others the latter.
The boot loader must pass at a minimum the size and location of
the system memory, and root filesystem location. Therefore, the
minimum tagged list should look:
+-----------+
base -> | ATAG_CORE | |
+-----------+ |
| ATAG_MEM | | increasing address
+-----------+ |
| ATAG_NONE | |
+-----------+ v
The tagged list should be stored in system RAM.
The tagged list must be placed in a region of memory where neither
the kernel decompressor nor initrd 'bootp' program will overwrite
it. The recommended placement is in the first 16KiB of RAM.
5. Calling the kernel image
---------------------------
Existing boot loaders: MANDATORY
New boot loaders: MANDATORY
There are two options for calling the kernel zImage. If the zImage
is stored in flash, and is linked correctly to be run from flash,
then it is legal for the boot loader to call the zImage in flash
directly.
The zImage may also be placed in system RAM (at any location) and
called there. Note that the kernel uses 16K of RAM below the image
to store page tables. The recommended placement is 32KiB into RAM.
In either case, the following conditions must be met:
- CPU register settings
r0 = 0,
r1 = machine type number discovered in (3) above.
r2 = physical address of tagged list in system RAM.
- CPU mode
All forms of interrupts must be disabled (IRQs and FIQs)
The CPU must be in SVC mode. (A special exception exists for Angel)
- Caches, MMUs
The MMU must be off.
Instruction cache may be on or off.
Data cache must be off.
- The boot loader is expected to call the kernel image by jumping
directly to the first instruction of the kernel image.
Support functions for the SA11x0 internal DMA channels
======================================================
Nicolas Pitre <nico@cam.org>
Last updated: 2001/07/15
The DMA controller consists of six independent DMA channels. Each channel
can be configured to service any of the serial controllers. Two channels
are required to service a full-duplex serial controller. The DMA
controller is intended to relieve the processor of the interrupt overhead
in servicing these ports with programmed I/ O.
If desired, any or all peripherals (except the UDC) may be serviced with
programmed I/ O instead of DMA. Each peripheral is capable of requesting
processor service through its own interrupt lines or through a DMA
request.
A set of functions is provided to support drivers working with DMA buffers
through a generic interface for (wishfully) all DMA usages. Those
functions will take care of buffer queueing and splitting, DMA register
management, interrupt handling, etc.
SA11x0 DMA API
--------------
Here is the description for the DMA API.
int sa1100_request_dma( dmach_t *channel, const char *device_id,
dma_device_t device );
This function will search for a free DMA channel and returns the channel
number in '*channel'. 'device_id' should point to a string identifying
the DMA usage or device (mainly for /proc). 'device' is the SA11x0
peripheral's ports. Note that reading from a port and writing to the
same port are actually considered as two different streams requiring
two DMA channels with their own device type. All possible dma_device_t
are defined in include/asm-arm/arch-sa1100/dma.h. If no channel is
available, or if the desired device is already in use by another DMA
channel, then an error code is returned. This function must be called
before any other DMA calls.
int sa1100_dma_queue_buffer( dmach_t channel, void *buf_id,
dma_addr_t data, int size );
This function enqueue the specified buffer for DMA processing. The buffer
will be transmitted or filled with incoming data depending on the channel
configuration made through sa1100_dma_set_device(). If the queue is
empty, DMA starts immediately on the given buffer.
Arguments are:
dmach_t channel: the channel number.
void *buf_id: a buffer identification known by the caller.
dma_addr_t data: the buffer's physical address.
int size: the buffer size in bytes.
Note here the dma_addr_t which is not the same as the virtual address as
returned by kmalloc() and friends. The DMA controller must be given a
physical address to a buffer which is not cached bye the CPU data cache.
To get such address, the DMA mapping functions (see
Documentation/DMA-mapping.txt) are recommended. The only relevant
functions are pci_alloc_consistent(), pci_map_single() and their unmap
counterparts. The PCI dev argument is NULL of course.
There is no restriction on the buffer size. The DMA code will split it up
internally to acommodate the DMA controller as needed. If the buffer
can't be enqueued the appropriate error code is returned.
int sa1100_dma_set_callback( dmach_t channel, dma_callback_t cb );
As soon as the DMa completes with a buffer, a callback function is used to
notify the driver which would have registered one. The callback function
is prototyped as:
void dma_callback( void *buf_id, int size );
The 'buf_id' argument is the buffer identifier as passed to
sa1100_dma_queue_buffer(). The 'size' argument is the number of bytes the
DMA processed (should be the same as the buffer size).
Note that this callback function is called while in interrupt context.
So it has to be small and efficient while posponing more complex
processing to a bottom-half function or similar. All
restrictions for interrupt handlers still apply.
int sa1100_dma_get_current( dmach_t channel, void **buf_id,
dma_addr_t *addr );
This returns the buffer ID and the DMA address pointer within the buffer
currently being processed. If no such buffer is currently processed, an
error code is returned. This is useful for mmap()'ed buffers like in
audio drivers.
int sa1100_dma_stop( dmach_t channel );
This call stops any DMA transfer on the given channel.
int sa1100_dma_resume( dmach_t channel );
This call resumes a DMA transfer which would have been stopped through
sa1100_dma_stop().
int sa1100_dma_flush_all( dmach_t channel );
This completely flushes all queued buffers and on-going DMA transfers on a
given channel. The next enqueued buffer following this call will be
processed right away.
int sa1100_dma_set_spin( dmach_t channel, dma_addr_t addr, int size );
Because there is at least one device out there that uses its receive
signal for its transmit clock reference, we need a mecanism to make the
DMA "spin" on a certain buffer for when there is no more actual buffer to
process. The 'addr' argument is the physical memory address to use, and
the 'size' argument determines the spin DMA chunk. This size can't be
larger than 8191 (if so, it is clamped to 4096). When the size is 0,
the spin function is turned off.
When activated, DMA will "spin" until there is any buffer in the queue.
The current DMA chunk will terminate before a newly queued buffer is
processed. The spin buffer will only be reused when there is no more
acctual buffer to process.
It is important not to choose a too small 'size' value since it will
greatly increase the interrupt load required to restart the spin. Since
this feature will typically be used on transmit DMAs, and because a buffer
full of zeros is probably the best thing to spin out, the 'addr' argument
may well be used with FLUSH_BASE_PHYS for which no allocation nor memory
bus request are needed.
The spinning DMA is affected by sa1100_dma_stop() and sa1100_dma_resume()
but not bu sa1100_dma_flush_all().
void sa1100_free_dma( dmach_t channel );
This clears all activities on a given DMA channel and releases it for
future requests.
Buffer allocation
-----------------
Like mentionned above, it is the driver's responsibility to allocate, free
and keep track of buffer space with dma_addr_t type addresses. However the
driver must not change the state of any buffer after it has been sent to
sa1100-dma_queue_buffer(). When that function has been called, the buffer
becomes the DMA's ownership until one of these events occur:
- The callback function is called by the DMA code with a buffer ID to
indicate that DMA processing terminated on that buffer. Then the
driver owns the buffer again.
- The sa1100-dma_flush_all() function is called by the driver at which
point *all* queued buffers are owned by the driver again.
- The sa1100-free_dma() does the same as sa1100-dma_flush_all().
This doesn't mean that you can't change the content of a queued buffer in
conjonction with the usage of pci_map_consistent() and
sa1100_dma_get_current()... but then you must be sure you know what you're
doing (this doesn't work with pci_map_single()).
Examples
--------
A real example of audio ring buffers is implemented in the
drivers/sound/sa1100-audio.c driver. The SA1110 USB client and the
SA11x0 FIR drivers are also using this interface to implement packetized
DMA.
A transmit DMA for network packets could look like this (largely simplified):
struct sk_buff *tx_ring_skb[RING_SIZE];
dma_addr_t tx_ring_dma[RING_SIZE];
int cur_tx;
...
transmit function:
tx_ring_skb[cur_tx] = skb;
tx_ring_dma[cur_tx] = pci_map_single(NULL, skb->data, skb->len,
PCI_DMA_TODEVICE);
sa1100_dma_queue_buffer(channel, (void*)cur_tx,
tx_ring_dma[cur_tx], skb->len);
cur_tx++; cur_tx %= RING_SIZE;
...
and the callback function:
void tx_done_callback( void *buf_id, int size ) {
int done_tx = (int) buf_id;
struct sk_buff *skb = tx_ring_skb[done_tx];
pci_unmap_single(NULL, tx_ring_dma[done_tx], skb->len,
PCI_DMA_TODEVICE);
stats.tx_packets++;
stats.tx_bytes += size;
dev_kfree_skb_irq(skb);
tx_ring_skb[done_tx] = NULL;
}
For drivers expecting variable length packets i.e. USB client, it is
necessary to register the appropriate IRQ to be notified when the receiver
is idle, the packet is complete, etc. We could use one buffer at a time
with its ID being the virtual address of the buffer.
Then the sequence:
/* be sure DMA won't continue under our feet */
sa1100_dma_stop(channel);
/* get the actual DMA length */
sa1100_get_current(channel, &data, &dma_ptr);
/* acquire ownership for the buffer */
sa1100_dma_flush_all(channel);
/* unmap the DMA buffer (actually doing cache coherency on ARM) */
pci_unmap_single (NULL, dma_addr, MAX_PKT_SIZE, PCI_DMA_FROMDEVICE);
/* get remaining bytes from the fifo */
ptr = data + dma_ptr - dma_addr;
while (fifo_not_empty)
*ptr++ = get_byte_from_fifo;
/* feed another free buffer for the next packet */
dma_addr2 = pci_map_single(NULL, data2, MAX_PKT_SIZE,
PCI_DMA_FROMDEVICE);
sa1100_dma_queue_buffer(channel, data2, dma_addr2, MAX_PKT_SIZE);
/* process the current packet */
...
might do the trick. This looks a bit ugly but that's a starting point for
improvements.
TODO
----
- Create kernel-doc comments in the source to document the API and
let the documentation be generated automatically.
......@@ -366,9 +366,12 @@ __armv4_cache_on:
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
mrc p15, 0, r0, c1, c0, 0 @ read control reg
orr r0, r0, #0x1000 @ I-cache enable
orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement
orr r0, r0, #0x0030
b __common_cache_on
bl __common_cache_on
mov r0, #0
mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
mov pc, r12
__arm6_cache_on:
mov r12, lr
......@@ -377,6 +380,11 @@ __arm6_cache_on:
mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3
mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3
mov r0, #0x30
bl __common_cache_on
mov r0, #0
mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3
mov pc, r12
__common_cache_on:
#ifndef DEBUG
orr r0, r0, #0x000d @ Write buffer, mmu
......@@ -385,7 +393,7 @@ __common_cache_on:
mcr p15, 0, r3, c2, c0, 0 @ load page table pointer
mcr p15, 0, r1, c3, c0, 0 @ load domain access control
mcr p15, 0, r0, c1, c0, 0 @ load control register
mov pc, r12
mov pc, lr
/*
* All code following this line is relocatable. It is relocated by
......@@ -567,11 +575,12 @@ cache_clean_flush:
__armv4_cache_flush:
bic r1, pc, #31
add r2, r1, #65536 @ 2x the largest dcache size
1: ldr r12, [r1], #32 @ s/w flush D cache
1: ldr r3, [r1], #32 @ s/w flush D cache
teq r1, r2
bne 1b
mcr p15, 0, r1, c7, c7, 0 @ flush I cache
mcr p15, 0, r1, c7, c5, 0 @ flush I cache
mcr p15, 0, r1, c7, c6, 0 @ flush D cache
mcr p15, 0, r1, c7, c10, 4 @ drain WB
mov pc, lr
......
......@@ -978,6 +978,8 @@ ecard_probe(int slot, card_type_t type)
strcpy(ec->dev.name, "fixme!");
ec->dev.parent = NULL;
ec->dev.bus = &ecard_bus_type;
ec->dev.dma_mask = &ec->dma_mask;
ec->dma_mask = (u64)0xffffffff;
device_register(&ec->dev);
......
......@@ -81,7 +81,7 @@ unsigned long phys_initrd_start __initdata = 0;
unsigned long phys_initrd_size __initdata = 0;
static struct meminfo meminfo __initdata = { 0, };
static struct proc_info_item proc_info;
static const char *cpu_name;
static const char *machine_name;
static char command_line[COMMAND_LINE_SIZE];
......@@ -275,7 +275,7 @@ static void __init setup_processor(void)
while (1);
}
proc_info = *list->info;
cpu_name = list->cpu_name;
#ifdef MULTI_CPU
processor = *list->proc;
......@@ -287,9 +287,9 @@ static void __init setup_processor(void)
cpu_user = *list->user;
#endif
printk("CPU: %s %s revision %d (ARMv%s)\n",
proc_info.manufacturer, proc_info.cpu_name,
(int)processor_id & 15, proc_arch[cpu_architecture()]);
printk("CPU: %s [%08x] revision %d (ARMv%s)\n",
cpu_name, processor_id, (int)processor_id & 15,
proc_arch[cpu_architecture()]);
dump_cpu_info();
......@@ -723,9 +723,8 @@ static int c_show(struct seq_file *m, void *v)
{
int i;
seq_printf(m, "Processor\t: %s %s rev %d (%s)\n",
proc_info.manufacturer, proc_info.cpu_name,
(int)processor_id & 15, elf_platform);
seq_printf(m, "Processor\t: %s rev %d (%s)\n",
cpu_name, (int)processor_id & 15, elf_platform);
seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
loops_per_jiffy / (500000/HZ),
......
......@@ -97,11 +97,19 @@ static int integrator_verify_speed(struct cpufreq_policy *policy)
return 0;
}
static void do_set_policy(int cpu, struct cpufreq_policy *policy)
static int integrator_set_policy(struct cpufreq_policy *policy)
{
struct vco vco = freq_to_vco(policy->max, 1);
unsigned long cpus_allowed;
int cpu = policy->cpu;
struct vco vco;
struct cpufreq_freqs freqs;
u_int cm_osc;
/*
* Save this threads cpus_allowed mask.
*/
cpus_allowed = current->cpus_allowed;
/*
* Bind to the specified CPU. When this call returns,
* we should be running on the right CPU.
......@@ -109,6 +117,23 @@ static void do_set_policy(int cpu, struct cpufreq_policy *policy)
set_cpus_allowed(current, 1 << cpu);
BUG_ON(cpu != smp_processor_id());
/* get current setting */
cm_osc = __raw_readl(CM_OSC);
vco.od = (cm_osc >> 8) & 7;
vco.vdw = cm_osc & 255;
freqs.old = vco_to_freq(vco, 1);
freqs.new = target_freq;
freqs.cpu = policy->cpu;
if (freqs.old == freqs.new) {
set_cpus_allowed(current, cpus_allowed);
return 0;
}
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
vco = freq_to_vco(policy->max, 1);
cm_osc = __raw_readl(CM_OSC);
cm_osc &= 0xfffff800;
cm_osc |= vco.vdw | vco.od << 8;
......@@ -116,32 +141,14 @@ static void do_set_policy(int cpu, struct cpufreq_policy *policy)
__raw_writel(0xa05f, CM_LOCK);
__raw_writel(cm_osc, CM_OSC);
__raw_writel(0, CM_LOCK);
}
static int integrator_set_policy(struct cpufreq_policy *policy)
{
unsigned long cpus_allowed;
int cpu;
/*
* Save this threads cpus_allowed mask.
*/
cpus_allowed = current->cpus_allowed;
if (policy->cpu == CPUFREQ_ALL_CPUS) {
for (cpu = 0; cpu < NR_CPUS; cpu++) {
if (!cpu_online(cpu))
continue;
do_set_policy(cpu, policy);
}
} else
do_set_policy(policy->cpu, policy);
/*
* Restore the CPUs allowed mask.
*/
set_cpus_allowed(current, cpus_allowed);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return 0;
}
......@@ -149,8 +156,8 @@ static struct cpufreq_policy integrator_policy = {
.cpu = 0,
.policy = CPUFREQ_POLICY_POWERSAVE,
.cpuinfo = {
.max_cpu_freq = 160000,
.min_cpu_freq = 12000,
.max_freq = 160000,
.min_freq = 12000,
.transition_latency = CPUFREQ_ETERNAL,
},
};
......@@ -168,7 +175,7 @@ static int __init integrator_cpu_init(void)
unsigned long cpus_allowed;
int cpu;
policies = kmalloc(sizeof(struct cpufreq_freqs) * NR_CPUS,
policies = kmalloc(sizeof(struct cpufreq_policy) * NR_CPUS,
GFP_KERNEL);
if (!policies) {
printk(KERN_ERR "CPU: unable to allocate policies structure\n");
......
......@@ -183,7 +183,7 @@ static int sa1100_setspeed(struct cpufreq_policy *policy)
freqs.old = cur;
freqs.new = policy->max;
freqs.cpu = CPUFREQ_ALL_CPUS;
freqs.cpu = 0;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
......
......@@ -242,7 +242,7 @@ static int sa1110_setspeed(struct cpufreq_policy *policy)
freqs.old = sa11x0_getspeed();
freqs.new = policy->max;
freqs.cpu = CPUFREQ_ALL_CPUS;
freqs.cpu = 0;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
......
/*
* linux/arch/arm/mm/consistent.c
*
* Copyright (C) 2000 Russell King
* Copyright (C) 2000-2002 Russell King
*
* 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.
*
* Dynamic DMA mapping support.
* DMA uncached mapping support.
*/
#include <linux/config.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/list.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#define CONSISTENT_BASE (0xffc00000)
#define CONSISTENT_END (0xffe00000)
#define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT)
/*
* This allocates one page of cache-coherent memory space and returns
* both the virtual and a "dma" address to that space.
* This is the page table (2MB) covering uncached, DMA consistent allocations
*/
static pte_t *consistent_pte;
static spinlock_t consistent_lock = SPIN_LOCK_UNLOCKED;
/*
* VM region handling support.
*
* This should become something generic, handling VM region allocations for
* vmalloc and similar (ioremap, module space, etc).
*
* We should allow this function to be called from interrupt context.
* However, we call ioremap, which needs to fiddle around with various
* things (like the vmlist_lock, and allocating page tables). These
* things aren't interrupt safe (yet).
* I envisage vmalloc()'s supporting vm_struct becoming:
*
* Note that this does *not* zero the allocated area!
* struct vm_struct {
* struct vm_region region;
* unsigned long flags;
* struct page **pages;
* unsigned int nr_pages;
* unsigned long phys_addr;
* };
*
* get_vm_area() would then call vm_region_alloc with an appropriate
* struct vm_region head (eg):
*
* struct vm_region vmalloc_head = {
* .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list),
* .vm_start = VMALLOC_START,
* .vm_end = VMALLOC_END,
* };
*
* However, vmalloc_head.vm_start is variable (typically, it is dependent on
* the amount of RAM found at boot time.) I would imagine that get_vm_area()
* would have to initialise this each time prior to calling vm_region_alloc().
*/
void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
struct vm_region {
struct list_head vm_list;
unsigned long vm_start;
unsigned long vm_end;
};
static struct vm_region consistent_head = {
.vm_list = LIST_HEAD_INIT(consistent_head.vm_list),
.vm_start = CONSISTENT_BASE,
.vm_end = CONSISTENT_END,
};
#if 0
static void vm_region_dump(struct vm_region *head, char *fn)
{
struct page *page, *end, *free;
unsigned long order;
void *ret;
struct vm_region *c;
/* FIXME */
if (in_interrupt())
BUG();
printk("Consistent Allocation Map (%s):\n", fn);
list_for_each_entry(c, &head->list, vm_list) {
printk(" %p: %08lx - %08lx (0x%08x)\n", c,
c->vm_start, c->vm_end, c->vm_end - c->vm_start);
}
}
#else
#define vm_region_dump(head,fn) do { } while(0)
#endif
static int vm_region_alloc(struct vm_region *head, struct vm_region *new, size_t size)
{
unsigned long addr = head->vm_start, end = head->vm_end - size;
struct vm_region *c;
list_for_each_entry(c, &head->vm_list, vm_list) {
if ((addr + size) < addr)
goto out;
if ((addr + size) <= c->vm_start)
goto found;
addr = c->vm_end;
if (addr > end)
goto out;
}
found:
/*
* Insert this entry _before_ the one we found.
*/
list_add_tail(&new->vm_list, &c->vm_list);
new->vm_start = addr;
new->vm_end = addr + size;
return 0;
out:
return -ENOMEM;
}
static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr)
{
struct vm_region *c;
list_for_each_entry(c, &head->vm_list, vm_list) {
if (c->vm_start == addr)
goto out;
}
c = NULL;
out:
return c;
}
/*
* This allocates one page of cache-coherent memory space and returns
* both the virtual and a "dma" address to that space.
*/
void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle,
unsigned long cache_flags)
{
struct page *page;
struct vm_region *c;
unsigned long order, flags;
void *ret = NULL;
if (!consistent_pte) {
printk(KERN_ERR "consistent_alloc: not initialised\n");
dump_stack();
return NULL;
}
size = PAGE_ALIGN(size);
order = get_order(size);
......@@ -51,74 +159,176 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
if (!page)
goto no_page;
*dma_handle = page_to_bus(page);
ret = __ioremap(page_to_pfn(page) << PAGE_SHIFT, size, 0,
PAGE_SIZE << order);
if (!ret)
/*
* Invalidate any data that might be lurking in the
* kernel direct-mapped region.
*/
{
unsigned long kaddr = (unsigned long)page_address(page);
invalidate_dcache_range(kaddr, kaddr + size);
}
/*
* Our housekeeping doesn't need to come from DMA,
* but it must not come from highmem.
*/
c = kmalloc(sizeof(struct vm_region),
gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
if (!c)
goto no_remap;
#if 0 /* ioremap_does_flush_cache_all */
{
void *virt = page_address(page);
spin_lock_irqsave(&consistent_lock, flags);
vm_region_dump(&consistent_head, "before alloc");
/*
* we need to ensure that there are no cachelines in use, or
* worse dirty in this area. Really, we don't need to do
* this since __ioremap does a flush_cache_all() anyway. --rmk
* Attempt to allocate a virtual address in the
* consistent mapping region.
*/
invalidate_dcache_range(virt, virt + size);
}
#endif
if (!vm_region_alloc(&consistent_head, c, size)) {
pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
struct page *end = page + (1 << order);
pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
L_PTE_DIRTY | L_PTE_WRITE |
cache_flags);
/*
* free wasted pages. We skip the first page since we know
* that it will have count = 1 and won't require freeing.
* We also mark the pages in use as reserved so that
* remap_page_range works.
* Set the "dma handle"
*/
free = page + (size >> PAGE_SHIFT);
end = page + (1 << order);
*handle = page_to_bus(page);
do {
BUG_ON(!pte_none(*pte));
for (; page < end; page++) {
set_page_count(page, 1);
if (page >= free)
__free_page(page);
else
SetPageReserved(page);
set_pte(pte, mk_pte(page, prot));
page++;
pte++;
} while (size -= PAGE_SIZE);
/*
* Free the otherwise unused pages.
*/
while (page < end) {
set_page_count(page, 1);
__free_page(page);
page++;
}
return ret;
no_remap:
ret = (void *)c->vm_start;
}
vm_region_dump(&consistent_head, "after alloc");
spin_unlock_irqrestore(&consistent_lock, flags);
no_remap:
if (ret == NULL) {
kfree(c);
__free_pages(page, order);
no_page:
return NULL;
}
no_page:
return ret;
}
/*
* free a page as defined by the above mapping. We expressly forbid
* calling this from interrupt context.
* free a page as defined by the above mapping.
*/
void consistent_free(void *vaddr, size_t size, dma_addr_t handle)
{
struct page *page, *end;
if (in_interrupt())
BUG();
struct vm_region *c;
unsigned long flags;
pte_t *ptep;
/*
* More messing around with the MM internals. This is
* sick, but then so is remap_page_range().
*/
size = PAGE_ALIGN(size);
page = virt_to_page(bus_to_virt(handle));
end = page + (size >> PAGE_SHIFT);
for (; page < end; page++)
spin_lock_irqsave(&consistent_lock, flags);
vm_region_dump(&consistent_head, "before free");
c = vm_region_find(&consistent_head, (unsigned long)vaddr);
if (!c)
goto no_area;
if ((c->vm_end - c->vm_start) != size) {
printk(KERN_ERR "consistent_free: wrong size (%ld != %d)\n",
c->vm_end - c->vm_start, size);
dump_stack();
size = c->vm_end - c->vm_start;
}
ptep = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
do {
pte_t pte = ptep_get_and_clear(ptep);
unsigned long pfn;
ptep++;
if (!pte_none(pte) && pte_present(pte)) {
pfn = pte_pfn(pte);
if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);
ClearPageReserved(page);
__iounmap(vaddr);
__free_page(page);
continue;
}
}
printk(KERN_CRIT "consistent_free: bad page in kernel page "
"table\n");
} while (size -= PAGE_SIZE);
flush_tlb_kernel_range(c->vm_start, c->vm_end);
list_del(&c->vm_list);
vm_region_dump(&consistent_head, "after free");
spin_unlock_irqrestore(&consistent_lock, flags);
kfree(c);
return;
no_area:
spin_unlock_irqrestore(&consistent_lock, flags);
printk(KERN_ERR "consistent_free: trying to free "
"invalid area: %p\n", vaddr);
dump_stack();
}
/*
* Initialise the consistent memory allocation.
*/
static int __init consistent_init(void)
{
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
do {
pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE);
if (!pmd) {
printk(KERN_ERR "consistent_init: out of pmd tables\n");
return -ENOMEM;
}
if (!pmd_none(*pmd)) {
printk(KERN_ERR "consistent_init: PMD already allocated\n");
return -EINVAL;
}
pte = pte_alloc_kernel(&init_mm, pmd, CONSISTENT_BASE);
if (!pte) {
printk(KERN_ERR "consistent_init: out of pte tables\n");
return -ENOMEM;
}
consistent_pte = pte;
} while (0);
return 0;
}
core_initcall(consistent_init);
/*
* make an area consistent.
*/
......@@ -128,16 +338,16 @@ void consistent_sync(void *vaddr, size_t size, int direction)
unsigned long end = start + size;
switch (direction) {
case PCI_DMA_NONE:
BUG();
case PCI_DMA_FROMDEVICE: /* invalidate only */
case DMA_FROM_DEVICE: /* invalidate only */
invalidate_dcache_range(start, end);
break;
case PCI_DMA_TODEVICE: /* writeback only */
case DMA_TO_DEVICE: /* writeback only */
clean_dcache_range(start, end);
break;
case PCI_DMA_BIDIRECTIONAL: /* writeback and invalidate */
case DMA_BIDIRECTIONAL: /* writeback and invalidate */
flush_dcache_range(start, end);
break;
default:
BUG();
}
}
/*
* linux/arch/arm/mm/extable.c
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <asm/uaccess.h>
extern const struct exception_table_entry __start___ex_table[];
extern const struct exception_table_entry __stop___ex_table[];
static inline unsigned long
search_one_table(const struct exception_table_entry *first,
const struct exception_table_entry *
search_extable(const struct exception_table_entry *first,
const struct exception_table_entry *last,
unsigned long value)
{
......@@ -22,44 +16,11 @@ search_one_table(const struct exception_table_entry *first,
mid = (last - first) / 2 + first;
diff = mid->insn - value;
if (diff == 0)
return mid->fixup;
return mid;
else if (diff < 0)
first = mid+1;
else
last = mid-1;
}
return 0;
}
extern spinlock_t modlist_lock;
unsigned long
search_exception_table(unsigned long addr)
{
unsigned long ret;
#ifndef CONFIG_MODULES
/* There is only the kernel to search. */
ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
#else
unsigned long flags;
struct list_head *l;
ret = 0;
/* The kernel is the last "module" -- no need to treat it special. */
spin_lock_irqsave(&modlist_lock, flags);
list_for_each(l, &extables) {
struct exception_table *ex
= list_entry(l, struct exception_table, list);
if (ex->num_entries == 0)
continue;
ret = search_one_table(ex->entry,
ex->entry + ex->num_entries - 1, addr);
if (ret)
break;
}
spin_unlock_irqrestore(&modlist_lock, flags);
#endif
return ret;
return NULL;
}
......@@ -9,6 +9,7 @@
* published by the Free Software Foundation.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
......@@ -102,23 +103,25 @@ static void
__do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
unsigned long fixup;
const struct exception_table_entry *fixup;
/*
* Are we prepared to handle this kernel fault?
*/
if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
fixup = search_exception_tables(instruction_pointer(regs));
if (fixup) {
#ifdef DEBUG
printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
current->comm, regs->ARM_pc, addr, fixup);
current->comm, regs->ARM_pc, addr, fixup->fixup);
#endif
regs->ARM_pc = fixup;
regs->ARM_pc = fixup->fixup;
return;
}
/*
* No handler, we'll have to terminate things with extreme prejudice.
*/
bust_spinlocks(1);
printk(KERN_ALERT
"Unable to handle kernel %s at virtual address %08lx\n",
(addr < PAGE_SIZE) ? "NULL pointer dereference" :
......@@ -126,6 +129,7 @@ __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
show_pte(mm, addr);
die("Oops", regs, fsr);
bust_spinlocks(0);
do_exit(SIGKILL);
}
......
......@@ -420,8 +420,6 @@ ENTRY(cpu_arm1020_set_pte)
mov pc, lr
cpu_manu_name:
.asciz "ARM/VLSI"
ENTRY(cpu_arm1020_name)
.ascii "Arm1020"
#ifndef CONFIG_CPU_ICACHE_DISABLE
......@@ -518,15 +516,9 @@ arm1020_processor_functions:
.size arm1020_processor_functions, . - arm1020_processor_functions
.type cpu_arm1020_info, #object
cpu_arm1020_info:
.long cpu_manu_name
.long cpu_arm1020_name
.size cpu_arm1020_info, . - cpu_arm1020_info
.type cpu_arch_name, #object
cpu_arch_name:
.asciz "armv4"
.asciz "armv4t"
.size cpu_arch_name, . - cpu_arch_name
.type cpu_elf_name, #object
......@@ -546,7 +538,7 @@ __arm1020_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
.long cpu_arm1020_info
.long cpu_arm1020_name
.long arm1020_processor_functions
.long v4wbi_tlb_fns
.long v4wb_user_fns
......
......@@ -276,10 +276,12 @@ _arm3_xchg_4: swp r0, r0, [r1]
_arm2_3_check_bugs:
bics pc, lr, #0x04000000 @ Clear FIQ disable bit
armvlsi_name: .asciz "ARM/VLSI"
_arm2_name: .asciz "ARM 2"
_arm250_name: .asciz "ARM 250"
_arm3_name: .asciz "ARM 3"
cpu_arm2_name:
.asciz "ARM 2"
cpu_arm250_name:
.asciz "ARM 250"
cpu_arm3_name:
.asciz "ARM 3"
__INIT
/*
......@@ -295,10 +297,6 @@ arm2_processor_functions:
.word _arm2_xchg_1
.word _arm2_xchg_4
cpu_arm2_info:
.long armvlsi_name
.long _arm2_name
.globl arm250_processor_functions
arm250_processor_functions:
.word _arm2_3_check_bugs
......@@ -308,10 +306,6 @@ arm250_processor_functions:
.word _arm3_xchg_1
.word _arm3_xchg_4
cpu_arm250_info:
.long armvlsi_name
.long _arm250_name
.globl arm3_processor_functions
arm3_processor_functions:
.word _arm2_3_check_bugs
......@@ -321,10 +315,6 @@ arm3_processor_functions:
.word _arm3_xchg_1
.word _arm3_xchg_4
cpu_arm3_info:
.long armvlsi_name
.long _arm3_name
arm2_arch_name: .asciz "armv1"
arm3_arch_name: .asciz "armv2"
arm2_elf_name: .asciz "v1"
......@@ -340,7 +330,7 @@ arm3_elf_name: .asciz "v2"
.long arm2_arch_name
.long arm2_elf_name
.long 0
.long cpu_arm2_info
.long cpu_arm2_name
.long arm2_processor_functions
.long 0
.long 0
......@@ -352,7 +342,7 @@ arm3_elf_name: .asciz "v2"
.long arm3_arch_name
.long arm3_elf_name
.long 0
.long cpu_arm250_info
.long cpu_arm250_name
.long arm250_processor_functions
.long 0
.long 0
......@@ -364,7 +354,7 @@ arm3_elf_name: .asciz "v2"
.long arm3_arch_name
.long arm3_elf_name
.long 0
.long cpu_arm3_info
.long cpu_arm3_name
.long arm3_processor_functions
.long 0
.long 0
......
......@@ -287,14 +287,12 @@ ENTRY(cpu_arm7_reset)
mcr p15, 0, r1, c1, c0, 0 @ turn off MMU etc
mov pc, r0
cpu_armvlsi_name:
.asciz "ARM/VLSI"
cpu_arm6_name: .asciz "ARM 6"
cpu_arm6_name: .asciz "ARM6"
cpu_arm610_name:
.asciz "ARM 610"
cpu_arm7_name: .asciz "ARM 7"
.asciz "ARM610"
cpu_arm7_name: .asciz "ARM7"
cpu_arm710_name:
.asciz "ARM 710"
.asciz "ARM710"
.align
__INIT
......@@ -387,30 +385,6 @@ ENTRY(arm7_processor_functions)
.size arm7_processor_functions, . - arm7_processor_functions
.type cpu_arm6_info, #object
cpu_arm6_info:
.long cpu_armvlsi_name
.long cpu_arm6_name
.size cpu_arm6_info, . - cpu_arm6_info
.type cpu_arm610_info, #object
cpu_arm610_info:
.long cpu_armvlsi_name
.long cpu_arm610_name
.size cpu_arm610_info, . - cpu_Arm610_info
.type cpu_arm7_info, #object
cpu_arm7_info:
.long cpu_armvlsi_name
.long cpu_arm7_name
.size cpu_arm7_info, . - cpu_arm7_info
.type cpu_arm710_info, #object
cpu_arm710_info:
.long cpu_armvlsi_name
.long cpu_arm710_name
.size cpu_arm710_info, . - cpu_arm710_info
.type cpu_arch_name, #object
cpu_arch_name: .asciz "armv3"
.size cpu_arch_name, . - cpu_arch_name
......@@ -431,7 +405,7 @@ __arm6_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_26BIT
.long cpu_arm6_info
.long cpu_arm6_name
.long arm6_processor_functions
.long v3_tlb_fns
.long v3_user_fns
......@@ -446,7 +420,7 @@ __arm610_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_26BIT
.long cpu_arm610_info
.long cpu_arm610_name
.long arm6_processor_functions
.long v3_tlb_fns
.long v3_user_fns
......@@ -461,7 +435,7 @@ __arm7_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_26BIT
.long cpu_arm7_info
.long cpu_arm7_name
.long arm7_processor_functions
.long v3_tlb_fns
.long v3_user_fns
......@@ -476,7 +450,7 @@ __arm710_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_26BIT
.long cpu_arm710_info
.long cpu_arm710_name
.long arm7_processor_functions
.long v3_tlb_fns
.long v3_user_fns
......
......@@ -168,8 +168,6 @@ ENTRY(cpu_arm720_reset)
mov pc, r0
cpu_armvlsi_name:
.asciz "ARM"
cpu_arm720_name:
.asciz "ARM720T"
.align
......@@ -223,14 +221,8 @@ ENTRY(arm720_processor_functions)
.size arm720_processor_functions, . - arm720_processor_functions
.type cpu_arm720_info, #object
cpu_arm720_info:
.long cpu_armvlsi_name
.long cpu_arm720_name
.size cpu_arm720_info, . - cpu_arm720_info
.type cpu_arch_name, #object
cpu_arch_name: .asciz "armv4"
cpu_arch_name: .asciz "armv4t"
.size cpu_arch_name, . - cpu_arch_name
.type cpu_elf_name, #object
......@@ -253,7 +245,7 @@ __arm720_proc_info:
.long cpu_arch_name @ arch_name
.long cpu_elf_name @ elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB @ elf_hwcap
.long cpu_arm720_info @ info
.long cpu_arm720_name @ name
.long arm720_processor_functions
.long v4_tlb_fns
.long v4wt_user_fns
......
......@@ -419,8 +419,6 @@ ENTRY(cpu_arm920_set_pte)
mov pc, lr
cpu_manu_name:
.asciz "ARM/CIRRUS"
ENTRY(cpu_arm920_name)
.ascii "Arm920T"
#ifndef CONFIG_CPU_ICACHE_DISABLE
......@@ -506,15 +504,9 @@ arm920_processor_functions:
.size arm920_processor_functions, . - arm920_processor_functions
.type cpu_arm920_info, #object
cpu_arm920_info:
.long cpu_manu_name
.long cpu_arm920_name
.size cpu_arm920_info, . - cpu_arm920_info
.type cpu_arch_name, #object
cpu_arch_name:
.asciz "armv4"
.asciz "armv4t"
.size cpu_arch_name, . - cpu_arch_name
.type cpu_elf_name, #object
......@@ -534,7 +526,7 @@ __arm920_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
.long cpu_arm920_info
.long cpu_arm920_name
.long arm920_processor_functions
.long v4wbi_tlb_fns
.long v4wb_user_fns
......
......@@ -418,8 +418,6 @@ ENTRY(cpu_arm922_set_pte)
mov pc, lr
cpu_manu_name:
.asciz "ARM/ALTERA"
ENTRY(cpu_arm922_name)
.ascii "Arm922T"
#ifndef CONFIG_CPU_ICACHE_DISABLE
......@@ -505,15 +503,9 @@ arm922_processor_functions:
.size arm922_processor_functions, . - arm922_processor_functions
.type cpu_arm922_info, #object
cpu_arm922_info:
.long cpu_manu_name
.long cpu_arm922_name
.size cpu_arm922_info, . - cpu_arm922_info
.type cpu_arch_name, #object
cpu_arch_name:
.asciz "armv4"
.asciz "armv4t"
.size cpu_arch_name, . - cpu_arch_name
.type cpu_elf_name, #object
......@@ -533,7 +525,7 @@ __arm922_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
.long cpu_arm922_info
.long cpu_arm922_name
.long arm922_processor_functions
.long v4wbi_tlb_fns
.long v4wb_user_fns
......
......@@ -403,8 +403,6 @@ ENTRY(cpu_arm926_set_pte)
mov pc, lr
cpu_manu_name:
.asciz "ARM"
ENTRY(cpu_arm926_name)
.ascii "ARM926EJ-S"
#ifndef CONFIG_CPU_ICACHE_DISABLE
......@@ -503,12 +501,6 @@ arm926_processor_functions:
.size arm926_processor_functions, . - arm926_processor_functions
.type cpu_arm926_info, #object
cpu_arm926_info:
.long cpu_manu_name
.long cpu_arm926_name
.size cpu_arm926_info, . - cpu_arm926_info
.type cpu_arch_name, #object
cpu_arch_name:
.asciz "armv5tej"
......@@ -532,7 +524,7 @@ __arm926_proc_info:
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB | \
HWCAP_FAST_MULT | HWCAP_JAVA
.long cpu_arm926_info
.long cpu_arm926_name
.long arm926_processor_functions
.long v4wbi_tlb_fns
.long v4wb_user_fns
......
......@@ -473,8 +473,6 @@ ENTRY(cpu_sa1100_set_pte)
mov pc, lr
cpu_manu_name:
.asciz "Intel"
cpu_sa110_name:
.asciz "StrongARM-110"
cpu_sa1100_name:
......@@ -547,13 +545,6 @@ ENTRY(sa110_processor_functions)
.size sa110_processor_functions, . - sa110_processor_functions
.type cpu_sa110_info, #object
cpu_sa110_info:
.long cpu_manu_name
.long cpu_sa110_name
.size cpu_sa110_info, . - cpu_sa110_info
/*
* SA1100 and SA1110 share the same function calls
*/
......@@ -587,16 +578,6 @@ ENTRY(sa1100_processor_functions)
.size sa1100_processor_functions, . - sa1100_processor_functions
cpu_sa1100_info:
.long cpu_manu_name
.long cpu_sa1100_name
.size cpu_sa1100_info, . - cpu_sa1100_info
cpu_sa1110_info:
.long cpu_manu_name
.long cpu_sa1110_name
.size cpu_sa1110_info, . - cpu_sa1110_info
.type cpu_arch_name, #object
cpu_arch_name:
.asciz "armv4"
......@@ -620,7 +601,7 @@ __sa110_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
.long cpu_sa110_info
.long cpu_sa110_name
.long sa110_processor_functions
.long v4wb_tlb_fns
.long v4wb_user_fns
......@@ -637,7 +618,7 @@ __sa1100_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
.long cpu_sa1100_info
.long cpu_sa1100_name
.long sa1100_processor_functions
.long v4wb_tlb_fns
.long v4_mc_user_fns
......@@ -652,7 +633,7 @@ __sa1110_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT | HWCAP_FAST_MULT
.long cpu_sa1110_info
.long cpu_sa1110_name
.long sa1100_processor_functions
.long v4wb_tlb_fns
.long v4_mc_user_fns
......
......@@ -651,9 +651,6 @@ ENTRY(cpu_xscale_set_pte)
.ltorg
cpu_manu_name:
.asciz "Intel"
cpu_80200_name:
.asciz "XScale-80200"
......@@ -723,24 +720,6 @@ ENTRY(xscale_processor_functions)
.word cpu_xscale_set_pte
.size xscale_processor_functions, . - xscale_processor_functions
.type cpu_80200_info, #object
cpu_80200_info:
.long cpu_manu_name
.long cpu_80200_name
.size cpu_80200_info, . - cpu_80200_info
.type cpu_pxa250_info, #object
cpu_pxa250_info:
.long cpu_manu_name
.long cpu_pxa250_name
.size cpu_pxa250_info, . - cpu_pxa250_info
.type cpu_pxa210_info, #object
cpu_pxa210_info:
.long cpu_manu_name
.long cpu_pxa210_name
.size cpu_pxa210_info, . - cpu_pxa210_info
.type cpu_arch_name, #object
cpu_arch_name:
.asciz "armv5te"
......@@ -763,7 +742,7 @@ __80200_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
.long cpu_80200_info
.long cpu_80200_name
.long xscale_processor_functions
.long v4wbi_tlb_fns
.long xscale_mc_user_fns
......@@ -778,7 +757,7 @@ __pxa250_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
.long cpu_pxa250_info
.long cpu_pxa250_name
.long xscale_processor_functions
.long v4wbi_tlb_fns
.long xscale_mc_user_fns
......@@ -793,7 +772,7 @@ __pxa210_proc_info:
.long cpu_arch_name
.long cpu_elf_name
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
.long cpu_pxa210_info
.long cpu_pxa210_name
.long xscale_processor_functions
.long v4wbi_tlb_fns
.long xscale_mc_user_fns
......
......@@ -75,6 +75,12 @@ SECTIONS
__stop___ex_table = .;
}
__gpl_ksymtab : { /* GPL Kernel symbol table */
__start___gpl_ksymtab = .;
*(__gpl_ksymtab)
__stop___gpl_ksymtab = .;
}
__ksymtab : { /* Kernel symbol table */
__start___ksymtab = .;
*(__ksymtab)
......
......@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <asm/dma.h>
#include <asm/ecard.h>
......@@ -163,26 +164,27 @@ cumanascsi_2_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
fasdmadir_t direction, fasdmatype_t min_type)
{
struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
struct device *dev = scsi_get_device(host);
int dmach = host->dma_channel;
outb(ALATCH_DIS_DMA, info->alatch);
if (dmach != NO_DMA &&
(min_type == fasdma_real_all || SCp->this_residual >= 512)) {
int bufs, pci_dir, dma_dir, alatch_dir;
int bufs, map_dir, dma_dir, alatch_dir;
bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
if (direction == DMA_OUT)
pci_dir = PCI_DMA_TODEVICE,
map_dir = DMA_TO_DEVICE,
dma_dir = DMA_MODE_WRITE,
alatch_dir = ALATCH_DMA_OUT;
else
pci_dir = PCI_DMA_FROMDEVICE,
map_dir = DMA_FROM_DEVICE,
dma_dir = DMA_MODE_READ,
alatch_dir = ALATCH_DMA_IN;
pci_map_sg(NULL, info->sg, bufs + 1, pci_dir);
dma_map_sg(dev, info->sg, bufs + 1, map_dir);
disable_dma(dmach);
set_dma_sg(dmach, info->sg, bufs + 1);
......
......@@ -32,6 +32,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/irq.h>
......@@ -165,22 +166,23 @@ eesoxscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
fasdmadir_t direction, fasdmatype_t min_type)
{
struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
struct device *dev = scsi_get_device(host);
int dmach = host->dma_channel;
if (dmach != NO_DMA &&
(min_type == fasdma_real_all || SCp->this_residual >= 512)) {
int bufs, pci_dir, dma_dir;
int bufs, map_dir, dma_dir;
bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
if (direction == DMA_OUT)
pci_dir = PCI_DMA_TODEVICE,
map_dir = DMA_TO_DEVICE,
dma_dir = DMA_MODE_WRITE;
else
pci_dir = PCI_DMA_FROMDEVICE,
map_dir = DMA_FROM_DEVICE,
dma_dir = DMA_MODE_READ;
pci_map_sg(NULL, info->sg, bufs + 1, pci_dir);
dma_map_sg(dev, info->sg, bufs + 1, map_dir);
disable_dma(dmach);
set_dma_sg(dmach, info->sg, bufs + 1);
......
......@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <asm/dma.h>
#include <asm/ecard.h>
......@@ -135,22 +136,23 @@ powertecscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
fasdmadir_t direction, fasdmatype_t min_type)
{
struct powertec_info *info = (struct powertec_info *)host->hostdata;
struct device *dev = scsi_get_device(host);
int dmach = host->dma_channel;
if (dmach != NO_DMA &&
(min_type == fasdma_real_all || SCp->this_residual >= 512)) {
int bufs, pci_dir, dma_dir;
int bufs, map_dir, dma_dir;
bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
if (direction == DMA_OUT)
pci_dir = PCI_DMA_TODEVICE,
map_dir = DMA_TO_DEVICE,
dma_dir = DMA_MODE_WRITE;
else
pci_dir = PCI_DMA_FROMDEVICE,
map_dir = DMA_FROM_DEVICE,
dma_dir = DMA_MODE_READ;
pci_map_sg(NULL, info->sg, bufs + 1, pci_dir);
dma_map_sg(dev, info->sg, bufs + 1, map_dir);
disable_dma(dmach);
set_dma_sg(dmach, info->sg, bufs + 1);
......
......@@ -168,6 +168,19 @@ config 977_WATCHDOG
Not sure? It's safe to say N.
config SA1100_WATCHDOG
tristate "SA1100 watchdog"
depends on WATCHDOG && ARCH_SA1100
help
Watchdog timer embedded into SA11x0 chips. This will reboot your
system when timeout is reached.
NOTE, that once enabled, this timer cannot be disabled.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
If you want to compile it as a module, say M here and read
Documentation/modules.txt. The module will be called sa1100_wdt.o.
config EUROTECH_WDT
tristate "Eurotech CPU-1220/1410 Watchdog Timer"
depends on WATCHDOG
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_I810_TCO) += i810-tco.o
obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SH_WDT) += shwdt.o
obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
......
/*
* Watchdog driver for the SA11x0
*
* (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
* Based on SoftDog driver by Alan Cox <alan@redhat.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Neither Oleg Drokin nor iXcelerator.com admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
*
* (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
*
* 27/11/2000 Initial release
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <asm/hardware.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#define OSCR_FREQ 3686400
#define SA1100_CLOSE_MAGIC (0x5afc4453)
static unsigned long sa1100wdt_users;
static int expect_close;
static int pre_margin;
static int boot_status;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static int nowayout = 1;
#else
static int nowayout = 0;
#endif
/*
* Allow only one person to hold it open
*/
static int sa1100dog_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(1,&sa1100wdt_users))
return -EBUSY;
/* Activate SA1100 Watchdog timer */
OSMR3 = OSCR + pre_margin;
OSSR = OSSR_M3;
OWER = OWER_WME;
OIER |= OIER_E3;
return 0;
}
/*
* Shut off the timer.
* Lock it in if it's a module and we defined ...NOWAYOUT
* Oddly, the watchdog can only be enabled, but we can turn off
* the interrupt, which appears to prevent the watchdog timing out.
*/
static int sa1100dog_release(struct inode *inode, struct file *file)
{
OSMR3 = OSCR + pre_margin;
if (expect_close == SA1100_CLOSE_MAGIC) {
OIER &= ~OIER_E3;
} else {
printk(KERN_CRIT "WATCHDOG: WDT device closed unexpectedly. WDT will not stop!\n");
}
clear_bit(1, &sa1100wdt_users);
return 0;
}
static ssize_t sa1100dog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
{
/* Can't seek (pwrite) on this device */
if (ppos != &file->f_pos)
return -ESPIPE;
if (len) {
if (!nowayout) {
size_t i;
expect_close = 0;
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_close = SA1100_CLOSE_MAGIC;
}
}
/* Refresh OSMR3 timer. */
OSMR3 = OSCR + pre_margin;
}
return len ? 1 : 0;
}
static struct watchdog_info ident = {
.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "SA1100 Watchdog",
};
static int sa1100dog_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int ret = -ENOIOCTLCMD;
int time;
switch (cmd) {
case WDIOC_GETSUPPORT:
ret = copy_to_user((struct watchdog_info *)arg, &ident,
sizeof(ident)) ? -EFAULT : 0;
break;
case WDIOC_GETSTATUS:
ret = put_user(0, (int *)arg);
break;
case WDIOC_GETBOOTSTATUS:
ret = put_user(boot_status, (int *)arg);
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, (int *)arg);
if (ret)
break;
if (time <= 0 || time > 255) {
ret = -EINVAL;
break;
}
pre_margin = OSCR_FREQ * time;
OSMR3 = OSCR + pre_margin;
/*fall through*/
case WDIOC_GETTIMEOUT:
ret = put_user(pre_margin / OSCR_FREQ, (int *)arg);
break;
case WDIOC_KEEPALIVE:
OSMR3 = OSCR + pre_margin;
ret = 0;
break;
}
return ret;
}
static struct file_operations sa1100dog_fops =
{
.owner = THIS_MODULE,
.write = sa1100dog_write,
.ioctl = sa1100dog_ioctl,
.open = sa1100dog_open,
.release = sa1100dog_release,
};
static struct miscdevice sa1100dog_miscdev =
{
.minor = WATCHDOG_MINOR,
.name = "SA1100 watchdog",
.fops = &sa1100dog_fops,
};
static int margin __initdata = 60; /* (secs) Default is 1 minute */
static int __init sa1100dog_init(void)
{
int ret;
/*
* Read the reset status, and save it for later. If
* we suspend, RCSR will be cleared, and the watchdog
* reset reason will be lost.
*/
boot_status = (RCSR & RCSR_WDR) ? WDIOF_CARDRESET : 0;
pre_margin = OSCR_FREQ * margin;
ret = misc_register(&sa1100dog_miscdev);
if (ret == 0)
printk("SA1100 Watchdog Timer: timer margin %d sec\n",
margin);
return ret;
}
static void __exit sa1100dog_exit(void)
{
misc_deregister(&sa1100dog_miscdev);
}
module_init(sa1100dog_init);
module_exit(sa1100dog_exit);
MODULE_AUTHOR("Oleg Drokin <green@crimea.edu>");
MODULE_DESCRIPTION("SA1100 Watchdog");
MODULE_PARM(margin,"i");
MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
MODULE_PARM(nowayout, "i");
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
MODULE_LICENSE("GPL");
......@@ -89,6 +89,7 @@ config SERIO_PARKBD
config SERIO_RPCKBD
tristate "Acorn RiscPC keyboard controller"
depends on ARCH_ACORN && SERIO
default y
help
Say Y here if you have the Acorn RiscPC and want to use an AT
keyboard connected to its keyboard controller.
......
......@@ -74,15 +74,15 @@ static void sa1100_copy_to(struct map_info *map, unsigned long to, const void *f
}
static struct map_info sa1100_map __initdata = {
name: "SA1100 flash",
read8: sa1100_read8,
read16: sa1100_read16,
read32: sa1100_read32,
copy_from: sa1100_copy_from,
write8: sa1100_write8,
write16: sa1100_write16,
write32: sa1100_write32,
copy_to: sa1100_copy_to,
.name = "SA1100 flash",
.read8 = sa1100_read8,
.read16 = sa1100_read16,
.read32 = sa1100_read32,
.copy_from = sa1100_copy_from,
.write8 = sa1100_write8,
.write16 = sa1100_write16,
.write32 = sa1100_write32,
.copy_to = sa1100_copy_to,
};
......@@ -108,24 +108,24 @@ static struct map_info sa1100_map __initdata = {
#ifdef CONFIG_SA1100_ADSBITSY
static struct mtd_partition adsbitsy_partitions[] = {
{
name: "bootROM",
size: 0x80000,
offset: 0,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "bootROM",
.size = 0x80000,
.offset = 0,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
name: "zImage",
size: 0x100000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "zImage",
.size = 0x100000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
name: "ramdisk.gz",
size: 0x300000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "ramdisk.gz",
.size = 0x300000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
name: "User FS",
size: MTDPART_SIZ_FULL,
offset: MTDPART_OFS_APPEND,
.name = "User FS",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
#endif
......@@ -134,38 +134,38 @@ static struct mtd_partition adsbitsy_partitions[] = {
/* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
static struct mtd_partition assabet4_partitions[] = {
{
name: "bootloader",
size: 0x00020000,
offset: 0,
mask_flags: MTD_WRITEABLE,
.name = "bootloader",
.size = 0x00020000,
.offset = 0,
.mask_flags = MTD_WRITEABLE,
}, {
name: "bootloader params",
size: 0x00020000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE,
.name = "bootloader params",
.size = 0x00020000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE,
}, {
name: "jffs",
size: MTDPART_SIZ_FULL,
offset: MTDPART_OFS_APPEND,
.name = "jffs",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
/* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */
static struct mtd_partition assabet5_partitions[] = {
{
name: "bootloader",
size: 0x00040000,
offset: 0,
mask_flags: MTD_WRITEABLE,
.name = "bootloader",
.size = 0x00040000,
.offset = 0,
.mask_flags = MTD_WRITEABLE,
}, {
name: "bootloader params",
size: 0x00040000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE,
.name = "bootloader params",
.size = 0x00040000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE,
}, {
name: "jffs",
size: MTDPART_SIZ_FULL,
offset: MTDPART_OFS_APPEND,
.name = "jffs",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
......@@ -180,21 +180,21 @@ static struct mtd_partition assabet5_partitions[] = {
*/
static struct mtd_partition badge4_partitions[] = {
{
name: "BLOB boot loader",
offset: 0,
size: 0x0000A000
.name = "BLOB boot loader",
.offset = 0,
.size = 0x0000A000
}, {
name: "params",
offset: MTDPART_OFS_APPEND,
size: 0x00006000
.name = "params",
.offset = MTDPART_OFS_APPEND,
.size = 0x00006000
}, {
name: "kernel",
offset: MTDPART_OFS_APPEND,
size: 0x00100000
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = 0x00100000
}, {
name: "root",
offset: MTDPART_OFS_APPEND,
size: MTDPART_SIZ_FULL
.name = "root",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL
}
};
#endif
......@@ -204,41 +204,41 @@ static struct mtd_partition badge4_partitions[] = {
#ifdef CONFIG_SA1100_CERF_FLASH_32MB
static struct mtd_partition cerf_partitions[] = {
{
name: "firmware",
size: 0x00040000,
offset: 0,
.name = "firmware",
.size = 0x00040000,
.offset = 0,
}, {
name: "params",
size: 0x00040000,
offset: 0x00040000,
.name = "params",
.size = 0x00040000,
.offset = 0x00040000,
}, {
name: "kernel",
size: 0x00100000,
offset: 0x00080000,
.name = "kernel",
.size = 0x00100000,
.offset = 0x00080000,
}, {
name: "rootdisk",
size: 0x01E80000,
offset: 0x00180000,
.name = "rootdisk",
.size = 0x01E80000,
.offset = 0x00180000,
}
};
#elif defined CONFIG_SA1100_CERF_FLASH_16MB
static struct mtd_partition cerf_partitions[] = {
{
name: "firmware",
size: 0x00020000,
offset: 0,
.name = "firmware",
.size = 0x00020000,
.offset = 0,
}, {
name: "params",
size: 0x00020000,
offset: 0x00020000,
.name = "params",
.size = 0x00020000,
.offset = 0x00020000,
}, {
name: "kernel",
size: 0x00100000,
offset: 0x00040000,
.name = "kernel",
.size = 0x00100000,
.offset = 0x00040000,
}, {
name: "rootdisk",
size: 0x00EC0000,
offset: 0x00140000,
.name = "rootdisk",
.size = 0x00EC0000,
.offset = 0x00140000,
}
};
#elif defined CONFIG_SA1100_CERF_FLASH_8MB
......@@ -251,36 +251,36 @@ static struct mtd_partition cerf_partitions[] = {
#ifdef CONFIG_SA1100_CONSUS
static struct mtd_partition consus_partitions[] = {
{
name: "Consus boot firmware",
offset: 0,
size: 0x00040000,
mask_flags: MTD_WRITABLE, /* force read-only */
}, {
name: "Consus kernel",
offset: 0x00040000,
size: 0x00100000,
mask_flags: 0,
}, {
name: "Consus disk",
offset: 0x00140000,
.name = "Consus boot firmware",
.offset = 0,
.size = 0x00040000,
.mask_flags = MTD_WRITABLE, /* force read-only */
}, {
.name = "Consus kernel",
.offset = 0x00040000,
.size = 0x00100000,
.mask_flags = 0,
}, {
.name = "Consus disk",
.offset = 0x00140000,
/* The rest (up to 16M) for jffs. We could put 0 and
make it find the size automatically, but right now
i have 32 megs. jffs will use all 32 megs if given
the chance, and this leads to horrible problems
when you try to re-flash the image because blob
won't erase the whole partition. */
size: 0x01000000 - 0x00140000,
mask_flags: 0,
.size = 0x01000000 - 0x00140000,
.mask_flags = 0,
}, {
/* this disk is a secondary disk, which can be used as
needed, for simplicity, make it the size of the other
consus partition, although realistically it could be
the remainder of the disk (depending on the file
system used) */
name: "Consus disk2",
offset: 0x01000000,
size: 0x01000000 - 0x00140000,
mask_flags: 0,
.name = "Consus disk2",
.offset = 0x01000000,
.size = 0x01000000 - 0x00140000,
.mask_flags = 0,
}
};
#endif
......@@ -290,45 +290,45 @@ static struct mtd_partition consus_partitions[] = {
#define FLEXANET_FLASH_SIZE 0x02000000
static struct mtd_partition flexanet_partitions[] = {
{
name: "bootloader",
size: 0x00040000,
offset: 0,
mask_flags: MTD_WRITEABLE,
}, {
name: "bootloader params",
size: 0x00040000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE,
}, {
name: "kernel",
size: 0x000C0000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE,
}, {
name: "altkernel",
size: 0x000C0000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE,
}, {
name: "root",
size: 0x00400000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE,
}, {
name: "free1",
size: 0x00300000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE,
}, {
name: "free2",
size: 0x00300000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE,
}, {
name: "free3",
size: MTDPART_SIZ_FULL,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE,
.name = "bootloader",
.size = 0x00040000,
.offset = 0,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "bootloader params",
.size = 0x00040000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "kernel",
.size = 0x000C0000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "altkernel",
.size = 0x000C0000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "root",
.size = 0x00400000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "free1",
.size = 0x00300000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "free2",
.size = 0x00300000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE,
}, {
.name = "free3",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE,
}
};
#endif
......@@ -337,48 +337,48 @@ static struct mtd_partition flexanet_partitions[] = {
static struct mtd_partition freebird_partitions[] = {
#if CONFIG_SA1100_FREEBIRD_NEW
{
name: "firmware",
size: 0x00040000,
offset: 0,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "firmware",
.size = 0x00040000,
.offset = 0,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
name: "kernel",
size: 0x00080000,
offset: 0x00040000,
.name = "kernel",
.size = 0x00080000,
.offset = 0x00040000,
}, {
name: "params",
size: 0x00040000,
offset: 0x000C0000,
.name = "params",
.size = 0x00040000,
.offset = 0x000C0000,
}, {
name: "initrd",
size: 0x00100000,
offset: 0x00100000,
.name = "initrd",
.size = 0x00100000,
.offset = 0x00100000,
}, {
name: "root cramfs",
size: 0x00300000,
offset: 0x00200000,
.name = "root cramfs",
.size = 0x00300000,
.offset = 0x00200000,
}, {
name: "usr cramfs",
size: 0x00C00000,
offset: 0x00500000,
.name = "usr cramfs",
.size = 0x00C00000,
.offset = 0x00500000,
}, {
name: "local",
size: MTDPART_SIZ_FULL,
offset: 0x01100000,
.name = "local",
.size = MTDPART_SIZ_FULL,
.offset = 0x01100000,
}
#else
{
size: 0x00040000,
offset: 0,
.size = 0x00040000,
.offset = 0,
}, {
size: 0x000c0000,
offset: MTDPART_OFS_APPEND,
.size = 0x000c0000,
.offset = MTDPART_OFS_APPEND,
}, {
size: 0x00400000,
offset: MTDPART_OFS_APPEND,
.size = 0x00400000,
.offset = MTDPART_OFS_APPEND,
}, {
size: MTDPART_SIZ_FULL,
offset: MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
#endif
};
......@@ -389,29 +389,29 @@ static struct mtd_partition freebird_partitions[] = {
static struct mtd_partition frodo_partitions[] =
{
{
name: "bootloader",
size: 0x00040000,
offset: 0x00000000,
mask_flags: MTD_WRITEABLE
}, {
name: "bootloader params",
size: 0x00040000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE
}, {
name: "kernel",
size: 0x00100000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE
}, {
name: "ramdisk",
size: 0x00400000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE
}, {
name: "file system",
size: MTDPART_SIZ_FULL,
offset: MTDPART_OFS_APPEND
.name = "bootloader",
.size = 0x00040000,
.offset = 0x00000000,
.mask_flags = MTD_WRITEABLE
}, {
.name = "bootloader params",
.size = 0x00040000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE
}, {
.name = "kernel",
.size = 0x00100000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE
}, {
.name = "ramdisk",
.size = 0x00400000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE
}, {
.name = "file system",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND
}
};
#endif
......@@ -419,19 +419,19 @@ static struct mtd_partition frodo_partitions[] =
#ifdef CONFIG_SA1100_GRAPHICSCLIENT
static struct mtd_partition graphicsclient_partitions[] = {
{
name: "zImage",
size: 0x100000,
offset: 0,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "zImage",
.size = 0x100000,
.offset = 0,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
name: "ramdisk.gz",
size: 0x300000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "ramdisk.gz",
.size = 0x300000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
name: "User FS",
size: MTDPART_SIZ_FULL,
offset: MTDPART_OFS_APPEND,
.name = "User FS",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
#endif
......@@ -439,21 +439,21 @@ static struct mtd_partition graphicsclient_partitions[] = {
#ifdef CONFIG_SA1100_GRAPHICSMASTER
static struct mtd_partition graphicsmaster_partitions[] = {
{
name: "zImage",
size: 0x100000,
offset: 0,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "zImage",
.size = 0x100000,
.offset = 0,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
{
name: "ramdisk.gz",
size: 0x300000,
offset: MTDPART_OFS_APPEND,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "ramdisk.gz",
.size = 0x300000,
.offset = MTDPART_OFS_APPEND,
.mask_flags = MTD_WRITEABLE, /* force read-only */
},
{
name: "User FS",
size: MTDPART_SIZ_FULL,
offset: MTDPART_OFS_APPEND,
.name = "User FS",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
#endif
......@@ -461,44 +461,44 @@ static struct mtd_partition graphicsmaster_partitions[] = {
#ifdef CONFIG_SA1100_H3XXX
static struct mtd_partition h3xxx_partitions[] = {
{
name: "H3XXX boot firmware",
size: 0x00040000,
offset: 0,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "H3XXX boot firmware",
.size = 0x00040000,
.offset = 0,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
#ifdef CONFIG_MTD_2PARTS_IPAQ
name: "H3XXX root jffs2",
size: MTDPART_SIZ_FULL,
offset: 0x00040000,
.name = "H3XXX root jffs2",
.size = MTDPART_SIZ_FULL,
.offset = 0x00040000,
#else
name: "H3XXX kernel",
size: 0x00080000,
offset: 0x00040000,
.name = "H3XXX kernel",
.size = 0x00080000,
.offset = 0x00040000,
}, {
name: "H3XXX params",
size: 0x00040000,
offset: 0x000C0000,
.name = "H3XXX params",
.size = 0x00040000,
.offset = 0x000C0000,
}, {
#ifdef CONFIG_JFFS2_FS
name: "H3XXX root jffs2",
size: MTDPART_SIZ_FULL,
offset: 0x00100000,
.name = "H3XXX root jffs2",
.size = MTDPART_SIZ_FULL,
.offset = 0x00100000,
#else
name: "H3XXX initrd",
size: 0x00100000,
offset: 0x00100000,
.name = "H3XXX initrd",
.size = 0x00100000,
.offset = 0x00100000,
}, {
name: "H3XXX root cramfs",
size: 0x00300000,
offset: 0x00200000,
.name = "H3XXX root cramfs",
.size = 0x00300000,
.offset = 0x00200000,
}, {
name: "H3XXX usr cramfs",
size: 0x00800000,
offset: 0x00500000,
.name = "H3XXX usr cramfs",
.size = 0x00800000,
.offset = 0x00500000,
}, {
name: "H3XXX usr local",
size: MTDPART_SIZ_FULL,
offset: 0x00d00000,
.name = "H3XXX usr local",
.size = MTDPART_SIZ_FULL,
.offset = 0x00d00000,
#endif
#endif
}
......@@ -515,16 +515,16 @@ static void h3xxx_set_vpp(struct map_info *map, int vpp)
#ifdef CONFIG_SA1100_HUW_WEBPANEL
static struct mtd_partition huw_webpanel_partitions[] = {
{
name: "Loader",
size: 0x00040000,
offset: 0,
.name = "Loader",
.size = 0x00040000,
.offset = 0,
}, {
name: "Sector 1",
size: 0x00040000,
offset: MTDPART_OFS_APPEND,
.name = "Sector 1",
.size = 0x00040000,
.offset = MTDPART_OFS_APPEND,
}, {
size: MTDPART_SIZ_FULL,
offset: MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
#endif
......@@ -532,38 +532,38 @@ static struct mtd_partition huw_webpanel_partitions[] = {
#ifdef CONFIG_SA1100_JORNADA720
static struct mtd_partition jornada720_partitions[] = {
{
name: "JORNADA720 boot firmware",
size: 0x00040000,
offset: 0,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "JORNADA720 boot firmware",
.size = 0x00040000,
.offset = 0,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
name: "JORNADA720 kernel",
size: 0x000c0000,
offset: 0x00040000,
.name = "JORNADA720 kernel",
.size = 0x000c0000,
.offset = 0x00040000,
}, {
name: "JORNADA720 params",
size: 0x00040000,
offset: 0x00100000,
.name = "JORNADA720 params",
.size = 0x00040000,
.offset = 0x00100000,
}, {
name: "JORNADA720 initrd",
size: 0x00100000,
offset: 0x00140000,
.name = "JORNADA720 initrd",
.size = 0x00100000,
.offset = 0x00140000,
}, {
name: "JORNADA720 root cramfs",
size: 0x00300000,
offset: 0x00240000,
.name = "JORNADA720 root cramfs",
.size = 0x00300000,
.offset = 0x00240000,
}, {
name: "JORNADA720 usr cramfs",
size: 0x00800000,
offset: 0x00540000,
.name = "JORNADA720 usr cramfs",
.size = 0x00800000,
.offset = 0x00540000,
}, {
name: "JORNADA720 usr local",
size: 0 /* will expand to the end of the flash */
offset: 0x00d00000,
.name = "JORNADA720 usr local",
.size = 0, /* will expand to the end of the flash */
.offset = 0x00d00000,
}
};
static void jornada720_set_vpp(int vpp)
static void jornada720_set_vpp(struct map_info *map, int vpp)
{
if (vpp)
PPSR |= 0x80;
......@@ -578,22 +578,22 @@ static void jornada720_set_vpp(int vpp)
#ifdef CONFIG_SA1100_PANGOLIN
static struct mtd_partition pangolin_partitions[] = {
{
name: "boot firmware",
size: 0x00080000,
offset: 0x00000000,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "boot firmware",
.size = 0x00080000,
.offset = 0x00000000,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
name: "kernel",
size: 0x00100000,
offset: 0x00080000,
.name = "kernel",
.size = 0x00100000,
.offset = 0x00080000,
}, {
name: "initrd",
size: 0x00280000,
offset: 0x00180000,
.name = "initrd",
.size = 0x00280000,
.offset = 0x00180000,
}, {
name: "initrd-test",
size: 0x03C00000,
offset: 0x00400000,
.name = "initrd-test",
.size = 0x03C00000,
.offset = 0x00400000,
}
};
#endif
......@@ -602,22 +602,22 @@ static struct mtd_partition pangolin_partitions[] = {
/* erase size is 0x40000 == 256k partitions have to have this boundary */
static struct mtd_partition system3_partitions[] = {
{
name: "BLOB",
size: 0x00040000,
offset: 0x00000000,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "BLOB",
.size = 0x00040000,
.offset = 0x00000000,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
name: "config",
size: 0x00040000,
offset: MTDPART_OFS_APPEND,
.name = "config",
.size = 0x00040000,
.offset = MTDPART_OFS_APPEND,
}, {
name: "kernel",
size: 0x00100000,
offset: MTDPART_OFS_APPEND,
.name = "kernel",
.size = 0x00100000,
.offset = MTDPART_OFS_APPEND,
}, {
name: "root",
size: MTDPART_SIZ_FULL,
offset: MTDPART_OFS_APPEND,
.name = "root",
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
#endif
......@@ -625,19 +625,19 @@ static struct mtd_partition system3_partitions[] = {
#ifdef CONFIG_SA1100_SHANNON
static struct mtd_partition shannon_partitions[] = {
{
name: "BLOB boot loader",
offset: 0,
size: 0x20000
.name = "BLOB boot loader",
.offset = 0,
.size = 0x20000
},
{
name: "kernel",
offset: MTDPART_OFS_APPEND,
size: 0xe0000
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = 0xe0000
},
{
name: "initrd",
offset: MTDPART_OFS_APPEND,
size: MTDPART_SIZ_FULL
.name = "initrd",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL
}
};
......@@ -646,17 +646,17 @@ static struct mtd_partition shannon_partitions[] = {
#ifdef CONFIG_SA1100_SHERMAN
static struct mtd_partition sherman_partitions[] = {
{
size: 0x50000,
offset: 0,
.size = 0x50000,
.offset = 0,
}, {
size: 0x70000,
offset: MTDPART_OFS_APPEND,
.size = 0x70000,
.offset = MTDPART_OFS_APPEND,
}, {
size: 0x600000,
offset: MTDPART_OFS_APPEND,
.size = 0x600000,
.offset = MTDPART_OFS_APPEND,
}, {
size: 0xA0000,
offset: MTDPART_OFS_APPEND,
.size = 0xA0000,
.offset = MTDPART_OFS_APPEND,
}
};
#endif
......@@ -664,35 +664,35 @@ static struct mtd_partition sherman_partitions[] = {
#ifdef CONFIG_SA1100_SIMPAD
static struct mtd_partition simpad_partitions[] = {
{
name: "SIMpad boot firmware",
size: 0x00080000,
offset: 0,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "SIMpad boot firmware",
.size = 0x00080000,
.offset = 0,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
name: "SIMpad kernel",
size: 0x00100000,
offset: 0x00080000,
.name = "SIMpad kernel",
.size = 0x00100000,
.offset = 0x00080000,
}, {
#ifdef CONFIG_JFFS2_FS
name: "SIMpad root jffs2",
size: MTDPART_SIZ_FULL,
offset: 0x00180000,
.name = "SIMpad root jffs2",
.size = MTDPART_SIZ_FULL,
.offset = 0x00180000,
#else
name: "SIMpad initrd",
size: 0x00300000,
offset: 0x00180000,
.name = "SIMpad initrd",
.size = 0x00300000,
.offset = 0x00180000,
}, {
name: "SIMpad root cramfs",
size: 0x00300000,
offset: 0x00480000,
.name = "SIMpad root cramfs",
.size = 0x00300000,
.offset = 0x00480000,
}, {
name: "SIMpad usr cramfs",
size: 0x005c0000,
offset: 0x00780000,
.name = "SIMpad usr cramfs",
.size = 0x005c0000,
.offset = 0x00780000,
}, {
name: "SIMpad usr local",
size: MTDPART_SIZ_FULL,
offset: 0x00d40000,
.name = "SIMpad usr local",
.size = MTDPART_SIZ_FULL,
.offset = 0x00d40000,
#endif
}
};
......@@ -701,39 +701,39 @@ static struct mtd_partition simpad_partitions[] = {
#ifdef CONFIG_SA1100_STORK
static struct mtd_partition stork_partitions[] = {
{
name: "STORK boot firmware",
size: 0x00040000,
offset: 0,
mask_flags: MTD_WRITEABLE, /* force read-only */
.name = "STORK boot firmware",
.size = 0x00040000,
.offset = 0,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
name: "STORK params",
size: 0x00040000,
offset: 0x00040000,
.name = "STORK params",
.size = 0x00040000,
.offset = 0x00040000,
}, {
name: "STORK kernel",
size: 0x00100000,
offset: 0x00080000,
.name = "STORK kernel",
.size = 0x00100000,
.offset = 0x00080000,
}, {
#ifdef CONFIG_JFFS2_FS
name: "STORK root jffs2",
offset: 0x00180000,
size: MTDPART_SIZ_FULL,
.name = "STORK root jffs2",
.offset = 0x00180000,
.size = MTDPART_SIZ_FULL,
#else
name: "STORK initrd",
size: 0x00100000,
offset: 0x00180000,
.name = "STORK initrd",
.size = 0x00100000,
.offset = 0x00180000,
}, {
name: "STORK root cramfs",
size: 0x00300000,
offset: 0x00280000,
.name = "STORK root cramfs",
.size = 0x00300000,
.offset = 0x00280000,
}, {
name: "STORK usr cramfs",
size: 0x00800000,
offset: 0x00580000,
.name = "STORK usr cramfs",
.size = 0x00800000,
.offset = 0x00580000,
}, {
name: "STORK usr local",
offset: 0x00d80000,
size: MTDPART_SIZ_FULL,
.name = "STORK usr local",
.offset = 0x00d80000,
.size = MTDPART_SIZ_FULL,
#endif
}
};
......@@ -742,16 +742,16 @@ static struct mtd_partition stork_partitions[] = {
#ifdef CONFIG_SA1100_TRIZEPS
static struct mtd_partition trizeps_partitions[] = {
{
name: "Bootloader & the kernel",
size: 0x00200000,
offset: 0,
.name = "Bootloader & the kernel",
.size = 0x00200000,
.offset = 0,
}, {
name: "Data",
size: 0x00400000,
offset: MTDPART_OFS_APPEND,
.name = "Data",
.size = 0x00400000,
.offset = MTDPART_OFS_APPEND,
}, {
size: MTDPART_SIZ_FULL,
offset: MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
.offset = MTDPART_OFS_APPEND,
}
};
#endif
......@@ -759,22 +759,22 @@ static struct mtd_partition trizeps_partitions[] = {
#ifdef CONFIG_SA1100_YOPY
static struct mtd_partition yopy_partitions[] = {
{
name: "boot firmware",
size: 0x00040000,
offset: 0x00000000,
mask_flags: MTD_WRITEABLE, /* force read-only */
}, {
name: "kernel",
size: 0x00080000,
offset: 0x00080000,
}, {
name: "initrd",
size: 0x00300000,
offset: 0x00100000,
}, {
name: "root",
size: 0x01000000,
offset: 0x00400000,
.name = "boot firmware",
.size = 0x00040000,
.offset = 0x00000000,
.mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
.name = "kernel",
.size = 0x00080000,
.offset = 0x00080000,
}, {
.name = "initrd",
.size = 0x00300000,
.offset = 0x00100000,
}, {
.name = "root",
.size = 0x01000000,
.offset = 0x00400000,
}
};
#endif
......
......@@ -10,8 +10,7 @@
* Infra-red driver for the StrongARM SA1100 embedded microprocessor
*
* Note that we don't have to worry about the SA1111's DMA bugs in here,
* so we use the straight forward pci_map_* functions with a null pointer.
* IMHO we should really be using our own machine specific set.
* so we use the straight forward dma_map_* functions with a null pointer.
*
* This driver takes one kernel command line parameter, sa1100ir=, with
* the following options:
......@@ -29,8 +28,8 @@
#include <linux/rtnetlink.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <net/irda/irda.h>
#include <net/irda/wrapper.h>
......@@ -57,11 +56,6 @@ static int power_level = 3;
static int tx_lpm;
static int max_rate = 4000000;
/*
* Our netdevice. There is only ever one of these.
*/
static struct net_device *netdev;
struct sa1100_irda {
unsigned char hscr0;
unsigned char utcr4;
......@@ -79,8 +73,8 @@ struct sa1100_irda {
dma_regs_t *rxdma;
struct net_device_stats stats;
struct device *dev;
struct irlap_cb *irlap;
struct pm_dev *pmdev;
struct qos_info qos;
iobuff_t tx_buff;
......@@ -112,9 +106,9 @@ static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
*/
skb_reserve(si->rxskb, 1);
si->rxbuf_dma = pci_map_single(NULL, si->rxskb->data,
si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
HPSIR_MAX_RXLEN,
PCI_DMA_FROMDEVICE);
DMA_FROM_DEVICE);
return 0;
}
......@@ -361,11 +355,12 @@ static void sa1100_irda_shutdown(struct sa1100_irda *si)
/*
* Suspend the IrDA interface.
*/
static int sa1100_irda_suspend(struct net_device *dev, int state)
static int sa1100_irda_suspend(struct device *_dev, u32 state, u32 level)
{
struct net_device *dev = dev_get_drvdata(_dev);
struct sa1100_irda *si = dev->priv;
if (si && si->open) {
if (si && si->open && level == SUSPEND_DISABLE) {
/*
* Stop the transmit queue
*/
......@@ -381,11 +376,12 @@ static int sa1100_irda_suspend(struct net_device *dev, int state)
/*
* Resume the IrDA interface.
*/
static int sa1100_irda_resume(struct net_device *dev)
static int sa1100_irda_resume(struct device *_dev, u32 level)
{
struct net_device *dev = dev_get_drvdata(_dev);
struct sa1100_irda *si = dev->priv;
if (si && si->open) {
if (si && si->open && level == RESUME_ENABLE) {
/*
* If we missed a speed change, initialise at the new speed
* directly. It is debatable whether this is actually
......@@ -410,31 +406,9 @@ static int sa1100_irda_resume(struct net_device *dev)
return 0;
}
static int sa1100_irda_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
{
int ret;
if (!dev->data)
return -EINVAL;
switch (rqst) {
case PM_SUSPEND:
ret = sa1100_irda_suspend((struct net_device *)dev->data,
(int)data);
break;
case PM_RESUME:
ret = sa1100_irda_resume((struct net_device *)dev->data);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
#else
#define sa1100_irda_suspend NULL
#define sa1100_irda_resume NULL
#endif
/*
......@@ -555,7 +529,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
len = dma_addr - si->rxbuf_dma;
if (len > HPSIR_MAX_RXLEN)
len = HPSIR_MAX_RXLEN;
pci_unmap_single(NULL, si->rxbuf_dma, len, PCI_DMA_FROMDEVICE);
dma_unmap_single(si->dev, si->rxbuf_dma, len, DMA_FROM_DEVICE);
do {
/*
......@@ -603,9 +577,9 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev
/*
* Remap the buffer.
*/
si->rxbuf_dma = pci_map_single(NULL, si->rxskb->data,
si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
HPSIR_MAX_RXLEN,
PCI_DMA_FROMDEVICE);
DMA_FROM_DEVICE);
}
}
......@@ -716,7 +690,7 @@ static void sa1100_irda_txdma_irq(void *id)
* Account and free the packet.
*/
if (skb) {
pci_unmap_single(NULL, si->txbuf_dma, skb->len, PCI_DMA_TODEVICE);
dma_unmap_single(si->dev, si->txbuf_dma, skb->len, DMA_TO_DEVICE);
si->stats.tx_packets ++;
si->stats.tx_bytes += skb->len;
dev_kfree_skb_irq(skb);
......@@ -782,8 +756,8 @@ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
si->txskb = skb;
si->txbuf_dma = pci_map_single(NULL, skb->data,
skb->len, PCI_DMA_TODEVICE);
si->txbuf_dma = dma_map_single(si->dev, skb->data,
skb->len, DMA_TO_DEVICE);
sa1100_start_dma(si->txdma, si->txbuf_dma, skb->len);
......@@ -931,8 +905,8 @@ static int sa1100_irda_stop(struct net_device *dev)
* tidy that up cleanly.
*/
if (si->rxskb) {
pci_unmap_single(NULL, si->rxbuf_dma, HPSIR_MAX_RXLEN,
PCI_DMA_FROMDEVICE);
dma_unmap_single(si->dev, si->rxbuf_dma, HPSIR_MAX_RXLEN,
DMA_FROM_DEVICE);
dev_kfree_skb(si->rxskb);
si->rxskb = NULL;
}
......@@ -972,6 +946,24 @@ static int sa1100_irda_init_iobuf(iobuff_t *io, int size)
return io->head ? 0 : -ENOMEM;
}
static struct device_driver sa1100ir_driver = {
.name = "sa1100ir",
.bus = &system_bus_type,
.suspend = sa1100_irda_suspend,
.resume = sa1100_irda_resume,
};
static struct sys_device sa1100ir_device = {
.name = "sa1100ir",
.id = 0,
.root = NULL,
.dev = {
.name = "Intel Corporation SA11x0 [IrDA]",
.bus_id = "0",
.driver = &sa1100ir_driver,
},
};
static int sa1100_irda_net_init(struct net_device *dev)
{
struct sa1100_irda *si = dev->priv;
......@@ -984,6 +976,8 @@ static int sa1100_irda_net_init(struct net_device *dev)
memset(si, 0, sizeof(*si));
si->dev = &sa1100ir_device.dev;
/*
* Initialise the HP-SIR buffers
*/
......@@ -1035,15 +1029,6 @@ static int sa1100_irda_net_init(struct net_device *dev)
Ser2UTCR4 = si->utcr4;
Ser2HSCR0 = HSCR0_UART;
#ifdef CONFIG_PM
/*
* Power-Management is optional.
*/
si->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, sa1100_irda_pmproc);
if (si->pmdev)
si->pmdev->data = dev;
#endif
return 0;
kfree(si->tx_buff.head);
......@@ -1071,15 +1056,12 @@ static void sa1100_irda_net_uninit(struct net_device *dev)
dev->get_stats = NULL;
dev->priv = NULL;
pm_unregister(si->pmdev);
kfree(si->tx_buff.head);
kfree(si->rx_buff.head);
kfree(si);
}
static
int __init sa1100_irda_init(void)
static int __init sa1100_irda_init(void)
{
struct net_device *dev;
int err;
......@@ -1102,6 +1084,9 @@ int __init sa1100_irda_init(void)
if (err)
goto err_mem_3;
driver_register(&sa1100ir_driver);
sys_device_register(&sa1100ir_device);
rtnl_lock();
dev = dev_alloc("irda%d", &err);
if (dev) {
......@@ -1114,11 +1099,14 @@ int __init sa1100_irda_init(void)
if (err)
kfree(dev);
else
netdev = dev;
dev_set_drvdata(&sa1100ir_device.dev, dev);
}
rtnl_unlock();
if (err) {
sys_device_unregister(&sa1100ir_device);
driver_unregister(&sa1100ir_driver);
release_mem_region(__PREG(Ser2HSCR2), 0x04);
err_mem_3:
release_mem_region(__PREG(Ser2HSCR0), 0x1c);
......@@ -1131,15 +1119,17 @@ int __init sa1100_irda_init(void)
static void __exit sa1100_irda_exit(void)
{
struct net_device *dev = netdev;
struct net_device *dev = dev_get_drvdata(&sa1100ir_device.dev);
netdev = NULL;
if (dev) {
rtnl_lock();
unregister_netdevice(dev);
rtnl_unlock();
}
sys_device_unregister(&sa1100ir_device);
driver_unregister(&sa1100ir_driver);
release_mem_region(__PREG(Ser2HSCR2), 0x04);
release_mem_region(__PREG(Ser2HSCR0), 0x1c);
release_mem_region(__PREG(Ser2UTCR0), 0x24);
......
......@@ -185,7 +185,6 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
goto err1;
}
set_irq_type(hcd->irq, IRQT_RISING);
retval = request_irq (hcd->irq, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
hcd->description, hcd);
if (retval != 0) {
......@@ -399,7 +398,7 @@ static int ohci_hcd_sa1111_drv_resume(struct device *dev, u32 level)
static struct sa1111_driver ohci_hcd_sa1111_driver = {
.drv = {
.name = "SA1111 OHCI",
.name = "sa1111-ohci",
.bus = &sa1111_bus_type,
.probe = ohci_hcd_sa1111_drv_probe,
.remove = ohci_hcd_sa1111_drv_remove,
......
......@@ -170,10 +170,11 @@
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/cpufreq.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <asm/hardware.h>
#include <asm/io.h>
......@@ -183,12 +184,6 @@
#include <asm/arch/assabet.h>
#include <asm/arch/shannon.h>
#include <video/fbcon.h>
#include <video/fbcon-mfb.h>
#include <video/fbcon-cfb4.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb16.h>
/*
* debugging?
*/
......@@ -806,15 +801,9 @@ static inline u_int palette_pbs(struct fb_var_screeninfo *var)
{
int ret = 0;
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB4
case 4: ret = 0 << 12; break;
#endif
#ifdef FBCON_HAS_CFB8
case 8: ret = 1 << 12; break;
#endif
#ifdef FBCON_HAS_CFB16
case 16: ret = 2 << 12; break;
#endif
}
return ret;
}
......@@ -875,7 +864,7 @@ sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
* according to the RGB bitfield information.
*/
if (regno < 16) {
u16 *pal = fbi->fb.pseudo_palette;
u32 *pal = fbi->fb.pseudo_palette;
val = chan_to_field(red, &fbi->fb.var.red);
val |= chan_to_field(green, &fbi->fb.var.green);
......@@ -935,21 +924,15 @@ sa1100fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB4
case 4:
rgbidx = RGB_8;
break;
#endif
#ifdef FBCON_HAS_CFB8
case 8:
rgbidx = RGB_8;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 16:
rgbidx = RGB_16;
break;
#endif
default:
return -EINVAL;
}
......@@ -1023,6 +1006,8 @@ static int sa1100fb_set_par(struct fb_info *info)
fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
}
fbi->fb.fix.line_length = var->xres_virtual *
var->bits_per_pixel / 8;
fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
palette_mem_size = fbi->palette_size * sizeof(u16);
......@@ -1048,46 +1033,22 @@ static int sa1100fb_set_par(struct fb_info *info)
return 0;
}
/*
* sa1100fb_set_var():
* Set the user defined part of the display for the specified console
*/
static int
sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
int ret, act;
act = var->activate & FB_ACTIVATE_MASK;
ret = gen_set_var(var, con, info);
if (ret == 0 && act & FB_ACTIVATE_NOW) {
struct display *display = (con < 0) ? info->disp : fb_display + con;
/*
* fbcon assumes too much.
*/
display->can_soft_blank = 1;
}
return ret;
}
#if 0
static int
sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
struct display *disp = (con < 0) ? info->disp : (fb_display + con);
/*
* Make sure the user isn't doing something stupid.
*/
if (!kspc && (disp->var.bits_per_pixel == 16 || fbi->cmap_static))
if (!kspc && (fbi->fb.var.bits_per_pixel == 16 || fbi->cmap_static))
return -EINVAL;
return gen_set_cmap(cmap, kspc, con, info);
}
#endif
/*
* Formal definition of the VESA spec:
......@@ -1129,8 +1090,7 @@ static int sa1100fb_blank(int blank, struct fb_info *info)
struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
int i;
DPRINTK("sa1100fb_blank: blank=%d info->modename=%s\n", blank,
fbi->fb.modename);
DPRINTK("sa1100fb_blank: blank=%d\n", blank);
switch (blank) {
case VESA_POWERDOWN:
......@@ -1156,19 +1116,14 @@ static struct fb_ops sa1100fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = sa1100fb_check_var,
.fb_set_par = sa1100fb_set_par,
.fb_set_var = sa1100fb_set_var,
.fb_get_cmap = gen_get_cmap,
.fb_set_cmap = sa1100fb_set_cmap,
// .fb_set_cmap = sa1100fb_set_cmap,
.fb_setcolreg = sa1100fb_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_blank = sa1100fb_blank,
};
static int sa1100fb_updatevar(int con, struct fb_info *info)
{
/* we don't support panning nor scrolling */
return 0;
}
/*
* Calculate the PCD value from the clock rate (in picoseconds).
* We take account of the PPCR clock setting.
......@@ -1259,10 +1214,10 @@ static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_
(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2);
DPRINTK("nlccr3 = 0x%08x\n", new_regs.lccr3);
DPRINTK("nlccr0 = 0x%08lx\n", new_regs.lccr0);
DPRINTK("nlccr1 = 0x%08lx\n", new_regs.lccr1);
DPRINTK("nlccr2 = 0x%08lx\n", new_regs.lccr2);
DPRINTK("nlccr3 = 0x%08lx\n", new_regs.lccr3);
half_screen_size = var->bits_per_pixel;
half_screen_size = half_screen_size * var->xres * var->yres / 16;
......@@ -1382,8 +1337,8 @@ static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
GPSR |= SHANNON_GPIO_DISP_EN;
}
DPRINTK("DBAR1 = %p\n", DBAR1);
DPRINTK("DBAR2 = %p\n", DBAR2);
DPRINTK("DBAR1 = 0x%08x\n", DBAR1);
DPRINTK("DBAR2 = 0x%08x\n", DBAR2);
DPRINTK("LCCR0 = 0x%08x\n", LCCR0);
DPRINTK("LCCR1 = 0x%08x\n", LCCR1);
DPRINTK("LCCR2 = 0x%08x\n", LCCR2);
......@@ -1465,6 +1420,12 @@ static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
old_state = fbi->state;
/*
* Hack around fbcon initialisation.
*/
if (old_state == C_STARTUP && state == C_REENABLE)
state = C_ENABLE;
switch (state) {
case C_DISABLE_CLKCHANGE:
/*
......@@ -1563,6 +1524,7 @@ static void sa1100fb_task(void *dummy)
*/
static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
{
#if 0
unsigned int min_period = (unsigned int)-1;
int i;
......@@ -1585,6 +1547,12 @@ static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
}
return min_period;
#else
/*
* FIXME: we need to verify _all_ consoles.
*/
return sa1100fb_display_dma_period(&fbi->fb.var);
#endif
}
/*
......@@ -1633,30 +1601,29 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
#ifdef CONFIG_PM
/*
* Power management hook. Note that we won't be called from IRQ context,
* Power management hooks. Note that we won't be called from IRQ context,
* unlike the blank functions above, so we may sleep.
*/
static int
sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
static int sa1100fb_suspend(struct device *dev, u32 state, u32 level)
{
struct sa1100fb_info *fbi = pm_dev->data;
struct sa1100fb_info *fbi = dev_get_drvdata(dev);
DPRINTK("pm_callback: %d\n", req);
if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN)
set_ctrlr_state(fbi, C_DISABLE_PM);
return 0;
}
if (req == PM_SUSPEND || req == PM_RESUME) {
int state = (int)data;
static int sa1100fb_resume(struct device *dev, u32 level)
{
struct sa1100fb_info *fbi = dev_get_drvdata(dev);
if (state == 0) {
/* Enter D0. */
if (level == RESUME_ENABLE)
set_ctrlr_state(fbi, C_ENABLE_PM);
} else {
/* Enter D1-D3. Disable the LCD controller. */
set_ctrlr_state(fbi, C_DISABLE_PM);
}
}
DPRINTK("done\n");
return 0;
}
#else
#define sa1100fb_suspend NULL
#define sa1100fb_resume NULL
#endif
/*
......@@ -1675,7 +1642,7 @@ static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
*/
fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
&fbi->map_dma);
&fbi->map_dma, PTE_BUFFERABLE);
if (fbi->map_cpu) {
fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
......@@ -1697,12 +1664,12 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
struct sa1100fb_mach_info *inf;
struct sa1100fb_info *fbi;
fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(struct display) +
sizeof(u16) * 16, GFP_KERNEL);
fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(u32) * 16,
GFP_KERNEL);
if (!fbi)
return NULL;
memset(fbi, 0, sizeof(struct sa1100fb_info) + sizeof(struct display));
memset(fbi, 0, sizeof(struct sa1100fb_info));
strcpy(fbi->fb.fix.id, SA1100_NAME);
......@@ -1711,7 +1678,6 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
fbi->fb.fix.xpanstep = 0;
fbi->fb.fix.ypanstep = 0;
fbi->fb.fix.ywrapstep = 0;
fbi->fb.fix.line_length = 0;
fbi->fb.fix.accel = FB_ACCEL_NONE;
fbi->fb.var.nonstd = 0;
......@@ -1721,19 +1687,12 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
fbi->fb.var.accel_flags = 0;
fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
strcpy(fbi->fb.modename, SA1100_NAME);
strcpy(fbi->fb.fontname, "Acorn8x8");
fbi->fb.fbops = &sa1100fb_ops;
fbi->fb.changevar = NULL;
fbi->fb.switch_con = gen_switch;
fbi->fb.updatevar = sa1100fb_updatevar;
fbi->fb.flags = FBINFO_FLAG_DEFAULT;
fbi->fb.node = NODEV;
fbi->fb.monspecs = monspecs;
fbi->fb.currcon = -1;
fbi->fb.disp = (struct display *)(fbi + 1);
fbi->fb.pseudo_palette = (void *)(fbi->fb.disp + 1);
fbi->fb.pseudo_palette = (fbi + 1);
fbi->rgb[RGB_8] = &rgb_8;
fbi->rgb[RGB_16] = &def_rgb_16;
......@@ -1771,11 +1730,10 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
fbi->cmap_static = inf->cmap_static;
fbi->lccr0 = inf->lccr0;
fbi->lccr3 = inf->lccr3;
fbi->state = C_DISABLE;
fbi->state = C_STARTUP;
fbi->task_state = (u_char)-1;
fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
fbi->max_bpp / 8;
fbi->fb.disp->inverse = inf->cmap_inverse;
init_waitqueue_head(&fbi->ctrlr_wait);
INIT_WORK(&fbi->task, sa1100fb_task, fbi);
......@@ -1784,6 +1742,24 @@ static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
return fbi;
}
static struct device_driver sa1100fb_driver = {
.name = "sa1100fb",
.bus = &system_bus_type,
.suspend = sa1100fb_suspend,
.resume = sa1100fb_resume,
};
static struct sys_device sa1100fb_dev = {
.name = "LCD",
.id = 0,
.root = NULL,
.dev = {
.name = "Intel Corporation SA11x0 [LCD]",
.bus_id = "b0100000",
.driver = &sa1100fb_driver,
},
};
int __init sa1100fb_init(void)
{
struct sa1100fb_info *fbi;
......@@ -1792,11 +1768,16 @@ int __init sa1100fb_init(void)
if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
return -EBUSY;
driver_register(&sa1100fb_driver);
sys_device_register(&sa1100fb_dev);
fbi = sa1100fb_init_fbinfo();
ret = -ENOMEM;
if (!fbi)
goto failed;
dev_set_drvdata(&sa1100fb_dev.dev, fbi);
/* Initialize video memory */
ret = sa1100fb_map_video_memory(fbi);
if (ret)
......@@ -1824,21 +1805,16 @@ int __init sa1100fb_init(void)
}
#endif
sa1100fb_set_var(&fbi->fb.var, -1, &fbi->fb);
/*
* This makes sure that our colour bitfield
* descriptors are correctly initialised.
*/
sa1100fb_check_var(&fbi->fb.var, &fbi->fb);
ret = register_framebuffer(&fbi->fb);
if (ret < 0)
goto failed;
#ifdef CONFIG_PM
/*
* Note that the console registers this as well, but we want to
* power down the display prior to sleeping.
*/
fbi->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, sa1100fb_pm_callback);
if (fbi->pm)
fbi->pm->data = fbi;
#endif
#ifdef CONFIG_CPU_FREQ
fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
fbi->freq_policy.notifier_call = sa1100fb_freq_policy;
......@@ -1846,17 +1822,14 @@ int __init sa1100fb_init(void)
cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
#endif
/*
* Ok, now enable the LCD controller
*/
set_ctrlr_state(fbi, C_ENABLE);
/* This driver cannot be unloaded at the moment */
MOD_INC_USE_COUNT;
return 0;
failed:
sys_device_unregister(&sa1100fb_dev);
driver_unregister(&sa1100fb_driver);
if (fbi)
kfree(fbi);
release_mem_region(0xb0100000, 0x10000);
......
......@@ -14,7 +14,7 @@
* devices. This is the "generic" version. The PCI specific version
* is in pci.h
*/
extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, unsigned long flags);
extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle);
extern void consistent_sync(void *kaddr, size_t size, int rw);
......@@ -84,12 +84,12 @@ static inline int dma_is_consistent(dma_addr_t handle)
static inline void *
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle)
{
int gfp = GFP_KERNEL;
int gfp = GFP_ATOMIC;
if (dev == NULL || dmadev_is_sa1111(dev) || *dev->dma_mask != 0xffffffff)
gfp |= GFP_DMA;
return consistent_alloc(gfp, size, handle);
return consistent_alloc(gfp, size, handle, 0);
}
/**
......
......@@ -160,6 +160,7 @@ struct expansion_card {
const char *card_desc; /* Card description */
CONST unsigned int podaddr; /* Base Linux address for card */
CONST loader_t loader; /* loader program */
u64 dma_mask;
};
struct in_chunk_dir {
......
......@@ -40,13 +40,13 @@ static inline void pcibios_penalize_isa_irq(int irq)
static inline void *
pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *handle)
{
int gfp = GFP_KERNEL;
int gfp = GFP_ATOMIC;
if (hwdev == NULL || pcidev_is_sa1111(hwdev) ||
hwdev->dma_mask != 0xffffffff)
gfp |= GFP_DMA;
return consistent_alloc(gfp, size, handle);
return consistent_alloc(gfp, size, handle, 0);
}
static inline void
......
......@@ -12,7 +12,7 @@
* Note that this is actually 0x1,0000,0000
*/
#define KERNEL_DS 0x00000000
#define USER_DS PAGE_OFFSET
#define USER_DS TASK_SIZE
static inline void set_fs (mm_segment_t fs)
{
......@@ -50,8 +50,8 @@ static inline void set_fs (mm_segment_t fs)
" .align 3\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err) \
: "r" (x), "r" (__pu_addr), "i" (-EFAULT), "0" (err) \
: "+r" (err) \
: "r" (x), "r" (__pu_addr), "i" (-EFAULT) \
: "cc")
#ifndef __ARMEB__
......@@ -83,19 +83,18 @@ static inline void set_fs (mm_segment_t fs)
" .align 3\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err) \
: "r" (x), "r" (__pu_addr), "i" (-EFAULT), "0" (err))
: "+r" (err) \
: "r" (x), "r" (__pu_addr), "i" (-EFAULT) \
: "cc")
#define __put_user_asm_dword(x,__pu_addr,err) \
({ \
unsigned long long __temp = (unsigned long long)x; \
__asm__ __volatile__( \
"1: strt %1, [%2], #0\n" \
"2: strt %3, [%4], #0\n" \
"1: strt %Q2, [%1], #4\n" \
"2: strt %R2, [%1], #0\n" \
"3:\n" \
" .section .fixup,\"ax\"\n" \
" .align 2\n" \
"4: mov %0, %5\n" \
"4: mov %0, %3\n" \
" b 3b\n" \
" .previous\n" \
" .section __ex_table,\"a\"\n" \
......@@ -103,12 +102,9 @@ static inline void set_fs (mm_segment_t fs)
" .long 1b, 4b\n" \
" .long 2b, 4b\n" \
" .previous" \
: "=r" (err) \
: "r" (__temp), "r" (__pu_addr), \
"r" (__temp >> 32), "r" (__pu_addr + 4), \
"i" (-EFAULT), "0" (err) \
: "cc"); \
})
: "+r" (err), "+r" (__pu_addr) \
: "r" (x), "i" (-EFAULT) \
: "cc")
#define __get_user_asm_byte(x,addr,err) \
__asm__ __volatile__( \
......@@ -124,23 +120,24 @@ static inline void set_fs (mm_segment_t fs)
" .align 3\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err), "=&r" (x) \
: "r" (addr), "i" (-EFAULT), "0" (err))
: "+r" (err), "=&r" (x) \
: "r" (addr), "i" (-EFAULT) \
: "cc")
#ifndef __ARMEB__
#define __get_user_asm_half(x,addr,err) \
#define __get_user_asm_half(x,__gu_addr,err) \
({ \
unsigned long __b1, __b2, __ptr = (unsigned long)addr; \
__get_user_asm_byte(__b1, __ptr, err); \
__get_user_asm_byte(__b2, __ptr + 1, err); \
unsigned long __b1, __b2; \
__get_user_asm_byte(__b1, __gu_addr, err); \
__get_user_asm_byte(__b2, __gu_addr + 1, err); \
(x) = __b1 | (__b2 << 8); \
})
#else
#define __get_user_asm_half(x,addr,err) \
#define __get_user_asm_half(x,__gu_addr,err) \
({ \
unsigned long __b1, __b2; \
__get_user_asm_byte(__b1, addr, err); \
__get_user_asm_byte(__b2, (int)(addr) + 1, err); \
__get_user_asm_byte(__b1, __gu_addr, err); \
__get_user_asm_byte(__b2, __gu_addr + 1, err); \
(x) = (__b1 << 8) | __b2; \
})
#endif
......@@ -159,8 +156,9 @@ static inline void set_fs (mm_segment_t fs)
" .align 3\n" \
" .long 1b, 3b\n" \
" .previous" \
: "=r" (err), "=&r" (x) \
: "r" (addr), "i" (-EFAULT), "0" (err))
: "+r" (err), "=&r" (x) \
: "r" (addr), "i" (-EFAULT) \
: "cc")
extern unsigned long __arch_copy_from_user(void *to, const void *from, unsigned long n);
#define __do_copy_from_user(to,from,n) \
......
......@@ -16,11 +16,6 @@ struct cpu_tlb_fns;
struct cpu_user_fns;
struct processor;
struct proc_info_item {
const char *manufacturer;
const char *cpu_name;
};
/*
* Note! struct processor is always defined if we're
* using MULTI_CPU, otherwise this entry is unused,
......@@ -38,7 +33,7 @@ struct proc_info_list {
const char *arch_name;
const char *elf_name;
unsigned int elf_hwcap;
struct proc_info_item *info;
const char *cpu_name;
struct processor *proc;
struct cpu_tlb_fns *tlb;
struct cpu_user_fns *user;
......
......@@ -74,7 +74,7 @@ extern int __get_user_bad(void);
__asm__ __volatile__ ("bl __get_user_" #__s \
: "=&r" (__e), "=r" (__r1) \
: "0" (__p) \
: __i)
: __i, "cc")
#define get_user(x,p) \
({ \
......@@ -100,8 +100,31 @@ extern int __get_user_bad(void);
__e; \
})
#define __get_user(x,p) __get_user_nocheck((x),(p),sizeof(*(p)))
#define __get_user_error(x,p,e) __get_user_nocheck_error((x),(p),sizeof(*(p)),(e))
#define __get_user(x,ptr) \
({ \
long __gu_err = 0; \
__get_user_err((x),(ptr),__gu_err); \
__gu_err; \
})
#define __get_user_error(x,ptr,err) \
({ \
__get_user_err((x),(ptr),err); \
(void) 0; \
})
#define __get_user_err(x,ptr,err) \
do { \
unsigned long __gu_addr = (unsigned long)(ptr); \
unsigned long __gu_val; \
switch (sizeof(*(ptr))) { \
case 1: __get_user_asm_byte(__gu_val,__gu_addr,err); break; \
case 2: __get_user_asm_half(__gu_val,__gu_addr,err); break; \
case 4: __get_user_asm_word(__gu_val,__gu_addr,err); break; \
default: (__gu_val) = __get_user_bad(); \
} \
(x) = (__typeof__(*(ptr)))__gu_val; \
} while (0)
extern int __put_user_1(void *, unsigned int);
extern int __put_user_2(void *, unsigned int);
......@@ -113,7 +136,7 @@ extern int __put_user_bad(void);
__asm__ __volatile__ ("bl __put_user_" #__s \
: "=&r" (__e) \
: "0" (__p), "r" (__r1) \
: __i)
: __i, "cc")
#define put_user(x,p) \
({ \
......@@ -138,8 +161,31 @@ extern int __put_user_bad(void);
__e; \
})
#define __put_user(x,p) __put_user_nocheck((__typeof(*(p)))(x),(p),sizeof(*(p)))
#define __put_user_error(x,p,e) __put_user_nocheck_error((x),(p),sizeof(*(p)),(e))
#define __put_user(x,ptr) \
({ \
long __pu_err = 0; \
__put_user_err((x),(ptr),__pu_err); \
__pu_err; \
})
#define __put_user_error(x,ptr,err) \
({ \
__put_user_err((x),(ptr),err); \
(void) 0; \
})
#define __put_user_err(x,ptr,err) \
do { \
unsigned long __pu_addr = (unsigned long)(ptr); \
__typeof__(*(ptr)) __pu_val = (x); \
switch (sizeof(*(ptr))) { \
case 1: __put_user_asm_byte(__pu_val,__pu_addr,err); break; \
case 2: __put_user_asm_half(__pu_val,__pu_addr,err); break; \
case 4: __put_user_asm_word(__pu_val,__pu_addr,err); break; \
case 8: __put_user_asm_dword(__pu_val,__pu_addr,err); break; \
default: __put_user_bad(); \
} \
} while (0)
static __inline__ unsigned long copy_from_user(void *to, const void *from, unsigned long n)
{
......@@ -209,85 +255,4 @@ static inline long strnlen_user(const char *s, long n)
return res;
}
/*
* These are the work horses of the get/put_user functions
*/
#if 0
#define __get_user_check(x,ptr,size) \
({ \
long __gu_err = -EFAULT, __gu_val = 0; \
const __typeof__(*(ptr)) *__gu_addr = (ptr); \
if (access_ok(VERIFY_READ,__gu_addr,size)) { \
__gu_err = 0; \
__get_user_size(__gu_val,__gu_addr,(size),__gu_err); \
} \
(x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \
})
#endif
#define __get_user_nocheck(x,ptr,size) \
({ \
long __gu_err = 0, __gu_val; \
__get_user_size(__gu_val,(ptr),(size),__gu_err); \
(x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \
})
#define __get_user_nocheck_error(x,ptr,size,err) \
({ \
long __gu_val; \
__get_user_size(__gu_val,(ptr),(size),(err)); \
(x) = (__typeof__(*(ptr)))__gu_val; \
(void) 0; \
})
#define __put_user_check(x,ptr,size) \
({ \
long __pu_err = -EFAULT; \
__typeof__(*(ptr)) *__pu_addr = (ptr); \
if (access_ok(VERIFY_WRITE,__pu_addr,size)) { \
__pu_err = 0; \
__put_user_size((x),__pu_addr,(size),__pu_err); \
} \
__pu_err; \
})
#define __put_user_nocheck(x,ptr,size) \
({ \
long __pu_err = 0; \
unsigned long __pu_addr = (unsigned long)(ptr); \
__put_user_size((x),__pu_addr,(size),__pu_err); \
__pu_err; \
})
#define __put_user_nocheck_error(x,ptr,size,err) \
({ \
unsigned long __pu_addr = (unsigned long)(ptr); \
__put_user_size((x),__pu_addr,(size),err); \
(void) 0; \
})
#define __get_user_size(x,ptr,size,retval) \
do { \
switch (size) { \
case 1: __get_user_asm_byte(x,ptr,retval); break; \
case 2: __get_user_asm_half(x,ptr,retval); break; \
case 4: __get_user_asm_word(x,ptr,retval); break; \
case 8: __get_user_asm_dword(x,ptr,retval); break; \
default: (x) = __get_user_bad(); \
} \
} while (0)
#define __put_user_size(x,ptr,size,retval) \
do { \
switch (size) { \
case 1: __put_user_asm_byte(x,ptr,retval); break; \
case 2: __put_user_asm_half(x,ptr,retval); break; \
case 4: __put_user_asm_word(x,ptr,retval); break; \
case 8: __put_user_asm_dword(x,ptr,retval); break; \
default: __put_user_bad(); \
} \
} while (0)
#endif /* _ASMARM_UACCESS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment