What: old NCR53C9x driver
When: October 2007
Why: Replaced by the much better esp_scsi driver. Actual low-level
- driver can ported over almost trivially.
+ driver can be ported over almost trivially.
Who: David Miller <davem@davemloft.net>
Christoph Hellwig <hch@lst.de>
when set.
Format: <int>
- noaliencache [MM, NUMA] Disables the allcoation of alien caches in
- the slab allocator. Saves per-node memory, but will
- impact performance on real NUMA hardware.
+ noaliencache [MM, NUMA, SLAB] Disables the allocation of alien
+ caches in the slab allocator. Saves per-node memory,
+ but will impact performance.
noalign [KNL,ARM]
slram= [HW,MTD]
+ slub_debug [MM, SLUB]
+ Enabling slub_debug allows one to determine the culprit
+ if slab objects become corrupted. Enabling slub_debug
+ creates guard zones around objects and poisons objects
+ when not in use. Also tracks the last alloc / free.
+ For more information see Documentation/vm/slub.txt.
+
+ slub_max_order= [MM, SLUB]
+ Determines the maximum allowed order for slabs. Setting
+ this too high may cause fragmentation.
+ For more information see Documentation/vm/slub.txt.
+
+ slub_min_objects= [MM, SLUB]
+ The minimum objects per slab. SLUB will increase the
+ slab order up to slub_max_order to generate a
+ sufficiently big slab to satisfy the number of objects.
+ The higher the number of objects the smaller the overhead
+ of tracking slabs.
+ For more information see Documentation/vm/slub.txt.
+
+ slub_min_order= [MM, SLUB]
+ Determines the mininum page order for slabs. Must be
+ lower than slub_max_order
+ For more information see Documentation/vm/slub.txt.
+
+ slub_nomerge [MM, SLUB]
+ Disable merging of slabs of similar size. May be
+ necessary if there is some reason to distinguish
+ allocs to different slabs.
+ For more information see Documentation/vm/slub.txt.
+
smart2= [HW]
Format: <io1>[,<io2>[,...,<io8>]]
--- /dev/null
+/proc/sys/net/core/xfrm_* Variables:
+
+xfrm_acq_expires - INTEGER
+ default 30 - hard timeout in seconds for acquire requests
ref Reference board, base config
m2-2 Some Gateway MX series laptops
m6 Some Gateway NX series laptops
+ pa6 Gateway NX860 series
STAC9227/9228/9229/927x
ref Reference board
Short users guide for SLUB
--------------------------
-First of all slub should transparently replace SLAB. If you enable
-SLUB then everything should work the same (Note the word "should".
-There is likely not much value in that word at this point).
-
The basic philosophy of SLUB is very different from SLAB. SLAB
requires rebuilding the kernel to activate debug options for all
-SLABS. SLUB always includes full debugging but its off by default.
+slab caches. SLUB always includes full debugging but it is off by default.
SLUB can enable debugging only for selected slabs in order to avoid
an impact on overall system performance which may make a bug more
difficult to find.
Careful with tracing: It may spew out lots of information and never stop if
used on the wrong slab.
-SLAB Merging
+Slab merging
------------
-If no debugging is specified then SLUB may merge similar slabs together
+If no debug options are specified then SLUB may merge similar slabs together
in order to reduce overhead and increase cache hotness of objects.
slabinfo -a displays which slabs were merged together.
+Slab validation
+---------------
+
+SLUB can validate all object if the kernel was booted with slub_debug. In
+order to do so you must have the slabinfo tool. Then you can do
+
+slabinfo -v
+
+which will test all objects. Output will be generated to the syslog.
+
+This also works in a more limited way if boot was without slab debug.
+In that case slabinfo -v simply tests all reachable objects. Usually
+these are in the cpu slabs and the partial slabs. Full slabs are not
+tracked by SLUB in a non debug situation.
+
Getting more performance
------------------------
governed by the order of the allocation for each slab. The allocations
can be influenced by kernel parameters:
-slub_min_objects=x (default 8)
+slub_min_objects=x (default 4)
slub_min_order=x (default 0)
-slub_max_order=x (default 4)
+slub_max_order=x (default 1)
slub_min_objects allows to specify how many objects must at least fit
into one slab in order for the allocation order to be acceptable.
super large order pages to fit slub_min_objects of a slab cache with
large object sizes into one high order page.
-
-Christoph Lameter, <clameter@sgi.com>, April 10, 2007
+SLUB Debug output
+-----------------
+
+Here is a sample of slub debug output:
+
+*** SLUB kmalloc-8: Redzone Active@0xc90f6d20 slab 0xc528c530 offset=3360 flags=0x400000c3 inuse=61 freelist=0xc90f6d58
+ Bytes b4 0xc90f6d10: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
+ Object 0xc90f6d20: 31 30 31 39 2e 30 30 35 1019.005
+ Redzone 0xc90f6d28: 00 cc cc cc .
+FreePointer 0xc90f6d2c -> 0xc90f6d58
+Last alloc: get_modalias+0x61/0xf5 jiffies_ago=53 cpu=1 pid=554
+Filler 0xc90f6d50: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
+ [<c010523d>] dump_trace+0x63/0x1eb
+ [<c01053df>] show_trace_log_lvl+0x1a/0x2f
+ [<c010601d>] show_trace+0x12/0x14
+ [<c0106035>] dump_stack+0x16/0x18
+ [<c017e0fa>] object_err+0x143/0x14b
+ [<c017e2cc>] check_object+0x66/0x234
+ [<c017eb43>] __slab_free+0x239/0x384
+ [<c017f446>] kfree+0xa6/0xc6
+ [<c02e2335>] get_modalias+0xb9/0xf5
+ [<c02e23b7>] dmi_dev_uevent+0x27/0x3c
+ [<c027866a>] dev_uevent+0x1ad/0x1da
+ [<c0205024>] kobject_uevent_env+0x20a/0x45b
+ [<c020527f>] kobject_uevent+0xa/0xf
+ [<c02779f1>] store_uevent+0x4f/0x58
+ [<c027758e>] dev_attr_store+0x29/0x2f
+ [<c01bec4f>] sysfs_write_file+0x16e/0x19c
+ [<c0183ba7>] vfs_write+0xd1/0x15a
+ [<c01841d7>] sys_write+0x3d/0x72
+ [<c0104112>] sysenter_past_esp+0x5f/0x99
+ [<b7f7b410>] 0xb7f7b410
+ =======================
+@@@ SLUB kmalloc-8: Restoring redzone (0xcc) from 0xc90f6d28-0xc90f6d2b
+
+
+
+If SLUB encounters a corrupted object then it will perform the following
+actions:
+
+1. Isolation and report of the issue
+
+This will be a message in the system log starting with
+
+*** SLUB <slab cache affected>: <What went wrong>@<object address>
+offset=<offset of object into slab> flags=<slabflags>
+inuse=<objects in use in this slab> freelist=<first free object in slab>
+
+2. Report on how the problem was dealt with in order to ensure the continued
+operation of the system.
+
+These are messages in the system log beginning with
+
+@@@ SLUB <slab cache affected>: <corrective action taken>
+
+
+In the above sample SLUB found that the Redzone of an active object has
+been overwritten. Here a string of 8 characters was written into a slab that
+has the length of 8 characters. However, a 8 character string needs a
+terminating 0. That zero has overwritten the first byte of the Redzone field.
+After reporting the details of the issue encountered the @@@ SLUB message
+tell us that SLUB has restored the redzone to its proper value and then
+system operations continue.
+
+Various types of lines can follow the @@@ SLUB line:
+
+Bytes b4 <address> : <bytes>
+ Show a few bytes before the object where the problem was detected.
+ Can be useful if the corruption does not stop with the start of the
+ object.
+
+Object <address> : <bytes>
+ The bytes of the object. If the object is inactive then the bytes
+ typically contain poisoning values. Any non-poison value shows a
+ corruption by a write after free.
+
+Redzone <address> : <bytes>
+ The redzone following the object. The redzone is used to detect
+ writes after the object. All bytes should always have the same
+ value. If there is any deviation then it is due to a write after
+ the object boundary.
+
+Freepointer
+ The pointer to the next free object in the slab. May become
+ corrupted if overwriting continues after the red zone.
+
+Last alloc:
+Last free:
+ Shows the address from which the object was allocated/freed last.
+ We note the pid, the time and the CPU that did so. This is usually
+ the most useful information to figure out where things went wrong.
+ Here get_modalias() did an kmalloc(8) instead of a kmalloc(9).
+
+Filler <address> : <bytes>
+ Unused data to fill up the space in order to get the next object
+ properly aligned. In the debug case we make sure that there are
+ at least 4 bytes of filler. This allow for the detection of writes
+ before the object.
+
+Following the filler will be a stackdump. That stackdump describes the
+location where the error was detected. The cause of the corruption is more
+likely to be found by looking at the information about the last alloc / free.
+
+Christoph Lameter, <clameter@sgi.com>, May 23, 2007
MEGARAID SCSI DRIVERS
P: Neela Syam Kolli
-M: Neela.Kolli@engenio.com
+M: megaraidlinux@lsi.com
S: linux-scsi@vger.kernel.org
W: http://megaraid.lsilogic.com
S: Maintained
bne $2, $work_resched
$work_notifysig:
- mov $sp, $17
+ mov $sp, $16
br $1, do_switch_stack
- mov $5, $21
- mov $sp, $18
- mov $31, $16
+ mov $sp, $17
+ mov $5, $18
jsr $26, do_notify_resume
bsr $1, undo_switch_stack
br restore_all
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/bootmem.h>
+#include <linux/log2.h>
#include <asm/io.h>
#include <asm/hwrpb.h>
{
unsigned long mem = max_low_pfn << PAGE_SHIFT;
if (mem < max)
- max = 1UL << ceil_log2(mem);
+ max = roundup_pow_of_two(mem);
return max;
}
\f
#include <linux/notifier.h>
#include <asm/setup.h>
#include <asm/io.h>
+#include <linux/log2.h>
extern struct atomic_notifier_head panic_notifier_list;
static int alpha_panic_event(struct notifier_block *, unsigned long, void *);
long size = minsize, maxsize = MAX_BCACHE_SIZE * 2;
if (maxsize > (max_low_pfn + 1) << PAGE_SHIFT)
- maxsize = 1 << (floor_log2(max_low_pfn + 1) + PAGE_SHIFT);
+ maxsize = 1 << (ilog2(max_low_pfn + 1) + PAGE_SHIFT);
/* Get the first block cached. */
read_mem_block(__va(0), stride, size);
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage void ret_from_sys_call(void);
-static int do_signal(sigset_t *, struct pt_regs *, struct switch_stack *,
- unsigned long, unsigned long);
+static void do_signal(struct pt_regs *, struct switch_stack *,
+ unsigned long, unsigned long);
/*
asmlinkage int
do_sigsuspend(old_sigset_t mask, struct pt_regs *regs, struct switch_stack *sw)
{
- sigset_t oldset;
-
mask &= _BLOCKABLE;
spin_lock_irq(¤t->sighand->siglock);
- oldset = current->blocked;
+ current->saved_sigmask = current->blocked;
siginitset(¤t->blocked, mask);
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
regs->r0 = EINTR;
regs->r19 = 1;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(&oldset, regs, sw, 0, 0))
- return -EINTR;
- }
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_thread_flag(TIF_RESTORE_SIGMASK);
+ return -ERESTARTNOHAND;
}
asmlinkage int
do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize,
struct pt_regs *regs, struct switch_stack *sw)
{
- sigset_t oldset, set;
+ sigset_t set;
/* XXX: Don't preclude handling different sized sigset_t's. */
if (sigsetsize != sizeof(sigset_t))
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(¤t->sighand->siglock);
- oldset = current->blocked;
+ current->saved_sigmask = current->blocked;
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(¤t->sighand->siglock);
regs->r0 = EINTR;
regs->r19 = 1;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(&oldset, regs, sw, 0, 0))
- return -EINTR;
- }
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_thread_flag(TIF_RESTORE_SIGMASK);
+ return -ERESTARTNOHAND;
}
asmlinkage int
return err;
}
-static void
+static int
setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
struct pt_regs *regs, struct switch_stack * sw)
{
current->comm, current->pid, frame, regs->pc, regs->r26);
#endif
- return;
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
-static void
+static int
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs, struct switch_stack * sw)
{
current->comm, current->pid, frame, regs->pc, regs->r26);
#endif
- return;
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
/*
* OK, we're invoking a handler.
*/
-static inline void
+static inline int
handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw)
{
+ int ret;
+
if (ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame(sig, ka, info, oldset, regs, sw);
+ ret = setup_rt_frame(sig, ka, info, oldset, regs, sw);
else
- setup_frame(sig, ka, oldset, regs, sw);
+ ret = setup_frame(sig, ka, oldset, regs, sw);
- if (ka->sa.sa_flags & SA_RESETHAND)
- ka->sa.sa_handler = SIG_DFL;
+ if (ret == 0) {
+ spin_lock_irq(¤t->sighand->siglock);
+ sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+ sigaddset(¤t->blocked,sig);
+ recalc_sigpending();
+ spin_unlock_irq(¤t->sighand->siglock);
+ }
- spin_lock_irq(¤t->sighand->siglock);
- sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(¤t->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(¤t->sighand->siglock);
+ return ret;
}
static inline void
* restart. "r0" is also used as an indicator whether we can restart at
* all (if we get here from anything but a syscall return, it will be 0)
*/
-static int
-do_signal(sigset_t *oldset, struct pt_regs * regs, struct switch_stack * sw,
+static void
+do_signal(struct pt_regs * regs, struct switch_stack * sw,
unsigned long r0, unsigned long r19)
{
siginfo_t info;
int signr;
unsigned long single_stepping = ptrace_cancel_bpt(current);
struct k_sigaction ka;
+ sigset_t *oldset;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+ else
oldset = ¤t->blocked;
/* This lets the debugger run, ... */
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
/* ... so re-check the single stepping. */
single_stepping |= ptrace_cancel_bpt(current);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
- if (r0) syscall_restart(r0, r19, regs, &ka);
- handle_signal(signr, &ka, &info, oldset, regs, sw);
+ if (r0)
+ syscall_restart(r0, r19, regs, &ka);
+ if (handle_signal(signr, &ka, &info, oldset, regs, sw) == 0) {
+ /* A signal was successfully delivered, and the
+ saved sigmask was stored on the signal frame,
+ and will be restored by sigreturn. So we can
+ simply clear the restore sigmask flag. */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
if (single_stepping)
ptrace_set_bpt(current); /* re-set bpt */
- return 1;
+ return;
}
if (r0) {
break;
}
}
+
+ /* If there's no signal to deliver, we just restore the saved mask. */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
+ }
+
if (single_stepping)
ptrace_set_bpt(current); /* re-set breakpoint */
-
- return 0;
}
void
-do_notify_resume(sigset_t *oldset, struct pt_regs *regs,
- struct switch_stack *sw, unsigned long r0,
- unsigned long r19, unsigned long thread_info_flags)
+do_notify_resume(struct pt_regs *regs, struct switch_stack *sw,
+ unsigned long thread_info_flags,
+ unsigned long r0, unsigned long r19)
{
- if (thread_info_flags & _TIF_SIGPENDING)
- do_signal(oldset, regs, sw, r0, r19);
+ if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ do_signal(regs, sw, r0, r19);
}
.quad sys_inotify_init
.quad sys_inotify_add_watch /* 445 */
.quad sys_inotify_rm_watch
+ .quad sys_fdatasync
+ .quad sys_kexec_load
+ .quad sys_migrate_pages
+ .quad sys_openat /* 450 */
+ .quad sys_mkdirat
+ .quad sys_mknodat
+ .quad sys_fchownat
+ .quad sys_futimesat
+ .quad sys_fstatat64 /* 455 */
+ .quad sys_unlinkat
+ .quad sys_renameat
+ .quad sys_linkat
+ .quad sys_symlinkat
+ .quad sys_readlinkat /* 460 */
+ .quad sys_fchmodat
+ .quad sys_faccessat
+ .quad sys_pselect6
+ .quad sys_ppoll
+ .quad sys_unshare /* 465 */
+ .quad sys_set_robust_list
+ .quad sys_get_robust_list
+ .quad sys_splice
+ .quad sys_sync_file_range
+ .quad sys_tee /* 470 */
+ .quad sys_vmsplice
+ .quad sys_move_pages
+ .quad sys_getcpu
+ .quad sys_epoll_pwait
+ .quad sys_utimensat /* 475 */
+ .quad sys_signalfd
+ .quad sys_timerfd
+ .quad sys_eventfd
.size sys_call_table, . - sys_call_table
.type sys_call_table, @object
$(ev6-y)clear_page.o \
$(ev6-y)copy_page.o \
fpreg.o \
- callback_srm.o srm_puts.o srm_printk.o
+ callback_srm.o srm_puts.o srm_printk.o \
+ fls.o
lib-$(CONFIG_SMP) += dec_and_lock.o
--- /dev/null
+/*
+ * arch/alpha/lib/fls.c
+ */
+
+#include <linux/module.h>
+#include <asm/bitops.h>
+
+/* This is fls(x)-1, except zero is held to zero. This allows most
+ efficent input into extbl, plus it allows easy handling of fls(0)=0. */
+
+const unsigned char __flsm1_tab[256] =
+{
+ 0,
+ 0,
+ 1, 1,
+ 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+};
+
+EXPORT_SYMBOL(__flsm1_tab);
#define EXPORT_SYMBOL_ALIAS(sym,orig) \
EXPORT_CRC_ALIAS(sym) \
static const struct kernel_symbol __ksymtab_##sym \
- __attribute_used__ __attribute__((section("__ksymtab"))) = \
+ __used __attribute__((section("__ksymtab"))) = \
{ (unsigned long)&orig, #sym };
/*
/*
* Check current frame pointer is within bounds
*/
- if ((fp - 12) < low || fp + 4 >= high)
+ if (fp < (low + 12) || fp + 4 >= high)
break;
frame = (struct stackframe *)(fp - 12);
},
};
-static struct mtd_partition *nand_partitions(int size, int *num_partitions)
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
{
*num_partitions = ARRAY_SIZE(dk_nand_partition);
return dk_nand_partition;
},
};
-static struct mtd_partition *nand_partitions(int size, int *num_partitions)
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
{
*num_partitions = ARRAY_SIZE(kb9202_nand_partition);
return kb9202_nand_partition;
},
};
-static struct mtd_partition *nand_partitions(int size, int *num_partitions)
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
{
*num_partitions = ARRAY_SIZE(ek_nand_partition);
return ek_nand_partition;
},
};
-static struct mtd_partition *nand_partitions(int size, int *num_partitions)
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
{
*num_partitions = ARRAY_SIZE(ek_nand_partition);
return ek_nand_partition;
},
};
-static struct mtd_partition *nand_partitions(int size, int *num_partitions)
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
{
*num_partitions = ARRAY_SIZE(ek_nand_partition);
return ek_nand_partition;
.postinit = dc21285_postinit,
};
-static int cats_pci_init(void)
+static int __init cats_pci_init(void)
{
if (machine_is_cats())
pci_common_init(&cats_pci);
{
imx_mmc_device.dev.platform_data = info;
}
-EXPORT_SYMBOL(imx_set_mmc_info);
static struct imxfb_mach_info imx_fb_info;
subsys_initcall(ixdp2400_pci_init);
-void ixdp2400_init_irq(void)
+void __init ixdp2400_init_irq(void)
{
ixdp2x00_init_irq(IXDP2400_CPLD_INT_STAT, IXDP2400_CPLD_INT_MASK, IXDP2400_NR_IRQS);
}
subsys_initcall(ixdp2800_pci_init);
-void ixdp2800_init_irq(void)
+void __init ixdp2800_init_irq(void)
{
ixdp2x00_init_irq(IXDP2800_CPLD_INT_STAT, IXDP2800_CPLD_INT_MASK, IXDP2800_NR_IRQS);
}
.unmask = ixdp2x00_irq_unmask
};
-void ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_irqs)
+void __init ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_irqs)
{
unsigned int irq;
.unmask = ixdp2351_intb_unmask
};
-void ixdp2351_init_irq(void)
+void __init ixdp2351_init_irq(void)
{
int irq;
return 1;
}
-void ixp23xx_pci_slave_init(void)
+void __init ixp23xx_pci_slave_init(void)
{
ixp23xx_pci_common_init();
}
return NO_IRQ;
}
-static void roadrunner_pci_preinit(void)
+static void __init roadrunner_pci_preinit(void)
{
set_irq_type(IRQ_ROADRUNNER_PCI_INTC, IRQT_LOW);
set_irq_type(IRQ_ROADRUNNER_PCI_INTD, IRQT_LOW);
DSM-G600 RevA device. For more information on this platform,
see http://www.nslu2-linux.org/wiki/DSMG600/HomePage
-#
-# Avila and IXDP share the same source for now. Will change in future
-#
config ARCH_IXDP4XX
bool
depends on ARCH_IXDP425 || MACH_IXDP465 || MACH_KIXRP435
.handler = ixp4xx_timer_interrupt,
};
-static void __init ixp4xx_timer_init(void)
+void __init ixp4xx_timer_init(void)
{
/* Reset/disable counter */
*IXP4XX_OSRT1 = 0;
#include <asm/mach/pci.h>
-extern void ixp4xx_pci_preinit(void);
-extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
-extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
-
void __init coyote_pci_preinit(void)
{
set_irq_type(IRQ_COYOTE_PCI_SLOT0, IRQT_LOW);
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
+#include <asm/mach/time.h>
static struct flash_platform_data dsmg600_flash_data = {
.map_name = "cfi_probe",
gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH);
}
+static void __init dsmg600_timer_init(void)
+{
+ /* The xtal on this machine is non-standard. */
+ ixp4xx_timer_freq = DSMG600_FREQ;
+
+ /* Call standard timer_init function. */
+ ixp4xx_timer_init();
+}
+
+static struct sys_timer dsmg600_timer = {
+ .init = dsmg600_timer_init,
+};
+
static void __init dsmg600_init(void)
{
ixp4xx_sys_init();
#endif
}
-static void __init dsmg600_fixup(struct machine_desc *desc,
- struct tag *tags, char **cmdline, struct meminfo *mi)
-{
- /* The xtal on this machine is non-standard. */
- ixp4xx_timer_freq = DSMG600_FREQ;
-}
-
MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")
/* Maintainer: www.nslu2-linux.org */
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
.boot_params = 0x00000100,
- .fixup = dsmg600_fixup,
.map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .timer = &dsmg600_timer,
.init_machine = dsmg600_init,
MACHINE_END
#include <asm/mach/pci.h>
-extern void ixp4xx_pci_preinit(void);
-extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
-extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
-
void __init ixdpg425_pci_preinit(void)
{
set_irq_type(IRQ_IXP4XX_GPIO6, IRQT_LOW);
pm_power_off = nas100d_power_off;
- /* This is only useful on a modified machine, but it is valuable
+ /*
+ * This is only useful on a modified machine, but it is valuable
* to have it first in order to see debug messages, and so that
* it does *not* get removed if platform_add_devices fails!
*/
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
+#include <asm/mach/time.h>
static struct flash_platform_data nslu2_flash_data = {
.map_name = "cfi_probe",
static struct resource nslu2_led_resources[] = {
{
.name = "ready", /* green led */
- .start = NSLU2_LED_GRN,
- .end = NSLU2_LED_GRN,
+ .start = NSLU2_LED_GRN_GPIO,
+ .end = NSLU2_LED_GRN_GPIO,
.flags = IXP4XX_GPIO_HIGH,
},
{
.name = "status", /* red led */
- .start = NSLU2_LED_RED,
- .end = NSLU2_LED_RED,
+ .start = NSLU2_LED_RED_GPIO,
+ .end = NSLU2_LED_RED_GPIO,
.flags = IXP4XX_GPIO_HIGH,
},
{
.name = "disk-1",
- .start = NSLU2_LED_DISK1,
- .end = NSLU2_LED_DISK1,
+ .start = NSLU2_LED_DISK1_GPIO,
+ .end = NSLU2_LED_DISK1_GPIO,
.flags = IXP4XX_GPIO_LOW,
},
{
.name = "disk-2",
- .start = NSLU2_LED_DISK2,
- .end = NSLU2_LED_DISK2,
+ .start = NSLU2_LED_DISK2_GPIO,
+ .end = NSLU2_LED_DISK2_GPIO,
.flags = IXP4XX_GPIO_LOW,
},
};
gpio_line_set(NSLU2_PO_GPIO, IXP4XX_GPIO_HIGH);
}
-static void __init nslu2_init(void)
+static void __init nslu2_timer_init(void)
{
- ixp4xx_timer_freq = NSLU2_FREQ;
+ /* The xtal on this machine is non-standard. */
+ ixp4xx_timer_freq = NSLU2_FREQ;
+
+ /* Call standard timer_init function. */
+ ixp4xx_timer_init();
+}
+static struct sys_timer nslu2_timer = {
+ .init = nslu2_timer_init,
+};
+
+static void __init nslu2_init(void)
+{
ixp4xx_sys_init();
nslu2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
pm_power_off = nslu2_power_off;
- /* This is only useful on a modified machine, but it is valuable
+ /*
+ * This is only useful on a modified machine, but it is valuable
* to have it first in order to see debug messages, and so that
* it does *not* get removed if platform_add_devices fails!
*/
.boot_params = 0x00000100,
.map_io = ixp4xx_map_io,
.init_irq = ixp4xx_init_irq,
- .timer = &ixp4xx_timer,
+ .timer = &nslu2_timer,
.init_machine = nslu2_init,
MACHINE_END
+++ /dev/null
-/* linux/arch/arm/mach-s3c2410/bast.h
-extern void bast_init_irq(void);
#endif
};
-void __init amlm5900_map_io(void)
+static void __init amlm5900_map_io(void)
{
s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc));
s3c24xx_init_clocks(0);
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/delay.h>
#include <linux/sysdev.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/arch/reset.h>
#include <asm/arch/idle.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpioj.h>
#include <asm/arch/regs-dsc.h>
#include <asm/arch/regs-spi.h>
+#include <asm/arch/regs-s3c2412.h>
#include <asm/plat-s3c24xx/s3c2412.h>
#include <asm/plat-s3c24xx/cpu.h>
cpu_do_idle();
}
+static void s3c2412_hard_reset(void)
+{
+ /* errata "Watch-dog/Software Reset Problem" specifies that
+ * this reset must be done with the SYSCLK sourced from
+ * EXTCLK instead of FOUT to avoid a glitch in the reset
+ * mechanism.
+ *
+ * See the watchdog section of the S3C2412 manual for more
+ * information on this fix.
+ */
+
+ __raw_writel(0x00, S3C2412_CLKSRC);
+ __raw_writel(S3C2412_SWRST_RESET, S3C2412_SWRST);
+
+ mdelay(1);
+}
+
/* s3c2412_map_io
*
* register the standard cpu IO areas, and any passed in from the
s3c24xx_idle = s3c2412_idle;
+ /* set custom reset hook */
+
+ s3c24xx_reset_hook = s3c2412_hard_reset;
+
/* register our io-tables */
iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
return 0;
}
-struct clk clk_usb_bus_host = {
+static struct clk clk_usb_bus_host = {
.name = "usb-bus-host-parent",
.id = -1,
.parent = &clk_esysclk,
.parent = &clk_h,
.enable = s3c2443_clkcon_enable_h,
.ctrlbit = S3C2443_HCLKCON_CFC,
- .ctrlbit = S3C2443_HCLKCON_HSMMC,
}, {
.name = "ssmc",
.id = -1,
return ret;
}
-static struct sa1100_port_fns neponset_port_fns __initdata = {
+static struct sa1100_port_fns neponset_port_fns __devinitdata = {
.set_mctrl = neponset_set_mctrl,
.get_mctrl = neponset_get_mctrl,
};
-static int neponset_probe(struct platform_device *dev)
+static int __devinit neponset_probe(struct platform_device *dev)
{
sa1100_register_uart_fns(&neponset_port_fns);
select CPU_CP15_MMU
select CPU_HAS_ASID
select CPU_COPY_V6 if MMU
- select CPU_TLB_V6 if MMU
+ select CPU_TLB_V7 if MMU
# Figure out what processor architecture version we should be using.
# This defines the compiler instruction set which depends on the machine type.
config CPU_TLB_V6
bool
+config CPU_TLB_V7
+ bool
+
endif
config CPU_HAS_ASID
obj-$(CONFIG_CPU_TLB_V4WB) += tlb-v4wb.o
obj-$(CONFIG_CPU_TLB_V4WBI) += tlb-v4wbi.o
obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o
+obj-$(CONFIG_CPU_TLB_V7) += tlb-v7.o
obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o
obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o
.long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
.long cpu_v7_name
.long v7_processor_functions
- .long v6wbi_tlb_fns
+ .long v7wbi_tlb_fns
.long v6_user_fns
.long v7_cache_fns
.size __v7_proc_info, . - __v7_proc_info
--- /dev/null
+/*
+ * linux/arch/arm/mm/tlb-v7.S
+ *
+ * Copyright (C) 1997-2002 Russell King
+ * Modified for ARMv7 by Catalin Marinas
+ *
+ * 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.
+ *
+ * ARM architecture version 6 TLB handling functions.
+ * These assume a split I/D TLB.
+ */
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+#include "proc-macros.S"
+
+/*
+ * v7wbi_flush_user_tlb_range(start, end, vma)
+ *
+ * Invalidate a range of TLB entries in the specified address space.
+ *
+ * - start - start address (may not be aligned)
+ * - end - end address (exclusive, may not be aligned)
+ * - vma - vma_struct describing address range
+ *
+ * It is assumed that:
+ * - the "Invalidate single entry" instruction will invalidate
+ * both the I and the D TLBs on Harvard-style TLBs
+ */
+ENTRY(v7wbi_flush_user_tlb_range)
+ vma_vm_mm r3, r2 @ get vma->vm_mm
+ mmid r3, r3 @ get vm_mm->context.id
+ dsb
+ mov r0, r0, lsr #PAGE_SHIFT @ align address
+ mov r1, r1, lsr #PAGE_SHIFT
+ asid r3, r3 @ mask ASID
+ orr r0, r3, r0, lsl #PAGE_SHIFT @ Create initial MVA
+ mov r1, r1, lsl #PAGE_SHIFT
+ vma_vm_flags r2, r2 @ get vma->vm_flags
+1:
+ mcr p15, 0, r0, c8, c6, 1 @ TLB invalidate D MVA (was 1)
+ tst r2, #VM_EXEC @ Executable area ?
+ mcrne p15, 0, r0, c8, c5, 1 @ TLB invalidate I MVA (was 1)
+ add r0, r0, #PAGE_SZ
+ cmp r0, r1
+ blo 1b
+ mov ip, #0
+ mcr p15, 0, ip, c7, c5, 6 @ flush BTAC/BTB
+ dsb
+ mov pc, lr
+
+/*
+ * v7wbi_flush_kern_tlb_range(start,end)
+ *
+ * Invalidate a range of kernel TLB entries
+ *
+ * - start - start address (may not be aligned)
+ * - end - end address (exclusive, may not be aligned)
+ */
+ENTRY(v7wbi_flush_kern_tlb_range)
+ dsb
+ mov r0, r0, lsr #PAGE_SHIFT @ align address
+ mov r1, r1, lsr #PAGE_SHIFT
+ mov r0, r0, lsl #PAGE_SHIFT
+ mov r1, r1, lsl #PAGE_SHIFT
+1:
+ mcr p15, 0, r0, c8, c6, 1 @ TLB invalidate D MVA
+ mcr p15, 0, r0, c8, c5, 1 @ TLB invalidate I MVA
+ add r0, r0, #PAGE_SZ
+ cmp r0, r1
+ blo 1b
+ mov r2, #0
+ mcr p15, 0, r2, c7, c5, 6 @ flush BTAC/BTB
+ dsb
+ isb
+ mov pc, lr
+
+ .section ".text.init", #alloc, #execinstr
+
+ .type v7wbi_tlb_fns, #object
+ENTRY(v7wbi_tlb_fns)
+ .long v7wbi_flush_user_tlb_range
+ .long v7wbi_flush_kern_tlb_range
+ .long v6wbi_tlb_flags
+ .size v7wbi_tlb_fns, . - v7wbi_tlb_fns
extern flag float32_is_nan( float32 a );
extern flag float64_is_nan( float64 a );
+extern int32 float64_to_uint32( struct roundingData *roundData, float64 a );
+extern int32 float64_to_uint32_round_to_zero( float64 a );
+
#endif
*/
static void em_route_irq(int irq, unsigned int cpu)
{
- irq_desc[irq].affinity = cpumask_of_cpu(cpu);
- irq_desc[irq].chip->set_affinity(irq, cpumask_of_cpu(cpu));
+ struct irq_desc *desc = irq_desc + irq;
+ cpumask_t mask = cpumask_of_cpu(cpu);
+
+ spin_lock_irq(&desc->lock);
+ desc->affinity = mask;
+ desc->chip->set_affinity(irq, mask);
+ spin_unlock_irq(&desc->lock);
}
static int em_setup(void)
static void smp_tune_scheduling(void)
{
- unsigned long cachesize; /* kB */
-
if (cpu_khz) {
- cachesize = boot_cpu_data.x86_cache_size;
+ /* cache size in kB */
+ long cachesize = boot_cpu_data.x86_cache_size;
if (cachesize > 0)
max_cache_size = cachesize * 1024;
adventurous.
config SINGLE_MEMORY_CHUNK
- bool "Use one physical chunk of memory only"
- depends on ADVANCED && !SUN3
+ bool "Use one physical chunk of memory only" if ADVANCED && !SUN3
+ default y if SUN3
+ select NEED_MULTIPLE_NODES
help
Ignore all but the first contiguous chunk of physical memory for VM
purposes. This will save a few bytes kernel size and may speed up
is hardwired on. The 53c710 SCSI driver is known to suffer from
this problem.
+config ARCH_DISCONTIGMEM_ENABLE
+ def_bool !SINGLE_MEMORY_CHUNK
+
+config NODES_SHIFT
+ int
+ default "3"
+ depends on !SINGLE_MEMORY_CHUNK
+
source "mm/Kconfig"
endmenu
# override top level makefile
AS += -m68020
LDFLAGS := -m m68kelf
+LDFLAGS_MODULE += -T $(srctree)/arch/m68k/kernel/module.lds
ifneq ($(COMPILE_ARCH),$(ARCH))
# prefix for cross-compiling binaries
CROSS_COMPILE = m68k-linux-gnu-
endif
extra-y += vmlinux.lds
-obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \
+obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \
sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o devres.o
devres-y = ../../../kernel/irq/devres.o
obj-$(CONFIG_PCI) += bios32.o
-obj-$(CONFIG_MODULES) += module.o
obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo
EXTRA_AFLAGS := -traditional
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
#include <linux/moduleloader.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
#define DEBUGP(fmt...)
#endif
+#ifdef CONFIG_MODULES
+
void *module_alloc(unsigned long size)
{
if (size == 0)
int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
- struct module *me)
+ struct module *mod)
{
+ module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
+
return 0;
}
void module_arch_cleanup(struct module *mod)
{
}
+
+#endif /* CONFIG_MODULES */
+
+void module_fixup(struct module *mod, struct m68k_fixup_info *start,
+ struct m68k_fixup_info *end)
+{
+ struct m68k_fixup_info *fixup;
+
+ for (fixup = start; fixup < end; fixup++) {
+ switch (fixup->type) {
+ case m68k_fixup_memoffset:
+ *(u32 *)fixup->addr = m68k_memoffset;
+ break;
+ case m68k_fixup_vnode_shift:
+ *(u16 *)fixup->addr += m68k_virt_to_node_shift;
+ break;
+ }
+ }
+}
--- /dev/null
+SECTIONS {
+ .m68k_fixup : {
+ __start_fixup = .;
+ *(.m68k_fixup)
+ __stop_fixup = .;
+ }
+}
int m68k_num_memory;
int m68k_realnum_memory;
EXPORT_SYMBOL(m68k_realnum_memory);
-#ifdef CONFIG_SINGLE_MEMORY_CHUNK
unsigned long m68k_memoffset;
EXPORT_SYMBOL(m68k_memoffset);
-#endif
struct mem_info m68k_memory[NUM_MEMINFO];
EXPORT_SYMBOL(m68k_memory);
-static struct mem_info m68k_ramdisk;
+struct mem_info m68k_ramdisk;
static char m68k_command_line[CL_SIZE];
void __init setup_arch(char **cmdline_p)
{
extern int _etext, _edata, _end;
-#ifndef CONFIG_SUN3
- unsigned long endmem, startmem;
-#endif
int i;
/* The bootinfo is located right after the kernel bss */
panic("No configuration setup");
}
-#ifndef CONFIG_SUN3
- startmem= m68k_memory[0].addr;
- endmem = startmem + m68k_memory[0].size;
- high_memory = (void *)PAGE_OFFSET;
- for (i = 0; i < m68k_num_memory; i++) {
- m68k_memory[i].size &= MASK_256K;
- if (m68k_memory[i].addr < startmem)
- startmem = m68k_memory[i].addr;
- if (m68k_memory[i].addr+m68k_memory[i].size > endmem)
- endmem = m68k_memory[i].addr+m68k_memory[i].size;
- high_memory += m68k_memory[i].size;
- }
-
- availmem += init_bootmem_node(NODE_DATA(0), availmem >> PAGE_SHIFT,
- startmem >> PAGE_SHIFT, endmem >> PAGE_SHIFT);
-
- for (i = 0; i < m68k_num_memory; i++)
- free_bootmem(m68k_memory[i].addr, m68k_memory[i].size);
-
- reserve_bootmem(m68k_memory[0].addr, availmem - m68k_memory[0].addr);
+ paging_init();
+#ifndef CONFIG_SUN3
+ for (i = 1; i < m68k_num_memory; i++)
+ free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr,
+ m68k_memory[i].size);
#ifdef CONFIG_BLK_DEV_INITRD
if (m68k_ramdisk.size) {
- reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size);
+ reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)),
+ m68k_ramdisk.addr, m68k_ramdisk.size);
initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
initrd_end = initrd_start + m68k_ramdisk.size;
printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
#endif /* !CONFIG_SUN3 */
- paging_init();
-
/* set ISA defs early as possible */
#if defined(CONFIG_ISA) && defined(MULTI_ISA)
#if defined(CONFIG_Q40)
__con_initcall_start = .;
.con_initcall.init : { *(.con_initcall.init) }
__con_initcall_end = .;
+ .m68k_fixup : {
+ __start_fixup = .;
+ *(.m68k_fixup)
+ __stop_fixup = .;
+ }
SECURITY_INIT
#ifdef CONFIG_BLK_DEV_INITRD
. = ALIGN(8192);
__con_initcall_start = .;
.con_initcall.init : { *(.con_initcall.init) }
__con_initcall_end = .;
+ .m68k_fixup : {
+ __start_fixup = .;
+ *(.m68k_fixup)
+ __stop_fixup = .;
+ }
SECURITY_INIT
#ifdef CONFIG_BLK_DEV_INITRD
. = ALIGN(8192);
* to motorola.c and sun3mmu.c
*/
+#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/mm.h>
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+static bootmem_data_t __initdata bootmem_data[MAX_NUMNODES];
+
+pg_data_t pg_data_map[MAX_NUMNODES];
+EXPORT_SYMBOL(pg_data_map);
+
+int m68k_virt_to_node_shift;
+
+#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+pg_data_t *pg_data_table[65];
+EXPORT_SYMBOL(pg_data_table);
+#endif
+
+void m68k_setup_node(int node)
+{
+#ifndef CONFIG_SINGLE_MEMORY_CHUNK
+ struct mem_info *info = m68k_memory + node;
+ int i, end;
+
+ i = (unsigned long)phys_to_virt(info->addr) >> __virt_to_node_shift();
+ end = (unsigned long)phys_to_virt(info->addr + info->size - 1) >> __virt_to_node_shift();
+ for (; i <= end; i++) {
+ if (pg_data_table[i])
+ printk("overlap at %u for chunk %u\n", i, node);
+ pg_data_table[i] = pg_data_map + node;
+ }
+#endif
+ pg_data_map[node].bdata = bootmem_data + node;
+ node_set_online(node);
+}
+
+
/*
* ZERO_PAGE is a special page that is used for zero-initialized
* data and COW.
void show_mem(void)
{
- unsigned long i;
- int free = 0, total = 0, reserved = 0, shared = 0;
- int cached = 0;
-
- printk("\nMem-info:\n");
- show_free_areas();
- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
- i = max_mapnr;
- while (i-- > 0) {
- total++;
- if (PageReserved(mem_map+i))
- reserved++;
- else if (PageSwapCache(mem_map+i))
- cached++;
- else if (!page_count(mem_map+i))
- free++;
- else
- shared += page_count(mem_map+i) - 1;
- }
- printk("%d pages of RAM\n",total);
- printk("%d free pages\n",free);
- printk("%d reserved pages\n",reserved);
- printk("%d pages shared\n",shared);
- printk("%d pages swap cached\n",cached);
+ pg_data_t *pgdat;
+ int free = 0, total = 0, reserved = 0, shared = 0;
+ int cached = 0;
+ int i;
+
+ printk("\nMem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+ for_each_online_pgdat(pgdat) {
+ for (i = 0; i < pgdat->node_spanned_pages; i++) {
+ struct page *page = pgdat->node_mem_map + i;
+ total++;
+ if (PageReserved(page))
+ reserved++;
+ else if (PageSwapCache(page))
+ cached++;
+ else if (!page_count(page))
+ free++;
+ else
+ shared += page_count(page) - 1;
+ }
+ }
+ printk("%d pages of RAM\n",total);
+ printk("%d free pages\n",free);
+ printk("%d reserved pages\n",reserved);
+ printk("%d pages shared\n",shared);
+ printk("%d pages swap cached\n",cached);
}
extern void init_pointer_table(unsigned long ptable);
/* References to section boundaries */
-extern char _text, _etext, _edata, __bss_start, _end;
-extern char __init_begin, __init_end;
+extern char _text[], _etext[];
+extern char __init_begin[], __init_end[];
extern pmd_t *zero_pgtable;
void __init mem_init(void)
{
+ pg_data_t *pgdat;
int codepages = 0;
int datapages = 0;
int initpages = 0;
- unsigned long tmp;
-#ifndef CONFIG_SUN3
int i;
-#endif
-
- max_mapnr = num_physpages = (((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT);
#ifdef CONFIG_ATARI
if (MACH_IS_ATARI)
#endif
/* this will put all memory onto the freelists */
- totalram_pages = free_all_bootmem();
-
- for (tmp = PAGE_OFFSET ; tmp < (unsigned long)high_memory; tmp += PAGE_SIZE) {
- if (PageReserved(virt_to_page(tmp))) {
- if (tmp >= (unsigned long)&_text
- && tmp < (unsigned long)&_etext)
+ totalram_pages = num_physpages = 0;
+ for_each_online_pgdat(pgdat) {
+ num_physpages += pgdat->node_present_pages;
+
+ totalram_pages += free_all_bootmem_node(pgdat);
+ for (i = 0; i < pgdat->node_spanned_pages; i++) {
+ struct page *page = pgdat->node_mem_map + i;
+ char *addr = page_to_virt(page);
+
+ if (!PageReserved(page))
+ continue;
+ if (addr >= _text &&
+ addr < _etext)
codepages++;
- else if (tmp >= (unsigned long) &__init_begin
- && tmp < (unsigned long) &__init_end)
+ else if (addr >= __init_begin &&
+ addr < __init_end)
initpages++;
else
datapages++;
- continue;
}
}
printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
(unsigned long)nr_free_pages() << (PAGE_SHIFT-10),
- max_mapnr << (PAGE_SHIFT-10),
+ totalram_pages << (PAGE_SHIFT-10),
codepages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
initpages << (PAGE_SHIFT-10));
return 0;
}
-#ifdef DEBUG_INVALID_PTOV
-int mm_inv_cnt = 5;
-#endif
-
-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
-/*
- * The following two routines map from a physical address to a kernel
- * virtual address and vice versa.
- */
-unsigned long mm_vtop(unsigned long vaddr)
-{
- int i=0;
- unsigned long voff = (unsigned long)vaddr - PAGE_OFFSET;
-
- do {
- if (voff < m68k_memory[i].size) {
-#ifdef DEBUGPV
- printk ("VTOP(%p)=%lx\n", vaddr,
- m68k_memory[i].addr + voff);
-#endif
- return m68k_memory[i].addr + voff;
- }
- voff -= m68k_memory[i].size;
- } while (++i < m68k_num_memory);
-
- /* As a special case allow `__pa(high_memory)'. */
- if (voff == 0)
- return m68k_memory[i-1].addr + m68k_memory[i-1].size;
-
- return -1;
-}
-EXPORT_SYMBOL(mm_vtop);
-
-unsigned long mm_ptov (unsigned long paddr)
-{
- int i = 0;
- unsigned long poff, voff = PAGE_OFFSET;
-
- do {
- poff = paddr - m68k_memory[i].addr;
- if (poff < m68k_memory[i].size) {
-#ifdef DEBUGPV
- printk ("PTOV(%lx)=%lx\n", paddr, poff + voff);
-#endif
- return poff + voff;
- }
- voff += m68k_memory[i].size;
- } while (++i < m68k_num_memory);
-
-#ifdef DEBUG_INVALID_PTOV
- if (mm_inv_cnt > 0) {
- mm_inv_cnt--;
- printk("Invalid use of phys_to_virt(0x%lx) at 0x%p!\n",
- paddr, __builtin_return_address(0));
- }
-#endif
- return -1;
-}
-EXPORT_SYMBOL(mm_ptov);
-#endif
-
/* invalidate page in both caches */
static inline void clear040(unsigned long paddr)
{
}
EXPORT_SYMBOL(cache_push);
-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
-int mm_end_of_chunk (unsigned long addr, int len)
-{
- int i;
-
- for (i = 0; i < m68k_num_memory; i++)
- if (m68k_memory[i].addr + m68k_memory[i].size == addr + len)
- return 1;
- return 0;
-}
-EXPORT_SYMBOL(mm_end_of_chunk);
-#endif
EXPORT_SYMBOL(mm_cachebits);
#endif
+/* size of memory already mapped in head.S */
+#define INIT_MAPPED_SIZE (4UL<<20)
+
+extern unsigned long availmem;
+
static pte_t * __init kernel_page_table(void)
{
pte_t *ptablep;
return last_pgtable;
}
-static unsigned long __init
-map_chunk (unsigned long addr, long size)
+static void __init map_node(int node)
{
#define PTRTREESIZE (256*1024)
#define ROOTTREESIZE (32*1024*1024)
- static unsigned long virtaddr = PAGE_OFFSET;
- unsigned long physaddr;
+ unsigned long physaddr, virtaddr, size;
pgd_t *pgd_dir;
pmd_t *pmd_dir;
pte_t *pte_dir;
- physaddr = (addr | m68k_supervisor_cachemode |
- _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+ size = m68k_memory[node].size;
+ physaddr = m68k_memory[node].addr;
+ virtaddr = (unsigned long)phys_to_virt(physaddr);
+ physaddr |= m68k_supervisor_cachemode |
+ _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY;
if (CPU_IS_040_OR_060)
physaddr |= _PAGE_GLOBAL040;
#ifdef DEBUG
printk("\n");
#endif
-
- return virtaddr;
}
/*
*/
void __init paging_init(void)
{
- int chunk;
- unsigned long mem_avail = 0;
unsigned long zones_size[MAX_NR_ZONES] = { 0, };
+ unsigned long min_addr, max_addr;
+ unsigned long addr, size, end;
+ int i;
#ifdef DEBUG
{
extern unsigned long availmem;
- printk ("start of paging_init (%p, %lx, %lx, %lx)\n",
- kernel_pg_dir, availmem, start_mem, end_mem);
+ printk ("start of paging_init (%p, %lx)\n",
+ kernel_pg_dir, availmem);
}
#endif
pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
}
+ min_addr = m68k_memory[0].addr;
+ max_addr = min_addr + m68k_memory[0].size;
+ for (i = 1; i < m68k_num_memory;) {
+ if (m68k_memory[i].addr < min_addr) {
+ printk("Ignoring memory chunk at 0x%lx:0x%lx before the first chunk\n",
+ m68k_memory[i].addr, m68k_memory[i].size);
+ printk("Fix your bootloader or use a memfile to make use of this area!\n");
+ m68k_num_memory--;
+ memmove(m68k_memory + i, m68k_memory + i + 1,
+ (m68k_num_memory - i) * sizeof(struct mem_info));
+ continue;
+ }
+ addr = m68k_memory[i].addr + m68k_memory[i].size;
+ if (addr > max_addr)
+ max_addr = addr;
+ i++;
+ }
+ m68k_memoffset = min_addr - PAGE_OFFSET;
+ m68k_virt_to_node_shift = fls(max_addr - min_addr - 1) - 6;
+
+ module_fixup(NULL, __start_fixup, __stop_fixup);
+ flush_icache();
+
+ high_memory = phys_to_virt(max_addr);
+
+ min_low_pfn = availmem >> PAGE_SHIFT;
+ max_low_pfn = max_addr >> PAGE_SHIFT;
+
+ for (i = 0; i < m68k_num_memory; i++) {
+ addr = m68k_memory[i].addr;
+ end = addr + m68k_memory[i].size;
+ m68k_setup_node(i);
+ availmem = PAGE_ALIGN(availmem);
+ availmem += init_bootmem_node(NODE_DATA(i),
+ availmem >> PAGE_SHIFT,
+ addr >> PAGE_SHIFT,
+ end >> PAGE_SHIFT);
+ }
+
/*
* Map the physical memory available into the kernel virtual
- * address space. It may allocate some memory for page
- * tables and thus modify availmem.
+ * address space. First initialize the bootmem allocator with
+ * the memory we already mapped, so map_node() has something
+ * to allocate.
*/
+ addr = m68k_memory[0].addr;
+ size = m68k_memory[0].size;
+ free_bootmem_node(NODE_DATA(0), availmem, min(INIT_MAPPED_SIZE, size) - (availmem - addr));
+ map_node(0);
+ if (size > INIT_MAPPED_SIZE)
+ free_bootmem_node(NODE_DATA(0), addr + INIT_MAPPED_SIZE, size - INIT_MAPPED_SIZE);
- for (chunk = 0; chunk < m68k_num_memory; chunk++) {
- mem_avail = map_chunk (m68k_memory[chunk].addr,
- m68k_memory[chunk].size);
-
- }
+ for (i = 1; i < m68k_num_memory; i++)
+ map_node(i);
flush_tlb_all();
-#ifdef DEBUG
- printk ("memory available is %ldKB\n", mem_avail >> 10);
- printk ("start_mem is %#lx\nvirtual_end is %#lx\n",
- start_mem, end_mem);
-#endif
/*
* initialize the bad page table and bad page to point
#ifdef DEBUG
printk ("before free_area_init\n");
#endif
- zones_size[ZONE_DMA] = (mach_max_dma_address < (unsigned long)high_memory ?
- (mach_max_dma_address+1) : (unsigned long)high_memory);
- zones_size[ZONE_NORMAL] = (unsigned long)high_memory - zones_size[0];
-
- zones_size[ZONE_DMA] = (zones_size[ZONE_DMA] - PAGE_OFFSET) >> PAGE_SHIFT;
- zones_size[ZONE_NORMAL] >>= PAGE_SHIFT;
-
- free_area_init(zones_size);
+ for (i = 0; i < m68k_num_memory; i++) {
+ zones_size[ZONE_DMA] = m68k_memory[i].size >> PAGE_SHIFT;
+ free_area_init_node(i, pg_data_map + i, zones_size,
+ m68k_memory[i].addr >> PAGE_SHIFT, NULL);
+ }
}
extern char __init_begin, __init_end;
#include <asm/contregs.h>
#include <asm/movs.h>
#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
#include <asm/sun3-head.h>
#include <asm/sun3mmu.h>
#include <asm/rtc.h>
high_memory = (void *)memory_end;
availmem = memory_start;
+ m68k_setup_node(0);
availmem += init_bootmem_node(NODE_DATA(0), start_page, 0, num_pages);
availmem = (availmem + (PAGE_SIZE-1)) & PAGE_MASK;
depends on BUG
config SYS_SUPPORTS_APM_EMULATION
+ default y if PMAC_APM_EMU
bool
config DEFAULT_UIMAGE
interrupt-controller;
#interrupt-cells = <3>;
device_type = "interrupt-controller";
- compatible = "mpc5200_pic";
+ compatible = "mpc5200-pic";
reg = <500 80>;
built-in;
};
interrupt-controller;
#interrupt-cells = <3>;
device_type = "interrupt-controller";
- compatible = "mpc5200b-pic\0mpc5200_pic";
+ compatible = "mpc5200b-pic\0mpc5200-pic";
reg = <500 80>;
built-in;
};
free_pages((unsigned long)pgd, PGDIR_ORDER);
}
-pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+__init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
{
pte_t *pte;
extern int mem_init_done;
/***********/
/***********/
-int mv643xx_eth_add_pds(void)
+static int __init mv643xx_eth_add_pds(void)
{
int ret = 0;
static struct pci_device_id pci_marvell_mv64360[] = {
static dev_t boot_dev;
#ifdef CONFIG_SCSI
-void __init note_scsi_host(struct device_node *node, void *host)
+void note_scsi_host(struct device_node *node, void *host)
{
int l;
char *p;
config UCC_SLOW
bool
default n
- select UCC
help
This option provides qe_lib support to UCC slow
protocols: UART, BISYNC, QMC
config UCC_FAST
bool
- default n
- select UCC
+ default y if UCC_GETH
help
This option provides qe_lib support to UCC fast
protocols: HDLC, Ethernet, ATM, transparent
mr r12,r4 /* restart at exc_exit_restart */
b 2b
- .comm fee_restarts,4
+ .section .bss
+ .align 2
+fee_restarts:
+ .space 4
+ .previous
/* aargh, a nonrecoverable interrupt, panic */
/* aargh, we don't know which trap this is */
mtspr SPRN_DBSR,r11 /* clear all pending debug events */
blr
- .comm global_dbcr0,8
+ .section .bss
+ .align 4
+global_dbcr0:
+ .space 8
+ .previous
#endif /* !(CONFIG_4xx || CONFIG_BOOKE) */
do_work: /* r10 contains MSR_KERNEL here */
/* shouldn't return */
b 4b
- .comm ee_restarts,4
+ .section .bss
+ .align 2
+ee_restarts:
+ .space 4
+ .previous
#include <asm/time.h>
#include <asm/cputable.h>
#include <asm/btext.h>
-#include <asm/div64.h>
#include <asm/xmon.h>
#include <asm/signal.h>
#include <asm/dcr.h>
EXPORT_SYMBOL(strcat);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(__div64_32);
EXPORT_SYMBOL(csum_partial);
EXPORT_SYMBOL(csum_partial_copy_generic);
#include <asm/asm-offsets.h>
#ifdef CONFIG_SMP
- .comm mmu_hash_lock,4
+ .section .bss
+ .align 2
+ .globl mmu_hash_lock
+mmu_hash_lock:
+ .space 4
#endif /* CONFIG_SMP */
/*
sync /* make sure pte updates get to memory */
blr
- .comm next_slot,4
- .comm primary_pteg_full,4
- .comm htab_hash_searches,4
+ .section .bss
+ .align 2
+next_slot:
+ .space 4
+ .globl primary_pteg_full
+primary_pteg_full:
+ .space 4
+ .globl htab_hash_searches
+htab_hash_searches:
+ .space 4
+ .previous
/*
* Flush the entry for a particular page from the hash table.
free_pages((unsigned long)pgd, PGDIR_ORDER);
}
-pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+__init_refok pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
{
pte_t *pte;
extern int mem_init_done;
/* Diagnose 224 functions */
-static void diag224(void *ptr)
+static int diag224(void *ptr)
{
- asm volatile("diag %0,%1,0x224" : :"d" (0), "d"(ptr) : "memory");
+ int rc = -ENOTSUPP;
+
+ asm volatile(
+ " diag %1,%2,0x224\n"
+ "0: lhi %0,0x0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "+d" (rc) :"d" (0), "d" (ptr) : "memory");
+ return rc;
}
static int diag224_get_name_table(void)
diag224_cpu_names = kmalloc(PAGE_SIZE, GFP_KERNEL | GFP_DMA);
if (!diag224_cpu_names)
return -ENOMEM;
- diag224(diag224_cpu_names);
+ if (diag224(diag224_cpu_names)) {
+ kfree(diag224_cpu_names);
+ return -ENOTSUPP;
+ }
EBCASC(diag224_cpu_names + 16, (*diag224_cpu_names + 1) * 16);
return 0;
}
static debug_info_t *debug_area_first = NULL;
static debug_info_t *debug_area_last = NULL;
-static DECLARE_MUTEX(debug_lock);
+static DEFINE_MUTEX(debug_mutex);
static int initialized;
int rc = 0;
file_private_info_t *p_info;
- down(&debug_lock);
+ mutex_lock(&debug_mutex);
p_info = ((file_private_info_t *) file->private_data);
if (p_info->view->input_proc)
rc = p_info->view->input_proc(p_info->debug_info_org,
length, offset);
else
rc = -EPERM;
- up(&debug_lock);
+ mutex_unlock(&debug_mutex);
return rc; /* number of input characters */
}
file_private_info_t *p_info;
debug_info_t *debug_info, *debug_info_snapshot;
- down(&debug_lock);
+ mutex_lock(&debug_mutex);
debug_info = file->f_path.dentry->d_inode->i_private;
/* find debug view */
for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
file->private_data = p_info;
debug_info_get(debug_info);
out:
- up(&debug_lock);
+ mutex_unlock(&debug_mutex);
return rc;
}
if (!initialized)
BUG();
- down(&debug_lock);
+ mutex_lock(&debug_mutex);
/* create new debug_info */
if (!rc){
printk(KERN_ERR "debug: debug_register failed for %s\n",name);
}
- up(&debug_lock);
+ mutex_unlock(&debug_mutex);
return rc;
}
{
if (!id)
goto out;
- down(&debug_lock);
+ mutex_lock(&debug_mutex);
debug_info_put(id);
- up(&debug_lock);
+ mutex_unlock(&debug_mutex);
out:
return;
int rc = 0;
s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table);
- down(&debug_lock);
+ mutex_lock(&debug_mutex);
debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL);
printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1;
- up(&debug_lock);
+ mutex_unlock(&debug_mutex);
return rc;
}
/*
* cpu_init() initializes state that is per-CPU.
*/
-void __devinit cpu_init (void)
+void __cpuinit cpu_init(void)
{
int addr = hard_smp_processor_id();
setup_zfcpdump(console_devno);
}
-void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
+void __cpuinit print_cpu_info(struct cpuinfo_S390 *cpuinfo)
{
printk("cpu %d "
#ifdef CONFIG_SMP
/*
* Activate a secondary processor.
*/
-int __devinit start_secondary(void *cpuvoid)
+int __cpuinit start_secondary(void *cpuvoid)
{
/* Setup the cpu */
cpu_init();
smp_create_idle(cpu);
}
-void __devinit smp_prepare_boot_cpu(void)
+void __init smp_prepare_boot_cpu(void)
{
BUG_ON(smp_processor_id() != 0);
current_set[0] = current;
}
-void smp_cpus_done(unsigned int max_cpus)
+void __init smp_cpus_done(unsigned int max_cpus)
{
cpu_present_map = cpu_possible_map;
}
cflags-$(CONFIG_CPU_SH3) := -m3
cflags-$(CONFIG_CPU_SH4) := -m4 \
$(call cc-option,-mno-implicit-fp,-m4-nofpu)
-cflags-$(CONFIG_CPU_SH4A) := -m4a $(call cc-option,-m4a-nofpu,)
+cflags-$(CONFIG_CPU_SH4A) := $(call cc-option,-m4a,) $(call cc-option,-m4a-nofpu,)
cflags-$(CONFIG_CPU_BIG_ENDIAN) += -mb
cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/mm.h>
+#include <linux/sched.h>
#include <asm/dma.h>
DEFINE_SPINLOCK(dma_spin_lock);
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/irq.h>
ctrl_outb(0x42, PA_MRSHPC_MW2 + 0x200);
return 0;
}
+#else
+static int __init cf_init_se(void)
+{
+ return -1;
+}
#endif
int __init cf_init(void)
.align 2
5: .long 0x00001000 ! DSP
+6: .long in_nmi
7: .long 0x30000000
! common exception handler
*/
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/smp.h>
#include <asm/processor.h>
#include <asm/cache.h>
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
+
+#include <linux/err.h>
#include <linux/cache.h>
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <asm/timer.h>
-static struct sys_timer *sys_timers[] __initdata = {
+static struct sys_timer *sys_timers[] = {
#ifdef CONFIG_SH_TMU
&tmu_timer,
#endif
NULL,
};
-static char timer_override[10] __initdata;
+static char timer_override[10];
static int __init timer_setup(char *str)
{
if (str)
return NULL;
}
-
#include <linux/gfp.h>
#include <linux/module.h>
#include <linux/elf.h>
+#include <linux/sched.h>
/*
* Should the kernel map a VDSO page into processes and pass its
bool
default n
+config EMULATED_CMPXCHG
+ bool
+ default y
+ help
+ Sparc32 does not have a CAS instruction like sparc64. cmpxchg()
+ is emulated, and therefore it is not completely atomic.
+
config SUN_PM
bool
default y
}
/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void __init kick_start_clock(void)
+static void __devinit kick_start_clock(void)
{
struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
unsigned char sec;
return (data1 == data2); /* Was the write blocked? */
}
-static void __init mostek_set_system_time(void)
+static void __devinit mostek_set_system_time(void)
{
unsigned int year, mon, day, hour, min, sec;
struct mostek48t02 *mregs;
* atomic32.c: 32-bit atomic_t implementation
*
* Copyright (C) 2004 Keith M Wesolowski
+ * Copyright (C) 2007 Kyle McMartin
*
* Based on asm-parisc/atomic.h Copyright (C) 2000 Philipp Rumpf
*/
return old & mask;
}
EXPORT_SYMBOL(___change_bit);
+
+unsigned long __cmpxchg_u32(volatile u32 *ptr, u32 old, u32 new)
+{
+ unsigned long flags;
+ u32 prev;
+
+ spin_lock_irqsave(ATOMIC_HASH(ptr), flags);
+ if ((prev = *ptr) == old)
+ *ptr = new;
+ spin_unlock_irqrestore(ATOMIC_HASH(ptr), flags);
+
+ return (unsigned long)prev;
+}
+EXPORT_SYMBOL(__cmpxchg_u32);
If you don't know what to do here, say N.
config NR_CPUS
- int "Maximum number of CPUs (2-64)"
- range 2 64
+ int "Maximum number of CPUs (2-1024)"
+ range 2 1024
depends on SMP
- default "32"
+ default "64"
source "drivers/cpufreq/Kconfig"
extra-y := head.o init_task.o vmlinux.lds
obj-y := process.o setup.o cpu.o idprom.o \
- traps.o devices.o auxio.o una_asm.o \
+ traps.o auxio.o una_asm.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
unaligned.o central.o pci.o starfire.o semaphore.o \
power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
- visemul.o prom.o of_device.o hvapi.o
+ visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
+++ /dev/null
-/* devices.c: Initial scan of the prom device tree for important
- * Sparc device nodes which we need to find.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/threads.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/bootmem.h>
-
-#include <asm/page.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/smp.h>
-#include <asm/spitfire.h>
-#include <asm/timer.h>
-#include <asm/cpudata.h>
-
-/* Used to synchronize accesses to NatSemi SUPER I/O chip configure
- * operations in asm/ns87303.h
- */
-DEFINE_SPINLOCK(ns87303_lock);
-
-extern void cpu_probe(void);
-extern void central_probe(void);
-
-static const char *cpu_mid_prop(void)
-{
- if (tlb_type == spitfire)
- return "upa-portid";
- return "portid";
-}
-
-static int get_cpu_mid(struct device_node *dp)
-{
- struct property *prop;
-
- if (tlb_type == hypervisor) {
- struct linux_prom64_registers *reg;
- int len;
-
- prop = of_find_property(dp, "cpuid", &len);
- if (prop && len == 4)
- return *(int *) prop->value;
-
- prop = of_find_property(dp, "reg", NULL);
- reg = prop->value;
- return (reg[0].phys_addr >> 32) & 0x0fffffffUL;
- } else {
- const char *prop_name = cpu_mid_prop();
-
- prop = of_find_property(dp, prop_name, NULL);
- if (prop)
- return *(int *) prop->value;
- return 0;
- }
-}
-
-static int check_cpu_node(struct device_node *dp, int *cur_inst,
- int (*compare)(struct device_node *, int, void *),
- void *compare_arg,
- struct device_node **dev_node, int *mid)
-{
- if (!compare(dp, *cur_inst, compare_arg)) {
- if (dev_node)
- *dev_node = dp;
- if (mid)
- *mid = get_cpu_mid(dp);
- return 0;
- }
-
- (*cur_inst)++;
-
- return -ENODEV;
-}
-
-static int __cpu_find_by(int (*compare)(struct device_node *, int, void *),
- void *compare_arg,
- struct device_node **dev_node, int *mid)
-{
- struct device_node *dp;
- int cur_inst;
-
- cur_inst = 0;
- for_each_node_by_type(dp, "cpu") {
- int err = check_cpu_node(dp, &cur_inst,
- compare, compare_arg,
- dev_node, mid);
- if (err == 0)
- return 0;
- }
-
- return -ENODEV;
-}
-
-static int cpu_instance_compare(struct device_node *dp, int instance, void *_arg)
-{
- int desired_instance = (int) (long) _arg;
-
- if (instance == desired_instance)
- return 0;
- return -ENODEV;
-}
-
-int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid)
-{
- return __cpu_find_by(cpu_instance_compare, (void *)(long)instance,
- dev_node, mid);
-}
-
-static int cpu_mid_compare(struct device_node *dp, int instance, void *_arg)
-{
- int desired_mid = (int) (long) _arg;
- int this_mid;
-
- this_mid = get_cpu_mid(dp);
- if (this_mid == desired_mid)
- return 0;
- return -ENODEV;
-}
-
-int cpu_find_by_mid(int mid, struct device_node **dev_node)
-{
- return __cpu_find_by(cpu_mid_compare, (void *)(long)mid,
- dev_node, NULL);
-}
-
-void __init device_scan(void)
-{
- /* FIX ME FAST... -DaveM */
- ioport_resource.end = 0xffffffffffffffffUL;
-
- prom_printf("Booting Linux...\n");
-
-#ifndef CONFIG_SMP
- {
- struct device_node *dp;
- int err, def;
-
- err = cpu_find_by_instance(0, &dp, NULL);
- if (err) {
- prom_printf("No cpu nodes, cannot continue\n");
- prom_halt();
- }
- cpu_data(0).clock_tick =
- of_getintprop_default(dp, "clock-frequency", 0);
-
- def = ((tlb_type == hypervisor) ?
- (8 * 1024) :
- (16 * 1024));
- cpu_data(0).dcache_size = of_getintprop_default(dp,
- "dcache-size",
- def);
-
- def = 32;
- cpu_data(0).dcache_line_size =
- of_getintprop_default(dp, "dcache-line-size", def);
-
- def = 16 * 1024;
- cpu_data(0).icache_size = of_getintprop_default(dp,
- "icache-size",
- def);
-
- def = 32;
- cpu_data(0).icache_line_size =
- of_getintprop_default(dp, "icache-line-size", def);
-
- def = ((tlb_type == hypervisor) ?
- (3 * 1024 * 1024) :
- (4 * 1024 * 1024));
- cpu_data(0).ecache_size = of_getintprop_default(dp,
- "ecache-size",
- def);
-
- def = 64;
- cpu_data(0).ecache_line_size =
- of_getintprop_default(dp, "ecache-line-size", def);
- printk("CPU[0]: Caches "
- "D[sz(%d):line_sz(%d)] "
- "I[sz(%d):line_sz(%d)] "
- "E[sz(%d):line_sz(%d)]\n",
- cpu_data(0).dcache_size, cpu_data(0).dcache_line_size,
- cpu_data(0).icache_size, cpu_data(0).icache_line_size,
- cpu_data(0).ecache_size, cpu_data(0).ecache_line_size);
- }
-#endif
-
- central_probe();
-
- cpu_probe();
-}
* returns %o0: sysino
*/
.globl sun4v_devino_to_sysino
+ .type sun4v_devino_to_sysino,#function
sun4v_devino_to_sysino:
mov HV_FAST_INTR_DEVINO2SYSINO, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
+ .size sun4v_devino_to_sysino, .-sun4v_devino_to_sysino
/* %o0: sysino
*
* returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED})
*/
.globl sun4v_intr_getenabled
+ .type sun4v_intr_getenabled,#function
sun4v_intr_getenabled:
mov HV_FAST_INTR_GETENABLED, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
+ .size sun4v_intr_getenabled, .-sun4v_intr_getenabled
/* %o0: sysino
* %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED})
*/
.globl sun4v_intr_setenabled
+ .type sun4v_intr_setenabled,#function
sun4v_intr_setenabled:
mov HV_FAST_INTR_SETENABLED, %o5
ta HV_FAST_TRAP
retl
nop
+ .size sun4v_intr_setenabled, .-sun4v_intr_setenabled
/* %o0: sysino
*
* returns %o0: intr_state (HV_INTR_STATE_*)
*/
.globl sun4v_intr_getstate
+ .type sun4v_intr_getstate,#function
sun4v_intr_getstate:
mov HV_FAST_INTR_GETSTATE, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
+ .size sun4v_intr_getstate, .-sun4v_intr_getstate
/* %o0: sysino
* %o1: intr_state (HV_INTR_STATE_*)
*/
.globl sun4v_intr_setstate
+ .type sun4v_intr_setstate,#function
sun4v_intr_setstate:
mov HV_FAST_INTR_SETSTATE, %o5
ta HV_FAST_TRAP
retl
nop
+ .size sun4v_intr_setstate, .-sun4v_intr_setstate
/* %o0: sysino
*
* returns %o0: cpuid
*/
.globl sun4v_intr_gettarget
+ .type sun4v_intr_gettarget,#function
sun4v_intr_gettarget:
mov HV_FAST_INTR_GETTARGET, %o5
ta HV_FAST_TRAP
retl
mov %o1, %o0
+ .size sun4v_intr_gettarget, .-sun4v_intr_gettarget
/* %o0: sysino
* %o1: cpuid
*/
.globl sun4v_intr_settarget
+ .type sun4v_intr_settarget,#function
sun4v_intr_settarget:
mov HV_FAST_INTR_SETTARGET, %o5
ta HV_FAST_TRAP
retl
nop
+ .size sun4v_intr_settarget, .-sun4v_intr_settarget
- /* %o0: type
- * %o1: queue paddr
- * %o2: num queue entries
+ /* %o0: cpuid
+ * %o1: pc
+ * %o2: rtba
+ * %o3: arg0
*
* returns %o0: status
*/
- .globl sun4v_cpu_qconf
-sun4v_cpu_qconf:
- mov HV_FAST_CPU_QCONF, %o5
+ .globl sun4v_cpu_start
+ .type sun4v_cpu_start,#function
+sun4v_cpu_start:
+ mov HV_FAST_CPU_START, %o5
ta HV_FAST_TRAP
retl
nop
+ .size sun4v_cpu_start, .-sun4v_cpu_start
- /* returns %o0: status
+ /* %o0: cpuid
+ *
+ * returns %o0: status
*/
+ .globl sun4v_cpu_stop
+ .type sun4v_cpu_stop,#function
+sun4v_cpu_stop:
+ mov HV_FAST_CPU_STOP, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_cpu_stop, .-sun4v_cpu_stop
+
+ /* returns %o0: status */
.globl sun4v_cpu_yield
+ .type sun4v_cpu_yield, #function
sun4v_cpu_yield:
mov HV_FAST_CPU_YIELD, %o5
ta HV_FAST_TRAP
retl
nop
+ .size sun4v_cpu_yield, .-sun4v_cpu_yield
+
+ /* %o0: type
+ * %o1: queue paddr
+ * %o2: num queue entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_cpu_qconf
+ .type sun4v_cpu_qconf,#function
+sun4v_cpu_qconf:
+ mov HV_FAST_CPU_QCONF, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_cpu_qconf, .-sun4v_cpu_qconf
/* %o0: num cpus in cpu list
* %o1: cpu list paddr
* returns %o0: status
*/
.globl sun4v_cpu_mondo_send
+ .type sun4v_cpu_mondo_send,#function
sun4v_cpu_mondo_send:
mov HV_FAST_CPU_MONDO_SEND, %o5
ta HV_FAST_TRAP
retl
nop
+ .size sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send
/* %o0: CPU ID
*
* %o0: cpu state as HV_CPU_STATE_*
*/
.globl sun4v_cpu_state
+ .type sun4v_cpu_state,#function
sun4v_cpu_state:
mov HV_FAST_CPU_STATE, %o5
ta HV_FAST_TRAP
mov %o1, %o0
1: retl
nop
+ .size sun4v_cpu_state, .-sun4v_cpu_state
+
+ /* %o0: virtual address
+ * %o1: must be zero
+ * %o2: TTE
+ * %o3: HV_MMU_* flags
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_mmu_map_perm_addr
+ .type sun4v_mmu_map_perm_addr,#function
+sun4v_mmu_map_perm_addr:
+ mov HV_FAST_MMU_MAP_PERM_ADDR, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr
+
+ /* %o0: number of TSB descriptions
+ * %o1: TSB descriptions real address
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_mmu_tsb_ctx0
+ .type sun4v_mmu_tsb_ctx0,#function
+sun4v_mmu_tsb_ctx0:
+ mov HV_FAST_MMU_TSB_CTX0, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0
/* %o0: API group number
* %o1: pointer to unsigned long major number storage
* returns %o0: status
*/
.globl sun4v_get_version
+ .type sun4v_get_version,#function
sun4v_get_version:
mov HV_CORE_GET_VER, %o5
mov %o1, %o3
stx %o1, [%o3]
retl
stx %o2, [%o4]
+ .size sun4v_get_version, .-sun4v_get_version
/* %o0: API group number
* %o1: desired major number
* returns %o0: status
*/
.globl sun4v_set_version
+ .type sun4v_set_version,#function
sun4v_set_version:
mov HV_CORE_SET_VER, %o5
mov %o3, %o4
ta HV_CORE_TRAP
retl
stx %o1, [%o4]
+ .size sun4v_set_version, .-sun4v_set_version
+
+ /* %o0: pointer to unsigned long time
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_tod_get
+ .type sun4v_tod_get,#function
+sun4v_tod_get:
+ mov %o0, %o4
+ mov HV_FAST_TOD_GET, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_tod_get, .-sun4v_tod_get
+
+ /* %o0: time
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_tod_set
+ .type sun4v_tod_set,#function
+sun4v_tod_set:
+ mov HV_FAST_TOD_SET, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_tod_set, .-sun4v_tod_set
/* %o0: pointer to unsigned long status
*
* returns %o0: signed character
*/
.globl sun4v_con_getchar
+ .type sun4v_con_getchar,#function
sun4v_con_getchar:
mov %o0, %o4
mov HV_FAST_CONS_GETCHAR, %o5
stx %o0, [%o4]
retl
sra %o1, 0, %o0
+ .size sun4v_con_getchar, .-sun4v_con_getchar
/* %o0: signed long character
*
* returns %o0: status
*/
.globl sun4v_con_putchar
+ .type sun4v_con_putchar,#function
sun4v_con_putchar:
mov HV_FAST_CONS_PUTCHAR, %o5
ta HV_FAST_TRAP
retl
sra %o0, 0, %o0
+ .size sun4v_con_putchar, .-sun4v_con_putchar
/* %o0: buffer real address
* %o1: buffer size
* returns %o0: status
*/
.globl sun4v_con_read
+ .type sun4v_con_read,#function
sun4v_con_read:
mov %o2, %o4
mov HV_FAST_CONS_READ, %o5
stx %o1, [%o4]
1: retl
nop
+ .size sun4v_con_read, .-sun4v_con_read
/* %o0: buffer real address
* %o1: buffer size
* returns %o0: status
*/
.globl sun4v_con_write
+ .type sun4v_con_write,#function
sun4v_con_write:
mov %o2, %o4
mov HV_FAST_CONS_WRITE, %o5
stx %o1, [%o4]
retl
nop
+ .size sun4v_con_write, .-sun4v_con_write
+
+ /* %o0: soft state
+ * %o1: address of description string
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_mach_set_soft_state
+ .type sun4v_mach_set_soft_state,#function
+sun4v_mach_set_soft_state:
+ mov HV_FAST_MACH_SET_SOFT_STATE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state
+
+ /* %o0: exit code
+ *
+ * Does not return.
+ */
+ .globl sun4v_mach_exit
+ .type sun4v_mach_exit,#function
+sun4v_mach_exit:
+ mov HV_FAST_MACH_EXIT, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_mach_exit, .-sun4v_mach_exit
+
+ /* %o0: buffer real address
+ * %o1: buffer length
+ * %o2: pointer to unsigned long real_buf_len
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_mach_desc
+ .type sun4v_mach_desc,#function
+sun4v_mach_desc:
+ mov %o2, %o4
+ mov HV_FAST_MACH_DESC, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_mach_desc, .-sun4v_mach_desc
+
+ /* %o0: new timeout in milliseconds
+ * %o1: pointer to unsigned long orig_timeout
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_mach_set_watchdog
+ .type sun4v_mach_set_watchdog,#function
+sun4v_mach_set_watchdog:
+ mov %o1, %o4
+ mov HV_FAST_MACH_SET_WATCHDOG, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog
+
+ /* No inputs and does not return. */
+ .globl sun4v_mach_sir
+ .type sun4v_mach_sir,#function
+sun4v_mach_sir:
+ mov %o1, %o4
+ mov HV_FAST_MACH_SIR, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_mach_sir, .-sun4v_mach_sir
+
+ /* %o0: channel
+ * %o1: ra
+ * %o2: num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_tx_qconf
+ .type sun4v_ldc_tx_qconf,#function
+sun4v_ldc_tx_qconf:
+ mov HV_FAST_LDC_TX_QCONF, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long ra
+ * %o2: pointer to unsigned long num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_tx_qinfo
+ .type sun4v_ldc_tx_qinfo,#function
+sun4v_ldc_tx_qinfo:
+ mov %o1, %g1
+ mov %o2, %g2
+ mov HV_FAST_LDC_TX_QINFO, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ .size sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long head_off
+ * %o2: pointer to unsigned long tail_off
+ * %o2: pointer to unsigned long chan_state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_tx_get_state
+ .type sun4v_ldc_tx_get_state,#function
+sun4v_ldc_tx_get_state:
+ mov %o1, %g1
+ mov %o2, %g2
+ mov %o3, %g3
+ mov HV_FAST_LDC_TX_GET_STATE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ stx %o3, [%g3]
+ retl
+ nop
+ .size sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state
+
+ /* %o0: channel
+ * %o1: tail_off
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_tx_set_qtail
+ .type sun4v_ldc_tx_set_qtail,#function
+sun4v_ldc_tx_set_qtail:
+ mov HV_FAST_LDC_TX_SET_QTAIL, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail
+
+ /* %o0: channel
+ * %o1: ra
+ * %o2: num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_rx_qconf
+ .type sun4v_ldc_rx_qconf,#function
+sun4v_ldc_rx_qconf:
+ mov HV_FAST_LDC_RX_QCONF, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long ra
+ * %o2: pointer to unsigned long num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_rx_qinfo
+ .type sun4v_ldc_rx_qinfo,#function
+sun4v_ldc_rx_qinfo:
+ mov %o1, %g1
+ mov %o2, %g2
+ mov HV_FAST_LDC_RX_QINFO, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ .size sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long head_off
+ * %o2: pointer to unsigned long tail_off
+ * %o2: pointer to unsigned long chan_state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_rx_get_state
+ .type sun4v_ldc_rx_get_state,#function
+sun4v_ldc_rx_get_state:
+ mov %o1, %g1
+ mov %o2, %g2
+ mov %o3, %g3
+ mov HV_FAST_LDC_RX_GET_STATE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ stx %o3, [%g3]
+ retl
+ nop
+ .size sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state
+
+ /* %o0: channel
+ * %o1: head_off
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_rx_set_qhead
+ .type sun4v_ldc_rx_set_qhead,#function
+sun4v_ldc_rx_set_qhead:
+ mov HV_FAST_LDC_RX_SET_QHEAD, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead
+
+ /* %o0: channel
+ * %o1: ra
+ * %o2: num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_set_map_table
+ .type sun4v_ldc_set_map_table,#function
+sun4v_ldc_set_map_table:
+ mov HV_FAST_LDC_SET_MAP_TABLE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long ra
+ * %o2: pointer to unsigned long num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_get_map_table
+ .type sun4v_ldc_get_map_table,#function
+sun4v_ldc_get_map_table:
+ mov %o1, %g1
+ mov %o2, %g2
+ mov HV_FAST_LDC_GET_MAP_TABLE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ .size sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table
+
+ /* %o0: channel
+ * %o1: dir_code
+ * %o2: tgt_raddr
+ * %o3: lcl_raddr
+ * %o4: len
+ * %o5: pointer to unsigned long actual_len
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_copy
+ .type sun4v_ldc_copy,#function
+sun4v_ldc_copy:
+ mov %o5, %g1
+ mov HV_FAST_LDC_COPY, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ .size sun4v_ldc_copy, .-sun4v_ldc_copy
+
+ /* %o0: channel
+ * %o1: cookie
+ * %o2: pointer to unsigned long ra
+ * %o3: pointer to unsigned long perm
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_mapin
+ .type sun4v_ldc_mapin,#function
+sun4v_ldc_mapin:
+ mov %o2, %g1
+ mov %o3, %g2
+ mov HV_FAST_LDC_MAPIN, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ .size sun4v_ldc_mapin, .-sun4v_ldc_mapin
+
+ /* %o0: ra
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_unmap
+ .type sun4v_ldc_unmap,#function
+sun4v_ldc_unmap:
+ mov HV_FAST_LDC_UNMAP, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_unmap, .-sun4v_ldc_unmap
+
+ /* %o0: cookie
+ * %o1: mte_cookie
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_revoke
+ .type sun4v_ldc_revoke,#function
+sun4v_ldc_revoke:
+ mov HV_FAST_LDC_REVOKE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_revoke, .-sun4v_ldc_revoke
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long cookie
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_get_cookie
+ .type sun4v_vintr_get_cookie,#function
+sun4v_vintr_get_cookie:
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_COOKIE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ .size sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: cookie
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_set_cookie
+ .type sun4v_vintr_set_cookie,#function
+sun4v_vintr_set_cookie:
+ mov HV_FAST_VINTR_SET_COOKIE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long valid_state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_get_valid
+ .type sun4v_vintr_get_valid,#function
+sun4v_vintr_get_valid:
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_VALID, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ .size sun4v_vintr_get_valid, .-sun4v_vintr_get_valid
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: valid_state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_set_valid
+ .type sun4v_vintr_set_valid,#function
+sun4v_vintr_set_valid:
+ mov HV_FAST_VINTR_SET_VALID, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_vintr_set_valid, .-sun4v_vintr_set_valid
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_get_state
+ .type sun4v_vintr_get_state,#function
+sun4v_vintr_get_state:
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_STATE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ .size sun4v_vintr_get_state, .-sun4v_vintr_get_state
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_set_state
+ .type sun4v_vintr_set_state,#function
+sun4v_vintr_set_state:
+ mov HV_FAST_VINTR_SET_STATE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_vintr_set_state, .-sun4v_vintr_set_state
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long cpuid
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_get_target
+ .type sun4v_vintr_get_target,#function
+sun4v_vintr_get_target:
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_TARGET, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ .size sun4v_vintr_get_target, .-sun4v_vintr_get_target
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: cpuid
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_set_target
+ .type sun4v_vintr_set_target,#function
+sun4v_vintr_set_target:
+ mov HV_FAST_VINTR_SET_TARGET, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_vintr_set_target, .-sun4v_vintr_set_target
+
+ /* %o0: NCS sub-function
+ * %o1: sub-function arg real-address
+ * %o2: sub-function arg size
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ncs_request
+ .type sun4v_ncs_request,#function
+sun4v_ncs_request:
+ mov HV_FAST_NCS_REQUEST, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ncs_request, .-sun4v_ncs_request
+
+ .globl sun4v_scv_send
+ .type sun4v_scv_send,#function
+sun4v_scv_send:
+ save %sp, -192, %sp
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov HV_FAST_SVC_SEND, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%i3]
+ ret
+ restore
+ .size sun4v_scv_send, .-sun4v_scv_send
+
+ .globl sun4v_scv_recv
+ .type sun4v_scv_recv,#function
+sun4v_scv_recv:
+ save %sp, -192, %sp
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov HV_FAST_SVC_RECV, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%i3]
+ ret
+ restore
+ .size sun4v_scv_recv, .-sun4v_scv_recv
+
+ .globl sun4v_scv_getstatus
+ .type sun4v_scv_getstatus,#function
+sun4v_scv_getstatus:
+ mov HV_FAST_SVC_GETSTATUS, %o5
+ mov %o1, %o4
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_scv_getstatus, .-sun4v_scv_getstatus
+
+ .globl sun4v_scv_setstatus
+ .type sun4v_scv_setstatus,#function
+sun4v_scv_setstatus:
+ mov HV_FAST_SVC_SETSTATUS, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_scv_setstatus, .-sun4v_scv_setstatus
+
+ .globl sun4v_scv_clrstatus
+ .type sun4v_scv_clrstatus,#function
+sun4v_scv_clrstatus:
+ mov HV_FAST_SVC_CLRSTATUS, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_scv_clrstatus, .-sun4v_scv_clrstatus
#else
mov 0, %o0
#endif
- stb %o0, [%g6 + TI_CPU]
+ sth %o0, [%g6 + TI_CPU]
/* Off we go.... */
call start_kernel
restore
sparc64_boot_end:
-#include "ktlb.S"
-#include "tsb.S"
#include "etrap.S"
#include "rtrap.S"
#include "winfixup.S"
#include "entry.S"
#include "sun4v_tlb_miss.S"
#include "sun4v_ivec.S"
+#include "ktlb.S"
+#include "tsb.S"
/*
* The following skip makes sure the trap table in ttable.S is aligned
* on a 32K boundary as required by the v9 specs for TBA register.
*
* We align to a 32K boundary, then we have the 32K kernel TSB,
- * then the 32K aligned trap table.
+ * the 64K kernel 4MB TSB, and then the 32K aligned trap table.
*/
1:
.skip 0x4000 + _start - 1b
+! 0x0000000000408000
+
.globl swapper_tsb
swapper_tsb:
.skip (32 * 1024)
-! 0x0000000000408000
+ .globl swapper_4m_tsb
+swapper_4m_tsb:
+ .skip (64 * 1024)
+
+! 0x0000000000420000
+ /* Some care needs to be exercised if you try to move the
+ * location of the trap table relative to other things. For
+ * one thing there are br* instructions in some of the
+ * trap table entires which branch back to code in ktlb.S
+ * Those instructions can only handle a signed 16-bit
+ * displacement.
+ *
+ * There is a binutils bug (bugzilla #4558) which causes
+ * the relocation overflow checks for such instructions to
+ * not be done correctly. So bintuils will not notice the
+ * error and will instead write junk into the relocation and
+ * you'll have an unbootable kernel.
+ */
#include "ttable.S"
+! 0x0000000000428000
+
#include "systbls.S"
.data
#include <asm/hypervisor.h>
#include <asm/oplib.h>
+#include <asm/sstate.h>
/* If the hypervisor indicates that the API setting
* calls are unsupported, by returning HV_EBADTRAP or
p->minor = actual_minor;
ret = 0;
} else if (hv_ret == HV_EBADTRAP ||
- HV_ENOTSUPPORTED) {
+ hv_ret == HV_ENOTSUPPORTED) {
if (p->flags & FLAG_PRE_API) {
if (major == 1) {
p->major = 1;
if (sun4v_hvapi_register(group, major, &minor))
goto bad;
+ sun4v_sstate_init();
+
return;
bad:
return 0;
}
-extern unsigned long real_hard_smp_processor_id(void);
-
static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid)
{
unsigned int tid;
trap_block[cpu].irq_worklist = 0;
}
-static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type)
+/* Please be very careful with register_one_mondo() and
+ * sun4v_register_mondo_queues().
+ *
+ * On SMP this gets invoked from the CPU trampoline before
+ * the cpu has fully taken over the trap table from OBP,
+ * and it's kernel stack + %g6 thread register state is
+ * not fully cooked yet.
+ *
+ * Therefore you cannot make any OBP calls, not even prom_printf,
+ * from these two routines.
+ */
+static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type, unsigned long qmask)
{
- unsigned long num_entries = 128;
+ unsigned long num_entries = (qmask + 1) / 64;
unsigned long status;
status = sun4v_cpu_qconf(type, paddr, num_entries);
{
struct trap_per_cpu *tb = &trap_block[this_cpu];
- register_one_mondo(tb->cpu_mondo_pa, HV_CPU_QUEUE_CPU_MONDO);
- register_one_mondo(tb->dev_mondo_pa, HV_CPU_QUEUE_DEVICE_MONDO);
- register_one_mondo(tb->resum_mondo_pa, HV_CPU_QUEUE_RES_ERROR);
- register_one_mondo(tb->nonresum_mondo_pa, HV_CPU_QUEUE_NONRES_ERROR);
+ register_one_mondo(tb->cpu_mondo_pa, HV_CPU_QUEUE_CPU_MONDO,
+ tb->cpu_mondo_qmask);
+ register_one_mondo(tb->dev_mondo_pa, HV_CPU_QUEUE_DEVICE_MONDO,
+ tb->dev_mondo_qmask);
+ register_one_mondo(tb->resum_mondo_pa, HV_CPU_QUEUE_RES_ERROR,
+ tb->resum_qmask);
+ register_one_mondo(tb->nonresum_mondo_pa, HV_CPU_QUEUE_NONRES_ERROR,
+ tb->nonresum_qmask);
}
-static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, int use_bootmem)
+static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem)
{
- void *page;
+ unsigned long size = PAGE_ALIGN(qmask + 1);
+ unsigned long order = get_order(size);
+ void *p = NULL;
- if (use_bootmem)
- page = alloc_bootmem_low_pages(PAGE_SIZE);
- else
- page = (void *) get_zeroed_page(GFP_ATOMIC);
+ if (use_bootmem) {
+ p = __alloc_bootmem_low(size, size, 0);
+ } else {
+ struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order);
+ if (page)
+ p = page_address(page);
+ }
- if (!page) {
+ if (!p) {
prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
prom_halt();
}
- *pa_ptr = __pa(page);
+ *pa_ptr = __pa(p);
}
-static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, int use_bootmem)
+static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem)
{
- void *page;
+ unsigned long size = PAGE_ALIGN(qmask + 1);
+ unsigned long order = get_order(size);
+ void *p = NULL;
- if (use_bootmem)
- page = alloc_bootmem_low_pages(PAGE_SIZE);
- else
- page = (void *) get_zeroed_page(GFP_ATOMIC);
+ if (use_bootmem) {
+ p = __alloc_bootmem_low(size, size, 0);
+ } else {
+ struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order);
+ if (page)
+ p = page_address(page);
+ }
- if (!page) {
+ if (!p) {
prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
prom_halt();
}
- *pa_ptr = __pa(page);
+ *pa_ptr = __pa(p);
}
static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_bootmem)
struct trap_per_cpu *tb = &trap_block[cpu];
if (alloc) {
- alloc_one_mondo(&tb->cpu_mondo_pa, use_bootmem);
- alloc_one_mondo(&tb->dev_mondo_pa, use_bootmem);
- alloc_one_mondo(&tb->resum_mondo_pa, use_bootmem);
- alloc_one_kbuf(&tb->resum_kernel_buf_pa, use_bootmem);
- alloc_one_mondo(&tb->nonresum_mondo_pa, use_bootmem);
- alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, use_bootmem);
+ alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask, use_bootmem);
+ alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask, use_bootmem);
+ alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask, use_bootmem);
+ alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask, use_bootmem);
+ alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask, use_bootmem);
+ alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, tb->nonresum_qmask, use_bootmem);
init_cpu_send_mondo_info(tb, use_bootmem);
}
/* ITLB ** ICACHE line 2: TSB compare and TLB load */
bne,pn %xcc, tsb_miss_itlb ! Miss
mov FAULT_CODE_ITLB, %g3
- andcc %g5, _PAGE_EXEC_4U, %g0 ! Executable?
+ sethi %hi(_PAGE_EXEC_4U), %g4
+ andcc %g5, %g4, %g0 ! Executable?
be,pn %xcc, tsb_do_fault
nop ! Delay slot, fill me
stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load TLB
retry ! Trap done
- nop
/* ITLB ** ICACHE line 3: */
nop
--- /dev/null
+/* mdesc.c: Sun4V machine description handling.
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/bootmem.h>
+#include <linux/log2.h>
+
+#include <asm/hypervisor.h>
+#include <asm/mdesc.h>
+#include <asm/prom.h>
+#include <asm/oplib.h>
+#include <asm/smp.h>
+
+/* Unlike the OBP device tree, the machine description is a full-on
+ * DAG. An arbitrary number of ARCs are possible from one
+ * node to other nodes and thus we can't use the OBP device_node
+ * data structure to represent these nodes inside of the kernel.
+ *
+ * Actually, it isn't even a DAG, because there are back pointers
+ * which create cycles in the graph.
+ *
+ * mdesc_hdr and mdesc_elem describe the layout of the data structure
+ * we get from the Hypervisor.
+ */
+struct mdesc_hdr {
+ u32 version; /* Transport version */
+ u32 node_sz; /* node block size */
+ u32 name_sz; /* name block size */
+ u32 data_sz; /* data block size */
+};
+
+struct mdesc_elem {
+ u8 tag;
+#define MD_LIST_END 0x00
+#define MD_NODE 0x4e
+#define MD_NODE_END 0x45
+#define MD_NOOP 0x20
+#define MD_PROP_ARC 0x61
+#define MD_PROP_VAL 0x76
+#define MD_PROP_STR 0x73
+#define MD_PROP_DATA 0x64
+ u8 name_len;
+ u16 resv;
+ u32 name_offset;
+ union {
+ struct {
+ u32 data_len;
+ u32 data_offset;
+ } data;
+ u64 val;
+ } d;
+};
+
+static struct mdesc_hdr *main_mdesc;
+static struct mdesc_node *allnodes;
+
+static struct mdesc_node *allnodes_tail;
+static unsigned int unique_id;
+
+static struct mdesc_node **mdesc_hash;
+static unsigned int mdesc_hash_size;
+
+static inline unsigned int node_hashfn(u64 node)
+{
+ return ((unsigned int) (node ^ (node >> 8) ^ (node >> 16)))
+ & (mdesc_hash_size - 1);
+}
+
+static inline void hash_node(struct mdesc_node *mp)
+{
+ struct mdesc_node **head = &mdesc_hash[node_hashfn(mp->node)];
+
+ mp->hash_next = *head;
+ *head = mp;
+
+ if (allnodes_tail) {
+ allnodes_tail->allnodes_next = mp;
+ allnodes_tail = mp;
+ } else {
+ allnodes = allnodes_tail = mp;
+ }
+}
+
+static struct mdesc_node *find_node(u64 node)
+{
+ struct mdesc_node *mp = mdesc_hash[node_hashfn(node)];
+
+ while (mp) {
+ if (mp->node == node)
+ return mp;
+
+ mp = mp->hash_next;
+ }
+ return NULL;
+}
+
+struct property *md_find_property(const struct mdesc_node *mp,
+ const char *name,
+ int *lenp)
+{
+ struct property *pp;
+
+ for (pp = mp->properties; pp != 0; pp = pp->next) {
+ if (strcasecmp(pp->name, name) == 0) {
+ if (lenp)
+ *lenp = pp->length;
+ break;
+ }
+ }
+ return pp;
+}
+EXPORT_SYMBOL(md_find_property);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+const void *md_get_property(const struct mdesc_node *mp, const char *name,
+ int *lenp)
+{
+ struct property *pp = md_find_property(mp, name, lenp);
+ return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(md_get_property);
+
+struct mdesc_node *md_find_node_by_name(struct mdesc_node *from,
+ const char *name)
+{
+ struct mdesc_node *mp;
+
+ mp = from ? from->allnodes_next : allnodes;
+ for (; mp != NULL; mp = mp->allnodes_next) {
+ if (strcmp(mp->name, name) == 0)
+ break;
+ }
+ return mp;
+}
+EXPORT_SYMBOL(md_find_node_by_name);
+
+static unsigned int mdesc_early_allocated;
+
+static void * __init mdesc_early_alloc(unsigned long size)
+{
+ void *ret;
+
+ ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
+ if (ret == NULL) {
+ prom_printf("MDESC: alloc of %lu bytes failed.\n", size);
+ prom_halt();
+ }
+
+ memset(ret, 0, size);
+
+ mdesc_early_allocated += size;
+
+ return ret;
+}
+
+static unsigned int __init count_arcs(struct mdesc_elem *ep)
+{
+ unsigned int ret = 0;
+
+ ep++;
+ while (ep->tag != MD_NODE_END) {
+ if (ep->tag == MD_PROP_ARC)
+ ret++;
+ ep++;
+ }
+ return ret;
+}
+
+static void __init mdesc_node_alloc(u64 node, struct mdesc_elem *ep, const char *names)
+{
+ unsigned int num_arcs = count_arcs(ep);
+ struct mdesc_node *mp;
+
+ mp = mdesc_early_alloc(sizeof(*mp) +
+ (num_arcs * sizeof(struct mdesc_arc)));
+ mp->name = names + ep->name_offset;
+ mp->node = node;
+ mp->unique_id = unique_id++;
+ mp->num_arcs = num_arcs;
+
+ hash_node(mp);
+}
+
+static inline struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
+{
+ return (struct mdesc_elem *) (mdesc + 1);
+}
+
+static inline void *name_block(struct mdesc_hdr *mdesc)
+{
+ return ((void *) node_block(mdesc)) + mdesc->node_sz;
+}
+
+static inline void *data_block(struct mdesc_hdr *mdesc)
+{
+ return ((void *) name_block(mdesc)) + mdesc->name_sz;
+}
+
+/* In order to avoid recursion (the graph can be very deep) we use a
+ * two pass algorithm. First we allocate all the nodes and hash them.
+ * Then we iterate over each node, filling in the arcs and properties.
+ */
+static void __init build_all_nodes(struct mdesc_hdr *mdesc)
+{
+ struct mdesc_elem *start, *ep;
+ struct mdesc_node *mp;
+ const char *names;
+ void *data;
+ u64 last_node;
+
+ start = ep = node_block(mdesc);
+ last_node = mdesc->node_sz / 16;
+
+ names = name_block(mdesc);
+
+ while (1) {
+ u64 node = ep - start;
+
+ if (ep->tag == MD_LIST_END)
+ break;
+
+ if (ep->tag != MD_NODE) {
+ prom_printf("MDESC: Inconsistent element list.\n");
+ prom_halt();
+ }
+
+ mdesc_node_alloc(node, ep, names);
+
+ if (ep->d.val >= last_node) {
+ printk("MDESC: Warning, early break out of node scan.\n");
+ printk("MDESC: Next node [%lu] last_node [%lu].\n",
+ node, last_node);
+ break;
+ }
+
+ ep = start + ep->d.val;
+ }
+
+ data = data_block(mdesc);
+ for (mp = allnodes; mp; mp = mp->allnodes_next) {
+ struct mdesc_elem *ep = start + mp->node;
+ struct property **link = &mp->properties;
+ unsigned int this_arc = 0;
+
+ ep++;
+ while (ep->tag != MD_NODE_END) {
+ switch (ep->tag) {
+ case MD_PROP_ARC: {
+ struct mdesc_node *target;
+
+ if (this_arc >= mp->num_arcs) {
+ prom_printf("MDESC: ARC overrun [%u:%u]\n",
+ this_arc, mp->num_arcs);
+ prom_halt();
+ }
+ target = find_node(ep->d.val);
+ if (!target) {
+ printk("MDESC: Warning, arc points to "
+ "missing node, ignoring.\n");
+ break;
+ }
+ mp->arcs[this_arc].name =
+ (names + ep->name_offset);
+ mp->arcs[this_arc].arc = target;
+ this_arc++;
+ break;
+ }
+
+ case MD_PROP_VAL:
+ case MD_PROP_STR:
+ case MD_PROP_DATA: {
+ struct property *p = mdesc_early_alloc(sizeof(*p));
+
+ p->unique_id = unique_id++;
+ p->name = (char *) names + ep->name_offset;
+ if (ep->tag == MD_PROP_VAL) {
+ p->value = &ep->d.val;
+ p->length = 8;
+ } else {
+ p->value = data + ep->d.data.data_offset;
+ p->length = ep->d.data.data_len;
+ }
+ *link = p;
+ link = &p->next;
+ break;
+ }
+
+ case MD_NOOP:
+ break;
+
+ default:
+ printk("MDESC: Warning, ignoring unknown tag type %02x\n",
+ ep->tag);
+ }
+ ep++;
+ }
+ }
+}
+
+static unsigned int __init count_nodes(struct mdesc_hdr *mdesc)
+{
+ struct mdesc_elem *ep = node_block(mdesc);
+ struct mdesc_elem *end;
+ unsigned int cnt = 0;
+
+ end = ((void *)ep) + mdesc->node_sz;
+ while (ep < end) {
+ if (ep->tag == MD_NODE)
+ cnt++;
+ ep++;
+ }
+ return cnt;
+}
+
+static void __init report_platform_properties(void)
+{
+ struct mdesc_node *pn = md_find_node_by_name(NULL, "platform");
+ const char *s;
+ const u64 *v;
+
+ if (!pn) {
+ prom_printf("No platform node in machine-description.\n");
+ prom_halt();
+ }
+
+ s = md_get_property(pn, "banner-name", NULL);
+ printk("PLATFORM: banner-name [%s]\n", s);
+ s = md_get_property(pn, "name", NULL);
+ printk("PLATFORM: name [%s]\n", s);
+
+ v = md_get_property(pn, "hostid", NULL);
+ if (v)
+ printk("PLATFORM: hostid [%08lx]\n", *v);
+ v = md_get_property(pn, "serial#", NULL);
+ if (v)
+ printk("PLATFORM: serial# [%08lx]\n", *v);
+ v = md_get_property(pn, "stick-frequency", NULL);
+ printk("PLATFORM: stick-frequency [%08lx]\n", *v);
+ v = md_get_property(pn, "mac-address", NULL);
+ if (v)
+ printk("PLATFORM: mac-address [%lx]\n", *v);
+ v = md_get_property(pn, "watchdog-resolution", NULL);
+ if (v)
+ printk("PLATFORM: watchdog-resolution [%lu ms]\n", *v);
+ v = md_get_property(pn, "watchdog-max-timeout", NULL);
+ if (v)
+ printk("PLATFORM: watchdog-max-timeout [%lu ms]\n", *v);
+ v = md_get_property(pn, "max-cpus", NULL);
+ if (v)
+ printk("PLATFORM: max-cpus [%lu]\n", *v);
+}
+
+static int inline find_in_proplist(const char *list, const char *match, int len)
+{
+ while (len > 0) {
+ int l;
+
+ if (!strcmp(list, match))
+ return 1;
+ l = strlen(list) + 1;
+ list += l;
+ len -= l;
+ }
+ return 0;
+}
+
+static void __init fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_node *mp)
+{
+ const u64 *level = md_get_property(mp, "level", NULL);
+ const u64 *size = md_get_property(mp, "size", NULL);
+ const u64 *line_size = md_get_property(mp, "line-size", NULL);
+ const char *type;
+ int type_len;
+
+ type = md_get_property(mp, "type", &type_len);
+
+ switch (*level) {
+ case 1:
+ if (find_in_proplist(type, "instn", type_len)) {
+ c->icache_size = *size;
+ c->icache_line_size = *line_size;
+ } else if (find_in_proplist(type, "data", type_len)) {
+ c->dcache_size = *size;
+ c->dcache_line_size = *line_size;
+ }
+ break;
+
+ case 2:
+ c->ecache_size = *size;
+ c->ecache_line_size = *line_size;
+ break;
+
+ default:
+ break;
+ }
+
+ if (*level == 1) {
+ unsigned int i;
+
+ for (i = 0; i < mp->num_arcs; i++) {
+ struct mdesc_node *t = mp->arcs[i].arc;
+
+ if (strcmp(mp->arcs[i].name, "fwd"))
+ continue;
+
+ if (!strcmp(t->name, "cache"))
+ fill_in_one_cache(c, t);
+ }
+ }
+}
+
+static void __init mark_core_ids(struct mdesc_node *mp, int core_id)
+{
+ unsigned int i;
+
+ for (i = 0; i < mp->num_arcs; i++) {
+ struct mdesc_node *t = mp->arcs[i].arc;
+ const u64 *id;
+
+ if (strcmp(mp->arcs[i].name, "back"))
+ continue;
+
+ if (!strcmp(t->name, "cpu")) {
+ id = md_get_property(t, "id", NULL);
+ if (*id < NR_CPUS)
+ cpu_data(*id).core_id = core_id;
+ } else {
+ unsigned int j;
+
+ for (j = 0; j < t->num_arcs; j++) {
+ struct mdesc_node *n = t->arcs[j].arc;
+
+ if (strcmp(t->arcs[j].name, "back"))
+ continue;
+
+ if (strcmp(n->name, "cpu"))
+ continue;
+
+ id = md_get_property(n, "id", NULL);
+ if (*id < NR_CPUS)
+ cpu_data(*id).core_id = core_id;
+ }
+ }
+ }
+}
+
+static void __init set_core_ids(void)
+{
+ struct mdesc_node *mp;
+ int idx;
+
+ idx = 1;
+ md_for_each_node_by_name(mp, "cache") {
+ const u64 *level = md_get_property(mp, "level", NULL);
+ const char *type;
+ int len;
+
+ if (*level != 1)
+ continue;
+
+ type = md_get_property(mp, "type", &len);
+ if (!find_in_proplist(type, "instn", len))
+ continue;
+
+ mark_core_ids(mp, idx);
+
+ idx++;
+ }
+}
+
+static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def)
+{
+ u64 val;
+
+ if (!p)
+ goto use_default;
+ val = *p;
+
+ if (!val || val >= 64)
+ goto use_default;
+
+ *mask = ((1U << val) * 64U) - 1U;
+ return;
+
+use_default:
+ *mask = ((1U << def) * 64U) - 1U;
+}
+
+static void __init get_mondo_data(struct mdesc_node *mp, struct trap_per_cpu *tb)
+{
+ const u64 *val;
+
+ val = md_get_property(mp, "q-cpu-mondo-#bits", NULL);
+ get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7);
+
+ val = md_get_property(mp, "q-dev-mondo-#bits", NULL);
+ get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7);
+
+ val = md_get_property(mp, "q-resumable-#bits", NULL);
+ get_one_mondo_bits(val, &tb->resum_qmask, 6);
+
+ val = md_get_property(mp, "q-nonresumable-#bits", NULL);
+ get_one_mondo_bits(val, &tb->nonresum_qmask, 2);
+}
+
+static void __init mdesc_fill_in_cpu_data(void)
+{
+ struct mdesc_node *mp;
+
+ ncpus_probed = 0;
+ md_for_each_node_by_name(mp, "cpu") {
+ const u64 *id = md_get_property(mp, "id", NULL);
+ const u64 *cfreq = md_get_property(mp, "clock-frequency", NULL);
+ struct trap_per_cpu *tb;
+ cpuinfo_sparc *c;
+ unsigned int i;
+ int cpuid;
+
+ ncpus_probed++;
+
+ cpuid = *id;
+
+#ifdef CONFIG_SMP
+ if (cpuid >= NR_CPUS)
+ continue;
+#else
+ /* On uniprocessor we only want the values for the
+ * real physical cpu the kernel booted onto, however
+ * cpu_data() only has one entry at index 0.
+ */
+ if (cpuid != real_hard_smp_processor_id())
+ continue;
+ cpuid = 0;
+#endif
+
+ c = &cpu_data(cpuid);
+ c->clock_tick = *cfreq;
+
+ tb = &trap_block[cpuid];
+ get_mondo_data(mp, tb);
+
+ for (i = 0; i < mp->num_arcs; i++) {
+ struct mdesc_node *t = mp->arcs[i].arc;
+ unsigned int j;
+
+ if (strcmp(mp->arcs[i].name, "fwd"))
+ continue;
+
+ if (!strcmp(t->name, "cache")) {
+ fill_in_one_cache(c, t);
+ continue;
+ }
+
+ for (j = 0; j < t->num_arcs; j++) {
+ struct mdesc_node *n;
+
+ n = t->arcs[j].arc;
+ if (strcmp(t->arcs[j].name, "fwd"))
+ continue;
+
+ if (!strcmp(n->name, "cache"))
+ fill_in_one_cache(c, n);
+ }
+ }
+
+#ifdef CONFIG_SMP
+ cpu_set(cpuid, cpu_present_map);
+ cpu_set(cpuid, phys_cpu_present_map);
+#endif
+
+ c->core_id = 0;
+ }
+
+ set_core_ids();
+
+ smp_fill_in_sib_core_maps();
+}
+
+void __init sun4v_mdesc_init(void)
+{
+ unsigned long len, real_len, status;
+
+ (void) sun4v_mach_desc(0UL, 0UL, &len);
+
+ printk("MDESC: Size is %lu bytes.\n", len);
+
+ main_mdesc = mdesc_early_alloc(len);
+
+ status = sun4v_mach_desc(__pa(main_mdesc), len, &real_len);
+ if (status != HV_EOK || real_len > len) {
+ prom_printf("sun4v_mach_desc fails, err(%lu), "
+ "len(%lu), real_len(%lu)\n",
+ status, len, real_len);
+ prom_halt();
+ }
+
+ len = count_nodes(main_mdesc);
+ printk("MDESC: %lu nodes.\n", len);
+
+ len = roundup_pow_of_two(len);
+
+ mdesc_hash = mdesc_early_alloc(len * sizeof(struct mdesc_node *));
+ mdesc_hash_size = len;
+
+ printk("MDESC: Hash size %lu entries.\n", len);
+
+ build_all_nodes(main_mdesc);
+
+ printk("MDESC: Built graph with %u bytes of memory.\n",
+ mdesc_early_allocated);
+
+ report_platform_properties();
+ mdesc_fill_in_cpu_data();
+}
pci_controller_scan(pci_controller_init);
}
+static int ofpci_verbose;
+
+static int __init ofpci_debug(char *str)
+{
+ int val = 0;
+
+ get_option(&str, &val);
+ if (val)
+ ofpci_verbose = 1;
+ return 1;
+}
+
+__setup("ofpci_debug=", ofpci_debug);
+
static unsigned long pci_parse_of_flags(u32 addr0)
{
unsigned long flags = 0;
addrs = of_get_property(node, "assigned-addresses", &proplen);
if (!addrs)
return;
- printk(" parse addresses (%d bytes) @ %p\n", proplen, addrs);
+ if (ofpci_verbose)
+ printk(" parse addresses (%d bytes) @ %p\n",
+ proplen, addrs);
op_res = &op->resource[0];
for (; proplen >= 20; proplen -= 20, addrs += 5, op_res++) {
struct resource *res;
if (!flags)
continue;
i = addrs[0] & 0xff;
- printk(" start: %lx, end: %lx, i: %x\n",
- op_res->start, op_res->end, i);
+ if (ofpci_verbose)
+ printk(" start: %lx, end: %lx, i: %x\n",
+ op_res->start, op_res->end, i);
if (PCI_BASE_ADDRESS_0 <= i && i <= PCI_BASE_ADDRESS_5) {
res = &dev->resource[(i - PCI_BASE_ADDRESS_0) >> 2];
if (type == NULL)
type = "";
- printk(" create device, devfn: %x, type: %s hostcontroller(%d)\n",
- devfn, type, host_controller);
+ if (ofpci_verbose)
+ printk(" create device, devfn: %x, type: %s\n",
+ devfn, type);
dev->bus = bus;
dev->sysdata = node;
sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
}
- printk(" class: 0x%x device name: %s\n",
- dev->class, pci_name(dev));
+ if (ofpci_verbose)
+ printk(" class: 0x%x device name: %s\n",
+ dev->class, pci_name(dev));
/* I have seen IDE devices which will not respond to
* the bmdma simplex check reads if bus mastering is
}
pci_parse_of_addrs(sd->op, node, dev);
- printk(" adding to system ...\n");
+ if (ofpci_verbose)
+ printk(" adding to system ...\n");
pci_device_add(dev, bus);
unsigned int flags;
u64 size;
- printk("of_scan_pci_bridge(%s)\n", node->full_name);
+ if (ofpci_verbose)
+ printk("of_scan_pci_bridge(%s)\n", node->full_name);
/* parse bus-range property */
busrange = of_get_property(node, "bus-range", &len);
simba_cont:
sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
bus->number);
- printk(" bus name: %s\n", bus->name);
+ if (ofpci_verbose)
+ printk(" bus name: %s\n", bus->name);
pci_of_scan_bus(pbm, node, bus);
}
int reglen, devfn;
struct pci_dev *dev;
- printk("PCI: scan_bus[%s] bus no %d\n",
- node->full_name, bus->number);
+ if (ofpci_verbose)
+ printk("PCI: scan_bus[%s] bus no %d\n",
+ node->full_name, bus->number);
child = NULL;
while ((child = of_get_next_child(node, child)) != NULL) {
- printk(" * %s\n", child->full_name);
+ if (ofpci_verbose)
+ printk(" * %s\n", child->full_name);
reg = of_get_property(child, "reg", ®len);
if (reg == NULL || reglen < 20)
continue;
dev = of_create_pci_dev(pbm, child, bus, devfn, 0);
if (!dev)
continue;
- printk("PCI: dev header type: %x\n", dev->hdr_type);
+ if (ofpci_verbose)
+ printk("PCI: dev header type: %x\n",
+ dev->hdr_type);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
/* Of course, Sun has to encode things a thousand
* different ways, inconsistently.
*/
- cpu_find_by_instance(0, &dp, NULL);
- if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe"))
- hummingbird_p = 1;
+ for_each_node_by_type(dp, "cpu") {
+ if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe"))
+ hummingbird_p = 1;
+ }
}
}
#include <linux/percpu.h>
#include <linux/irq.h>
#include <linux/msi.h>
+#include <linux/log2.h>
#include <asm/iommu.h>
#include <asm/irq.h>
#include "pci_sun4v.h"
+static unsigned long vpci_major = 1;
+static unsigned long vpci_minor = 1;
+
#define PGLIST_NENTS (PAGE_SIZE / sizeof(u64))
struct iommu_batch {
{
struct iommu *iommu = pbm->iommu;
struct property *prop;
- unsigned long num_tsb_entries, sz;
+ unsigned long num_tsb_entries, sz, tsbsize;
u32 vdma[2], dma_mask, dma_offset;
- int tsbsize;
prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
if (prop) {
vdma[1] = 0x80000000;
}
- dma_mask = vdma[0];
- switch (vdma[1]) {
- case 0x20000000:
- dma_mask |= 0x1fffffff;
- tsbsize = 64;
- break;
-
- case 0x40000000:
- dma_mask |= 0x3fffffff;
- tsbsize = 128;
- break;
-
- case 0x80000000:
- dma_mask |= 0x7fffffff;
- tsbsize = 256;
- break;
-
- default:
- prom_printf("PCI-SUN4V: strange virtual-dma size.\n");
- prom_halt();
+ if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) {
+ prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n",
+ vdma[0], vdma[1]);
+ prom_halt();
};
- tsbsize *= (8 * 1024);
-
- num_tsb_entries = tsbsize / sizeof(iopte_t);
+ dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL);
+ num_tsb_entries = vdma[1] / IO_PAGE_SIZE;
+ tsbsize = num_tsb_entries * sizeof(iopte_t);
dma_offset = vdma[0];
iommu->dma_addr_mask = dma_mask;
/* Allocate and initialize the free area map. */
- sz = num_tsb_entries / 8;
+ sz = (num_tsb_entries + 7) / 8;
sz = (sz + 7UL) & ~7UL;
iommu->arena.map = kzalloc(sz, GFP_KERNEL);
if (!iommu->arena.map) {
void sun4v_pci_init(struct device_node *dp, char *model_name)
{
+ static int hvapi_negotiated = 0;
struct pci_controller_info *p;
struct pci_pbm_info *pbm;
struct iommu *iommu;
u32 devhandle;
int i;
+ if (!hvapi_negotiated++) {
+ int err = sun4v_hvapi_register(HV_GRP_PCI,
+ vpci_major,
+ &vpci_minor);
+
+ if (err) {
+ prom_printf("SUN4V_PCI: Could not register hvapi, "
+ "err=%d\n", err);
+ prom_halt();
+ }
+ printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n",
+ vpci_major, vpci_minor);
+ }
+
prop = of_find_property(dp, "reg", NULL);
regs = prop->value;
#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/io.h>
+#include <asm/sstate.h>
#include <linux/unistd.h>
void machine_power_off(void)
{
+ sstate_poweroff();
if (!serial_console || scons_pwroff) {
#ifdef CONFIG_PCI
if (power_reg) {
#include <asm/mmu_context.h>
#include <asm/unistd.h>
#include <asm/hypervisor.h>
+#include <asm/sstate.h>
/* #define VERBOSE_SHOWREGS */
void machine_halt(void)
{
+ sstate_halt();
if (!serial_console && prom_palette)
prom_palette (1);
if (prom_keyboard)
void machine_alt_power_off(void)
{
+ sstate_poweroff();
if (!serial_console && prom_palette)
prom_palette(1);
if (prom_keyboard)
{
char *p;
+ sstate_reboot();
p = strchr (reboot_command, '\n');
if (p) *p = 0;
if (!serial_console && prom_palette)
#include <asm/irq.h>
#include <asm/asi.h>
#include <asm/upa.h>
+#include <asm/smp.h>
static struct device_node *allnodes;
return ret;
}
+static const char *get_mid_prop(void)
+{
+ return (tlb_type == spitfire ? "upa-portid" : "portid");
+}
+
+struct device_node *of_find_node_by_cpuid(int cpuid)
+{
+ struct device_node *dp;
+ const char *mid_prop = get_mid_prop();
+
+ for_each_node_by_type(dp, "cpu") {
+ int id = of_getintprop_default(dp, mid_prop, -1);
+ const char *this_mid_prop = mid_prop;
+
+ if (id < 0) {
+ this_mid_prop = "cpuid";
+ id = of_getintprop_default(dp, this_mid_prop, -1);
+ }
+
+ if (id < 0) {
+ prom_printf("OF: Serious problem, cpu lacks "
+ "%s property", this_mid_prop);
+ prom_halt();
+ }
+ if (cpuid == id)
+ return dp;
+ }
+ return NULL;
+}
+
+static void __init of_fill_in_cpu_data(void)
+{
+ struct device_node *dp;
+ const char *mid_prop = get_mid_prop();
+
+ ncpus_probed = 0;
+ for_each_node_by_type(dp, "cpu") {
+ int cpuid = of_getintprop_default(dp, mid_prop, -1);
+ const char *this_mid_prop = mid_prop;
+ struct device_node *portid_parent;
+ int portid = -1;
+
+ portid_parent = NULL;
+ if (cpuid < 0) {
+ this_mid_prop = "cpuid";
+ cpuid = of_getintprop_default(dp, this_mid_prop, -1);
+ if (cpuid >= 0) {
+ int limit = 2;
+
+ portid_parent = dp;
+ while (limit--) {
+ portid_parent = portid_parent->parent;
+ if (!portid_parent)
+ break;
+ portid = of_getintprop_default(portid_parent,
+ "portid", -1);
+ if (portid >= 0)
+ break;
+ }
+ }
+ }
+
+ if (cpuid < 0) {
+ prom_printf("OF: Serious problem, cpu lacks "
+ "%s property", this_mid_prop);
+ prom_halt();
+ }
+
+ ncpus_probed++;
+
+#ifdef CONFIG_SMP
+ if (cpuid >= NR_CPUS)
+ continue;
+#else
+ /* On uniprocessor we only want the values for the
+ * real physical cpu the kernel booted onto, however
+ * cpu_data() only has one entry at index 0.
+ */
+ if (cpuid != real_hard_smp_processor_id())
+ continue;
+ cpuid = 0;
+#endif
+
+ cpu_data(cpuid).clock_tick =
+ of_getintprop_default(dp, "clock-frequency", 0);
+
+ if (portid_parent) {
+ cpu_data(cpuid).dcache_size =
+ of_getintprop_default(dp, "l1-dcache-size",
+ 16 * 1024);
+ cpu_data(cpuid).dcache_line_size =
+ of_getintprop_default(dp, "l1-dcache-line-size",
+ 32);
+ cpu_data(cpuid).icache_size =
+ of_getintprop_default(dp, "l1-icache-size",
+ 8 * 1024);
+ cpu_data(cpuid).icache_line_size =
+ of_getintprop_default(dp, "l1-icache-line-size",
+ 32);
+ cpu_data(cpuid).ecache_size =
+ of_getintprop_default(dp, "l2-cache-size", 0);
+ cpu_data(cpuid).ecache_line_size =
+ of_getintprop_default(dp, "l2-cache-line-size", 0);
+ if (!cpu_data(cpuid).ecache_size ||
+ !cpu_data(cpuid).ecache_line_size) {
+ cpu_data(cpuid).ecache_size =
+ of_getintprop_default(portid_parent,
+ "l2-cache-size",
+ (4 * 1024 * 1024));
+ cpu_data(cpuid).ecache_line_size =
+ of_getintprop_default(portid_parent,
+ "l2-cache-line-size", 64);
+ }
+
+ cpu_data(cpuid).core_id = portid + 1;
+ } else {
+ cpu_data(cpuid).dcache_size =
+ of_getintprop_default(dp, "dcache-size", 16 * 1024);
+ cpu_data(cpuid).dcache_line_size =
+ of_getintprop_default(dp, "dcache-line-size", 32);
+
+ cpu_data(cpuid).icache_size =
+ of_getintprop_default(dp, "icache-size", 16 * 1024);
+ cpu_data(cpuid).icache_line_size =
+ of_getintprop_default(dp, "icache-line-size", 32);
+
+ cpu_data(cpuid).ecache_size =
+ of_getintprop_default(dp, "ecache-size",
+ (4 * 1024 * 1024));
+ cpu_data(cpuid).ecache_line_size =
+ of_getintprop_default(dp, "ecache-line-size", 64);
+
+ cpu_data(cpuid).core_id = 0;
+ }
+
+#ifdef CONFIG_SMP
+ cpu_set(cpuid, cpu_present_map);
+ cpu_set(cpuid, phys_cpu_present_map);
+#endif
+ }
+
+ smp_fill_in_sib_core_maps();
+}
+
void __init prom_build_devicetree(void)
{
struct device_node **nextp;
&nextp);
printk("PROM: Built device tree with %u bytes of memory.\n",
prom_early_allocated);
+
+ if (tlb_type != hypervisor)
+ of_fill_in_cpu_data();
}
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/mmu.h>
+#include <asm/ns87303.h>
#ifdef CONFIG_IP_PNP
#include <net/ipconfig.h>
#endif
+/* Used to synchronize accesses to NatSemi SUPER I/O chip configure
+ * operations in asm/ns87303.h
+ */
+DEFINE_SPINLOCK(ns87303_lock);
+
struct screen_info screen_info = {
0, 0, /* orig-x, orig-y */
0, /* unused */
init_cur_cpu_trap(current_thread_info());
paging_init();
-
- smp_setup_cpu_possible_map();
}
static int __init set_preferred_console(void)
unsigned int dcache_parity_tl1_occurred;
unsigned int icache_parity_tl1_occurred;
-static int ncpus_probed;
+int ncpus_probed;
static int show_cpuinfo(struct seq_file *m, void *__unused)
{
err = -ENOMEM;
- /* Count the number of physically present processors in
- * the machine, even on uniprocessor, so that /proc/cpuinfo
- * output is consistent with 2.4.x
- */
- ncpus_probed = 0;
- while (!cpu_find_by_instance(ncpus_probed, NULL, NULL))
- ncpus_probed++;
-
for_each_possible_cpu(i) {
struct cpu *p = kzalloc(sizeof(*p), GFP_KERNEL);
if (p) {
#include <asm/tlb.h>
#include <asm/sections.h>
#include <asm/prom.h>
+#include <asm/mdesc.h>
extern void calibrate_delay(void);
i, cpu_data(i).clock_tick);
}
-void __init smp_store_cpu_info(int id)
-{
- struct device_node *dp;
- int def;
-
- cpu_data(id).udelay_val = loops_per_jiffy;
-
- cpu_find_by_mid(id, &dp);
- cpu_data(id).clock_tick =
- of_getintprop_default(dp, "clock-frequency", 0);
-
- def = ((tlb_type == hypervisor) ? (8 * 1024) : (16 * 1024));
- cpu_data(id).dcache_size =
- of_getintprop_default(dp, "dcache-size", def);
-
- def = 32;
- cpu_data(id).dcache_line_size =
- of_getintprop_default(dp, "dcache-line-size", def);
-
- def = 16 * 1024;
- cpu_data(id).icache_size =
- of_getintprop_default(dp, "icache-size", def);
-
- def = 32;
- cpu_data(id).icache_line_size =
- of_getintprop_default(dp, "icache-line-size", def);
-
- def = ((tlb_type == hypervisor) ?
- (3 * 1024 * 1024) :
- (4 * 1024 * 1024));
- cpu_data(id).ecache_size =
- of_getintprop_default(dp, "ecache-size", def);
-
- def = 64;
- cpu_data(id).ecache_line_size =
- of_getintprop_default(dp, "ecache-line-size", def);
-
- printk("CPU[%d]: Caches "
- "D[sz(%d):line_sz(%d)] "
- "I[sz(%d):line_sz(%d)] "
- "E[sz(%d):line_sz(%d)]\n",
- id,
- cpu_data(id).dcache_size, cpu_data(id).dcache_line_size,
- cpu_data(id).icache_size, cpu_data(id).icache_line_size,
- cpu_data(id).ecache_size, cpu_data(id).ecache_line_size);
-}
-
extern void setup_sparc64_timer(void);
static volatile unsigned long callin_flag = 0;
local_irq_enable();
calibrate_delay();
- smp_store_cpu_info(cpuid);
+ cpu_data(cpuid).udelay_val = loops_per_jiffy;
callin_flag = 1;
__asm__ __volatile__("membar #Sync\n\t"
"flush %%g6" : : : "memory");
prom_startcpu_cpuid(cpu, entry, cookie);
} else {
- struct device_node *dp;
+ struct device_node *dp = of_find_node_by_cpuid(cpu);
- cpu_find_by_mid(cpu, &dp);
prom_startcpu(dp->node, entry, cookie);
}
static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask)
{
u64 pstate, ver;
- int nack_busy_id, is_jbus;
+ int nack_busy_id, is_jbus, need_more;
if (cpus_empty(mask))
return;
__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
retry:
+ need_more = 0;
__asm__ __volatile__("wrpr %0, %1, %%pstate\n\t"
: : "r" (pstate), "i" (PSTATE_IE));
: /* no outputs */
: "r" (target), "i" (ASI_INTR_W));
nack_busy_id++;
+ if (nack_busy_id == 32) {
+ need_more = 1;
+ break;
+ }
}
}
if (dispatch_stat == 0UL) {
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: : "r" (pstate));
+ if (unlikely(need_more)) {
+ int i, cnt = 0;
+ for_each_cpu_mask(i, mask) {
+ cpu_clear(i, mask);
+ cnt++;
+ if (cnt == 32)
+ break;
+ }
+ goto retry;
+ }
return;
}
if (!--stuck)
if ((dispatch_stat & check_mask) == 0)
cpu_clear(i, mask);
this_busy_nack += 2;
+ if (this_busy_nack == 64)
+ break;
}
goto retry;
static void __init smp_tune_scheduling(void)
{
- struct device_node *dp;
- int instance;
- unsigned int def, smallest = ~0U;
-
- def = ((tlb_type == hypervisor) ?
- (3 * 1024 * 1024) :
- (4 * 1024 * 1024));
+ unsigned int smallest = ~0U;
+ int i;
- instance = 0;
- while (!cpu_find_by_instance(instance, &dp, NULL)) {
- unsigned int val;
+ for (i = 0; i < NR_CPUS; i++) {
+ unsigned int val = cpu_data(i).ecache_size;
- val = of_getintprop_default(dp, "ecache-size", def);
- if (val < smallest)
+ if (val && val < smallest)
smallest = val;
-
- instance++;
}
/* Any value less than 256K is nonsense. */
int i;
if (num_possible_cpus() > max_cpus) {
- int instance, mid;
-
- instance = 0;
- while (!cpu_find_by_instance(instance, NULL, &mid)) {
- if (mid != boot_cpu_id) {
- cpu_clear(mid, phys_cpu_present_map);
- cpu_clear(mid, cpu_present_map);
+ for_each_possible_cpu(i) {
+ if (i != boot_cpu_id) {
+ cpu_clear(i, phys_cpu_present_map);
+ cpu_clear(i, cpu_present_map);
if (num_possible_cpus() <= max_cpus)
break;
}
- instance++;
}
}
- for_each_possible_cpu(i) {
- if (tlb_type == hypervisor) {
- int j;
-
- /* XXX get this mapping from machine description */
- for_each_possible_cpu(j) {
- if ((j >> 2) == (i >> 2))
- cpu_set(j, cpu_sibling_map[i]);
- }
- } else {
- cpu_set(i, cpu_sibling_map[i]);
- }
- }
-
- smp_store_cpu_info(boot_cpu_id);
+ cpu_data(boot_cpu_id).udelay_val = loops_per_jiffy;
smp_tune_scheduling();
}
-/* Set this up early so that things like the scheduler can init
- * properly. We use the same cpu mask for both the present and
- * possible cpu map.
- */
-void __init smp_setup_cpu_possible_map(void)
+void __devinit smp_prepare_boot_cpu(void)
{
- int instance, mid;
-
- instance = 0;
- while (!cpu_find_by_instance(instance, NULL, &mid)) {
- if (mid < NR_CPUS) {
- cpu_set(mid, phys_cpu_present_map);
- cpu_set(mid, cpu_present_map);
- }
- instance++;
- }
}
-void __devinit smp_prepare_boot_cpu(void)
+void __devinit smp_fill_in_sib_core_maps(void)
{
+ unsigned int i;
+
+ for_each_possible_cpu(i) {
+ unsigned int j;
+
+ if (cpu_data(i).core_id == 0) {
+ cpu_set(i, cpu_sibling_map[i]);
+ continue;
+ }
+
+ for_each_possible_cpu(j) {
+ if (cpu_data(i).core_id ==
+ cpu_data(j).core_id)
+ cpu_set(j, cpu_sibling_map[i]);
+ }
+ }
}
int __cpuinit __cpu_up(unsigned int cpu)
EXPORT_SYMBOL(__per_cpu_base);
EXPORT_SYMBOL(__per_cpu_shift);
-void __init setup_per_cpu_areas(void)
+void __init real_setup_per_cpu_areas(void)
{
unsigned long goal, size, i;
char *ptr;
--- /dev/null
+/* sstate.c: System soft state support.
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+
+#include <asm/hypervisor.h>
+#include <asm/sstate.h>
+#include <asm/oplib.h>
+#include <asm/head.h>
+#include <asm/io.h>
+
+static int hv_supports_soft_state;
+
+static unsigned long kimage_addr_to_ra(const char *p)
+{
+ unsigned long val = (unsigned long) p;
+
+ return kern_base + (val - KERNBASE);
+}
+
+static void do_set_sstate(unsigned long state, const char *msg)
+{
+ unsigned long err;
+
+ if (!hv_supports_soft_state)
+ return;
+
+ err = sun4v_mach_set_soft_state(state, kimage_addr_to_ra(msg));
+ if (err) {
+ printk(KERN_WARNING "SSTATE: Failed to set soft-state to "
+ "state[%lx] msg[%s], err=%lu\n",
+ state, msg, err);
+ }
+}
+
+static const char booting_msg[32] __attribute__((aligned(32))) =
+ "Linux booting";
+static const char running_msg[32] __attribute__((aligned(32))) =
+ "Linux running";
+static const char halting_msg[32] __attribute__((aligned(32))) =
+ "Linux halting";
+static const char poweroff_msg[32] __attribute__((aligned(32))) =
+ "Linux powering off";
+static const char rebooting_msg[32] __attribute__((aligned(32))) =
+ "Linux rebooting";
+static const char panicing_msg[32] __attribute__((aligned(32))) =
+ "Linux panicing";
+
+void sstate_booting(void)
+{
+ do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
+}
+
+void sstate_running(void)
+{
+ do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
+}
+
+void sstate_halt(void)
+{
+ do_set_sstate(HV_SOFT_STATE_TRANSITION, halting_msg);
+}
+
+void sstate_poweroff(void)
+{
+ do_set_sstate(HV_SOFT_STATE_TRANSITION, poweroff_msg);
+}
+
+void sstate_reboot(void)
+{
+ do_set_sstate(HV_SOFT_STATE_TRANSITION, rebooting_msg);
+}
+
+static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr)
+{
+ do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block sstate_panic_block = {
+ .notifier_call = sstate_panic_event,
+ .priority = INT_MAX,
+};
+
+void __init sun4v_sstate_init(void)
+{
+ unsigned long major, minor;
+
+ major = 1;
+ minor = 0;
+ if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor))
+ return;
+
+ hv_supports_soft_state = 1;
+
+ prom_sun4v_guest_soft_state();
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &sstate_panic_block);
+}
be,pn %xcc, sun4v_cpu_mondo_queue_empty
nop
- /* Get &trap_block[smp_processor_id()] into %g3. */
- ldxa [%g0] ASI_SCRATCHPAD, %g3
- sub %g3, TRAP_PER_CPU_FAULT_INFO, %g3
+ /* Get &trap_block[smp_processor_id()] into %g4. */
+ ldxa [%g0] ASI_SCRATCHPAD, %g4
+ sub %g4, TRAP_PER_CPU_FAULT_INFO, %g4
/* Get CPU mondo queue base phys address into %g7. */
- ldx [%g3 + TRAP_PER_CPU_CPU_MONDO_PA], %g7
+ ldx [%g4 + TRAP_PER_CPU_CPU_MONDO_PA], %g7
/* Now get the cross-call arguments and handler PC, same
* layout as sun4u:
add %g2, 0x40 - 0x8 - 0x8, %g2
/* Update queue head pointer. */
- sethi %hi(8192 - 1), %g4
- or %g4, %lo(8192 - 1), %g4
+ lduw [%g4 + TRAP_PER_CPU_CPU_MONDO_QMASK], %g4
and %g2, %g4, %g2
mov INTRQ_CPU_MONDO_HEAD, %g4
be,pn %xcc, sun4v_dev_mondo_queue_empty
nop
- /* Get &trap_block[smp_processor_id()] into %g3. */
- ldxa [%g0] ASI_SCRATCHPAD, %g3
- sub %g3, TRAP_PER_CPU_FAULT_INFO, %g3
+ /* Get &trap_block[smp_processor_id()] into %g4. */
+ ldxa [%g0] ASI_SCRATCHPAD, %g4
+ sub %g4, TRAP_PER_CPU_FAULT_INFO, %g4
/* Get DEV mondo queue base phys address into %g5. */
- ldx [%g3 + TRAP_PER_CPU_DEV_MONDO_PA], %g5
+ ldx [%g4 + TRAP_PER_CPU_DEV_MONDO_PA], %g5
/* Load IVEC into %g3. */
ldxa [%g5 + %g2] ASI_PHYS_USE_EC, %g3
*/
/* Update queue head pointer, this frees up some registers. */
- sethi %hi(8192 - 1), %g4
- or %g4, %lo(8192 - 1), %g4
+ lduw [%g4 + TRAP_PER_CPU_DEV_MONDO_QMASK], %g4
and %g2, %g4, %g2
mov INTRQ_DEVICE_MONDO_HEAD, %g4
brnz,pn %g1, sun4v_res_mondo_queue_full
nop
+ lduw [%g3 + TRAP_PER_CPU_RESUM_QMASK], %g4
+
/* Remember this entry's offset in %g1. */
mov %g2, %g1
add %g2, 0x08, %g2
/* Update queue head pointer. */
- sethi %hi(8192 - 1), %g4
- or %g4, %lo(8192 - 1), %g4
and %g2, %g4, %g2
mov INTRQ_RESUM_MONDO_HEAD, %g4
brnz,pn %g1, sun4v_nonres_mondo_queue_full
nop
+ lduw [%g3 + TRAP_PER_CPU_NONRESUM_QMASK], %g4
+
/* Remember this entry's offset in %g1. */
mov %g2, %g1
add %g2, 0x08, %g2
/* Update queue head pointer. */
- sethi %hi(8192 - 1), %g4
- or %g4, %lo(8192 - 1), %g4
and %g2, %g4, %g2
mov INTRQ_NONRESUM_MONDO_HEAD, %g4
static u32 hypervisor_get_time(void)
{
- register unsigned long func asm("%o5");
- register unsigned long arg0 asm("%o0");
- register unsigned long arg1 asm("%o1");
+ unsigned long ret, time;
int retries = 10000;
retry:
- func = HV_FAST_TOD_GET;
- arg0 = 0;
- arg1 = 0;
- __asm__ __volatile__("ta %6"
- : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
- : "0" (func), "1" (arg0), "2" (arg1),
- "i" (HV_FAST_TRAP));
- if (arg0 == HV_EOK)
- return arg1;
- if (arg0 == HV_EWOULDBLOCK) {
+ ret = sun4v_tod_get(&time);
+ if (ret == HV_EOK)
+ return time;
+ if (ret == HV_EWOULDBLOCK) {
if (--retries > 0) {
udelay(100);
goto retry;
static int hypervisor_set_time(u32 secs)
{
- register unsigned long func asm("%o5");
- register unsigned long arg0 asm("%o0");
+ unsigned long ret;
int retries = 10000;
retry:
- func = HV_FAST_TOD_SET;
- arg0 = secs;
- __asm__ __volatile__("ta %4"
- : "=&r" (func), "=&r" (arg0)
- : "0" (func), "1" (arg0),
- "i" (HV_FAST_TRAP));
- if (arg0 == HV_EOK)
+ ret = sun4v_tod_set(secs);
+ if (ret == HV_EOK)
return 0;
- if (arg0 == HV_EWOULDBLOCK) {
+ if (ret == HV_EWOULDBLOCK) {
if (--retries > 0) {
udelay(100);
goto retry;
static unsigned long sparc64_init_timers(void)
{
struct device_node *dp;
- struct property *prop;
unsigned long clock;
#ifdef CONFIG_SMP
extern void smp_tick_init(void);
if (manuf == 0x17 && impl == 0x13) {
/* Hummingbird, aka Ultra-IIe */
tick_ops = &hbtick_operations;
- prop = of_find_property(dp, "stick-frequency", NULL);
+ clock = of_getintprop_default(dp, "stick-frequency", 0);
} else {
tick_ops = &tick_operations;
- cpu_find_by_instance(0, &dp, NULL);
- prop = of_find_property(dp, "clock-frequency", NULL);
+ clock = local_cpu_data().clock_tick;
}
} else {
tick_ops = &stick_operations;
- prop = of_find_property(dp, "stick-frequency", NULL);
+ clock = of_getintprop_default(dp, "stick-frequency", 0);
}
- clock = *(unsigned int *) prop->value;
#ifdef CONFIG_SMP
smp_tick_init();
return hypervisor_set_time(seconds);
}
+#ifdef CONFIG_PCI
static void bq4802_get_rtc_time(struct rtc_time *time)
{
unsigned char val = readb(bq4802_regs + 0x0e);
return 0;
}
+#endif /* CONFIG_PCI */
struct mini_rtc_ops {
void (*get_rtc_time)(struct rtc_time *);
.set_rtc_time = hypervisor_set_rtc_time,
};
+#ifdef CONFIG_PCI
static struct mini_rtc_ops bq4802_rtc_ops = {
.get_rtc_time = bq4802_get_rtc_time,
.set_rtc_time = bq4802_set_rtc_time,
};
+#endif /* CONFIG_PCI */
static struct mini_rtc_ops *mini_rtc_ops;
mini_rtc_ops = &hypervisor_rtc_ops;
else if (this_is_starfire)
mini_rtc_ops = &starfire_rtc_ops;
+#ifdef CONFIG_PCI
else if (bq4802_regs)
mini_rtc_ops = &bq4802_rtc_ops;
+#endif /* CONFIG_PCI */
else
return -ENODEV;
void __init cheetah_ecache_flush_init(void)
{
unsigned long largest_size, smallest_linesize, order, ver;
- struct device_node *dp;
- int i, instance, sz;
+ int i, sz;
/* Scan all cpu device tree nodes, note two values:
* 1) largest E-cache size
largest_size = 0UL;
smallest_linesize = ~0UL;
- instance = 0;
- while (!cpu_find_by_instance(instance, &dp, NULL)) {
+ for (i = 0; i < NR_CPUS; i++) {
unsigned long val;
- val = of_getintprop_default(dp, "ecache-size",
- (2 * 1024 * 1024));
+ val = cpu_data(i).ecache_size;
+ if (!val)
+ continue;
+
if (val > largest_size)
largest_size = val;
- val = of_getintprop_default(dp, "ecache-line-size", 64);
+
+ val = cpu_data(i).ecache_line_size;
if (val < smallest_linesize)
smallest_linesize = val;
- instance++;
+
}
if (largest_size == 0UL || smallest_linesize == ~0UL) {
(TRAP_PER_CPU_TSB_HUGE_TEMP !=
offsetof(struct trap_per_cpu, tsb_huge_temp)) ||
(TRAP_PER_CPU_IRQ_WORKLIST !=
- offsetof(struct trap_per_cpu, irq_worklist)))
+ offsetof(struct trap_per_cpu, irq_worklist)) ||
+ (TRAP_PER_CPU_CPU_MONDO_QMASK !=
+ offsetof(struct trap_per_cpu, cpu_mondo_qmask)) ||
+ (TRAP_PER_CPU_DEV_MONDO_QMASK !=
+ offsetof(struct trap_per_cpu, dev_mondo_qmask)) ||
+ (TRAP_PER_CPU_RESUM_QMASK !=
+ offsetof(struct trap_per_cpu, resum_qmask)) ||
+ (TRAP_PER_CPU_NONRESUM_QMASK !=
+ offsetof(struct trap_per_cpu, nonresum_qmask)))
trap_per_cpu_offsets_are_bolixed_dave();
if ((TSB_CONFIG_TSB !=
#include <linux/kprobes.h>
#include <linux/cache.h>
#include <linux/sort.h>
+#include <linux/percpu.h>
#include <asm/head.h>
#include <asm/system.h>
#include <asm/tsb.h>
#include <asm/hypervisor.h>
#include <asm/prom.h>
-
-extern void device_scan(void);
+#include <asm/sstate.h>
+#include <asm/mdesc.h>
#define MAX_PHYS_ADDRESS (1UL << 42UL)
#define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL)
unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
#ifndef CONFIG_DEBUG_PAGEALLOC
-/* A special kernel TSB for 4MB and 256MB linear mappings. */
-struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES];
+/* A special kernel TSB for 4MB and 256MB linear mappings.
+ * Space is allocated for this right after the trap table
+ * in arch/sparc64/kernel/head.S
+ */
+extern struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES];
#endif
#define MAX_BANKS 32
}
#define PG_dcache_dirty PG_arch_1
-#define PG_dcache_cpu_shift 24UL
-#define PG_dcache_cpu_mask (256UL - 1UL)
-
-#if NR_CPUS > 256
-#error D-cache dirty tracking and thread_info->cpu need fixing for > 256 cpus
-#endif
+#define PG_dcache_cpu_shift 32UL
+#define PG_dcache_cpu_mask \
+ ((1UL<<ilog2(roundup_pow_of_two(NR_CPUS)))-1UL)
#define dcache_dirty_cpu(page) \
(((page)->flags >> PG_dcache_cpu_shift) & PG_dcache_cpu_mask)
unsigned long pte,
unsigned long mmu)
{
- register unsigned long func asm("%o5");
- register unsigned long arg0 asm("%o0");
- register unsigned long arg1 asm("%o1");
- register unsigned long arg2 asm("%o2");
- register unsigned long arg3 asm("%o3");
-
- func = HV_FAST_MMU_MAP_PERM_ADDR;
- arg0 = vaddr;
- arg1 = 0;
- arg2 = pte;
- arg3 = mmu;
- __asm__ __volatile__("ta 0x80"
- : "=&r" (func), "=&r" (arg0),
- "=&r" (arg1), "=&r" (arg2),
- "=&r" (arg3)
- : "0" (func), "1" (arg0), "2" (arg1),
- "3" (arg2), "4" (arg3));
- if (arg0 != 0) {
+ unsigned long ret = sun4v_mmu_map_perm_addr(vaddr, 0, pte, mmu);
+
+ if (ret != 0) {
prom_printf("hypervisor_tlb_lock[%lx:%lx:%lx:%lx]: "
- "errors with %lx\n", vaddr, 0, pte, mmu, arg0);
+ "errors with %lx\n", vaddr, 0, pte, mmu, ret);
prom_halt();
}
}
void __cpuinit sun4v_ktsb_register(void)
{
- register unsigned long func asm("%o5");
- register unsigned long arg0 asm("%o0");
- register unsigned long arg1 asm("%o1");
- unsigned long pa;
+ unsigned long pa, ret;
pa = kern_base + ((unsigned long)&ktsb_descr[0] - KERNBASE);
- func = HV_FAST_MMU_TSB_CTX0;
- arg0 = NUM_KTSB_DESCR;
- arg1 = pa;
- __asm__ __volatile__("ta %6"
- : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
- : "0" (func), "1" (arg0), "2" (arg1),
-