Merge branch 'master' of /home/trondmy/kernel/linux-2.6/

This commit is contained in:
Trond Myklebust 2006-06-25 06:44:44 -04:00
commit 76a9f26c9e
153 changed files with 7615 additions and 3523 deletions

View File

@ -25,42 +25,84 @@ the bits necessary to run your device. The most commonly
used members of this structure, and their typical usage,
will be detailed below.
Here is how probing is performed by an SBUS driver
under Linux:
Here is a piece of skeleton code for perofming a device
probe in an SBUS driverunder Linux:
static void init_one_mydevice(struct sbus_dev *sdev)
static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
{
struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
if (!mp)
return -ENODEV;
...
dev_set_drvdata(&sdev->ofdev.dev, mp);
return 0;
...
}
static int mydevice_match(struct sbus_dev *sdev)
static int __devinit mydevice_probe(struct of_device *dev,
const struct of_device_id *match)
{
if (some_criteria(sdev))
return 1;
return 0;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
return mydevice_probe_one(sdev);
}
static void mydevice_probe(void)
static int __devexit mydevice_remove(struct of_device *dev)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct mydevice *mp = dev_get_drvdata(&dev->dev);
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if (mydevice_match(sdev))
init_one_mydevice(sdev);
}
}
return mydevice_remove_one(sdev, mp);
}
All this does is walk through all SBUS devices in the
system, checks each to see if it is of the type which
your driver is written for, and if so it calls the init
routine to attach the device and prepare to drive it.
static struct of_device_id mydevice_match[] = {
{
.name = "mydevice",
},
{},
};
"init_one_mydevice" might do things like allocate software
state structures, map in I/O registers, place the hardware
into an initialized state, etc.
MODULE_DEVICE_TABLE(of, mydevice_match);
static struct of_platform_driver mydevice_driver = {
.name = "mydevice",
.match_table = mydevice_match,
.probe = mydevice_probe,
.remove = __devexit_p(mydevice_remove),
};
static int __init mydevice_init(void)
{
return of_register_driver(&mydevice_driver, &sbus_bus_type);
}
static void __exit mydevice_exit(void)
{
of_unregister_driver(&mydevice_driver);
}
module_init(mydevice_init);
module_exit(mydevice_exit);
The mydevice_match table is a series of entries which
describes what SBUS devices your driver is meant for. In the
simplest case you specify a string for the 'name' field. Every
SBUS device with a 'name' property matching your string will
be passed one-by-one to your .probe method.
You should store away your device private state structure
pointer in the drvdata area so that you can retrieve it later on
in your .remove method.
Any memory allocated, registers mapped, IRQs registered,
etc. must be undone by your .remove method so that all resources
of your device are relased by the time it returns.
You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
and for_all_sbusdev() interfaces. They are deprecated, will be
removed, and no new driver should reference them ever.
Mapping and Accessing I/O Registers
@ -263,10 +305,3 @@ discussed above and plus it handles both PCI and SBUS boards.
Lance driver abuses consistent mappings for data transfer.
It is a nifty trick which we do not particularly recommend...
Just check it out and know that it's legal.
Bad examples, do NOT use
drivers/video/cgsix.c
This one uses result of sbus_ioremap as if it is an address.
This does NOT work on sparc64 and therefore is broken. We will
convert it at a later date.

View File

@ -273,7 +273,7 @@ ENTRY(iwmmxt_task_restore)
*
* r0 = previous task_struct pointer (must be preserved)
* r1 = previous thread_info pointer
* r2 = next thread_info.cpu_domain pointer (must be preserved)
* r2 = next thread_info pointer (must be preserved)
*
* Called only from __switch_to with task preemption disabled.
* No need to care about preserving r4 and above.

View File

@ -134,17 +134,6 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
#ifdef CONFIG_IWMMXT
/* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */
#define IWMMXT_STORAGE_SIZE (0x98 + 8)
#define IWMMXT_MAGIC0 0x12ef842a
#define IWMMXT_MAGIC1 0x1c07ca71
struct iwmmxt_sigframe {
unsigned long magic0;
unsigned long magic1;
unsigned long storage[0x98/4];
};
static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
{
char kbuf[sizeof(*frame) + 8];
@ -152,8 +141,8 @@ static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
/* the iWMMXt context must be 64 bit aligned */
kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7);
kframe->magic0 = IWMMXT_MAGIC0;
kframe->magic1 = IWMMXT_MAGIC1;
kframe->magic = IWMMXT_MAGIC;
kframe->size = IWMMXT_STORAGE_SIZE;
iwmmxt_task_copy(current_thread_info(), &kframe->storage);
return __copy_to_user(frame, kframe, sizeof(*frame));
}
@ -167,8 +156,8 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7);
if (__copy_from_user(kframe, frame, sizeof(*frame)))
return -1;
if (kframe->magic0 != IWMMXT_MAGIC0 ||
kframe->magic1 != IWMMXT_MAGIC1)
if (kframe->magic != IWMMXT_MAGIC ||
kframe->size != IWMMXT_STORAGE_SIZE)
return -1;
iwmmxt_task_restore(current_thread_info(), &kframe->storage);
return 0;
@ -176,71 +165,62 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
#endif
/*
* Auxiliary signal frame. This saves stuff like FP state.
* The layout of this structure is not part of the user ABI.
*/
struct aux_sigframe {
#ifdef CONFIG_IWMMXT
struct iwmmxt_sigframe iwmmxt;
#endif
#ifdef CONFIG_VFP
union vfp_state vfp;
#endif
};
/*
* Do a signal return; undo the signal stack. These are aligned to 64-bit.
*/
struct sigframe {
struct sigcontext sc;
unsigned long extramask[_NSIG_WORDS-1];
struct ucontext uc;
unsigned long retcode[2];
struct aux_sigframe aux __attribute__((aligned(8)));
};
struct rt_sigframe {
struct siginfo __user *pinfo;
void __user *puc;
struct siginfo info;
struct ucontext uc;
unsigned long retcode[2];
struct aux_sigframe aux __attribute__((aligned(8)));
struct sigframe sig;
};
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
struct aux_sigframe __user *aux)
static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
{
int err = 0;
struct aux_sigframe __user *aux;
sigset_t set;
int err;
__get_user_error(regs->ARM_r0, &sc->arm_r0, err);
__get_user_error(regs->ARM_r1, &sc->arm_r1, err);
__get_user_error(regs->ARM_r2, &sc->arm_r2, err);
__get_user_error(regs->ARM_r3, &sc->arm_r3, err);
__get_user_error(regs->ARM_r4, &sc->arm_r4, err);
__get_user_error(regs->ARM_r5, &sc->arm_r5, err);
__get_user_error(regs->ARM_r6, &sc->arm_r6, err);
__get_user_error(regs->ARM_r7, &sc->arm_r7, err);
__get_user_error(regs->ARM_r8, &sc->arm_r8, err);
__get_user_error(regs->ARM_r9, &sc->arm_r9, err);
__get_user_error(regs->ARM_r10, &sc->arm_r10, err);
__get_user_error(regs->ARM_fp, &sc->arm_fp, err);
__get_user_error(regs->ARM_ip, &sc->arm_ip, err);
__get_user_error(regs->ARM_sp, &sc->arm_sp, err);
__get_user_error(regs->ARM_lr, &sc->arm_lr, err);
__get_user_error(regs->ARM_pc, &sc->arm_pc, err);
__get_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err);
err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
if (err == 0) {
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
}
__get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
__get_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err);
__get_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err);
__get_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err);
__get_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err);
__get_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err);
__get_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err);
__get_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err);
__get_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err);
__get_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err);
__get_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err);
__get_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err);
__get_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err);
__get_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err);
__get_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err);
__get_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err);
__get_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err);
err |= !valid_user_regs(regs);
aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
#ifdef CONFIG_IWMMXT
if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
err |= restore_iwmmxt_context(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
// if (err == 0)
// err |= vfp_restore_state(&aux->vfp);
// err |= vfp_restore_state(&sf->aux.vfp);
#endif
return err;
@ -249,7 +229,6 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
struct sigframe __user *frame;
sigset_t set;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
@ -266,19 +245,8 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
goto badframe;
if (__get_user(set.sig[0], &frame->sc.oldmask)
|| (_NSIG_WORDS > 1
&& __copy_from_user(&set.sig[1], &frame->extramask,
sizeof(frame->extramask))))
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
if (restore_sigcontext(regs, &frame->sc, &frame->aux))
if (restore_sigframe(regs, frame))
goto badframe;
/* Send SIGTRAP if we're single-stepping */
@ -297,7 +265,6 @@ badframe:
asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
sigset_t set;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
@ -314,19 +281,11 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
goto badframe;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
if (restore_sigframe(regs, &frame->sig))
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &frame->aux))
goto badframe;
if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT)
if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT)
goto badframe;
/* Send SIGTRAP if we're single-stepping */
@ -343,42 +302,46 @@ badframe:
}
static int
setup_sigcontext(struct sigcontext __user *sc, struct aux_sigframe __user *aux,
struct pt_regs *regs, unsigned long mask)
setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
{
struct aux_sigframe __user *aux;
int err = 0;
__put_user_error(regs->ARM_r0, &sc->arm_r0, err);
__put_user_error(regs->ARM_r1, &sc->arm_r1, err);
__put_user_error(regs->ARM_r2, &sc->arm_r2, err);
__put_user_error(regs->ARM_r3, &sc->arm_r3, err);
__put_user_error(regs->ARM_r4, &sc->arm_r4, err);
__put_user_error(regs->ARM_r5, &sc->arm_r5, err);
__put_user_error(regs->ARM_r6, &sc->arm_r6, err);
__put_user_error(regs->ARM_r7, &sc->arm_r7, err);
__put_user_error(regs->ARM_r8, &sc->arm_r8, err);
__put_user_error(regs->ARM_r9, &sc->arm_r9, err);
__put_user_error(regs->ARM_r10, &sc->arm_r10, err);
__put_user_error(regs->ARM_fp, &sc->arm_fp, err);
__put_user_error(regs->ARM_ip, &sc->arm_ip, err);
__put_user_error(regs->ARM_sp, &sc->arm_sp, err);
__put_user_error(regs->ARM_lr, &sc->arm_lr, err);
__put_user_error(regs->ARM_pc, &sc->arm_pc, err);
__put_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err);
__put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
__put_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err);
__put_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err);
__put_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err);
__put_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err);
__put_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err);
__put_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err);
__put_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err);
__put_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err);
__put_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err);
__put_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err);
__put_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err);
__put_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err);
__put_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err);
__put_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err);
__put_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err);
__put_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err);
__put_user_error(current->thread.trap_no, &sc->trap_no, err);
__put_user_error(current->thread.error_code, &sc->error_code, err);
__put_user_error(current->thread.address, &sc->fault_address, err);
__put_user_error(mask, &sc->oldmask, err);
__put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err);
__put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err);
__put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err);
__put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);
err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
#ifdef CONFIG_IWMMXT
if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
err |= preserve_iwmmxt_context(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
// if (err == 0)
// err |= vfp_save_state(&aux->vfp);
// err |= vfp_save_state(&sf->aux.vfp);
#endif
__put_user_error(0, &aux->end_magic, err);
return err;
}
@ -487,13 +450,12 @@ setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *reg
if (!frame)
return 1;
err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]);
if (_NSIG_WORDS > 1) {
err |= __copy_to_user(frame->extramask, &set->sig[1],
sizeof(frame->extramask));
}
/*
* Set uc.uc_flags to a value which sc.trap_no would never have.
*/
__put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err);
err |= setup_sigframe(frame, regs, set);
if (err == 0)
err = setup_return(regs, ka, frame->retcode, frame, usig);
@ -511,25 +473,20 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
if (!frame)
return 1;
__put_user_error(&frame->info, &frame->pinfo, err);
__put_user_error(&frame->uc, &frame->puc, err);
err |= copy_siginfo_to_user(&frame->info, info);
__put_user_error(0, &frame->uc.uc_flags, err);
__put_user_error(NULL, &frame->uc.uc_link, err);
__put_user_error(0, &frame->sig.uc.uc_flags, err);
__put_user_error(NULL, &frame->sig.uc.uc_link, err);
memset(&stack, 0, sizeof(stack));
stack.ss_sp = (void __user *)current->sas_ss_sp;
stack.ss_flags = sas_ss_flags(regs->ARM_sp);
stack.ss_size = current->sas_ss_size;
err |= __copy_to_user(&frame->uc.uc_stack, &stack, sizeof(stack));
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->aux,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
err |= __copy_to_user(&frame->sig.uc.uc_stack, &stack, sizeof(stack));
err |= setup_sigframe(&frame->sig, regs, set);
if (err == 0)
err = setup_return(regs, ka, frame->retcode, frame, usig);
err = setup_return(regs, ka, frame->sig.retcode, frame, usig);
if (err == 0) {
/*
@ -538,7 +495,7 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
* -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
*/
regs->ARM_r1 = (unsigned long)&frame->info;
regs->ARM_r2 = (unsigned long)&frame->uc;
regs->ARM_r2 = (unsigned long)&frame->sig.uc;
}
return err;

View File

@ -1,7 +1,7 @@
#
# Makefile for the linux kernel.
#
obj-y := core.o
obj-y := core.o clock.o
obj-m :=
obj-n :=
obj- :=

View File

@ -0,0 +1,156 @@
/*
* arch/arm/mach-ep93xx/clock.c
* Clock control for Cirrus EP93xx chips.
*
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/string.h>
#include <asm/div64.h>
#include <asm/hardware.h>
#include <asm/io.h>
struct clk {
char *name;
unsigned long rate;
int users;
u32 enable_reg;
u32 enable_mask;
};
static struct clk clk_pll1 = {
.name = "pll1",
};
static struct clk clk_f = {
.name = "fclk",
};
static struct clk clk_h = {
.name = "hclk",
};
static struct clk clk_p = {
.name = "pclk",
};
static struct clk clk_pll2 = {
.name = "pll2",
};
static struct clk clk_usb_host = {
.name = "usb_host",
.enable_reg = EP93XX_SYSCON_CLOCK_CONTROL,
.enable_mask = EP93XX_SYSCON_CLOCK_USH_EN,
};
static struct clk *clocks[] = {
&clk_pll1,
&clk_f,
&clk_h,
&clk_p,
&clk_pll2,
&clk_usb_host,
};
struct clk *clk_get(struct device *dev, const char *id)
{
int i;
for (i = 0; i < ARRAY_SIZE(clocks); i++) {
if (!strcmp(clocks[i]->name, id))
return clocks[i];
}
return ERR_PTR(-ENOENT);
}
int clk_enable(struct clk *clk)
{
if (!clk->users++ && clk->enable_reg) {
u32 value;
value = __raw_readl(clk->enable_reg);
__raw_writel(value | clk->enable_mask, clk->enable_reg);
}
return 0;
}
void clk_disable(struct clk *clk)
{
if (!--clk->users && clk->enable_reg) {
u32 value;
value = __raw_readl(clk->enable_reg);
__raw_writel(value & ~clk->enable_mask, clk->enable_reg);
}
}
unsigned long clk_get_rate(struct clk *clk)
{
return clk->rate;
}
void clk_put(struct clk *clk)
{
}
static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
static char pclk_divisors[] = { 1, 2, 4, 8 };
/*
* PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS
*/
static unsigned long calc_pll_rate(u32 config_word)
{
unsigned long long rate;
int i;
rate = 14745600;
rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */
rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */
do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */
for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */
rate >>= 1;
return (unsigned long)rate;
}
void ep93xx_clock_init(void)
{
u32 value;
value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1);
if (!(value & 0x00800000)) { /* PLL1 bypassed? */
clk_pll1.rate = 14745600;
} else {
clk_pll1.rate = calc_pll_rate(value);
}
clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7];
clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7];
clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3];
value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2);
if (!(value & 0x00080000)) { /* PLL2 bypassed? */
clk_pll2.rate = 14745600;
} else if (value & 0x00040000) { /* PLL2 enabled? */
clk_pll2.rate = calc_pll_rate(value);
} else {
clk_pll2.rate = 0;
}
clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1);
printk(KERN_INFO "ep93xx: PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
clk_pll1.rate / 1000000, clk_pll2.rate / 1000000);
printk(KERN_INFO "ep93xx: FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
clk_f.rate / 1000000, clk_h.rate / 1000000,
clk_p.rate / 1000000);
}

View File

@ -433,10 +433,37 @@ static struct platform_device ep93xx_rtc_device = {
};
static struct resource ep93xx_ohci_resources[] = {
[0] = {
.start = EP93XX_USB_PHYS_BASE,
.end = EP93XX_USB_PHYS_BASE + 0x0fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_EP93XX_USB,
.end = IRQ_EP93XX_USB,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device ep93xx_ohci_device = {
.name = "ep93xx-ohci",
.id = -1,
.dev = {
.dma_mask = (void *)0xffffffff,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(ep93xx_ohci_resources),
.resource = ep93xx_ohci_resources,
};
void __init ep93xx_init_devices(void)
{
unsigned int v;
ep93xx_clock_init();
/*
* Disallow access to MaverickCrunch initially.
*/
@ -450,4 +477,5 @@ void __init ep93xx_init_devices(void)
amba_device_register(&uart3_device, &iomem_resource);
platform_device_register(&ep93xx_rtc_device);
platform_device_register(&ep93xx_ohci_device);
}

View File

@ -302,6 +302,7 @@ void gpio_line_config(int line, int direction)
}
local_irq_restore(flags);
}
EXPORT_SYMBOL(gpio_line_config);
/*************************************************************************

View File

@ -81,6 +81,12 @@ config SMDK2440_CPU2442
depends on ARCH_S3C2440
select CPU_S3C2442
config MACH_SMDK2413
bool "SMDK2413"
select CPU_S3C2412
select MACH_SMDK
help
Say Y here if you are using an SMDK2413
config MACH_VR1000
bool "Thorcom VR1000"
@ -127,6 +133,20 @@ config CPU_S3C2410
Support for S3C2410 and S3C2410A family from the S3C24XX line
of Samsung Mobile CPUs.
# internal node to signify if we are only dealing with an S3C2412
config CPU_S3C2412_ONLY
bool
depends on ARCH_S3C2410 && !CPU_S3C2400 && !CPU_S3C2410 && \
!CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412
default y if CPU_S3C2412
config CPU_S3C2412
bool
depends on ARCH_S3C2410
help
Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line
config CPU_S3C244X
bool
depends on ARCH_S3C2410 && (CPU_S3C2440 || CPU_S3C2442)

View File

@ -24,6 +24,11 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
# S3C2412 support
obj-$(CONFIG_CPU_S3C2412) += s3c2412.o
obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o
#
# S3C244X support
obj-$(CONFIG_CPU_S3C244X) += s3c244x.o
@ -57,6 +62,7 @@ obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
obj-$(CONFIG_ARCH_H1940) += mach-h1940.o
obj-$(CONFIG_MACH_N30) += mach-n30.o
obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o
obj-$(CONFIG_MACH_SMDK2413) += mach-smdk2413.o
obj-$(CONFIG_ARCH_S3C2440) += mach-smdk2440.o
obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o

View File

@ -213,7 +213,7 @@ EXPORT_SYMBOL(clk_set_parent);
/* base clocks */
static struct clk clk_xtal = {
struct clk clk_xtal = {
.name = "xtal",
.id = -1,
.rate = 0,
@ -221,6 +221,11 @@ static struct clk clk_xtal = {
.ctrlbit = 0,
};
struct clk clk_mpll = {
.name = "mpll",
.id = -1,
};
struct clk clk_upll = {
.name = "upll",
.id = -1,
@ -232,7 +237,7 @@ struct clk clk_f = {
.name = "fclk",
.id = -1,
.rate = 0,
.parent = NULL,
.parent = &clk_mpll,
.ctrlbit = 0,
};
@ -263,14 +268,14 @@ struct clk clk_usb_bus = {
static int s3c24xx_dclk_enable(struct clk *clk, int enable)
{
unsigned long dclkcon = __raw_readl(S3C2410_DCLKCON);
unsigned long dclkcon = __raw_readl(S3C24XX_DCLKCON);
if (enable)
dclkcon |= clk->ctrlbit;
else
dclkcon &= ~clk->ctrlbit;
__raw_writel(dclkcon, S3C2410_DCLKCON);
__raw_writel(dclkcon, S3C24XX_DCLKCON);
return 0;
}
@ -289,7 +294,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
clk->parent = parent;
dclkcon = __raw_readl(S3C2410_DCLKCON);
dclkcon = __raw_readl(S3C24XX_DCLKCON);
if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
if (uclk)
@ -303,7 +308,7 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
}
__raw_writel(dclkcon, S3C2410_DCLKCON);
__raw_writel(dclkcon, S3C24XX_DCLKCON);
return 0;
}
@ -413,6 +418,7 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
clk_xtal.rate = xtal;
clk_upll.rate = s3c2410_get_pll(__raw_readl(S3C2410_UPLLCON), xtal);
clk_mpll.rate = fclk;
clk_h.rate = hclk;
clk_p.rate = pclk;
clk_f.rate = fclk;
@ -424,6 +430,9 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
if (s3c24xx_register_clock(&clk_xtal) < 0)
printk(KERN_ERR "failed to register master xtal\n");
if (s3c24xx_register_clock(&clk_mpll) < 0)
printk(KERN_ERR "failed to register mpll clock\n");
if (s3c24xx_register_clock(&clk_upll) < 0)
printk(KERN_ERR "failed to register upll clock\n");

View File

@ -42,7 +42,9 @@ extern struct clk clk_usb_bus;
extern struct clk clk_f;
extern struct clk clk_h;
extern struct clk clk_p;
extern struct clk clk_mpll;
extern struct clk clk_upll;
extern struct clk clk_xtal;
/* exports for arch/arm/mach-s3c2410
*

View File

@ -44,6 +44,7 @@
#include "clock.h"
#include "s3c2400.h"
#include "s3c2410.h"
#include "s3c2412.h"
#include "s3c244x.h"
#include "s3c2440.h"
#include "s3c2442.h"
@ -62,6 +63,7 @@ struct cpu_table {
static const char name_s3c2400[] = "S3C2400";
static const char name_s3c2410[] = "S3C2410";
static const char name_s3c2412[] = "S3C2412";
static const char name_s3c2440[] = "S3C2440";
static const char name_s3c2442[] = "S3C2442";
static const char name_s3c2410a[] = "S3C2410A";
@ -113,6 +115,15 @@ static struct cpu_table cpu_ids[] __initdata = {
.init = s3c2442_init,
.name = name_s3c2442
},
{
.idcode = 0x32412001,
.idmask = 0xffffffff,
.map_io = s3c2412_map_io,
.init_clocks = s3c2412_init_clocks,
.init_uarts = s3c2412_init_uarts,
.init = s3c2412_init,
.name = name_s3c2412,
},
{
.idcode = 0x0, /* S3C2400 doesn't have an idcode */
.idmask = 0xffffffff,
@ -171,6 +182,24 @@ void s3c24xx_set_board(struct s3c24xx_board *b)
static struct cpu_table *cpu;
static unsigned long s3c24xx_read_idcode_v5(void)
{
#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
return __raw_readl(S3C2412_GSTATUS1);
#else
return 1UL; /* don't look like an 2400 */
#endif
}
static unsigned long s3c24xx_read_idcode_v4(void)
{
#ifndef CONFIG_CPU_S3C2400
return __raw_readl(S3C2410_GSTATUS1);
#else
return 0UL;
#endif
}
void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
{
unsigned long idcode = 0x0;
@ -178,9 +207,11 @@ void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
/* initialise the io descriptors we need for initialisation */
iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
#ifndef CONFIG_CPU_S3C2400
idcode = __raw_readl(S3C2410_GSTATUS1);
#endif
if (cpu_architecture() >= CPU_ARCH_ARMv5) {
idcode = s3c24xx_read_idcode_v5();
} else {
idcode = s3c24xx_read_idcode_v4();
}
cpu = s3c_lookup_cpu(idcode);

View File

@ -74,5 +74,6 @@ extern struct sys_timer s3c24xx_timer;
/* system device classes */
extern struct sysdev_class s3c2410_sysclass;
extern struct sysdev_class s3c2412_sysclass;
extern struct sysdev_class s3c2440_sysclass;
extern struct sysdev_class s3c2442_sysclass;

View File

@ -191,13 +191,9 @@ static struct irqchip s3c_irq_chip = {
.ack = s3c_irq_ack,
.mask = s3c_irq_mask,
.unmask = s3c_irq_unmask,
.set_wake = s3c_irq_wake
.set_wake = s3c_irq_wake
};
/* S3C2410_EINTMASK
* S3C2410_EINTPEND
*/
static void
s3c_irqext_mask(unsigned int irqno)
{
@ -205,9 +201,9 @@ s3c_irqext_mask(unsigned int irqno)
irqno -= EXTINT_OFF;
mask = __raw_readl(S3C2410_EINTMASK);
mask = __raw_readl(S3C24XX_EINTMASK);
mask |= ( 1UL << irqno);
__raw_writel(mask, S3C2410_EINTMASK);
__raw_writel(mask, S3C24XX_EINTMASK);
if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) {
/* check to see if all need masking */
@ -232,11 +228,11 @@ s3c_irqext_ack(unsigned int irqno)
bit = 1UL << (irqno - EXTINT_OFF);
mask = __raw_readl(S3C2410_EINTMASK);
mask = __raw_readl(S3C24XX_EINTMASK);
__raw_writel(bit, S3C2410_EINTPEND);
__raw_writel(bit, S3C24XX_EINTPEND);
req = __raw_readl(S3C2410_EINTPEND);
req = __raw_readl(S3C24XX_EINTPEND);
req &= ~mask;
/* not sure if we should be acking the parent irq... */
@ -257,9 +253,9 @@ s3c_irqext_unmask(unsigned int irqno)
irqno -= EXTINT_OFF;
mask = __raw_readl(S3C2410_EINTMASK);
mask = __raw_readl(S3C24XX_EINTMASK);
mask &= ~( 1UL << irqno);
__raw_writel(mask, S3C2410_EINTMASK);
__raw_writel(mask, S3C24XX_EINTMASK);
s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23);
}
@ -275,28 +271,28 @@ s3c_irqext_type(unsigned int irq, unsigned int type)
if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
{
gpcon_reg = S3C2410_GPFCON;
extint_reg = S3C2410_EXTINT0;
extint_reg = S3C24XX_EXTINT0;
gpcon_offset = (irq - IRQ_EINT0) * 2;
extint_offset = (irq - IRQ_EINT0) * 4;
}
else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
{
gpcon_reg = S3C2410_GPFCON;
extint_reg = S3C2410_EXTINT0;
extint_reg = S3C24XX_EXTINT0;
gpcon_offset = (irq - (EXTINT_OFF)) * 2;
extint_offset = (irq - (EXTINT_OFF)) * 4;
}
else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
{
gpcon_reg = S3C2410_GPGCON;
extint_reg = S3C2410_EXTINT1;
extint_reg = S3C24XX_EXTINT1;
gpcon_offset = (irq - IRQ_EINT8) * 2;
extint_offset = (irq - IRQ_EINT8) * 4;
}
else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
{
gpcon_reg = S3C2410_GPGCON;
extint_reg = S3C2410_EXTINT2;
extint_reg = S3C24XX_EXTINT2;
gpcon_offset = (irq - IRQ_EINT8) * 2;
extint_offset = (irq - IRQ_EINT16) * 4;
} else
@ -572,6 +568,23 @@ s3c_irq_demux_uart2(unsigned int irq,
s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs);
}
static void
s3c_irq_demux_extint(unsigned int irq,
struct irqdesc *desc,
struct pt_regs *regs)
{
unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
eintpnd &= ~eintmsk;
if (eintpnd) {
irq = fls(eintpnd);
irq += (IRQ_EINT4 - (4 + 1));
desc_handle_irq(irq, irq_desc + irq, regs);
}
}
/* s3c24xx_init_irq
*
@ -591,12 +604,12 @@ void __init s3c24xx_init_irq(void)
last = 0;
for (i = 0; i < 4; i++) {
pend = __raw_readl(S3C2410_EINTPEND);
pend = __raw_readl(S3C24XX_EINTPEND);
if (pend == 0 || pend == last)
break;
__raw_writel(pend, S3C2410_EINTPEND);
__raw_writel(pend, S3C24XX_EINTPEND);
printk("irq: clearing pending ext status %08x\n", (int)pend);
last = pend;
}
@ -630,12 +643,14 @@ void __init s3c24xx_init_irq(void)
irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) {
for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
/* set all the s3c2410 internal irqs */
switch (irqno) {
/* deal with the special IRQs (cascaded) */
case IRQ_EINT4t7:
case IRQ_EINT8t23:
case IRQ_UART0:
case IRQ_UART1:
case IRQ_UART2:
@ -659,12 +674,14 @@ void __init s3c24xx_init_irq(void)
/* setup the cascade irq handlers */
set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint);
set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint);
set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
/* external interrupts */
for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {

View File

@ -0,0 +1,126 @@
/* linux/arch/arm/mach-s3c2410/mach-smdk2413.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* Thanks to Dimity Andric (TomTom) and Steven Ryu (Samsung) for the
* loans of SMDK2413 to work with.
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include <asm/hardware.h>
#include <asm/hardware/iomd.h>
#include <asm/setup.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
//#include <asm/debug-ll.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/idle.h>
#include <asm/arch/fb.h>
#include "s3c2410.h"
#include "s3c2412.h"
#include "clock.h"
#include "devs.h"
#include "cpu.h"
#include "common-smdk.h"
static struct map_desc smdk2413_iodesc[] __initdata = {
};
static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = {
[0] = {
.hwport = 0,
.flags = 0,
.ucon = 0x3c5,
.ulcon = 0x03,
.ufcon = 0x51,
},
[1] = {
.hwport = 1,
.flags = 0,
.ucon = 0x3c5,
.ulcon = 0x03,
.ufcon = 0x51,
},
/* IR port */
[2] = {
.hwport = 2,
.flags = 0,
.ucon = 0x3c5,
.ulcon = 0x43,
.ufcon = 0x51,
}
};
static struct platform_device *smdk2413_devices[] __initdata = {
&s3c_device_usb,
//&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
};
static struct s3c24xx_board smdk2413_board __initdata = {
.devices = smdk2413_devices,
.devices_count = ARRAY_SIZE(smdk2413_devices)
};
static void __init smdk2413_fixup(struct machine_desc *desc,
struct tag *tags, char **cmdline,
struct meminfo *mi)
{
if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
mi->nr_banks=1;
mi->bank[0].start = 0x30000000;
mi->bank[0].size = SZ_64M;
mi->bank[0].node = 0;
}
}
static void __init smdk2413_map_io(void)
{
s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc));
s3c24xx_init_clocks(12000000);
s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs));
s3c24xx_set_board(&smdk2413_board);
}
static void __init smdk2413_machine_init(void)
{
smdk_machine_init();
}
MACHINE_START(S3C2413, "SMDK2413")
/* Maintainer: Ben Dooks <ben@fluff.org> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.fixup = smdk2413_fixup,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2413_map_io,
.init_machine = smdk2413_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END

View File

@ -48,7 +48,8 @@ static __init int pm_simtec_init(void)
/* check which machine we are running on */
if (!machine_is_bast() && !machine_is_vr1000() && !machine_is_anubis())
if (!machine_is_bast() && !machine_is_vr1000() &&
!machine_is_anubis() && !machine_is_osiris())
return 0;
printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n");

View File

@ -182,7 +182,15 @@ static struct clk init_clocks[] = {
.id = -1,
.parent = &clk_p,
.ctrlbit = 0,
}
}, {
.name = "usb-bus-host",
.id = -1,
.parent = &clk_usb_bus,
}, {
.name = "usb-bus-gadget",
.id = -1,
.parent = &clk_usb_bus,
},
};
/* s3c2410_baseclk_add()

View File

@ -18,9 +18,6 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Changelog
* 15-Jan-2006 LCVR Splitted from gpio.c
*/
#include <linux/kernel.h>
@ -38,7 +35,7 @@
int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
unsigned int config)
{
void __iomem *reg = S3C2410_EINFLT0;
void __iomem *reg = S3C24XX_EINFLT0;
unsigned long flags;
unsigned long val;
@ -47,7 +44,7 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
config &= 0xff;
pin -= S3C2410_GPG8_EINT16;
pin -= S3C2410_GPG8;
reg += pin & ~3;
local_irq_save(flags);
@ -61,10 +58,10 @@ int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
/* update filter enable */
val = __raw_readl(S3C2410_EXTINT2);
val = __raw_readl(S3C24XX_EXTINT2);
val &= ~(1 << ((pin * 4) + 3));
val |= on << ((pin * 4) + 3);
__raw_writel(val, S3C2410_EXTINT2);
__raw_writel(val, S3C24XX_EXTINT2);
local_irq_restore(flags);
@ -75,7 +72,7 @@ EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
int s3c2410_gpio_getirq(unsigned int pin)
{
if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23)
if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15)
return -1; /* not valid interrupts */
if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)

View File

@ -0,0 +1,711 @@
/* linux/arch/arm/mach-s3c2410/s3c2412-clock.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2412,S3C2413 Clock control support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/sysdev.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
#include "clock.h"
#include "cpu.h"
/* We currently have to assume that the system is running
* from the XTPll input, and that all ***REFCLKs are being
* fed from it, as we cannot read the state of OM[4] from
* software.
*
* It would be possible for each board initialisation to
* set the correct muxing at initialisation
*/
int s3c2412_clkcon_enable(struct clk *clk, int enable)
{
unsigned int clocks = clk->ctrlbit;
unsigned long clkcon;
clkcon = __raw_readl(S3C2410_CLKCON);
if (enable)
clkcon |= clocks;
else
clkcon &= ~clocks;
__raw_writel(clkcon, S3C2410_CLKCON);
return 0;
}
static int s3c2412_upll_enable(struct clk *clk, int enable)
{
unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
unsigned long orig = upllcon;
if (!enable)
upllcon |= S3C2412_PLLCON_OFF;
else
upllcon &= ~S3C2412_PLLCON_OFF;
__raw_writel(upllcon, S3C2410_UPLLCON);
/* allow ~150uS for the PLL to settle and lock */
if (enable && (orig & S3C2412_PLLCON_OFF))
udelay(150);
return 0;
}
/* clock selections */
/* CPU EXTCLK input */
static struct clk clk_ext = {
.name = "extclk",
.id = -1,
};
static struct clk clk_erefclk = {
.name = "erefclk",
.id = -1,
};
static struct clk clk_urefclk = {
.name = "urefclk",
.id = -1,
};
static int s3c2412_setparent_usysclk(struct clk *clk, struct clk *parent)
{
unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
if (parent == &clk_urefclk)
clksrc &= ~S3C2412_CLKSRC_USYSCLK_UPLL;
else if (parent == &clk_upll)
clksrc |= S3C2412_CLKSRC_USYSCLK_UPLL;
else
return -EINVAL;
clk->parent = parent;
__raw_writel(clksrc, S3C2412_CLKSRC);
return 0;
}
static struct clk clk_usysclk = {
.name = "usysclk",
.id = -1,
.parent = &clk_xtal,
.set_parent = s3c2412_setparent_usysclk,
};
static struct clk clk_mrefclk = {
.name = "mrefclk",
.parent = &clk_xtal,
.id = -1,
};
static struct clk clk_mdivclk = {
.name = "mdivclk",
.parent = &clk_xtal,
.id = -1,
};
static int s3c2412_setparent_usbsrc(struct clk *clk, struct clk *parent)
{
unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
if (parent == &clk_usysclk)
clksrc &= ~S3C2412_CLKSRC_USBCLK_HCLK;
else if (parent == &clk_h)
clksrc |= S3C2412_CLKSRC_USBCLK_HCLK;
else
return -EINVAL;
clk->parent = parent;
__raw_writel(clksrc, S3C2412_CLKSRC);
return 0;
}
static unsigned long s3c2412_roundrate_usbsrc(struct clk *clk,
unsigned long rate)
{
unsigned long parent_rate = clk_get_rate(clk->parent);
int div;
if (rate > parent_rate)
return parent_rate;
div = parent_rate / rate;
if (div > 2)
div = 2;
return parent_rate / div;
}
static unsigned long s3c2412_getrate_usbsrc(struct clk *clk)
{
unsigned long parent_rate = clk_get_rate(clk->parent);
unsigned long div = __raw_readl(S3C2410_CLKDIVN);
return parent_rate / ((div & S3C2412_CLKDIVN_USB48DIV) ? 2 : 1);
}
static int s3c2412_setrate_usbsrc(struct clk *clk, unsigned long rate)
{
unsigned long parent_rate = clk_get_rate(clk->parent);
unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
rate = s3c2412_roundrate_usbsrc(clk, rate);
if ((parent_rate / rate) == 2)
clkdivn |= S3C2412_CLKDIVN_USB48DIV;
else
clkdivn &= ~S3C2412_CLKDIVN_USB48DIV;
__raw_writel(clkdivn, S3C2410_CLKDIVN);
return 0;
}
static struct clk clk_usbsrc = {
.name = "usbsrc",
.id = -1,
.get_rate = s3c2412_getrate_usbsrc,
.set_rate = s3c2412_setrate_usbsrc,
.round_rate = s3c2412_roundrate_usbsrc,
.set_parent = s3c2412_setparent_usbsrc,
};
static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent)
{
unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
if (parent == &clk_mdivclk)
clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL;
else if (parent == &clk_upll)
clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL;
else
return -EINVAL;
clk->parent = parent;
__raw_writel(clksrc, S3C2412_CLKSRC);
return 0;
}
static struct clk clk_msysclk = {
.name = "msysclk",
.id = -1,
.set_parent = s3c2412_setparent_msysclk,
};
/* these next clocks have an divider immediately after them,
* so we can register them with their divider and leave out the
* intermediate clock stage
*/
static unsigned long s3c2412_roundrate_clksrc(struct clk *clk,
unsigned long rate)
{
unsigned long parent_rate = clk_get_rate(clk->parent);
int div;
if (rate > parent_rate)
return parent_rate;
/* note, we remove the +/- 1 calculations as they cancel out */
div = (rate / parent_rate);
if (div < 1)
div = 1;
else if (div > 16)
div = 16;
return parent_rate / div;
}
static int s3c2412_setparent_uart(struct clk *clk, struct clk *parent)
{
unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
if (parent == &clk_erefclk)
clksrc &= ~S3C2412_CLKSRC_UARTCLK_MPLL;
else if (parent == &clk_mpll)
clksrc |= S3C2412_CLKSRC_UARTCLK_MPLL;
else
return -EINVAL;
clk->parent = parent;
__raw_writel(clksrc, S3C2412_CLKSRC);
return 0;
}
static unsigned long s3c2412_getrate_uart(struct clk *clk)
{
unsigned long parent_rate = clk_get_rate(clk->parent);
unsigned long div = __raw_readl(S3C2410_CLKDIVN);
div &= S3C2412_CLKDIVN_UARTDIV_MASK;
div >>= S3C2412_CLKDIVN_UARTDIV_SHIFT;
return parent_rate / (div + 1);
}
static int s3c2412_setrate_uart(struct clk *clk, unsigned long rate)
{
unsigned long parent_rate = clk_get_rate(clk->parent);
unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
rate = s3c2412_roundrate_clksrc(clk, rate);
clkdivn &= ~S3C2412_CLKDIVN_UARTDIV_MASK;
clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_UARTDIV_SHIFT;
__raw_writel(clkdivn, S3C2410_CLKDIVN);
return 0;
}
static struct clk clk_uart = {
.name = "uartclk",
.id = -1,
.get_rate = s3c2412_getrate_uart,
.set_rate = s3c2412_setrate_uart,
.set_parent = s3c2412_setparent_uart,
.round_rate = s3c2412_roundrate_clksrc,
};
static int s3c2412_setparent_i2s(struct clk *clk, struct clk *parent)
{
unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
if (parent == &clk_erefclk)
clksrc &= ~S3C2412_CLKSRC_I2SCLK_MPLL;
else if (parent == &clk_mpll)
clksrc |= S3C2412_CLKSRC_I2SCLK_MPLL;
else
return -EINVAL;
clk->parent = parent;
__raw_writel(clksrc, S3C2412_CLKSRC);
return 0;
}
static unsigned long s3c2412_getrate_i2s(struct clk *clk)
{
unsigned long parent_rate = clk_get_rate(clk->parent);
unsigned long div = __raw_readl(S3C2410_CLKDIVN);
div &= S3C2412_CLKDIVN_I2SDIV_MASK;
div >>= S3C2412_CLKDIVN_I2SDIV_SHIFT;
return parent_rate / (div + 1);
}
static int s3c2412_setrate_i2s(struct clk *clk, unsigned long rate)
{
unsigned long parent_rate = clk_get_rate(clk->parent);
unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
rate = s3c2412_roundrate_clksrc(clk, rate);
clkdivn &= ~S3C2412_CLKDIVN_I2SDIV_MASK;
clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_I2SDIV_SHIFT;
__raw_writel(clkdivn, S3C2410_CLKDIVN);
return 0;
}
static struct clk clk_i2s = {
.name = "i2sclk",
.id = -1,
.get_rate = s3c2412_getrate_i2s,
.set_rate = s3c2412_setrate_i2s,
.set_parent = s3c2412_setparent_i2s,
.round_rate = s3c2412_roundrate_clksrc,
};
static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent)
{
unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
if (parent == &clk_usysclk)
clksrc &= ~S3C2412_CLKSRC_CAMCLK_HCLK;
else if (parent == &clk_h)
clksrc |= S3C2412_CLKSRC_CAMCLK_HCLK;
else
return -EINVAL;
clk->parent = parent;
__raw_writel(clksrc, S3C2412_CLKSRC);
return 0;
}
static unsigned long s3c2412_getrate_cam(struct clk *clk)
{
unsigned long parent_rate = clk_get_rate(clk->parent);
unsigned long div = __raw_readl(S3C2410_CLKDIVN);
div &= S3C2412_CLKDIVN_CAMDIV_MASK;
div >>= S3C2412_CLKDIVN_CAMDIV_SHIFT;
return parent_rate / (div + 1);
}
static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate)
{
unsigned long parent_rate = clk_get_rate(clk->parent);
unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
rate = s3c2412_roundrate_clksrc(clk, rate);
clkdivn &= ~S3C2412_CLKDIVN_CAMDIV_MASK;
clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_CAMDIV_SHIFT;
__raw_writel(clkdivn, S3C2410_CLKDIVN);
return 0;
}
static struct clk clk_cam = {
.name = "camif-upll", /* same as 2440 name */
.id = -1,
.get_rate = s3c2412_getrate_cam,
.set_rate = s3c2412_setrate_cam,
.set_parent = s3c2412_setparent_cam,
.round_rate = s3c2412_roundrate_clksrc,
};
/* standard clock definitions */
static struct clk init_clocks_disable[] = {
{
.name = "nand",
.id = -1,
.parent = &clk_h,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_NAND,
}, {
.name = "sdi",
.id = -1,
.parent = &clk_p,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_SDI,
}, {
.name = "adc",
.id = -1,
.parent = &clk_p,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_ADC,
}, {
.name = "i2c",
.id = -1,
.parent = &clk_p,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_IIC,
}, {
.name = "iis",
.id = -1,
.parent = &clk_p,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_IIS,
}, {
.name = "spi",
.id = -1,
.parent = &clk_p,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_SPI,
}
};
static struct clk init_clocks[] = {
{
.name = "dma",
.id = 0,
.parent = &clk_h,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_DMA0,
}, {
.name = "dma",
.id = 1,
.parent = &clk_h,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_DMA1,
}, {
.name = "dma",
.id = 2,
.parent = &clk_h,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_DMA2,
}, {
.name = "dma",
.id = 3,
.parent = &clk_h,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_DMA3,
}, {
.name = "lcd",
.id = -1,
.parent = &clk_h,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_LCDC,
}, {
.name = "gpio",
.id = -1,
.parent = &clk_p,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_GPIO,
}, {
.name = "usb-host",
.id = -1,
.parent = &clk_h,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_USBH,
}, {
.name = "usb-device",
.id = -1,
.parent = &clk_h,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_USBD,
}, {
.name = "timers",
.id = -1,
.parent = &clk_p,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_PWMT,
}, {
.name = "uart",
.id = 0,
.parent = &clk_p,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_UART0,
}, {
.name = "uart",
.id = 1,
.parent = &clk_p,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_UART1,
}, {
.name = "uart",
.id = 2,
.parent = &clk_p,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_UART2,
}, {
.name = "rtc",
.id = -1,
.parent = &clk_p,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_RTC,
}, {
.name = "watchdog",
.id = -1,
.parent = &clk_p,
.ctrlbit = 0,
}, {
.name = "usb-bus-gadget",
.id = -1,
.parent = &clk_usb_bus,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_USB_DEV48,
}, {
.name = "usb-bus-host",
.id = -1,
.parent = &clk_usb_bus,
.enable = s3c2412_clkcon_enable,
.ctrlbit = S3C2412_CLKCON_USB_HOST48,
}
};
/* clocks to add where we need to check their parentage */
struct clk_init {
struct clk *clk;
unsigned int bit;
struct clk *src_0;
struct clk *src_1;
};
struct clk_init clks_src[] __initdata = {
{
.clk = &clk_usysclk,
.bit = S3C2412_CLKSRC_USBCLK_HCLK,
.src_0 = &clk_urefclk,
.src_1 = &clk_upll,
}, {
.clk = &clk_i2s,
.bit = S3C2412_CLKSRC_I2SCLK_MPLL,
.src_0 = &clk_erefclk,
.src_1 = &clk_mpll,
}, {
.clk = &clk_cam,
.bit = S3C2412_CLKSRC_CAMCLK_HCLK,
.src_0 = &clk_usysclk,
.src_1 = &clk_h,
}, {
.clk = &clk_msysclk,
.bit = S3C2412_CLKSRC_MSYSCLK_MPLL,
.src_0 = &clk_mdivclk,
.src_1 = &clk_mpll,
}, {
.clk = &clk_uart,
.bit = S3C2412_CLKSRC_UARTCLK_MPLL,
.src_0 = &clk_erefclk,
.src_1 = &clk_mpll,
}, {
.clk = &clk_usbsrc,
.bit = S3C2412_CLKSRC_USBCLK_HCLK,
.src_0 = &clk_usysclk,
.src_1 = &clk_h,
},
};
/* s3c2412_clk_initparents
*
* Initialise the parents for the clocks that we get at start-time
*/
static void __init s3c2412_clk_initparents(void)
{
unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
struct clk_init *cip = clks_src;
struct clk *src;
int ptr;
int ret;
for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++, cip++) {
ret = s3c24xx_register_clock(cip->clk);
if (ret < 0) {
printk(KERN_ERR "Failed to register clock %s (%d)\n",
cip->clk->name, ret);
}
src = (clksrc & cip->bit) ? cip->src_1 : cip->src_0;
printk(KERN_INFO "%s: parent %s\n", cip->clk->name, src->name);
clk_set_parent(cip->clk, src);
}
}
/* clocks to add straight away */
struct clk *clks[] __initdata = {
&clk_ext,
&clk_usb_bus,
&clk_erefclk,
&clk_urefclk,
&clk_mrefclk,
};
int __init s3c2412_baseclk_add(void)
{
unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
struct clk *clkp;
int ret;
int ptr;
clk_upll.enable = s3c2412_upll_enable;
clk_usb_bus.parent = &clk_usbsrc;
clk_usb_bus.rate = 0x0;
s3c2412_clk_initparents();
for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
clkp = clks[ptr];
ret = s3c24xx_register_clock(clkp);
if (ret < 0) {
printk(KERN_ERR "Failed to register clock %s (%d)\n",
clkp->name, ret);
}
}
/* ensure usb bus clock is within correct rate of 48MHz */
if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) {
printk(KERN_INFO "Warning: USB bus clock not at 48MHz\n");
/* for the moment, let's use the UPLL, and see if we can
* get 48MHz */
clk_set_parent(&clk_usysclk, &clk_upll);
clk_set_parent(&clk_usbsrc, &clk_usysclk);
clk_set_rate(&clk_usbsrc, 48*1000*1000);
}
printk("S3C2412: upll %s, %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
(__raw_readl(S3C2410_UPLLCON) & S3C2412_PLLCON_OFF) ? "off":"on",
print_mhz(clk_get_rate(&clk_upll)),
print_mhz(clk_get_rate(&clk_usb_bus)));
/* register clocks from clock array */
clkp = init_clocks;
for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
/* ensure that we note the clock state */
clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
ret = s3c24xx_register_clock(clkp);
if (ret < 0) {
printk(KERN_ERR "Failed to register clock %s (%d)\n",
clkp->name, ret);
}
}
/* We must be careful disabling the clocks we are not intending to
* be using at boot time, as subsytems such as the LCD which do
* their own DMA requests to the bus can cause the system to lockup
* if they where in the middle of requesting bus access.
*
* Disabling the LCD clock if the LCD is active is very dangerous,
* and therefore the bootloader should be careful to not enable
* the LCD clock if it is not needed.
*/
/* install (and disable) the clocks we do not need immediately */
clkp = init_clocks_disable;
for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
ret = s3c24xx_register_clock(clkp);
if (ret < 0) {
printk(KERN_ERR "Failed to register clock %s (%d)\n",
clkp->name, ret);
}
s3c2412_clkcon_enable(clkp, 0);
}
return 0;
}

View File

@ -0,0 +1,195 @@
/* linux/arch/arm/mach-s3c2410/s3c2412.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* http://armlinux.simtec.co.uk/.
*
* 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.
*
* Modifications:
* 16-May-2003 BJD Created initial version
* 16-Aug-2003 BJD Fixed header files and copyright, added URL
* 05-Sep-2003 BJD Moved to kernel v2.6
* 18-Jan-2004 BJD Added serial port configuration
* 21-Aug-2004 BJD Added new struct s3c2410_board handler
* 28-Sep-2004 BJD Updates for new serial port bits
* 04-Nov-2004 BJD Updated UART configuration process
* 10-Jan-2005 BJD Removed s3c2410_clock_tick_rate
* 13-Aug-2005 DA Removed UART from initial I/O mappings
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/sysdev.h>
#include <linux/platform_device.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-gpioj.h>
#include <asm/arch/regs-dsc.h>
#include "s3c2412.h"
#include "cpu.h"
#include "devs.h"
#include "clock.h"
#include "pm.h"
#ifndef CONFIG_CPU_S3C2412_ONLY
void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
#endif
/* Initial IO mappings */
static struct map_desc s3c2412_iodesc[] __initdata = {
IODESC_ENT(CLKPWR),
IODESC_ENT(LCD),
IODESC_ENT(TIMER),
IODESC_ENT(ADC),
IODESC_ENT(WATCHDOG),
};
/* uart registration process */
void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no)
{
s3c24xx_init_uartdevs("s3c2412-uart", s3c2410_uart_resources, cfg, no);
/* rename devices that are s3c2412/s3c2413 specific */
s3c_device_sdi.name = "s3c2412-sdi";
s3c_device_nand.name = "s3c2412-nand";
}
/* s3c2412_map_io
*
* register the standard cpu IO areas, and any passed in from the
* machine specific initialisation.
*/
void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size)
{
/* move base of IO */
s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10;
/* register our io-tables */
iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc));
iotable_init(mach_desc, mach_size);
}
void __init s3c2412_init_clocks(int xtal)
{
unsigned long tmp;
unsigned long fclk;
unsigned long hclk;
unsigned long pclk;
/* now we've got our machine bits initialised, work out what
* clocks we've got */
fclk = s3c2410_get_pll(__raw_readl(S3C2410_MPLLCON), xtal*2);
tmp = __raw_readl(S3C2410_CLKDIVN);
/* work out clock scalings */
hclk = fclk / ((tmp & S3C2412_CLKDIVN_HDIVN_MASK) + 1);
hclk /= ((tmp & S3C2421_CLKDIVN_ARMDIVN) ? 2 : 1);
pclk = hclk / ((tmp & S3C2412_CLKDIVN_PDIVN) ? 2 : 1);
/* print brieft summary of clocks, etc */
printk("S3C2412: core %ld.%03ld MHz, memory %ld.%03ld MHz, peripheral %ld.%03ld MHz\n",
print_mhz(fclk), print_mhz(hclk), print_mhz(pclk));
/* initialise the clocks here, to allow other things like the
* console to use them
*/
s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
s3c2412_baseclk_add();
}
/* need to register class before we actually register the device, and
* we also need to ensure that it has been initialised before any of the
* drivers even try to use it (even if not on an s3c2412 based system)
* as a driver which may support both 2410 and 2440 may try and use it.
*/
#ifdef CONFIG_PM
static struct sleep_save s3c2412_sleep[] = {
SAVE_ITEM(S3C2412_DSC0),
SAVE_ITEM(S3C2412_DSC1),
SAVE_ITEM(S3C2413_GPJDAT),
SAVE_ITEM(S3C2413_GPJCON),
SAVE_ITEM(S3C2413_GPJUP),
/* save the sleep configuration anyway, just in case these
* get damaged during wakeup */
SAVE_ITEM(S3C2412_GPBSLPCON),
SAVE_ITEM(S3C2412_GPCSLPCON),
SAVE_ITEM(S3C2412_GPDSLPCON),
SAVE_ITEM(S3C2412_GPESLPCON),
SAVE_ITEM(S3C2412_GPFSLPCON),
SAVE_ITEM(S3C2412_GPGSLPCON),
SAVE_ITEM(S3C2412_GPHSLPCON),
SAVE_ITEM(S3C2413_GPJSLPCON),
};
static int s3c2412_suspend(struct sys_device *dev, pm_message_t state)
{
s3c2410_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
return 0;
}
static int s3c2412_resume(struct sys_device *dev)
{
s3c2410_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
return 0;
}
#else
#define s3c2412_suspend NULL
#define s3c2412_resume NULL
#endif
struct sysdev_class s3c2412_sysclass = {
set_kset_name("s3c2412-core"),
.suspend = s3c2412_suspend,
.resume = s3c2412_resume
};
static int __init s3c2412_core_init(void)
{
return sysdev_class_register(&s3c2412_sysclass);
}
core_initcall(s3c2412_core_init);
static struct sys_device s3c2412_sysdev = {
.cls = &s3c2412_sysclass,
};
int __init s3c2412_init(void)
{
printk("S3C2412: Initialising architecture\n");
return sysdev_register(&s3c2412_sysdev);
}

View File

@ -0,0 +1,29 @@
/* arch/arm/mach-s3c2410/s3c2412.h
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* Header file for s3c2412 cpu support
*
* 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.
*/
#ifdef CONFIG_CPU_S3C2412
extern int s3c2412_init(void);
extern void s3c2412_map_io(struct map_desc *mach_desc, int size);
extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no);
extern void s3c2412_init_clocks(int xtal);
extern int s3c2412_baseclk_add(void);
#else
#define s3c2412_init_clocks NULL
#define s3c2412_init_uarts NULL
#define s3c2412_map_io NULL
#define s3c2412_init NULL
#endif

View File

@ -61,9 +61,9 @@ config CPU_ARM720T
# ARM920T
config CPU_ARM920T
bool "Support ARM920T processor" if !ARCH_S3C2410
depends on ARCH_EP93XX || ARCH_INTEGRATOR || ARCH_S3C2410 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200
default y if ARCH_S3C2410 || ARCH_AT91RM9200
bool "Support ARM920T processor"
depends on ARCH_EP93XX || ARCH_INTEGRATOR || CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_IMX || ARCH_AAEC2000 || ARCH_AT91RM9200
default y if CPU_S3C2410 || CPU_S3C2440 || CPU_S3C2442 || ARCH_AT91RM9200
select CPU_32v4
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
@ -121,8 +121,8 @@ config CPU_ARM925T
# ARM926T
config CPU_ARM926T
bool "Support ARM926T processor"
depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX
default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX
depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412
default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412
select CPU_32v5
select CPU_ABRT_EV5TJ
select CPU_CACHE_VIVT

View File

@ -37,6 +37,13 @@ SECTIONS
RODATA
. = ALIGN(4);
__tracedata_start = .;
.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
*(.tracedata)
}
__tracedata_end = .;
/* writeable */
.data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
*(.data)

View File

@ -12,7 +12,7 @@ obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
sys_sparc.o sunos_asm.o systbls.o \
time.o windows.o cpu.o devices.o sclow.o \
tadpole.o tick14.o ptrace.o sys_solaris.o \
unaligned.o muldiv.o semaphore.o
unaligned.o muldiv.o semaphore.o prom.o of_device.o
obj-$(CONFIG_PCI) += pcic.o
obj-$(CONFIG_SUN4) += sun4setup.o

View File

@ -20,6 +20,7 @@
#include <asm/ebus.h>
#include <asm/io.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/bpp.h>
struct linux_ebus *ebus_chain = NULL;
@ -83,79 +84,81 @@ int __init ebus_blacklist_irq(char *name)
return 0;
}
void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
struct linux_ebus_child *dev)
void __init fill_ebus_child(struct device_node *dp,
struct linux_ebus_child *dev)
{
int regs[PROMREG_MAX];
int irqs[PROMREG_MAX];
char lbuf[128];
int *regs;
int *irqs;
int i, len;
dev->prom_node = node;
prom_getstring(node, "name", lbuf, sizeof(lbuf));
strcpy(dev->prom_name, lbuf);
len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
if (len == -1) len = 0;
dev->prom_node = dp;
regs = of_get_property(dp, "reg", &len);
if (!regs)
len = 0;
dev->num_addrs = len / sizeof(regs[0]);
for (i = 0; i < dev->num_addrs; i++) {
if (regs[i] >= dev->parent->num_addrs) {
prom_printf("UGH: property for %s was %d, need < %d\n",
dev->prom_name, len, dev->parent->num_addrs);
dev->prom_node->name, len,
dev->parent->num_addrs);
panic(__FUNCTION__);
}
dev->resource[i].start = dev->parent->resource[regs[i]].start; /* XXX resource */
/* XXX resource */
dev->resource[i].start =
dev->parent->resource[regs[i]].start;
}
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;
if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) {
if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
dev->num_irqs = 1;
} else if ((len = prom_getproperty(node, "interrupts",
(char *)&irqs, sizeof(irqs))) == -1 || len == 0) {
dev->num_irqs = 0;
dev->irqs[0] = 0;
if (dev->parent->num_irqs != 0) {
dev->num_irqs = 1;
dev->irqs[0] = dev->parent->irqs[0];
/* P3 */ /* printk("EBUS: dev %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
}
} else {
dev->num_irqs = len / sizeof(irqs[0]);
if (irqs[0] == 0 || irqs[0] >= 8) {
/*
* XXX Zero is a valid pin number...
* This works as long as Ebus is not wired to INTA#.
*/
printk("EBUS: %s got bad irq %d from PROM\n",
dev->prom_name, irqs[0]);
irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
dev->num_irqs = 0;
dev->irqs[0] = 0;
if (dev->parent->num_irqs != 0) {
dev->num_irqs = 1;
dev->irqs[0] = dev->parent->irqs[0];
}
} else {
dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
dev->num_irqs = len / sizeof(irqs[0]);
if (irqs[0] == 0 || irqs[0] >= 8) {
/*
* XXX Zero is a valid pin number...
* This works as long as Ebus is not wired
* to INTA#.
*/
printk("EBUS: %s got bad irq %d from PROM\n",
dev->prom_node->name, irqs[0]);
dev->num_irqs = 0;
dev->irqs[0] = 0;
} else {
dev->irqs[0] =
pcic_pin_to_irq(irqs[0],
dev->prom_node->name);
}
}
}
}
void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
struct linux_prom_registers regs[PROMREG_MAX];
struct linux_prom_registers *regs;
struct linux_ebus_child *child;
int irqs[PROMINTR_MAX];
char lbuf[128];
int *irqs;
int i, n, len;
unsigned long baseaddr;
dev->prom_node = node;
prom_getstring(node, "name", lbuf, sizeof(lbuf));
strcpy(dev->prom_name, lbuf);
dev->prom_node = dp;
len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
regs = of_get_property(dp, "reg", &len);
if (len % sizeof(struct linux_prom_registers)) {
prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
dev->prom_name, len,
dev->prom_node->name, len,
(int)sizeof(struct linux_prom_registers));
panic(__FUNCTION__);
}
@ -197,7 +200,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
if ((baseaddr = (unsigned long) ioremap(baseaddr,
regs[i].reg_size)) == 0) {
panic("ebus: unable to remap dev %s",
dev->prom_name);
dev->prom_node->name);
}
}
dev->resource[i].start = baseaddr; /* XXX Unaligned */
@ -206,29 +209,43 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;
if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_name)) != 0) {
if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
dev->num_irqs = 1;
} else if ((len = prom_getproperty(node, "interrupts",
(char *)&irqs, sizeof(irqs))) == -1 || len == 0) {
dev->num_irqs = 0;
if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
dev->num_irqs = 1;
/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
}
} else {
dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */
if (irqs[0] == 0 || irqs[0] >= 8) {
/* See above for the parent. XXX */
printk("EBUS: %s got bad irq %d from PROM\n",
dev->prom_name, irqs[0]);
irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
dev->num_irqs = 0;
dev->irqs[0] = 0;
if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
dev->num_irqs = 1;
/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
}
} else {
dev->irqs[0] = pcic_pin_to_irq(irqs[0], dev->prom_name);
dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */
if (irqs[0] == 0 || irqs[0] >= 8) {
/* See above for the parent. XXX */
printk("EBUS: %s got bad irq %d from PROM\n",
dev->prom_node->name, irqs[0]);
dev->num_irqs = 0;
dev->irqs[0] = 0;
} else {
dev->irqs[0] =
pcic_pin_to_irq(irqs[0],
dev->prom_node->name);
}
}
}
if ((node = prom_getchild(node))) {
dev->ofdev.node = dp;
dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
dev->ofdev.dev.bus = &ebus_bus_type;
strcpy(dev->ofdev.dev.bus_id, dp->path_component_name);
/* Register with core */
if (of_device_register(&dev->ofdev) != 0)
printk(KERN_DEBUG "ebus: device registration error for %s!\n",
dev->ofdev.dev.bus_id);
if ((dp = dp->child) != NULL) {
dev->children = (struct linux_ebus_child *)
ebus_alloc(sizeof(struct linux_ebus_child));
@ -236,9 +253,9 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
fill_ebus_child(node, &regs[0], child);
fill_ebus_child(dp, child);
while ((node = prom_getsibling(node)) != 0) {
while ((dp = dp->sibling) != NULL) {
child->next = (struct linux_ebus_child *)
ebus_alloc(sizeof(struct linux_ebus_child));
@ -246,51 +263,49 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
fill_ebus_child(node, &regs[0], child);
fill_ebus_child(dp, child);
}
}
}
void __init ebus_init(void)
{
struct linux_prom_pci_registers regs[PROMREG_MAX];
struct linux_prom_pci_registers *regs;
struct linux_pbm_info *pbm;
struct linux_ebus_device *dev;
struct linux_ebus *ebus;
struct ebus_system_entry *sp;
struct pci_dev *pdev;
struct pcidev_cookie *cookie;
char lbuf[128];
struct device_node *dp;
unsigned long addr, *base;
unsigned short pci_command;
int nd, len, ebusnd;
int reg, nreg;
int len, reg, nreg;
int num_ebus = 0;
prom_getstring(prom_root_node, "name", lbuf, sizeof(lbuf));
dp = of_find_node_by_path("/");
for (sp = ebus_blacklist; sp->esname != NULL; sp++) {
if (strcmp(lbuf, sp->esname) == 0) {
if (strcmp(dp->name, sp->esname) == 0) {
ebus_blackp = sp->ipt;
break;
}
}
pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);
if (!pdev) {
if (!pdev)
return;
}
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
dp = cookie->prom_node;
ebus_chain = ebus = (struct linux_ebus *)
ebus_alloc(sizeof(struct linux_ebus));
ebus->next = NULL;
while (ebusnd) {
while (dp) {
struct device_node *nd;
prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
ebus->prom_node = ebusnd;
strcpy(ebus->prom_name, lbuf);
ebus->prom_node = dp;
ebus->self = pdev;
ebus->parent = pbm = cookie->pbm;
@ -299,9 +314,8 @@ void __init ebus_init(void)
pci_command |= PCI_COMMAND_MASTER;
pci_write_config_word(pdev, PCI_COMMAND, pci_command);
len = prom_getproperty(ebusnd, "reg", (void *)regs,
sizeof(regs));
if (len == 0 || len == -1) {
regs = of_get_property(dp, "reg", &len);
if (!regs) {
prom_printf("%s: can't find reg property\n",
__FUNCTION__);
prom_halt();
@ -317,7 +331,18 @@ void __init ebus_init(void)
*base++ = addr;
}
nd = prom_getchild(ebusnd);
ebus->ofdev.node = dp;
ebus->ofdev.dev.parent = &pdev->dev;
ebus->ofdev.dev.bus = &ebus_bus_type;
strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name);
/* Register with core */
if (of_device_register(&ebus->ofdev) != 0)
printk(KERN_DEBUG "ebus: device registration error for %s!\n",
ebus->ofdev.dev.bus_id);
nd = dp->child;
if (!nd)
goto next_ebus;
@ -330,7 +355,7 @@ void __init ebus_init(void)
dev->bus = ebus;
fill_ebus_device(nd, dev);
while ((nd = prom_getsibling(nd)) != 0) {
while ((nd = nd->sibling) != NULL) {
dev->next = (struct linux_ebus_device *)
ebus_alloc(sizeof(struct linux_ebus_device));
@ -348,7 +373,7 @@ void __init ebus_init(void)
break;
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
dp = cookie->prom_node;
ebus->next = (struct linux_ebus *)
ebus_alloc(sizeof(struct linux_ebus));

View File

@ -39,6 +39,8 @@
#include <asm/io.h>
#include <asm/vaddrs.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/sbus.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/dma.h>
@ -224,10 +226,54 @@ static void _sparc_free_io(struct resource *res)
#ifdef CONFIG_SBUS
void sbus_set_sbus64(struct sbus_dev *sdev, int x) {
void sbus_set_sbus64(struct sbus_dev *sdev, int x)
{
printk("sbus_set_sbus64: unsupported\n");
}
extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
void __init sbus_fill_device_irq(struct sbus_dev *sdev)
{
struct linux_prom_irqs irqs[PROMINTR_MAX];
int len;
len = prom_getproperty(sdev->prom_node, "intr",
(char *)irqs, sizeof(irqs));
if (len != -1) {
sdev->num_irqs = len / 8;
if (sdev->num_irqs == 0) {
sdev->irqs[0] = 0;
} else if (sparc_cpu_model == sun4d) {
for (len = 0; len < sdev->num_irqs; len++)
sdev->irqs[len] =
sun4d_build_irq(sdev, irqs[len].pri);
} else {
for (len = 0; len < sdev->num_irqs; len++)
sdev->irqs[len] = irqs[len].pri;
}
} else {
int interrupts[PROMINTR_MAX];
/* No "intr" node found-- check for "interrupts" node.
* This node contains SBus interrupt levels, not IPLs
* as in "intr", and no vector values. We convert
* SBus interrupt levels to PILs (platform specific).
*/
len = prom_getproperty(sdev->prom_node, "interrupts",
(char *)interrupts, sizeof(interrupts));
if (len == -1) {
sdev->irqs[0] = 0;
sdev->num_irqs = 0;
} else {
sdev->num_irqs = len / sizeof(int);
for (len = 0; len < sdev->num_irqs; len++) {
sdev->irqs[len] =
sbint_to_irq(sdev, interrupts[len]);
}
}
}
}
/*
* Allocate a chunk of memory suitable for DMA.
* Typically devices use them for control blocks.
@ -414,6 +460,89 @@ void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg,
{
printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
}
/* Support code for sbus_init(). */
/*
* XXX This functions appears to be a distorted version of
* prom_sbus_ranges_init(), with all sun4d stuff cut away.
* Ask DaveM what is going on here, how is sun4d supposed to work... XXX
*/
/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
{
int parent_node = pn->node;
if (sparc_cpu_model == sun4d) {
struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
int num_iounit_ranges, len;
len = prom_getproperty(parent_node, "ranges",
(char *) iounit_ranges,
sizeof (iounit_ranges));
if (len != -1) {
num_iounit_ranges =
(len / sizeof(struct linux_prom_ranges));
prom_adjust_ranges(sbus->sbus_ranges,
sbus->num_sbus_ranges,
iounit_ranges, num_iounit_ranges);
}
}
}
void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
{
struct device_node *parent = dp->parent;
if (sparc_cpu_model != sun4d &&
parent != NULL &&
!strcmp(parent->name, "iommu")) {
extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
iommu_init(parent->node, sbus);
}
if (sparc_cpu_model == sun4d) {
extern void iounit_init(int sbi_node, int iounit_node,
struct sbus_bus *sbus);
iounit_init(dp->node, parent->node, sbus);
}
}
void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
{
if (sparc_cpu_model == sun4d) {
struct device_node *parent = dp->parent;
sbus->devid = of_getintprop_default(parent, "device-id", 0);
sbus->board = of_getintprop_default(parent, "board#", 0);
}
}
int __init sbus_arch_preinit(void)
{
extern void register_proc_sparc_ioport(void);
register_proc_sparc_ioport();
#ifdef CONFIG_SUN4
{
extern void sun4_dvma_init(void);
sun4_dvma_init();
}
return 1;
#else
return 0;
#endif
}
void __init sbus_arch_postinit(void)
{
if (sparc_cpu_model == sun4d) {
extern void sun4d_init_sbi_irq(void);
sun4d_init_sbi_irq();
}
}
#endif /* CONFIG_SBUS */
#ifdef CONFIG_PCI

View File

@ -0,0 +1,268 @@
#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <asm/errno.h>
#include <asm/of_device.h>
/**
* of_match_device - Tell if an of_device structure has a matching
* of_match structure
* @ids: array of of device match structures to search in
* @dev: the of device structure to match against
*
* Used by a driver to check whether an of_device present in the
* system is in its list of supported devices.
*/
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct of_device *dev)
{
if (!dev->node)
return NULL;
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
if (matches->name[0])
match &= dev->node->name
&& !strcmp(matches->name, dev->node->name);
if (matches->type[0])
match &= dev->node->type
&& !strcmp(matches->type, dev->node->type);
if (matches->compatible[0])
match &= of_device_is_compatible(dev->node,
matches->compatible);
if (match)
return matches;
matches++;
}
return NULL;
}
static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * of_drv = to_of_platform_driver(drv);
const struct of_device_id * matches = of_drv->match_table;
if (!matches)
return 0;
return of_match_device(matches, of_dev) != NULL;
}
struct of_device *of_dev_get(struct of_device *dev)
{
struct device *tmp;
if (!dev)
return NULL;
tmp = get_device(&dev->dev);
if (tmp)
return to_of_device(tmp);
else
return NULL;
}
void of_dev_put(struct of_device *dev)
{
if (dev)
put_device(&dev->dev);
}
static int of_device_probe(struct device *dev)
{
int error = -ENODEV;
struct of_platform_driver *drv;
struct of_device *of_dev;
const struct of_device_id *match;
drv = to_of_platform_driver(dev->driver);
of_dev = to_of_device(dev);
if (!drv->probe)
return error;
of_dev_get(of_dev);
match = of_match_device(drv->match_table, of_dev);
if (match)
error = drv->probe(of_dev, match);
if (error)
of_dev_put(of_dev);
return error;
}
static int of_device_remove(struct device *dev)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
if (dev->driver && drv->remove)
drv->remove(of_dev);
return 0;
}
static int of_device_suspend(struct device *dev, pm_message_t state)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
int error = 0;
if (dev->driver && drv->suspend)
error = drv->suspend(of_dev, state);
return error;
}
static int of_device_resume(struct device * dev)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
int error = 0;
if (dev->driver && drv->resume)
error = drv->resume(of_dev);
return error;
}
#ifdef CONFIG_PCI
struct bus_type ebus_bus_type = {
.name = "ebus",
.match = of_platform_bus_match,
.probe = of_device_probe,
.remove = of_device_remove,
.suspend = of_device_suspend,
.resume = of_device_resume,
};
#endif
#ifdef CONFIG_SBUS
struct bus_type sbus_bus_type = {
.name = "sbus",
.match = of_platform_bus_match,
.probe = of_device_probe,
.remove = of_device_remove,
.suspend = of_device_suspend,
.resume = of_device_resume,
};
#endif
static int __init of_bus_driver_init(void)
{
int err = 0;
#ifdef CONFIG_PCI
if (!err)
err = bus_register(&ebus_bus_type);
#endif
#ifdef CONFIG_SBUS
if (!err)
err = bus_register(&sbus_bus_type);
#endif
return 0;
}
postcore_initcall(of_bus_driver_init);
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
/* initialize common driver fields */
drv->driver.name = drv->name;
drv->driver.bus = bus;
/* register with core */
return driver_register(&drv->driver);
}
void of_unregister_driver(struct of_platform_driver *drv)
{
driver_unregister(&drv->driver);
}
static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
{
struct of_device *ofdev;
ofdev = to_of_device(dev);
return sprintf(buf, "%s", ofdev->node->full_name);
}
static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
/**
* of_release_dev - free an of device structure when all users of it are finished.
* @dev: device that's been disconnected
*
* Will be called only by the device core when all users of this of device are
* done.
*/
void of_release_dev(struct device *dev)
{
struct of_device *ofdev;
ofdev = to_of_device(dev);
kfree(ofdev);
}
int of_device_register(struct of_device *ofdev)
{
int rc;
BUG_ON(ofdev->node == NULL);
rc = device_register(&ofdev->dev);
if (rc)
return rc;
device_create_file(&ofdev->dev, &dev_attr_devspec);
return 0;
}
void of_device_unregister(struct of_device *ofdev)
{
device_remove_file(&ofdev->dev, &dev_attr_devspec);
device_unregister(&ofdev->dev);
}
struct of_device* of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent,
struct bus_type *bus)
{
struct of_device *dev;
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
memset(dev, 0, sizeof(*dev));
dev->dev.parent = parent;
dev->dev.bus = bus;
dev->dev.release = of_release_dev;
strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
if (of_device_register(dev) != 0) {
kfree(dev);
return NULL;
}
return dev;
}
EXPORT_SYMBOL(of_match_device);
EXPORT_SYMBOL(of_register_driver);
EXPORT_SYMBOL(of_unregister_driver);
EXPORT_SYMBOL(of_device_register);
EXPORT_SYMBOL(of_device_unregister);
EXPORT_SYMBOL(of_dev_get);
EXPORT_SYMBOL(of_dev_put);
EXPORT_SYMBOL(of_platform_device_create);
EXPORT_SYMBOL(of_release_dev);

View File

@ -31,6 +31,7 @@
#include <asm/irq.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/pcic.h>
#include <asm/timer.h>
#include <asm/uaccess.h>
@ -665,7 +666,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
/* cookies */
pcp = pci_devcookie_alloc();
pcp->pbm = &pcic->pbm;
pcp->prom_node = node;
pcp->prom_node = of_find_node_by_phandle(node);
dev->sysdata = pcp;
/* fixing I/O to look like memory */

474
arch/sparc/kernel/prom.c Normal file
View File

@ -0,0 +1,474 @@
/*
* Procedures for creating, accessing and interpreting the device tree.
*
* Paul Mackerras August 1996.
* Copyright (C) 1996-2005 Paul Mackerras.
*
* Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
* {engebret|bergner}@us.ibm.com
*
* Adapted for sparc32 by David S. Miller davem@davemloft.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/module.h>
#include <asm/prom.h>
#include <asm/oplib.h>
static struct device_node *allnodes;
int of_device_is_compatible(struct device_node *device, const char *compat)
{
const char* cp;
int cplen, l;
cp = (char *) of_get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
if (strncmp(cp, compat, strlen(compat)) == 0)
return 1;
l = strlen(cp) + 1;
cp += l;
cplen -= l;
}
return 0;
}
EXPORT_SYMBOL(of_device_is_compatible);
struct device_node *of_get_parent(const struct device_node *node)
{
struct device_node *np;
if (!node)
return NULL;
np = node->parent;
return np;
}
EXPORT_SYMBOL(of_get_parent);
struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;
next = prev ? prev->sibling : node->child;
for (; next != 0; next = next->sibling) {
break;
}
return next;
}
EXPORT_SYMBOL(of_get_next_child);
struct device_node *of_find_node_by_path(const char *path)
{
struct device_node *np = allnodes;
for (; np != 0; np = np->allnext) {
if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
break;
}
return np;
}
EXPORT_SYMBOL(of_find_node_by_path);
struct device_node *of_find_node_by_phandle(phandle handle)
{
struct device_node *np;
for (np = allnodes; np != 0; np = np->allnext)
if (np->node == handle)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_phandle);
struct device_node *of_find_node_by_name(struct device_node *from,
const char *name)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != NULL; np = np->allnext)
if (np->name != NULL && strcmp(np->name, name) == 0)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_name);
struct device_node *of_find_node_by_type(struct device_node *from,
const char *type)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != 0; np = np->allnext)
if (np->type != 0 && strcmp(np->type, type) == 0)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_type);
struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compatible)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != 0; np = np->allnext) {
if (type != NULL
&& !(np->type != 0 && strcmp(np->type, type) == 0))
continue;
if (of_device_is_compatible(np, compatible))
break;
}
return np;
}
EXPORT_SYMBOL(of_find_compatible_node);
struct property *of_find_property(struct device_node *np, const char *name,
int *lenp)
{
struct property *pp;
for (pp = np->properties; pp != 0; pp = pp->next) {
if (strcmp(pp->name, name) == 0) {
if (lenp != 0)
*lenp = pp->length;
break;
}
}
return pp;
}
EXPORT_SYMBOL(of_find_property);
/*
* Find a property with a given name for a given node
* and return the value.
*/
void *of_get_property(struct device_node *np, const char *name, int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
}
EXPORT_SYMBOL(of_get_property);
int of_getintprop_default(struct device_node *np, const char *name, int def)
{
struct property *prop;
int len;
prop = of_find_property(np, name, &len);
if (!prop || len != 4)
return def;
return *(int *) prop->value;
}
EXPORT_SYMBOL(of_getintprop_default);
static unsigned int prom_early_allocated;
static void * __init prom_early_alloc(unsigned long size)
{
void *ret;
ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
if (ret != NULL)
memset(ret, 0, size);
prom_early_allocated += size;
return ret;
}
static int is_root_node(const struct device_node *dp)
{
if (!dp)
return 0;
return (dp->parent == NULL);
}
/* The following routines deal with the black magic of fully naming a
* node.
*
* Certain well known named nodes are just the simple name string.
*
* Actual devices have an address specifier appended to the base name
* string, like this "foo@addr". The "addr" can be in any number of
* formats, and the platform plus the type of the node determine the
* format and how it is constructed.
*
* For children of the ROOT node, the naming convention is fixed and
* determined by whether this is a sun4u or sun4v system.
*
* For children of other nodes, it is bus type specific. So
* we walk up the tree until we discover a "device_type" property
* we recognize and we go from there.
*/
static void __init sparc32_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_registers *regs;
struct property *rprop;
rprop = of_find_property(dp, "reg", NULL);
if (!rprop)
return;
regs = rprop->value;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
regs->which_io, regs->phys_addr);
}
/* "name@slot,offset" */
static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
regs->which_io,
regs->phys_addr);
}
/* "name@devnum[,func]" */
static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_pci_registers *regs;
struct property *prop;
unsigned int devfn;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
devfn = (regs->phys_hi >> 8) & 0xff;
if (devfn & 0x07) {
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
devfn >> 3,
devfn & 0x07);
} else {
sprintf(tmp_buf, "%s@%x",
dp->name,
devfn >> 3);
}
}
/* "name@addrhi,addrlo" */
static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
regs->which_io, regs->phys_addr);
}
static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
{
struct device_node *parent = dp->parent;
if (parent != NULL) {
if (!strcmp(parent->type, "pci") ||
!strcmp(parent->type, "pciex"))
return pci_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "sbus"))
return sbus_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "ebus"))
return ebus_path_component(dp, tmp_buf);
/* "isa" is handled with platform naming */
}
/* Use platform naming convention. */
return sparc32_path_component(dp, tmp_buf);
}
static char * __init build_path_component(struct device_node *dp)
{
char tmp_buf[64], *n;
tmp_buf[0] = '\0';
__build_path_component(dp, tmp_buf);
if (tmp_buf[0] == '\0')
strcpy(tmp_buf, dp->name);
n = prom_early_alloc(strlen(tmp_buf) + 1);
strcpy(n, tmp_buf);
return n;
}
static char * __init build_full_name(struct device_node *dp)
{
int len, ourlen, plen;
char *n;
plen = strlen(dp->parent->full_name);
ourlen = strlen(dp->path_component_name);
len = ourlen + plen + 2;
n = prom_early_alloc(len);
strcpy(n, dp->parent->full_name);
if (!is_root_node(dp->parent)) {
strcpy(n + plen, "/");
plen++;
}
strcpy(n + plen, dp->path_component_name);
return n;
}
static struct property * __init build_one_prop(phandle node, char *prev)
{
static struct property *tmp = NULL;
struct property *p;
int len;
if (tmp) {
p = tmp;
memset(p, 0, sizeof(*p) + 32);
tmp = NULL;
} else
p = prom_early_alloc(sizeof(struct property) + 32);
p->name = (char *) (p + 1);
if (prev == NULL) {
prom_firstprop(node, p->name);
} else {
prom_nextprop(node, prev, p->name);
}
if (strlen(p->name) == 0) {
tmp = p;
return NULL;
}
p->length = prom_getproplen(node, p->name);
if (p->length <= 0) {
p->length = 0;
} else {
p->value = prom_early_alloc(p->length);
len = prom_getproperty(node, p->name, p->value, p->length);
}
return p;
}
static struct property * __init build_prop_list(phandle node)
{
struct property *head, *tail;
head = tail = build_one_prop(node, NULL);
while(tail) {
tail->next = build_one_prop(node, tail->name);
tail = tail->next;
}
return head;
}
static char * __init get_one_property(phandle node, char *name)
{
char *buf = "<NULL>";
int len;
len = prom_getproplen(node, name);
if (len > 0) {
buf = prom_early_alloc(len);
len = prom_getproperty(node, name, buf, len);
}
return buf;
}
static struct device_node * __init create_node(phandle node)
{
struct device_node *dp;
if (!node)
return NULL;
dp = prom_early_alloc(sizeof(*dp));
kref_init(&dp->kref);
dp->name = get_one_property(node, "name");
dp->type = get_one_property(node, "device_type");
dp->node = node;
/* Build interrupts later... */
dp->properties = build_prop_list(node);
return dp;
}
static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
{
struct device_node *dp;
dp = create_node(node);
if (dp) {
*(*nextp) = dp;
*nextp = &dp->allnext;
dp->parent = parent;
dp->path_component_name = build_path_component(dp);
dp->full_name = build_full_name(dp);
dp->child = build_tree(dp, prom_getchild(node), nextp);
dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
}
return dp;
}
void __init prom_build_devicetree(void)
{
struct device_node **nextp;
allnodes = create_node(prom_root_node);
allnodes->path_component_name = "";
allnodes->full_name = "/";
nextp = &allnodes->allnext;
allnodes->child = build_tree(allnodes,
prom_getchild(allnodes->node),
&nextp);
printk("PROM: Built device tree with %u bytes of memory.\n",
prom_early_allocated);
}

View File

@ -31,6 +31,7 @@
#include <asm/vaddrs.h>
#include <asm/pgalloc.h> /* bug in asm-generic/tlb.h: check_pgt_cache */
#include <asm/tlb.h>
#include <asm/prom.h>
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
@ -349,6 +350,7 @@ void __init paging_init(void)
protection_map[14] = PAGE_SHARED;
protection_map[15] = PAGE_SHARED;
btfixup();
prom_build_devicetree();
device_scan();
}

View File

@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.17
# Tue Jun 20 01:26:43 2006
# Fri Jun 23 23:17:09 2006
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@ -286,6 +286,7 @@ CONFIG_STANDALONE=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
@ -434,6 +435,7 @@ CONFIG_ISCSI_TCP=m
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_IPS is not set
@ -733,6 +735,7 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
@ -776,6 +779,7 @@ CONFIG_I2C_ALGOBIT=y
#
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
@ -804,10 +808,12 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
@ -1018,6 +1024,7 @@ CONFIG_USB_DEVICEFS=y
CONFIG_USB_EHCI_HCD=m
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=y
# CONFIG_USB_OHCI_BIG_ENDIAN is not set
@ -1097,10 +1104,12 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_LED is not set
# CONFIG_USB_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_PHIDGETKIT is not set
# CONFIG_USB_PHIDGETSERVO is not set
# CONFIG_USB_IDMOUSE is not set
# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TEST is not set
@ -1198,6 +1207,7 @@ CONFIG_FS_POSIX_ACL=y
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set

View File

@ -12,7 +12,7 @@ obj-y := process.o setup.o cpu.o idprom.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
visemul.o prom.o of_device.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o pci_schizo.o \

View File

@ -110,43 +110,82 @@ void auxio_set_lte(int on)
}
}
void __init auxio_probe(void)
static void __devinit auxio_report_dev(struct device_node *dp)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev = NULL;
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if(!strcmp(sdev->prom_name, "auxio"))
goto found_sdev;
}
}
found_sdev:
if (sdev) {
auxio_devtype = AUXIO_TYPE_SBUS;
auxio_register = sbus_ioremap(&sdev->resource[0], 0,
sdev->reg_addrs[0].reg_size,
"auxiliaryIO");
}
#ifdef CONFIG_PCI
else {
struct linux_ebus *ebus;
struct linux_ebus_device *edev = NULL;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "auxio"))
goto ebus_done;
}
}
ebus_done:
if (edev) {
auxio_devtype = AUXIO_TYPE_EBUS;
auxio_register =
ioremap(edev->resource[0].start, sizeof(u32));
}
}
auxio_set_led(AUXIO_LED_ON);
#endif
printk(KERN_INFO "AUXIO: Found device at %s\n",
dp->full_name);
}
static struct of_device_id auxio_match[] = {
{
.name = "auxio",
},
{},
};
MODULE_DEVICE_TABLE(of, auxio_match);
#ifdef CONFIG_SBUS
static int __devinit auxio_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
auxio_devtype = AUXIO_TYPE_SBUS;
auxio_register = sbus_ioremap(&sdev->resource[0], 0,
sdev->reg_addrs[0].reg_size,
"auxiliaryIO");
if (!auxio_register)
return -ENODEV;
auxio_report_dev(dev->node);
return 0;
}
static struct of_platform_driver auxio_sbus_driver = {
.name = "auxio",
.match_table = auxio_match,
.probe = auxio_sbus_probe,
};
#endif
#ifdef CONFIG_PCI
static int __devinit auxio_ebus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
auxio_devtype = AUXIO_TYPE_EBUS;
auxio_register = ioremap(edev->resource[0].start, sizeof(u32));
if (!auxio_register)
return -ENODEV;
auxio_report_dev(dev->node);
auxio_set_led(AUXIO_LED_ON);
return 0;
}
static struct of_platform_driver auxio_ebus_driver = {
.name = "auxio",
.match_table = auxio_match,
.probe = auxio_ebus_probe,
};
#endif
static int __init auxio_probe(void)
{
#ifdef CONFIG_SBUS
of_register_driver(&auxio_sbus_driver, &sbus_bus_type);
#endif
#ifdef CONFIG_PCI
of_register_driver(&auxio_ebus_driver, &ebus_bus_type);
#endif
return 0;
}
/* Must be after subsys_initcall() so that busses are probed. Must
* be before device_initcall() because things like the floppy driver
* need to use the AUXIO register.
*/
fs_initcall(auxio_probe);

View File

@ -29,28 +29,34 @@ static void central_probe_failure(int line)
prom_halt();
}
static void central_ranges_init(int cnode, struct linux_central *central)
static void central_ranges_init(struct linux_central *central)
{
int success;
struct device_node *dp = central->prom_node;
void *pval;
int len;
central->num_central_ranges = 0;
success = prom_getproperty(central->prom_node, "ranges",
(char *) central->central_ranges,
sizeof (central->central_ranges));
if (success != -1)
central->num_central_ranges = (success/sizeof(struct linux_prom_ranges));
pval = of_get_property(dp, "ranges", &len);
if (pval) {
memcpy(central->central_ranges, pval, len);
central->num_central_ranges =
(len / sizeof(struct linux_prom_ranges));
}
}
static void fhc_ranges_init(int fnode, struct linux_fhc *fhc)
static void fhc_ranges_init(struct linux_fhc *fhc)
{
int success;
struct device_node *dp = fhc->prom_node;
void *pval;
int len;
fhc->num_fhc_ranges = 0;
success = prom_getproperty(fhc->prom_node, "ranges",
(char *) fhc->fhc_ranges,
sizeof (fhc->fhc_ranges));
if (success != -1)
fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges));
pval = of_get_property(dp, "ranges", &len);
if (pval) {
memcpy(fhc->fhc_ranges, pval, len);
fhc->num_fhc_ranges =
(len / sizeof(struct linux_prom_ranges));
}
}
/* Range application routines are exported to various drivers,
@ -112,15 +118,10 @@ static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r)
static void probe_other_fhcs(void)
{
struct linux_prom64_registers fpregs[6];
char namebuf[128];
int node;
struct device_node *dp;
struct linux_prom64_registers *fpregs;
node = prom_getchild(prom_root_node);
node = prom_searchsiblings(node, "fhc");
if (node == 0)
central_probe_failure(__LINE__);
while (node) {
for_each_node_by_name(dp, "fhc") {
struct linux_fhc *fhc;
int board;
u32 tmp;
@ -137,14 +138,12 @@ static void probe_other_fhcs(void)
/* Toplevel FHCs have no parent. */
fhc->parent = NULL;
fhc->prom_node = node;
prom_getstring(node, "name", namebuf, sizeof(namebuf));
strcpy(fhc->prom_name, namebuf);
fhc_ranges_init(node, fhc);
fhc->prom_node = dp;
fhc_ranges_init(fhc);
/* Non-central FHC's have 64-bit OBP format registers. */
if (prom_getproperty(node, "reg",
(char *)&fpregs[0], sizeof(fpregs)) == -1)
fpregs = of_get_property(dp, "reg", NULL);
if (!fpregs)
central_probe_failure(__LINE__);
/* Only central FHC needs special ranges applied. */
@ -155,7 +154,7 @@ static void probe_other_fhcs(void)
fhc->fhc_regs.uregs = fpregs[4].phys_addr;
fhc->fhc_regs.tregs = fpregs[5].phys_addr;
board = prom_getintdefault(node, "board#", -1);
board = of_getintprop_default(dp, "board#", -1);
fhc->board = board;
tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL);
@ -179,33 +178,33 @@ static void probe_other_fhcs(void)
tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
tmp |= FHC_CONTROL_IXIST;
upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
/* Look for the next FHC. */
node = prom_getsibling(node);
if (node == 0)
break;
node = prom_searchsiblings(node, "fhc");
if (node == 0)
break;
}
}
static void probe_clock_board(struct linux_central *central,
struct linux_fhc *fhc,
int cnode, int fnode)
struct device_node *fp)
{
struct linux_prom_registers cregs[3];
int clknode, nslots, tmp, nregs;
struct device_node *dp;
struct linux_prom_registers cregs[3], *pr;
int nslots, tmp, nregs;
clknode = prom_searchsiblings(prom_getchild(fnode), "clock-board");
if (clknode == 0 || clknode == -1)
dp = fp->child;
while (dp) {
if (!strcmp(dp->name, "clock-board"))
break;
dp = dp->sibling;
}
if (!dp)
central_probe_failure(__LINE__);
nregs = prom_getproperty(clknode, "reg", (char *)&cregs[0], sizeof(cregs));
if (nregs == -1)
pr = of_get_property(dp, "reg", &nregs);
if (!pr)
central_probe_failure(__LINE__);
memcpy(cregs, pr, nregs);
nregs /= sizeof(struct linux_prom_registers);
apply_fhc_ranges(fhc, &cregs[0], nregs);
apply_central_ranges(central, &cregs[0], nregs);
central->cfreg = prom_reg_to_paddr(&cregs[0]);
@ -296,13 +295,13 @@ static void init_all_fhc_hw(void)
void central_probe(void)
{
struct linux_prom_registers fpregs[6];
struct linux_prom_registers fpregs[6], *pr;
struct linux_fhc *fhc;
char namebuf[128];
int cnode, fnode, err;
struct device_node *dp, *fp;
int err;
cnode = prom_finddevice("/central");
if (cnode == 0 || cnode == -1) {
dp = of_find_node_by_name(NULL, "central");
if (!dp) {
if (this_is_starfire)
starfire_cpu_setup();
return;
@ -321,31 +320,31 @@ void central_probe(void)
/* First init central. */
central_bus->child = fhc;
central_bus->prom_node = cnode;
prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
strcpy(central_bus->prom_name, namebuf);
central_ranges_init(cnode, central_bus);
central_bus->prom_node = dp;
central_ranges_init(central_bus);
/* And then central's FHC. */
fhc->next = fhc_list;
fhc_list = fhc;
fhc->parent = central_bus;
fnode = prom_searchsiblings(prom_getchild(cnode), "fhc");
if (fnode == 0 || fnode == -1)
fp = dp->child;
while (fp) {
if (!strcmp(fp->name, "fhc"))
break;
fp = fp->sibling;
}
if (!fp)
central_probe_failure(__LINE__);
fhc->prom_node = fnode;
prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
strcpy(fhc->prom_name, namebuf);
fhc_ranges_init(fnode, fhc);
fhc->prom_node = fp;
fhc_ranges_init(fhc);
/* Now, map in FHC register set. */
if (prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)) == -1)
pr = of_get_property(fp, "reg", NULL);
if (!pr)
central_probe_failure(__LINE__);
memcpy(fpregs, pr, sizeof(fpregs));
apply_central_ranges(central_bus, &fpregs[0], 6);
@ -366,7 +365,7 @@ void central_probe(void)
fhc->jtag_master = 0;
/* Attach the clock board registers for CENTRAL. */
probe_clock_board(central_bus, fhc, cnode, fnode);
probe_clock_board(central_bus, fhc, fp);
err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n",

View File

@ -17,6 +17,7 @@
#include <asm/spitfire.h>
#include <asm/chmctrl.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/io.h>
#define CHMCTRL_NDGRPS 2
@ -67,7 +68,6 @@ struct bank_info {
struct mctrl_info {
struct list_head list;
int portid;
int index;
struct obp_mem_layout layout_prop;
int layout_size;
@ -339,12 +339,13 @@ static void fetch_decode_regs(struct mctrl_info *mp)
read_mcreg(mp, CHMCTRL_DECODE4));
}
static int init_one_mctrl(int node, int index)
static int init_one_mctrl(struct device_node *dp)
{
struct mctrl_info *mp = kmalloc(sizeof(*mp), GFP_KERNEL);
int portid = prom_getintdefault(node, "portid", -1);
struct linux_prom64_registers p_reg_prop;
int t;
int portid = of_getintprop_default(dp, "portid", -1);
struct linux_prom64_registers *regs;
void *pval;
int len;
if (!mp)
return -1;
@ -353,24 +354,21 @@ static int init_one_mctrl(int node, int index)
goto fail;
mp->portid = portid;
mp->layout_size = prom_getproplen(node, "memory-layout");
if (mp->layout_size < 0)
pval = of_get_property(dp, "memory-layout", &len);
mp->layout_size = len;
if (!pval)
mp->layout_size = 0;
if (mp->layout_size > sizeof(mp->layout_prop))
else {
if (mp->layout_size > sizeof(mp->layout_prop))
goto fail;
memcpy(&mp->layout_prop, pval, len);
}
regs = of_get_property(dp, "reg", NULL);
if (!regs || regs->reg_size != 0x48)
goto fail;
if (mp->layout_size > 0)
prom_getproperty(node, "memory-layout",
(char *) &mp->layout_prop,
mp->layout_size);
t = prom_getproperty(node, "reg",
(char *) &p_reg_prop,
sizeof(p_reg_prop));
if (t < 0 || p_reg_prop.reg_size != 0x48)
goto fail;
mp->regs = ioremap(p_reg_prop.phys_addr, p_reg_prop.reg_size);
mp->regs = ioremap(regs->phys_addr, regs->reg_size);
if (mp->regs == NULL)
goto fail;
@ -384,13 +382,11 @@ static int init_one_mctrl(int node, int index)
fetch_decode_regs(mp);
mp->index = index;
list_add(&mp->list, &mctrl_list);
/* Report the device. */
printk(KERN_INFO "chmc%d: US3 memory controller at %p [%s]\n",
mp->index,
printk(KERN_INFO "%s: US3 memory controller at %p [%s]\n",
dp->full_name,
mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE"));
return 0;
@ -404,34 +400,19 @@ fail:
return -1;
}
static int __init probe_for_string(char *name, int index)
{
int node = prom_getchild(prom_root_node);
while ((node = prom_searchsiblings(node, name)) != 0) {
int ret = init_one_mctrl(node, index);
if (!ret)
index++;
node = prom_getsibling(node);
if (!node)
break;
}
return index;
}
static int __init chmc_init(void)
{
int index;
struct device_node *dp;
/* This driver is only for cheetah platforms. */
if (tlb_type != cheetah && tlb_type != cheetah_plus)
return -ENODEV;
index = probe_for_string("memory-controller", 0);
index = probe_for_string("mc-us3", index);
for_each_node_by_name(dp, "memory-controller")
init_one_mctrl(dp);
for_each_node_by_name(dp, "mc-us3")
init_one_mctrl(dp);
return 0;
}

View File

@ -33,7 +33,7 @@ extern void cpu_probe(void);
extern void central_probe(void);
u32 sun4v_vdev_devhandle;
int sun4v_vdev_root;
struct device_node *sun4v_vdev_root;
struct vdev_intmap {
unsigned int phys;
@ -50,102 +50,68 @@ struct vdev_intmask {
static struct vdev_intmap *vdev_intmap;
static int vdev_num_intmap;
static struct vdev_intmask vdev_intmask;
static struct vdev_intmask *vdev_intmask;
static void __init sun4v_virtual_device_probe(void)
{
struct linux_prom64_registers regs;
struct vdev_intmap *ip;
int node, sz, err;
struct linux_prom64_registers *regs;
struct property *prop;
struct device_node *dp;
int sz;
if (tlb_type != hypervisor)
return;
node = prom_getchild(prom_root_node);
node = prom_searchsiblings(node, "virtual-devices");
if (!node) {
dp = of_find_node_by_name(NULL, "virtual-devices");
if (!dp) {
prom_printf("SUN4V: Fatal error, no virtual-devices node.\n");
prom_halt();
}
sun4v_vdev_root = node;
sun4v_vdev_root = dp;
prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
sun4v_vdev_devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
prop = of_find_property(dp, "reg", NULL);
regs = prop->value;
sun4v_vdev_devhandle = (regs[0].phys_addr >> 32UL) & 0x0fffffff;
sz = prom_getproplen(node, "interrupt-map");
if (sz <= 0) {
prom_printf("SUN4V: Error, no vdev interrupt-map.\n");
prom_halt();
}
prop = of_find_property(dp, "interrupt-map", &sz);
vdev_intmap = prop->value;
vdev_num_intmap = sz / sizeof(struct vdev_intmap);
if ((sz % sizeof(*ip)) != 0) {
prom_printf("SUN4V: Bogus interrupt-map property size %d\n",
sz);
prom_halt();
}
prop = of_find_property(dp, "interrupt-map-mask", NULL);
vdev_intmask = prop->value;
vdev_intmap = ip = alloc_bootmem_low_pages(sz);
if (!vdev_intmap) {
prom_printf("SUN4V: Error, cannot allocate vdev_intmap.\n");
prom_halt();
}
err = prom_getproperty(node, "interrupt-map", (char *) ip, sz);
if (err == -1) {
prom_printf("SUN4V: Fatal error, no vdev interrupt-map.\n");
prom_halt();
}
if (err != sz) {
prom_printf("SUN4V: Inconsistent interrupt-map size, "
"proplen(%d) vs getprop(%d).\n", sz,err);
prom_halt();
}
vdev_num_intmap = err / sizeof(*ip);
err = prom_getproperty(node, "interrupt-map-mask",
(char *) &vdev_intmask,
sizeof(vdev_intmask));
if (err <= 0) {
prom_printf("SUN4V: Fatal error, no vdev "
"interrupt-map-mask.\n");
prom_halt();
}
if (err % sizeof(vdev_intmask)) {
prom_printf("SUN4V: Bogus interrupt-map-mask "
"property size %d\n", err);
prom_halt();
}
printk("SUN4V: virtual-devices devhandle[%x]\n",
sun4v_vdev_devhandle);
printk("%s: Virtual Device Bus devhandle[%x]\n",
dp->full_name, sun4v_vdev_devhandle);
}
unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node)
unsigned int sun4v_vdev_device_interrupt(struct device_node *dev_node)
{
struct property *prop;
unsigned int irq, reg;
int err, i;
int i;
err = prom_getproperty(dev_node, "interrupts",
(char *) &irq, sizeof(irq));
if (err <= 0) {
prop = of_find_property(dev_node, "interrupts", NULL);
if (!prop) {
printk("VDEV: Cannot get \"interrupts\" "
"property for OBP node %x\n", dev_node);
"property for OBP node %s\n",
dev_node->full_name);
return 0;
}
irq = *(unsigned int *) prop->value;
err = prom_getproperty(dev_node, "reg",
(char *) &reg, sizeof(reg));
if (err <= 0) {
prop = of_find_property(dev_node, "reg", NULL);
if (!prop) {
printk("VDEV: Cannot get \"reg\" "
"property for OBP node %x\n", dev_node);
"property for OBP node %s\n",
dev_node->full_name);
return 0;
}
reg = *(unsigned int *) prop->value;
for (i = 0; i < vdev_num_intmap; i++) {
if (vdev_intmap[i].phys == (reg & vdev_intmask.phys) &&
vdev_intmap[i].irq == (irq & vdev_intmask.interrupt)) {
if (vdev_intmap[i].phys == (reg & vdev_intmask->phys) &&
vdev_intmap[i].irq == (irq & vdev_intmask->interrupt)) {
irq = vdev_intmap[i].cinterrupt;
break;
}
@ -153,7 +119,7 @@ unsigned int sun4v_vdev_device_interrupt(unsigned int dev_node)
if (i == vdev_num_intmap) {
printk("VDEV: No matching interrupt map entry "
"for OBP node %x\n", dev_node);
"for OBP node %s\n", dev_node->full_name);
return 0;
}
@ -167,38 +133,44 @@ static const char *cpu_mid_prop(void)
return "portid";
}
static int get_cpu_mid(int prom_node)
static int get_cpu_mid(struct device_node *dp)
{
struct property *prop;
if (tlb_type == hypervisor) {
struct linux_prom64_registers reg;
struct linux_prom64_registers *reg;
int len;
if (prom_getproplen(prom_node, "cpuid") == 4)
return prom_getintdefault(prom_node, "cpuid", 0);
prop = of_find_property(dp, "cpuid", &len);
if (prop && len == 4)
return *(int *) prop->value;
prom_getproperty(prom_node, "reg", (char *) &reg, sizeof(reg));
return (reg.phys_addr >> 32) & 0x0fffffffUL;
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();
return prom_getintdefault(prom_node, prop_name, 0);
prop = of_find_property(dp, prop_name, NULL);
if (prop)
return *(int *) prop->value;
return 0;
}
}
static int check_cpu_node(int nd, int *cur_inst,
int (*compare)(int, int, void *), void *compare_arg,
int *prom_node, int *mid)
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)
{
char node_str[128];
prom_getstring(nd, "device_type", node_str, sizeof(node_str));
if (strcmp(node_str, "cpu"))
if (strcmp(dp->type, "cpu"))
return -ENODEV;
if (!compare(nd, *cur_inst, compare_arg)) {
if (prom_node)
*prom_node = nd;
if (!compare(dp, *cur_inst, compare_arg)) {
if (dev_node)
*dev_node = dp;
if (mid)
*mid = get_cpu_mid(nd);
*mid = get_cpu_mid(dp);
return 0;
}
@ -207,25 +179,18 @@ static int check_cpu_node(int nd, int *cur_inst,
return -ENODEV;
}
static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
int *prom_node, int *mid)
static int __cpu_find_by(int (*compare)(struct device_node *, int, void *),
void *compare_arg,
struct device_node **dev_node, int *mid)
{
int nd, cur_inst, err;
struct device_node *dp;
int cur_inst;
nd = prom_root_node;
cur_inst = 0;
err = check_cpu_node(nd, &cur_inst,
compare, compare_arg,
prom_node, mid);
if (err == 0)
return 0;
nd = prom_getchild(nd);
while ((nd = prom_getsibling(nd)) != 0) {
err = check_cpu_node(nd, &cur_inst,
compare, compare_arg,
prom_node, mid);
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;
}
@ -233,7 +198,7 @@ static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
return -ENODEV;
}
static int cpu_instance_compare(int nd, int instance, void *_arg)
static int cpu_instance_compare(struct device_node *dp, int instance, void *_arg)
{
int desired_instance = (int) (long) _arg;
@ -242,27 +207,27 @@ static int cpu_instance_compare(int nd, int instance, void *_arg)
return -ENODEV;
}
int cpu_find_by_instance(int instance, int *prom_node, int *mid)
int cpu_find_by_instance(int instance, struct device_node **dev_node, int *mid)
{
return __cpu_find_by(cpu_instance_compare, (void *)(long)instance,
prom_node, mid);
dev_node, mid);
}
static int cpu_mid_compare(int nd, int instance, void *_arg)
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(nd);
this_mid = get_cpu_mid(dp);
if (this_mid == desired_mid)
return 0;
return -ENODEV;
}
int cpu_find_by_mid(int mid, int *prom_node)
int cpu_find_by_mid(int mid, struct device_node **dev_node)
{
return __cpu_find_by(cpu_mid_compare, (void *)(long)mid,
prom_node, NULL);
dev_node, NULL);
}
void __init device_scan(void)
@ -274,50 +239,47 @@ void __init device_scan(void)
#ifndef CONFIG_SMP
{
int err, cpu_node, def;
struct device_node *dp;
int err, def;
err = cpu_find_by_instance(0, &cpu_node, NULL);
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 = prom_getintdefault(cpu_node,
"clock-frequency",
0);
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 = prom_getintdefault(cpu_node,
"dcache-size",
def);
cpu_data(0).dcache_size = of_getintprop_default(dp,
"dcache-size",
def);
def = 32;
cpu_data(0).dcache_line_size =
prom_getintdefault(cpu_node, "dcache-line-size",
def);
of_getintprop_default(dp, "dcache-line-size", def);
def = 16 * 1024;
cpu_data(0).icache_size = prom_getintdefault(cpu_node,
"icache-size",
def);
cpu_data(0).icache_size = of_getintprop_default(dp,
"icache-size",
def);
def = 32;
cpu_data(0).icache_line_size =
prom_getintdefault(cpu_node, "icache-line-size",
def);
of_getintprop_default(dp, "icache-line-size", def);
def = ((tlb_type == hypervisor) ?
(3 * 1024 * 1024) :
(4 * 1024 * 1024));
cpu_data(0).ecache_size = prom_getintdefault(cpu_node,
"ecache-size",
def);
cpu_data(0).ecache_size = of_getintprop_default(dp,
"ecache-size",
def);
def = 64;
cpu_data(0).ecache_line_size =
prom_getintdefault(cpu_node, "ecache-line-size",
def);
of_getintprop_default(dp, "ecache-line-size", def);
printk("CPU[0]: Caches "
"D[sz(%d):line_sz(%d)] "
"I[sz(%d):line_sz(%d)] "

View File

@ -269,10 +269,6 @@ EXPORT_SYMBOL(ebus_dma_enable);
struct linux_ebus *ebus_chain = NULL;
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
static inline void *ebus_alloc(size_t size)
{
void *mem;
@ -283,77 +279,55 @@ static inline void *ebus_alloc(size_t size)
return mem;
}
static void __init ebus_ranges_init(struct linux_ebus *ebus)
{
int success;
ebus->num_ebus_ranges = 0;
success = prom_getproperty(ebus->prom_node, "ranges",
(char *)ebus->ebus_ranges,
sizeof(ebus->ebus_ranges));
if (success != -1)
ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges));
}
static void __init ebus_intmap_init(struct linux_ebus *ebus)
{
int success;
ebus->num_ebus_intmap = 0;
success = prom_getproperty(ebus->prom_node, "interrupt-map",
(char *)ebus->ebus_intmap,
sizeof(ebus->ebus_intmap));
if (success == -1)
return;
ebus->num_ebus_intmap = (success/sizeof(struct linux_prom_ebus_intmap));
success = prom_getproperty(ebus->prom_node, "interrupt-map-mask",
(char *)&ebus->ebus_intmask,
sizeof(ebus->ebus_intmask));
if (success == -1) {
prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__);
prom_halt();
}
}
int __init ebus_intmap_match(struct linux_ebus *ebus,
struct linux_prom_registers *reg,
int *interrupt)
{
struct linux_prom_ebus_intmap *imap;
struct linux_prom_ebus_intmask *imask;
unsigned int hi, lo, irq;
int i;
int i, len, n_imap;
if (!ebus->num_ebus_intmap)
imap = of_get_property(ebus->prom_node, "interrupt-map", &len);
if (!imap)
return 0;
n_imap = len / sizeof(imap[0]);
imask = of_get_property(ebus->prom_node, "interrupt-map-mask", NULL);
if (!imask)
return 0;
hi = reg->which_io & ebus->ebus_intmask.phys_hi;
lo = reg->phys_addr & ebus->ebus_intmask.phys_lo;
irq = *interrupt & ebus->ebus_intmask.interrupt;
for (i = 0; i < ebus->num_ebus_intmap; i++) {
if ((ebus->ebus_intmap[i].phys_hi == hi) &&
(ebus->ebus_intmap[i].phys_lo == lo) &&
(ebus->ebus_intmap[i].interrupt == irq)) {
*interrupt = ebus->ebus_intmap[i].cinterrupt;
hi = reg->which_io & imask->phys_hi;
lo = reg->phys_addr & imask->phys_lo;
irq = *interrupt & imask->interrupt;
for (i = 0; i < n_imap; i++) {
if ((imap[i].phys_hi == hi) &&
(imap[i].phys_lo == lo) &&
(imap[i].interrupt == irq)) {
*interrupt = imap[i].cinterrupt;
return 0;
}
}
return -1;
}
void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
struct linux_ebus_child *dev, int non_standard_regs)
void __init fill_ebus_child(struct device_node *dp,
struct linux_prom_registers *preg,
struct linux_ebus_child *dev,
int non_standard_regs)
{
int regs[PROMREG_MAX];
int irqs[PROMREG_MAX];
int *regs;
int *irqs;
int i, len;
dev->prom_node = node;
prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
printk(" (%s)", dev->prom_name);
dev->prom_node = dp;
printk(" (%s)", dp->name);
len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
dev->num_addrs = len / sizeof(regs[0]);
regs = of_get_property(dp, "reg", &len);
if (!regs)
dev->num_addrs = 0;
else
dev->num_addrs = len / sizeof(regs[0]);
if (non_standard_regs) {
/* This is to handle reg properties which are not
@ -370,21 +344,21 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
int rnum = regs[i];
if (rnum >= dev->parent->num_addrs) {
prom_printf("UGH: property for %s was %d, need < %d\n",
dev->prom_name, len, dev->parent->num_addrs);
panic(__FUNCTION__);
dp->name, len, dev->parent->num_addrs);
prom_halt();
}
dev->resource[i].start = dev->parent->resource[i].start;
dev->resource[i].end = dev->parent->resource[i].end;
dev->resource[i].flags = IORESOURCE_MEM;
dev->resource[i].name = dev->prom_name;
dev->resource[i].name = dp->name;
}
}
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;
len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
if ((len == -1) || (len == 0)) {
irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
dev->num_irqs = 0;
/*
* Oh, well, some PROMs don't export interrupts
@ -392,8 +366,8 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
*
* Be smart about PS/2 keyboard and mouse.
*/
if (!strcmp(dev->parent->prom_name, "8042")) {
if (!strcmp(dev->prom_name, "kb_ps2")) {
if (!strcmp(dev->parent->prom_node->name, "8042")) {
if (!strcmp(dev->prom_node->name, "kb_ps2")) {
dev->num_irqs = 1;
dev->irqs[0] = dev->parent->irqs[0];
} else {
@ -423,32 +397,32 @@ void __init fill_ebus_child(int node, struct linux_prom_registers *preg,
static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
{
if (!strcmp(dev->prom_name, "i2c") ||
!strcmp(dev->prom_name, "SUNW,lombus"))
if (!strcmp(dev->prom_node->name, "i2c") ||
!strcmp(dev->prom_node->name, "SUNW,lombus"))
return 1;
return 0;
}
void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
struct linux_prom_registers regs[PROMREG_MAX];
struct linux_prom_registers *regs;
struct linux_ebus_child *child;
int irqs[PROMINTR_MAX];
int *irqs;
int i, n, len;
dev->prom_node = node;
prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name));
printk(" [%s", dev->prom_name);
dev->prom_node = dp;
len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
if (len == -1) {
printk(" [%s", dp->name);
regs = of_get_property(dp, "reg", &len);
if (!regs) {
dev->num_addrs = 0;
goto probe_interrupts;
}
if (len % sizeof(struct linux_prom_registers)) {
prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
dev->prom_name, len,
dev->prom_node->name, len,
(int)sizeof(struct linux_prom_registers));
prom_halt();
}
@ -466,7 +440,7 @@ void __init fill_ebus_device(int node, struct linux_ebus_device *dev)
dev->resource[i].end =
(dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL);
dev->resource[i].flags = IORESOURCE_MEM;
dev->resource[i].name = dev->prom_name;
dev->resource[i].name = dev->prom_node->name;
request_resource(&dev->bus->self->resource[n],
&dev->resource[i]);
}
@ -475,8 +449,8 @@ probe_interrupts:
for (i = 0; i < PROMINTR_MAX; i++)
dev->irqs[i] = PCI_IRQ_NONE;
len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
if ((len == -1) || (len == 0)) {
irqs = of_get_property(dp, "interrupts", &len);
if (!irqs) {
dev->num_irqs = 0;
} else {
dev->num_irqs = len / sizeof(irqs[0]);
@ -497,7 +471,18 @@ probe_interrupts:
}
}
if ((node = prom_getchild(node))) {
dev->ofdev.node = dp;
dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
dev->ofdev.dev.bus = &ebus_bus_type;
strcpy(dev->ofdev.dev.bus_id, dp->path_component_name);
/* Register with core */
if (of_device_register(&dev->ofdev) != 0)
printk(KERN_DEBUG "ebus: device registration error for %s!\n",
dev->ofdev.dev.bus_id);
dp = dp->child;
if (dp) {
printk(" ->");
dev->children = ebus_alloc(sizeof(struct linux_ebus_child));
@ -505,18 +490,18 @@ probe_interrupts:
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
fill_ebus_child(node, &regs[0],
child, child_regs_nonstandard(dev));
fill_ebus_child(dp, regs, child,
child_regs_nonstandard(dev));
while ((node = prom_getsibling(node)) != 0) {
while ((dp = dp->sibling) != NULL) {
child->next = ebus_alloc(sizeof(struct linux_ebus_child));
child = child->next;
child->next = NULL;
child->parent = dev;
child->bus = dev->bus;
fill_ebus_child(node, &regs[0],
child, child_regs_nonstandard(dev));
fill_ebus_child(dp, regs, child,
child_regs_nonstandard(dev));
}
}
printk("]");
@ -543,7 +528,8 @@ void __init ebus_init(void)
struct linux_ebus *ebus;
struct pci_dev *pdev;
struct pcidev_cookie *cookie;
int nd, ebusnd, is_rio;
struct device_node *dp;
int is_rio;
int num_ebus = 0;
pdev = find_next_ebus(NULL, &is_rio);
@ -553,20 +539,22 @@ void __init ebus_init(void)
}
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
dp = cookie->prom_node;
ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
ebus->next = NULL;
ebus->is_rio = is_rio;
while (ebusnd) {
while (dp) {
struct device_node *child;
/* SUNW,pci-qfe uses four empty ebuses on it.
I think we should not consider them here,
as they have half of the properties this
code expects and once we do PCI hot-plug,
we'd have to tweak with the ebus_chain
in the runtime after initialization. -jj */
if (!prom_getchild (ebusnd)) {
if (!dp->child) {
pdev = find_next_ebus(pdev, &is_rio);
if (!pdev) {
if (ebus == ebus_chain) {
@ -578,22 +566,29 @@ void __init ebus_init(void)
}
ebus->is_rio = is_rio;
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
dp = cookie->prom_node;
continue;
}
printk("ebus%d:", num_ebus);
prom_getstring(ebusnd, "name", ebus->prom_name, sizeof(ebus->prom_name));
ebus->index = num_ebus;
ebus->prom_node = ebusnd;
ebus->prom_node = dp;
ebus->self = pdev;
ebus->parent = pbm = cookie->pbm;
ebus_ranges_init(ebus);
ebus_intmap_init(ebus);
ebus->ofdev.node = dp;
ebus->ofdev.dev.parent = &pdev->dev;
ebus->ofdev.dev.bus = &ebus_bus_type;
strcpy(ebus->ofdev.dev.bus_id, dp->path_component_name);
nd = prom_getchild(ebusnd);
if (!nd)
/* Register with core */
if (of_device_register(&ebus->ofdev) != 0)
printk(KERN_DEBUG "ebus: device registration error for %s!\n",
ebus->ofdev.dev.bus_id);
child = dp->child;
if (!child)
goto next_ebus;
ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
@ -602,16 +597,16 @@ void __init ebus_init(void)
dev->next = NULL;
dev->children = NULL;
dev->bus = ebus;
fill_ebus_device(nd, dev);
fill_ebus_device(child, dev);
while ((nd = prom_getsibling(nd)) != 0) {
while ((child = child->sibling) != NULL) {
dev->next = ebus_alloc(sizeof(struct linux_ebus_device));
dev = dev->next;
dev->next = NULL;
dev->children = NULL;
dev->bus = ebus;
fill_ebus_device(nd, dev);
fill_ebus_device(child, dev);
}
next_ebus:
@ -622,7 +617,7 @@ void __init ebus_init(void)
break;
cookie = pdev->sysdata;
ebusnd = cookie->prom_node;
dp = cookie->prom_node;
ebus->next = ebus_alloc(sizeof(struct linux_ebus));
ebus = ebus->next;
@ -631,8 +626,4 @@ void __init ebus_init(void)
++num_ebus;
}
pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */
#ifdef CONFIG_SUN_AUXIO
auxio_probe();
#endif
}

View File

@ -34,6 +34,7 @@
#include <asm/iommu.h>
#include <asm/upa.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/timer.h>
#include <asm/smp.h>
#include <asm/starfire.h>
@ -635,23 +636,29 @@ static u64 prom_limit0, prom_limit1;
static void map_prom_timers(void)
{
unsigned int addr[3];
int tnode, err;
struct device_node *dp;
unsigned int *addr;
/* PROM timer node hangs out in the top level of device siblings... */
tnode = prom_finddevice("/counter-timer");
dp = of_find_node_by_path("/");
dp = dp->child;
while (dp) {
if (!strcmp(dp->name, "counter-timer"))
break;
dp = dp->sibling;
}
/* Assume if node is not present, PROM uses different tick mechanism
* which we should not care about.
*/
if (tnode == 0 || tnode == -1) {
if (!dp) {
prom_timers = (struct sun5_timer *) 0;
return;
}
/* If PROM is really using this, it must be mapped by him. */
err = prom_getproperty(tnode, "address", (char *)addr, sizeof(addr));
if (err == -1) {
addr = of_get_property(dp, "address", NULL);
if (!addr) {
prom_printf("PROM does not have timer mapped, trying to continue.\n");
prom_timers = (struct sun5_timer *) 0;
return;

View File

@ -15,23 +15,19 @@ static void __init fatal_err(const char *reason)
static void __init report_dev(struct sparc_isa_device *isa_dev, int child)
{
if (child)
printk(" (%s)", isa_dev->prom_name);
printk(" (%s)", isa_dev->prom_node->name);
else
printk(" [%s", isa_dev->prom_name);
printk(" [%s", isa_dev->prom_node->name);
}
static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev,
struct linux_prom_registers *pregs,
int pregs_size)
static struct linux_prom_registers * __init
isa_dev_get_resource(struct sparc_isa_device *isa_dev)
{
struct linux_prom_registers *pregs;
unsigned long base, len;
int prop_len;
prop_len = prom_getproperty(isa_dev->prom_node, "reg",
(char *) pregs, pregs_size);
if (prop_len <= 0)
return;
pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len);
/* Only the first one is interesting. */
len = pregs[0].reg_size;
@ -42,10 +38,12 @@ static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev,
isa_dev->resource.start = base;
isa_dev->resource.end = (base + len - 1UL);
isa_dev->resource.flags = IORESOURCE_IO;
isa_dev->resource.name = isa_dev->prom_name;
isa_dev->resource.name = isa_dev->prom_node->name;
request_resource(&isa_dev->bus->parent->io_space,
&isa_dev->resource);
return pregs;
}
/* I can't believe they didn't put a real INO in the isa device
@ -74,19 +72,30 @@ static struct {
static int __init isa_dev_get_irq_using_imap(struct sparc_isa_device *isa_dev,
struct sparc_isa_bridge *isa_br,
int *interrupt,
struct linux_prom_registers *pregs)
struct linux_prom_registers *reg)
{
struct linux_prom_ebus_intmap *imap;
struct linux_prom_ebus_intmap *imask;
unsigned int hi, lo, irq;
int i;
int i, len, n_imap;
hi = pregs->which_io & isa_br->isa_intmask.phys_hi;
lo = pregs->phys_addr & isa_br->isa_intmask.phys_lo;
irq = *interrupt & isa_br->isa_intmask.interrupt;
for (i = 0; i < isa_br->num_isa_intmap; i++) {
if ((isa_br->isa_intmap[i].phys_hi == hi) &&
(isa_br->isa_intmap[i].phys_lo == lo) &&
(isa_br->isa_intmap[i].interrupt == irq)) {
*interrupt = isa_br->isa_intmap[i].cinterrupt;
imap = of_get_property(isa_br->prom_node, "interrupt-map", &len);
if (!imap)
return 0;
n_imap = len / sizeof(imap[0]);
imask = of_get_property(isa_br->prom_node, "interrupt-map-mask", NULL);
if (!imask)
return 0;
hi = reg->which_io & imask->phys_hi;
lo = reg->phys_addr & imask->phys_lo;
irq = *interrupt & imask->interrupt;
for (i = 0; i < n_imap; i++) {
if ((imap[i].phys_hi == hi) &&
(imap[i].phys_lo == lo) &&
(imap[i].interrupt == irq)) {
*interrupt = imap[i].cinterrupt;
return 0;
}
}
@ -98,8 +107,8 @@ static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
{
int irq_prop;
irq_prop = prom_getintdefault(isa_dev->prom_node,
"interrupts", -1);
irq_prop = of_getintprop_default(isa_dev->prom_node,
"interrupts", -1);
if (irq_prop <= 0) {
goto no_irq;
} else {
@ -107,7 +116,8 @@ static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev,
struct pci_pbm_info *pbm;
int i;
if (isa_dev->bus->num_isa_intmap) {
if (of_find_property(isa_dev->bus->prom_node,
"interrupt-map", NULL)) {
if (!isa_dev_get_irq_using_imap(isa_dev,
isa_dev->bus,
&irq_prop,
@ -141,16 +151,15 @@ no_irq:
static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
{
int node = prom_getchild(parent_isa_dev->prom_node);
struct device_node *dp = parent_isa_dev->prom_node->child;
if (node == 0)
if (!dp)
return;
printk(" ->");
while (node != 0) {
struct linux_prom_registers regs[PROMREG_MAX];
while (dp) {
struct linux_prom_registers *regs;
struct sparc_isa_device *isa_dev;
int prop_len;
isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
@ -165,49 +174,46 @@ static void __init isa_fill_children(struct sparc_isa_device *parent_isa_dev)
parent_isa_dev->child = isa_dev;
isa_dev->bus = parent_isa_dev->bus;
isa_dev->prom_node = node;
prop_len = prom_getproperty(node, "name",
(char *) isa_dev->prom_name,
sizeof(isa_dev->prom_name));
if (prop_len <= 0) {
fatal_err("cannot get child isa_dev OBP node name");
prom_halt();
}
isa_dev->prom_node = dp;
prop_len = prom_getproperty(node, "compatible",
(char *) isa_dev->compatible,
sizeof(isa_dev->compatible));
/* Not having this is OK. */
if (prop_len <= 0)
isa_dev->compatible[0] = '\0';
isa_dev_get_resource(isa_dev, regs, sizeof(regs));
regs = isa_dev_get_resource(isa_dev);
isa_dev_get_irq(isa_dev, regs);
report_dev(isa_dev, 1);
node = prom_getsibling(node);
dp = dp->sibling;
}
}
static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
{
int node = prom_getchild(isa_br->prom_node);
struct device_node *dp = isa_br->prom_node->child;
while (node != 0) {
struct linux_prom_registers regs[PROMREG_MAX];
while (dp) {
struct linux_prom_registers *regs;
struct sparc_isa_device *isa_dev;
int prop_len;
isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
fatal_err("cannot allocate isa_dev");
prom_halt();
printk(KERN_DEBUG "ISA: cannot allocate isa_dev");
return;
}
memset(isa_dev, 0, sizeof(*isa_dev));
isa_dev->ofdev.node = dp;
isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
isa_dev->ofdev.dev.bus = &isa_bus_type;
strcpy(isa_dev->ofdev.dev.bus_id, dp->path_component_name);
/* Register with core */
if (of_device_register(&isa_dev->ofdev) != 0) {
printk(KERN_DEBUG "isa: device registration error for %s!\n",
isa_dev->ofdev.dev.bus_id);
kfree(isa_dev);
goto next_sibling;
}
/* Link it in. */
isa_dev->next = NULL;
if (isa_br->devices == NULL) {
@ -222,24 +228,9 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
}
isa_dev->bus = isa_br;
isa_dev->prom_node = node;
prop_len = prom_getproperty(node, "name",
(char *) isa_dev->prom_name,
sizeof(isa_dev->prom_name));
if (prop_len <= 0) {
fatal_err("cannot get isa_dev OBP node name");
prom_halt();
}
isa_dev->prom_node = dp;
prop_len = prom_getproperty(node, "compatible",
(char *) isa_dev->compatible,
sizeof(isa_dev->compatible));
/* Not having this is OK. */
if (prop_len <= 0)
isa_dev->compatible[0] = '\0';
isa_dev_get_resource(isa_dev, regs, sizeof(regs));
regs = isa_dev_get_resource(isa_dev);
isa_dev_get_irq(isa_dev, regs);
report_dev(isa_dev, 0);
@ -248,7 +239,8 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
printk("]");
node = prom_getsibling(node);
next_sibling:
dp = dp->sibling;
}
}
@ -266,7 +258,7 @@ void __init isa_init(void)
struct pcidev_cookie *pdev_cookie;
struct pci_pbm_info *pbm;
struct sparc_isa_bridge *isa_br;
int prop_len;
struct device_node *dp;
pdev_cookie = pdev->sysdata;
if (!pdev_cookie) {
@ -275,15 +267,29 @@ void __init isa_init(void)
continue;
}
pbm = pdev_cookie->pbm;
dp = pdev_cookie->prom_node;
isa_br = kmalloc(sizeof(*isa_br), GFP_KERNEL);
if (!isa_br) {
fatal_err("cannot allocate sparc_isa_bridge");
prom_halt();
printk(KERN_DEBUG "isa: cannot allocate sparc_isa_bridge");
return;
}
memset(isa_br, 0, sizeof(*isa_br));
isa_br->ofdev.node = dp;
isa_br->ofdev.dev.parent = &pdev->dev;
isa_br->ofdev.dev.bus = &isa_bus_type;
strcpy(isa_br->ofdev.dev.bus_id, dp->path_component_name);
/* Register with core */
if (of_device_register(&isa_br->ofdev) != 0) {
printk(KERN_DEBUG "isa: device registration error for %s!\n",
isa_br->ofdev.dev.bus_id);
kfree(isa_br);
return;
}
/* Link it in. */
isa_br->next = isa_chain;
isa_chain = isa_br;
@ -292,33 +298,6 @@ void __init isa_init(void)
isa_br->self = pdev;
isa_br->index = index++;
isa_br->prom_node = pdev_cookie->prom_node;
strncpy(isa_br->prom_name, pdev_cookie->prom_name,
sizeof(isa_br->prom_name));
prop_len = prom_getproperty(isa_br->prom_node,
"ranges",
(char *) isa_br->isa_ranges,
sizeof(isa_br->isa_ranges));
if (prop_len <= 0)
isa_br->num_isa_ranges = 0;
else
isa_br->num_isa_ranges =
(prop_len / sizeof(struct linux_prom_isa_ranges));
prop_len = prom_getproperty(isa_br->prom_node,
"interrupt-map",
(char *) isa_br->isa_intmap,
sizeof(isa_br->isa_intmap));
if (prop_len <= 0)
isa_br->num_isa_intmap = 0;
else
isa_br->num_isa_intmap =
(prop_len / sizeof(struct linux_prom_isa_intmap));
prop_len = prom_getproperty(isa_br->prom_node,
"interrupt-map-mask",
(char *) &(isa_br->isa_intmask),
sizeof(isa_br->isa_intmask));
printk("isa%d:", isa_br->index);

View File

@ -0,0 +1,279 @@
#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
#include <asm/errno.h>
#include <asm/of_device.h>
/**
* of_match_device - Tell if an of_device structure has a matching
* of_match structure
* @ids: array of of device match structures to search in
* @dev: the of device structure to match against
*
* Used by a driver to check whether an of_device present in the
* system is in its list of supported devices.
*/
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct of_device *dev)
{
if (!dev->node)
return NULL;
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
if (matches->name[0])
match &= dev->node->name
&& !strcmp(matches->name, dev->node->name);
if (matches->type[0])
match &= dev->node->type
&& !strcmp(matches->type, dev->node->type);
if (matches->compatible[0])
match &= of_device_is_compatible(dev->node,
matches->compatible);
if (match)
return matches;
matches++;
}
return NULL;
}
static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * of_drv = to_of_platform_driver(drv);
const struct of_device_id * matches = of_drv->match_table;
if (!matches)
return 0;
return of_match_device(matches, of_dev) != NULL;
}
struct of_device *of_dev_get(struct of_device *dev)
{
struct device *tmp;
if (!dev)
return NULL;
tmp = get_device(&dev->dev);
if (tmp)
return to_of_device(tmp);
else
return NULL;
}
void of_dev_put(struct of_device *dev)
{
if (dev)
put_device(&dev->dev);
}
static int of_device_probe(struct device *dev)
{
int error = -ENODEV;
struct of_platform_driver *drv;
struct of_device *of_dev;
const struct of_device_id *match;
drv = to_of_platform_driver(dev->driver);
of_dev = to_of_device(dev);
if (!drv->probe)
return error;
of_dev_get(of_dev);
match = of_match_device(drv->match_table, of_dev);
if (match)
error = drv->probe(of_dev, match);
if (error)
of_dev_put(of_dev);
return error;
}
static int of_device_remove(struct device *dev)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
if (dev->driver && drv->remove)
drv->remove(of_dev);
return 0;
}
static int of_device_suspend(struct device *dev, pm_message_t state)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
int error = 0;
if (dev->driver && drv->suspend)
error = drv->suspend(of_dev, state);
return error;
}
static int of_device_resume(struct device * dev)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
int error = 0;
if (dev->driver && drv->resume)
error = drv->resume(of_dev);
return error;
}
#ifdef CONFIG_PCI
struct bus_type isa_bus_type = {
.name = "isa",
.match = of_platform_bus_match,
.probe = of_device_probe,
.remove = of_device_remove,
.suspend = of_device_suspend,
.resume = of_device_resume,
};
struct bus_type ebus_bus_type = {
.name = "ebus",
.match = of_platform_bus_match,
.probe = of_device_probe,
.remove = of_device_remove,
.suspend = of_device_suspend,
.resume = of_device_resume,
};
#endif
#ifdef CONFIG_SBUS
struct bus_type sbus_bus_type = {
.name = "sbus",
.match = of_platform_bus_match,
.probe = of_device_probe,
.remove = of_device_remove,
.suspend = of_device_suspend,
.resume = of_device_resume,
};
#endif
static int __init of_bus_driver_init(void)
{
int err = 0;
#ifdef CONFIG_PCI
if (!err)
err = bus_register(&isa_bus_type);
if (!err)
err = bus_register(&ebus_bus_type);
#endif
#ifdef CONFIG_SBUS
if (!err)
err = bus_register(&sbus_bus_type);
#endif
return 0;
}
postcore_initcall(of_bus_driver_init);
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
/* initialize common driver fields */
drv->driver.name = drv->name;
drv->driver.bus = bus;
/* register with core */
return driver_register(&drv->driver);
}
void of_unregister_driver(struct of_platform_driver *drv)
{
driver_unregister(&drv->driver);
}
static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
{
struct of_device *ofdev;
ofdev = to_of_device(dev);
return sprintf(buf, "%s", ofdev->node->full_name);
}
static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
/**
* of_release_dev - free an of device structure when all users of it are finished.
* @dev: device that's been disconnected
*
* Will be called only by the device core when all users of this of device are
* done.
*/
void of_release_dev(struct device *dev)
{
struct of_device *ofdev;
ofdev = to_of_device(dev);
kfree(ofdev);
}
int of_device_register(struct of_device *ofdev)
{
int rc;
BUG_ON(ofdev->node == NULL);
rc = device_register(&ofdev->dev);
if (rc)
return rc;
device_create_file(&ofdev->dev, &dev_attr_devspec);
return 0;
}
void of_device_unregister(struct of_device *ofdev)
{
device_remove_file(&ofdev->dev, &dev_attr_devspec);
device_unregister(&ofdev->dev);
}
struct of_device* of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent,
struct bus_type *bus)
{
struct of_device *dev;
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
memset(dev, 0, sizeof(*dev));
dev->dev.parent = parent;
dev->dev.bus = bus;
dev->dev.release = of_release_dev;
strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
if (of_device_register(dev) != 0) {
kfree(dev);
return NULL;
}
return dev;
}
EXPORT_SYMBOL(of_match_device);
EXPORT_SYMBOL(of_register_driver);
EXPORT_SYMBOL(of_unregister_driver);
EXPORT_SYMBOL(of_device_register);
EXPORT_SYMBOL(of_device_unregister);
EXPORT_SYMBOL(of_dev_get);
EXPORT_SYMBOL(of_dev_put);
EXPORT_SYMBOL(of_platform_device_create);
EXPORT_SYMBOL(of_release_dev);

View File

@ -22,6 +22,7 @@
#include <asm/irq.h>
#include <asm/ebus.h>
#include <asm/isa.h>
#include <asm/prom.h>
unsigned long pci_memspace_mask = 0xffffffffUL;
@ -177,16 +178,16 @@ void pci_config_write32(u32 *addr, u32 val)
}
/* Probe for all PCI controllers in the system. */
extern void sabre_init(int, char *);
extern void psycho_init(int, char *);
extern void schizo_init(int, char *);
extern void schizo_plus_init(int, char *);
extern void tomatillo_init(int, char *);
extern void sun4v_pci_init(int, char *);
extern void sabre_init(struct device_node *, const char *);
extern void psycho_init(struct device_node *, const char *);
extern void schizo_init(struct device_node *, const char *);
extern void schizo_plus_init(struct device_node *, const char *);
extern void tomatillo_init(struct device_node *, const char *);
extern void sun4v_pci_init(struct device_node *, const char *);
static struct {
char *model_name;
void (*init)(int, char *);
void (*init)(struct device_node *, const char *);
} pci_controller_table[] __initdata = {
{ "SUNW,sabre", sabre_init },
{ "pci108e,a000", sabre_init },
@ -204,7 +205,7 @@ static struct {
#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
sizeof(pci_controller_table[0]))
static int __init pci_controller_init(char *model_name, int namelen, int node)
static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp)
{
int i;
@ -212,18 +213,15 @@ static int __init pci_controller_init(char *model_name, int namelen, int node)
if (!strncmp(model_name,
pci_controller_table[i].model_name,
namelen)) {
pci_controller_table[i].init(node, model_name);
pci_controller_table[i].init(dp, model_name);
return 1;
}
}
printk("PCI: Warning unknown controller, model name [%s]\n",
model_name);
printk("PCI: Ignoring controller...\n");
return 0;
}
static int __init pci_is_controller(char *model_name, int namelen, int node)
static int __init pci_is_controller(const char *model_name, int namelen, struct device_node *dp)
{
int i;
@ -237,36 +235,35 @@ static int __init pci_is_controller(char *model_name, int namelen, int node)
return 0;
}
static int __init pci_controller_scan(int (*handler)(char *, int, int))
static int __init pci_controller_scan(int (*handler)(const char *, int, struct device_node *))
{
char namebuf[64];
int node;
struct device_node *dp;
int count = 0;
node = prom_getchild(prom_root_node);
while ((node = prom_searchsiblings(node, "pci")) != 0) {
for_each_node_by_name(dp, "pci") {
struct property *prop;
int len;
if ((len = prom_getproperty(node, "model", namebuf, sizeof(namebuf))) > 0 ||
(len = prom_getproperty(node, "compatible", namebuf, sizeof(namebuf))) > 0) {
prop = of_find_property(dp, "model", &len);
if (!prop)
prop = of_find_property(dp, "compatible", &len);
if (prop) {
const char *model = prop->value;
int item_len = 0;
/* Our value may be a multi-valued string in the
* case of some compatible properties. For sanity,
* only try the first one. */
while (namebuf[item_len] && len) {
* only try the first one.
*/
while (model[item_len] && len) {
len--;
item_len++;
}
if (handler(namebuf, item_len, node))
if (handler(model, item_len, dp))
count++;
}
node = prom_getsibling(node);
if (!node)
break;
}
return count;
@ -409,8 +406,14 @@ void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res,
}
EXPORT_SYMBOL(pcibios_bus_to_resource);
extern int pci_irq_verbose;
char * __init pcibios_setup(char *str)
{
if (!strcmp(str, "irq_verbose")) {
pci_irq_verbose = 1;
return NULL;
}
return str;
}

View File

@ -9,6 +9,12 @@
#include <linux/init.h>
#include <asm/pbm.h>
#include <asm/prom.h>
#include "pci_impl.h"
/* Pass "pci=irq_verbose" on the kernel command line to enable this. */
int pci_irq_verbose;
/* Fix self device of BUS and hook it into BUS->self.
* The pci_scan_bus does not do this for the host bridge.
@ -28,16 +34,14 @@ void __init pci_fixup_host_bridge_self(struct pci_bus *pbus)
prom_halt();
}
/* Find the OBP PROM device tree node for a PCI device.
* Return zero if not found.
*/
static int __init find_device_prom_node(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
int bus_prom_node,
struct linux_prom_pci_registers *pregs,
int *nregs)
/* Find the OBP PROM device tree node for a PCI device. */
static struct device_node * __init
find_device_prom_node(struct pci_pbm_info *pbm, struct pci_dev *pdev,
struct device_node *bus_node,
struct linux_prom_pci_registers **pregs,
int *nregs)
{
int node;
struct device_node *dp;
*nregs = 0;
@ -54,24 +58,30 @@ static int __init find_device_prom_node(struct pci_pbm_info *pbm,
pdev->device == PCI_DEVICE_ID_SUN_TOMATILLO ||
pdev->device == PCI_DEVICE_ID_SUN_SABRE ||
pdev->device == PCI_DEVICE_ID_SUN_HUMMINGBIRD))
return bus_prom_node;
return bus_node;
node = prom_getchild(bus_prom_node);
while (node != 0) {
int err = prom_getproperty(node, "reg",
(char *)pregs,
sizeof(*pregs) * PROMREG_MAX);
if (err == 0 || err == -1)
dp = bus_node->child;
while (dp) {
struct linux_prom_pci_registers *regs;
struct property *prop;
int len;
prop = of_find_property(dp, "reg", &len);
if (!prop)
goto do_next_sibling;
if (((pregs[0].phys_hi >> 8) & 0xff) == pdev->devfn) {
*nregs = err / sizeof(*pregs);
return node;
regs = prop->value;
if (((regs[0].phys_hi >> 8) & 0xff) == pdev->devfn) {
*pregs = regs;
*nregs = len / sizeof(struct linux_prom_pci_registers);
return dp;
}
do_next_sibling:
node = prom_getsibling(node);
dp = dp->sibling;
}
return 0;
return NULL;
}
/* Older versions of OBP on PCI systems encode 64-bit MEM
@ -128,15 +138,17 @@ static void __init fixup_obp_assignments(struct pci_dev *pdev,
*/
static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
int bus_prom_node)
struct device_node *bus_node)
{
struct linux_prom_pci_registers pregs[PROMREG_MAX];
struct linux_prom_pci_registers *pregs = NULL;
struct pcidev_cookie *pcp;
int device_prom_node, nregs, err;
struct device_node *dp;
struct property *prop;
int nregs, len;
device_prom_node = find_device_prom_node(pbm, pdev, bus_prom_node,
pregs, &nregs);
if (device_prom_node == 0) {
dp = find_device_prom_node(pbm, pdev, bus_node,
&pregs, &nregs);
if (!dp) {
/* If it is not in the OBP device tree then
* there must be a damn good reason for it.
*
@ -150,45 +162,43 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
return;
}
pcp = kmalloc(sizeof(*pcp), GFP_ATOMIC);
pcp = kzalloc(sizeof(*pcp), GFP_ATOMIC);
if (pcp == NULL) {
prom_printf("PCI_COOKIE: Fatal malloc error, aborting...\n");
prom_halt();
}
pcp->pbm = pbm;
pcp->prom_node = device_prom_node;
memcpy(pcp->prom_regs, pregs, sizeof(pcp->prom_regs));
pcp->prom_node = dp;
memcpy(pcp->prom_regs, pregs,
nregs * sizeof(struct linux_prom_pci_registers));
pcp->num_prom_regs = nregs;
err = prom_getproperty(device_prom_node, "name",
pcp->prom_name, sizeof(pcp->prom_name));
if (err > 0)
pcp->prom_name[err] = 0;
else
pcp->prom_name[0] = 0;
err = prom_getproperty(device_prom_node,
"assigned-addresses",
(char *)pcp->prom_assignments,
sizeof(pcp->prom_assignments));
if (err == 0 || err == -1)
/* We can't have the pcidev_cookie assignments be just
* direct pointers into the property value, since they
* are potentially modified by the probing process.
*/
prop = of_find_property(dp, "assigned-addresses", &len);
if (!prop) {
pcp->num_prom_assignments = 0;
else
} else {
memcpy(pcp->prom_assignments, prop->value, len);
pcp->num_prom_assignments =
(err / sizeof(pcp->prom_assignments[0]));
(len / sizeof(pcp->prom_assignments[0]));
}
if (strcmp(pcp->prom_name, "ebus") == 0) {
struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX];
if (strcmp(dp->name, "ebus") == 0) {
struct linux_prom_ebus_ranges *erng;
int iter;
/* EBUS is special... */
err = prom_getproperty(device_prom_node, "ranges",
(char *)&erng[0], sizeof(erng));
if (err == 0 || err == -1) {
prop = of_find_property(dp, "ranges", &len);
if (!prop) {
prom_printf("EBUS: Fatal error, no range property\n");
prom_halt();
}
err = (err / sizeof(erng[0]));
for(iter = 0; iter < err; iter++) {
erng = prop->value;
len = (len / sizeof(erng[0]));
for (iter = 0; iter < len; iter++) {
struct linux_prom_ebus_ranges *ep = &erng[iter];
struct linux_prom_pci_registers *ap;
@ -200,7 +210,7 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
ap->size_hi = 0;
ap->size_lo = ep->size;
}
pcp->num_prom_assignments = err;
pcp->num_prom_assignments = len;
}
fixup_obp_assignments(pdev, pcp);
@ -210,7 +220,7 @@ static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm,
void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
struct pci_pbm_info *pbm,
int prom_node)
struct device_node *dp)
{
struct pci_dev *pdev, *pdev_next;
struct pci_bus *this_pbus, *pbus_next;
@ -218,7 +228,7 @@ void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus,
/* This must be _safe because the cookie fillin
routine can delete devices from the tree. */
list_for_each_entry_safe(pdev, pdev_next, &pbus->devices, bus_list)
pdev_cookie_fillin(pbm, pdev, prom_node);
pdev_cookie_fillin(pbm, pdev, dp);
list_for_each_entry_safe(this_pbus, pbus_next, &pbus->children, node) {
struct pcidev_cookie *pcp = this_pbus->self->sysdata;
@ -241,7 +251,6 @@ static void __init bad_assignment(struct pci_dev *pdev,
if (res)
prom_printf("PCI: RES[%016lx-->%016lx:(%lx)]\n",
res->start, res->end, res->flags);
prom_printf("Please email this information to davem@redhat.com\n");
if (do_prom_halt)
prom_halt();
}
@ -273,8 +282,7 @@ __init get_root_resource(struct linux_prom_pci_registers *ap,
return &pbm->mem_space;
default:
printk("PCI: What is resource space %x? "
"Tell davem@redhat.com about it!\n", space);
printk("PCI: What is resource space %x?\n", space);
return NULL;
};
}
@ -556,9 +564,10 @@ static inline unsigned int pci_slot_swivel(struct pci_pbm_info *pbm,
ret = ((interrupt - 1 + (PCI_SLOT(pdev->devfn) & 3)) & 3) + 1;
printk("%s: %s IRQ Swivel %s [%x:%x] -> [%x]\n",
pbm->name, pci_name(toplevel_pdev), pci_name(pdev),
interrupt, PCI_SLOT(pdev->devfn), ret);
if (pci_irq_verbose)
printk("%s: %s IRQ Swivel %s [%x:%x] -> [%x]\n",
pbm->name, pci_name(toplevel_pdev), pci_name(pdev),
interrupt, PCI_SLOT(pdev->devfn), ret);
return ret;
}
@ -568,58 +577,60 @@ static inline unsigned int pci_apply_intmap(struct pci_pbm_info *pbm,
struct pci_dev *pbus,
struct pci_dev *pdev,
unsigned int interrupt,
unsigned int *cnode)
struct device_node **cnode)
{
struct linux_prom_pci_intmap imap[PROM_PCIIMAP_MAX];
struct linux_prom_pci_intmask imask;
struct linux_prom_pci_intmap *imap;
struct linux_prom_pci_intmask *imask;
struct pcidev_cookie *pbus_pcp = pbus->sysdata;
struct pcidev_cookie *pdev_pcp = pdev->sysdata;
struct linux_prom_pci_registers *pregs = pdev_pcp->prom_regs;
struct property *prop;
int plen, num_imap, i;
unsigned int hi, mid, lo, irq, orig_interrupt;
*cnode = pbus_pcp->prom_node;
plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map",
(char *) &imap[0], sizeof(imap));
if (plen <= 0 ||
prop = of_find_property(pbus_pcp->prom_node, "interrupt-map", &plen);
if (!prop ||
(plen % sizeof(struct linux_prom_pci_intmap)) != 0) {
printk("%s: Device %s interrupt-map has bad len %d\n",
pbm->name, pci_name(pbus), plen);
goto no_intmap;
}
imap = prop->value;
num_imap = plen / sizeof(struct linux_prom_pci_intmap);
plen = prom_getproperty(pbus_pcp->prom_node, "interrupt-map-mask",
(char *) &imask, sizeof(imask));
if (plen <= 0 ||
prop = of_find_property(pbus_pcp->prom_node, "interrupt-map-mask", &plen);
if (!prop ||
(plen % sizeof(struct linux_prom_pci_intmask)) != 0) {
printk("%s: Device %s interrupt-map-mask has bad len %d\n",
pbm->name, pci_name(pbus), plen);
goto no_intmap;
}
imask = prop->value;
orig_interrupt = interrupt;
hi = pregs->phys_hi & imask.phys_hi;
mid = pregs->phys_mid & imask.phys_mid;
lo = pregs->phys_lo & imask.phys_lo;
irq = interrupt & imask.interrupt;
hi = pregs->phys_hi & imask->phys_hi;
mid = pregs->phys_mid & imask->phys_mid;
lo = pregs->phys_lo & imask->phys_lo;
irq = interrupt & imask->interrupt;
for (i = 0; i < num_imap; i++) {
if (imap[i].phys_hi == hi &&
imap[i].phys_mid == mid &&
imap[i].phys_lo == lo &&
imap[i].interrupt == irq) {
*cnode = imap[i].cnode;
*cnode = of_find_node_by_phandle(imap[i].cnode);
interrupt = imap[i].cinterrupt;
}
}
printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n",
pbm->name, pci_name(toplevel_pdev),
pci_name(pbus), pci_name(pdev),
orig_interrupt, interrupt);
if (pci_irq_verbose)
printk("%s: %s MAP BUS %s DEV %s [%x] -> [%x]\n",
pbm->name, pci_name(toplevel_pdev),
pci_name(pbus), pci_name(pdev),
orig_interrupt, interrupt);
no_intmap:
return interrupt;
@ -633,21 +644,22 @@ no_intmap:
* all interrupt translations are complete, else we should use that node's
* "reg" property to apply the PBM's "interrupt-{map,mask}" to the interrupt.
*/
static unsigned int __init pci_intmap_match_to_root(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
unsigned int *interrupt)
static struct device_node * __init
pci_intmap_match_to_root(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
unsigned int *interrupt)
{
struct pci_dev *toplevel_pdev = pdev;
struct pcidev_cookie *toplevel_pcp = toplevel_pdev->sysdata;
unsigned int cnode = toplevel_pcp->prom_node;
struct device_node *cnode = toplevel_pcp->prom_node;
while (pdev->bus->number != pbm->pci_first_busno) {
struct pci_dev *pbus = pdev->bus->self;
struct pcidev_cookie *pcp = pbus->sysdata;
int plen;
struct property *prop;
plen = prom_getproplen(pcp->prom_node, "interrupt-map");
if (plen <= 0) {
prop = of_find_property(pcp->prom_node, "interrupt-map", NULL);
if (!prop) {
*interrupt = pci_slot_swivel(pbm, toplevel_pdev,
pdev, *interrupt);
cnode = pcp->prom_node;
@ -675,26 +687,29 @@ static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt
{
struct pcidev_cookie *dev_pcp = pdev->sysdata;
struct pci_pbm_info *pbm = dev_pcp->pbm;
struct linux_prom_pci_registers reg[PROMREG_MAX];
struct linux_prom_pci_registers *reg;
struct device_node *cnode;
struct property *prop;
unsigned int hi, mid, lo, irq;
int i, cnode, plen;
int i, plen;
cnode = pci_intmap_match_to_root(pbm, pdev, interrupt);
if (cnode == pbm->prom_node)
goto success;
plen = prom_getproperty(cnode, "reg", (char *) reg, sizeof(reg));
if (plen <= 0 ||
prop = of_find_property(cnode, "reg", &plen);
if (!prop ||
(plen % sizeof(struct linux_prom_pci_registers)) != 0) {
printk("%s: OBP node %x reg property has bad len %d\n",
pbm->name, cnode, plen);
printk("%s: OBP node %s reg property has bad len %d\n",
pbm->name, cnode->full_name, plen);
goto fail;
}
reg = prop->value;
hi = reg[0].phys_hi & pbm->pbm_intmask.phys_hi;
mid = reg[0].phys_mid & pbm->pbm_intmask.phys_mid;
lo = reg[0].phys_lo & pbm->pbm_intmask.phys_lo;
irq = *interrupt & pbm->pbm_intmask.interrupt;
hi = reg[0].phys_hi & pbm->pbm_intmask->phys_hi;
mid = reg[0].phys_mid & pbm->pbm_intmask->phys_mid;
lo = reg[0].phys_lo & pbm->pbm_intmask->phys_lo;
irq = *interrupt & pbm->pbm_intmask->interrupt;
for (i = 0; i < pbm->num_pbm_intmap; i++) {
struct linux_prom_pci_intmap *intmap;
@ -714,9 +729,11 @@ fail:
return 0;
success:
printk("PCI-IRQ: Routing bus[%2x] slot[%2x] to INO[%02x]\n",
pdev->bus->number, PCI_SLOT(pdev->devfn),
*interrupt);
if (pci_irq_verbose)
printk("%s: Routing bus[%2x] slot[%2x] to INO[%02x]\n",
pbm->name,
pdev->bus->number, PCI_SLOT(pdev->devfn),
*interrupt);
return 1;
}
@ -727,8 +744,8 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev)
struct pci_controller_info *p = pbm->parent;
unsigned int portid = pbm->portid;
unsigned int prom_irq;
int prom_node = pcp->prom_node;
int err;
struct device_node *dp = pcp->prom_node;
struct property *prop;
/* If this is an empty EBUS device, sometimes OBP fails to
* give it a valid fully specified interrupts property.
@ -739,17 +756,17 @@ static void __init pdev_fixup_irq(struct pci_dev *pdev)
*/
if (pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_EBUS &&
!prom_getchild(prom_node)) {
!dp->child) {
pdev->irq = 0;
return;
}
err = prom_getproperty(prom_node, "interrupts",
(char *)&prom_irq, sizeof(prom_irq));
if (err == 0 || err == -1) {
prop = of_find_property(dp, "interrupts", NULL);
if (!prop) {
pdev->irq = 0;
return;
}
prom_irq = *(unsigned int *) prop->value;
if (tlb_type != hypervisor) {
/* Fully specified already? */

View File

@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/prom.h>
extern struct pci_controller_info *pci_controller_root;
@ -19,7 +20,7 @@ extern int pci_num_controllers;
extern void pci_fixup_host_bridge_self(struct pci_bus *pbus);
extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus,
struct pci_pbm_info *pbm,
int prom_node);
struct device_node *prom_node);
extern void pci_record_assignments(struct pci_pbm_info *pbm,
struct pci_bus *pbus);
extern void pci_assign_unassigned(struct pci_pbm_info *pbm,

View File

@ -17,6 +17,7 @@
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/starfire.h>
#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
@ -1291,11 +1292,12 @@ static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL
static void psycho_pbm_init(struct pci_controller_info *p,
int prom_node, int is_pbm_a)
struct device_node *dp, int is_pbm_a)
{
unsigned int busrange[2];
unsigned int *busrange;
struct property *prop;
struct pci_pbm_info *pbm;
int err;
int len;
if (is_pbm_a) {
pbm = &p->pbm_A;
@ -1310,10 +1312,14 @@ static void psycho_pbm_init(struct pci_controller_info *p,
}
pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
pbm->chip_version =
prom_getintdefault(prom_node, "version#", 0);
pbm->chip_revision =
prom_getintdefault(prom_node, "module-revision#", 0);
pbm->chip_version = 0;
prop = of_find_property(dp, "version#", NULL);
if (prop)
pbm->chip_version = *(int *) prop->value;
pbm->chip_revision = 0;
prop = of_find_property(dp, "module-revision#", NULL);
if (prop)
pbm->chip_revision = *(int *) prop->value;
pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE;
pbm->io_space.flags = IORESOURCE_IO;
@ -1322,45 +1328,36 @@ static void psycho_pbm_init(struct pci_controller_info *p,
pbm_register_toplevel_resources(p, pbm);
pbm->parent = p;
pbm->prom_node = prom_node;
prom_getstring(prom_node, "name",
pbm->prom_name,
sizeof(pbm->prom_name));
pbm->prom_node = dp;
pbm->name = dp->full_name;
err = prom_getproperty(prom_node, "ranges",
(char *)pbm->pbm_ranges,
sizeof(pbm->pbm_ranges));
if (err != -1)
printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n",
pbm->name,
pbm->chip_version, pbm->chip_revision);
prop = of_find_property(dp, "ranges", &len);
if (prop) {
pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
(err / sizeof(struct linux_prom_pci_ranges));
else
(len / sizeof(struct linux_prom_pci_ranges));
} else {
pbm->num_pbm_ranges = 0;
}
err = prom_getproperty(prom_node, "interrupt-map",
(char *)pbm->pbm_intmap,
sizeof(pbm->pbm_intmap));
if (err != -1) {
pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
err = prom_getproperty(prom_node, "interrupt-map-mask",
(char *)&pbm->pbm_intmask,
sizeof(pbm->pbm_intmask));
if (err == -1) {
prom_printf("PSYCHO-PBM: Fatal error, no "
"interrupt-map-mask.\n");
prom_halt();
}
prop = of_find_property(dp, "interrupt-map", &len);
if (prop) {
pbm->pbm_intmap = prop->value;
pbm->num_pbm_intmap =
(len / sizeof(struct linux_prom_pci_intmap));
prop = of_find_property(dp, "interrupt-map-mask", NULL);
pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
err = prom_getproperty(prom_node, "bus-range",
(char *)&busrange[0],
sizeof(busrange));
if (err == 0 || err == -1) {
prom_printf("PSYCHO-PBM: Fatal error, no bus-range.\n");
prom_halt();
}
prop = of_find_property(dp, "bus-range", NULL);
busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
@ -1369,20 +1366,24 @@ static void psycho_pbm_init(struct pci_controller_info *p,
#define PSYCHO_CONFIGSPACE 0x001000000UL
void psycho_init(int node, char *model_name)
void psycho_init(struct device_node *dp, char *model_name)
{
struct linux_prom64_registers pr_regs[3];
struct linux_prom64_registers *pr_regs;
struct pci_controller_info *p;
struct pci_iommu *iommu;
struct property *prop;
u32 upa_portid;
int is_pbm_a, err;
int is_pbm_a;
upa_portid = prom_getintdefault(node, "upa-portid", 0xff);
upa_portid = 0xff;
prop = of_find_property(dp, "upa-portid", NULL);
if (prop)
upa_portid = *(u32 *) prop->value;
for(p = pci_controller_root; p; p = p->next) {
if (p->pbm_A.portid == upa_portid) {
is_pbm_a = (p->pbm_A.prom_node == 0);
psycho_pbm_init(p, node, is_pbm_a);
is_pbm_a = (p->pbm_A.prom_node == NULL);
psycho_pbm_init(p, dp, is_pbm_a);
return;
}
}
@ -1412,23 +1413,14 @@ void psycho_init(int node, char *model_name)
p->resource_adjust = psycho_resource_adjust;
p->pci_ops = &psycho_ops;
err = prom_getproperty(node, "reg",
(char *)&pr_regs[0],
sizeof(pr_regs));
if (err == 0 || err == -1) {
prom_printf("PSYCHO: Fatal error, no reg property.\n");
prom_halt();
}
prop = of_find_property(dp, "reg", NULL);
pr_regs = prop->value;
p->pbm_A.controller_regs = pr_regs[2].phys_addr;
p->pbm_B.controller_regs = pr_regs[2].phys_addr;
printk("PCI: Found PSYCHO, control regs at %016lx\n",
p->pbm_A.controller_regs);
p->pbm_A.config_space = p->pbm_B.config_space =
(pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
printk("PSYCHO: Shared PCI config space at %016lx\n",
p->pbm_A.config_space);
/*
* Psycho's PCI MEM space is mapped to a 2GB aligned area, so
@ -1441,5 +1433,5 @@ void psycho_init(int node, char *model_name)
psycho_iommu_init(p);
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
psycho_pbm_init(p, node, is_pbm_a);
psycho_pbm_init(p, dp, is_pbm_a);
}

View File

@ -19,6 +19,7 @@
#include <asm/irq.h>
#include <asm/smp.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
@ -1306,34 +1307,36 @@ static void pbm_register_toplevel_resources(struct pci_controller_info *p,
&pbm->mem_space);
}
static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dma_begin)
static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_begin)
{
struct pci_pbm_info *pbm;
char namebuf[128];
u32 busrange[2];
int node, simbas_found;
struct device_node *node;
struct property *prop;
u32 *busrange;
int len, simbas_found;
simbas_found = 0;
node = prom_getchild(sabre_node);
while ((node = prom_searchsiblings(node, "pci")) != 0) {
int err;
err = prom_getproperty(node, "model", namebuf, sizeof(namebuf));
if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err))
node = dp->child;
while (node != NULL) {
if (strcmp(node->name, "pci"))
goto next_pci;
err = prom_getproperty(node, "bus-range",
(char *)&busrange[0], sizeof(busrange));
if (err == 0 || err == -1) {
prom_printf("APB: Error, cannot get PCI bus-range.\n");
prom_halt();
}
prop = of_find_property(node, "model", NULL);
if (!prop || strncmp(prop->value, "SUNW,simba", prop->length))
goto next_pci;
simbas_found++;
prop = of_find_property(node, "bus-range", NULL);
busrange = prop->value;
if (busrange[0] == 1)
pbm = &p->pbm_B;
else
pbm = &p->pbm_A;
pbm->name = node->full_name;
printk("%s: SABRE PCI Bus Module\n", pbm->name);
pbm->chip_type = PBM_CHIP_TYPE_SABRE;
pbm->parent = p;
pbm->prom_node = node;
@ -1341,83 +1344,68 @@ static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dm
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
prom_getstring(node, "name", pbm->prom_name, sizeof(pbm->prom_name));
err = prom_getproperty(node, "ranges",
(char *)pbm->pbm_ranges,
sizeof(pbm->pbm_ranges));
if (err != -1)
prop = of_find_property(node, "ranges", &len);
if (prop) {
pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
(err / sizeof(struct linux_prom_pci_ranges));
else
(len / sizeof(struct linux_prom_pci_ranges));
} else {
pbm->num_pbm_ranges = 0;
}
err = prom_getproperty(node, "interrupt-map",
(char *)pbm->pbm_intmap,
sizeof(pbm->pbm_intmap));
if (err != -1) {
pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
err = prom_getproperty(node, "interrupt-map-mask",
(char *)&pbm->pbm_intmask,
sizeof(pbm->pbm_intmask));
if (err == -1) {
prom_printf("APB: Fatal error, no interrupt-map-mask.\n");
prom_halt();
}
prop = of_find_property(node, "interrupt-map", &len);
if (prop) {
pbm->pbm_intmap = prop->value;
pbm->num_pbm_intmap =
(len / sizeof(struct linux_prom_pci_intmap));
prop = of_find_property(node, "interrupt-map-mask",
NULL);
pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
pbm_register_toplevel_resources(p, pbm);
next_pci:
node = prom_getsibling(node);
if (!node)
break;
node = node->sibling;
}
if (simbas_found == 0) {
int err;
/* No APBs underneath, probably this is a hummingbird
* system.
*/
pbm = &p->pbm_A;
pbm->parent = p;
pbm->prom_node = sabre_node;
pbm->prom_node = dp;
pbm->pci_first_busno = p->pci_first_busno;
pbm->pci_last_busno = p->pci_last_busno;
prom_getstring(sabre_node, "name", pbm->prom_name, sizeof(pbm->prom_name));
err = prom_getproperty(sabre_node, "ranges",
(char *) pbm->pbm_ranges,
sizeof(pbm->pbm_ranges));
if (err != -1)
prop = of_find_property(dp, "ranges", &len);
if (prop) {
pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
(err / sizeof(struct linux_prom_pci_ranges));
else
pbm->num_pbm_ranges = 0;
err = prom_getproperty(sabre_node, "interrupt-map",
(char *) pbm->pbm_intmap,
sizeof(pbm->pbm_intmap));
if (err != -1) {
pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
err = prom_getproperty(sabre_node, "interrupt-map-mask",
(char *)&pbm->pbm_intmask,
sizeof(pbm->pbm_intmask));
if (err == -1) {
prom_printf("Hummingbird: Fatal error, no interrupt-map-mask.\n");
prom_halt();
}
(len / sizeof(struct linux_prom_pci_ranges));
} else {
pbm->num_pbm_intmap = 0;
memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
pbm->num_pbm_ranges = 0;
}
prop = of_find_property(dp, "interrupt-map", &len);
if (prop) {
pbm->pbm_intmap = prop->value;
pbm->num_pbm_intmap =
(len / sizeof(struct linux_prom_pci_intmap));
prop = of_find_property(dp, "interrupt-map-mask",
NULL);
pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
}
pbm->name = dp->full_name;
printk("%s: SABRE PCI Bus Module\n", pbm->name);
sprintf(pbm->name, "SABRE%d PBM%c", p->index,
(pbm == &p->pbm_A ? 'A' : 'B'));
pbm->io_space.name = pbm->mem_space.name = pbm->name;
/* Hack up top-level resources. */
@ -1443,14 +1431,15 @@ static void sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dm
}
}
void sabre_init(int pnode, char *model_name)
void sabre_init(struct device_node *dp, char *model_name)
{
struct linux_prom64_registers pr_regs[2];
struct linux_prom64_registers *pr_regs;
struct pci_controller_info *p;
struct pci_iommu *iommu;
int tsbsize, err;
u32 busrange[2];
u32 vdma[2];
struct property *prop;
int tsbsize;
u32 *busrange;
u32 *vdma;
u32 upa_portid, dma_mask;
u64 clear_irq;
@ -1458,22 +1447,21 @@ void sabre_init(int pnode, char *model_name)
if (!strcmp(model_name, "pci108e,a001"))
hummingbird_p = 1;
else if (!strcmp(model_name, "SUNW,sabre")) {
char compat[64];
prop = of_find_property(dp, "compatible", NULL);
if (prop) {
const char *compat = prop->value;
if (prom_getproperty(pnode, "compatible",
compat, sizeof(compat)) > 0 &&
!strcmp(compat, "pci108e,a001")) {
hummingbird_p = 1;
} else {
int cpu_node;
if (!strcmp(compat, "pci108e,a001"))
hummingbird_p = 1;
}
if (!hummingbird_p) {
struct device_node *dp;
/* Of course, Sun has to encode things a thousand
* different ways, inconsistently.
*/
cpu_find_by_instance(0, &cpu_node, NULL);
if (prom_getproperty(cpu_node, "name",
compat, sizeof(compat)) > 0 &&
!strcmp(compat, "SUNW,UltraSPARC-IIe"))
cpu_find_by_instance(0, &dp, NULL);
if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe"))
hummingbird_p = 1;
}
}
@ -1491,7 +1479,10 @@ void sabre_init(int pnode, char *model_name)
}
p->pbm_A.iommu = p->pbm_B.iommu = iommu;
upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff);
upa_portid = 0xff;
prop = of_find_property(dp, "upa-portid", NULL);
if (prop)
upa_portid = *(u32 *) prop->value;
p->next = pci_controller_root;
pci_controller_root = p;
@ -1509,13 +1500,9 @@ void sabre_init(int pnode, char *model_name)
/*
* Map in SABRE register set and report the presence of this SABRE.
*/
err = prom_getproperty(pnode, "reg",
(char *)&pr_regs[0], sizeof(pr_regs));
if(err == 0 || err == -1) {
prom_printf("SABRE: Error, cannot get U2P registers "
"from PROM.\n");
prom_halt();
}
prop = of_find_property(dp, "reg", NULL);
pr_regs = prop->value;
/*
* First REG in property is base of entire SABRE register space.
@ -1523,9 +1510,6 @@ void sabre_init(int pnode, char *model_name)
p->pbm_A.controller_regs = pr_regs[0].phys_addr;
p->pbm_B.controller_regs = pr_regs[0].phys_addr;
printk("PCI: Found SABRE, main regs at %016lx\n",
p->pbm_A.controller_regs);
/* Clear interrupts */
/* PCI first */
@ -1544,16 +1528,9 @@ void sabre_init(int pnode, char *model_name)
/* Now map in PCI config space for entire SABRE. */
p->pbm_A.config_space = p->pbm_B.config_space =
(p->pbm_A.controller_regs + SABRE_CONFIGSPACE);
printk("SABRE: Shared PCI config space at %016lx\n",
p->pbm_A.config_space);
err = prom_getproperty(pnode, "virtual-dma",
(char *)&vdma[0], sizeof(vdma));
if(err == 0 || err == -1) {
prom_printf("SABRE: Error, cannot get virtual-dma property "
"from PROM.\n");
prom_halt();
}
prop = of_find_property(dp, "virtual-dma", NULL);
vdma = prop->value;
dma_mask = vdma[0];
switch(vdma[1]) {
@ -1577,21 +1554,13 @@ void sabre_init(int pnode, char *model_name)
sabre_iommu_init(p, tsbsize, vdma[0], dma_mask);
printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]);
err = prom_getproperty(pnode, "bus-range",
(char *)&busrange[0], sizeof(busrange));
if(err == 0 || err == -1) {
prom_printf("SABRE: Error, cannot get PCI bus-range "
" from PROM.\n");
prom_halt();
}
prop = of_find_property(dp, "bus-range", NULL);
busrange = prop->value;
p->pci_first_busno = busrange[0];
p->pci_last_busno = busrange[1];
/*
* Look for APB underneath.
*/
sabre_pbm_init(p, pnode, vdma[0]);
sabre_pbm_init(p, dp, vdma[0]);
}

View File

@ -16,6 +16,7 @@
#include <asm/irq.h>
#include <asm/upa.h>
#include <asm/pstate.h>
#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
@ -1456,10 +1457,12 @@ static void __schizo_scan_bus(struct pci_controller_info *p,
pbm_config_busmastering(&p->pbm_B);
p->pbm_B.is_66mhz_capable =
prom_getbool(p->pbm_B.prom_node, "66mhz-capable");
(of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL)
!= NULL);
pbm_config_busmastering(&p->pbm_A);
p->pbm_A.is_66mhz_capable =
prom_getbool(p->pbm_A.prom_node, "66mhz-capable");
(of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL)
!= NULL);
pbm_scan_bus(p, &p->pbm_B);
pbm_scan_bus(p, &p->pbm_A);
@ -1661,13 +1664,18 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
{
struct pci_iommu *iommu = pbm->iommu;
unsigned long i, tagbase, database;
struct property *prop;
u32 vdma[2], dma_mask;
u64 control;
int err, tsbsize;
int tsbsize;
err = prom_getproperty(pbm->prom_node, "virtual-dma",
(char *)&vdma[0], sizeof(vdma));
if (err == 0 || err == -1) {
prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
if (prop) {
u32 *val = prop->value;
vdma[0] = val[0];
vdma[1] = val[1];
} else {
/* No property, use default values. */
vdma[0] = 0xc0000000;
vdma[1] = 0x40000000;
@ -1778,6 +1786,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
{
struct property *prop;
u64 tmp;
schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
@ -1791,7 +1800,8 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
pbm->chip_version >= 0x2)
tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
if (!prom_getbool(pbm->prom_node, "no-bus-parking"))
prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL);
if (!prop)
tmp |= SCHIZO_PCICTRL_PARK;
else
tmp &= ~SCHIZO_PCICTRL_PARK;
@ -1831,16 +1841,17 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
}
static void schizo_pbm_init(struct pci_controller_info *p,
int prom_node, u32 portid,
struct device_node *dp, u32 portid,
int chip_type)
{
struct linux_prom64_registers pr_regs[4];
unsigned int busrange[2];
struct linux_prom64_registers *regs;
struct property *prop;
unsigned int *busrange;
struct pci_pbm_info *pbm;
const char *chipset_name;
u32 ino_bitmap[2];
u32 *ino_bitmap;
int is_pbm_a;
int err;
int len;
switch (chip_type) {
case PBM_CHIP_TYPE_TOMATILLO:
@ -1868,16 +1879,10 @@ static void schizo_pbm_init(struct pci_controller_info *p,
* 3) PBM PCI config space
* 4) Ichip regs
*/
err = prom_getproperty(prom_node, "reg",
(char *)&pr_regs[0],
sizeof(pr_regs));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no reg property.\n",
chipset_name);
prom_halt();
}
prop = of_find_property(dp, "reg", NULL);
regs = prop->value;
is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000);
is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000);
if (is_pbm_a)
pbm = &p->pbm_A;
@ -1886,92 +1891,62 @@ static void schizo_pbm_init(struct pci_controller_info *p,
pbm->portid = portid;
pbm->parent = p;
pbm->prom_node = prom_node;
pbm->prom_node = dp;
pbm->pci_first_slot = 1;
pbm->chip_type = chip_type;
pbm->chip_version =
prom_getintdefault(prom_node, "version#", 0);
pbm->chip_revision =
prom_getintdefault(prom_node, "module-revision#", 0);
pbm->chip_version = 0;
prop = of_find_property(dp, "version#", NULL);
if (prop)
pbm->chip_version = *(int *) prop->value;
pbm->chip_revision = 0;
prop = of_find_property(dp, "module-revision#", NULL);
if (prop)
pbm->chip_revision = *(int *) prop->value;
pbm->pbm_regs = pr_regs[0].phys_addr;
pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
pbm->pbm_regs = regs[0].phys_addr;
pbm->controller_regs = regs[1].phys_addr - 0x10000UL;
if (chip_type == PBM_CHIP_TYPE_TOMATILLO)
pbm->sync_reg = pr_regs[3].phys_addr + 0x1a18UL;
pbm->sync_reg = regs[3].phys_addr + 0x1a18UL;
sprintf(pbm->name,
(chip_type == PBM_CHIP_TYPE_TOMATILLO ?
"TOMATILLO%d PBM%c" :
"SCHIZO%d PBM%c"),
p->index,
(pbm == &p->pbm_A ? 'A' : 'B'));
pbm->name = dp->full_name;
printk("%s: ver[%x:%x], portid %x, "
"cregs[%lx] pregs[%lx]\n",
printk("%s: %s PCI Bus Module ver[%x:%x]\n",
pbm->name,
pbm->chip_version, pbm->chip_revision,
pbm->portid,
pbm->controller_regs,
pbm->pbm_regs);
(chip_type == PBM_CHIP_TYPE_TOMATILLO ?
"TOMATILLO" : "SCHIZO"),
pbm->chip_version, pbm->chip_revision);
schizo_pbm_hw_init(pbm);
prom_getstring(prom_node, "name",
pbm->prom_name,
sizeof(pbm->prom_name));
err = prom_getproperty(prom_node, "ranges",
(char *) pbm->pbm_ranges,
sizeof(pbm->pbm_ranges));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no ranges property.\n",
pbm->name);
prom_halt();
}
prop = of_find_property(dp, "ranges", &len);
pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
(err / sizeof(struct linux_prom_pci_ranges));
(len / sizeof(struct linux_prom_pci_ranges));
schizo_determine_mem_io_space(pbm);
pbm_register_toplevel_resources(p, pbm);
err = prom_getproperty(prom_node, "interrupt-map",
(char *)pbm->pbm_intmap,
sizeof(pbm->pbm_intmap));
if (err != -1) {
pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
err = prom_getproperty(prom_node, "interrupt-map-mask",
(char *)&pbm->pbm_intmask,
sizeof(pbm->pbm_intmask));
if (err == -1) {
prom_printf("%s: Fatal error, no "
"interrupt-map-mask.\n", pbm->name);
prom_halt();
}
prop = of_find_property(dp, "interrupt-map", &len);
if (prop) {
pbm->pbm_intmap = prop->value;
pbm->num_pbm_intmap =
(len / sizeof(struct linux_prom_pci_intmap));
prop = of_find_property(dp, "interrupt-map-mask", NULL);
pbm->pbm_intmask = prop->value;
} else {
pbm->num_pbm_intmap = 0;
memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask));
}
err = prom_getproperty(prom_node, "ino-bitmap",
(char *) &ino_bitmap[0],
sizeof(ino_bitmap));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no ino-bitmap.\n", pbm->name);
prom_halt();
}
prop = of_find_property(dp, "ino-bitmap", NULL);
ino_bitmap = prop->value;
pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
((u64)ino_bitmap[0] << 0UL));
err = prom_getproperty(prom_node, "bus-range",
(char *)&busrange[0],
sizeof(busrange));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no bus-range.\n", pbm->name);
prom_halt();
}
prop = of_find_property(dp, "bus-range", NULL);
busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
@ -1989,16 +1964,20 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
return (x == y);
}
static void __schizo_init(int node, char *model_name, int chip_type)
static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
{
struct pci_controller_info *p;
struct pci_iommu *iommu;
struct property *prop;
int is_pbm_a;
u32 portid;
portid = prom_getintdefault(node, "portid", 0xff);
portid = 0xff;
prop = of_find_property(dp, "portid", NULL);
if (prop)
portid = *(u32 *) prop->value;
for(p = pci_controller_root; p; p = p->next) {
for (p = pci_controller_root; p; p = p->next) {
struct pci_pbm_info *pbm;
if (p->pbm_A.prom_node && p->pbm_B.prom_node)
@ -2009,8 +1988,8 @@ static void __schizo_init(int node, char *model_name, int chip_type)
&p->pbm_B);
if (portid_compare(pbm->portid, portid, chip_type)) {
is_pbm_a = (p->pbm_A.prom_node == 0);
schizo_pbm_init(p, node, portid, chip_type);
is_pbm_a = (p->pbm_A.prom_node == NULL);
schizo_pbm_init(p, dp, portid, chip_type);
return;
}
}
@ -2051,20 +2030,20 @@ static void __schizo_init(int node, char *model_name, int chip_type)
/* Like PSYCHO we have a 2GB aligned area for memory space. */
pci_memspace_mask = 0x7fffffffUL;
schizo_pbm_init(p, node, portid, chip_type);
schizo_pbm_init(p, dp, portid, chip_type);
}
void schizo_init(int node, char *model_name)
void schizo_init(struct device_node *dp, char *model_name)
{
__schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO);
__schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO);
}
void schizo_plus_init(int node, char *model_name)
void schizo_plus_init(struct device_node *dp, char *model_name)
{
__schizo_init(node, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
__schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
}
void tomatillo_init(int node, char *model_name)
void tomatillo_init(struct device_node *dp, char *model_name)
{
__schizo_init(node, model_name, PBM_CHIP_TYPE_TOMATILLO);
__schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO);
}

View File

@ -18,6 +18,7 @@
#include <asm/pstate.h>
#include <asm/oplib.h>
#include <asm/hypervisor.h>
#include <asm/prom.h>
#include "pci_impl.h"
#include "iommu_common.h"
@ -646,35 +647,37 @@ static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, u
/* Recursively descend into the OBP device tree, rooted at toplevel_node,
* looking for a PCI device matching bus and devfn.
*/
static int obp_find(struct linux_prom_pci_registers *pregs, int toplevel_node, unsigned int bus, unsigned int devfn)
static int obp_find(struct device_node *toplevel_node, unsigned int bus, unsigned int devfn)
{
toplevel_node = prom_getchild(toplevel_node);
toplevel_node = toplevel_node->child;
while (toplevel_node != 0) {
int ret = obp_find(pregs, toplevel_node, bus, devfn);
while (toplevel_node != NULL) {
struct linux_prom_pci_registers *regs;
struct property *prop;
int ret;
ret = obp_find(toplevel_node, bus, devfn);
if (ret != 0)
return ret;
ret = prom_getproperty(toplevel_node, "reg", (char *) pregs,
sizeof(*pregs) * PROMREG_MAX);
if (ret == 0 || ret == -1)
prop = of_find_property(toplevel_node, "reg", NULL);
if (!prop)
goto next_sibling;
if (((pregs[0].phys_hi >> 16) & 0xff) == bus &&
((pregs[0].phys_hi >> 8) & 0xff) == devfn)
regs = prop->value;
if (((regs->phys_hi >> 16) & 0xff) == bus &&
((regs->phys_hi >> 8) & 0xff) == devfn)
break;
next_sibling:
toplevel_node = prom_getsibling(toplevel_node);
toplevel_node = toplevel_node->sibling;
}
return toplevel_node;
return toplevel_node != NULL;
}
static int pdev_htab_populate(struct pci_pbm_info *pbm)
{
struct linux_prom_pci_registers pr[PROMREG_MAX];
u32 devhandle = pbm->devhandle;
unsigned int bus;
@ -685,7 +688,7 @@ static int pdev_htab_populate(struct pci_pbm_info *pbm)
unsigned int device = PCI_SLOT(devfn);
unsigned int func = PCI_FUNC(devfn);
if (obp_find(pr, pbm->prom_node, bus, devfn)) {
if (obp_find(pbm->prom_node, bus, devfn)) {
int err = pdev_htab_add(devhandle, bus,
device, func);
if (err)
@ -811,8 +814,7 @@ static void pbm_scan_bus(struct pci_controller_info *p,
pci_fixup_host_bridge_self(pbm->pci_bus);
pbm->pci_bus->self->sysdata = cookie;
#endif
pci_fill_in_pbm_cookies(pbm->pci_bus, pbm,
pbm->prom_node);
pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node);
pci_record_assignments(pbm, pbm->pci_bus);
pci_assign_unassigned(pbm, pbm->pci_bus);
pci_fixup_irq(pbm, pbm->pci_bus);
@ -822,15 +824,18 @@ static void pbm_scan_bus(struct pci_controller_info *p,
static void pci_sun4v_scan_bus(struct pci_controller_info *p)
{
if (p->pbm_A.prom_node) {
p->pbm_A.is_66mhz_capable =
prom_getbool(p->pbm_A.prom_node, "66mhz-capable");
struct property *prop;
struct device_node *dp;
if ((dp = p->pbm_A.prom_node) != NULL) {
prop = of_find_property(dp, "66mhz-capable", NULL);
p->pbm_A.is_66mhz_capable = (prop != NULL);
pbm_scan_bus(p, &p->pbm_A);
}
if (p->pbm_B.prom_node) {
p->pbm_B.is_66mhz_capable =
prom_getbool(p->pbm_B.prom_node, "66mhz-capable");
if ((dp = p->pbm_B.prom_node) != NULL) {
prop = of_find_property(dp, "66mhz-capable", NULL);
p->pbm_B.is_66mhz_capable = (prop != NULL);
pbm_scan_bus(p, &p->pbm_B);
}
@ -982,8 +987,13 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
HV_PCI_TSBID(0, i),
&io_attrs, &ra);
if (ret == HV_EOK) {
cnt++;
__set_bit(i, arena->map);
if (page_in_phys_avail(ra)) {
pci_sun4v_iommu_demap(devhandle,
HV_PCI_TSBID(0, i), 1);
} else {
cnt++;
__set_bit(i, arena->map);
}
}
}
@ -993,13 +1003,18 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm,
static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
{
struct pci_iommu *iommu = pbm->iommu;
struct property *prop;
unsigned long num_tsb_entries, sz;
u32 vdma[2], dma_mask, dma_offset;
int err, tsbsize;
int tsbsize;
err = prom_getproperty(pbm->prom_node, "virtual-dma",
(char *)&vdma[0], sizeof(vdma));
if (err == 0 || err == -1) {
prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
if (prop) {
u32 *val = prop->value;
vdma[0] = val[0];
vdma[1] = val[1];
} else {
/* No property, use default values. */
vdma[0] = 0x80000000;
vdma[1] = 0x80000000;
@ -1051,34 +1066,30 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
iommu->arena.limit = num_tsb_entries;
sz = probe_existing_entries(pbm, iommu);
printk("%s: TSB entries [%lu], existing mapings [%lu]\n",
pbm->name, num_tsb_entries, sz);
if (sz)
printk("%s: Imported %lu TSB entries from OBP\n",
pbm->name, sz);
}
static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm)
{
unsigned int busrange[2];
int prom_node = pbm->prom_node;
int err;
struct property *prop;
unsigned int *busrange;
err = prom_getproperty(prom_node, "bus-range",
(char *)&busrange[0],
sizeof(busrange));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no bus-range.\n", pbm->name);
prom_halt();
}
prop = of_find_property(pbm->prom_node, "bus-range", NULL);
busrange = prop->value;
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
}
static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 devhandle)
static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
{
struct pci_pbm_info *pbm;
int err, i;
struct property *prop;
int len, i;
if (devhandle & 0x40)
pbm = &p->pbm_B;
@ -1086,32 +1097,19 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32
pbm = &p->pbm_A;
pbm->parent = p;
pbm->prom_node = prom_node;
pbm->prom_node = dp;
pbm->pci_first_slot = 1;
pbm->devhandle = devhandle;
sprintf(pbm->name, "SUN4V-PCI%d PBM%c",
p->index, (pbm == &p->pbm_A ? 'A' : 'B'));
pbm->name = dp->full_name;
printk("%s: devhandle[%x] prom_node[%x:%x]\n",
pbm->name, pbm->devhandle,
pbm->prom_node, prom_getchild(pbm->prom_node));
prom_getstring(prom_node, "name",
pbm->prom_name, sizeof(pbm->prom_name));
err = prom_getproperty(prom_node, "ranges",
(char *) pbm->pbm_ranges,
sizeof(pbm->pbm_ranges));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no ranges property.\n",
pbm->name);
prom_halt();
}
printk("%s: SUN4V PCI Bus Module\n", pbm->name);
prop = of_find_property(dp, "ranges", &len);
pbm->pbm_ranges = prop->value;
pbm->num_pbm_ranges =
(err / sizeof(struct linux_prom_pci_ranges));
(len / sizeof(struct linux_prom_pci_ranges));
/* Mask out the top 8 bits of the ranges, leaving the real
* physical address.
@ -1122,24 +1120,13 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32
pci_sun4v_determine_mem_io_space(pbm);
pbm_register_toplevel_resources(p, pbm);
err = prom_getproperty(prom_node, "interrupt-map",
(char *)pbm->pbm_intmap,
sizeof(pbm->pbm_intmap));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no interrupt-map property.\n",
pbm->name);
prom_halt();
}
prop = of_find_property(dp, "interrupt-map", &len);
pbm->pbm_intmap = prop->value;
pbm->num_pbm_intmap =
(len / sizeof(struct linux_prom_pci_intmap));
pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap));
err = prom_getproperty(prom_node, "interrupt-map-mask",
(char *)&pbm->pbm_intmask,
sizeof(pbm->pbm_intmask));
if (err == 0 || err == -1) {
prom_printf("%s: Fatal error, no interrupt-map-mask.\n",
pbm->name);
prom_halt();
}
prop = of_find_property(dp, "interrupt-map-mask", NULL);
pbm->pbm_intmask = prop->value;
pci_sun4v_get_bus_range(pbm);
pci_sun4v_iommu_init(pbm);
@ -1147,16 +1134,19 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32
pdev_htab_populate(pbm);
}
void sun4v_pci_init(int node, char *model_name)
void sun4v_pci_init(struct device_node *dp, char *model_name)
{
struct pci_controller_info *p;
struct pci_iommu *iommu;
struct linux_prom64_registers regs;
struct property *prop;
struct linux_prom64_registers *regs;
u32 devhandle;
int i;
prom_getproperty(node, "reg", (char *)&regs, sizeof(regs));
devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff;
prop = of_find_property(dp, "reg", NULL);
regs = prop->value;
devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
for (p = pci_controller_root; p; p = p->next) {
struct pci_pbm_info *pbm;
@ -1169,7 +1159,7 @@ void sun4v_pci_init(int node, char *model_name)
&p->pbm_B);
if (pbm->devhandle == (devhandle ^ 0x40)) {
pci_sun4v_pbm_init(p, node, devhandle);
pci_sun4v_pbm_init(p, dp, devhandle);
return;
}
}
@ -1220,7 +1210,7 @@ void sun4v_pci_init(int node, char *model_name)
*/
pci_memspace_mask = 0x7fffffffUL;
pci_sun4v_pbm_init(p, node, devhandle);
pci_sun4v_pbm_init(p, dp, devhandle);
return;
fatal_memory_error:

View File

@ -105,76 +105,25 @@ again:
return 0;
}
static int __init has_button_interrupt(unsigned int irq, int prom_node)
static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
{
if (irq == PCI_IRQ_NONE)
return 0;
if (!prom_node_has_property(prom_node, "button"))
if (!of_find_property(dp, "button", NULL))
return 0;
return 1;
}
static int __init power_probe_ebus(struct resource **resp, unsigned int *irq_p, int *prom_node_p)
static void __devinit power_probe_common(struct of_device *dev, struct resource *res, unsigned int irq)
{
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "power")) {
*resp = &edev->resource[0];
*irq_p = edev->irqs[0];
*prom_node_p = edev->prom_node;
return 0;
}
}
}
return -ENODEV;
}
static int __init power_probe_isa(struct resource **resp, unsigned int *irq_p, int *prom_node_p)
{
struct sparc_isa_bridge *isa_bus;
struct sparc_isa_device *isa_dev;
for_each_isa(isa_bus) {
for_each_isadev(isa_dev, isa_bus) {
if (!strcmp(isa_dev->prom_name, "power")) {
*resp = &isa_dev->resource;
*irq_p = isa_dev->irq;
*prom_node_p = isa_dev->prom_node;
return 0;
}
}
}
return -ENODEV;
}
void __init power_init(void)
{
struct resource *res = NULL;
unsigned int irq;
int prom_node;
static int invoked;
if (invoked)
return;
invoked = 1;
if (!power_probe_ebus(&res, &irq, &prom_node))
goto found;
if (!power_probe_isa(&res, &irq, &prom_node))
goto found;
return;
found:
power_reg = ioremap(res->start, 0x4);
printk("power: Control reg at %p ... ", power_reg);
poweroff_method = machine_halt; /* able to use the standard halt */
if (has_button_interrupt(irq, prom_node)) {
if (has_button_interrupt(irq, dev->node)) {
if (kernel_thread(powerd, NULL, CLONE_FS) < 0) {
printk("Failed to start power daemon.\n");
return;
@ -188,4 +137,52 @@ found:
printk("not using powerd.\n");
}
}
static struct of_device_id power_match[] = {
{
.name = "power",
},
{},
};
static int __devinit ebus_power_probe(struct of_device *dev, const struct of_device_id *match)
{
struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
struct resource *res = &edev->resource[0];
unsigned int irq = edev->irqs[0];
power_probe_common(dev, res,irq);
return 0;
}
static struct of_platform_driver ebus_power_driver = {
.name = "power",
.match_table = power_match,
.probe = ebus_power_probe,
};
static int __devinit isa_power_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sparc_isa_device *idev = to_isa_device(&dev->dev);
struct resource *res = &idev->resource;
unsigned int irq = idev->irq;
power_probe_common(dev, res,irq);
return 0;
}
static struct of_platform_driver isa_power_driver = {
.name = "power",
.match_table = power_match,
.probe = isa_power_probe,
};
void __init power_init(void)
{
of_register_driver(&ebus_power_driver, &ebus_bus_type);
of_register_driver(&isa_power_driver, &isa_bus_type);
return;
}
#endif /* CONFIG_PCI */

650
arch/sparc64/kernel/prom.c Normal file
View File

@ -0,0 +1,650 @@
/*
* Procedures for creating, accessing and interpreting the device tree.
*
* Paul Mackerras August 1996.
* Copyright (C) 1996-2005 Paul Mackerras.
*
* Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
* {engebret|bergner}@us.ibm.com
*
* Adapted for sparc64 by David S. Miller davem@davemloft.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/module.h>
#include <asm/prom.h>
#include <asm/oplib.h>
static struct device_node *allnodes;
int of_device_is_compatible(struct device_node *device, const char *compat)
{
const char* cp;
int cplen, l;
cp = (char *) of_get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
if (strncmp(cp, compat, strlen(compat)) == 0)
return 1;
l = strlen(cp) + 1;
cp += l;
cplen -= l;
}
return 0;
}
EXPORT_SYMBOL(of_device_is_compatible);
struct device_node *of_get_parent(const struct device_node *node)
{
struct device_node *np;
if (!node)
return NULL;
np = node->parent;
return np;
}
EXPORT_SYMBOL(of_get_parent);
struct device_node *of_get_next_child(const struct device_node *node,
struct device_node *prev)
{
struct device_node *next;
next = prev ? prev->sibling : node->child;
for (; next != 0; next = next->sibling) {
break;
}
return next;
}
EXPORT_SYMBOL(of_get_next_child);
struct device_node *of_find_node_by_path(const char *path)
{
struct device_node *np = allnodes;
for (; np != 0; np = np->allnext) {
if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
break;
}
return np;
}
EXPORT_SYMBOL(of_find_node_by_path);
struct device_node *of_find_node_by_phandle(phandle handle)
{
struct device_node *np;
for (np = allnodes; np != 0; np = np->allnext)
if (np->node == handle)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_phandle);
struct device_node *of_find_node_by_name(struct device_node *from,
const char *name)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != NULL; np = np->allnext)
if (np->name != NULL && strcmp(np->name, name) == 0)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_name);
struct device_node *of_find_node_by_type(struct device_node *from,
const char *type)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != 0; np = np->allnext)
if (np->type != 0 && strcmp(np->type, type) == 0)
break;
return np;
}
EXPORT_SYMBOL(of_find_node_by_type);
struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compatible)
{
struct device_node *np;
np = from ? from->allnext : allnodes;
for (; np != 0; np = np->allnext) {
if (type != NULL
&& !(np->type != 0 && strcmp(np->type, type) == 0))
continue;
if (of_device_is_compatible(np, compatible))
break;
}
return np;
}
EXPORT_SYMBOL(of_find_compatible_node);
struct property *of_find_property(struct device_node *np, const char *name,
int *lenp)
{
struct property *pp;
for (pp = np->properties; pp != 0; pp = pp->next) {
if (strcmp(pp->name, name) == 0) {
if (lenp != 0)
*lenp = pp->length;
break;
}
}
return pp;
}
EXPORT_SYMBOL(of_find_property);
/*
* Find a property with a given name for a given node
* and return the value.
*/
void *of_get_property(struct device_node *np, const char *name, int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
}
EXPORT_SYMBOL(of_get_property);
int of_getintprop_default(struct device_node *np, const char *name, int def)
{
struct property *prop;
int len;
prop = of_find_property(np, name, &len);
if (!prop || len != 4)
return def;
return *(int *) prop->value;
}
EXPORT_SYMBOL(of_getintprop_default);
static unsigned int prom_early_allocated;
static void * __init prom_early_alloc(unsigned long size)
{
void *ret;
ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
if (ret != NULL)
memset(ret, 0, size);
prom_early_allocated += size;
return ret;
}
static int is_root_node(const struct device_node *dp)
{
if (!dp)
return 0;
return (dp->parent == NULL);
}
/* The following routines deal with the black magic of fully naming a
* node.
*
* Certain well known named nodes are just the simple name string.
*
* Actual devices have an address specifier appended to the base name
* string, like this "foo@addr". The "addr" can be in any number of
* formats, and the platform plus the type of the node determine the
* format and how it is constructed.
*
* For children of the ROOT node, the naming convention is fixed and
* determined by whether this is a sun4u or sun4v system.
*
* For children of other nodes, it is bus type specific. So
* we walk up the tree until we discover a "device_type" property
* we recognize and we go from there.
*
* As an example, the boot device on my workstation has a full path:
*
* /pci@1e,600000/ide@d/disk@0,0:c
*/
static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom64_registers *regs;
struct property *rprop;
u32 high_bits, low_bits, type;
rprop = of_find_property(dp, "reg", NULL);
if (!rprop)
return;
regs = rprop->value;
if (!is_root_node(dp->parent)) {
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
(unsigned int) (regs->phys_addr >> 32UL),
(unsigned int) (regs->phys_addr & 0xffffffffUL));
return;
}
type = regs->phys_addr >> 60UL;
high_bits = (regs->phys_addr >> 32UL) & 0x0fffffffUL;
low_bits = (regs->phys_addr & 0xffffffffUL);
if (type == 0 || type == 8) {
const char *prefix = (type == 0) ? "m" : "i";
if (low_bits)
sprintf(tmp_buf, "%s@%s%x,%x",
dp->name, prefix,
high_bits, low_bits);
else
sprintf(tmp_buf, "%s@%s%x",
dp->name,
prefix,
high_bits);
} else if (type == 12) {
sprintf(tmp_buf, "%s@%x",
dp->name, high_bits);
}
}
static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom64_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
if (!is_root_node(dp->parent)) {
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
(unsigned int) (regs->phys_addr >> 32UL),
(unsigned int) (regs->phys_addr & 0xffffffffUL));
return;
}
prop = of_find_property(dp, "upa-portid", NULL);
if (!prop)
prop = of_find_property(dp, "portid", NULL);
if (prop) {
unsigned long mask = 0xffffffffUL;
if (tlb_type >= cheetah)
mask = 0x7fffff;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
*(u32 *)prop->value,
(unsigned int) (regs->phys_addr & mask));
}
}
/* "name@slot,offset" */
static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
regs->which_io,
regs->phys_addr);
}
/* "name@devnum[,func]" */
static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom_pci_registers *regs;
struct property *prop;
unsigned int devfn;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
devfn = (regs->phys_hi >> 8) & 0xff;
if (devfn & 0x07) {
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
devfn >> 3,
devfn & 0x07);
} else {
sprintf(tmp_buf, "%s@%x",
dp->name,
devfn >> 3);
}
}
/* "name@UPA_PORTID,offset" */
static void __init upa_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom64_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
prop = of_find_property(dp, "upa-portid", NULL);
if (!prop)
return;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
*(u32 *) prop->value,
(unsigned int) (regs->phys_addr & 0xffffffffUL));
}
/* "name@reg" */
static void __init vdev_path_component(struct device_node *dp, char *tmp_buf)
{
struct property *prop;
u32 *regs;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
sprintf(tmp_buf, "%s@%x", dp->name, *regs);
}
/* "name@addrhi,addrlo" */
static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
{
struct linux_prom64_registers *regs;
struct property *prop;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
sprintf(tmp_buf, "%s@%x,%x",
dp->name,
(unsigned int) (regs->phys_addr >> 32UL),
(unsigned int) (regs->phys_addr & 0xffffffffUL));
}
/* "name@bus,addr" */
static void __init i2c_path_component(struct device_node *dp, char *tmp_buf)
{
struct property *prop;
u32 *regs;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
/* This actually isn't right... should look at the #address-cells
* property of the i2c bus node etc. etc.
*/
sprintf(tmp_buf, "%s@%x,%x",
dp->name, regs[0], regs[1]);
}
/* "name@reg0[,reg1]" */
static void __init usb_path_component(struct device_node *dp, char *tmp_buf)
{
struct property *prop;
u32 *regs;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
if (prop->length == sizeof(u32) || regs[1] == 1) {
sprintf(tmp_buf, "%s@%x",
dp->name, regs[0]);
} else {
sprintf(tmp_buf, "%s@%x,%x",
dp->name, regs[0], regs[1]);
}
}
/* "name@reg0reg1[,reg2reg3]" */
static void __init ieee1394_path_component(struct device_node *dp, char *tmp_buf)
{
struct property *prop;
u32 *regs;
prop = of_find_property(dp, "reg", NULL);
if (!prop)
return;
regs = prop->value;
if (regs[2] || regs[3]) {
sprintf(tmp_buf, "%s@%08x%08x,%04x%08x",
dp->name, regs[0], regs[1], regs[2], regs[3]);
} else {
sprintf(tmp_buf, "%s@%08x%08x",
dp->name, regs[0], regs[1]);
}
}
static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
{
struct device_node *parent = dp->parent;
if (parent != NULL) {
if (!strcmp(parent->type, "pci") ||
!strcmp(parent->type, "pciex"))
return pci_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "sbus"))
return sbus_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "upa"))
return upa_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "ebus"))
return ebus_path_component(dp, tmp_buf);
if (!strcmp(parent->name, "usb") ||
!strcmp(parent->name, "hub"))
return usb_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "i2c"))
return i2c_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "firewire"))
return ieee1394_path_component(dp, tmp_buf);
if (!strcmp(parent->type, "virtual-devices"))
return vdev_path_component(dp, tmp_buf);
/* "isa" is handled with platform naming */
}
/* Use platform naming convention. */
if (tlb_type == hypervisor)
return sun4v_path_component(dp, tmp_buf);
else
return sun4u_path_component(dp, tmp_buf);
}
static char * __init build_path_component(struct device_node *dp)
{
char tmp_buf[64], *n;
tmp_buf[0] = '\0';
__build_path_component(dp, tmp_buf);
if (tmp_buf[0] == '\0')
strcpy(tmp_buf, dp->name);
n = prom_early_alloc(strlen(tmp_buf) + 1);
strcpy(n, tmp_buf);
return n;
}
static char * __init build_full_name(struct device_node *dp)
{
int len, ourlen, plen;
char *n;
plen = strlen(dp->parent->full_name);
ourlen = strlen(dp->path_component_name);
len = ourlen + plen + 2;
n = prom_early_alloc(len);
strcpy(n, dp->parent->full_name);
if (!is_root_node(dp->parent)) {
strcpy(n + plen, "/");
plen++;
}
strcpy(n + plen, dp->path_component_name);
return n;
}
static struct property * __init build_one_prop(phandle node, char *prev)
{
static struct property *tmp = NULL;
struct property *p;
if (tmp) {
p = tmp;
memset(p, 0, sizeof(*p) + 32);
tmp = NULL;
} else
p = prom_early_alloc(sizeof(struct property) + 32);
p->name = (char *) (p + 1);
if (prev == NULL) {
prom_firstprop(node, p->name);
} else {
prom_nextprop(node, prev, p->name);
}
if (strlen(p->name) == 0) {
tmp = p;
return NULL;
}
p->length = prom_getproplen(node, p->name);
if (p->length <= 0) {
p->length = 0;
} else {
p->value = prom_early_alloc(p->length);
prom_getproperty(node, p->name, p->value, p->length);
}
return p;
}
static struct property * __init build_prop_list(phandle node)
{
struct property *head, *tail;
head = tail = build_one_prop(node, NULL);
while(tail) {
tail->next = build_one_prop(node, tail->name);
tail = tail->next;
}
return head;
}
static char * __init get_one_property(phandle node, const char *name)
{
char *buf = "<NULL>";
int len;
len = prom_getproplen(node, name);
if (len > 0) {
buf = prom_early_alloc(len);
prom_getproperty(node, name, buf, len);
}
return buf;
}
static struct device_node * __init create_node(phandle node)
{
struct device_node *dp;
if (!node)
return NULL;
dp = prom_early_alloc(sizeof(*dp));
kref_init(&dp->kref);
dp->name = get_one_property(node, "name");
dp->type = get_one_property(node, "device_type");
dp->node = node;
/* Build interrupts later... */
dp->properties = build_prop_list(node);
return dp;
}
static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
{
struct device_node *dp;
dp = create_node(node);
if (dp) {
*(*nextp) = dp;
*nextp = &dp->allnext;
dp->parent = parent;
dp->path_component_name = build_path_component(dp);
dp->full_name = build_full_name(dp);
dp->child = build_tree(dp, prom_getchild(node), nextp);
dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
}
return dp;
}
void __init prom_build_devicetree(void)
{
struct device_node **nextp;
allnodes = create_node(prom_root_node);
allnodes->path_component_name = "";
allnodes->full_name = "/";
nextp = &allnodes->allnext;
allnodes->child = build_tree(allnodes,
prom_getchild(allnodes->node),
&nextp);
printk("PROM: Built device tree with %u bytes of memory.\n",
prom_early_allocated);
}

View File

@ -19,6 +19,7 @@
#include <asm/cache.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/starfire.h>
#include "iommu_common.h"
@ -1098,24 +1099,25 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
}
/* Boot time initialization. */
void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus)
static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
{
struct linux_prom64_registers rprop;
struct linux_prom64_registers *pr;
struct device_node *dp;
struct sbus_iommu *iommu;
unsigned long regs, tsb_base;
u64 control;
int err, i;
int i;
sbus->portid = prom_getintdefault(sbus->prom_node,
"upa-portid", -1);
dp = of_find_node_by_phandle(__node);
err = prom_getproperty(prom_node, "reg",
(char *)&rprop, sizeof(rprop));
if (err < 0) {
sbus->portid = of_getintprop_default(dp, "upa-portid", -1);
pr = of_get_property(dp, "reg", NULL);
if (!pr) {
prom_printf("sbus_iommu_init: Cannot map SYSIO control registers.\n");
prom_halt();
}
regs = rprop.phys_addr;
regs = pr->phys_addr;
iommu = kmalloc(sizeof(*iommu) + SMP_CACHE_BYTES, GFP_ATOMIC);
if (iommu == NULL) {
@ -1225,3 +1227,50 @@ void __init sbus_iommu_init(int prom_node, struct sbus_bus *sbus)
sysio_register_error_handlers(sbus);
}
void sbus_fill_device_irq(struct sbus_dev *sdev)
{
struct device_node *dp = of_find_node_by_phandle(sdev->prom_node);
struct linux_prom_irqs *irqs;
irqs = of_get_property(dp, "interrupts", NULL);
if (!irqs) {
sdev->irqs[0] = 0;
sdev->num_irqs = 0;
} else {
unsigned int pri = irqs[0].pri;
sdev->num_irqs = 1;
if (pri < 0x20)
pri += sdev->slot * 8;
sdev->irqs[0] = sbus_build_irq(sdev->bus, pri);
}
}
void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
{
}
void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
{
sbus_iommu_init(dp->node, sbus);
}
void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
{
}
int __init sbus_arch_preinit(void)
{
return 0;
}
void __init sbus_arch_postinit(void)
{
extern void firetruck_init(void);
extern void clock_probe(void);
firetruck_init();
clock_probe();
}

View File

@ -376,12 +376,12 @@ void __init setup_arch(char **cmdline_p)
}
#endif
smp_setup_cpu_possible_map();
/* Get boot processor trap_block[] setup. */
init_cur_cpu_trap(current_thread_info());
paging_init();
smp_setup_cpu_possible_map();
}
static int __init set_preferred_console(void)

View File

@ -39,6 +39,7 @@
#include <asm/starfire.h>
#include <asm/tlb.h>
#include <asm/sections.h>
#include <asm/prom.h>
extern void calibrate_delay(void);
@ -76,41 +77,42 @@ void smp_bogo(struct seq_file *m)
void __init smp_store_cpu_info(int id)
{
int cpu_node, def;
struct device_node *dp;
int def;
/* multiplier and counter set by
smp_setup_percpu_timer() */
cpu_data(id).udelay_val = loops_per_jiffy;
cpu_find_by_mid(id, &cpu_node);
cpu_data(id).clock_tick = prom_getintdefault(cpu_node,
"clock-frequency", 0);
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 = prom_getintdefault(cpu_node, "dcache-size",
def);
cpu_data(id).dcache_size =
of_getintprop_default(dp, "dcache-size", def);
def = 32;
cpu_data(id).dcache_line_size =
prom_getintdefault(cpu_node, "dcache-line-size", def);
of_getintprop_default(dp, "dcache-line-size", def);
def = 16 * 1024;
cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size",
def);
cpu_data(id).icache_size =
of_getintprop_default(dp, "icache-size", def);
def = 32;
cpu_data(id).icache_line_size =
prom_getintdefault(cpu_node, "icache-line-size", def);
of_getintprop_default(dp, "icache-line-size", def);
def = ((tlb_type == hypervisor) ?
(3 * 1024 * 1024) :
(4 * 1024 * 1024));
cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size",
def);
cpu_data(id).ecache_size =
of_getintprop_default(dp, "ecache-size", def);
def = 64;
cpu_data(id).ecache_line_size =
prom_getintdefault(cpu_node, "ecache-line-size", def);
of_getintprop_default(dp, "ecache-line-size", def);
printk("CPU[%d]: Caches "
"D[sz(%d):line_sz(%d)] "
@ -342,10 +344,10 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
prom_startcpu_cpuid(cpu, entry, cookie);
} else {
int cpu_node;
struct device_node *dp;
cpu_find_by_mid(cpu, &cpu_node);
prom_startcpu(cpu_node, entry, cookie);
cpu_find_by_mid(cpu, &dp);
prom_startcpu(dp->node, entry, cookie);
}
for (timeout = 0; timeout < 5000000; timeout++) {
@ -1289,7 +1291,8 @@ int setup_profiling_timer(unsigned int multiplier)
static void __init smp_tune_scheduling(void)
{
int instance, node;
struct device_node *dp;
int instance;
unsigned int def, smallest = ~0U;
def = ((tlb_type == hypervisor) ?
@ -1297,10 +1300,10 @@ static void __init smp_tune_scheduling(void)
(4 * 1024 * 1024));
instance = 0;
while (!cpu_find_by_instance(instance, &node, NULL)) {
while (!cpu_find_by_instance(instance, &dp, NULL)) {
unsigned int val;
val = prom_getintdefault(node, "ecache-size", def);
val = of_getintprop_default(dp, "ecache-size", def);
if (val < smallest)
smallest = val;

View File

@ -48,6 +48,7 @@
#include <asm/sections.h>
#include <asm/cpudata.h>
#include <asm/uaccess.h>
#include <asm/prom.h>
DEFINE_SPINLOCK(mostek_lock);
DEFINE_SPINLOCK(rtc_lock);
@ -755,24 +756,200 @@ retry:
return -EOPNOTSUPP;
}
static int __init clock_model_matches(char *model)
{
if (strcmp(model, "mk48t02") &&
strcmp(model, "mk48t08") &&
strcmp(model, "mk48t59") &&
strcmp(model, "m5819") &&
strcmp(model, "m5819p") &&
strcmp(model, "m5823") &&
strcmp(model, "ds1287"))
return 0;
return 1;
}
static void __init __clock_assign_common(void __iomem *addr, char *model)
{
if (model[5] == '0' && model[6] == '2') {
mstk48t02_regs = addr;
} else if(model[5] == '0' && model[6] == '8') {
mstk48t08_regs = addr;
mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
} else {
mstk48t59_regs = addr;
mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
}
static void __init clock_assign_clk_reg(struct linux_prom_registers *clk_reg,
char *model)
{
unsigned long addr;
addr = ((unsigned long) clk_reg[0].phys_addr |
(((unsigned long) clk_reg[0].which_io) << 32UL));
__clock_assign_common((void __iomem *) addr, model);
}
static int __init clock_probe_central(void)
{
struct linux_prom_registers clk_reg[2], *pr;
struct device_node *dp;
char *model;
if (!central_bus)
return 0;
/* Get Central FHC's prom node. */
dp = central_bus->child->prom_node;
/* Then get the first child device below it. */
dp = dp->child;
while (dp) {
model = of_get_property(dp, "model", NULL);
if (!model || !clock_model_matches(model))
goto next_sibling;
pr = of_get_property(dp, "reg", NULL);
memcpy(clk_reg, pr, sizeof(clk_reg));
apply_fhc_ranges(central_bus->child, clk_reg, 1);
apply_central_ranges(central_bus, clk_reg, 1);
clock_assign_clk_reg(clk_reg, model);
return 1;
next_sibling:
dp = dp->sibling;
}
return 0;
}
#ifdef CONFIG_PCI
static void __init clock_isa_ebus_assign_regs(struct resource *res, char *model)
{
if (!strcmp(model, "ds1287") ||
!strcmp(model, "m5819") ||
!strcmp(model, "m5819p") ||
!strcmp(model, "m5823")) {
ds1287_regs = res->start;
} else {
mstk48t59_regs = (void __iomem *) res->start;
mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
}
static int __init clock_probe_one_ebus_dev(struct linux_ebus_device *edev)
{
struct device_node *dp = edev->prom_node;
char *model;
model = of_get_property(dp, "model", NULL);
if (!clock_model_matches(model))
return 0;
clock_isa_ebus_assign_regs(&edev->resource[0], model);
return 1;
}
static int __init clock_probe_ebus(void)
{
struct linux_ebus *ebus;
for_each_ebus(ebus) {
struct linux_ebus_device *edev;
for_each_ebusdev(edev, ebus) {
if (clock_probe_one_ebus_dev(edev))
return 1;
}
}
return 0;
}
static int __init clock_probe_one_isa_dev(struct sparc_isa_device *idev)
{
struct device_node *dp = idev->prom_node;
char *model;
model = of_get_property(dp, "model", NULL);
if (!clock_model_matches(model))
return 0;
clock_isa_ebus_assign_regs(&idev->resource, model);
return 1;
}
static int __init clock_probe_isa(void)
{
struct sparc_isa_bridge *isa_br;
for_each_isa(isa_br) {
struct sparc_isa_device *isa_dev;
for_each_isadev(isa_dev, isa_br) {
if (clock_probe_one_isa_dev(isa_dev))
return 1;
}
}
return 0;
}
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
static int __init clock_probe_one_sbus_dev(struct sbus_bus *sbus, struct sbus_dev *sdev)
{
struct resource *res;
char model[64];
void __iomem *addr;
prom_getstring(sdev->prom_node, "model", model, sizeof(model));
if (!clock_model_matches(model))
return 0;
res = &sdev->resource[0];
addr = sbus_ioremap(res, 0, 0x800UL, "eeprom");
__clock_assign_common(addr, model);
return 1;
}
static int __init clock_probe_sbus(void)
{
struct sbus_bus *sbus;
for_each_sbus(sbus) {
struct sbus_dev *sdev;
for_each_sbusdev(sdev, sbus) {
if (clock_probe_one_sbus_dev(sbus, sdev))
return 1;
}
}
return 0;
}
#endif
void __init clock_probe(void)
{
struct linux_prom_registers clk_reg[2];
char model[128];
int node, busnd = -1, err;
unsigned long flags;
struct linux_central *cbus;
#ifdef CONFIG_PCI
struct linux_ebus *ebus = NULL;
struct sparc_isa_bridge *isa_br = NULL;
#endif
static int invoked;
unsigned long flags;
if (invoked)
return;
invoked = 1;
if (this_is_starfire) {
xtime.tv_sec = starfire_get_time();
xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
@ -788,182 +965,26 @@ void __init clock_probe(void)
return;
}
local_irq_save(flags);
cbus = central_bus;
if (cbus != NULL)
busnd = central_bus->child->prom_node;
/* Check FHC Central then EBUSs then ISA bridges then SBUSs.
* That way we handle the presence of multiple properly.
*
* As a special case, machines with Central must provide the
* timer chip there.
*/
if (!clock_probe_central() &&
#ifdef CONFIG_PCI
if (ebus_chain != NULL) {
ebus = ebus_chain;
if (busnd == -1)
busnd = ebus->prom_node;
}
if (isa_chain != NULL) {
isa_br = isa_chain;
if (busnd == -1)
busnd = isa_br->prom_node;
}
!clock_probe_ebus() &&
!clock_probe_isa() &&
#endif
if (sbus_root != NULL && busnd == -1)
busnd = sbus_root->prom_node;
if (busnd == -1) {
prom_printf("clock_probe: problem, cannot find bus to search.\n");
prom_halt();
#ifdef CONFIG_SBUS
!clock_probe_sbus()
#endif
) {
printk(KERN_WARNING "No clock chip found.\n");
return;
}
node = prom_getchild(busnd);
while (1) {
if (!node)
model[0] = 0;
else
prom_getstring(node, "model", model, sizeof(model));
if (strcmp(model, "mk48t02") &&
strcmp(model, "mk48t08") &&
strcmp(model, "mk48t59") &&
strcmp(model, "m5819") &&
strcmp(model, "m5819p") &&
strcmp(model, "m5823") &&
strcmp(model, "ds1287")) {
if (cbus != NULL) {
prom_printf("clock_probe: Central bus lacks timer chip.\n");
prom_halt();
}
if (node != 0)
node = prom_getsibling(node);
#ifdef CONFIG_PCI
while ((node == 0) && ebus != NULL) {
ebus = ebus->next;
if (ebus != NULL) {
busnd = ebus->prom_node;
node = prom_getchild(busnd);
}
}
while ((node == 0) && isa_br != NULL) {
isa_br = isa_br->next;
if (isa_br != NULL) {
busnd = isa_br->prom_node;
node = prom_getchild(busnd);
}
}
#endif
if (node == 0) {
prom_printf("clock_probe: Cannot find timer chip\n");
prom_halt();
}
continue;
}
err = prom_getproperty(node, "reg", (char *)clk_reg,
sizeof(clk_reg));
if(err == -1) {
prom_printf("clock_probe: Cannot get Mostek reg property\n");
prom_halt();
}
if (cbus != NULL) {
apply_fhc_ranges(central_bus->child, clk_reg, 1);
apply_central_ranges(central_bus, clk_reg, 1);
}
#ifdef CONFIG_PCI
else if (ebus != NULL) {
struct linux_ebus_device *edev;
for_each_ebusdev(edev, ebus)
if (edev->prom_node == node)
break;
if (edev == NULL) {
if (isa_chain != NULL)
goto try_isa_clock;
prom_printf("%s: Mostek not probed by EBUS\n",
__FUNCTION__);
prom_halt();
}
if (!strcmp(model, "ds1287") ||
!strcmp(model, "m5819") ||
!strcmp(model, "m5819p") ||
!strcmp(model, "m5823")) {
ds1287_regs = edev->resource[0].start;
} else {
mstk48t59_regs = (void __iomem *)
edev->resource[0].start;
mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
break;
}
else if (isa_br != NULL) {
struct sparc_isa_device *isadev;
try_isa_clock:
for_each_isadev(isadev, isa_br)
if (isadev->prom_node == node)
break;
if (isadev == NULL) {
prom_printf("%s: Mostek not probed by ISA\n");
prom_halt();
}
if (!strcmp(model, "ds1287") ||
!strcmp(model, "m5819") ||
!strcmp(model, "m5819p") ||
!strcmp(model, "m5823")) {
ds1287_regs = isadev->resource.start;
} else {
mstk48t59_regs = (void __iomem *)
isadev->resource.start;
mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
break;
}
#endif
else {
if (sbus_root->num_sbus_ranges) {
int nranges = sbus_root->num_sbus_ranges;
int rngc;
for (rngc = 0; rngc < nranges; rngc++)
if (clk_reg[0].which_io ==
sbus_root->sbus_ranges[rngc].ot_child_space)
break;
if (rngc == nranges) {
prom_printf("clock_probe: Cannot find ranges for "
"clock regs.\n");
prom_halt();
}
clk_reg[0].which_io =
sbus_root->sbus_ranges[rngc].ot_parent_space;
clk_reg[0].phys_addr +=
sbus_root->sbus_ranges[rngc].ot_parent_base;
}
}
if(model[5] == '0' && model[6] == '2') {
mstk48t02_regs = (void __iomem *)
(((u64)clk_reg[0].phys_addr) |
(((u64)clk_reg[0].which_io)<<32UL));
} else if(model[5] == '0' && model[6] == '8') {
mstk48t08_regs = (void __iomem *)
(((u64)clk_reg[0].phys_addr) |
(((u64)clk_reg[0].which_io)<<32UL));
mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
} else {
mstk48t59_regs = (void __iomem *)
(((u64)clk_reg[0].phys_addr) |
(((u64)clk_reg[0].which_io)<<32UL));
mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
}
break;
}
local_irq_save(flags);
if (mstk48t02_regs != NULL) {
/* Report a low battery voltage condition. */
@ -983,12 +1004,14 @@ try_isa_clock:
/* This is gets the master TICK_INT timer going. */
static unsigned long sparc64_init_timers(void)
{
struct device_node *dp;
struct property *prop;
unsigned long clock;
int node;
#ifdef CONFIG_SMP
extern void smp_tick_init(void);
#endif
dp = of_find_node_by_path("/");
if (tlb_type == spitfire) {
unsigned long ver, manuf, impl;
@ -999,18 +1022,17 @@ static unsigned long sparc64_init_timers(void)
if (manuf == 0x17 && impl == 0x13) {
/* Hummingbird, aka Ultra-IIe */
tick_ops = &hbtick_operations;
node = prom_root_node;
clock = prom_getint(node, "stick-frequency");
prop = of_find_property(dp, "stick-frequency", NULL);
} else {
tick_ops = &tick_operations;
cpu_find_by_instance(0, &node, NULL);
clock = prom_getint(node, "clock-frequency");
cpu_find_by_instance(0, &dp, NULL);
prop = of_find_property(dp, "clock-frequency", NULL);
}
} else {
tick_ops = &stick_operations;
node = prom_root_node;
clock = prom_getint(node, "stick-frequency");
prop = of_find_property(dp, "stick-frequency", NULL);
}
clock = *(unsigned int *) prop->value;
timer_tick_offset = clock / HZ;
#ifdef CONFIG_SMP

View File

@ -42,6 +42,7 @@
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
#include <asm/prom.h>
ATOMIC_NOTIFIER_HEAD(sparc64die_chain);
@ -807,7 +808,8 @@ extern unsigned int cheetah_deferred_trap_vector[], cheetah_deferred_trap_vector
void __init cheetah_ecache_flush_init(void)
{
unsigned long largest_size, smallest_linesize, order, ver;
int node, i, instance;
struct device_node *dp;
int i, instance, sz;
/* Scan all cpu device tree nodes, note two values:
* 1) largest E-cache size
@ -817,14 +819,14 @@ void __init cheetah_ecache_flush_init(void)
smallest_linesize = ~0UL;
instance = 0;
while (!cpu_find_by_instance(instance, &node, NULL)) {
while (!cpu_find_by_instance(instance, &dp, NULL)) {
unsigned long val;
val = prom_getintdefault(node, "ecache-size",
(2 * 1024 * 1024));
val = of_getintprop_default(dp, "ecache-size",
(2 * 1024 * 1024));
if (val > largest_size)
largest_size = val;
val = prom_getintdefault(node, "ecache-line-size", 64);
val = of_getintprop_default(dp, "ecache-line-size", 64);
if (val < smallest_linesize)
smallest_linesize = val;
instance++;
@ -849,16 +851,16 @@ void __init cheetah_ecache_flush_init(void)
}
/* Now allocate error trap reporting scoreboard. */
node = NR_CPUS * (2 * sizeof(struct cheetah_err_info));
sz = NR_CPUS * (2 * sizeof(struct cheetah_err_info));
for (order = 0; order < MAX_ORDER; order++) {
if ((PAGE_SIZE << order) >= node)
if ((PAGE_SIZE << order) >= sz)
break;
}
cheetah_error_log = (struct cheetah_err_info *)
__get_free_pages(GFP_KERNEL, order);
if (!cheetah_error_log) {
prom_printf("cheetah_ecache_flush_init: Failed to allocate "
"error logging scoreboard (%d bytes).\n", node);
"error logging scoreboard (%d bytes).\n", sz);
prom_halt();
}
memset(cheetah_error_log, 0, PAGE_SIZE << order);

View File

@ -279,12 +279,21 @@ static void kernel_mna_trap_fault(void)
asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
{
static unsigned long count, last_time;
enum direction dir = decode_direction(insn);
int size = decode_access_size(insn);
current_thread_info()->kern_una_regs = regs;
current_thread_info()->kern_una_insn = insn;
if (jiffies - last_time > 5 * HZ)
count = 0;
if (count < 5) {
last_time = jiffies;
count++;
printk("Kernel unaligned access at TPC[%lx]\n", regs->tpc);
}
if (!ok_for_kernel(insn) || dir == both) {
printk("Unsupported unaligned load/store trap for kernel "
"at <%016lx>.\n", regs->tpc);

View File

@ -42,6 +42,7 @@
#include <asm/sections.h>
#include <asm/tsb.h>
#include <asm/hypervisor.h>
#include <asm/prom.h>
extern void device_scan(void);
@ -101,8 +102,6 @@ static void __init read_obp_memory(const char *property,
prom_halt();
}
*num_ents = ents;
/* Sanitize what we got from the firmware, by page aligning
* everything.
*/
@ -124,6 +123,25 @@ static void __init read_obp_memory(const char *property,
regs[i].phys_addr = base;
regs[i].reg_size = size;
}
for (i = 0; i < ents; i++) {
if (regs[i].reg_size == 0UL) {
int j;
for (j = i; j < ents - 1; j++) {
regs[j].phys_addr =
regs[j+1].phys_addr;
regs[j].reg_size =
regs[j+1].reg_size;
}
ents--;
i--;
}
}
*num_ents = ents;
sort(regs, ents, sizeof(struct linux_prom64_registers),
cmp_p64, NULL);
}
@ -1339,6 +1357,8 @@ void __init paging_init(void)
kernel_physical_mapping_init();
prom_build_devicetree();
{
unsigned long zones_size[MAX_NR_ZONES];
unsigned long zholes_size[MAX_NR_ZONES];
@ -1376,7 +1396,7 @@ static void __init taint_real_pages(void)
while (old_start < old_end) {
int n;
for (n = 0; pavail_rescan_ents; n++) {
for (n = 0; n < pavail_rescan_ents; n++) {
unsigned long new_start, new_end;
new_start = pavail_rescan[n].phys_addr;
@ -1398,6 +1418,32 @@ static void __init taint_real_pages(void)
}
}
int __init page_in_phys_avail(unsigned long paddr)
{
int i;
paddr &= PAGE_MASK;
for (i = 0; i < pavail_rescan_ents; i++) {
unsigned long start, end;
start = pavail_rescan[i].phys_addr;
end = start + pavail_rescan[i].reg_size;
if (paddr >= start && paddr < end)
return 1;
}
if (paddr >= kern_base && paddr < (kern_base + kern_size))
return 1;
#ifdef CONFIG_BLK_DEV_INITRD
if (paddr >= __pa(initrd_start) &&
paddr < __pa(PAGE_ALIGN(initrd_end)))
return 1;
#endif
return 0;
}
void __init mem_init(void)
{
unsigned long codepages, datapages, initpages;

View File

@ -23,6 +23,7 @@
#include <asm/oplib.h>
#include <asm/idprom.h>
#include <asm/smp.h>
#include <asm/prom.h>
#include "conv.h"
@ -194,14 +195,17 @@ static char *machine(void)
}
}
static char *platform(char *buffer)
static char *platform(char *buffer, int sz)
{
struct device_node *dp = of_find_node_by_path("/");
int len;
*buffer = 0;
len = prom_getproperty(prom_root_node, "name", buffer, 256);
if(len > 0)
buffer[len] = 0;
len = strlen(dp->name);
if (len > sz)
len = sz;
memcpy(buffer, dp->name, len);
buffer[len] = 0;
if (*buffer) {
char *p;
@ -213,16 +217,22 @@ static char *platform(char *buffer)
return "sun4u";
}
static char *serial(char *buffer)
static char *serial(char *buffer, int sz)
{
int node = prom_getchild(prom_root_node);
struct device_node *dp = of_find_node_by_path("/options");
int len;
node = prom_searchsiblings(node, "options");
*buffer = 0;
len = prom_getproperty(node, "system-board-serial#", buffer, 256);
if(len > 0)
buffer[len] = 0;
if (dp) {
char *val = of_get_property(dp, "system-board-serial#", &len);
if (val && len > 0) {
if (len > sz)
len = sz;
memcpy(buffer, val, len);
buffer[len] = 0;
}
}
if (!*buffer)
return "4512348717234";
else
@ -305,8 +315,8 @@ asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count)
case SI_MACHINE: r = machine(); break;
case SI_ARCHITECTURE: r = "sparc"; break;
case SI_HW_PROVIDER: r = "Sun_Microsystems"; break;
case SI_HW_SERIAL: r = serial(buffer); break;
case SI_PLATFORM: r = platform(buffer); break;
case SI_HW_SERIAL: r = serial(buffer, sizeof(buffer)); break;
case SI_PLATFORM: r = platform(buffer, sizeof(buffer)); break;
case SI_SRPC_DOMAIN: r = ""; break;
case SI_VERSION: r = "Generic"; break;
default: return -EINVAL;

View File

@ -1,5 +1,6 @@
obj-y := shutdown.o
obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o
obj-$(CONFIG_PM_TRACE) += trace.o
ifeq ($(CONFIG_DEBUG_DRIVER),y)
EXTRA_CFLAGS += -DDEBUG

View File

@ -9,6 +9,7 @@
*/
#include <linux/device.h>
#include <linux/resume-trace.h>
#include "../base.h"
#include "power.h"
@ -23,6 +24,8 @@ int resume_device(struct device * dev)
{
int error = 0;
TRACE_DEVICE(dev);
TRACE_RESUME(0);
down(&dev->sem);
if (dev->power.pm_parent
&& dev->power.pm_parent->power.power_state.event) {
@ -36,6 +39,7 @@ int resume_device(struct device * dev)
error = dev->bus->resume(dev);
}
up(&dev->sem);
TRACE_RESUME(error);
return error;
}

228
drivers/base/power/trace.c Normal file
View File

@ -0,0 +1,228 @@
/*
* drivers/base/power/trace.c
*
* Copyright (C) 2006 Linus Torvalds
*
* Trace facility for suspend/resume problems, when none of the
* devices may be working.
*/
#include <linux/resume-trace.h>
#include <linux/rtc.h>
#include <asm/rtc.h>
#include "power.h"
/*
* Horrid, horrid, horrid.
*
* It turns out that the _only_ piece of hardware that actually
* keeps its value across a hard boot (and, more importantly, the
* POST init sequence) is literally the realtime clock.
*
* Never mind that an RTC chip has 114 bytes (and often a whole
* other bank of an additional 128 bytes) of nice SRAM that is
* _designed_ to keep data - the POST will clear it. So we literally
* can just use the few bytes of actual time data, which means that
* we're really limited.
*
* It means, for example, that we can't use the seconds at all
* (since the time between the hang and the boot might be more
* than a minute), and we'd better not depend on the low bits of
* the minutes either.
*
* There are the wday fields etc, but I wouldn't guarantee those
* are dependable either. And if the date isn't valid, either the
* hw or POST will do strange things.
*
* So we're left with:
* - year: 0-99
* - month: 0-11
* - day-of-month: 1-28
* - hour: 0-23
* - min: (0-30)*2
*
* Giving us a total range of 0-16128000 (0xf61800), ie less
* than 24 bits of actual data we can save across reboots.
*
* And if your box can't boot in less than three minutes,
* you're screwed.
*
* Now, almost 24 bits of data is pitifully small, so we need
* to be pretty dense if we want to use it for anything nice.
* What we do is that instead of saving off nice readable info,
* we save off _hashes_ of information that we can hopefully
* regenerate after the reboot.
*
* In particular, this means that we might be unlucky, and hit
* a case where we have a hash collision, and we end up not
* being able to tell for certain exactly which case happened.
* But that's hopefully unlikely.
*
* What we do is to take the bits we can fit, and split them
* into three parts (16*997*1009 = 16095568), and use the values
* for:
* - 0-15: user-settable
* - 0-996: file + line number
* - 0-1008: device
*/
#define USERHASH (16)
#define FILEHASH (997)
#define DEVHASH (1009)
#define DEVSEED (7919)
static unsigned int dev_hash_value;
static int set_magic_time(unsigned int user, unsigned int file, unsigned int device)
{
unsigned int n = user + USERHASH*(file + FILEHASH*device);
// June 7th, 2006
static struct rtc_time time = {
.tm_sec = 0,
.tm_min = 0,
.tm_hour = 0,
.tm_mday = 7,
.tm_mon = 5, // June - counting from zero
.tm_year = 106,
.tm_wday = 3,
.tm_yday = 160,
.tm_isdst = 1
};
time.tm_year = (n % 100);
n /= 100;
time.tm_mon = (n % 12);
n /= 12;
time.tm_mday = (n % 28) + 1;
n /= 28;
time.tm_hour = (n % 24);
n /= 24;
time.tm_min = (n % 20) * 3;
n /= 20;
set_rtc_time(&time);
return n ? -1 : 0;
}
static unsigned int read_magic_time(void)
{
struct rtc_time time;
unsigned int val;
get_rtc_time(&time);
printk("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n",
time.tm_hour, time.tm_min, time.tm_sec,
time.tm_mon, time.tm_mday, time.tm_year);
val = time.tm_year; /* 100 years */
if (val > 100)
val -= 100;
val += time.tm_mon * 100; /* 12 months */
val += (time.tm_mday-1) * 100 * 12; /* 28 month-days */
val += time.tm_hour * 100 * 12 * 28; /* 24 hours */
val += (time.tm_min / 3) * 100 * 12 * 28 * 24; /* 20 3-minute intervals */
return val;
}
/*
* This is just the sdbm hash function with a user-supplied
* seed and final size parameter.
*/
static unsigned int hash_string(unsigned int seed, const char *data, unsigned int mod)
{
unsigned char c;
while ((c = *data++) != 0) {
seed = (seed << 16) + (seed << 6) - seed + c;
}
return seed % mod;
}
void set_trace_device(struct device *dev)
{
dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH);
}
/*
* We could just take the "tracedata" index into the .tracedata
* section instead. Generating a hash of the data gives us a
* chance to work across kernel versions, and perhaps more
* importantly it also gives us valid/invalid check (ie we will
* likely not give totally bogus reports - if the hash matches,
* it's not any guarantee, but it's a high _likelihood_ that
* the match is valid).
*/
void generate_resume_trace(void *tracedata, unsigned int user)
{
unsigned short lineno = *(unsigned short *)tracedata;
const char *file = *(const char **)(tracedata + 2);
unsigned int user_hash_value, file_hash_value;
user_hash_value = user % USERHASH;
file_hash_value = hash_string(lineno, file, FILEHASH);
set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
}
extern char __tracedata_start, __tracedata_end;
static int show_file_hash(unsigned int value)
{
int match;
char *tracedata;
match = 0;
for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; tracedata += 6) {
unsigned short lineno = *(unsigned short *)tracedata;
const char *file = *(const char **)(tracedata + 2);
unsigned int hash = hash_string(lineno, file, FILEHASH);
if (hash != value)
continue;
printk(" hash matches %s:%u\n", file, lineno);
match++;
}
return match;
}
static int show_dev_hash(unsigned int value)
{
int match = 0;
struct list_head * entry = dpm_active.prev;
while (entry != &dpm_active) {
struct device * dev = to_device(entry);
unsigned int hash = hash_string(DEVSEED, dev->bus_id, DEVHASH);
if (hash == value) {
printk(" hash matches device %s\n", dev->bus_id);
match++;
}
entry = entry->prev;
}
return match;
}
static unsigned int hash_value_early_read;
static int early_resume_init(void)
{
hash_value_early_read = read_magic_time();
return 0;
}
static int late_resume_init(void)
{
unsigned int val = hash_value_early_read;
unsigned int user, file, dev;
user = val % USERHASH;
val = val / USERHASH;
file = val % FILEHASH;
val = val / FILEHASH;
dev = val /* % DEVHASH */;
printk(" Magic number: %d:%d:%d\n", user, file, dev);
show_file_hash(file);
show_dev_hash(dev);
return 0;
}
core_initcall(early_resume_init);
late_initcall(late_resume_init);

View File

@ -758,7 +758,9 @@ drm_ioctl_desc_t i915_ioctls[] = {
[DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }
[DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
[DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
[DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH },
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);

View File

@ -124,6 +124,8 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_INIT_HEAP 0x0a
#define DRM_I915_CMDBUFFER 0x0b
#define DRM_I915_DESTROY_HEAP 0x0c
#define DRM_I915_SET_VBLANK_PIPE 0x0d
#define DRM_I915_GET_VBLANK_PIPE 0x0e
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@ -138,6 +140,8 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t)
#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t)
#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@ -224,4 +228,13 @@ typedef struct drm_i915_mem_destroy_heap {
int region;
} drm_i915_mem_destroy_heap_t;
/* Allow X server to configure which pipes to monitor for vblank signals
*/
#define DRM_I915_VBLANK_PIPE_A 1
#define DRM_I915_VBLANK_PIPE_B 2
typedef struct drm_i915_vblank_pipe {
int pipe;
} drm_i915_vblank_pipe_t;
#endif /* _I915_DRM_H_ */

View File

@ -45,9 +45,10 @@
* 1.2: Add Power Management
* 1.3: Add vblank support
* 1.4: Fix cmdbuffer path, add heap destroy
* 1.5: Add vblank pipe configuration
*/
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 4
#define DRIVER_MINOR 5
#define DRIVER_PATCHLEVEL 0
typedef struct _drm_i915_ring_buffer {
@ -96,6 +97,7 @@ typedef struct drm_i915_private {
int allow_batchbuffer;
struct mem_block *agp_heap;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
int vblank_pipe;
} drm_i915_private_t;
extern drm_ioctl_desc_t i915_ioctls[];
@ -119,6 +121,8 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(drm_device_t * dev);
extern void i915_driver_irq_postinstall(drm_device_t * dev);
extern void i915_driver_irq_uninstall(drm_device_t * dev);
extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
/* i915_mem.c */
extern int i915_mem_alloc(DRM_IOCTL_ARGS);

View File

@ -44,7 +44,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
u16 temp;
temp = I915_READ16(I915REG_INT_IDENTITY_R);
temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG);
temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
@ -58,7 +59,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
if (temp & USER_INT_FLAG)
DRM_WAKEUP(&dev_priv->irq_queue);
if (temp & VSYNC_PIPEA_FLAG) {
if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
drm_vbl_send_signals(dev);
@ -182,6 +183,68 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
return i915_wait_irq(dev, irqwait.irq_seq);
}
static int i915_enable_interrupt (drm_device_t *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u16 flag;
flag = 0;
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
flag |= VSYNC_PIPEA_FLAG;
if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
flag |= VSYNC_PIPEB_FLAG;
if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
DRM_ERROR("%s called with invalid pipe 0x%x\n",
__FUNCTION__, dev_priv->vblank_pipe);
return DRM_ERR(EINVAL);
}
I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
return 0;
}
/* Set the vblank monitor pipe
*/
int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_vblank_pipe_t pipe;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data,
sizeof(pipe));
dev_priv->vblank_pipe = pipe.pipe;
return i915_enable_interrupt (dev);
}
int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_vblank_pipe_t pipe;
u16 flag;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
flag = I915_READ(I915REG_INT_ENABLE_R);
pipe.pipe = 0;
if (flag & VSYNC_PIPEA_FLAG)
pipe.pipe |= DRM_I915_VBLANK_PIPE_A;
if (flag & VSYNC_PIPEB_FLAG)
pipe.pipe |= DRM_I915_VBLANK_PIPE_B;
DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_pipe_t __user *) data, pipe,
sizeof(pipe));
return 0;
}
/* drm_dma.h hooks
*/
void i915_driver_irq_preinstall(drm_device_t * dev)
@ -197,7 +260,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | VSYNC_PIPEA_FLAG);
i915_enable_interrupt(dev);
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
}

View File

@ -39,7 +39,7 @@
static int radeon_do_cleanup_cp(drm_device_t * dev);
/* CP microcode (from ATI) */
static u32 R200_cp_microcode[][2] = {
static const u32 R200_cp_microcode[][2] = {
{0x21007000, 0000000000},
{0x20007000, 0000000000},
{0x000000ab, 0x00000004},
@ -298,7 +298,7 @@ static u32 R200_cp_microcode[][2] = {
{0000000000, 0000000000},
};
static u32 radeon_cp_microcode[][2] = {
static const u32 radeon_cp_microcode[][2] = {
{0x21007000, 0000000000},
{0x20007000, 0000000000},
{0x000000b4, 0x00000004},
@ -557,7 +557,7 @@ static u32 radeon_cp_microcode[][2] = {
{0000000000, 0000000000},
};
static u32 R300_cp_microcode[][2] = {
static const u32 R300_cp_microcode[][2] = {
{0x4200e000, 0000000000},
{0x4000e000, 0000000000},
{0x000000af, 0x00000008},

View File

@ -161,7 +161,8 @@
#define R200_EMIT_PP_TXCTLALL_3 91
#define R200_EMIT_PP_TXCTLALL_4 92
#define R200_EMIT_PP_TXCTLALL_5 93
#define RADEON_MAX_STATE_PACKETS 94
#define R200_EMIT_VAP_PVS_CNTL 94
#define RADEON_MAX_STATE_PACKETS 95
/* Commands understood by cmd_buffer ioctl. More can be added but
* obviously these can't be removed or changed:
@ -176,6 +177,7 @@
#define RADEON_CMD_WAIT 8 /* emit hw wait commands -- note:
* doesn't make the cpu wait, just
* the graphics hardware */
#define RADEON_CMD_VECLINEAR 9 /* another r200 stopgap */
typedef union {
int i;
@ -191,6 +193,9 @@ typedef union {
struct {
unsigned char cmd_type, offset, stride, count;
} vectors;
struct {
unsigned char cmd_type, addr_lo, addr_hi, count;
} veclinear;
struct {
unsigned char cmd_type, buf_idx, pad0, pad1;
} dma;

View File

@ -38,7 +38,7 @@
#define DRIVER_NAME "radeon"
#define DRIVER_DESC "ATI Radeon"
#define DRIVER_DATE "20060225"
#define DRIVER_DATE "20060524"
/* Interface history:
*
@ -93,9 +93,11 @@
* 1.22- Add support for texture cache flushes (R300_TX_CNTL)
* 1.23- Add new radeon memory map work from benh
* 1.24- Add general-purpose packet for manipulating scratch registers (r300)
* 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL,
* new packet type)
*/
#define DRIVER_MAJOR 1
#define DRIVER_MINOR 24
#define DRIVER_MINOR 25
#define DRIVER_PATCHLEVEL 0
/*
@ -884,6 +886,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
#define RADEON_PP_CUBIC_OFFSET_T1_0 0x1e00
#define RADEON_PP_CUBIC_OFFSET_T2_0 0x1e14
#define RADEON_SE_TCL_STATE_FLUSH 0x2284
#define SE_VAP_CNTL__TCL_ENA_MASK 0x00000001
#define SE_VAP_CNTL__FORCE_W_TO_ONE_MASK 0x00010000
#define SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT 0x00000012
@ -905,6 +909,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
#define R200_PP_AFS_0 0x2f80
#define R200_PP_AFS_1 0x2f00 /* same as txcblend_0 */
#define R200_VAP_PVS_CNTL_1 0x22D0
/* Constants */
#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */

View File

@ -249,6 +249,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
case R200_EMIT_PP_TXCTLALL_3:
case R200_EMIT_PP_TXCTLALL_4:
case R200_EMIT_PP_TXCTLALL_5:
case R200_EMIT_VAP_PVS_CNTL:
/* These packets don't contain memory offsets */
break;
@ -626,6 +627,7 @@ static struct {
{R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
{R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
{R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
{R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"},
};
/* ================================================================
@ -2595,7 +2597,8 @@ static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
int stride = header.vectors.stride;
RING_LOCALS;
BEGIN_RING(3 + sz);
BEGIN_RING(5 + sz);
OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
@ -2607,6 +2610,32 @@ static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
return 0;
}
static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
drm_radeon_cmd_header_t header,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
int sz = header.veclinear.count * 4;
int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8);
RING_LOCALS;
if (!sz)
return 0;
if (sz * 4 > cmdbuf->bufsz)
return DRM_ERR(EINVAL);
BEGIN_RING(5 + sz);
OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
OUT_RING_TABLE(cmdbuf->buf, sz);
ADVANCE_RING();
cmdbuf->buf += sz * sizeof(int);
cmdbuf->bufsz -= sz * sizeof(int);
return 0;
}
static int radeon_emit_packet3(drm_device_t * dev,
drm_file_t * filp_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
@ -2865,6 +2894,14 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
goto err;
}
break;
case RADEON_CMD_VECLINEAR:
DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) {
DRM_ERROR("radeon_emit_veclinear failed\n");
goto err;
}
break;
default:
DRM_ERROR("bad cmd_type %d at %p\n",
header.header.cmd_type,

View File

@ -928,7 +928,7 @@ static int __init rtc_init(void)
#ifdef __sparc__
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if(strcmp(edev->prom_name, "rtc") == 0) {
if(strcmp(edev->prom_node->name, "rtc") == 0) {
rtc_port = edev->resource[0].start;
rtc_irq = edev->irqs[0];
goto found;
@ -938,7 +938,7 @@ static int __init rtc_init(void)
#ifdef __sparc_v9__
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
if (strcmp(isa_dev->prom_name, "rtc") == 0) {
if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
rtc_port = isa_dev->resource.start;
rtc_irq = isa_dev->irq;
goto found;

View File

@ -26,7 +26,7 @@ config INPUT_PCSPKR
config INPUT_SPARCSPKR
tristate "SPARC Speaker support"
depends on PCI && SPARC
depends on PCI && SPARC64
help
Say Y here if you want the standard Speaker on Sparc PCI systems
to be used for bells and whistles.

View File

@ -2,7 +2,7 @@
* Driver for PC-speaker like devices found on various Sparc systems.
*
* Copyright (c) 2002 Vojtech Pavlik
* Copyright (c) 2002 David S. Miller (davem@redhat.com)
* Copyright (c) 2002, 2006 David S. Miller (davem@davemloft.net)
*/
#include <linux/config.h>
#include <linux/kernel.h>
@ -13,21 +13,23 @@
#include <asm/io.h>
#include <asm/ebus.h>
#ifdef CONFIG_SPARC64
#include <asm/isa.h>
#endif
MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_DESCRIPTION("Sparc Speaker beeper driver");
MODULE_LICENSE("GPL");
const char *beep_name;
static unsigned long beep_iobase;
static int (*beep_event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
static DEFINE_SPINLOCK(beep_lock);
struct sparcspkr_state {
const char *name;
unsigned long iobase;
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
spinlock_t lock;
struct input_dev *input_dev;
};
static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
unsigned int count = 0;
unsigned long flags;
@ -43,24 +45,24 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in
if (value > 20 && value < 32767)
count = 1193182 / value;
spin_lock_irqsave(&beep_lock, flags);
spin_lock_irqsave(&state->lock, flags);
/* EBUS speaker only has on/off state, the frequency does not
* appear to be programmable.
*/
if (beep_iobase & 0x2UL)
outb(!!count, beep_iobase);
if (state->iobase & 0x2UL)
outb(!!count, state->iobase);
else
outl(!!count, beep_iobase);
outl(!!count, state->iobase);
spin_unlock_irqrestore(&beep_lock, flags);
spin_unlock_irqrestore(&state->lock, flags);
return 0;
}
#ifdef CONFIG_SPARC64
static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
unsigned int count = 0;
unsigned long flags;
@ -76,29 +78,29 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int
if (value > 20 && value < 32767)
count = 1193182 / value;
spin_lock_irqsave(&beep_lock, flags);
spin_lock_irqsave(&state->lock, flags);
if (count) {
/* enable counter 2 */
outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61);
outb(inb(state->iobase + 0x61) | 3, state->iobase + 0x61);
/* set command for counter 2, 2 byte write */
outb(0xB6, beep_iobase + 0x43);
outb(0xB6, state->iobase + 0x43);
/* select desired HZ */
outb(count & 0xff, beep_iobase + 0x42);
outb((count >> 8) & 0xff, beep_iobase + 0x42);
outb(count & 0xff, state->iobase + 0x42);
outb((count >> 8) & 0xff, state->iobase + 0x42);
} else {
/* disable counter 2 */
outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61);
outb(inb_p(state->iobase + 0x61) & 0xFC, state->iobase + 0x61);
}
spin_unlock_irqrestore(&beep_lock, flags);
spin_unlock_irqrestore(&state->lock, flags);
return 0;
}
#endif
static int __devinit sparcspkr_probe(struct platform_device *dev)
static int __devinit sparcspkr_probe(struct device *dev)
{
struct sparcspkr_state *state = dev_get_drvdata(dev);
struct input_dev *input_dev;
int error;
@ -106,18 +108,18 @@ static int __devinit sparcspkr_probe(struct platform_device *dev)
if (!input_dev)
return -ENOMEM;
input_dev->name = beep_name;
input_dev->name = state->name;
input_dev->phys = "sparc/input0";
input_dev->id.bustype = BUS_ISA;
input_dev->id.vendor = 0x001f;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
input_dev->cdev.dev = &dev->dev;
input_dev->cdev.dev = dev;
input_dev->evbit[0] = BIT(EV_SND);
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
input_dev->event = beep_event;
input_dev->event = state->event;
error = input_register_device(input_dev);
if (error) {
@ -125,111 +127,137 @@ static int __devinit sparcspkr_probe(struct platform_device *dev)
return error;
}
platform_set_drvdata(dev, input_dev);
state->input_dev = input_dev;
return 0;
}
static int __devexit sparcspkr_remove(struct platform_device *dev)
static int __devexit sparcspkr_remove(struct of_device *dev)
{
struct input_dev *input_dev = platform_get_drvdata(dev);
struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
struct input_dev *input_dev = state->input_dev;
/* turn off the speaker */
state->event(input_dev, EV_SND, SND_BELL, 0);
input_unregister_device(input_dev);
platform_set_drvdata(dev, NULL);
/* turn off the speaker */
beep_event(NULL, EV_SND, SND_BELL, 0);
dev_set_drvdata(&dev->dev, NULL);
kfree(state);
return 0;
}
static void sparcspkr_shutdown(struct platform_device *dev)
static int sparcspkr_shutdown(struct of_device *dev)
{
struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
struct input_dev *input_dev = state->input_dev;
/* turn off the speaker */
beep_event(NULL, EV_SND, SND_BELL, 0);
state->event(input_dev, EV_SND, SND_BELL, 0);
return 0;
}
static struct platform_driver sparcspkr_platform_driver = {
.driver = {
.name = "sparcspkr",
.owner = THIS_MODULE,
static int __devinit ebus_beep_probe(struct of_device *dev, const struct of_device_id *match)
{
struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
struct sparcspkr_state *state;
int err;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
state->name = "Sparc EBUS Speaker";
state->iobase = edev->resource[0].start;
state->event = ebus_spkr_event;
spin_lock_init(&state->lock);
dev_set_drvdata(&dev->dev, state);
err = sparcspkr_probe(&dev->dev);
if (err) {
dev_set_drvdata(&dev->dev, NULL);
kfree(state);
}
return 0;
}
static struct of_device_id ebus_beep_match[] = {
{
.name = "beep",
},
.probe = sparcspkr_probe,
.remove = __devexit_p(sparcspkr_remove),
{},
};
static struct of_platform_driver ebus_beep_driver = {
.name = "beep",
.match_table = ebus_beep_match,
.probe = ebus_beep_probe,
.remove = sparcspkr_remove,
.shutdown = sparcspkr_shutdown,
};
static struct platform_device *sparcspkr_platform_device;
static int __init sparcspkr_drv_init(void)
static int __devinit isa_beep_probe(struct of_device *dev, const struct of_device_id *match)
{
int error;
struct sparc_isa_device *idev = to_isa_device(&dev->dev);
struct sparcspkr_state *state;
int err;
error = platform_driver_register(&sparcspkr_platform_driver);
if (error)
return error;
state = kzalloc(sizeof(*state), GFP_KERNEL);
if (!state)
return -ENOMEM;
sparcspkr_platform_device = platform_device_alloc("sparcspkr", -1);
if (!sparcspkr_platform_device) {
error = -ENOMEM;
goto err_unregister_driver;
state->name = "Sparc ISA Speaker";
state->iobase = idev->resource.start;
state->event = isa_spkr_event;
spin_lock_init(&state->lock);
dev_set_drvdata(&dev->dev, state);
err = sparcspkr_probe(&dev->dev);
if (err) {
dev_set_drvdata(&dev->dev, NULL);
kfree(state);
}
error = platform_device_add(sparcspkr_platform_device);
if (error)
goto err_free_device;
return 0;
err_free_device:
platform_device_put(sparcspkr_platform_device);
err_unregister_driver:
platform_driver_unregister(&sparcspkr_platform_driver);
return error;
}
static struct of_device_id isa_beep_match[] = {
{
.name = "dma",
},
{},
};
static struct of_platform_driver isa_beep_driver = {
.name = "beep",
.match_table = isa_beep_match,
.probe = isa_beep_probe,
.remove = sparcspkr_remove,
.shutdown = sparcspkr_shutdown,
};
static int __init sparcspkr_init(void)
{
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
#ifdef CONFIG_SPARC64
struct sparc_isa_bridge *isa_br;
struct sparc_isa_device *isa_dev;
#endif
int err = of_register_driver(&ebus_beep_driver, &ebus_bus_type);
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "beep")) {
beep_name = "Sparc EBUS Speaker";
beep_event = ebus_spkr_event;
beep_iobase = edev->resource[0].start;
return sparcspkr_drv_init();
}
}
if (!err) {
err = of_register_driver(&isa_beep_driver, &isa_bus_type);
if (err)
of_unregister_driver(&ebus_beep_driver);
}
#ifdef CONFIG_SPARC64
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
/* A hack, the beep device's base lives in
* the DMA isa node.
*/
if (!strcmp(isa_dev->prom_name, "dma")) {
beep_name = "Sparc ISA Speaker";
beep_event = isa_spkr_event,
beep_iobase = isa_dev->resource.start;
return sparcspkr_drv_init();
}
}
}
#endif
return -ENODEV;
return err;
}
static void __exit sparcspkr_exit(void)
{
platform_device_unregister(sparcspkr_platform_device);
platform_driver_unregister(&sparcspkr_platform_driver);
of_unregister_driver(&ebus_beep_driver);
of_unregister_driver(&isa_beep_driver);
}
module_init(sparcspkr_init);

View File

@ -74,7 +74,7 @@ static int __init i8042_platform_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "8042"))
if (!strcmp(edev->prom_node->name, "8042"))
goto edev_found;
}
}
@ -82,14 +82,14 @@ static int __init i8042_platform_init(void)
edev_found:
for_each_edevchild(edev, child) {
if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) ||
!strcmp(child->prom_name, OBP_PS2KBD_NAME2)) {
if (!strcmp(child->prom_node->name, OBP_PS2KBD_NAME1) ||
!strcmp(child->prom_node->name, OBP_PS2KBD_NAME2)) {
i8042_kbd_irq = child->irqs[0];
kbd_iobase =
ioremap(child->resource[0].start, 8);
}
if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) ||
!strcmp(child->prom_name, OBP_PS2MS_NAME2))
if (!strcmp(child->prom_node->name, OBP_PS2MS_NAME1) ||
!strcmp(child->prom_node->name, OBP_PS2MS_NAME2))
i8042_aux_irq = child->irqs[0];
}
if (i8042_kbd_irq == -1 ||

View File

@ -1,10 +1,10 @@
/* myri_sbus.h: MyriCOM MyriNET SBUS card driver.
/* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
*
* Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
* Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
*/
static char version[] =
"myri_sbus.c:v1.9 12/Sep/99 David S. Miller (davem@redhat.com)\n";
"myri_sbus.c:v2.0 June 23, 2006 David S. Miller (davem@davemloft.net)\n";
#include <linux/module.h>
#include <linux/config.h>
@ -81,10 +81,6 @@ static char version[] =
#define DHDR(x)
#endif
#ifdef MODULE
static struct myri_eth *root_myri_dev;
#endif
static void myri_reset_off(void __iomem *lp, void __iomem *cregs)
{
/* Clear IRQ mask. */
@ -896,8 +892,9 @@ static void dump_eeprom(struct myri_eth *mp)
}
#endif
static int __init myri_ether_init(struct sbus_dev *sdev, int num)
static int __init myri_ether_init(struct sbus_dev *sdev)
{
static int num;
static unsigned version_printed;
struct net_device *dev;
struct myri_eth *mp;
@ -913,6 +910,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
if (version_printed++ == 0)
printk(version);
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
mp = (struct myri_eth *) dev->priv;
spin_lock_init(&mp->irq_lock);
mp->myri_sdev = sdev;
@ -1092,10 +1092,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
goto err_free_irq;
}
#ifdef MODULE
mp->next_module = root_myri_dev;
root_myri_dev = mp;
#endif
dev_set_drvdata(&sdev->ofdev.dev, mp);
num++;
printk("%s: MyriCOM MyriNET Ethernet ", dev->name);
@ -1114,61 +1113,68 @@ err:
return -ENODEV;
}
static int __init myri_sbus_match(struct sbus_dev *sdev)
{
char *name = sdev->prom_name;
if (!strcmp(name, "MYRICOM,mlanai") ||
!strcmp(name, "myri"))
return 1;
static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
return myri_ether_init(sdev);
}
static int __devexit myri_sbus_remove(struct of_device *dev)
{
struct myri_eth *mp = dev_get_drvdata(&dev->dev);
struct net_device *net_dev = mp->dev;
unregister_netdevice(net_dev);
free_irq(net_dev->irq, net_dev);
if (mp->eeprom.cpuvers < CPUVERS_4_0) {
sbus_iounmap(mp->regs, mp->reg_size);
} else {
sbus_iounmap(mp->cregs, PAGE_SIZE);
sbus_iounmap(mp->lregs, (256 * 1024));
sbus_iounmap(mp->lanai, (512 * 1024));
}
free_netdev(net_dev);
dev_set_drvdata(&dev->dev, NULL);
return 0;
}
static int __init myri_sbus_probe(void)
static struct of_device_id myri_sbus_match[] = {
{
.name = "MYRICOM,mlanai",
},
{
.name = "myri",
},
{},
};
MODULE_DEVICE_TABLE(of, myri_sbus_match);
static struct of_platform_driver myri_sbus_driver = {
.name = "myri",
.match_table = myri_sbus_match,
.probe = myri_sbus_probe,
.remove = __devexit_p(myri_sbus_remove),
};
static int __init myri_sbus_init(void)
{
struct sbus_bus *bus;
struct sbus_dev *sdev = NULL;
static int called;
int cards = 0, v;
#ifdef MODULE
root_myri_dev = NULL;
#endif
if (called)
return -ENODEV;
called++;
for_each_sbus(bus) {
for_each_sbusdev(sdev, bus) {
if (myri_sbus_match(sdev)) {
cards++;
DET(("Found myricom myrinet as %s\n", sdev->prom_name));
if ((v = myri_ether_init(sdev, (cards - 1))))
return v;
}
}
}
if (!cards)
return -ENODEV;
return 0;
return of_register_driver(&myri_sbus_driver, &sbus_bus_type);
}
static void __exit myri_sbus_cleanup(void)
static void __exit myri_sbus_exit(void)
{
#ifdef MODULE
while (root_myri_dev) {
struct myri_eth *next = root_myri_dev->next_module;
unregister_netdev(root_myri_dev->dev);
/* this will also free the co-allocated 'root_myri_dev' */
free_netdev(root_myri_dev->dev);
root_myri_dev = next;
}
#endif /* MODULE */
of_unregister_driver(&myri_sbus_driver);
}
module_init(myri_sbus_probe);
module_exit(myri_sbus_cleanup);
module_init(myri_sbus_init);
module_exit(myri_sbus_exit);
MODULE_LICENSE("GPL");

View File

@ -290,7 +290,6 @@ struct myri_eth {
unsigned int reg_size; /* Size of register space. */
unsigned int shmem_base; /* Offset to shared ram. */
struct sbus_dev *myri_sdev; /* Our SBUS device struct. */
struct myri_eth *next_module; /* Next in adapter chain. */
};
/* We use this to acquire receive skb's that we can DMA directly into. */

View File

@ -72,8 +72,6 @@ MODULE_LICENSE("GPL");
#define DIRQ(x)
#endif
static struct bigmac *root_bigmac_dev;
#define DEFAULT_JAMSIZE 4 /* Toe jam */
#define QEC_RESET_TRIES 200
@ -491,7 +489,7 @@ static void bigmac_tcvr_init(struct bigmac *bp)
}
}
static int bigmac_init(struct bigmac *, int);
static int bigmac_init_hw(struct bigmac *, int);
static int try_next_permutation(struct bigmac *bp, void __iomem *tregs)
{
@ -551,7 +549,7 @@ static void bigmac_timer(unsigned long data)
if (ret == -1) {
printk(KERN_ERR "%s: Link down, cable problem?\n",
bp->dev->name);
ret = bigmac_init(bp, 0);
ret = bigmac_init_hw(bp, 0);
if (ret) {
printk(KERN_ERR "%s: Error, cannot re-init the "
"BigMAC.\n", bp->dev->name);
@ -621,7 +619,7 @@ static void bigmac_begin_auto_negotiation(struct bigmac *bp)
add_timer(&bp->bigmac_timer);
}
static int bigmac_init(struct bigmac *bp, int from_irq)
static int bigmac_init_hw(struct bigmac *bp, int from_irq)
{
void __iomem *gregs = bp->gregs;
void __iomem *cregs = bp->creg;
@ -752,7 +750,7 @@ static void bigmac_is_medium_rare(struct bigmac *bp, u32 qec_status, u32 bmac_st
}
printk(" RESET\n");
bigmac_init(bp, 1);
bigmac_init_hw(bp, 1);
}
/* BigMAC transmit complete service routines. */
@ -926,7 +924,7 @@ static int bigmac_open(struct net_device *dev)
return ret;
}
init_timer(&bp->bigmac_timer);
ret = bigmac_init(bp, 0);
ret = bigmac_init_hw(bp, 0);
if (ret)
free_irq(dev->irq, bp);
return ret;
@ -950,7 +948,7 @@ static void bigmac_tx_timeout(struct net_device *dev)
{
struct bigmac *bp = (struct bigmac *) dev->priv;
bigmac_init(bp, 0);
bigmac_init_hw(bp, 0);
netif_wake_queue(dev);
}
@ -1104,6 +1102,8 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
bp->qec_sdev = qec_sdev;
bp->bigmac_sdev = qec_sdev->child;
SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev);
spin_lock_init(&bp->lock);
/* Verify the registers we expect, are actually there. */
@ -1226,11 +1226,7 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
goto fail_and_cleanup;
}
/* Put us into the list of instances attached for later driver
* exit.
*/
bp->next_module = root_bigmac_dev;
root_bigmac_dev = bp;
dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name);
for (i = 0; i < 6; i++)
@ -1266,69 +1262,68 @@ fail_and_cleanup:
/* QEC can be the parent of either QuadEthernet or
* a BigMAC. We want the latter.
*/
static int __init bigmac_match(struct sbus_dev *sdev)
static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *child = sdev->child;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
if (strcmp(sdev->prom_name, "qec") != 0)
return 0;
if (!strcmp(dp->name, "be"))
sdev = sdev->parent;
if (child == NULL)
return 0;
if (strcmp(child->prom_name, "be") != 0)
return 0;
return 1;
return bigmac_ether_init(sdev);
}
static int __init bigmac_probe(void)
static int __devexit bigmac_sbus_remove(struct of_device *dev)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev = NULL;
static int called;
int cards = 0, v;
struct bigmac *bp = dev_get_drvdata(&dev->dev);
struct net_device *net_dev = bp->dev;
root_bigmac_dev = NULL;
unregister_netdevice(net_dev);
if (called)
return -ENODEV;
called++;
sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
sbus_iounmap(bp->creg, CREG_REG_SIZE);
sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
sbus_free_consistent(bp->bigmac_sdev,
PAGE_SIZE,
bp->bmac_block,
bp->bblock_dvma);
free_netdev(net_dev);
dev_set_drvdata(&dev->dev, NULL);
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if (bigmac_match(sdev)) {
cards++;
if ((v = bigmac_ether_init(sdev)))
return v;
}
}
}
if (!cards)
return -ENODEV;
return 0;
}
static void __exit bigmac_cleanup(void)
static struct of_device_id bigmac_sbus_match[] = {
{
.name = "qec",
},
{
.name = "be",
},
{},
};
MODULE_DEVICE_TABLE(of, bigmac_sbus_match);
static struct of_platform_driver bigmac_sbus_driver = {
.name = "sunbmac",
.match_table = bigmac_sbus_match,
.probe = bigmac_sbus_probe,
.remove = __devexit_p(bigmac_sbus_remove),
};
static int __init bigmac_init(void)
{
while (root_bigmac_dev) {
struct bigmac *bp = root_bigmac_dev;
struct bigmac *bp_nxt = root_bigmac_dev->next_module;
sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
sbus_iounmap(bp->creg, CREG_REG_SIZE);
sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
sbus_free_consistent(bp->bigmac_sdev,
PAGE_SIZE,
bp->bmac_block,
bp->bblock_dvma);
unregister_netdev(bp->dev);
free_netdev(bp->dev);
root_bigmac_dev = bp_nxt;
}
return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type);
}
module_init(bigmac_probe);
module_exit(bigmac_cleanup);
static void __exit bigmac_exit(void)
{
of_unregister_driver(&bigmac_sbus_driver);
}
module_init(bigmac_init);
module_exit(bigmac_exit);

View File

@ -332,7 +332,6 @@ struct bigmac {
struct sbus_dev *qec_sdev;
struct sbus_dev *bigmac_sdev;
struct net_device *dev;
struct bigmac *next_module;
};
/* We use this to acquire receive skb's that we can DMA directly into. */

View File

@ -2880,17 +2880,20 @@ static int __devinit gem_get_device_address(struct gem *gp)
#if defined(__sparc__)
struct pci_dev *pdev = gp->pdev;
struct pcidev_cookie *pcp = pdev->sysdata;
int node = -1;
int use_idprom = 1;
if (pcp != NULL) {
node = pcp->prom_node;
if (prom_getproplen(node, "local-mac-address") == 6)
prom_getproperty(node, "local-mac-address",
dev->dev_addr, 6);
else
node = -1;
unsigned char *addr;
int len;
addr = of_get_property(pcp->prom_node, "local-mac-address",
&len);
if (addr && len == 6) {
use_idprom = 0;
memcpy(dev->dev_addr, addr, 6);
}
}
if (node == -1)
if (use_idprom)
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
#elif defined(CONFIG_PPC_PMAC)
unsigned char *addr;

View File

@ -1,9 +1,9 @@
/* $Id: sunhme.c,v 1.124 2002/01/15 06:25:51 davem Exp $
* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
/* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
*
* Copyright (C) 1996, 1998, 1999, 2002, 2003 David S. Miller (davem@redhat.com)
* Copyright (C) 1996, 1998, 1999, 2002, 2003,
2006 David S. Miller (davem@davemloft.net)
*
* Changes :
* 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@ -40,15 +40,13 @@
#include <asm/dma.h>
#include <asm/byteorder.h>
#ifdef __sparc__
#ifdef CONFIG_SPARC
#include <asm/idprom.h>
#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/auxio.h>
#ifndef __sparc_v9__
#include <asm/io-unit.h>
#endif
#endif
#include <asm/uaccess.h>
@ -57,7 +55,7 @@
#ifdef CONFIG_PCI
#include <linux/pci.h>
#ifdef __sparc__
#ifdef CONFIG_SPARC
#include <asm/pbm.h>
#endif
#endif
@ -65,9 +63,9 @@
#include "sunhme.h"
#define DRV_NAME "sunhme"
#define DRV_VERSION "2.02"
#define DRV_RELDATE "8/24/03"
#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
#define DRV_VERSION "3.00"
#define DRV_RELDATE "June 23, 2006"
#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@ -83,8 +81,6 @@ static int macaddr[6];
module_param_array(macaddr, int, NULL, 0);
MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set");
static struct happy_meal *root_happy_dev;
#ifdef CONFIG_SBUS
static struct quattro *qfe_sbus_list;
#endif
@ -181,26 +177,6 @@ static __inline__ void tx_dump_ring(struct happy_meal *hp)
#define DEFAULT_IPG2 4 /* For all modes */
#define DEFAULT_JAMSIZE 4 /* Toe jam */
#if defined(CONFIG_PCI) && defined(MODULE)
/* This happy_pci_ids is declared __initdata because it is only used
as an advisory to depmod. If this is ported to the new PCI interface
where it could be referenced at any time due to hot plugging,
the __initdata reference should be removed. */
static struct pci_device_id happymeal_pci_ids[] = {
{
.vendor = PCI_VENDOR_ID_SUN,
.device = PCI_DEVICE_ID_SUN_HAPPYMEAL,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
#endif
/* NOTE: In the descriptor writes one _must_ write the address
* member _first_. The card must not be allowed to see
* the updated descriptor flags until the address is
@ -1610,7 +1586,7 @@ static int happy_meal_init(struct happy_meal *hp)
HMD(("happy_meal_init: old[%08x] bursts<",
hme_read32(hp, gregs + GREG_CFG)));
#ifndef __sparc__
#ifndef CONFIG_SPARC
/* It is always PCI and can handle 64byte bursts. */
hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST64);
#else
@ -1647,7 +1623,7 @@ static int happy_meal_init(struct happy_meal *hp)
HMD(("XXX>"));
hme_write32(hp, gregs + GREG_CFG, 0);
}
#endif /* __sparc__ */
#endif /* CONFIG_SPARC */
/* Turn off interrupts we do not want to hear. */
HMD((", enable global interrupts, "));
@ -2592,14 +2568,10 @@ static void __init quattro_apply_ranges(struct quattro *qp, struct happy_meal *h
*/
static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev;
struct quattro *qp;
int i;
if (qfe_sbus_list == NULL)
goto found;
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
for (i = 0, sdev = qp->quattro_dev;
(sdev != NULL) && (i < 4);
@ -2608,17 +2580,7 @@ static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev)
return qp;
}
}
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if (sdev == goal_sdev)
goto found;
}
}
/* Cannot find quattro parent, fail. */
return NULL;
found:
qp = kmalloc(sizeof(struct quattro), GFP_KERNEL);
if (qp != NULL) {
int i;
@ -2655,6 +2617,17 @@ static void __init quattro_sbus_register_irqs(void)
}
}
}
static void __devexit quattro_sbus_free_irqs(void)
{
struct quattro *qp;
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
struct sbus_dev *sdev = qp->quattro_dev;
free_irq(sdev->irqs[0], qp);
}
}
#endif /* CONFIG_SBUS */
#ifdef CONFIG_PCI
@ -2689,8 +2662,9 @@ static struct quattro * __init quattro_pci_find(struct pci_dev *pdev)
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
static int __init happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe)
{
struct device_node *dp = sdev->ofdev.node;
struct quattro *qp = NULL;
struct happy_meal *hp;
struct net_device *dev;
@ -2713,6 +2687,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
if (!dev)
goto err_out;
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
if (hme_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@ -2728,13 +2703,16 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
for (i = 0; i < 6; i++)
dev->dev_addr[i] = macaddr[i];
macaddr[5]++;
} else if (qfe_slot != -1 &&
prom_getproplen(sdev->prom_node,
"local-mac-address") == 6) {
prom_getproperty(sdev->prom_node, "local-mac-address",
dev->dev_addr, 6);
} else {
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
unsigned char *addr;
int len;
addr = of_get_property(dp, "local-mac-address", &len);
if (qfe_slot != -1 && addr && len == 6)
memcpy(dev->dev_addr, addr, 6);
else
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
hp = dev->priv;
@ -2745,9 +2723,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
err = -ENODEV;
if (sdev->num_registers != 5) {
printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n",
printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n",
sdev->num_registers);
printk(KERN_ERR "happymeal: Would you like that for here or to go?\n");
goto err_out_free_netdev;
}
@ -2761,39 +2738,39 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
hp->gregs = sbus_ioremap(&sdev->resource[0], 0,
GREG_REG_SIZE, "HME Global Regs");
if (!hp->gregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal global registers.\n");
printk(KERN_ERR "happymeal: Cannot map global registers.\n");
goto err_out_free_netdev;
}
hp->etxregs = sbus_ioremap(&sdev->resource[1], 0,
ETX_REG_SIZE, "HME TX Regs");
if (!hp->etxregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Transmit registers.\n");
printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n");
goto err_out_iounmap;
}
hp->erxregs = sbus_ioremap(&sdev->resource[2], 0,
ERX_REG_SIZE, "HME RX Regs");
if (!hp->erxregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Receive registers.\n");
printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n");
goto err_out_iounmap;
}
hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0,
BMAC_REG_SIZE, "HME BIGMAC Regs");
if (!hp->bigmacregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal BIGMAC registers.\n");
printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n");
goto err_out_iounmap;
}
hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0,
TCVR_REG_SIZE, "HME Tranceiver Regs");
if (!hp->tcvregs) {
printk(KERN_ERR "happymeal: Cannot map Happy Meal Tranceiver registers.\n");
printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n");
goto err_out_iounmap;
}
hp->hm_revision = prom_getintdefault(sdev->prom_node, "hm-rev", 0xff);
hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff);
if (hp->hm_revision == 0xff)
hp->hm_revision = 0xa0;
@ -2807,8 +2784,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
hp->happy_flags |= HFLAG_QUATTRO;
/* Get the supported DVMA burst sizes from our Happy SBUS. */
hp->happy_bursts = prom_getintdefault(sdev->bus->prom_node,
"burst-sizes", 0x00);
hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node,
"burst-sizes", 0x00);
hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
PAGE_SIZE,
@ -2871,6 +2848,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
goto err_out_free_consistent;
}
dev_set_drvdata(&sdev->ofdev.dev, hp);
if (qfe_slot != -1)
printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
dev->name, qfe_slot);
@ -2883,12 +2862,6 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
dev->dev_addr[i], i == 5 ? ' ' : ':');
printk("\n");
/* We are home free at this point, link us in to the happy
* device list.
*/
hp->next_module = root_happy_dev;
root_happy_dev = hp;
return 0;
err_out_free_consistent:
@ -2918,7 +2891,7 @@ err_out:
#endif
#ifdef CONFIG_PCI
#ifndef __sparc__
#ifndef CONFIG_SPARC
static int is_quattro_p(struct pci_dev *pdev)
{
struct pci_dev *busdev = pdev->bus->self;
@ -3006,14 +2979,14 @@ static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
get_random_bytes(&dev_addr[3], 3);
return;
}
#endif /* !(__sparc__) */
#endif /* !(CONFIG_SPARC) */
static int __init happy_meal_pci_init(struct pci_dev *pdev)
static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct quattro *qp = NULL;
#ifdef __sparc__
#ifdef CONFIG_SPARC
struct pcidev_cookie *pcp;
int node;
#endif
struct happy_meal *hp;
struct net_device *dev;
@ -3024,15 +2997,14 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
int err;
/* Now make sure pci_dev cookie is there. */
#ifdef __sparc__
#ifdef CONFIG_SPARC
pcp = pdev->sysdata;
if (pcp == NULL || pcp->prom_node == -1) {
if (pcp == NULL) {
printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
return -ENODEV;
}
node = pcp->prom_node;
prom_getstring(node, "name", prom_name, sizeof(prom_name));
strcpy(prom_name, pcp->prom_node->name);
#else
if (is_quattro_p(pdev))
strcpy(prom_name, "SUNW,qfe");
@ -3103,11 +3075,15 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
dev->dev_addr[i] = macaddr[i];
macaddr[5]++;
} else {
#ifdef __sparc__
#ifdef CONFIG_SPARC
unsigned char *addr;
int len;
if (qfe_slot != -1 &&
prom_getproplen(node, "local-mac-address") == 6) {
prom_getproperty(node, "local-mac-address",
dev->dev_addr, 6);
(addr = of_get_property(pcp->prom_node,
"local-mac-address", &len)) != NULL
&& len == 6) {
memcpy(dev->dev_addr, addr, 6);
} else {
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
@ -3123,8 +3099,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
hp->bigmacregs = (hpreg_base + 0x6000UL);
hp->tcvregs = (hpreg_base + 0x7000UL);
#ifdef __sparc__
hp->hm_revision = prom_getintdefault(node, "hm-rev", 0xff);
#ifdef CONFIG_SPARC
hp->hm_revision = of_getintprop_default(pcp->prom_node, "hm-rev", 0xff);
if (hp->hm_revision == 0xff) {
unsigned char prev;
@ -3148,7 +3124,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
/* And of course, indicate this is PCI. */
hp->happy_flags |= HFLAG_PCI;
#ifdef __sparc__
#ifdef CONFIG_SPARC
/* Assume PCI happy meals can handle all burst sizes. */
hp->happy_bursts = DMA_BURSTBITS;
#endif
@ -3211,6 +3187,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
goto err_out_iounmap;
}
dev_set_drvdata(&pdev->dev, hp);
if (!qfe_slot) {
struct pci_dev *qpdev = qp->quattro_dev;
@ -3240,12 +3218,6 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
printk("\n");
/* We are home free at this point, link us in to the happy
* device list.
*/
hp->next_module = root_happy_dev;
root_happy_dev = hp;
return 0;
err_out_iounmap:
@ -3263,146 +3235,54 @@ err_out_clear_quattro:
err_out:
return err;
}
#endif
#ifdef CONFIG_SBUS
static int __init happy_meal_sbus_probe(void)
static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev;
int cards = 0;
char model[128];
struct happy_meal *hp = dev_get_drvdata(&pdev->dev);
struct net_device *net_dev = hp->dev;
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
char *name = sdev->prom_name;
unregister_netdev(net_dev);
if (!strcmp(name, "SUNW,hme")) {
cards++;
prom_getstring(sdev->prom_node, "model",
model, sizeof(model));
if (!strcmp(model, "SUNW,sbus-qfe"))
happy_meal_sbus_init(sdev, 1);
else
happy_meal_sbus_init(sdev, 0);
} else if (!strcmp(name, "qfe") ||
!strcmp(name, "SUNW,qfe")) {
cards++;
happy_meal_sbus_init(sdev, 1);
}
}
}
if (cards != 0)
quattro_sbus_register_irqs();
return cards;
}
#endif
pci_free_consistent(hp->happy_dev,
PAGE_SIZE,
hp->happy_block,
hp->hblock_dvma);
iounmap(hp->gregs);
pci_release_regions(hp->happy_dev);
#ifdef CONFIG_PCI
static int __init happy_meal_pci_probe(void)
{
struct pci_dev *pdev = NULL;
int cards = 0;
free_netdev(net_dev);
while ((pdev = pci_find_device(PCI_VENDOR_ID_SUN,
PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
if (pci_enable_device(pdev))
continue;
pci_set_master(pdev);
cards++;
happy_meal_pci_init(pdev);
}
return cards;
}
#endif
static int __init happy_meal_probe(void)
{
static int called = 0;
int cards;
root_happy_dev = NULL;
if (called)
return -ENODEV;
called++;
cards = 0;
#ifdef CONFIG_SBUS
cards += happy_meal_sbus_probe();
#endif
#ifdef CONFIG_PCI
cards += happy_meal_pci_probe();
#endif
if (!cards)
return -ENODEV;
return 0;
dev_set_drvdata(&pdev->dev, NULL);
}
static struct pci_device_id happymeal_pci_ids[] = {
{
.vendor = PCI_VENDOR_ID_SUN,
.device = PCI_DEVICE_ID_SUN_HAPPYMEAL,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ } /* Terminating entry */
};
static void __exit happy_meal_cleanup_module(void)
MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
static struct pci_driver hme_pci_driver = {
.name = "hme",
.id_table = happymeal_pci_ids,
.probe = happy_meal_pci_probe,
.remove = __devexit_p(happy_meal_pci_remove),
};
static int __init happy_meal_pci_init(void)
{
#ifdef CONFIG_SBUS
struct quattro *last_seen_qfe = NULL;
#endif
return pci_module_init(&hme_pci_driver);
}
while (root_happy_dev) {
struct happy_meal *hp = root_happy_dev;
struct happy_meal *next = root_happy_dev->next_module;
struct net_device *dev = hp->dev;
static void happy_meal_pci_exit(void)
{
pci_unregister_driver(&hme_pci_driver);
/* Unregister netdev before unmapping registers as this
* call can end up trying to access those registers.
*/
unregister_netdev(dev);
#ifdef CONFIG_SBUS
if (!(hp->happy_flags & HFLAG_PCI)) {
if (hp->happy_flags & HFLAG_QUATTRO) {
if (hp->qfe_parent != last_seen_qfe) {
free_irq(dev->irq, hp->qfe_parent);
last_seen_qfe = hp->qfe_parent;
}
}
sbus_iounmap(hp->gregs, GREG_REG_SIZE);
sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
sbus_free_consistent(hp->happy_dev,
PAGE_SIZE,
hp->happy_block,
hp->hblock_dvma);
}
#endif
#ifdef CONFIG_PCI
if ((hp->happy_flags & HFLAG_PCI)) {
pci_free_consistent(hp->happy_dev,
PAGE_SIZE,
hp->happy_block,
hp->hblock_dvma);
iounmap(hp->gregs);
pci_release_regions(hp->happy_dev);
}
#endif
free_netdev(dev);
root_happy_dev = next;
}
/* Now cleanup the quattro lists. */
#ifdef CONFIG_SBUS
while (qfe_sbus_list) {
struct quattro *qfe = qfe_sbus_list;
struct quattro *next = qfe->next;
kfree(qfe);
qfe_sbus_list = next;
}
#endif
#ifdef CONFIG_PCI
while (qfe_pci_list) {
struct quattro *qfe = qfe_pci_list;
struct quattro *next = qfe->next;
@ -3411,8 +3291,131 @@ static void __exit happy_meal_cleanup_module(void)
qfe_pci_list = next;
}
}
#endif
#ifdef CONFIG_SBUS
static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
char *model = of_get_property(dp, "model", NULL);
int is_qfe = (match->data != NULL);
if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
is_qfe = 1;
return happy_meal_sbus_probe_one(sdev, is_qfe);
}
static int __devexit hme_sbus_remove(struct of_device *dev)
{
struct happy_meal *hp = dev_get_drvdata(&dev->dev);
struct net_device *net_dev = hp->dev;
unregister_netdevice(net_dev);
/* XXX qfe parent interrupt... */
sbus_iounmap(hp->gregs, GREG_REG_SIZE);
sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
sbus_free_consistent(hp->happy_dev,
PAGE_SIZE,
hp->happy_block,
hp->hblock_dvma);
free_netdev(net_dev);
dev_set_drvdata(&dev->dev, NULL);
return 0;
}
static struct of_device_id hme_sbus_match[] = {
{
.name = "SUNW,hme",
},
{
.name = "SUNW,qfe",
.data = (void *) 1,
},
{
.name = "qfe",
.data = (void *) 1,
},
{},
};
MODULE_DEVICE_TABLE(of, hme_sbus_match);
static struct of_platform_driver hme_sbus_driver = {
.name = "hme",
.match_table = hme_sbus_match,
.probe = hme_sbus_probe,
.remove = __devexit_p(hme_sbus_remove),
};
static int __init happy_meal_sbus_init(void)
{
int err;
err = of_register_driver(&hme_sbus_driver, &sbus_bus_type);
if (!err)
quattro_sbus_register_irqs();
return err;
}
static void happy_meal_sbus_exit(void)
{
of_unregister_driver(&hme_sbus_driver);
quattro_sbus_free_irqs();
while (qfe_sbus_list) {
struct quattro *qfe = qfe_sbus_list;
struct quattro *next = qfe->next;
kfree(qfe);
qfe_sbus_list = next;
}
}
#endif
static int __init happy_meal_probe(void)
{
int err = 0;
#ifdef CONFIG_SBUS
err = happy_meal_sbus_init();
#endif
#ifdef CONFIG_PCI
if (!err) {
err = happy_meal_pci_init();
#ifdef CONFIG_SBUS
if (err)
happy_meal_sbus_exit();
#endif
}
#endif
return err;
}
static void __exit happy_meal_exit(void)
{
#ifdef CONFIG_SBUS
happy_meal_sbus_exit();
#endif
#ifdef CONFIG_PCI
happy_meal_pci_exit();
#endif
}
module_init(happy_meal_probe);
module_exit(happy_meal_cleanup_module);
module_exit(happy_meal_exit);

View File

@ -461,7 +461,6 @@ struct happy_meal {
struct net_device *dev; /* Backpointer */
struct quattro *qfe_parent; /* For Quattro cards */
int qfe_ent; /* Which instance on quattro */
struct happy_meal *next_module;
};
/* Here are the happy flags. */

View File

@ -266,7 +266,6 @@ struct lance_private {
char *name;
dma_addr_t init_block_dvma;
struct net_device *dev; /* Backpointer */
struct lance_private *next_module;
struct sbus_dev *sdev;
struct timer_list multicast_timer;
};
@ -298,8 +297,6 @@ int sparc_lance_debug = 2;
#define LANCE_ADDR(x) ((long)(x) & ~0xff000000)
static struct lance_private *root_lance_dev;
/* Load the CSR registers */
static void load_csrs(struct lance_private *lp)
{
@ -1327,9 +1324,9 @@ static struct ethtool_ops sparc_lance_ethtool_ops = {
.get_link = sparc_lance_get_link,
};
static int __init sparc_lance_init(struct sbus_dev *sdev,
struct sbus_dma *ledma,
struct sbus_dev *lebuffer)
static int __init sparc_lance_probe_one(struct sbus_dev *sdev,
struct sbus_dma *ledma,
struct sbus_dev *lebuffer)
{
static unsigned version_printed;
struct net_device *dev;
@ -1473,6 +1470,7 @@ no_link_test:
lp->dev = dev;
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
@ -1500,8 +1498,7 @@ no_link_test:
goto fail;
}
lp->next_module = root_lance_dev;
root_lance_dev = lp;
dev_set_drvdata(&sdev->ofdev.dev, lp);
printk(KERN_INFO "%s: LANCE ", dev->name);
@ -1536,88 +1533,112 @@ static inline struct sbus_dma *find_ledma(struct sbus_dev *sdev)
#include <asm/machines.h>
/* Find all the lance cards on the system and initialize them */
static int __init sparc_lance_probe(void)
static struct sbus_dev sun4_sdev;
static int __init sparc_lance_init(void)
{
static struct sbus_dev sdev;
static int called;
root_lance_dev = NULL;
if (called)
return -ENODEV;
called++;
if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
(idprom->id_machtype == (SM_SUN4|SM_4_470))) {
memset(&sdev, 0, sizeof(sdev));
sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
sdev.irqs[0] = 6;
return sparc_lance_init(&sdev, NULL, NULL);
memset(&sun4_sdev, 0, sizeof(sdev));
sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
sun4_sdev.irqs[0] = 6;
return sparc_lance_probe_one(&sun4_sdev, NULL, NULL);
}
return -ENODEV;
}
static int __exit sunlance_sun4_remove(void)
{
struct lance_private *lp = dev_get_drvdata(&sun4_sdev->dev);
struct net_device *net_dev = lp->dev;
unregister_netdevice(net_dev);
lance_free_hwresources(root_lance_dev);
free_netdev(net_dev);
dev_set_drvdata(&sun4_sdev->dev, NULL);
return 0;
}
#else /* !CONFIG_SUN4 */
/* Find all the lance cards on the system and initialize them */
static int __init sparc_lance_probe(void)
static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_bus *bus;
struct sbus_dev *sdev = NULL;
struct sbus_dma *ledma = NULL;
static int called;
int cards = 0, v;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
int err;
root_lance_dev = NULL;
if (!strcmp(dp->name, "le")) {
err = sparc_lance_probe_one(sdev, NULL, NULL);
} else if (!strcmp(dp->name, "ledma")) {
struct sbus_dma *ledma = find_ledma(sdev);
if (called)
return -ENODEV;
called++;
err = sparc_lance_probe_one(sdev->child, ledma, NULL);
} else {
BUG_ON(strcmp(dp->name, "lebuffer"));
err = sparc_lance_probe_one(sdev->child, NULL, sdev);
}
return err;
}
static int __devexit sunlance_sbus_remove(struct of_device *dev)
{
struct lance_private *lp = dev_get_drvdata(&dev->dev);
struct net_device *net_dev = lp->dev;
unregister_netdevice(net_dev);
lance_free_hwresources(lp);
free_netdev(net_dev);
dev_set_drvdata(&dev->dev, NULL);
for_each_sbus (bus) {
for_each_sbusdev (sdev, bus) {
if (strcmp(sdev->prom_name, "le") == 0) {
cards++;
if ((v = sparc_lance_init(sdev, NULL, NULL)))
return v;
continue;
}
if (strcmp(sdev->prom_name, "ledma") == 0) {
cards++;
ledma = find_ledma(sdev);
if ((v = sparc_lance_init(sdev->child,
ledma, NULL)))
return v;
continue;
}
if (strcmp(sdev->prom_name, "lebuffer") == 0){
cards++;
if ((v = sparc_lance_init(sdev->child,
NULL, sdev)))
return v;
continue;
}
} /* for each sbusdev */
} /* for each sbus */
if (!cards)
return -ENODEV;
return 0;
}
static struct of_device_id sunlance_sbus_match[] = {
{
.name = "le",
},
{
.name = "ledma",
},
{
.name = "lebuffer",
},
{},
};
MODULE_DEVICE_TABLE(of, sunlance_sbus_match);
static struct of_platform_driver sunlance_sbus_driver = {
.name = "sunlance",
.match_table = sunlance_sbus_match,
.probe = sunlance_sbus_probe,
.remove = __devexit_p(sunlance_sbus_remove),
};
/* Find all the lance cards on the system and initialize them */
static int __init sparc_lance_init(void)
{
return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type);
}
#endif /* !CONFIG_SUN4 */
static void __exit sparc_lance_cleanup(void)
static void __exit sparc_lance_exit(void)
{
struct lance_private *lp;
while (root_lance_dev) {
lp = root_lance_dev->next_module;
unregister_netdev(root_lance_dev->dev);
lance_free_hwresources(root_lance_dev);
free_netdev(root_lance_dev->dev);
root_lance_dev = lp;
}
#ifdef CONFIG_SUN4
sunlance_sun4_remove();
#else
of_unregister_driver(&sunlance_sbus_driver);
#endif
}
module_init(sparc_lance_probe);
module_exit(sparc_lance_cleanup);
module_init(sparc_lance_init);
module_exit(sparc_lance_exit);

View File

@ -1,10 +1,9 @@
/* $Id: sunqe.c,v 1.55 2002/01/15 06:48:55 davem Exp $
* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
/* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
* Once again I am out to prove that every ethernet
* controller out there can be most efficiently programmed
* if you make it look like a LANCE.
*
* Copyright (C) 1996, 1999, 2003 David S. Miller (davem@redhat.com)
* Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@ -41,9 +40,9 @@
#include "sunqe.h"
#define DRV_NAME "sunqe"
#define DRV_VERSION "3.0"
#define DRV_RELDATE "8/24/03"
#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
#define DRV_VERSION "4.0"
#define DRV_RELDATE "June 23, 2006"
#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@ -755,298 +754,269 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
qecp->gregs + GLOB_RSIZE);
}
/* Four QE's per QEC card. */
static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev)
static u8 __init qec_get_burst(struct device_node *dp)
{
static unsigned version_printed;
struct net_device *qe_devs[4];
struct sunqe *qeps[4];
struct sbus_dev *qesdevs[4];
struct sbus_dev *child;
struct sunqec *qecp = NULL;
u8 bsizes, bsizes_more;
int i, j, res = -ENOMEM;
for (i = 0; i < 4; i++) {
qe_devs[i] = alloc_etherdev(sizeof(struct sunqe));
if (!qe_devs[i])
goto out;
}
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
for (i = 0; i < 4; i++) {
qeps[i] = (struct sunqe *) qe_devs[i]->priv;
for (j = 0; j < 6; j++)
qe_devs[i]->dev_addr[j] = idprom->id_ethaddr[j];
qeps[i]->channel = i;
spin_lock_init(&qeps[i]->lock);
}
qecp = kmalloc(sizeof(struct sunqec), GFP_KERNEL);
if (qecp == NULL)
goto out1;
qecp->qec_sdev = sdev;
for (i = 0; i < 4; i++) {
qecp->qes[i] = qeps[i];
qeps[i]->dev = qe_devs[i];
qeps[i]->parent = qecp;
}
res = -ENODEV;
for (i = 0, child = sdev->child; i < 4; i++, child = child->next) {
/* Link in channel */
j = prom_getintdefault(child->prom_node, "channel#", -1);
if (j == -1)
goto out2;
qesdevs[j] = child;
}
for (i = 0; i < 4; i++)
qeps[i]->qe_sdev = qesdevs[i];
/* Now map in the registers, QEC globals first. */
qecp->gregs = sbus_ioremap(&sdev->resource[0], 0,
GLOB_REG_SIZE, "QEC Global Registers");
if (!qecp->gregs) {
printk(KERN_ERR "QuadEther: Cannot map QEC global registers.\n");
goto out2;
}
/* Make sure the QEC is in MACE mode. */
if ((sbus_readl(qecp->gregs + GLOB_CTRL) & 0xf0000000) != GLOB_CTRL_MMODE) {
printk(KERN_ERR "QuadEther: AIEEE, QEC is not in MACE mode!\n");
goto out3;
}
/* Reset the QEC. */
if (qec_global_reset(qecp->gregs))
goto out3;
/* Find and set the burst sizes for the QEC, since it does
* the actual dma for all 4 channels.
/* Find and set the burst sizes for the QEC, since it
* does the actual dma for all 4 channels.
*/
bsizes = prom_getintdefault(sdev->prom_node, "burst-sizes", 0xff);
bsizes = of_getintprop_default(dp, "burst-sizes", 0xff);
bsizes &= 0xff;
bsizes_more = prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff);
bsizes_more = of_getintprop_default(dp->parent, "burst-sizes", 0xff);
if (bsizes_more != 0xff)
bsizes &= bsizes_more;
if (bsizes == 0xff || (bsizes & DMA_BURST16) == 0 ||
(bsizes & DMA_BURST32)==0)
(bsizes & DMA_BURST32)==0)
bsizes = (DMA_BURST32 - 1);
qecp->qec_bursts = bsizes;
return bsizes;
}
/* Perform one time QEC initialization, we never touch the QEC
* globals again after this.
*/
qec_init_once(qecp, sdev);
static struct sunqec * __init get_qec(struct sbus_dev *child_sdev)
{
struct sbus_dev *qec_sdev = child_sdev->parent;
struct sunqec *qecp;
for (i = 0; i < 4; i++) {
struct sunqe *qe = qeps[i];
/* Map in QEC per-channel control registers. */
qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
CREG_REG_SIZE, "QEC Channel Registers");
if (!qe->qcregs) {
printk(KERN_ERR "QuadEther: Cannot map QE %d's channel registers.\n", i);
goto out4;
for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) {
if (qecp->qec_sdev == qec_sdev)
break;
}
if (!qecp) {
qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL);
if (qecp) {
u32 ctrl;
qecp->qec_sdev = qec_sdev;
qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0,
GLOB_REG_SIZE,
"QEC Global Registers");
if (!qecp->gregs)
goto fail;
/* Make sure the QEC is in MACE mode. */
ctrl = sbus_readl(qecp->gregs + GLOB_CTRL);
ctrl &= 0xf0000000;
if (ctrl != GLOB_CTRL_MMODE) {
printk(KERN_ERR "qec: Not in MACE mode!\n");
goto fail;
}
if (qec_global_reset(qecp->gregs))
goto fail;
qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node);
qec_init_once(qecp, qec_sdev);
if (request_irq(qec_sdev->irqs[0], &qec_interrupt,
SA_SHIRQ, "qec", (void *) qecp)) {
printk(KERN_ERR "qec: Can't register irq.\n");
goto fail;
}
qecp->next_module = root_qec_dev;
root_qec_dev = qecp;
}
}
/* Map in per-channel AMD MACE registers. */
qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
MREGS_REG_SIZE, "QE MACE Registers");
if (!qe->mregs) {
printk(KERN_ERR "QuadEther: Cannot map QE %d's MACE registers.\n", i);
goto out4;
return qecp;
fail:
if (qecp->gregs)
sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
kfree(qecp);
return NULL;
}
static int __init qec_ether_init(struct sbus_dev *sdev)
{
static unsigned version_printed;
struct net_device *dev;
struct sunqe *qe;
struct sunqec *qecp;
int i, res;
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
dev = alloc_etherdev(sizeof(struct sunqe));
if (!dev)
return -ENOMEM;
qe = netdev_priv(dev);
i = of_getintprop_default(sdev->ofdev.node, "channel#", -1);
if (i == -1) {
struct sbus_dev *td = sdev->parent->child;
i = 0;
while (td != sdev) {
td = td->next;
i++;
}
}
qe->channel = i;
spin_lock_init(&qe->lock);
res = -ENODEV;
qecp = get_qec(sdev);
if (!qecp)
goto fail;
qe->qe_block = sbus_alloc_consistent(qe->qe_sdev,
PAGE_SIZE,
&qe->qblock_dvma);
qe->buffers = sbus_alloc_consistent(qe->qe_sdev,
sizeof(struct sunqe_buffers),
&qe->buffers_dvma);
if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
qe->buffers == NULL || qe->buffers_dvma == 0) {
goto out4;
}
qecp->qes[qe->channel] = qe;
qe->dev = dev;
qe->parent = qecp;
qe->qe_sdev = sdev;
/* Stop this QE. */
qe_stop(qe);
res = -ENOMEM;
qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
CREG_REG_SIZE, "QEC Channel Registers");
if (!qe->qcregs) {
printk(KERN_ERR "qe: Cannot map channel registers.\n");
goto fail;
}
for (i = 0; i < 4; i++) {
SET_MODULE_OWNER(qe_devs[i]);
qe_devs[i]->open = qe_open;
qe_devs[i]->stop = qe_close;
qe_devs[i]->hard_start_xmit = qe_start_xmit;
qe_devs[i]->get_stats = qe_get_stats;
qe_devs[i]->set_multicast_list = qe_set_multicast;
qe_devs[i]->tx_timeout = qe_tx_timeout;
qe_devs[i]->watchdog_timeo = 5*HZ;
qe_devs[i]->irq = sdev->irqs[0];
qe_devs[i]->dma = 0;
qe_devs[i]->ethtool_ops = &qe_ethtool_ops;
qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
MREGS_REG_SIZE, "QE MACE Registers");
if (!qe->mregs) {
printk(KERN_ERR "qe: Cannot map MACE registers.\n");
goto fail;
}
/* QEC receives interrupts from each QE, then it sends the actual
* IRQ to the cpu itself. Since QEC is the single point of
* interrupt for all QE channels we register the IRQ handler
* for it now.
*/
if (request_irq(sdev->irqs[0], &qec_interrupt,
SA_SHIRQ, "QuadEther", (void *) qecp)) {
printk(KERN_ERR "QuadEther: Can't register QEC master irq handler.\n");
res = -EAGAIN;
goto out4;
}
qe->qe_block = sbus_alloc_consistent(qe->qe_sdev,
PAGE_SIZE,
&qe->qblock_dvma);
qe->buffers = sbus_alloc_consistent(qe->qe_sdev,
sizeof(struct sunqe_buffers),
&qe->buffers_dvma);
if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
qe->buffers == NULL || qe->buffers_dvma == 0)
goto fail;
for (i = 0; i < 4; i++) {
if (register_netdev(qe_devs[i]) != 0)
goto out5;
}
/* Stop this QE. */
qe_stop(qe);
/* Report the QE channels. */
for (i = 0; i < 4; i++) {
printk(KERN_INFO "%s: QuadEthernet channel[%d] ", qe_devs[i]->name, i);
for (j = 0; j < 6; j++)
printk ("%2.2x%c",
qe_devs[i]->dev_addr[j],
j == 5 ? ' ': ':');
printk("\n");
}
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
dev->open = qe_open;
dev->stop = qe_close;
dev->hard_start_xmit = qe_start_xmit;
dev->get_stats = qe_get_stats;
dev->set_multicast_list = qe_set_multicast;
dev->tx_timeout = qe_tx_timeout;
dev->watchdog_timeo = 5*HZ;
dev->irq = sdev->irqs[0];
dev->dma = 0;
dev->ethtool_ops = &qe_ethtool_ops;
res = register_netdev(dev);
if (res)
goto fail;
dev_set_drvdata(&sdev->ofdev.dev, qe);
printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel);
for (i = 0; i < 6; i++)
printk ("%2.2x%c",
dev->dev_addr[i],
i == 5 ? ' ': ':');
printk("\n");
/* We are home free at this point, link the qe's into
* the master list for later driver exit.
*/
qecp->next_module = root_qec_dev;
root_qec_dev = qecp;
return 0;
out5:
while (i--)
unregister_netdev(qe_devs[i]);
free_irq(sdev->irqs[0], (void *)qecp);
out4:
for (i = 0; i < 4; i++) {
struct sunqe *qe = (struct sunqe *)qe_devs[i]->priv;
fail:
if (qe->qcregs)
sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
if (qe->mregs)
sbus_iounmap(qe->mregs, MREGS_REG_SIZE);
if (qe->qe_block)
sbus_free_consistent(qe->qe_sdev,
PAGE_SIZE,
qe->qe_block,
qe->qblock_dvma);
if (qe->buffers)
sbus_free_consistent(qe->qe_sdev,
sizeof(struct sunqe_buffers),
qe->buffers,
qe->buffers_dvma);
free_netdev(dev);
if (qe->qcregs)
sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
if (qe->mregs)
sbus_iounmap(qe->mregs, MREGS_REG_SIZE);
if (qe->qe_block)
sbus_free_consistent(qe->qe_sdev,
PAGE_SIZE,
qe->qe_block,
qe->qblock_dvma);
if (qe->buffers)
sbus_free_consistent(qe->qe_sdev,
sizeof(struct sunqe_buffers),
qe->buffers,
qe->buffers_dvma);
}
out3:
sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
out2:
kfree(qecp);
out1:
i = 4;
out:
while (i--)
free_netdev(qe_devs[i]);
return res;
}
static int __init qec_match(struct sbus_dev *sdev)
static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sibling;
int i;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
if (strcmp(sdev->prom_name, "qec") != 0)
return 0;
/* QEC can be parent of either QuadEthernet or BigMAC
* children. Do not confuse this with qfe/SUNW,qfe
* which is a quad-happymeal card and handled by
* a different driver.
*/
sibling = sdev->child;
for (i = 0; i < 4; i++) {
if (sibling == NULL)
return 0;
if (strcmp(sibling->prom_name, "qe") != 0)
return 0;
sibling = sibling->next;
}
return 1;
return qec_ether_init(sdev);
}
static int __init qec_probe(void)
static int __devexit qec_sbus_remove(struct of_device *dev)
{
struct net_device *dev = NULL;
struct sbus_bus *bus;
struct sbus_dev *sdev = NULL;
static int called;
int cards = 0, v;
struct sunqe *qp = dev_get_drvdata(&dev->dev);
struct net_device *net_dev = qp->dev;
root_qec_dev = NULL;
unregister_netdevice(net_dev);
if (called)
return -ENODEV;
called++;
sbus_iounmap(qp->qcregs, CREG_REG_SIZE);
sbus_iounmap(qp->mregs, MREGS_REG_SIZE);
sbus_free_consistent(qp->qe_sdev,
PAGE_SIZE,
qp->qe_block,
qp->qblock_dvma);
sbus_free_consistent(qp->qe_sdev,
sizeof(struct sunqe_buffers),
qp->buffers,
qp->buffers_dvma);
for_each_sbus(bus) {
for_each_sbusdev(sdev, bus) {
if (cards)
dev = NULL;
free_netdev(net_dev);
dev_set_drvdata(&dev->dev, NULL);
if (qec_match(sdev)) {
cards++;
if ((v = qec_ether_init(dev, sdev)))
return v;
}
}
}
if (!cards)
return -ENODEV;
return 0;
}
static void __exit qec_cleanup(void)
static struct of_device_id qec_sbus_match[] = {
{
.name = "qe",
},
{},
};
MODULE_DEVICE_TABLE(of, qec_sbus_match);
static struct of_platform_driver qec_sbus_driver = {
.name = "qec",
.match_table = qec_sbus_match,
.probe = qec_sbus_probe,
.remove = __devexit_p(qec_sbus_remove),
};
static int __init qec_init(void)
{
struct sunqec *next_qec;
int i;
return of_register_driver(&qec_sbus_driver, &sbus_bus_type);
}
static void __exit qec_exit(void)
{
of_unregister_driver(&qec_sbus_driver);
while (root_qec_dev) {
next_qec = root_qec_dev->next_module;
struct sunqec *next = root_qec_dev->next_module;
/* Release all four QE channels, then the QEC itself. */
for (i = 0; i < 4; i++) {
unregister_netdev(root_qec_dev->qes[i]->dev);
sbus_iounmap(root_qec_dev->qes[i]->qcregs, CREG_REG_SIZE);
sbus_iounmap(root_qec_dev->qes[i]->mregs, MREGS_REG_SIZE);
sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev,
PAGE_SIZE,
root_qec_dev->qes[i]->qe_block,
root_qec_dev->qes[i]->qblock_dvma);
sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev,
sizeof(struct sunqe_buffers),
root_qec_dev->qes[i]->buffers,
root_qec_dev->qes[i]->buffers_dvma);
free_netdev(root_qec_dev->qes[i]->dev);
}
free_irq(root_qec_dev->qec_sdev->irqs[0], (void *)root_qec_dev);
free_irq(root_qec_dev->qec_sdev->irqs[0],
(void *) root_qec_dev);
sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE);
kfree(root_qec_dev);
root_qec_dev = next_qec;
root_qec_dev = next;
}
}
module_init(qec_probe);
module_exit(qec_cleanup);
module_init(qec_init);
module_exit(qec_exit);

View File

@ -10549,11 +10549,13 @@ static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp)
struct pcidev_cookie *pcp = pdev->sysdata;
if (pcp != NULL) {
int node = pcp->prom_node;
unsigned char *addr;
int len;
if (prom_getproplen(node, "local-mac-address") == 6) {
prom_getproperty(node, "local-mac-address",
dev->dev_addr, 6);
addr = of_get_property(pcp->prom_node, "local-mac-address",
&len);
if (addr && len == 6) {
memcpy(dev->dev_addr, addr, 6);
memcpy(dev->perm_addr, dev->dev_addr, 6);
return 0;
}

View File

@ -1550,10 +1550,14 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
dev->dev_addr[i] = last_phys_addr[i];
dev->dev_addr[i] = last_phys_addr[i] + 1;
#if defined(__sparc__)
if ((pcp != NULL) && prom_getproplen(pcp->prom_node,
"local-mac-address") == 6) {
prom_getproperty(pcp->prom_node, "local-mac-address",
dev->dev_addr, 6);
if (pcp) {
unsigned char *addr;
int len;
addr = of_get_property(pcp->prom_node,
"local-mac-address", &len);
if (addr && len == 6)
memcpy(dev->dev_addr, addr, 6);
}
#endif
#if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */

View File

@ -1,5 +1,4 @@
/* $Id: parport_sunbpp.c,v 1.12 2001/05/26 03:01:42 davem Exp $
* Parallel-port routines for Sun architecture
/* parport_sunbpp.c: Parallel-port routines for SBUS
*
* Author: Derrick J. Brashear <shadow@dementia.org>
*
@ -14,6 +13,9 @@
* Gus Baldauf (gbaldauf@ix.netcom.com)
* Peter Zaitcev
* Tom Dyas
*
* Updated to new SBUS device framework: David S. Miller <davem@davemloft.net>
*
*/
#include <linux/string.h>
@ -287,14 +289,7 @@ static struct parport_operations parport_sunbpp_ops =
.owner = THIS_MODULE,
};
typedef struct {
struct list_head list;
struct parport *port;
} Node;
/* no locks, everything's serialized */
static LIST_HEAD(port_list);
static int __init init_one_port(struct sbus_dev *sdev)
static int __devinit init_one_port(struct sbus_dev *sdev)
{
struct parport *p;
/* at least in theory there may be a "we don't dma" case */
@ -303,109 +298,120 @@ static int __init init_one_port(struct sbus_dev *sdev)
int irq, dma, err = 0, size;
struct bpp_regs __iomem *regs;
unsigned char value_tcr;
Node *node;
dprintk((KERN_DEBUG "init_one_port(%p): ranges, alloc_io, ", sdev));
node = kmalloc(sizeof(Node), GFP_KERNEL);
if (!node)
goto out0;
irq = sdev->irqs[0];
base = sbus_ioremap(&sdev->resource[0], 0,
sdev->reg_addrs[0].reg_size,
"sunbpp");
if (!base)
goto out1;
return -ENODEV;
size = sdev->reg_addrs[0].reg_size;
dma = PARPORT_DMA_NONE;
dprintk(("alloc(ppops), "));
ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
if (!ops)
goto out2;
goto out_unmap;
memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations));
dprintk(("register_port\n"));
if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
goto out3;
goto out_free_ops;
p->size = size;
dprintk((KERN_DEBUG "init_one_port: request_irq(%08x:%p:%x:%s:%p) ",
p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p));
if ((err = request_irq(p->irq, parport_sunbpp_interrupt,
SA_SHIRQ, p->name, p)) != 0) {
dprintk(("ERROR %d\n", err));
goto out4;
goto out_put_port;
}
dprintk(("OK\n"));
parport_sunbpp_enable_irq(p);
regs = (struct bpp_regs __iomem *)p->base;
dprintk((KERN_DEBUG "forward\n"));
value_tcr = sbus_readb(&regs->p_tcr);
value_tcr &= ~P_TCR_DIR;
sbus_writeb(value_tcr, &regs->p_tcr);
printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base);
node->port = p;
list_add(&node->list, &port_list);
parport_announce_port (p);
return 1;
dev_set_drvdata(&sdev->ofdev.dev, p);
out4:
parport_announce_port(p);
return 0;
out_put_port:
parport_put_port(p);
out3:
out_free_ops:
kfree(ops);
out2:
out_unmap:
sbus_iounmap(base, size);
out1:
kfree(node);
out0:
return err;
}
static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
return init_one_port(sdev);
}
static int __devexit bpp_remove(struct of_device *dev)
{
struct parport *p = dev_get_drvdata(&dev->dev);
struct parport_operations *ops = p->ops;
parport_remove_port(p);
if (p->irq != PARPORT_IRQ_NONE) {
parport_sunbpp_disable_irq(p);
free_irq(p->irq, p);
}
sbus_iounmap((void __iomem *) p->base, p->size);
parport_put_port(p);
kfree(ops);
dev_set_drvdata(&dev->dev, NULL);
return 0;
}
static struct of_device_id bpp_match[] = {
{
.name = "SUNW,bpp",
},
{},
};
MODULE_DEVICE_TABLE(of, qec_sbus_match);
static struct of_platform_driver bpp_sbus_driver = {
.name = "bpp",
.match_table = bpp_match,
.probe = bpp_probe,
.remove = __devexit_p(bpp_remove),
};
static int __init parport_sunbpp_init(void)
{
struct sbus_bus *sbus;
struct sbus_dev *sdev;
int count = 0;
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
if (!strcmp(sdev->prom_name, "SUNW,bpp"))
count += init_one_port(sdev);
}
}
return count ? 0 : -ENODEV;
return of_register_driver(&bpp_sbus_driver, &sbus_bus_type);
}
static void __exit parport_sunbpp_exit(void)
{
while (!list_empty(&port_list)) {
Node *node = list_entry(port_list.next, Node, list);
struct parport *p = node->port;
struct parport_operations *ops = p->ops;
parport_remove_port(p);
if (p->irq != PARPORT_IRQ_NONE) {
parport_sunbpp_disable_irq(p);
free_irq(p->irq, p);
}
sbus_iounmap((void __iomem *)p->base, p->size);
parport_put_port(p);
kfree (ops);
list_del(&node->list);
kfree (node);
}
of_unregister_driver(&bpp_sbus_driver);
}
MODULE_AUTHOR("Derrick J Brashear");
MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");
MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port");
MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
module_init(parport_sunbpp_init)

View File

@ -575,9 +575,9 @@ int bbc_envctrl_init(void)
int devidx = 0;
while ((echild = bbc_i2c_getdev(devidx++)) != NULL) {
if (!strcmp(echild->prom_name, "temperature"))
if (!strcmp(echild->prom_node->name, "temperature"))
attach_one_temp(echild, temp_index++);
if (!strcmp(echild->prom_name, "fan-control"))
if (!strcmp(echild->prom_node->name, "fan-control"))
attach_one_fan(echild, fan_index++);
}
if (temp_index != 0 && fan_index != 0) {

View File

@ -423,7 +423,7 @@ static int __init bbc_present(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "bbc"))
if (!strcmp(edev->prom_node->name, "bbc"))
return 1;
}
}
@ -446,7 +446,7 @@ static int __init bbc_i2c_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "i2c")) {
if (!strcmp(edev->prom_node->name, "i2c")) {
if (!attach_one_i2c(edev, index))
index++;
}

View File

@ -184,7 +184,7 @@ static int __init d7s_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, D7S_OBPNAME))
if (!strcmp(edev->prom_node->name, D7S_OBPNAME))
goto ebus_done;
}
}

View File

@ -768,16 +768,14 @@ static void envctrl_set_mon(struct i2c_child_t *pchild,
* decoding tables, monitor type, optional properties.
* Return: None.
*/
static void envctrl_init_adc(struct i2c_child_t *pchild, int node)
static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp)
{
char chnls_desc[CHANNEL_DESC_SZ];
int i = 0, len;
char *pos = chnls_desc;
char *pos;
unsigned int *pval;
/* Firmware describe channels into a stream separated by a '\0'. */
len = prom_getproperty(node, "channels-description", chnls_desc,
CHANNEL_DESC_SZ);
chnls_desc[CHANNEL_DESC_SZ - 1] = '\0';
pos = of_get_property(dp, "channels-description", &len);
while (len > 0) {
int l = strlen(pos) + 1;
@ -787,10 +785,13 @@ static void envctrl_init_adc(struct i2c_child_t *pchild, int node)
}
/* Get optional properties. */
len = prom_getproperty(node, "warning-temp", (char *)&warning_temperature,
sizeof(warning_temperature));
len = prom_getproperty(node, "shutdown-temp", (char *)&shutdown_temperature,
sizeof(shutdown_temperature));
pval = of_get_property(dp, "warning-temp", NULL);
if (pval)
warning_temperature = *pval;
pval = of_get_property(dp, "shutdown-temp", NULL);
if (pval)
shutdown_temperature = *pval;
}
/* Function Description: Initialize child device monitoring fan status.
@ -864,21 +865,18 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
struct i2c_child_t *pchild)
{
int node, len, i, tbls_size = 0;
node = edev_child->prom_node;
int len, i, tbls_size = 0;
struct device_node *dp = edev_child->prom_node;
void *pval;
/* Get device address. */
len = prom_getproperty(node, "reg",
(char *) &(pchild->addr),
sizeof(pchild->addr));
pval = of_get_property(dp, "reg", &len);
memcpy(&pchild->addr, pval, len);
/* Get tables property. Read firmware temperature tables. */
len = prom_getproperty(node, "translation",
(char *) pchild->tblprop_array,
(PCF8584_MAX_CHANNELS *
sizeof(struct pcf8584_tblprop)));
if (len > 0) {
pval = of_get_property(dp, "translation", &len);
if (pval && len > 0) {
memcpy(pchild->tblprop_array, pval, len);
pchild->total_tbls = len / sizeof(struct pcf8584_tblprop);
for (i = 0; i < pchild->total_tbls; i++) {
if ((pchild->tblprop_array[i].size + pchild->tblprop_array[i].offset) > tbls_size) {
@ -891,12 +889,12 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
printk("envctrl: Failed to allocate table.\n");
return;
}
len = prom_getproperty(node, "tables",
(char *) pchild->tables, tbls_size);
if (len <= 0) {
pval = of_get_property(dp, "tables", &len);
if (!pval || len <= 0) {
printk("envctrl: Failed to get table.\n");
return;
}
memcpy(pchild->tables, pval, len);
}
/* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04)
@ -907,12 +905,11 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
* 'NULL' monitor type.
*/
if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) {
struct device_node *root_node;
int len;
char prop[56];
len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len)))
{
root_node = of_find_node_by_path("/");
if (!strcmp(root_node->name, "SUNW,UltraSPARC-IIi-cEngine")) {
for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) {
pchild->mon_type[len] = ENVCTRL_NOMON;
}
@ -921,16 +918,14 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
}
/* Get the monitor channels. */
len = prom_getproperty(node, "channels-in-use",
(char *) pchild->chnl_array,
(PCF8584_MAX_CHANNELS *
sizeof(struct pcf8584_channel)));
pval = of_get_property(dp, "channels-in-use", &len);
memcpy(pchild->chnl_array, pval, len);
pchild->total_chnls = len / sizeof(struct pcf8584_channel);
for (i = 0; i < pchild->total_chnls; i++) {
switch (pchild->chnl_array[i].type) {
case PCF8584_TEMP_TYPE:
envctrl_init_adc(pchild, node);
envctrl_init_adc(pchild, dp);
break;
case PCF8584_GLOBALADDR_TYPE:
@ -945,7 +940,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
case PCF8584_VOLTAGE_TYPE:
if (pchild->i2ctype == I2C_ADC) {
envctrl_init_adc(pchild,node);
envctrl_init_adc(pchild,dp);
} else {
envctrl_init_voltage_status(pchild);
}
@ -1046,7 +1041,7 @@ static int __init envctrl_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "bbc")) {
if (!strcmp(edev->prom_node->name, "bbc")) {
/* If we find a boot-bus controller node,
* then this envctrl driver is not for us.
*/
@ -1060,14 +1055,14 @@ static int __init envctrl_init(void)
*/
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "i2c")) {
if (!strcmp(edev->prom_node->name, "i2c")) {
i2c = ioremap(edev->resource[0].start, 0x2);
for_each_edevchild(edev, edev_child) {
if (!strcmp("gpio", edev_child->prom_name)) {
if (!strcmp("gpio", edev_child->prom_node->name)) {
i2c_childlist[i].i2ctype = I2C_GPIO;
envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
}
if (!strcmp("adc", edev_child->prom_name)) {
if (!strcmp("adc", edev_child->prom_node->name)) {
i2c_childlist[i].i2ctype = I2C_ADC;
envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
}

View File

@ -192,9 +192,11 @@ static int __init flash_init(void)
}
if (!sdev) {
#ifdef CONFIG_PCI
struct linux_prom_registers *ebus_regs;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "flashprom"))
if (!strcmp(edev->prom_node->name, "flashprom"))
goto ebus_done;
}
}
@ -202,23 +204,23 @@ static int __init flash_init(void)
if (!edev)
return -ENODEV;
len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs));
if ((len % sizeof(regs[0])) != 0) {
ebus_regs = of_get_property(edev->prom_node, "reg", &len);
if (!ebus_regs || (len % sizeof(regs[0])) != 0) {
printk("flash: Strange reg property size %d\n", len);
return -ENODEV;
}
nregs = len / sizeof(regs[0]);
nregs = len / sizeof(ebus_regs[0]);
flash.read_base = edev->resource[0].start;
flash.read_size = regs[0].reg_size;
flash.read_size = ebus_regs[0].reg_size;
if (nregs == 1) {
flash.write_base = edev->resource[0].start;
flash.write_size = regs[0].reg_size;
flash.write_size = ebus_regs[0].reg_size;
} else if (nregs == 2) {
flash.write_base = edev->resource[1].start;
flash.write_size = regs[1].reg_size;
flash.write_size = ebus_regs[1].reg_size;
} else {
printk("flash: Strange number of regs %d\n", nregs);
return -ENODEV;

View File

@ -243,8 +243,8 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
((int *) opp->oprom_array)[1]);
pcp = pdev->sysdata;
if (pcp != NULL && pcp->prom_node != -1 && pcp->prom_node) {
node = pcp->prom_node;
if (pcp != NULL) {
node = pcp->prom_node->node;
data->current_node = node;
*((int *)opp->oprom_array) = node;
opp->oprom_size = sizeof(int);

View File

@ -1,7 +1,6 @@
/* $Id: sbus.c,v 1.100 2002/01/24 15:36:24 davem Exp $
* sbus.c: SBus support routines.
/* sbus.c: SBus support routines.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@ -14,237 +13,76 @@
#include <asm/sbus.h>
#include <asm/dma.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/bpp.h>
#include <asm/irq.h>
struct sbus_bus *sbus_root = NULL;
struct sbus_bus *sbus_root;
static struct linux_prom_irqs irqs[PROMINTR_MAX] __initdata = { { 0 } };
#ifdef CONFIG_SPARC32
static int interrupts[PROMINTR_MAX] __initdata = { 0 };
#endif
#ifdef CONFIG_PCI
extern int pcic_present(void);
#endif
/* Perhaps when I figure out more about the iommu we'll put a
* device registration routine here that probe_sbus() calls to
* setup the iommu for each Sbus.
*/
/* We call this for each SBus device, and fill the structure based
* upon the prom device tree. We return the start of memory after
* the things we have allocated.
*/
/* #define DEBUG_FILL */
static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev)
static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
{
unsigned long address, base;
unsigned long base;
void *pval;
int len;
sdev->prom_node = prom_node;
prom_getstring(prom_node, "name",
sdev->prom_name, sizeof(sdev->prom_name));
address = prom_getint(prom_node, "address");
len = prom_getproperty(prom_node, "reg",
(char *) sdev->reg_addrs,
sizeof(sdev->reg_addrs));
if (len == -1) {
sdev->num_registers = 0;
goto no_regs;
sdev->prom_node = dp->node;
strcpy(sdev->prom_name, dp->name);
pval = of_get_property(dp, "reg", &len);
sdev->num_registers = 0;
if (pval) {
memcpy(sdev->reg_addrs, pval, len);
sdev->num_registers =
len / sizeof(struct linux_prom_registers);
base = (unsigned long) sdev->reg_addrs[0].phys_addr;
/* Compute the slot number. */
if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m)
sdev->slot = sbus_dev_slot(base);
else
sdev->slot = sdev->reg_addrs[0].which_io;
}
if (len % sizeof(struct linux_prom_registers)) {
prom_printf("fill_sbus_device: proplen for regs of %s "
" was %d, need multiple of %d\n",
sdev->prom_name, len,
(int) sizeof(struct linux_prom_registers));
prom_halt();
}
if (len > (sizeof(struct linux_prom_registers) * PROMREG_MAX)) {
prom_printf("fill_sbus_device: Too many register properties "
"for device %s, len=%d\n",
sdev->prom_name, len);
prom_halt();
}
sdev->num_registers = len / sizeof(struct linux_prom_registers);
sdev->ranges_applied = 0;
base = (unsigned long) sdev->reg_addrs[0].phys_addr;
/* Compute the slot number. */
if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) {
sdev->slot = sbus_dev_slot(base);
} else {
sdev->slot = sdev->reg_addrs[0].which_io;
pval = of_get_property(dp, "ranges", &len);
sdev->num_device_ranges = 0;
if (pval) {
memcpy(sdev->device_ranges, pval, len);
sdev->num_device_ranges =
len / sizeof(struct linux_prom_ranges);
}
no_regs:
len = prom_getproperty(prom_node, "ranges",
(char *)sdev->device_ranges,
sizeof(sdev->device_ranges));
if (len == -1) {
sdev->num_device_ranges = 0;
goto no_ranges;
}
if (len % sizeof(struct linux_prom_ranges)) {
prom_printf("fill_sbus_device: proplen for ranges of %s "
" was %d, need multiple of %d\n",
sdev->prom_name, len,
(int) sizeof(struct linux_prom_ranges));
prom_halt();
}
if (len > (sizeof(struct linux_prom_ranges) * PROMREG_MAX)) {
prom_printf("fill_sbus_device: Too many range properties "
"for device %s, len=%d\n",
sdev->prom_name, len);
prom_halt();
}
sdev->num_device_ranges =
len / sizeof(struct linux_prom_ranges);
sbus_fill_device_irq(sdev);
no_ranges:
/* XXX Unfortunately, IRQ issues are very arch specific.
* XXX Pull this crud out into an arch specific area
* XXX at some point. -DaveM
*/
#ifdef CONFIG_SPARC64
len = prom_getproperty(prom_node, "interrupts",
(char *) irqs, sizeof(irqs));
if (len == -1 || len == 0) {
sdev->irqs[0] = 0;
sdev->num_irqs = 0;
} else {
unsigned int pri = irqs[0].pri;
sdev->ofdev.node = dp;
if (sdev->parent)
sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
else
sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev;
sdev->ofdev.dev.bus = &sbus_bus_type;
strcpy(sdev->ofdev.dev.bus_id, dp->path_component_name);
sdev->num_irqs = 1;
if (pri < 0x20)
pri += sdev->slot * 8;
sdev->irqs[0] = sbus_build_irq(sdev->bus, pri);
}
#endif /* CONFIG_SPARC64 */
#ifdef CONFIG_SPARC32
len = prom_getproperty(prom_node, "intr",
(char *)irqs, sizeof(irqs));
if (len != -1) {
sdev->num_irqs = len / 8;
if (sdev->num_irqs == 0) {
sdev->irqs[0] = 0;
} else if (sparc_cpu_model == sun4d) {
extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
for (len = 0; len < sdev->num_irqs; len++)
sdev->irqs[len] = sun4d_build_irq(sdev, irqs[len].pri);
} else {
for (len = 0; len < sdev->num_irqs; len++)
sdev->irqs[len] = irqs[len].pri;
}
} else {
/* No "intr" node found-- check for "interrupts" node.
* This node contains SBus interrupt levels, not IPLs
* as in "intr", and no vector values. We convert
* SBus interrupt levels to PILs (platform specific).
*/
len = prom_getproperty(prom_node, "interrupts",
(char *)interrupts, sizeof(interrupts));
if (len == -1) {
sdev->irqs[0] = 0;
sdev->num_irqs = 0;
} else {
sdev->num_irqs = len / sizeof(int);
for (len = 0; len < sdev->num_irqs; len++) {
sdev->irqs[len] = sbint_to_irq(sdev, interrupts[len]);
}
}
}
#endif /* CONFIG_SPARC32 */
if (of_device_register(&sdev->ofdev) != 0)
printk(KERN_DEBUG "sbus: device registration error for %s!\n",
sdev->ofdev.dev.bus_id);
}
/* This routine gets called from whoever needs the sbus first, to scan
* the SBus device tree. Currently it just prints out the devices
* found on the bus and builds trees of SBUS structs and attached
* devices.
*/
extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
extern void iounit_init(int sbi_node, int iounit_node, struct sbus_bus *sbus);
void sun4_init(void);
#ifdef CONFIG_SUN_AUXIO
extern void auxio_probe(void);
#endif
static void __init sbus_do_child_siblings(int start_node,
struct sbus_dev *child,
struct sbus_dev *parent,
struct sbus_bus *sbus)
{
struct sbus_dev *this_dev = child;
int this_node = start_node;
/* Child already filled in, just need to traverse siblings. */
child->child = NULL;
child->parent = parent;
while((this_node = prom_getsibling(this_node)) != 0) {
this_dev->next = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
this_dev = this_dev->next;
this_dev->next = NULL;
this_dev->parent = parent;
this_dev->bus = sbus;
fill_sbus_device(this_node, this_dev);
if(prom_getchild(this_node)) {
this_dev->child = kmalloc(sizeof(struct sbus_dev),
GFP_ATOMIC);
this_dev->child->bus = sbus;
this_dev->child->next = NULL;
fill_sbus_device(prom_getchild(this_node), this_dev->child);
sbus_do_child_siblings(prom_getchild(this_node),
this_dev->child, this_dev, sbus);
} else {
this_dev->child = NULL;
}
}
}
/*
* XXX This functions appears to be a distorted version of
* prom_sbus_ranges_init(), with all sun4d stuff cut away.
* Ask DaveM what is going on here, how is sun4d supposed to work... XXX
*/
/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
static void __init sbus_bus_ranges_init(int parent_node, struct sbus_bus *sbus)
static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
{
void *pval;
int len;
len = prom_getproperty(sbus->prom_node, "ranges",
(char *) sbus->sbus_ranges,
sizeof(sbus->sbus_ranges));
if (len == -1 || len == 0) {
sbus->num_sbus_ranges = 0;
return;
}
sbus->num_sbus_ranges = len / sizeof(struct linux_prom_ranges);
#ifdef CONFIG_SPARC32
if (sparc_cpu_model == sun4d) {
struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
int num_iounit_ranges;
pval = of_get_property(dp, "ranges", &len);
sbus->num_sbus_ranges = 0;
if (pval) {
memcpy(sbus->sbus_ranges, pval, len);
sbus->num_sbus_ranges =
len / sizeof(struct linux_prom_ranges);
len = prom_getproperty(parent_node, "ranges",
(char *) iounit_ranges,
sizeof (iounit_ranges));
if (len != -1) {
num_iounit_ranges = (len/sizeof(struct linux_prom_ranges));
prom_adjust_ranges (sbus->sbus_ranges, sbus->num_sbus_ranges, iounit_ranges, num_iounit_ranges);
}
sbus_arch_bus_ranges_init(dp->parent, sbus);
}
#endif
}
static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges,
@ -322,241 +160,127 @@ static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev)
}
}
extern void register_proc_sparc_ioport(void);
extern void firetruck_init(void);
/* We preserve the "probe order" of these bus and device lists to give
* the same ordering as the old code.
*/
static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root)
{
while (*root)
root = &(*root)->next;
*root = sbus;
sbus->next = NULL;
}
#ifdef CONFIG_SUN4
extern void sun4_dvma_init(void);
#endif
static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root)
{
while (*root)
root = &(*root)->next;
*root = sdev;
sdev->next = NULL;
}
static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus)
{
dp = dp->child;
while (dp) {
struct sbus_dev *sdev;
sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
if (sdev) {
sdev_insert(sdev, &parent->child);
sdev->bus = sbus;
sdev->parent = parent;
fill_sbus_device(dp, sdev);
walk_children(dp, sdev, sbus);
}
dp = dp->sibling;
}
}
static void __init build_one_sbus(struct device_node *dp, int num_sbus)
{
struct sbus_bus *sbus;
unsigned int sbus_clock;
struct device_node *dev_dp;
sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
if (!sbus)
return;
sbus_insert(sbus, &sbus_root);
sbus->prom_node = dp->node;
sbus_setup_iommu(sbus, dp);
printk("sbus%d: ", num_sbus);
sbus_clock = of_getintprop_default(dp, "clock-frequency",
(25*1000*1000));
sbus->clock_freq = sbus_clock;
printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
(int) (((sbus_clock/1000)%1000 != 0) ?
(((sbus_clock/1000)%1000) + 1000) : 0));
strcpy(sbus->prom_name, dp->name);
sbus_setup_arch_props(sbus, dp);
sbus_bus_ranges_init(dp, sbus);
sbus->ofdev.node = dp;
sbus->ofdev.dev.parent = NULL;
sbus->ofdev.dev.bus = &sbus_bus_type;
strcpy(sbus->ofdev.dev.bus_id, dp->path_component_name);
if (of_device_register(&sbus->ofdev) != 0)
printk(KERN_DEBUG "sbus: device registration error for %s!\n",
sbus->ofdev.dev.bus_id);
dev_dp = dp->child;
while (dev_dp) {
struct sbus_dev *sdev;
sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
if (sdev) {
sdev_insert(sdev, &sbus->devices);
sdev->bus = sbus;
sdev->parent = NULL;
fill_sbus_device(dev_dp, sdev);
walk_children(dev_dp, sdev, sbus);
}
dev_dp = dev_dp->sibling;
}
sbus_fixup_all_regs(sbus->devices);
dvma_init(sbus);
}
static int __init sbus_init(void)
{
int nd, this_sbus, sbus_devs, topnd, iommund;
unsigned int sbus_clock;
struct sbus_bus *sbus;
struct sbus_dev *this_dev;
int num_sbus = 0; /* How many did we find? */
struct device_node *dp;
const char *sbus_name = "sbus";
int num_sbus = 0;
#ifdef CONFIG_SPARC32
register_proc_sparc_ioport();
#endif
if (sbus_arch_preinit())
return 0;
#ifdef CONFIG_SUN4
sun4_dvma_init();
return 0;
#endif
if (sparc_cpu_model == sun4d)
sbus_name = "sbi";
topnd = prom_getchild(prom_root_node);
/* Finding the first sbus is a special case... */
iommund = 0;
if(sparc_cpu_model == sun4u) {
nd = prom_searchsiblings(topnd, "sbus");
if(nd == 0) {
#ifdef CONFIG_PCI
if (!pcic_present()) {
prom_printf("Neither SBUS nor PCI found.\n");
prom_halt();
} else {
#ifdef CONFIG_SPARC64
firetruck_init();
#endif
}
return 0;
#else
prom_printf("YEEE, UltraSparc sbus not found\n");
prom_halt();
#endif
}
} else if(sparc_cpu_model == sun4d) {
if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 ||
(nd = prom_getchild(iommund)) == 0 ||
(nd = prom_searchsiblings(nd, "sbi")) == 0) {
panic("sbi not found");
}
} else if((nd = prom_searchsiblings(topnd, "sbus")) == 0) {
if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 ||
(nd = prom_getchild(iommund)) == 0 ||
(nd = prom_searchsiblings(nd, "sbus")) == 0) {
#ifdef CONFIG_PCI
if (!pcic_present()) {
prom_printf("Neither SBUS nor PCI found.\n");
prom_halt();
}
return 0;
#else
/* No reason to run further - the data access trap will occur. */
panic("sbus not found");
#endif
}
}
/* Ok, we've found the first one, allocate first SBus struct
* and place in chain.
*/
sbus = sbus_root = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
sbus->next = NULL;
sbus->prom_node = nd;
this_sbus = nd;
if(iommund && sparc_cpu_model != sun4u && sparc_cpu_model != sun4d)
iommu_init(iommund, sbus);
/* Loop until we find no more SBUS's */
while(this_sbus) {
#ifdef CONFIG_SPARC64
/* IOMMU hides inside SBUS/SYSIO prom node on Ultra. */
if(sparc_cpu_model == sun4u) {
extern void sbus_iommu_init(int prom_node, struct sbus_bus *sbus);
sbus_iommu_init(this_sbus, sbus);
}
#endif /* CONFIG_SPARC64 */
#ifdef CONFIG_SPARC32
if (sparc_cpu_model == sun4d)
iounit_init(this_sbus, iommund, sbus);
#endif /* CONFIG_SPARC32 */
printk("sbus%d: ", num_sbus);
sbus_clock = prom_getint(this_sbus, "clock-frequency");
if(sbus_clock == -1)
sbus_clock = (25*1000*1000);
printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
(int) (((sbus_clock/1000)%1000 != 0) ?
(((sbus_clock/1000)%1000) + 1000) : 0));
prom_getstring(this_sbus, "name",
sbus->prom_name, sizeof(sbus->prom_name));
sbus->clock_freq = sbus_clock;
#ifdef CONFIG_SPARC32
if (sparc_cpu_model == sun4d) {
sbus->devid = prom_getint(iommund, "device-id");
sbus->board = prom_getint(iommund, "board#");
}
#endif
sbus_bus_ranges_init(iommund, sbus);
sbus_devs = prom_getchild(this_sbus);
if (!sbus_devs) {
sbus->devices = NULL;
goto next_bus;
}
sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
this_dev = sbus->devices;
this_dev->next = NULL;
this_dev->bus = sbus;
this_dev->parent = NULL;
fill_sbus_device(sbus_devs, this_dev);
/* Should we traverse for children? */
if(prom_getchild(sbus_devs)) {
/* Allocate device node */
this_dev->child = kmalloc(sizeof(struct sbus_dev),
GFP_ATOMIC);
/* Fill it */
this_dev->child->bus = sbus;
this_dev->child->next = NULL;
fill_sbus_device(prom_getchild(sbus_devs),
this_dev->child);
sbus_do_child_siblings(prom_getchild(sbus_devs),
this_dev->child,
this_dev,
sbus);
} else {
this_dev->child = NULL;
}
while((sbus_devs = prom_getsibling(sbus_devs)) != 0) {
/* Allocate device node */
this_dev->next = kmalloc(sizeof(struct sbus_dev),
GFP_ATOMIC);
this_dev = this_dev->next;
this_dev->next = NULL;
/* Fill it */
this_dev->bus = sbus;
this_dev->parent = NULL;
fill_sbus_device(sbus_devs, this_dev);
/* Is there a child node hanging off of us? */
if(prom_getchild(sbus_devs)) {
/* Get new device struct */
this_dev->child = kmalloc(sizeof(struct sbus_dev),
GFP_ATOMIC);
/* Fill it */
this_dev->child->bus = sbus;
this_dev->child->next = NULL;
fill_sbus_device(prom_getchild(sbus_devs),
this_dev->child);
sbus_do_child_siblings(prom_getchild(sbus_devs),
this_dev->child,
this_dev,
sbus);
} else {
this_dev->child = NULL;
}
}
/* Walk all devices and apply parent ranges. */
sbus_fixup_all_regs(sbus->devices);
dvma_init(sbus);
next_bus:
for_each_node_by_name(dp, sbus_name) {
build_one_sbus(dp, num_sbus);
num_sbus++;
if(sparc_cpu_model == sun4u) {
this_sbus = prom_getsibling(this_sbus);
if(!this_sbus)
break;
this_sbus = prom_searchsiblings(this_sbus, "sbus");
} else if(sparc_cpu_model == sun4d) {
iommund = prom_getsibling(iommund);
if(!iommund)
break;
iommund = prom_searchsiblings(iommund, "io-unit");
if(!iommund)
break;
this_sbus = prom_searchsiblings(prom_getchild(iommund), "sbi");
} else {
this_sbus = prom_getsibling(this_sbus);
if(!this_sbus)
break;
this_sbus = prom_searchsiblings(this_sbus, "sbus");
}
if(this_sbus) {
sbus->next = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
sbus = sbus->next;
sbus->next = NULL;
sbus->prom_node = this_sbus;
} else {
break;
}
} /* while(this_sbus) */
if (sparc_cpu_model == sun4d) {
extern void sun4d_init_sbi_irq(void);
sun4d_init_sbi_irq();
}
#ifdef CONFIG_SPARC64
if (sparc_cpu_model == sun4u) {
firetruck_init();
}
#endif
#ifdef CONFIG_SUN_AUXIO
if (sparc_cpu_model == sun4u)
auxio_probe ();
#endif
#ifdef CONFIG_SPARC64
if (sparc_cpu_model == sun4u) {
extern void clock_probe(void);
clock_probe();
}
#endif
sbus_arch_postinit();
return 0;
}

View File

@ -1,7 +1,6 @@
/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $
* esp.c: EnhancedScsiProcessor Sun SCSI driver code.
/* esp.c: ESP Sun SCSI driver.
*
* Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net)
*/
/* TODO:
@ -185,11 +184,6 @@ enum {
/*5*/ do_intr_end
};
/* The master ring of all esp hosts we are managing in this driver. */
static struct esp *espchain;
static DEFINE_SPINLOCK(espchain_lock);
static int esps_running = 0;
/* Forward declarations. */
static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
@ -694,36 +688,6 @@ static void __init esp_bootup_reset(struct esp *esp)
sbus_readb(esp->eregs + ESP_INTRPT);
}
static void esp_chain_add(struct esp *esp)
{
spin_lock_irq(&espchain_lock);
if (espchain) {
struct esp *elink = espchain;
while (elink->next)
elink = elink->next;
elink->next = esp;
} else {
espchain = esp;
}
esp->next = NULL;
spin_unlock_irq(&espchain_lock);
}
static void esp_chain_del(struct esp *esp)
{
spin_lock_irq(&espchain_lock);
if (espchain == esp) {
espchain = esp->next;
} else {
struct esp *elink = espchain;
while (elink->next != esp)
elink = elink->next;
elink->next = esp->next;
}
esp->next = NULL;
spin_unlock_irq(&espchain_lock);
}
static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
{
struct sbus_dev *sdev = esp->sdev;
@ -830,19 +794,20 @@ static int __init esp_register_irq(struct esp *esp)
static void __init esp_get_scsi_id(struct esp *esp)
{
struct sbus_dev *sdev = esp->sdev;
struct device_node *dp = sdev->ofdev.node;
esp->scsi_id = prom_getintdefault(esp->prom_node,
"initiator-id",
-1);
esp->scsi_id = of_getintprop_default(dp,
"initiator-id",
-1);
if (esp->scsi_id == -1)
esp->scsi_id = prom_getintdefault(esp->prom_node,
"scsi-initiator-id",
-1);
esp->scsi_id = of_getintprop_default(dp,
"scsi-initiator-id",
-1);
if (esp->scsi_id == -1)
esp->scsi_id = (sdev->bus == NULL) ? 7 :
prom_getintdefault(sdev->bus->prom_node,
"scsi-initiator-id",
7);
of_getintprop_default(sdev->bus->ofdev.node,
"scsi-initiator-id",
7);
esp->ehost->this_id = esp->scsi_id;
esp->scsi_id_mask = (1 << esp->scsi_id);
@ -1067,28 +1032,30 @@ static void __init esp_init_swstate(struct esp *esp)
esp->prev_hme_dmacsr = 0xffffffff;
}
static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_dev *esp_dev,
struct sbus_dev *espdma, struct sbus_bus *sbus,
int id, int hme)
static int __init detect_one_esp(struct scsi_host_template *tpnt,
struct device *dev,
struct sbus_dev *esp_dev,
struct sbus_dev *espdma,
struct sbus_bus *sbus,
int hme)
{
struct Scsi_Host *esp_host = scsi_register(tpnt, sizeof(struct esp));
static int instance;
struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp));
struct esp *esp;
if (!esp_host) {
printk("ESP: Cannot register SCSI host\n");
return -1;
}
if (!esp_host)
return -ENOMEM;
if (hme)
esp_host->max_id = 16;
esp = (struct esp *) esp_host->hostdata;
esp->ehost = esp_host;
esp->sdev = esp_dev;
esp->esp_id = id;
esp->esp_id = instance;
esp->prom_node = esp_dev->prom_node;
prom_getstring(esp->prom_node, "name", esp->prom_name,
sizeof(esp->prom_name));
esp_chain_add(esp);
if (esp_find_dvma(esp, espdma) < 0)
goto fail_unlink;
if (esp_map_regs(esp, hme) < 0) {
@ -1115,8 +1082,19 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de
esp_bootup_reset(esp);
if (scsi_add_host(esp_host, dev))
goto fail_free_irq;
dev_set_drvdata(&esp_dev->ofdev.dev, esp);
scsi_scan_host(esp_host);
instance++;
return 0;
fail_free_irq:
free_irq(esp->ehost->irq, esp);
fail_unmap_cmdarea:
sbus_free_consistent(esp->sdev, 16,
(void *) esp->esp_command,
@ -1129,102 +1107,18 @@ fail_dvma_release:
esp->dma->allocated = 0;
fail_unlink:
esp_chain_del(esp);
scsi_unregister(esp_host);
scsi_host_put(esp_host);
return -1;
}
/* Detecting ESP chips on the machine. This is the simple and easy
* version.
*/
#ifdef CONFIG_SUN4
#include <asm/sun4paddr.h>
static int __init esp_detect(struct scsi_host_template *tpnt)
static int __devexit esp_remove_common(struct esp *esp)
{
static struct sbus_dev esp_dev;
int esps_in_use = 0;
unsigned int irq = esp->ehost->irq;
espchain = NULL;
if (sun4_esp_physaddr) {
memset (&esp_dev, 0, sizeof(esp_dev));
esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
esp_dev.irqs[0] = 4;
esp_dev.resource[0].start = sun4_esp_physaddr;
esp_dev.resource[0].end = sun4_esp_physaddr + ESP_REG_SIZE - 1;
esp_dev.resource[0].flags = IORESOURCE_IO;
if (!detect_one_esp(tpnt, &esp_dev, NULL, NULL, 0, 0))
esps_in_use++;
printk("ESP: Total of 1 ESP hosts found, %d actually in use.\n", esps_in_use);
esps_running = esps_in_use;
}
return esps_in_use;
}
#else /* !CONFIG_SUN4 */
static int __init esp_detect(struct scsi_host_template *tpnt)
{
struct sbus_bus *sbus;
struct sbus_dev *esp_dev, *sbdev_iter;
int nesps = 0, esps_in_use = 0;
espchain = 0;
if (!sbus_root) {
#ifdef CONFIG_PCI
return 0;
#else
panic("No SBUS in esp_detect()");
#endif
}
for_each_sbus(sbus) {
for_each_sbusdev(sbdev_iter, sbus) {
struct sbus_dev *espdma = NULL;
int hme = 0;
/* Is it an esp sbus device? */
esp_dev = sbdev_iter;
if (strcmp(esp_dev->prom_name, "esp") &&
strcmp(esp_dev->prom_name, "SUNW,esp")) {
if (!strcmp(esp_dev->prom_name, "SUNW,fas")) {
hme = 1;
espdma = esp_dev;
} else {
if (!esp_dev->child ||
(strcmp(esp_dev->prom_name, "espdma") &&
strcmp(esp_dev->prom_name, "dma")))
continue; /* nope... */
espdma = esp_dev;
esp_dev = esp_dev->child;
if (strcmp(esp_dev->prom_name, "esp") &&
strcmp(esp_dev->prom_name, "SUNW,esp"))
continue; /* how can this happen? */
}
}
if (detect_one_esp(tpnt, esp_dev, espdma, sbus, nesps++, hme) < 0)
continue;
esps_in_use++;
} /* for each sbusdev */
} /* for each sbus */
printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,
esps_in_use);
esps_running = esps_in_use;
return esps_in_use;
}
#endif /* !CONFIG_SUN4 */
/*
*/
static int esp_release(struct Scsi_Host *host)
{
struct esp *esp = (struct esp *) host->hostdata;
scsi_remove_host(esp->ehost);
ESP_INTSOFF(esp->dregs);
#if 0
@ -1232,16 +1126,79 @@ static int esp_release(struct Scsi_Host *host)
esp_reset_esp(esp);
#endif
free_irq(esp->ehost->irq, esp);
free_irq(irq, esp);
sbus_free_consistent(esp->sdev, 16,
(void *) esp->esp_command, esp->esp_command_dvma);
sbus_iounmap(esp->eregs, ESP_REG_SIZE);
esp->dma->allocated = 0;
esp_chain_del(esp);
return 0;
scsi_host_put(esp->ehost);
return 0;
}
#ifdef CONFIG_SUN4
#include <asm/sun4paddr.h>
static struct sbus_dev sun4_esp_dev;
static int __init esp_sun4_probe(struct scsi_host_template *tpnt)
{
if (sun4_esp_physaddr) {
memset(&sun4_esp_dev, 0, sizeof(esp_dev));
sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
sun4_esp_dev.irqs[0] = 4;
sun4_esp_dev.resource[0].start = sun4_esp_physaddr;
sun4_esp_dev.resource[0].end =
sun4_esp_physaddr + ESP_REG_SIZE - 1;
sun4_esp_dev.resource[0].flags = IORESOURCE_IO;
return detect_one_esp(tpnt, NULL,
&sun4_esp_dev, NULL, NULL, 0);
}
return 0;
}
static int __devexit esp_sun4_remove(void)
{
struct esp *esp = dev_get_drvdata(&dev->dev);
return esp_remove_common(esp);
}
#else /* !CONFIG_SUN4 */
static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
struct sbus_dev *dma_sdev = NULL;
int hme = 0;
if (dp->parent &&
(!strcmp(dp->parent->name, "espdma") ||
!strcmp(dp->parent->name, "dma")))
dma_sdev = sdev->parent;
else if (!strcmp(dp->name, "SUNW,fas")) {
dma_sdev = sdev;
hme = 1;
}
return detect_one_esp(match->data, &dev->dev,
sdev, dma_sdev, sdev->bus, hme);
}
static int __devexit esp_sbus_remove(struct of_device *dev)
{
struct esp *esp = dev_get_drvdata(&dev->dev);
return esp_remove_common(esp);
}
#endif /* !CONFIG_SUN4 */
/* The info function will return whatever useful
* information the developer sees fit. If not provided, then
* the name field will be used instead.
@ -1415,18 +1372,11 @@ static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int inout)
{
struct esp *esp;
struct esp *esp = (struct esp *) host->hostdata;
if (inout)
return -EINVAL; /* not yet */
for_each_esp(esp) {
if (esp->ehost == host)
break;
}
if (!esp)
return -EINVAL;
if (start)
*start = buffer;
@ -4377,15 +4327,12 @@ static void esp_slave_destroy(struct scsi_device *SDptr)
SDptr->hostdata = NULL;
}
static struct scsi_host_template driver_template = {
.proc_name = "esp",
.proc_info = esp_proc_info,
.name = "Sun ESP 100/100a/200",
.detect = esp_detect,
static struct scsi_host_template esp_template = {
.module = THIS_MODULE,
.name = "esp",
.info = esp_info,
.slave_alloc = esp_slave_alloc,
.slave_destroy = esp_slave_destroy,
.release = esp_release,
.info = esp_info,
.queuecommand = esp_queue,
.eh_abort_handler = esp_abort,
.eh_bus_reset_handler = esp_reset,
@ -4394,12 +4341,58 @@ static struct scsi_host_template driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
.proc_name = "esp",
.proc_info = esp_proc_info,
};
#include "scsi_module.c"
#ifndef CONFIG_SUN4
static struct of_device_id esp_match[] = {
{
.name = "SUNW,esp",
.data = &esp_template,
},
{
.name = "SUNW,fas",
.data = &esp_template,
},
{
.name = "esp",
.data = &esp_template,
},
{},
};
MODULE_DEVICE_TABLE(of, esp_match);
MODULE_DESCRIPTION("EnhancedScsiProcessor Sun SCSI driver");
MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
static struct of_platform_driver esp_sbus_driver = {
.name = "esp",
.match_table = esp_match,
.probe = esp_sbus_probe,
.remove = __devexit_p(esp_sbus_remove),
};
#endif
static int __init esp_init(void)
{
#ifdef CONFIG_SUN4
return esp_sun4_probe(&esp_template);
#else
return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
#endif
}
static void __exit esp_exit(void)
{
#ifdef CONFIG_SUN4
esp_sun4_remove();
#else
of_unregister_driver(&esp_sbus_driver);
#endif
}
MODULE_DESCRIPTION("ESP Sun SCSI driver");
MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
module_init(esp_init);
module_exit(esp_exit);

View File

@ -403,8 +403,4 @@ struct esp {
#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
/* For our interrupt engine. */
#define for_each_esp(esp) \
for((esp) = espchain; (esp); (esp) = (esp)->next)
#endif /* !(_SPARC_ESP_H) */

View File

@ -1,6 +1,6 @@
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
*
* Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
* Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net)
*
* A lot of this driver was directly stolen from Erik H. Moe's PCI
* Qlogic ISP driver. Mucho kudos to him for this code.
@ -46,8 +46,6 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
#define MAX_TARGETS 16
#define MAX_LUNS 8 /* 32 for 1.31 F/W */
@ -57,7 +55,6 @@
static struct qlogicpti *qptichain = NULL;
static DEFINE_SPINLOCK(qptichain_lock);
static int qptis_running = 0;
#define PACKB(a, b) (((a)<<4)|(b))
@ -815,173 +812,6 @@ static int __init qpti_map_queues(struct qlogicpti *qpti)
return 0;
}
/* Detect all PTI Qlogic ISP's in the machine. */
static int __init qlogicpti_detect(struct scsi_host_template *tpnt)
{
struct qlogicpti *qpti;
struct Scsi_Host *qpti_host;
struct sbus_bus *sbus;
struct sbus_dev *sdev;
int nqptis = 0, nqptis_in_use = 0;
tpnt->proc_name = "qlogicpti";
for_each_sbus(sbus) {
for_each_sbusdev(sdev, sbus) {
/* Is this a red snapper? */
if (strcmp(sdev->prom_name, "ptisp") &&
strcmp(sdev->prom_name, "PTI,ptisp") &&
strcmp(sdev->prom_name, "QLGC,isp") &&
strcmp(sdev->prom_name, "SUNW,isp"))
continue;
/* Sometimes Antares cards come up not completely
* setup, and we get a report of a zero IRQ.
* Skip over them in such cases so we survive.
*/
if (sdev->irqs[0] == 0) {
printk("qpti%d: Adapter reports no interrupt, "
"skipping over this card.", nqptis);
continue;
}
/* Yep, register and allocate software state. */
qpti_host = scsi_register(tpnt, sizeof(struct qlogicpti));
if (!qpti_host) {
printk("QPTI: Cannot register PTI Qlogic ISP SCSI host");
continue;
}
qpti = (struct qlogicpti *) qpti_host->hostdata;
/* We are wide capable, 16 targets. */
qpti_host->max_id = MAX_TARGETS;
/* Setup back pointers and misc. state. */
qpti->qhost = qpti_host;
qpti->sdev = sdev;
qpti->qpti_id = nqptis++;
qpti->prom_node = sdev->prom_node;
prom_getstring(qpti->prom_node, "name",
qpti->prom_name,
sizeof(qpti->prom_name));
/* This is not correct, actually. There's a switch
* on the PTI cards that put them into "emulation"
* mode- i.e., report themselves as QLGC,isp
* instead of PTI,ptisp. The only real substantive
* difference between non-pti and pti cards is
* the tmon register. Which is possibly even
* there for Qlogic cards, but non-functional.
*/
qpti->is_pti = (strcmp (qpti->prom_name, "QLGC,isp") != 0);
qpti_chain_add(qpti);
if (qpti_map_regs(qpti) < 0)
goto fail_unlink;
if (qpti_register_irq(qpti) < 0)
goto fail_unmap_regs;
qpti_get_scsi_id(qpti);
qpti_get_bursts(qpti);
qpti_get_clock(qpti);
/* Clear out scsi_cmnd array. */
memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
if (qpti_map_queues(qpti) < 0)
goto fail_free_irq;
/* Load the firmware. */
if (qlogicpti_load_firmware(qpti))
goto fail_unmap_queues;
if (qpti->is_pti) {
/* Check the PTI status reg. */
if (qlogicpti_verify_tmon(qpti))
goto fail_unmap_queues;
}
/* Reset the ISP and init res/req queues. */
if (qlogicpti_reset_hardware(qpti_host))
goto fail_unmap_queues;
printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
qpti->fware_minrev, qpti->fware_micrev);
{
char buffer[60];
prom_getstring (qpti->prom_node,
"isp-fcode", buffer, 60);
if (buffer[0])
printk("(Firmware %s)", buffer);
if (prom_getbool(qpti->prom_node, "differential"))
qpti->differential = 1;
}
printk (" [%s Wide, using %s interface]\n",
(qpti->ultra ? "Ultra" : "Fast"),
(qpti->differential ? "differential" : "single ended"));
nqptis_in_use++;
continue;
fail_unmap_queues:
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent(qpti->sdev,
QSIZE(RES_QUEUE_LEN),
qpti->res_cpu, qpti->res_dvma);
sbus_free_consistent(qpti->sdev,
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
qpti->req_cpu, qpti->req_dvma);
#undef QSIZE
fail_free_irq:
free_irq(qpti->irq, qpti);
fail_unmap_regs:
sbus_iounmap(qpti->qregs,
qpti->sdev->reg_addrs[0].reg_size);
if (qpti->is_pti)
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
fail_unlink:
qpti_chain_del(qpti);
scsi_unregister(qpti->qhost);
}
}
if (nqptis)
printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
nqptis, nqptis_in_use);
qptis_running = nqptis_in_use;
return nqptis;
}
static int qlogicpti_release(struct Scsi_Host *host)
{
struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
/* Remove visibility from IRQ handlers. */
qpti_chain_del(qpti);
/* Shut up the card. */
sbus_writew(0, qpti->qregs + SBUS_CTRL);
/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
free_irq(qpti->irq, qpti);
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent(qpti->sdev,
QSIZE(RES_QUEUE_LEN),
qpti->res_cpu, qpti->res_dvma);
sbus_free_consistent(qpti->sdev,
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
qpti->req_cpu, qpti->req_dvma);
#undef QSIZE
sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
if (qpti->is_pti)
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
return 0;
}
const char *qlogicpti_info(struct Scsi_Host *host)
{
static char buf[80];
@ -1551,9 +1381,9 @@ static int qlogicpti_reset(struct scsi_cmnd *Cmnd)
return return_status;
}
static struct scsi_host_template driver_template = {
.detect = qlogicpti_detect,
.release = qlogicpti_release,
static struct scsi_host_template qpti_template = {
.module = THIS_MODULE,
.name = "qlogicpti",
.info = qlogicpti_info,
.queuecommand = qlogicpti_queuecommand_slow,
.eh_abort_handler = qlogicpti_abort,
@ -1565,8 +1395,189 @@ static struct scsi_host_template driver_template = {
.use_clustering = ENABLE_CLUSTERING,
};
static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
static int nqptis;
struct sbus_dev *sdev = to_sbus_device(&dev->dev);
struct device_node *dp = dev->node;
struct scsi_host_template *tpnt = match->data;
struct Scsi_Host *host;
struct qlogicpti *qpti;
char *fcode;
#include "scsi_module.c"
/* Sometimes Antares cards come up not completely
* setup, and we get a report of a zero IRQ.
*/
if (sdev->irqs[0] == 0)
return -ENODEV;
host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
if (!host)
return -ENOMEM;
qpti = (struct qlogicpti *) host->hostdata;
host->max_id = MAX_TARGETS;
qpti->qhost = host;
qpti->sdev = sdev;
qpti->qpti_id = nqptis;
qpti->prom_node = sdev->prom_node;
strcpy(qpti->prom_name, sdev->ofdev.node->name);
qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
if (qpti_map_regs(qpti) < 0)
goto fail_unlink;
if (qpti_register_irq(qpti) < 0)
goto fail_unmap_regs;
qpti_get_scsi_id(qpti);
qpti_get_bursts(qpti);
qpti_get_clock(qpti);
/* Clear out scsi_cmnd array. */
memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
if (qpti_map_queues(qpti) < 0)
goto fail_free_irq;
/* Load the firmware. */
if (qlogicpti_load_firmware(qpti))
goto fail_unmap_queues;
if (qpti->is_pti) {
/* Check the PTI status reg. */
if (qlogicpti_verify_tmon(qpti))
goto fail_unmap_queues;
}
/* Reset the ISP and init res/req queues. */
if (qlogicpti_reset_hardware(host))
goto fail_unmap_queues;
if (scsi_add_host(host, &dev->dev))
goto fail_unmap_queues;
printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
qpti->fware_minrev, qpti->fware_micrev);
fcode = of_get_property(dp, "isp-fcode", NULL);
if (fcode && fcode[0])
printk("(Firmware %s)", fcode);
if (of_find_property(dp, "differential", NULL) != NULL)
qpti->differential = 1;
printk (" [%s Wide, using %s interface]\n",
(qpti->ultra ? "Ultra" : "Fast"),
(qpti->differential ? "differential" : "single ended"));
dev_set_drvdata(&sdev->ofdev.dev, qpti);
qpti_chain_add(qpti);
scsi_scan_host(host);
nqptis++;
return 0;
fail_unmap_queues:
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent(qpti->sdev,
QSIZE(RES_QUEUE_LEN),
qpti->res_cpu, qpti->res_dvma);
sbus_free_consistent(qpti->sdev,
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
qpti->req_cpu, qpti->req_dvma);
#undef QSIZE
fail_unmap_regs:
sbus_iounmap(qpti->qregs,
qpti->sdev->reg_addrs[0].reg_size);
if (qpti->is_pti)
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
fail_free_irq:
free_irq(qpti->irq, qpti);
fail_unlink:
scsi_host_put(host);
return -ENODEV;
}
static int __devexit qpti_sbus_remove(struct of_device *dev)
{
struct qlogicpti *qpti = dev_get_drvdata(&dev->dev);
qpti_chain_del(qpti);
scsi_remove_host(qpti->qhost);
/* Shut up the card. */
sbus_writew(0, qpti->qregs + SBUS_CTRL);
/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
free_irq(qpti->irq, qpti);
#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
sbus_free_consistent(qpti->sdev,
QSIZE(RES_QUEUE_LEN),
qpti->res_cpu, qpti->res_dvma);
sbus_free_consistent(qpti->sdev,
QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
qpti->req_cpu, qpti->req_dvma);
#undef QSIZE
sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
if (qpti->is_pti)
sbus_iounmap(qpti->sreg, sizeof(unsigned char));
scsi_host_put(qpti->qhost);
return 0;
}
static struct of_device_id qpti_match[] = {
{
.name = "ptisp",
.data = &qpti_template,
},
{
.name = "PTI,ptisp",
.data = &qpti_template,
},
{
.name = "QLGC,isp",
.data = &qpti_template,
},
{
.name = "SUNW,isp",
.data = &qpti_template,
},
{},
};
MODULE_DEVICE_TABLE(of, qpti_match);
static struct of_platform_driver qpti_sbus_driver = {
.name = "qpti",
.match_table = qpti_match,
.probe = qpti_sbus_probe,
.remove = __devexit_p(qpti_sbus_remove),
};
static int __init qpti_init(void)
{
return of_register_driver(&qpti_sbus_driver, &sbus_bus_type);
}
static void __exit qpti_exit(void)
{
of_unregister_driver(&qpti_sbus_driver);
}
MODULE_DESCRIPTION("QlogicISP SBUS driver");
MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
MODULE_VERSION("2.0");
module_init(qpti_init);
module_exit(qpti_exit);

View File

@ -354,21 +354,24 @@ config SERIAL_CLPS711X_CONSOLE
kernel at boot time.)
config SERIAL_S3C2410
tristate "Samsung S3C2410 Serial port support"
tristate "Samsung S3C2410/S3C2440/S3C2442/S3C2412 Serial port support"
depends on ARM && ARCH_S3C2410
select SERIAL_CORE
help
Support for the on-chip UARTs on the Samsung S3C2410X CPU,
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
provide all of these ports, depending on how the serial port
pins are configured.
Currently this driver supports the UARTS on the S3C2410, S3C2440,
S3C2442, S3C2412 and S3C2413 CPUs.
config SERIAL_S3C2410_CONSOLE
bool "Support for console on S3C2410 serial port"
depends on SERIAL_S3C2410=y
select SERIAL_CORE_CONSOLE
help
Allow selection of the S3C2410 on-board serial ports for use as
Allow selection of the S3C24XX on-board serial ports for use as
an virtual console.
Even if you say Y here, the currently visible virtual console

View File

@ -872,6 +872,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port)
return "S3C2410";
case PORT_S3C2440:
return "S3C2440";
case PORT_S3C2412:
return "S3C2412";
default:
return NULL;
}
@ -1528,6 +1530,141 @@ static inline void s3c2440_serial_exit(void)
#define s3c2440_uart_inf_at NULL
#endif /* CONFIG_CPU_S3C2440 */
#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
static int s3c2412_serial_setsource(struct uart_port *port,
struct s3c24xx_uart_clksrc *clk)
{
unsigned long ucon = rd_regl(port, S3C2410_UCON);
ucon &= ~S3C2412_UCON_CLKMASK;
if (strcmp(clk->name, "uclk") == 0)
ucon |= S3C2440_UCON_UCLK;
else if (strcmp(clk->name, "pclk") == 0)
ucon |= S3C2440_UCON_PCLK;
else if (strcmp(clk->name, "usysclk") == 0)
ucon |= S3C2412_UCON_USYSCLK;
else {
printk(KERN_ERR "unknown clock source %s\n", clk->name);
return -EINVAL;
}
wr_regl(port, S3C2410_UCON, ucon);
return 0;
}
static int s3c2412_serial_getsource(struct uart_port *port,
struct s3c24xx_uart_clksrc *clk)
{
unsigned long ucon = rd_regl(port, S3C2410_UCON);
switch (ucon & S3C2412_UCON_CLKMASK) {
case S3C2412_UCON_UCLK:
clk->divisor = 1;
clk->name = "uclk";
break;
case S3C2412_UCON_PCLK:
case S3C2412_UCON_PCLK2:
clk->divisor = 1;
clk->name = "pclk";
break;
case S3C2412_UCON_USYSCLK:
clk->divisor = 1;
clk->name = "usysclk";
break;
}
return 0;
}
static int s3c2412_serial_resetport(struct uart_port *port,
struct s3c2410_uartcfg *cfg)
{
unsigned long ucon = rd_regl(port, S3C2410_UCON);
dbg("%s: port=%p (%08lx), cfg=%p\n",
__FUNCTION__, port, port->mapbase, cfg);
/* ensure we don't change the clock settings... */
ucon &= S3C2412_UCON_CLKMASK;
wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
wr_regl(port, S3C2410_ULCON, cfg->ulcon);
/* reset both fifos */
wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
wr_regl(port, S3C2410_UFCON, cfg->ufcon);
return 0;
}
static struct s3c24xx_uart_info s3c2412_uart_inf = {
.name = "Samsung S3C2412 UART",
.type = PORT_S3C2412,
.fifosize = 64,
.rx_fifomask = S3C2440_UFSTAT_RXMASK,
.rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
.rx_fifofull = S3C2440_UFSTAT_RXFULL,
.tx_fifofull = S3C2440_UFSTAT_TXFULL,
.tx_fifomask = S3C2440_UFSTAT_TXMASK,
.tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
.get_clksrc = s3c2412_serial_getsource,
.set_clksrc = s3c2412_serial_setsource,
.reset_port = s3c2412_serial_resetport,
};
/* device management */
static int s3c2412_serial_probe(struct platform_device *dev)
{
dbg("s3c2440_serial_probe: dev=%p\n", dev);
return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
}
static struct platform_driver s3c2412_serial_drv = {
.probe = s3c2412_serial_probe,
.remove = s3c24xx_serial_remove,
.suspend = s3c24xx_serial_suspend,
.resume = s3c24xx_serial_resume,
.driver = {
.name = "s3c2412-uart",
.owner = THIS_MODULE,
},
};
static inline int s3c2412_serial_init(void)
{
return s3c24xx_serial_init(&s3c2412_serial_drv, &s3c2412_uart_inf);
}
static inline void s3c2412_serial_exit(void)
{
platform_driver_unregister(&s3c2412_serial_drv);
}
#define s3c2412_uart_inf_at &s3c2412_uart_inf
#else
static inline int s3c2412_serial_init(void)
{
return 0;
}
static inline void s3c2412_serial_exit(void)
{
}
#define s3c2412_uart_inf_at NULL
#endif /* CONFIG_CPU_S3C2440 */
/* module initialisation code */
static int __init s3c24xx_serial_modinit(void)
@ -1542,6 +1679,7 @@ static int __init s3c24xx_serial_modinit(void)
s3c2400_serial_init();
s3c2410_serial_init();
s3c2412_serial_init();
s3c2440_serial_init();
return 0;
@ -1551,6 +1689,7 @@ static void __exit s3c24xx_serial_modexit(void)
{
s3c2400_serial_exit();
s3c2410_serial_exit();
s3c2412_serial_exit();
s3c2440_serial_exit();
uart_unregister_driver(&s3c24xx_uart_drv);
@ -1773,6 +1912,8 @@ static int s3c24xx_serial_initconsole(void)
info = s3c2410_uart_inf_at;
} else if (strcmp(dev->name, "s3c2440-uart") == 0) {
info = s3c2440_uart_inf_at;
} else if (strcmp(dev->name, "s3c2412-uart") == 0) {
info = s3c2412_uart_inf_at;
} else {
printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name);
return 0;
@ -1796,4 +1937,4 @@ console_initcall(s3c24xx_serial_initconsole);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_DESCRIPTION("Samsung S3C2410/S3C2440 Serial port driver");
MODULE_DESCRIPTION("Samsung S3C2410/S3C2440/S3C2412 Serial port driver");

View File

@ -427,31 +427,32 @@ static int __init hv_console_compatible(char *buf, int len)
static unsigned int __init get_interrupt(void)
{
const char *cons_str = "console";
const char *compat_str = "compatible";
int node = prom_getchild(sun4v_vdev_root);
char buf[64];
int err, len;
struct device_node *dev_node;
node = prom_searchsiblings(node, cons_str);
if (!node)
return 0;
dev_node = sun4v_vdev_root->child;
while (dev_node != NULL) {
struct property *prop;
len = prom_getproplen(node, compat_str);
if (len == 0 || len == -1)
return 0;
if (strcmp(dev_node->name, "console"))
goto next_sibling;
err = prom_getproperty(node, compat_str, buf, 64);
if (err == -1)
return 0;
prop = of_find_property(dev_node, "compatible", NULL);
if (!prop)
goto next_sibling;
if (!hv_console_compatible(buf, len))
if (hv_console_compatible(prop->value, prop->length))
break;
next_sibling:
dev_node = dev_node->sibling;
}
if (!dev_node)
return 0;
/* Ok, the this is the OBP node for the sun4v hypervisor
* console device. Decode the interrupt.
*/
return sun4v_vdev_device_interrupt(node);
return sun4v_vdev_device_interrupt(dev_node);
}
static int __init sunhv_init(void)

View File

@ -984,19 +984,19 @@ static void __init for_each_sab_edev(void (*callback)(struct linux_ebus_device *
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (!strcmp(edev->prom_name, "se")) {
if (!strcmp(edev->prom_node->name, "se")) {
callback(edev, arg);
continue;
} else if (!strcmp(edev->prom_name, "serial")) {
char compat[32];
} else if (!strcmp(edev->prom_node->name, "serial")) {
char *compat;
int clen;
/* On RIO this can be an SE, check it. We could
* just check ebus->is_rio, but this is more portable.
*/
clen = prom_getproperty(edev->prom_node, "compatible",
compat, sizeof(compat));
if (clen > 0) {
compat = of_get_property(edev->prom_node,
"compatible", &clen);
if (compat && clen > 0) {
if (strncmp(compat, "sab82532", 8) == 0) {
callback(edev, arg);
continue;

View File

@ -1053,7 +1053,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
*/
for_each_ebus(ebus) {
for_each_ebusdev(dev, ebus) {
if (dev->prom_node == up->port_node) {
if (dev->prom_node->node == up->port_node) {
/*
* The EBus is broken on sparc; it delivers
* virtual addresses in resources. Oh well...
@ -1073,7 +1073,7 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
#ifdef CONFIG_SPARC64
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
if (isa_dev->prom_node == up->port_node) {
if (isa_dev->prom_node->node == up->port_node) {
/* Same on sparc64. Cool architecure... */
up->port.membase = (char *) isa_dev->resource.start;
up->port.mapbase = isa_dev->resource.start;

View File

@ -1106,7 +1106,7 @@ static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode)
+ FHC_UREGS_ICLR;
imap = central_bus->child->fhc_regs.uregs
+ FHC_UREGS_IMAP;
zilog_irq = build_irq(12, 0, iclr, imap);
zilog_irq = build_irq(0, iclr, imap);
} else {
err = prom_getproperty(zsnode, "interrupts",
(char *) &sun4u_ino,

Some files were not shown because too many files have changed in this diff Show More