Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
24665cd0
Commit
24665cd0
authored
Jun 23, 2005
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
rsync://rsync.kernel.org/pub/scm/linux/kernel/git/paulus/ppc64-2.6
parents
fed2fc18
d7152fe1
Changes
44
Show whitespace changes
Inline
Side-by-side
Showing
44 changed files
with
2918 additions
and
754 deletions
+2918
-754
MAINTAINERS
MAINTAINERS
+7
-0
arch/ppc64/Kconfig
arch/ppc64/Kconfig
+20
-1
arch/ppc64/Makefile
arch/ppc64/Makefile
+2
-0
arch/ppc64/kernel/Makefile
arch/ppc64/kernel/Makefile
+9
-2
arch/ppc64/kernel/bpa_iic.c
arch/ppc64/kernel/bpa_iic.c
+270
-0
arch/ppc64/kernel/bpa_iic.h
arch/ppc64/kernel/bpa_iic.h
+62
-0
arch/ppc64/kernel/bpa_iommu.c
arch/ppc64/kernel/bpa_iommu.c
+377
-0
arch/ppc64/kernel/bpa_iommu.h
arch/ppc64/kernel/bpa_iommu.h
+65
-0
arch/ppc64/kernel/bpa_nvram.c
arch/ppc64/kernel/bpa_nvram.c
+118
-0
arch/ppc64/kernel/bpa_setup.c
arch/ppc64/kernel/bpa_setup.c
+140
-0
arch/ppc64/kernel/cpu_setup_power4.S
arch/ppc64/kernel/cpu_setup_power4.S
+15
-1
arch/ppc64/kernel/cputable.c
arch/ppc64/kernel/cputable.c
+11
-0
arch/ppc64/kernel/iSeries_setup.c
arch/ppc64/kernel/iSeries_setup.c
+0
-5
arch/ppc64/kernel/irq.c
arch/ppc64/kernel/irq.c
+3
-0
arch/ppc64/kernel/maple_setup.c
arch/ppc64/kernel/maple_setup.c
+62
-2
arch/ppc64/kernel/maple_time.c
arch/ppc64/kernel/maple_time.c
+0
-51
arch/ppc64/kernel/mpic.h
arch/ppc64/kernel/mpic.h
+3
-0
arch/ppc64/kernel/pSeries_pci.c
arch/ppc64/kernel/pSeries_pci.c
+19
-478
arch/ppc64/kernel/pSeries_setup.c
arch/ppc64/kernel/pSeries_setup.c
+6
-178
arch/ppc64/kernel/pSeries_smp.c
arch/ppc64/kernel/pSeries_smp.c
+64
-5
arch/ppc64/kernel/pci.c
arch/ppc64/kernel/pci.c
+3
-0
arch/ppc64/kernel/pci.h
arch/ppc64/kernel/pci.h
+5
-1
arch/ppc64/kernel/pmac_time.c
arch/ppc64/kernel/pmac_time.c
+1
-7
arch/ppc64/kernel/proc_ppc64.c
arch/ppc64/kernel/proc_ppc64.c
+1
-1
arch/ppc64/kernel/prom_init.c
arch/ppc64/kernel/prom_init.c
+2
-2
arch/ppc64/kernel/rtas-proc.c
arch/ppc64/kernel/rtas-proc.c
+2
-2
arch/ppc64/kernel/rtas.c
arch/ppc64/kernel/rtas.c
+119
-2
arch/ppc64/kernel/rtas_pci.c
arch/ppc64/kernel/rtas_pci.c
+495
-0
arch/ppc64/kernel/rtc.c
arch/ppc64/kernel/rtc.c
+3
-3
arch/ppc64/kernel/setup.c
arch/ppc64/kernel/setup.c
+26
-7
arch/ppc64/kernel/smp.c
arch/ppc64/kernel/smp.c
+2
-2
arch/ppc64/kernel/spider-pic.c
arch/ppc64/kernel/spider-pic.c
+191
-0
arch/ppc64/kernel/time.c
arch/ppc64/kernel/time.c
+63
-0
arch/ppc64/kernel/traps.c
arch/ppc64/kernel/traps.c
+4
-0
drivers/char/watchdog/Kconfig
drivers/char/watchdog/Kconfig
+10
-0
drivers/char/watchdog/Makefile
drivers/char/watchdog/Makefile
+1
-0
drivers/char/watchdog/wdrtas.c
drivers/char/watchdog/wdrtas.c
+696
-0
include/asm-ppc64/machdep.h
include/asm-ppc64/machdep.h
+1
-0
include/asm-ppc64/mmu.h
include/asm-ppc64/mmu.h
+3
-2
include/asm-ppc64/nvram.h
include/asm-ppc64/nvram.h
+1
-0
include/asm-ppc64/processor.h
include/asm-ppc64/processor.h
+13
-2
include/asm-ppc64/rtas.h
include/asm-ppc64/rtas.h
+6
-0
include/asm-ppc64/smp.h
include/asm-ppc64/smp.h
+8
-0
include/asm-ppc64/time.h
include/asm-ppc64/time.h
+9
-0
No files found.
MAINTAINERS
View file @
24665cd0
...
...
@@ -504,6 +504,13 @@ L: bonding-devel@lists.sourceforge.net
W: http://sourceforge.net/projects/bonding/
S: Supported
BROADBAND PROCESSOR ARCHITECTURE
P: Arnd Bergmann
M: arnd@arndb.de
L: linuxppc64-dev@ozlabs.org
W: http://linuxppc64.org
S: Supported
BTTV VIDEO4LINUX DRIVER
P: Gerd Knorr
M: kraxel@bytesex.org
...
...
arch/ppc64/Kconfig
View file @
24665cd0
...
...
@@ -77,6 +77,10 @@ config PPC_PSERIES
bool " IBM pSeries & new iSeries"
default y
config PPC_BPA
bool " Broadband Processor Architecture"
depends on PPC_MULTIPLATFORM
config PPC_PMAC
depends on PPC_MULTIPLATFORM
bool " Apple G5 based machines"
...
...
@@ -106,6 +110,21 @@ config PPC_OF
bool
default y
config XICS
depends on PPC_PSERIES
bool
default y
config MPIC
depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE
bool
default y
config BPA_IIC
depends on PPC_BPA
bool
default y
# VMX is pSeries only for now until somebody writes the iSeries
# exception vectors for it
config ALTIVEC
...
...
@@ -292,7 +311,7 @@ config MSCHUNKS
config PPC_RTAS
bool
depends on PPC_PSERIES
depends on PPC_PSERIES
|| PPC_BPA
default y
config RTAS_PROC
...
...
arch/ppc64/Makefile
View file @
24665cd0
...
...
@@ -90,12 +90,14 @@ boot := arch/ppc64/boot
boottarget-$(CONFIG_PPC_PSERIES)
:=
zImage zImage.initrd
boottarget-$(CONFIG_PPC_MAPLE)
:=
zImage zImage.initrd
boottarget-$(CONFIG_PPC_ISERIES)
:=
vmlinux.sminitrd vmlinux.initrd vmlinux.sm
boottarget-$(CONFIG_PPC_BPA)
:=
zImage zImage.initrd
$(boottarget-y)
:
vmlinux
$(Q)$(MAKE)
$(build)
=
$(boot)
$(boot)
/
$@
bootimage-$(CONFIG_PPC_PSERIES)
:=
$(boot)
/zImage
bootimage-$(CONFIG_PPC_PMAC)
:=
vmlinux
bootimage-$(CONFIG_PPC_MAPLE)
:=
$(boot)
/zImage
bootimage-$(CONFIG_PPC_BPA)
:=
zImage
bootimage-$(CONFIG_PPC_ISERIES)
:=
vmlinux
BOOTIMAGE
:=
$
(
bootimage-y
)
install
:
vmlinux
...
...
arch/ppc64/kernel/Makefile
View file @
24665cd0
...
...
@@ -27,17 +27,21 @@ obj-$(CONFIG_PPC_ISERIES) += HvCall.o HvLpConfig.o LparData.o \
mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o
\
iSeries_iommu.o
obj-$(CONFIG_PPC_MULTIPLATFORM)
+=
nvram.o i8259.o prom_init.o prom.o
mpic.o
obj-$(CONFIG_PPC_MULTIPLATFORM)
+=
nvram.o i8259.o prom_init.o prom.o
obj-$(CONFIG_PPC_PSERIES)
+=
pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o
\
pSeries_nvram.o rtasd.o ras.o pSeries_reconfig.o
\
xics.o rtas.o pSeries_setup.o pSeries_iommu.o
pSeries_setup.o pSeries_iommu.o
obj-$(CONFIG_PPC_BPA)
+=
bpa_setup.o bpa_iommu.o bpa_nvram.o
\
bpa_iic.o spider-pic.o
obj-$(CONFIG_EEH)
+=
eeh.o
obj-$(CONFIG_PROC_FS)
+=
proc_ppc64.o
obj-$(CONFIG_RTAS_FLASH)
+=
rtas_flash.o
obj-$(CONFIG_SMP)
+=
smp.o
obj-$(CONFIG_MODULES)
+=
module.o ppc_ksyms.o
obj-$(CONFIG_PPC_RTAS)
+=
rtas.o rtas_pci.o
obj-$(CONFIG_RTAS_PROC)
+=
rtas-proc.o
obj-$(CONFIG_SCANLOG)
+=
scanlog.o
obj-$(CONFIG_VIOPATH)
+=
viopath.o
...
...
@@ -46,6 +50,8 @@ obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
obj-$(CONFIG_BOOTX_TEXT)
+=
btext.o
obj-$(CONFIG_HVCS)
+=
hvcserver.o
obj-$(CONFIG_IBMVIO)
+=
vio.o
obj-$(CONFIG_XICS)
+=
xics.o
obj-$(CONFIG_MPIC)
+=
mpic.o
obj-$(CONFIG_PPC_PMAC)
+=
pmac_setup.o pmac_feature.o pmac_pci.o
\
pmac_time.o pmac_nvram.o pmac_low_i2c.o
...
...
@@ -58,6 +64,7 @@ ifdef CONFIG_SMP
obj-$(CONFIG_PPC_PMAC)
+=
pmac_smp.o smp-tbsync.o
obj-$(CONFIG_PPC_ISERIES)
+=
iSeries_smp.o
obj-$(CONFIG_PPC_PSERIES)
+=
pSeries_smp.o
obj-$(CONFIG_PPC_BPA)
+=
pSeries_smp.o
obj-$(CONFIG_PPC_MAPLE)
+=
smp-tbsync.o
endif
...
...
arch/ppc64/kernel/bpa_iic.c
0 → 100644
View file @
24665cd0
/*
* BPA Internal Interrupt Controller
*
* (C) Copyright IBM Deutschland Entwicklung GmbH 2005
*
* Author: Arnd Bergmann <arndb@de.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/percpu.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/ptrace.h>
#include "bpa_iic.h"
struct
iic_pending_bits
{
u32
data
;
u8
flags
;
u8
class
;
u8
source
;
u8
prio
;
};
enum
iic_pending_flags
{
IIC_VALID
=
0x80
,
IIC_IPI
=
0x40
,
};
struct
iic_regs
{
struct
iic_pending_bits
pending
;
struct
iic_pending_bits
pending_destr
;
u64
generate
;
u64
prio
;
};
struct
iic
{
struct
iic_regs
__iomem
*
regs
;
};
static
DEFINE_PER_CPU
(
struct
iic
,
iic
);
void
iic_local_enable
(
void
)
{
out_be64
(
&
__get_cpu_var
(
iic
).
regs
->
prio
,
0xff
);
}
void
iic_local_disable
(
void
)
{
out_be64
(
&
__get_cpu_var
(
iic
).
regs
->
prio
,
0x0
);
}
static
unsigned
int
iic_startup
(
unsigned
int
irq
)
{
return
0
;
}
static
void
iic_enable
(
unsigned
int
irq
)
{
iic_local_enable
();
}
static
void
iic_disable
(
unsigned
int
irq
)
{
}
static
void
iic_end
(
unsigned
int
irq
)
{
iic_local_enable
();
}
static
struct
hw_interrupt_type
iic_pic
=
{
.
typename
=
" BPA-IIC "
,
.
startup
=
iic_startup
,
.
enable
=
iic_enable
,
.
disable
=
iic_disable
,
.
end
=
iic_end
,
};
static
int
iic_external_get_irq
(
struct
iic_pending_bits
pending
)
{
int
irq
;
unsigned
char
node
,
unit
;
node
=
pending
.
source
>>
4
;
unit
=
pending
.
source
&
0xf
;
irq
=
-
1
;
/*
* This mapping is specific to the Broadband
* Engine. We might need to get the numbers
* from the device tree to support future CPUs.
*/
switch
(
unit
)
{
case
0x00
:
case
0x0b
:
/*
* One of these units can be connected
* to an external interrupt controller.
*/
if
(
pending
.
prio
>
0x3f
||
pending
.
class
!=
2
)
break
;
irq
=
IIC_EXT_OFFSET
+
spider_get_irq
(
pending
.
prio
+
node
*
IIC_NODE_STRIDE
)
+
node
*
IIC_NODE_STRIDE
;
break
;
case
0x01
...
0x04
:
case
0x07
...
0x0a
:
/*
* These units are connected to the SPEs
*/
if
(
pending
.
class
>
2
)
break
;
irq
=
IIC_SPE_OFFSET
+
pending
.
class
*
IIC_CLASS_STRIDE
+
node
*
IIC_NODE_STRIDE
+
unit
;
break
;
}
if
(
irq
==
-
1
)
printk
(
KERN_WARNING
"Unexpected interrupt class %02x, "
"source %02x, prio %02x, cpu %02x
\n
"
,
pending
.
class
,
pending
.
source
,
pending
.
prio
,
smp_processor_id
());
return
irq
;
}
/* Get an IRQ number from the pending state register of the IIC */
int
iic_get_irq
(
struct
pt_regs
*
regs
)
{
struct
iic
*
iic
;
int
irq
;
struct
iic_pending_bits
pending
;
iic
=
&
__get_cpu_var
(
iic
);
*
(
unsigned
long
*
)
&
pending
=
in_be64
((
unsigned
long
__iomem
*
)
&
iic
->
regs
->
pending_destr
);
irq
=
-
1
;
if
(
pending
.
flags
&
IIC_VALID
)
{
if
(
pending
.
flags
&
IIC_IPI
)
{
irq
=
IIC_IPI_OFFSET
+
(
pending
.
prio
>>
4
);
/*
if (irq > 0x80)
printk(KERN_WARNING "Unexpected IPI prio %02x"
"on CPU %02x\n", pending.prio,
smp_processor_id());
*/
}
else
{
irq
=
iic_external_get_irq
(
pending
);
}
}
return
irq
;
}
static
struct
iic_regs
__iomem
*
find_iic
(
int
cpu
)
{
struct
device_node
*
np
;
int
nodeid
=
cpu
/
2
;
unsigned
long
regs
;
struct
iic_regs
__iomem
*
iic_regs
;
for
(
np
=
of_find_node_by_type
(
NULL
,
"cpu"
);
np
;
np
=
of_find_node_by_type
(
np
,
"cpu"
))
{
if
(
nodeid
==
*
(
int
*
)
get_property
(
np
,
"node-id"
,
NULL
))
break
;
}
if
(
!
np
)
{
printk
(
KERN_WARNING
"IIC: CPU %d not found
\n
"
,
cpu
);
iic_regs
=
NULL
;
}
else
{
regs
=
*
(
long
*
)
get_property
(
np
,
"iic"
,
NULL
);
/* hack until we have decided on the devtree info */
regs
+=
0x400
;
if
(
cpu
&
1
)
regs
+=
0x20
;
printk
(
KERN_DEBUG
"IIC for CPU %d at %lx
\n
"
,
cpu
,
regs
);
iic_regs
=
__ioremap
(
regs
,
sizeof
(
struct
iic_regs
),
_PAGE_NO_CACHE
);
}
return
iic_regs
;
}
#ifdef CONFIG_SMP
void
iic_setup_cpu
(
void
)
{
out_be64
(
&
__get_cpu_var
(
iic
).
regs
->
prio
,
0xff
);
}
void
iic_cause_IPI
(
int
cpu
,
int
mesg
)
{
out_be64
(
&
per_cpu
(
iic
,
cpu
).
regs
->
generate
,
mesg
);
}
static
irqreturn_t
iic_ipi_action
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
smp_message_recv
(
irq
-
IIC_IPI_OFFSET
,
regs
);
return
IRQ_HANDLED
;
}
static
void
iic_request_ipi
(
int
irq
,
const
char
*
name
)
{
/* IPIs are marked SA_INTERRUPT as they must run with irqs
* disabled */
get_irq_desc
(
irq
)
->
handler
=
&
iic_pic
;
get_irq_desc
(
irq
)
->
status
|=
IRQ_PER_CPU
;
request_irq
(
irq
,
iic_ipi_action
,
SA_INTERRUPT
,
name
,
NULL
);
}
void
iic_request_IPIs
(
void
)
{
iic_request_ipi
(
IIC_IPI_OFFSET
+
PPC_MSG_CALL_FUNCTION
,
"IPI-call"
);
iic_request_ipi
(
IIC_IPI_OFFSET
+
PPC_MSG_RESCHEDULE
,
"IPI-resched"
);
#ifdef CONFIG_DEBUGGER
iic_request_ipi
(
IIC_IPI_OFFSET
+
PPC_MSG_DEBUGGER_BREAK
,
"IPI-debug"
);
#endif
/* CONFIG_DEBUGGER */
}
#endif
/* CONFIG_SMP */
static
void
iic_setup_spe_handlers
(
void
)
{
int
be
,
isrc
;
/* Assume two threads per BE are present */
for
(
be
=
0
;
be
<
num_present_cpus
()
/
2
;
be
++
)
{
for
(
isrc
=
0
;
isrc
<
IIC_CLASS_STRIDE
*
3
;
isrc
++
)
{
int
irq
=
IIC_NODE_STRIDE
*
be
+
IIC_SPE_OFFSET
+
isrc
;
get_irq_desc
(
irq
)
->
handler
=
&
iic_pic
;
}
}
}
void
iic_init_IRQ
(
void
)
{
int
cpu
,
irq_offset
;
struct
iic
*
iic
;
irq_offset
=
0
;
for_each_cpu
(
cpu
)
{
iic
=
&
per_cpu
(
iic
,
cpu
);
iic
->
regs
=
find_iic
(
cpu
);
if
(
iic
->
regs
)
out_be64
(
&
iic
->
regs
->
prio
,
0xff
);
}
iic_setup_spe_handlers
();
}
arch/ppc64/kernel/bpa_iic.h
0 → 100644
View file @
24665cd0
#ifndef ASM_BPA_IIC_H
#define ASM_BPA_IIC_H
#ifdef __KERNEL__
/*
* Mapping of IIC pending bits into per-node
* interrupt numbers.
*
* IRQ FF CC SS PP FF CC SS PP Description
*
* 00-3f 80 02 +0 00 - 80 02 +0 3f South Bridge
* 00-3f 80 02 +b 00 - 80 02 +b 3f South Bridge
* 41-4a 80 00 +1 ** - 80 00 +a ** SPU Class 0
* 51-5a 80 01 +1 ** - 80 01 +a ** SPU Class 1
* 61-6a 80 02 +1 ** - 80 02 +a ** SPU Class 2
* 70-7f C0 ** ** 00 - C0 ** ** 0f IPI
*
* F flags
* C class
* S source
* P Priority
* + node number
* * don't care
*
* A node consists of a Broadband Engine and an optional
* south bridge device providing a maximum of 64 IRQs.
* The south bridge may be connected to either IOIF0
* or IOIF1.
* Each SPE is represented as three IRQ lines, one per
* interrupt class.
* 16 IRQ numbers are reserved for inter processor
* interruptions, although these are only used in the
* range of the first node.
*
* This scheme needs 128 IRQ numbers per BIF node ID,
* which means that with the total of 512 lines
* available, we can have a maximum of four nodes.
*/
enum
{
IIC_EXT_OFFSET
=
0x00
,
/* Start of south bridge IRQs */
IIC_NUM_EXT
=
0x40
,
/* Number of south bridge IRQs */
IIC_SPE_OFFSET
=
0x40
,
/* Start of SPE interrupts */
IIC_CLASS_STRIDE
=
0x10
,
/* SPE IRQs per class */
IIC_IPI_OFFSET
=
0x70
,
/* Start of IPI IRQs */
IIC_NUM_IPIS
=
0x10
,
/* IRQs reserved for IPI */
IIC_NODE_STRIDE
=
0x80
,
/* Total IRQs per node */
};
extern
void
iic_init_IRQ
(
void
);
extern
int
iic_get_irq
(
struct
pt_regs
*
regs
);
extern
void
iic_cause_IPI
(
int
cpu
,
int
mesg
);
extern
void
iic_request_IPIs
(
void
);
extern
void
iic_setup_cpu
(
void
);
extern
void
iic_local_enable
(
void
);
extern
void
iic_local_disable
(
void
);
extern
void
spider_init_IRQ
(
void
);
extern
int
spider_get_irq
(
unsigned
long
int_pending
);
#endif
#endif
/* ASM_BPA_IIC_H */
arch/ppc64/kernel/bpa_iommu.c
0 → 100644
View file @
24665cd0
/*
* IOMMU implementation for Broadband Processor Architecture
* We just establish a linear mapping at boot by setting all the
* IOPT cache entries in the CPU.
* The mapping functions should be identical to pci_direct_iommu,
* except for the handling of the high order bit that is required
* by the Spider bridge. These should be split into a separate
* file at the point where we get a different bridge chip.
*
* Copyright (C) 2005 IBM Deutschland Entwicklung GmbH,
* Arnd Bergmann <arndb@de.ibm.com>
*
* Based on linear mapping
* Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.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.
*/
#undef DEBUG
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
#include <asm/sections.h>
#include <asm/iommu.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/abs_addr.h>
#include <asm/system.h>
#include "pci.h"
#include "bpa_iommu.h"
static
inline
unsigned
long
get_iopt_entry
(
unsigned
long
real_address
,
unsigned
long
ioid
,
unsigned
long
prot
)
{
return
(
prot
&
IOPT_PROT_MASK
)
|
(
IOPT_COHERENT
)
|
(
IOPT_ORDER_VC
)
|
(
real_address
&
IOPT_RPN_MASK
)
|
(
ioid
&
IOPT_IOID_MASK
);
}
typedef
struct
{
unsigned
long
val
;
}
ioste
;
static
inline
ioste
mk_ioste
(
unsigned
long
val
)
{
ioste
ioste
=
{
.
val
=
val
,
};
return
ioste
;
}
static
inline
ioste
get_iost_entry
(
unsigned
long
iopt_base
,
unsigned
long
io_address
,
unsigned
page_size
)
{
unsigned
long
ps
;
unsigned
long
iostep
;
unsigned
long
nnpt
;
unsigned
long
shift
;
switch
(
page_size
)
{
case
0x1000000
:
ps
=
IOST_PS_16M
;
nnpt
=
0
;
/* one page per segment */
shift
=
5
;
/* segment has 16 iopt entries */
break
;
case
0x100000
:
ps
=
IOST_PS_1M
;
nnpt
=
0
;
/* one page per segment */
shift
=
1
;
/* segment has 256 iopt entries */
break
;
case
0x10000
:
ps
=
IOST_PS_64K
;
nnpt
=
0x07
;
/* 8 pages per io page table */
shift
=
0
;
/* all entries are used */
break
;
case
0x1000
:
ps
=
IOST_PS_4K
;
nnpt
=
0x7f
;
/* 128 pages per io page table */
shift
=
0
;
/* all entries are used */
break
;
default:
/* not a known compile time constant */
BUILD_BUG_ON
(
1
);
break
;
}
iostep
=
iopt_base
+
/* need 8 bytes per iopte */
(((
io_address
/
page_size
*
8
)
/* align io page tables on 4k page boundaries */
<<
shift
)
/* nnpt+1 pages go into each iopt */
&
~
(
nnpt
<<
12
));
nnpt
++
;
/* this seems to work, but the documentation is not clear
about wether we put nnpt or nnpt-1 into the ioste bits.
In theory, this can't work for 4k pages. */
return
mk_ioste
(
IOST_VALID_MASK
|
(
iostep
&
IOST_PT_BASE_MASK
)
|
((
nnpt
<<
5
)
&
IOST_NNPT_MASK
)
|
(
ps
&
IOST_PS_MASK
));
}
/* compute the address of an io pte */
static
inline
unsigned
long
get_ioptep
(
ioste
iost_entry
,
unsigned
long
io_address
)
{
unsigned
long
iopt_base
;
unsigned
long
page_size
;
unsigned
long
page_number
;
unsigned
long
iopt_offset
;
iopt_base
=
iost_entry
.
val
&
IOST_PT_BASE_MASK
;
page_size
=
iost_entry
.
val
&
IOST_PS_MASK
;
/* decode page size to compute page number */
page_number
=
(
io_address
&
0x0fffffff
)
>>
(
10
+
2
*
page_size
);
/* page number is an offset into the io page table */
iopt_offset
=
(
page_number
<<
3
)
&
0x7fff8ul
;
return
iopt_base
+
iopt_offset
;
}
/* compute the tag field of the iopt cache entry */
static
inline
unsigned
long
get_ioc_tag
(
ioste
iost_entry
,
unsigned
long
io_address
)
{
unsigned
long
iopte
=
get_ioptep
(
iost_entry
,
io_address
);
return
IOPT_VALID_MASK
|
((
iopte
&
0x00000000000000ff8ul
)
>>
3
)
|
((
iopte
&
0x0000003fffffc0000ul
)
>>
9
);
}
/* compute the hashed 6 bit index for the 4-way associative pte cache */
static
inline
unsigned
long
get_ioc_hash
(
ioste
iost_entry
,
unsigned
long
io_address
)
{
unsigned
long
iopte
=
get_ioptep
(
iost_entry
,
io_address
);
return
((
iopte
&
0x000000000000001f8ul
)
>>
3
)
^
((
iopte
&
0x00000000000020000ul
)
>>
17
)
^
((
iopte
&
0x00000000000010000ul
)
>>
15
)
^
((
iopte
&
0x00000000000008000ul
)
>>
13
)
^
((
iopte
&
0x00000000000004000ul
)
>>
11
)
^
((
iopte
&
0x00000000000002000ul
)
>>
9
)
^
((
iopte
&
0x00000000000001000ul
)
>>
7
);
}
/* same as above, but pretend that we have a simpler 1-way associative
pte cache with an 8 bit index */
static
inline
unsigned
long
get_ioc_hash_1way
(
ioste
iost_entry
,
unsigned
long
io_address
)
{
unsigned
long
iopte
=
get_ioptep
(
iost_entry
,
io_address
);
return
((
iopte
&
0x000000000000001f8ul
)
>>
3
)
^
((
iopte
&
0x00000000000020000ul
)
>>
17
)
^
((
iopte
&
0x00000000000010000ul
)
>>
15
)
^
((
iopte
&
0x00000000000008000ul
)
>>
13
)
^
((
iopte
&
0x00000000000004000ul
)
>>
11
)
^
((
iopte
&
0x00000000000002000ul
)
>>
9
)
^
((
iopte
&
0x00000000000001000ul
)
>>
7
)
^
((
iopte
&
0x0000000000000c000ul
)
>>
8
);
}
static
inline
ioste
get_iost_cache
(
void
__iomem
*
base
,
unsigned
long
index
)
{
unsigned
long
__iomem
*
p
=
(
base
+
IOC_ST_CACHE_DIR
);
return
mk_ioste
(
in_be64
(
&
p
[
index
]));
}
static
inline
void
set_iost_cache
(
void
__iomem
*
base
,
unsigned
long
index
,
ioste
ste
)
{
unsigned
long
__iomem
*
p
=
(
base
+
IOC_ST_CACHE_DIR
);
pr_debug
(
"ioste %02lx was %016lx, store %016lx"
,
index
,
get_iost_cache
(
base
,
index
).
val
,
ste
.
val
);
out_be64
(
&
p
[
index
],
ste
.
val
);
pr_debug
(
" now %016lx
\n
"
,
get_iost_cache
(
base
,
index
).
val
);
}
static
inline
unsigned
long
get_iopt_cache
(
void
__iomem
*
base
,
unsigned
long
index
,
unsigned
long
*
tag
)
{
unsigned
long
__iomem
*
tags
=
(
void
*
)(
base
+
IOC_PT_CACHE_DIR
);
unsigned
long
__iomem
*
p
=
(
void
*
)(
base
+
IOC_PT_CACHE_REG
);
*
tag
=
tags
[
index
];
rmb
();
return
*
p
;
}
static
inline
void
set_iopt_cache
(
void
__iomem
*
base
,
unsigned
long
index
,
unsigned
long
tag
,
unsigned
long
val
)
{
unsigned
long
__iomem
*
tags
=
base
+
IOC_PT_CACHE_DIR
;
unsigned
long
__iomem
*
p
=
base
+
IOC_PT_CACHE_REG
;
pr_debug
(
"iopt %02lx was v%016lx/t%016lx, store v%016lx/t%016lx
\n
"
,
index
,
get_iopt_cache
(
base
,
index
,
&
oldtag
),
oldtag
,
val
,
tag
);
out_be64
(
p
,
val
);
out_be64
(
&
tags
[
index
],
tag
);
}
static
inline
void
set_iost_origin
(
void
__iomem
*
base
)
{
unsigned
long
__iomem
*
p
=
base
+
IOC_ST_ORIGIN
;
unsigned
long
origin
=
IOSTO_ENABLE
|
IOSTO_SW
;
pr_debug
(
"iost_origin %016lx, now %016lx
\n
"
,
in_be64
(
p
),
origin
);
out_be64
(
p
,
origin
);
}
static
inline
void
set_iocmd_config
(
void
__iomem
*
base
)
{
unsigned
long
__iomem
*
p
=
base
+
0xc00
;
unsigned
long
conf
;
conf
=
in_be64
(
p
);
pr_debug
(
"iost_conf %016lx, now %016lx
\n
"
,
conf
,
conf
|
IOCMD_CONF_TE
);
out_be64
(
p
,
conf
|
IOCMD_CONF_TE
);
}
/* FIXME: get these from the device tree */
#define ioc_base 0x20000511000ull
#define ioc_mmio_base 0x20000510000ull
#define ioid 0x48a
#define iopt_phys_offset (- 0x20000000)
/* We have a 512MB offset from the SB */
#define io_page_size 0x1000000
static
unsigned
long
map_iopt_entry
(
unsigned
long
address
)
{
switch
(
address
>>
20
)
{
case
0x600
:
address
=
0x24020000000ull
;
/* spider i/o */
break
;
default:
address
+=
iopt_phys_offset
;
break
;
}
return
get_iopt_entry
(
address
,
ioid
,
IOPT_PROT_RW
);
}
static
void
iommu_bus_setup_null
(
struct
pci_bus
*
b
)
{
}
static
void
iommu_dev_setup_null
(
struct
pci_dev
*
d
)
{
}
/* initialize the iommu to support a simple linear mapping
* for each DMA window used by any device. For now, we
* happen to know that there is only one DMA window in use,
* starting at iopt_phys_offset. */
static
void
bpa_map_iommu
(
void
)
{
unsigned
long
address
;
void
__iomem
*
base
;
ioste
ioste
;
unsigned
long
index
;
base
=
__ioremap
(
ioc_base
,
0x1000
,
_PAGE_NO_CACHE
);
pr_debug
(
"%lx mapped to %p
\n
"
,
ioc_base
,
base
);
set_iocmd_config
(
base
);
iounmap
(
base
);
base
=
__ioremap
(
ioc_mmio_base
,
0x1000
,
_PAGE_NO_CACHE
);
pr_debug
(
"%lx mapped to %p
\n
"
,
ioc_mmio_base
,
base
);
set_iost_origin
(
base
);
for
(
address
=
0
;
address
<
0x100000000ul
;
address
+=
io_page_size
)
{
ioste
=
get_iost_entry
(
0x10000000000ul
,
address
,
io_page_size
);
if
((
address
&
0xfffffff
)
==
0
)
/* segment start */
set_iost_cache
(
base
,
address
>>
28
,
ioste
);
index
=
get_ioc_hash_1way
(
ioste
,
address
);
pr_debug
(
"addr %08lx, index %02lx, ioste %016lx
\n
"
,
address
,
index
,
ioste
.
val
);
set_iopt_cache
(
base
,
get_ioc_hash_1way
(
ioste
,
address
),
get_ioc_tag
(
ioste
,
address
),
map_iopt_entry
(
address
));
}
iounmap
(
base
);
}
static
void
*
bpa_alloc_coherent
(
struct
device
*
hwdev
,
size_t
size
,
dma_addr_t
*
dma_handle
,
unsigned
int
__nocast
flag
)
{
void
*
ret
;
ret
=
(
void
*
)
__get_free_pages
(
flag
,
get_order
(
size
));
if
(
ret
!=
NULL
)
{
memset
(
ret
,
0
,
size
);
*
dma_handle
=
virt_to_abs
(
ret
)
|
BPA_DMA_VALID
;
}
return
ret
;
}
static
void
bpa_free_coherent
(
struct
device
*
hwdev
,
size_t
size
,
void
*
vaddr
,
dma_addr_t
dma_handle
)
{
free_pages
((
unsigned
long
)
vaddr
,
get_order
(
size
));
}
static
dma_addr_t
bpa_map_single
(
struct
device
*
hwdev
,
void
*
ptr
,
size_t
size
,
enum
dma_data_direction
direction
)
{
return
virt_to_abs
(
ptr
)
|
BPA_DMA_VALID
;
}
static
void
bpa_unmap_single
(
struct
device
*
hwdev
,
dma_addr_t
dma_addr
,
size_t
size
,
enum
dma_data_direction
direction
)
{
}
static
int
bpa_map_sg
(
struct
device
*
hwdev
,
struct
scatterlist
*
sg
,
int
nents
,
enum
dma_data_direction
direction
)
{
int
i
;
for
(
i
=
0
;
i
<
nents
;
i
++
,
sg
++
)
{
sg
->
dma_address
=
(
page_to_phys
(
sg
->
page
)
+
sg
->
offset
)
|
BPA_DMA_VALID
;
sg
->
dma_length
=
sg
->
length
;
}
return
nents
;
}
static
void
bpa_unmap_sg
(
struct
device
*
hwdev
,
struct
scatterlist
*
sg
,
int
nents
,
enum
dma_data_direction
direction
)
{
}
static
int
bpa_dma_supported
(
struct
device
*
dev
,
u64
mask
)
{
return
mask
<
0x100000000ull
;
}
void
bpa_init_iommu
(
void
)
{
bpa_map_iommu
();
/* Direct I/O, IOMMU off */
ppc_md
.
iommu_dev_setup
=
iommu_dev_setup_null
;
ppc_md
.
iommu_bus_setup
=
iommu_bus_setup_null
;
pci_dma_ops
.
alloc_coherent
=
bpa_alloc_coherent
;
pci_dma_ops
.
free_coherent
=
bpa_free_coherent
;
pci_dma_ops
.
map_single
=
bpa_map_single
;
pci_dma_ops
.
unmap_single
=
bpa_unmap_single
;
pci_dma_ops
.
map_sg
=
bpa_map_sg
;
pci_dma_ops
.
unmap_sg
=
bpa_unmap_sg
;
pci_dma_ops
.
dma_supported
=
bpa_dma_supported
;
}
arch/ppc64/kernel/bpa_iommu.h
0 → 100644
View file @
24665cd0
#ifndef BPA_IOMMU_H
#define BPA_IOMMU_H
/* some constants */
enum
{
/* segment table entries */
IOST_VALID_MASK
=
0x8000000000000000ul
,
IOST_TAG_MASK
=
0x3000000000000000ul
,
IOST_PT_BASE_MASK
=
0x000003fffffff000ul
,
IOST_NNPT_MASK
=
0x0000000000000fe0ul
,
IOST_PS_MASK
=
0x000000000000000ful
,
IOST_PS_4K
=
0x1
,
IOST_PS_64K
=
0x3
,
IOST_PS_1M
=
0x5
,
IOST_PS_16M
=
0x7
,
/* iopt tag register */
IOPT_VALID_MASK
=
0x0000000200000000ul
,
IOPT_TAG_MASK
=
0x00000001fffffffful
,
/* iopt cache register */
IOPT_PROT_MASK
=
0xc000000000000000ul
,
IOPT_PROT_NONE
=
0x0000000000000000ul
,
IOPT_PROT_READ
=
0x4000000000000000ul
,
IOPT_PROT_WRITE
=
0x8000000000000000ul
,
IOPT_PROT_RW
=
0xc000000000000000ul
,
IOPT_COHERENT
=
0x2000000000000000ul
,
IOPT_ORDER_MASK
=
0x1800000000000000ul
,
/* order access to same IOID/VC on same address */
IOPT_ORDER_ADDR
=
0x0800000000000000ul
,
/* similar, but only after a write access */
IOPT_ORDER_WRITES
=
0x1000000000000000ul
,
/* Order all accesses to same IOID/VC */
IOPT_ORDER_VC
=
0x1800000000000000ul
,
IOPT_RPN_MASK
=
0x000003fffffff000ul
,
IOPT_HINT_MASK
=
0x0000000000000800ul
,
IOPT_IOID_MASK
=
0x00000000000007fful
,
IOSTO_ENABLE
=
0x8000000000000000ul
,
IOSTO_ORIGIN
=
0x000003fffffff000ul
,
IOSTO_HW
=
0x0000000000000800ul
,
IOSTO_SW
=
0x0000000000000400ul
,
IOCMD_CONF_TE
=
0x0000800000000000ul
,
/* memory mapped registers */
IOC_PT_CACHE_DIR
=
0x000
,
IOC_ST_CACHE_DIR
=
0x800
,
IOC_PT_CACHE_REG
=
0x910
,
IOC_ST_ORIGIN
=
0x918
,
IOC_CONF
=
0x930
,
/* The high bit needs to be set on every DMA address,
only 2GB are addressable */
BPA_DMA_VALID
=
0x80000000
,
BPA_DMA_MASK
=
0x7fffffff
,
};
void
bpa_init_iommu
(
void
);
#endif
arch/ppc64/kernel/bpa_nvram.c
0 → 100644
View file @
24665cd0
/*
* NVRAM for CPBW
*
* (C) Copyright IBM Corp. 2005
*
* Authors : Utz Bacher <utz.bacher@de.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <asm/machdep.h>
#include <asm/nvram.h>
#include <asm/prom.h>
static
void
__iomem
*
bpa_nvram_start
;
static
long
bpa_nvram_len
;
static
spinlock_t
bpa_nvram_lock
=
SPIN_LOCK_UNLOCKED
;
static
ssize_t
bpa_nvram_read
(
char
*
buf
,
size_t
count
,
loff_t
*
index
)
{
unsigned
long
flags
;
if
(
*
index
>=
bpa_nvram_len
)
return
0
;
if
(
*
index
+
count
>
bpa_nvram_len
)
count
=
bpa_nvram_len
-
*
index
;
spin_lock_irqsave
(
&
bpa_nvram_lock
,
flags
);
memcpy_fromio
(
buf
,
bpa_nvram_start
+
*
index
,
count
);
spin_unlock_irqrestore
(
&
bpa_nvram_lock
,
flags
);
*
index
+=
count
;
return
count
;
}
static
ssize_t
bpa_nvram_write
(
char
*
buf
,
size_t
count
,
loff_t
*
index
)
{
unsigned
long
flags
;
if
(
*
index
>=
bpa_nvram_len
)
return
0
;
if
(
*
index
+
count
>
bpa_nvram_len
)
count
=
bpa_nvram_len
-
*
index
;
spin_lock_irqsave
(
&
bpa_nvram_lock
,
flags
);
memcpy_toio
(
bpa_nvram_start
+
*
index
,
buf
,
count
);
spin_unlock_irqrestore
(
&
bpa_nvram_lock
,
flags
);
*
index
+=
count
;
return
count
;
}
static
ssize_t
bpa_nvram_get_size
(
void
)
{
return
bpa_nvram_len
;
}
int
__init
bpa_nvram_init
(
void
)
{
struct
device_node
*
nvram_node
;
unsigned
long
*
buffer
;
int
proplen
;
unsigned
long
nvram_addr
;
int
ret
;
ret
=
-
ENODEV
;
nvram_node
=
of_find_node_by_type
(
NULL
,
"nvram"
);
if
(
!
nvram_node
)
goto
out
;
ret
=
-
EIO
;
buffer
=
(
unsigned
long
*
)
get_property
(
nvram_node
,
"reg"
,
&
proplen
);
if
(
proplen
!=
2
*
sizeof
(
unsigned
long
))
goto
out
;
ret
=
-
ENODEV
;
nvram_addr
=
buffer
[
0
];
bpa_nvram_len
=
buffer
[
1
];
if
(
(
!
bpa_nvram_len
)
||
(
!
nvram_addr
)
)
goto
out
;
bpa_nvram_start
=
ioremap
(
nvram_addr
,
bpa_nvram_len
);
if
(
!
bpa_nvram_start
)
goto
out
;
printk
(
KERN_INFO
"BPA NVRAM, %luk mapped to %p
\n
"
,
bpa_nvram_len
>>
10
,
bpa_nvram_start
);
ppc_md
.
nvram_read
=
bpa_nvram_read
;
ppc_md
.
nvram_write
=
bpa_nvram_write
;
ppc_md
.
nvram_size
=
bpa_nvram_get_size
;
out:
of_node_put
(
nvram_node
);
return
ret
;
}
arch/ppc64/kernel/bpa_setup.c
0 → 100644
View file @
24665cd0
/*
* linux/arch/ppc/kernel/bpa_setup.c
*
* Copyright (C) 1995 Linus Torvalds
* Adapted from 'alpha' version by Gary Thomas
* Modified by Cort Dougan (cort@cs.nmt.edu)
* Modified by PPC64 Team, IBM Corp
* Modified by BPA Team, IBM Deutschland Entwicklung GmbH
*
* 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.
*/
#undef DEBUG
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/console.h>
#include <asm/mmu.h>
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/pci-bridge.h>
#include <asm/iommu.h>
#include <asm/dma.h>
#include <asm/machdep.h>
#include <asm/time.h>
#include <asm/nvram.h>
#include <asm/cputable.h>
#include "pci.h"
#include "bpa_iic.h"
#include "bpa_iommu.h"
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
#else
#define DBG(fmt...)
#endif
void
bpa_get_cpuinfo
(
struct
seq_file
*
m
)
{
struct
device_node
*
root
;
const
char
*
model
=
""
;
root
=
of_find_node_by_path
(
"/"
);
if
(
root
)
model
=
get_property
(
root
,
"model"
,
NULL
);
seq_printf
(
m
,
"machine
\t\t
: BPA %s
\n
"
,
model
);
of_node_put
(
root
);
}
static
void
bpa_progress
(
char
*
s
,
unsigned
short
hex
)
{
printk
(
"*** %04x : %s
\n
"
,
hex
,
s
?
s
:
""
);
}
static
void
__init
bpa_setup_arch
(
void
)
{
ppc_md
.
init_IRQ
=
iic_init_IRQ
;
ppc_md
.
get_irq
=
iic_get_irq
;
#ifdef CONFIG_SMP
smp_init_pSeries
();
#endif
/* init to some ~sane value until calibrate_delay() runs */
loops_per_jiffy
=
50000000
;
if
(
ROOT_DEV
==
0
)
{
printk
(
"No ramdisk, default root is /dev/hda2
\n
"
);
ROOT_DEV
=
Root_HDA2
;
}
/* Find and initialize PCI host bridges */
init_pci_config_tokens
();
find_and_init_phbs
();
spider_init_IRQ
();
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp
=
&
dummy_con
;
#endif
bpa_nvram_init
();
}
/*
* Early initialization. Relocation is on but do not reference unbolted pages
*/
static
void
__init
bpa_init_early
(
void
)
{
DBG
(
" -> bpa_init_early()
\n
"
);
hpte_init_native
();
bpa_init_iommu
();
ppc64_interrupt_controller
=
IC_BPA_IIC
;
DBG
(
" <- bpa_init_early()
\n
"
);
}
static
int
__init
bpa_probe
(
int
platform
)
{
if
(
platform
!=
PLATFORM_BPA
)
return
0
;
return
1
;
}
struct
machdep_calls
__initdata
bpa_md
=
{
.
probe
=
bpa_probe
,
.
setup_arch
=
bpa_setup_arch
,
.
init_early
=
bpa_init_early
,
.
get_cpuinfo
=
bpa_get_cpuinfo
,
.
restart
=
rtas_restart
,
.
power_off
=
rtas_power_off
,
.
halt
=
rtas_halt
,
.
get_boot_time
=
rtas_get_boot_time
,
.
get_rtc_time
=
rtas_get_rtc_time
,
.
set_rtc_time
=
rtas_set_rtc_time
,
.
calibrate_decr
=
generic_calibrate_decr
,
.
progress
=
bpa_progress
,
};
arch/ppc64/kernel/cpu_setup_power4.S
View file @
24665cd0
...
...
@@ -74,6 +74,20 @@ _GLOBAL(__970_cpu_preinit)
_GLOBAL
(
__setup_cpu_power4
)
blr
_GLOBAL
(
__setup_cpu_be
)
/
*
Set
large
page
sizes
LP
=
0
:
16
MB
,
LP
=
1
:
64
KB
*/
addi
r3
,
0
,
0
ori
r3
,
r3
,
HID6_LB
sldi
r3
,
r3
,
32
nor
r3
,
r3
,
r3
mfspr
r4
,
SPRN_HID6
and
r4
,
r4
,
r3
addi
r3
,
0
,
0x02000
sldi
r3
,
r3
,
32
or
r4
,
r4
,
r3
mtspr
SPRN_HID6
,
r4
blr
_GLOBAL
(
__setup_cpu_ppc970
)
mfspr
r0
,
SPRN_HID0
li
r11
,
5
/*
clear
DOZE
and
SLEEP
*/
...
...
arch/ppc64/kernel/cputable.c
View file @
24665cd0
...
...
@@ -34,6 +34,7 @@ EXPORT_SYMBOL(cur_cpu_spec);
extern
void
__setup_cpu_power3
(
unsigned
long
offset
,
struct
cpu_spec
*
spec
);
extern
void
__setup_cpu_power4
(
unsigned
long
offset
,
struct
cpu_spec
*
spec
);
extern
void
__setup_cpu_ppc970
(
unsigned
long
offset
,
struct
cpu_spec
*
spec
);
extern
void
__setup_cpu_be
(
unsigned
long
offset
,
struct
cpu_spec
*
spec
);
/* We only set the altivec features if the kernel was compiled with altivec
...
...
@@ -162,6 +163,16 @@ struct cpu_spec cpu_specs[] = {
__setup_cpu_power4
,
COMMON_PPC64_FW
},
{
/* BE DD1.x */
0xffff0000
,
0x00700000
,
"Broadband Engine"
,
CPU_FTR_SPLIT_ID_CACHE
|
CPU_FTR_USE_TB
|
CPU_FTR_HPTE_TABLE
|
CPU_FTR_PPCAS_ARCH_V2
|
CPU_FTR_ALTIVEC_COMP
|
CPU_FTR_SMT
,
COMMON_USER_PPC64
|
PPC_FEATURE_HAS_ALTIVEC_COMP
,
128
,
128
,
__setup_cpu_be
,
COMMON_PPC64_FW
},
{
/* default match */
0x00000000
,
0x00000000
,
"POWER4 (compatible)"
,
CPU_FTR_SPLIT_ID_CACHE
|
CPU_FTR_USE_TB
|
CPU_FTR_HPTE_TABLE
|
...
...
arch/ppc64/kernel/iSeries_setup.c
View file @
24665cd0
...
...
@@ -671,9 +671,6 @@ static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr)
}
}
extern
unsigned
long
ppc_proc_freq
;
extern
unsigned
long
ppc_tb_freq
;
/*
* Document me.
*/
...
...
@@ -772,8 +769,6 @@ static void iSeries_halt(void)
mf_power_off
();
}
extern
void
setup_default_decr
(
void
);
/*
* void __init iSeries_calibrate_decr()
*
...
...
arch/ppc64/kernel/irq.c
View file @
24665cd0
...
...
@@ -395,6 +395,9 @@ int virt_irq_create_mapping(unsigned int real_irq)
if
(
ppc64_interrupt_controller
==
IC_OPEN_PIC
)
return
real_irq
;
/* no mapping for openpic (for now) */
if
(
ppc64_interrupt_controller
==
IC_BPA_IIC
)
return
real_irq
;
/* no mapping for iic either */
/* don't map interrupts < MIN_VIRT_IRQ */
if
(
real_irq
<
MIN_VIRT_IRQ
)
{
virt_irq_to_real_map
[
real_irq
]
=
real_irq
;
...
...
arch/ppc64/kernel/maple_setup.c
View file @
24665cd0
...
...
@@ -78,17 +78,77 @@ extern int maple_pci_get_legacy_ide_irq(struct pci_dev *dev, int channel);
extern
void
generic_find_legacy_serial_ports
(
u64
*
physport
,
unsigned
int
*
default_speed
);
static
void
maple_restart
(
char
*
cmd
)
{
unsigned
int
maple_nvram_base
;
unsigned
int
maple_nvram_offset
;
unsigned
int
maple_nvram_command
;
struct
device_node
*
rtcs
;
/* find NVRAM device */
rtcs
=
find_compatible_devices
(
"nvram"
,
"AMD8111"
);
if
(
rtcs
&&
rtcs
->
addrs
)
{
maple_nvram_base
=
rtcs
->
addrs
[
0
].
address
;
}
else
{
printk
(
KERN_EMERG
"Maple: Unable to find NVRAM
\n
"
);
printk
(
KERN_EMERG
"Maple: Manual Restart Required
\n
"
);
return
;
}
/* find service processor device */
rtcs
=
find_devices
(
"service-processor"
);
if
(
!
rtcs
)
{
printk
(
KERN_EMERG
"Maple: Unable to find Service Processor
\n
"
);
printk
(
KERN_EMERG
"Maple: Manual Restart Required
\n
"
);
return
;
}
maple_nvram_offset
=
*
(
unsigned
int
*
)
get_property
(
rtcs
,
"restart-addr"
,
NULL
);
maple_nvram_command
=
*
(
unsigned
int
*
)
get_property
(
rtcs
,
"restart-value"
,
NULL
);
/* send command */
outb_p
(
maple_nvram_command
,
maple_nvram_base
+
maple_nvram_offset
);
for
(;;)
;
}
static
void
maple_power_off
(
void
)
{
unsigned
int
maple_nvram_base
;
unsigned
int
maple_nvram_offset
;
unsigned
int
maple_nvram_command
;
struct
device_node
*
rtcs
;
/* find NVRAM device */
rtcs
=
find_compatible_devices
(
"nvram"
,
"AMD8111"
);
if
(
rtcs
&&
rtcs
->
addrs
)
{
maple_nvram_base
=
rtcs
->
addrs
[
0
].
address
;
}
else
{
printk
(
KERN_EMERG
"Maple: Unable to find NVRAM
\n
"
);
printk
(
KERN_EMERG
"Maple: Manual Power-Down Required
\n
"
);
return
;
}
/* find service processor device */
rtcs
=
find_devices
(
"service-processor"
);
if
(
!
rtcs
)
{
printk
(
KERN_EMERG
"Maple: Unable to find Service Processor
\n
"
);
printk
(
KERN_EMERG
"Maple: Manual Power-Down Required
\n
"
);
return
;
}
maple_nvram_offset
=
*
(
unsigned
int
*
)
get_property
(
rtcs
,
"power-off-addr"
,
NULL
);
maple_nvram_command
=
*
(
unsigned
int
*
)
get_property
(
rtcs
,
"power-off-value"
,
NULL
);
/* send command */
outb_p
(
maple_nvram_command
,
maple_nvram_base
+
maple_nvram_offset
);
for
(;;)
;
}
static
void
maple_halt
(
void
)
{
maple_power_off
();
}
#ifdef CONFIG_SMP
...
...
@@ -235,6 +295,6 @@ struct machdep_calls __initdata maple_md = {
.
get_boot_time
=
maple_get_boot_time
,
.
set_rtc_time
=
maple_set_rtc_time
,
.
get_rtc_time
=
maple_get_rtc_time
,
.
calibrate_decr
=
maple
_calibrate_decr
,
.
calibrate_decr
=
generic
_calibrate_decr
,
.
progress
=
maple_progress
,
};
arch/ppc64/kernel/maple_time.c
View file @
24665cd0
...
...
@@ -42,11 +42,8 @@
#define DBG(x...)
#endif
extern
void
setup_default_decr
(
void
);
extern
void
GregorianDay
(
struct
rtc_time
*
tm
);
extern
unsigned
long
ppc_tb_freq
;
extern
unsigned
long
ppc_proc_freq
;
static
int
maple_rtc_addr
;
static
int
maple_clock_read
(
int
addr
)
...
...
@@ -176,51 +173,3 @@ void __init maple_get_boot_time(struct rtc_time *tm)
maple_get_rtc_time
(
tm
);
}
/* XXX FIXME: Some sane defaults: 125 MHz timebase, 1GHz processor */
#define DEFAULT_TB_FREQ 125000000UL
#define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8)
void
__init
maple_calibrate_decr
(
void
)
{
struct
device_node
*
cpu
;
struct
div_result
divres
;
unsigned
int
*
fp
=
NULL
;
/*
* The cpu node should have a timebase-frequency property
* to tell us the rate at which the decrementer counts.
*/
cpu
=
of_find_node_by_type
(
NULL
,
"cpu"
);
ppc_tb_freq
=
DEFAULT_TB_FREQ
;
if
(
cpu
!=
0
)
fp
=
(
unsigned
int
*
)
get_property
(
cpu
,
"timebase-frequency"
,
NULL
);
if
(
fp
!=
NULL
)
ppc_tb_freq
=
*
fp
;
else
printk
(
KERN_ERR
"WARNING: Estimating decrementer frequency (not found)
\n
"
);
fp
=
NULL
;
ppc_proc_freq
=
DEFAULT_PROC_FREQ
;
if
(
cpu
!=
0
)
fp
=
(
unsigned
int
*
)
get_property
(
cpu
,
"clock-frequency"
,
NULL
);
if
(
fp
!=
NULL
)
ppc_proc_freq
=
*
fp
;
else
printk
(
KERN_ERR
"WARNING: Estimating processor frequency (not found)
\n
"
);
of_node_put
(
cpu
);
printk
(
KERN_INFO
"time_init: decrementer frequency = %lu.%.6lu MHz
\n
"
,
ppc_tb_freq
/
1000000
,
ppc_tb_freq
%
1000000
);
printk
(
KERN_INFO
"time_init: processor frequency = %lu.%.6lu MHz
\n
"
,
ppc_proc_freq
/
1000000
,
ppc_proc_freq
%
1000000
);
tb_ticks_per_jiffy
=
ppc_tb_freq
/
HZ
;
tb_ticks_per_sec
=
tb_ticks_per_jiffy
*
HZ
;
tb_ticks_per_usec
=
ppc_tb_freq
/
1000000
;
tb_to_us
=
mulhwu_scale_factor
(
ppc_tb_freq
,
1000000
);
div128_by_32
(
1024
*
1024
,
0
,
tb_ticks_per_sec
,
&
divres
);
tb_to_xs
=
divres
.
result_low
;
setup_default_decr
();
}
arch/ppc64/kernel/mpic.h
View file @
24665cd0
...
...
@@ -265,3 +265,6 @@ extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask);
extern
int
mpic_get_one_irq
(
struct
mpic
*
mpic
,
struct
pt_regs
*
regs
);
/* This one gets to the primary mpic */
extern
int
mpic_get_irq
(
struct
pt_regs
*
regs
);
/* global mpic for pSeries */
extern
struct
mpic
*
pSeries_mpic
;
arch/ppc64/kernel/pSeries_pci.c
View file @
24665cd0
/*
* pSeries_pci.c
*
arch/ppc64/kernel/
pSeries_pci.c
*
* Copyright (C) 2001 Dave Engebretsen, IBM Corporation
* Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
*
* pSeries specific routines for PCI.
*
* Based on code from pci.c and chrp_pci.c
*
* 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
...
...
@@ -23,430 +21,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/threads.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/iommu.h>
#include <asm/rtas.h>
#include <asm/prom.h>
#include "mpic.h"
#include "pci.h"
/* RTAS tokens */
static
int
read_pci_config
;
static
int
write_pci_config
;
static
int
ibm_read_pci_config
;
static
int
ibm_write_pci_config
;
static
int
s7a_workaround
;
extern
struct
mpic
*
pSeries_mpic
;
static
int
config_access_valid
(
struct
device_node
*
dn
,
int
where
)
{
if
(
where
<
256
)
return
1
;
if
(
where
<
4096
&&
dn
->
pci_ext_config_space
)
return
1
;
return
0
;
}
static
int
rtas_read_config
(
struct
device_node
*
dn
,
int
where
,
int
size
,
u32
*
val
)
{
int
returnval
=
-
1
;
unsigned
long
buid
,
addr
;
int
ret
;
if
(
!
dn
)
return
PCIBIOS_DEVICE_NOT_FOUND
;
if
(
!
config_access_valid
(
dn
,
where
))
return
PCIBIOS_BAD_REGISTER_NUMBER
;
addr
=
((
where
&
0xf00
)
<<
20
)
|
(
dn
->
busno
<<
16
)
|
(
dn
->
devfn
<<
8
)
|
(
where
&
0xff
);
buid
=
dn
->
phb
->
buid
;
if
(
buid
)
{
ret
=
rtas_call
(
ibm_read_pci_config
,
4
,
2
,
&
returnval
,
addr
,
buid
>>
32
,
buid
&
0xffffffff
,
size
);
}
else
{
ret
=
rtas_call
(
read_pci_config
,
2
,
2
,
&
returnval
,
addr
,
size
);
}
*
val
=
returnval
;
if
(
ret
)
return
PCIBIOS_DEVICE_NOT_FOUND
;
if
(
returnval
==
EEH_IO_ERROR_VALUE
(
size
)
&&
eeh_dn_check_failure
(
dn
,
NULL
))
return
PCIBIOS_DEVICE_NOT_FOUND
;
return
PCIBIOS_SUCCESSFUL
;
}
static
int
rtas_pci_read_config
(
struct
pci_bus
*
bus
,
unsigned
int
devfn
,
int
where
,
int
size
,
u32
*
val
)
{
struct
device_node
*
busdn
,
*
dn
;
if
(
bus
->
self
)
busdn
=
pci_device_to_OF_node
(
bus
->
self
);
else
busdn
=
bus
->
sysdata
;
/* must be a phb */
/* Search only direct children of the bus */
for
(
dn
=
busdn
->
child
;
dn
;
dn
=
dn
->
sibling
)
if
(
dn
->
devfn
==
devfn
)
return
rtas_read_config
(
dn
,
where
,
size
,
val
);
return
PCIBIOS_DEVICE_NOT_FOUND
;
}
static
int
rtas_write_config
(
struct
device_node
*
dn
,
int
where
,
int
size
,
u32
val
)
{
unsigned
long
buid
,
addr
;
int
ret
;
if
(
!
dn
)
return
PCIBIOS_DEVICE_NOT_FOUND
;
if
(
!
config_access_valid
(
dn
,
where
))
return
PCIBIOS_BAD_REGISTER_NUMBER
;
addr
=
((
where
&
0xf00
)
<<
20
)
|
(
dn
->
busno
<<
16
)
|
(
dn
->
devfn
<<
8
)
|
(
where
&
0xff
);
buid
=
dn
->
phb
->
buid
;
if
(
buid
)
{
ret
=
rtas_call
(
ibm_write_pci_config
,
5
,
1
,
NULL
,
addr
,
buid
>>
32
,
buid
&
0xffffffff
,
size
,
(
ulong
)
val
);
}
else
{
ret
=
rtas_call
(
write_pci_config
,
3
,
1
,
NULL
,
addr
,
size
,
(
ulong
)
val
);
}
if
(
ret
)
return
PCIBIOS_DEVICE_NOT_FOUND
;
return
PCIBIOS_SUCCESSFUL
;
}
static
int
rtas_pci_write_config
(
struct
pci_bus
*
bus
,
unsigned
int
devfn
,
int
where
,
int
size
,
u32
val
)
{
struct
device_node
*
busdn
,
*
dn
;
if
(
bus
->
self
)
busdn
=
pci_device_to_OF_node
(
bus
->
self
);
else
busdn
=
bus
->
sysdata
;
/* must be a phb */
/* Search only direct children of the bus */
for
(
dn
=
busdn
->
child
;
dn
;
dn
=
dn
->
sibling
)
if
(
dn
->
devfn
==
devfn
)
return
rtas_write_config
(
dn
,
where
,
size
,
val
);
return
PCIBIOS_DEVICE_NOT_FOUND
;
}
struct
pci_ops
rtas_pci_ops
=
{
rtas_pci_read_config
,
rtas_pci_write_config
};
int
is_python
(
struct
device_node
*
dev
)
{
char
*
model
=
(
char
*
)
get_property
(
dev
,
"model"
,
NULL
);
if
(
model
&&
strstr
(
model
,
"Python"
))
return
1
;
return
0
;
}
static
int
get_phb_reg_prop
(
struct
device_node
*
dev
,
unsigned
int
addr_size_words
,
struct
reg_property64
*
reg
)
{
unsigned
int
*
ui_ptr
=
NULL
,
len
;
/* Found a PHB, now figure out where his registers are mapped. */
ui_ptr
=
(
unsigned
int
*
)
get_property
(
dev
,
"reg"
,
&
len
);
if
(
ui_ptr
==
NULL
)
return
1
;
if
(
addr_size_words
==
1
)
{
reg
->
address
=
((
struct
reg_property32
*
)
ui_ptr
)
->
address
;
reg
->
size
=
((
struct
reg_property32
*
)
ui_ptr
)
->
size
;
}
else
{
*
reg
=
*
((
struct
reg_property64
*
)
ui_ptr
);
}
return
0
;
}
static
void
python_countermeasures
(
struct
device_node
*
dev
,
unsigned
int
addr_size_words
)
{
struct
reg_property64
reg_struct
;
void
__iomem
*
chip_regs
;
volatile
u32
val
;
if
(
get_phb_reg_prop
(
dev
,
addr_size_words
,
&
reg_struct
))
return
;
/* Python's register file is 1 MB in size. */
chip_regs
=
ioremap
(
reg_struct
.
address
&
~
(
0xfffffUL
),
0x100000
);
/*
* Firmware doesn't always clear this bit which is critical
* for good performance - Anton
*/
#define PRG_CL_RESET_VALID 0x00010000
val
=
in_be32
(
chip_regs
+
0xf6030
);
if
(
val
&
PRG_CL_RESET_VALID
)
{
printk
(
KERN_INFO
"Python workaround: "
);
val
&=
~
PRG_CL_RESET_VALID
;
out_be32
(
chip_regs
+
0xf6030
,
val
);
/*
* We must read it back for changes to
* take effect
*/
val
=
in_be32
(
chip_regs
+
0xf6030
);
printk
(
"reg0: %x
\n
"
,
val
);
}
iounmap
(
chip_regs
);
}
void
__init
init_pci_config_tokens
(
void
)
{
read_pci_config
=
rtas_token
(
"read-pci-config"
);
write_pci_config
=
rtas_token
(
"write-pci-config"
);
ibm_read_pci_config
=
rtas_token
(
"ibm,read-pci-config"
);
ibm_write_pci_config
=
rtas_token
(
"ibm,write-pci-config"
);
}
unsigned
long
__devinit
get_phb_buid
(
struct
device_node
*
phb
)
{
int
addr_cells
;
unsigned
int
*
buid_vals
;
unsigned
int
len
;
unsigned
long
buid
;
if
(
ibm_read_pci_config
==
-
1
)
return
0
;
/* PHB's will always be children of the root node,
* or so it is promised by the current firmware. */
if
(
phb
->
parent
==
NULL
)
return
0
;
if
(
phb
->
parent
->
parent
)
return
0
;
buid_vals
=
(
unsigned
int
*
)
get_property
(
phb
,
"reg"
,
&
len
);
if
(
buid_vals
==
NULL
)
return
0
;
addr_cells
=
prom_n_addr_cells
(
phb
);
if
(
addr_cells
==
1
)
{
buid
=
(
unsigned
long
)
buid_vals
[
0
];
}
else
{
buid
=
(((
unsigned
long
)
buid_vals
[
0
])
<<
32UL
)
|
(((
unsigned
long
)
buid_vals
[
1
])
&
0xffffffff
);
}
return
buid
;
}
static
int
phb_set_bus_ranges
(
struct
device_node
*
dev
,
struct
pci_controller
*
phb
)
{
int
*
bus_range
;
unsigned
int
len
;
bus_range
=
(
int
*
)
get_property
(
dev
,
"bus-range"
,
&
len
);
if
(
bus_range
==
NULL
||
len
<
2
*
sizeof
(
int
))
{
return
1
;
}
phb
->
first_busno
=
bus_range
[
0
];
phb
->
last_busno
=
bus_range
[
1
];
return
0
;
}
static
int
__devinit
setup_phb
(
struct
device_node
*
dev
,
struct
pci_controller
*
phb
,
unsigned
int
addr_size_words
)
{
pci_setup_pci_controller
(
phb
);
if
(
is_python
(
dev
))
python_countermeasures
(
dev
,
addr_size_words
);
if
(
phb_set_bus_ranges
(
dev
,
phb
))
return
1
;
phb
->
arch_data
=
dev
;
phb
->
ops
=
&
rtas_pci_ops
;
phb
->
buid
=
get_phb_buid
(
dev
);
return
0
;
}
static
void
__devinit
add_linux_pci_domain
(
struct
device_node
*
dev
,
struct
pci_controller
*
phb
,
struct
property
*
of_prop
)
{
memset
(
of_prop
,
0
,
sizeof
(
struct
property
));
of_prop
->
name
=
"linux,pci-domain"
;
of_prop
->
length
=
sizeof
(
phb
->
global_number
);
of_prop
->
value
=
(
unsigned
char
*
)
&
of_prop
[
1
];
memcpy
(
of_prop
->
value
,
&
phb
->
global_number
,
sizeof
(
phb
->
global_number
));
prom_add_property
(
dev
,
of_prop
);
}
static
struct
pci_controller
*
__init
alloc_phb
(
struct
device_node
*
dev
,
unsigned
int
addr_size_words
)
{
struct
pci_controller
*
phb
;
struct
property
*
of_prop
;
phb
=
alloc_bootmem
(
sizeof
(
struct
pci_controller
));
if
(
phb
==
NULL
)
return
NULL
;
of_prop
=
alloc_bootmem
(
sizeof
(
struct
property
)
+
sizeof
(
phb
->
global_number
));
if
(
!
of_prop
)
return
NULL
;
if
(
setup_phb
(
dev
,
phb
,
addr_size_words
))
return
NULL
;
add_linux_pci_domain
(
dev
,
phb
,
of_prop
);
return
phb
;
}
static
struct
pci_controller
*
__devinit
alloc_phb_dynamic
(
struct
device_node
*
dev
,
unsigned
int
addr_size_words
)
{
struct
pci_controller
*
phb
;
phb
=
(
struct
pci_controller
*
)
kmalloc
(
sizeof
(
struct
pci_controller
),
GFP_KERNEL
);
if
(
phb
==
NULL
)
return
NULL
;
if
(
setup_phb
(
dev
,
phb
,
addr_size_words
))
return
NULL
;
phb
->
is_dynamic
=
1
;
/* TODO: linux,pci-domain? */
return
phb
;
}
unsigned
long
__init
find_and_init_phbs
(
void
)
{
struct
device_node
*
node
;
struct
pci_controller
*
phb
;
unsigned
int
root_size_cells
=
0
;
unsigned
int
index
;
unsigned
int
*
opprop
=
NULL
;
struct
device_node
*
root
=
of_find_node_by_path
(
"/"
);
if
(
ppc64_interrupt_controller
==
IC_OPEN_PIC
)
{
opprop
=
(
unsigned
int
*
)
get_property
(
root
,
"platform-open-pic"
,
NULL
);
}
root_size_cells
=
prom_n_size_cells
(
root
);
index
=
0
;
for
(
node
=
of_get_next_child
(
root
,
NULL
);
node
!=
NULL
;
node
=
of_get_next_child
(
root
,
node
))
{
if
(
node
->
type
==
NULL
||
strcmp
(
node
->
type
,
"pci"
)
!=
0
)
continue
;
phb
=
alloc_phb
(
node
,
root_size_cells
);
if
(
!
phb
)
continue
;
pci_process_bridge_OF_ranges
(
phb
,
node
);
pci_setup_phb_io
(
phb
,
index
==
0
);
if
(
ppc64_interrupt_controller
==
IC_OPEN_PIC
&&
pSeries_mpic
)
{
int
addr
=
root_size_cells
*
(
index
+
2
)
-
1
;
mpic_assign_isu
(
pSeries_mpic
,
index
,
opprop
[
addr
]);
}
index
++
;
}
of_node_put
(
root
);
pci_devs_phb_init
();
/*
* pci_probe_only and pci_assign_all_buses can be set via properties
* in chosen.
*/
if
(
of_chosen
)
{
int
*
prop
;
prop
=
(
int
*
)
get_property
(
of_chosen
,
"linux,pci-probe-only"
,
NULL
);
if
(
prop
)
pci_probe_only
=
*
prop
;
prop
=
(
int
*
)
get_property
(
of_chosen
,
"linux,pci-assign-all-buses"
,
NULL
);
if
(
prop
)
pci_assign_all_buses
=
*
prop
;
}
return
0
;
}
struct
pci_controller
*
__devinit
init_phb_dynamic
(
struct
device_node
*
dn
)
{
struct
device_node
*
root
=
of_find_node_by_path
(
"/"
);
unsigned
int
root_size_cells
=
0
;
struct
pci_controller
*
phb
;
struct
pci_bus
*
bus
;
int
primary
;
root_size_cells
=
prom_n_size_cells
(
root
);
primary
=
list_empty
(
&
hose_list
);
phb
=
alloc_phb_dynamic
(
dn
,
root_size_cells
);
if
(
!
phb
)
return
NULL
;
pci_process_bridge_OF_ranges
(
phb
,
dn
);
pci_setup_phb_io_dynamic
(
phb
,
primary
);
of_node_put
(
root
);
pci_devs_phb_init_dynamic
(
phb
);
phb
->
last_busno
=
0xff
;
bus
=
pci_scan_bus
(
phb
->
first_busno
,
phb
->
ops
,
phb
->
arch_data
);
phb
->
bus
=
bus
;
phb
->
last_busno
=
bus
->
subordinate
;
return
phb
;
}
EXPORT_SYMBOL
(
init_phb_dynamic
);
static
int
__initdata
s7a_workaround
=
-
1
;
#if 0
void pcibios_name_device(struct pci_dev *dev)
...
...
@@ -474,11 +60,12 @@ void pcibios_name_device(struct pci_dev *dev)
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device);
#endif
static
void
check_s7a
(
void
)
static
void
__init
check_s7a
(
void
)
{
struct
device_node
*
root
;
char
*
model
;
s7a_workaround
=
0
;
root
=
of_find_node_by_path
(
"/"
);
if
(
root
)
{
model
=
get_property
(
root
,
"model"
,
NULL
);
...
...
@@ -488,55 +75,23 @@ static void check_s7a(void)
}
}
/* RPA-specific bits for removing PHBs */
int
pcibios_remove_root_bus
(
struct
pci_controller
*
phb
)
void
__devinit
pSeries_irq_bus_setup
(
struct
pci_bus
*
bus
)
{
struct
pci_bus
*
b
=
phb
->
bus
;
struct
resource
*
res
;
int
rc
,
i
;
res
=
b
->
resource
[
0
];
if
(
!
res
->
flags
)
{
printk
(
KERN_ERR
"%s: no IO resource for PHB %s
\n
"
,
__FUNCTION__
,
b
->
name
);
return
1
;
}
rc
=
unmap_bus_range
(
b
);
if
(
rc
)
{
printk
(
KERN_ERR
"%s: failed to unmap IO on bus %s
\n
"
,
__FUNCTION__
,
b
->
name
);
return
1
;
}
struct
pci_dev
*
dev
;
if
(
release_resource
(
res
))
{
printk
(
KERN_ERR
"%s: failed to release IO on bus %s
\n
"
,
__FUNCTION__
,
b
->
name
);
return
1
;
}
for
(
i
=
1
;
i
<
3
;
++
i
)
{
res
=
b
->
resource
[
i
];
if
(
!
res
->
flags
&&
i
==
0
)
{
printk
(
KERN_ERR
"%s: no MEM resource for PHB %s
\n
"
,
__FUNCTION__
,
b
->
name
);
return
1
;
if
(
s7a_workaround
<
0
)
check_s7a
();
list_for_each_entry
(
dev
,
&
bus
->
devices
,
bus_list
)
{
pci_read_irq_line
(
dev
);
if
(
s7a_workaround
)
{
if
(
dev
->
irq
>
16
)
{
dev
->
irq
-=
3
;
pci_write_config_byte
(
dev
,
PCI_INTERRUPT_LINE
,
dev
->
irq
);
}
if
(
res
->
flags
&&
release_resource
(
res
))
{
printk
(
KERN_ERR
"%s: failed to release IO %d on bus %s
\n
"
,
__FUNCTION__
,
i
,
b
->
name
);
return
1
;
}
}
list_del
(
&
phb
->
list_node
);
if
(
phb
->
is_dynamic
)
kfree
(
phb
);
return
0
;
}
EXPORT_SYMBOL
(
pcibios_remove_root_bus
);
static
void
__init
pSeries_request_regions
(
void
)
{
...
...
@@ -553,20 +108,6 @@ static void __init pSeries_request_regions(void)
void
__init
pSeries_final_fixup
(
void
)
{
struct
pci_dev
*
dev
=
NULL
;
check_s7a
();
for_each_pci_dev
(
dev
)
{
pci_read_irq_line
(
dev
);
if
(
s7a_workaround
)
{
if
(
dev
->
irq
>
16
)
{
dev
->
irq
-=
3
;
pci_write_config_byte
(
dev
,
PCI_INTERRUPT_LINE
,
dev
->
irq
);
}
}
}
phbs_remap_io
();
pSeries_request_regions
();
...
...
arch/ppc64/kernel/pSeries_setup.c
View file @
24665cd0
...
...
@@ -71,11 +71,6 @@
#define DBG(fmt...)
#endif
extern
void
pSeries_final_fixup
(
void
);
extern
void
pSeries_get_boot_time
(
struct
rtc_time
*
rtc_time
);
extern
void
pSeries_get_rtc_time
(
struct
rtc_time
*
rtc_time
);
extern
int
pSeries_set_rtc_time
(
struct
rtc_time
*
rtc_time
);
extern
void
find_udbg_vterm
(
void
);
extern
void
system_reset_fwnmi
(
void
);
/* from head.S */
extern
void
machine_check_fwnmi
(
void
);
/* from head.S */
...
...
@@ -84,9 +79,6 @@ extern void generic_find_legacy_serial_ports(u64 *physport,
int
fwnmi_active
;
/* TRUE if an FWNMI handler is present */
extern
unsigned
long
ppc_proc_freq
;
extern
unsigned
long
ppc_tb_freq
;
extern
void
pSeries_system_reset_exception
(
struct
pt_regs
*
regs
);
extern
int
pSeries_machine_check_exception
(
struct
pt_regs
*
regs
);
...
...
@@ -381,171 +373,6 @@ static void __init pSeries_init_early(void)
}
static
void
pSeries_progress
(
char
*
s
,
unsigned
short
hex
)
{
struct
device_node
*
root
;
int
width
,
*
p
;
char
*
os
;
static
int
display_character
,
set_indicator
;
static
int
max_width
;
static
DEFINE_SPINLOCK
(
progress_lock
);
static
int
pending_newline
=
0
;
/* did last write end with unprinted newline? */
if
(
!
rtas
.
base
)
return
;
if
(
max_width
==
0
)
{
if
((
root
=
find_path_device
(
"/rtas"
))
&&
(
p
=
(
unsigned
int
*
)
get_property
(
root
,
"ibm,display-line-length"
,
NULL
)))
max_width
=
*
p
;
else
max_width
=
0x10
;
display_character
=
rtas_token
(
"display-character"
);
set_indicator
=
rtas_token
(
"set-indicator"
);
}
if
(
display_character
==
RTAS_UNKNOWN_SERVICE
)
{
/* use hex display if available */
if
(
set_indicator
!=
RTAS_UNKNOWN_SERVICE
)
rtas_call
(
set_indicator
,
3
,
1
,
NULL
,
6
,
0
,
hex
);
return
;
}
spin_lock
(
&
progress_lock
);
/*
* Last write ended with newline, but we didn't print it since
* it would just clear the bottom line of output. Print it now
* instead.
*
* If no newline is pending, print a CR to start output at the
* beginning of the line.
*/
if
(
pending_newline
)
{
rtas_call
(
display_character
,
1
,
1
,
NULL
,
'\r'
);
rtas_call
(
display_character
,
1
,
1
,
NULL
,
'\n'
);
pending_newline
=
0
;
}
else
{
rtas_call
(
display_character
,
1
,
1
,
NULL
,
'\r'
);
}
width
=
max_width
;
os
=
s
;
while
(
*
os
)
{
if
(
*
os
==
'\n'
||
*
os
==
'\r'
)
{
/* Blank to end of line. */
while
(
width
--
>
0
)
rtas_call
(
display_character
,
1
,
1
,
NULL
,
' '
);
/* If newline is the last character, save it
* until next call to avoid bumping up the
* display output.
*/
if
(
*
os
==
'\n'
&&
!
os
[
1
])
{
pending_newline
=
1
;
spin_unlock
(
&
progress_lock
);
return
;
}
/* RTAS wants CR-LF, not just LF */
if
(
*
os
==
'\n'
)
{
rtas_call
(
display_character
,
1
,
1
,
NULL
,
'\r'
);
rtas_call
(
display_character
,
1
,
1
,
NULL
,
'\n'
);
}
else
{
/* CR might be used to re-draw a line, so we'll
* leave it alone and not add LF.
*/
rtas_call
(
display_character
,
1
,
1
,
NULL
,
*
os
);
}
width
=
max_width
;
}
else
{
width
--
;
rtas_call
(
display_character
,
1
,
1
,
NULL
,
*
os
);
}
os
++
;
/* if we overwrite the screen length */
if
(
width
<=
0
)
while
((
*
os
!=
0
)
&&
(
*
os
!=
'\n'
)
&&
(
*
os
!=
'\r'
))
os
++
;
}
/* Blank to end of line. */
while
(
width
--
>
0
)
rtas_call
(
display_character
,
1
,
1
,
NULL
,
' '
);
spin_unlock
(
&
progress_lock
);
}
extern
void
setup_default_decr
(
void
);
/* Some sane defaults: 125 MHz timebase, 1GHz processor */
#define DEFAULT_TB_FREQ 125000000UL
#define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8)
static
void
__init
pSeries_calibrate_decr
(
void
)
{
struct
device_node
*
cpu
;
struct
div_result
divres
;
unsigned
int
*
fp
;
int
node_found
;
/*
* The cpu node should have a timebase-frequency property
* to tell us the rate at which the decrementer counts.
*/
cpu
=
of_find_node_by_type
(
NULL
,
"cpu"
);
ppc_tb_freq
=
DEFAULT_TB_FREQ
;
/* hardcoded default */
node_found
=
0
;
if
(
cpu
!=
0
)
{
fp
=
(
unsigned
int
*
)
get_property
(
cpu
,
"timebase-frequency"
,
NULL
);
if
(
fp
!=
0
)
{
node_found
=
1
;
ppc_tb_freq
=
*
fp
;
}
}
if
(
!
node_found
)
printk
(
KERN_ERR
"WARNING: Estimating decrementer frequency "
"(not found)
\n
"
);
ppc_proc_freq
=
DEFAULT_PROC_FREQ
;
node_found
=
0
;
if
(
cpu
!=
0
)
{
fp
=
(
unsigned
int
*
)
get_property
(
cpu
,
"clock-frequency"
,
NULL
);
if
(
fp
!=
0
)
{
node_found
=
1
;
ppc_proc_freq
=
*
fp
;
}
}
if
(
!
node_found
)
printk
(
KERN_ERR
"WARNING: Estimating processor frequency "
"(not found)
\n
"
);
of_node_put
(
cpu
);
printk
(
KERN_INFO
"time_init: decrementer frequency = %lu.%.6lu MHz
\n
"
,
ppc_tb_freq
/
1000000
,
ppc_tb_freq
%
1000000
);
printk
(
KERN_INFO
"time_init: processor frequency = %lu.%.6lu MHz
\n
"
,
ppc_proc_freq
/
1000000
,
ppc_proc_freq
%
1000000
);
tb_ticks_per_jiffy
=
ppc_tb_freq
/
HZ
;
tb_ticks_per_sec
=
tb_ticks_per_jiffy
*
HZ
;
tb_ticks_per_usec
=
ppc_tb_freq
/
1000000
;
tb_to_us
=
mulhwu_scale_factor
(
ppc_tb_freq
,
1000000
);
div128_by_32
(
1024
*
1024
,
0
,
tb_ticks_per_sec
,
&
divres
);
tb_to_xs
=
divres
.
result_low
;
setup_default_decr
();
}
static
int
pSeries_check_legacy_ioport
(
unsigned
int
baseport
)
{
struct
device_node
*
np
;
...
...
@@ -596,16 +423,17 @@ struct machdep_calls __initdata pSeries_md = {
.
get_cpuinfo
=
pSeries_get_cpuinfo
,
.
log_error
=
pSeries_log_error
,
.
pcibios_fixup
=
pSeries_final_fixup
,
.
irq_bus_setup
=
pSeries_irq_bus_setup
,
.
restart
=
rtas_restart
,
.
power_off
=
rtas_power_off
,
.
halt
=
rtas_halt
,
.
panic
=
rtas_os_term
,
.
cpu_die
=
pSeries_mach_cpu_die
,
.
get_boot_time
=
pSerie
s_get_boot_time
,
.
get_rtc_time
=
pSerie
s_get_rtc_time
,
.
set_rtc_time
=
pSerie
s_set_rtc_time
,
.
calibrate_decr
=
pSeries
_calibrate_decr
,
.
progress
=
pSerie
s_progress
,
.
get_boot_time
=
rta
s_get_boot_time
,
.
get_rtc_time
=
rta
s_get_rtc_time
,
.
set_rtc_time
=
rta
s_set_rtc_time
,
.
calibrate_decr
=
generic
_calibrate_decr
,
.
progress
=
rta
s_progress
,
.
check_legacy_ioport
=
pSeries_check_legacy_ioport
,
.
system_reset_exception
=
pSeries_system_reset_exception
,
.
machine_check_exception
=
pSeries_machine_check_exception
,
...
...
arch/ppc64/kernel/pSeries_smp.c
View file @
24665cd0
/*
* SMP support for pSeries machines.
* SMP support for pSeries
and BPA
machines.
*
* Dave Engebretsen, Peter Bergner, and
* Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
...
...
@@ -47,6 +47,7 @@
#include <asm/pSeries_reconfig.h>
#include "mpic.h"
#include "bpa_iic.h"
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
...
...
@@ -286,6 +287,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu)
return
1
;
}
#ifdef CONFIG_XICS
static
inline
void
smp_xics_do_message
(
int
cpu
,
int
msg
)
{
set_bit
(
msg
,
&
xics_ipi_message
[
cpu
].
value
);
...
...
@@ -327,6 +329,37 @@ static void __devinit smp_xics_setup_cpu(int cpu)
cpu_clear
(
cpu
,
of_spin_map
);
}
#endif
/* CONFIG_XICS */
#ifdef CONFIG_BPA_IIC
static
void
smp_iic_message_pass
(
int
target
,
int
msg
)
{
unsigned
int
i
;
if
(
target
<
NR_CPUS
)
{
iic_cause_IPI
(
target
,
msg
);
}
else
{
for_each_online_cpu
(
i
)
{
if
(
target
==
MSG_ALL_BUT_SELF
&&
i
==
smp_processor_id
())
continue
;
iic_cause_IPI
(
i
,
msg
);
}
}
}
static
int
__init
smp_iic_probe
(
void
)
{
iic_request_IPIs
();
return
cpus_weight
(
cpu_possible_map
);
}
static
void
__devinit
smp_iic_setup_cpu
(
int
cpu
)
{
if
(
cpu
!=
boot_cpuid
)
iic_setup_cpu
();
}
#endif
/* CONFIG_BPA_IIC */
static
DEFINE_SPINLOCK
(
timebase_lock
);
static
unsigned
long
timebase
=
0
;
...
...
@@ -381,14 +414,15 @@ static int smp_pSeries_cpu_bootable(unsigned int nr)
return
1
;
}
#ifdef CONFIG_MPIC
static
struct
smp_ops_t
pSeries_mpic_smp_ops
=
{
.
message_pass
=
smp_mpic_message_pass
,
.
probe
=
smp_mpic_probe
,
.
kick_cpu
=
smp_pSeries_kick_cpu
,
.
setup_cpu
=
smp_mpic_setup_cpu
,
};
#endif
#ifdef CONFIG_XICS
static
struct
smp_ops_t
pSeries_xics_smp_ops
=
{
.
message_pass
=
smp_xics_message_pass
,
.
probe
=
smp_xics_probe
,
...
...
@@ -396,6 +430,16 @@ static struct smp_ops_t pSeries_xics_smp_ops = {
.
setup_cpu
=
smp_xics_setup_cpu
,
.
cpu_bootable
=
smp_pSeries_cpu_bootable
,
};
#endif
#ifdef CONFIG_BPA_IIC
static
struct
smp_ops_t
bpa_iic_smp_ops
=
{
.
message_pass
=
smp_iic_message_pass
,
.
probe
=
smp_iic_probe
,
.
kick_cpu
=
smp_pSeries_kick_cpu
,
.
setup_cpu
=
smp_iic_setup_cpu
,
.
cpu_bootable
=
smp_pSeries_cpu_bootable
,
};
#endif
/* This is called very early */
void
__init
smp_init_pSeries
(
void
)
...
...
@@ -404,10 +448,25 @@ void __init smp_init_pSeries(void)
DBG
(
" -> smp_init_pSeries()
\n
"
);
if
(
ppc64_interrupt_controller
==
IC_OPEN_PIC
)
switch
(
ppc64_interrupt_controller
)
{
#ifdef CONFIG_MPIC
case
IC_OPEN_PIC
:
smp_ops
=
&
pSeries_mpic_smp_ops
;
else
break
;
#endif
#ifdef CONFIG_XICS
case
IC_PPC_XIC
:
smp_ops
=
&
pSeries_xics_smp_ops
;
break
;
#endif
#ifdef CONFIG_BPA_IIC
case
IC_BPA_IIC
:
smp_ops
=
&
bpa_iic_smp_ops
;
break
;
#endif
default:
panic
(
"Invalid interrupt controller"
);
}
#ifdef CONFIG_HOTPLUG_CPU
smp_ops
->
cpu_disable
=
pSeries_cpu_disable
;
...
...
arch/ppc64/kernel/pci.c
View file @
24665cd0
...
...
@@ -902,6 +902,9 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
list_for_each_entry
(
dev
,
&
bus
->
devices
,
bus_list
)
ppc_md
.
iommu_dev_setup
(
dev
);
if
(
ppc_md
.
irq_bus_setup
)
ppc_md
.
irq_bus_setup
(
bus
);
if
(
!
pci_probe_only
)
return
;
...
...
arch/ppc64/kernel/pci.h
View file @
24665cd0
...
...
@@ -40,10 +40,14 @@ struct device_node *fetch_dev_dn(struct pci_dev *dev);
void
pci_addr_cache_insert_device
(
struct
pci_dev
*
dev
);
void
pci_addr_cache_remove_device
(
struct
pci_dev
*
dev
);
/* From
pSerie
s_pci.h */
/* From
rta
s_pci.h */
void
init_pci_config_tokens
(
void
);
unsigned
long
get_phb_buid
(
struct
device_node
*
);
/* From pSeries_pci.h */
extern
void
pSeries_final_fixup
(
void
);
extern
void
pSeries_irq_bus_setup
(
struct
pci_bus
*
bus
);
extern
unsigned
long
pci_probe_only
;
extern
unsigned
long
pci_assign_all_buses
;
extern
int
pci_read_irq_line
(
struct
pci_dev
*
pci_dev
);
...
...
arch/ppc64/kernel/pmac_time.c
View file @
24665cd0
...
...
@@ -40,11 +40,6 @@
#define DBG(x...)
#endif
extern
void
setup_default_decr
(
void
);
extern
unsigned
long
ppc_tb_freq
;
extern
unsigned
long
ppc_proc_freq
;
/* Apparently the RTC stores seconds since 1 Jan 1904 */
#define RTC_OFFSET 2082844800
...
...
@@ -161,8 +156,7 @@ void __init pmac_get_boot_time(struct rtc_time *tm)
/*
* Query the OF and get the decr frequency.
* This was taken from the pmac time_init() when merging the prep/pmac
* time functions.
* FIXME: merge this with generic_calibrate_decr
*/
void
__init
pmac_calibrate_decr
(
void
)
{
...
...
arch/ppc64/kernel/proc_ppc64.c
View file @
24665cd0
...
...
@@ -53,7 +53,7 @@ static int __init proc_ppc64_create(void)
if
(
!
root
)
return
1
;
if
(
!
(
systemcfg
->
platform
&
PLATFORM_PSERIES
))
if
(
!
(
systemcfg
->
platform
&
(
PLATFORM_PSERIES
|
PLATFORM_BPA
)
))
return
0
;
if
(
!
proc_mkdir
(
"rtas"
,
root
))
...
...
arch/ppc64/kernel/prom_init.c
View file @
24665cd0
...
...
@@ -1915,9 +1915,9 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long
prom_send_capabilities
();
/*
* On pSeries, copy the CPU hold code
* On pSeries
and BPA
, copy the CPU hold code
*/
if
(
RELOC
(
of_platform
)
&
PLATFORM_PSERIES
)
if
(
RELOC
(
of_platform
)
&
(
PLATFORM_PSERIES
|
PLATFORM_BPA
)
)
copy_and_flush
(
0
,
KERNELBASE
-
offset
,
0x100
,
0
);
/*
...
...
arch/ppc64/kernel/rtas-proc.c
View file @
24665cd0
...
...
@@ -371,11 +371,11 @@ static ssize_t ppc_rtas_progress_write(struct file *file,
/* Lets see if the user passed hexdigits */
hex
=
simple_strtoul
(
progress_led
,
NULL
,
10
);
ppc_md
.
progress
((
char
*
)
progress_led
,
hex
);
rtas_
progress
((
char
*
)
progress_led
,
hex
);
return
count
;
/* clear the line */
/*
ppc_md.
progress(" ", 0xffff);*/
/*
rtas_
progress(" ", 0xffff);*/
}
/* ****************************************************************** */
static
int
ppc_rtas_progress_show
(
struct
seq_file
*
m
,
void
*
v
)
...
...
arch/ppc64/kernel/rtas.c
View file @
24665cd0
...
...
@@ -91,6 +91,123 @@ call_rtas_display_status_delay(unsigned char c)
}
}
void
rtas_progress
(
char
*
s
,
unsigned
short
hex
)
{
struct
device_node
*
root
;
int
width
,
*
p
;
char
*
os
;
static
int
display_character
,
set_indicator
;
static
int
display_width
,
display_lines
,
*
row_width
,
form_feed
;
static
DEFINE_SPINLOCK
(
progress_lock
);
static
int
current_line
;
static
int
pending_newline
=
0
;
/* did last write end with unprinted newline? */
if
(
!
rtas
.
base
)
return
;
if
(
display_width
==
0
)
{
display_width
=
0x10
;
if
((
root
=
find_path_device
(
"/rtas"
)))
{
if
((
p
=
(
unsigned
int
*
)
get_property
(
root
,
"ibm,display-line-length"
,
NULL
)))
display_width
=
*
p
;
if
((
p
=
(
unsigned
int
*
)
get_property
(
root
,
"ibm,form-feed"
,
NULL
)))
form_feed
=
*
p
;
if
((
p
=
(
unsigned
int
*
)
get_property
(
root
,
"ibm,display-number-of-lines"
,
NULL
)))
display_lines
=
*
p
;
row_width
=
(
unsigned
int
*
)
get_property
(
root
,
"ibm,display-truncation-length"
,
NULL
);
}
display_character
=
rtas_token
(
"display-character"
);
set_indicator
=
rtas_token
(
"set-indicator"
);
}
if
(
display_character
==
RTAS_UNKNOWN_SERVICE
)
{
/* use hex display if available */
if
(
set_indicator
!=
RTAS_UNKNOWN_SERVICE
)
rtas_call
(
set_indicator
,
3
,
1
,
NULL
,
6
,
0
,
hex
);
return
;
}
spin_lock
(
&
progress_lock
);
/*
* Last write ended with newline, but we didn't print it since
* it would just clear the bottom line of output. Print it now
* instead.
*
* If no newline is pending and form feed is supported, clear the
* display with a form feed; otherwise, print a CR to start output
* at the beginning of the line.
*/
if
(
pending_newline
)
{
rtas_call
(
display_character
,
1
,
1
,
NULL
,
'\r'
);
rtas_call
(
display_character
,
1
,
1
,
NULL
,
'\n'
);
pending_newline
=
0
;
}
else
{
current_line
=
0
;
if
(
form_feed
)
rtas_call
(
display_character
,
1
,
1
,
NULL
,
(
char
)
form_feed
);
else
rtas_call
(
display_character
,
1
,
1
,
NULL
,
'\r'
);
}
if
(
row_width
)
width
=
row_width
[
current_line
];
else
width
=
display_width
;
os
=
s
;
while
(
*
os
)
{
if
(
*
os
==
'\n'
||
*
os
==
'\r'
)
{
/* If newline is the last character, save it
* until next call to avoid bumping up the
* display output.
*/
if
(
*
os
==
'\n'
&&
!
os
[
1
])
{
pending_newline
=
1
;
current_line
++
;
if
(
current_line
>
display_lines
-
1
)
current_line
=
display_lines
-
1
;
spin_unlock
(
&
progress_lock
);
return
;
}
/* RTAS wants CR-LF, not just LF */
if
(
*
os
==
'\n'
)
{
rtas_call
(
display_character
,
1
,
1
,
NULL
,
'\r'
);
rtas_call
(
display_character
,
1
,
1
,
NULL
,
'\n'
);
}
else
{
/* CR might be used to re-draw a line, so we'll
* leave it alone and not add LF.
*/
rtas_call
(
display_character
,
1
,
1
,
NULL
,
*
os
);
}
if
(
row_width
)
width
=
row_width
[
current_line
];
else
width
=
display_width
;
}
else
{
width
--
;
rtas_call
(
display_character
,
1
,
1
,
NULL
,
*
os
);
}
os
++
;
/* if we overwrite the screen length */
if
(
width
<=
0
)
while
((
*
os
!=
0
)
&&
(
*
os
!=
'\n'
)
&&
(
*
os
!=
'\r'
))
os
++
;
}
spin_unlock
(
&
progress_lock
);
}
int
rtas_token
(
const
char
*
service
)
{
...
...
@@ -425,8 +542,8 @@ rtas_flash_firmware(void)
printk
(
KERN_ALERT
"FLASH: flash image is %ld bytes
\n
"
,
image_size
);
printk
(
KERN_ALERT
"FLASH: performing flash and reboot
\n
"
);
ppc_md
.
progress
(
"Flashing
\n
"
,
0x0
);
ppc_md
.
progress
(
"Please Wait... "
,
0x0
);
rtas_
progress
(
"Flashing
\n
"
,
0x0
);
rtas_
progress
(
"Please Wait... "
,
0x0
);
printk
(
KERN_ALERT
"FLASH: this will take several minutes. Do not power off!
\n
"
);
status
=
rtas_call
(
update_token
,
1
,
1
,
NULL
,
rtas_block_list
);
switch
(
status
)
{
/* should only get "bad" status */
...
...
arch/ppc64/kernel/rtas_pci.c
0 → 100644
View file @
24665cd0
/*
* arch/ppc64/kernel/rtas_pci.c
*
* Copyright (C) 2001 Dave Engebretsen, IBM Corporation
* Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
*
* RTAS specific routines for PCI.
*
* Based on code from pci.c, chrp_pci.c and pSeries_pci.c
*
* 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/kernel.h>
#include <linux/threads.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/iommu.h>
#include <asm/rtas.h>
#include "mpic.h"
#include "pci.h"
/* RTAS tokens */
static
int
read_pci_config
;
static
int
write_pci_config
;
static
int
ibm_read_pci_config
;
static
int
ibm_write_pci_config
;
static
int
config_access_valid
(
struct
device_node
*
dn
,
int
where
)
{
if
(
where
<
256
)
return
1
;
if
(
where
<
4096
&&
dn
->
pci_ext_config_space
)
return
1
;
return
0
;
}
static
int
rtas_read_config
(
struct
device_node
*
dn
,
int
where
,
int
size
,
u32
*
val
)
{
int
returnval
=
-
1
;
unsigned
long
buid
,
addr
;
int
ret
;
if
(
!
dn
)
return
PCIBIOS_DEVICE_NOT_FOUND
;
if
(
!
config_access_valid
(
dn
,
where
))
return
PCIBIOS_BAD_REGISTER_NUMBER
;
addr
=
((
where
&
0xf00
)
<<
20
)
|
(
dn
->
busno
<<
16
)
|
(
dn
->
devfn
<<
8
)
|
(
where
&
0xff
);
buid
=
dn
->
phb
->
buid
;
if
(
buid
)
{
ret
=
rtas_call
(
ibm_read_pci_config
,
4
,
2
,
&
returnval
,
addr
,
buid
>>
32
,
buid
&
0xffffffff
,
size
);
}
else
{
ret
=
rtas_call
(
read_pci_config
,
2
,
2
,
&
returnval
,
addr
,
size
);
}
*
val
=
returnval
;
if
(
ret
)
return
PCIBIOS_DEVICE_NOT_FOUND
;
if
(
returnval
==
EEH_IO_ERROR_VALUE
(
size
)
&&
eeh_dn_check_failure
(
dn
,
NULL
))
return
PCIBIOS_DEVICE_NOT_FOUND
;
return
PCIBIOS_SUCCESSFUL
;
}
static
int
rtas_pci_read_config
(
struct
pci_bus
*
bus
,
unsigned
int
devfn
,
int
where
,
int
size
,
u32
*
val
)
{
struct
device_node
*
busdn
,
*
dn
;
if
(
bus
->
self
)
busdn
=
pci_device_to_OF_node
(
bus
->
self
);
else
busdn
=
bus
->
sysdata
;
/* must be a phb */
/* Search only direct children of the bus */
for
(
dn
=
busdn
->
child
;
dn
;
dn
=
dn
->
sibling
)
if
(
dn
->
devfn
==
devfn
)
return
rtas_read_config
(
dn
,
where
,
size
,
val
);
return
PCIBIOS_DEVICE_NOT_FOUND
;
}
static
int
rtas_write_config
(
struct
device_node
*
dn
,
int
where
,
int
size
,
u32
val
)
{
unsigned
long
buid
,
addr
;
int
ret
;
if
(
!
dn
)
return
PCIBIOS_DEVICE_NOT_FOUND
;
if
(
!
config_access_valid
(
dn
,
where
))
return
PCIBIOS_BAD_REGISTER_NUMBER
;
addr
=
((
where
&
0xf00
)
<<
20
)
|
(
dn
->
busno
<<
16
)
|
(
dn
->
devfn
<<
8
)
|
(
where
&
0xff
);
buid
=
dn
->
phb
->
buid
;
if
(
buid
)
{
ret
=
rtas_call
(
ibm_write_pci_config
,
5
,
1
,
NULL
,
addr
,
buid
>>
32
,
buid
&
0xffffffff
,
size
,
(
ulong
)
val
);
}
else
{
ret
=
rtas_call
(
write_pci_config
,
3
,
1
,
NULL
,
addr
,
size
,
(
ulong
)
val
);
}
if
(
ret
)
return
PCIBIOS_DEVICE_NOT_FOUND
;
return
PCIBIOS_SUCCESSFUL
;
}
static
int
rtas_pci_write_config
(
struct
pci_bus
*
bus
,
unsigned
int
devfn
,
int
where
,
int
size
,
u32
val
)
{
struct
device_node
*
busdn
,
*
dn
;
if
(
bus
->
self
)
busdn
=
pci_device_to_OF_node
(
bus
->
self
);
else
busdn
=
bus
->
sysdata
;
/* must be a phb */
/* Search only direct children of the bus */
for
(
dn
=
busdn
->
child
;
dn
;
dn
=
dn
->
sibling
)
if
(
dn
->
devfn
==
devfn
)
return
rtas_write_config
(
dn
,
where
,
size
,
val
);
return
PCIBIOS_DEVICE_NOT_FOUND
;
}
struct
pci_ops
rtas_pci_ops
=
{
rtas_pci_read_config
,
rtas_pci_write_config
};
int
is_python
(
struct
device_node
*
dev
)
{
char
*
model
=
(
char
*
)
get_property
(
dev
,
"model"
,
NULL
);
if
(
model
&&
strstr
(
model
,
"Python"
))
return
1
;
return
0
;
}
static
int
get_phb_reg_prop
(
struct
device_node
*
dev
,
unsigned
int
addr_size_words
,
struct
reg_property64
*
reg
)
{
unsigned
int
*
ui_ptr
=
NULL
,
len
;
/* Found a PHB, now figure out where his registers are mapped. */
ui_ptr
=
(
unsigned
int
*
)
get_property
(
dev
,
"reg"
,
&
len
);
if
(
ui_ptr
==
NULL
)
return
1
;
if
(
addr_size_words
==
1
)
{
reg
->
address
=
((
struct
reg_property32
*
)
ui_ptr
)
->
address
;
reg
->
size
=
((
struct
reg_property32
*
)
ui_ptr
)
->
size
;
}
else
{
*
reg
=
*
((
struct
reg_property64
*
)
ui_ptr
);
}
return
0
;
}
static
void
python_countermeasures
(
struct
device_node
*
dev
,
unsigned
int
addr_size_words
)
{
struct
reg_property64
reg_struct
;
void
__iomem
*
chip_regs
;
volatile
u32
val
;
if
(
get_phb_reg_prop
(
dev
,
addr_size_words
,
&
reg_struct
))
return
;
/* Python's register file is 1 MB in size. */
chip_regs
=
ioremap
(
reg_struct
.
address
&
~
(
0xfffffUL
),
0x100000
);
/*
* Firmware doesn't always clear this bit which is critical
* for good performance - Anton
*/
#define PRG_CL_RESET_VALID 0x00010000
val
=
in_be32
(
chip_regs
+
0xf6030
);
if
(
val
&
PRG_CL_RESET_VALID
)
{
printk
(
KERN_INFO
"Python workaround: "
);
val
&=
~
PRG_CL_RESET_VALID
;
out_be32
(
chip_regs
+
0xf6030
,
val
);
/*
* We must read it back for changes to
* take effect
*/
val
=
in_be32
(
chip_regs
+
0xf6030
);
printk
(
"reg0: %x
\n
"
,
val
);
}
iounmap
(
chip_regs
);
}
void
__init
init_pci_config_tokens
(
void
)
{
read_pci_config
=
rtas_token
(
"read-pci-config"
);
write_pci_config
=
rtas_token
(
"write-pci-config"
);
ibm_read_pci_config
=
rtas_token
(
"ibm,read-pci-config"
);
ibm_write_pci_config
=
rtas_token
(
"ibm,write-pci-config"
);
}
unsigned
long
__devinit
get_phb_buid
(
struct
device_node
*
phb
)
{
int
addr_cells
;
unsigned
int
*
buid_vals
;
unsigned
int
len
;
unsigned
long
buid
;
if
(
ibm_read_pci_config
==
-
1
)
return
0
;
/* PHB's will always be children of the root node,
* or so it is promised by the current firmware. */
if
(
phb
->
parent
==
NULL
)
return
0
;
if
(
phb
->
parent
->
parent
)
return
0
;
buid_vals
=
(
unsigned
int
*
)
get_property
(
phb
,
"reg"
,
&
len
);
if
(
buid_vals
==
NULL
)
return
0
;
addr_cells
=
prom_n_addr_cells
(
phb
);
if
(
addr_cells
==
1
)
{
buid
=
(
unsigned
long
)
buid_vals
[
0
];
}
else
{
buid
=
(((
unsigned
long
)
buid_vals
[
0
])
<<
32UL
)
|
(((
unsigned
long
)
buid_vals
[
1
])
&
0xffffffff
);
}
return
buid
;
}
static
int
phb_set_bus_ranges
(
struct
device_node
*
dev
,
struct
pci_controller
*
phb
)
{
int
*
bus_range
;
unsigned
int
len
;
bus_range
=
(
int
*
)
get_property
(
dev
,
"bus-range"
,
&
len
);
if
(
bus_range
==
NULL
||
len
<
2
*
sizeof
(
int
))
{
return
1
;
}
phb
->
first_busno
=
bus_range
[
0
];
phb
->
last_busno
=
bus_range
[
1
];
return
0
;
}
static
int
__devinit
setup_phb
(
struct
device_node
*
dev
,
struct
pci_controller
*
phb
,
unsigned
int
addr_size_words
)
{
pci_setup_pci_controller
(
phb
);
if
(
is_python
(
dev
))
python_countermeasures
(
dev
,
addr_size_words
);
if
(
phb_set_bus_ranges
(
dev
,
phb
))
return
1
;
phb
->
arch_data
=
dev
;
phb
->
ops
=
&
rtas_pci_ops
;
phb
->
buid
=
get_phb_buid
(
dev
);
return
0
;
}
static
void
__devinit
add_linux_pci_domain
(
struct
device_node
*
dev
,
struct
pci_controller
*
phb
,
struct
property
*
of_prop
)
{
memset
(
of_prop
,
0
,
sizeof
(
struct
property
));
of_prop
->
name
=
"linux,pci-domain"
;
of_prop
->
length
=
sizeof
(
phb
->
global_number
);
of_prop
->
value
=
(
unsigned
char
*
)
&
of_prop
[
1
];
memcpy
(
of_prop
->
value
,
&
phb
->
global_number
,
sizeof
(
phb
->
global_number
));
prom_add_property
(
dev
,
of_prop
);
}
static
struct
pci_controller
*
__init
alloc_phb
(
struct
device_node
*
dev
,
unsigned
int
addr_size_words
)
{
struct
pci_controller
*
phb
;
struct
property
*
of_prop
;
phb
=
alloc_bootmem
(
sizeof
(
struct
pci_controller
));
if
(
phb
==
NULL
)
return
NULL
;
of_prop
=
alloc_bootmem
(
sizeof
(
struct
property
)
+
sizeof
(
phb
->
global_number
));
if
(
!
of_prop
)
return
NULL
;
if
(
setup_phb
(
dev
,
phb
,
addr_size_words
))
return
NULL
;
add_linux_pci_domain
(
dev
,
phb
,
of_prop
);
return
phb
;
}
static
struct
pci_controller
*
__devinit
alloc_phb_dynamic
(
struct
device_node
*
dev
,
unsigned
int
addr_size_words
)
{
struct
pci_controller
*
phb
;
phb
=
(
struct
pci_controller
*
)
kmalloc
(
sizeof
(
struct
pci_controller
),
GFP_KERNEL
);
if
(
phb
==
NULL
)
return
NULL
;
if
(
setup_phb
(
dev
,
phb
,
addr_size_words
))
return
NULL
;
phb
->
is_dynamic
=
1
;
/* TODO: linux,pci-domain? */
return
phb
;
}
unsigned
long
__init
find_and_init_phbs
(
void
)
{
struct
device_node
*
node
;
struct
pci_controller
*
phb
;
unsigned
int
root_size_cells
=
0
;
unsigned
int
index
;
unsigned
int
*
opprop
=
NULL
;
struct
device_node
*
root
=
of_find_node_by_path
(
"/"
);
if
(
ppc64_interrupt_controller
==
IC_OPEN_PIC
)
{
opprop
=
(
unsigned
int
*
)
get_property
(
root
,
"platform-open-pic"
,
NULL
);
}
root_size_cells
=
prom_n_size_cells
(
root
);
index
=
0
;
for
(
node
=
of_get_next_child
(
root
,
NULL
);
node
!=
NULL
;
node
=
of_get_next_child
(
root
,
node
))
{
if
(
node
->
type
==
NULL
||
strcmp
(
node
->
type
,
"pci"
)
!=
0
)
continue
;
phb
=
alloc_phb
(
node
,
root_size_cells
);
if
(
!
phb
)
continue
;
pci_process_bridge_OF_ranges
(
phb
,
node
);
pci_setup_phb_io
(
phb
,
index
==
0
);
#ifdef CONFIG_PPC_PSERIES
if
(
ppc64_interrupt_controller
==
IC_OPEN_PIC
&&
pSeries_mpic
)
{
int
addr
=
root_size_cells
*
(
index
+
2
)
-
1
;
mpic_assign_isu
(
pSeries_mpic
,
index
,
opprop
[
addr
]);
}
#endif
index
++
;
}
of_node_put
(
root
);
pci_devs_phb_init
();
/*
* pci_probe_only and pci_assign_all_buses can be set via properties
* in chosen.
*/
if
(
of_chosen
)
{
int
*
prop
;
prop
=
(
int
*
)
get_property
(
of_chosen
,
"linux,pci-probe-only"
,
NULL
);
if
(
prop
)
pci_probe_only
=
*
prop
;
prop
=
(
int
*
)
get_property
(
of_chosen
,
"linux,pci-assign-all-buses"
,
NULL
);
if
(
prop
)
pci_assign_all_buses
=
*
prop
;
}
return
0
;
}
struct
pci_controller
*
__devinit
init_phb_dynamic
(
struct
device_node
*
dn
)
{
struct
device_node
*
root
=
of_find_node_by_path
(
"/"
);
unsigned
int
root_size_cells
=
0
;
struct
pci_controller
*
phb
;
struct
pci_bus
*
bus
;
int
primary
;
root_size_cells
=
prom_n_size_cells
(
root
);
primary
=
list_empty
(
&
hose_list
);
phb
=
alloc_phb_dynamic
(
dn
,
root_size_cells
);
if
(
!
phb
)
return
NULL
;
pci_process_bridge_OF_ranges
(
phb
,
dn
);
pci_setup_phb_io_dynamic
(
phb
,
primary
);
of_node_put
(
root
);
pci_devs_phb_init_dynamic
(
phb
);
phb
->
last_busno
=
0xff
;
bus
=
pci_scan_bus
(
phb
->
first_busno
,
phb
->
ops
,
phb
->
arch_data
);
phb
->
bus
=
bus
;
phb
->
last_busno
=
bus
->
subordinate
;
return
phb
;
}
EXPORT_SYMBOL
(
init_phb_dynamic
);
/* RPA-specific bits for removing PHBs */
int
pcibios_remove_root_bus
(
struct
pci_controller
*
phb
)
{
struct
pci_bus
*
b
=
phb
->
bus
;
struct
resource
*
res
;
int
rc
,
i
;
res
=
b
->
resource
[
0
];
if
(
!
res
->
flags
)
{
printk
(
KERN_ERR
"%s: no IO resource for PHB %s
\n
"
,
__FUNCTION__
,
b
->
name
);
return
1
;
}
rc
=
unmap_bus_range
(
b
);
if
(
rc
)
{
printk
(
KERN_ERR
"%s: failed to unmap IO on bus %s
\n
"
,
__FUNCTION__
,
b
->
name
);
return
1
;
}
if
(
release_resource
(
res
))
{
printk
(
KERN_ERR
"%s: failed to release IO on bus %s
\n
"
,
__FUNCTION__
,
b
->
name
);
return
1
;
}
for
(
i
=
1
;
i
<
3
;
++
i
)
{
res
=
b
->
resource
[
i
];
if
(
!
res
->
flags
&&
i
==
0
)
{
printk
(
KERN_ERR
"%s: no MEM resource for PHB %s
\n
"
,
__FUNCTION__
,
b
->
name
);
return
1
;
}
if
(
res
->
flags
&&
release_resource
(
res
))
{
printk
(
KERN_ERR
"%s: failed to release IO %d on bus %s
\n
"
,
__FUNCTION__
,
i
,
b
->
name
);
return
1
;
}
}
list_del
(
&
phb
->
list_node
);
if
(
phb
->
is_dynamic
)
kfree
(
phb
);
return
0
;
}
EXPORT_SYMBOL
(
pcibios_remove_root_bus
);
arch/ppc64/kernel/rtc.c
View file @
24665cd0
...
...
@@ -301,7 +301,7 @@ void iSeries_get_boot_time(struct rtc_time *tm)
#ifdef CONFIG_PPC_RTAS
#define MAX_RTC_WAIT 5000
/* 5 sec */
#define RTAS_CLOCK_BUSY (-2)
void
pSerie
s_get_boot_time
(
struct
rtc_time
*
rtc_tm
)
void
rta
s_get_boot_time
(
struct
rtc_time
*
rtc_tm
)
{
int
ret
[
8
];
int
error
,
wait_time
;
...
...
@@ -336,7 +336,7 @@ void pSeries_get_boot_time(struct rtc_time *rtc_tm)
* and if a delay is needed to read the clock. In this case we just
* silently return without updating rtc_tm.
*/
void
pSerie
s_get_rtc_time
(
struct
rtc_time
*
rtc_tm
)
void
rta
s_get_rtc_time
(
struct
rtc_time
*
rtc_tm
)
{
int
ret
[
8
];
int
error
,
wait_time
;
...
...
@@ -371,7 +371,7 @@ void pSeries_get_rtc_time(struct rtc_time *rtc_tm)
rtc_tm
->
tm_year
=
ret
[
0
]
-
1900
;
}
int
pSerie
s_set_rtc_time
(
struct
rtc_time
*
tm
)
int
rta
s_set_rtc_time
(
struct
rtc_time
*
tm
)
{
int
error
,
wait_time
;
unsigned
long
max_wait_tb
;
...
...
arch/ppc64/kernel/setup.c
View file @
24665cd0
...
...
@@ -344,6 +344,7 @@ static void __init setup_cpu_maps(void)
extern
struct
machdep_calls
pSeries_md
;
extern
struct
machdep_calls
pmac_md
;
extern
struct
machdep_calls
maple_md
;
extern
struct
machdep_calls
bpa_md
;
/* Ultimately, stuff them in an elf section like initcalls... */
static
struct
machdep_calls
__initdata
*
machines
[]
=
{
...
...
@@ -356,6 +357,9 @@ static struct machdep_calls __initdata *machines[] = {
#ifdef CONFIG_PPC_MAPLE
&
maple_md
,
#endif
/* CONFIG_PPC_MAPLE */
#ifdef CONFIG_PPC_BPA
&
bpa_md
,
#endif
NULL
};
...
...
@@ -679,6 +683,12 @@ void machine_restart(char *cmd)
if
(
ppc_md
.
nvram_sync
)
ppc_md
.
nvram_sync
();
ppc_md
.
restart
(
cmd
);
#ifdef CONFIG_SMP
smp_send_stop
();
#endif
printk
(
KERN_EMERG
"System Halted, OK to turn off power
\n
"
);
local_irq_disable
();
while
(
1
)
;
}
EXPORT_SYMBOL
(
machine_restart
);
...
...
@@ -688,6 +698,12 @@ void machine_power_off(void)
if
(
ppc_md
.
nvram_sync
)
ppc_md
.
nvram_sync
();
ppc_md
.
power_off
();
#ifdef CONFIG_SMP
smp_send_stop
();
#endif
printk
(
KERN_EMERG
"System Halted, OK to turn off power
\n
"
);
local_irq_disable
();
while
(
1
)
;
}
EXPORT_SYMBOL
(
machine_power_off
);
...
...
@@ -697,13 +713,16 @@ void machine_halt(void)
if
(
ppc_md
.
nvram_sync
)
ppc_md
.
nvram_sync
();
ppc_md
.
halt
();
#ifdef CONFIG_SMP
smp_send_stop
();
#endif
printk
(
KERN_EMERG
"System Halted, OK to turn off power
\n
"
);
local_irq_disable
();
while
(
1
)
;
}
EXPORT_SYMBOL
(
machine_halt
);
unsigned
long
ppc_proc_freq
;
unsigned
long
ppc_tb_freq
;
static
int
ppc64_panic_event
(
struct
notifier_block
*
this
,
unsigned
long
event
,
void
*
ptr
)
{
...
...
@@ -1080,11 +1099,11 @@ void __init setup_arch(char **cmdline_p)
static
void
ppc64_do_msg
(
unsigned
int
src
,
const
char
*
msg
)
{
if
(
ppc_md
.
progress
)
{
char
buf
[
32
];
char
buf
[
128
];
sprintf
(
buf
,
"%08
x
\n
"
,
src
);
sprintf
(
buf
,
"%08
X
\n
"
,
src
);
ppc_md
.
progress
(
buf
,
0
);
s
printf
(
buf
,
"%-16
s"
,
msg
);
s
nprintf
(
buf
,
128
,
"%
s"
,
msg
);
ppc_md
.
progress
(
buf
,
0
);
}
}
...
...
@@ -1118,7 +1137,7 @@ void ppc64_dump_msg(unsigned int src, const char *msg)
}
/* This should only be called on processor 0 during calibrate decr */
void
setup_default_decr
(
void
)
void
__init
setup_default_decr
(
void
)
{
struct
paca_struct
*
lpaca
=
get_paca
();
...
...
arch/ppc64/kernel/smp.c
View file @
24665cd0
...
...
@@ -71,7 +71,7 @@ void smp_call_function_interrupt(void);
int
smt_enabled_at_boot
=
1
;
#ifdef CONFIG_
PPC_MULTIPLATFORM
#ifdef CONFIG_
MPIC
void
smp_mpic_message_pass
(
int
target
,
int
msg
)
{
/* make sure we're sending something that translates to an IPI */
...
...
@@ -128,7 +128,7 @@ void __devinit smp_generic_kick_cpu(int nr)
smp_mb
();
}
#endif
/* CONFIG_
PPC_MULTIPLATFORM
*/
#endif
/* CONFIG_
MPIC
*/
static
void
__init
smp_space_timers
(
unsigned
int
max_cpus
)
{
...
...
arch/ppc64/kernel/spider-pic.c
0 → 100644
View file @
24665cd0
/*
* External Interrupt Controller on Spider South Bridge
*
* (C) Copyright IBM Deutschland Entwicklung GmbH 2005
*
* Author: Arnd Bergmann <arndb@de.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/io.h>
#include "bpa_iic.h"
/* register layout taken from Spider spec, table 7.4-4 */
enum
{
TIR_DEN
=
0x004
,
/* Detection Enable Register */
TIR_MSK
=
0x084
,
/* Mask Level Register */
TIR_EDC
=
0x0c0
,
/* Edge Detection Clear Register */
TIR_PNDA
=
0x100
,
/* Pending Register A */
TIR_PNDB
=
0x104
,
/* Pending Register B */
TIR_CS
=
0x144
,
/* Current Status Register */
TIR_LCSA
=
0x150
,
/* Level Current Status Register A */
TIR_LCSB
=
0x154
,
/* Level Current Status Register B */
TIR_LCSC
=
0x158
,
/* Level Current Status Register C */
TIR_LCSD
=
0x15c
,
/* Level Current Status Register D */
TIR_CFGA
=
0x200
,
/* Setting Register A0 */
TIR_CFGB
=
0x204
,
/* Setting Register B0 */
/* 0x208 ... 0x3ff Setting Register An/Bn */
TIR_PPNDA
=
0x400
,
/* Packet Pending Register A */
TIR_PPNDB
=
0x404
,
/* Packet Pending Register B */
TIR_PIERA
=
0x408
,
/* Packet Output Error Register A */
TIR_PIERB
=
0x40c
,
/* Packet Output Error Register B */
TIR_PIEN
=
0x444
,
/* Packet Output Enable Register */
TIR_PIPND
=
0x454
,
/* Packet Output Pending Register */
TIRDID
=
0x484
,
/* Spider Device ID Register */
REISTIM
=
0x500
,
/* Reissue Command Timeout Time Setting */
REISTIMEN
=
0x504
,
/* Reissue Command Timeout Setting */
REISWAITEN
=
0x508
,
/* Reissue Wait Control*/
};
static
void
__iomem
*
spider_pics
[
4
];
static
void
__iomem
*
spider_get_pic
(
int
irq
)
{
int
node
=
irq
/
IIC_NODE_STRIDE
;
irq
%=
IIC_NODE_STRIDE
;
if
(
irq
>=
IIC_EXT_OFFSET
&&
irq
<
IIC_EXT_OFFSET
+
IIC_NUM_EXT
&&
spider_pics
)
return
spider_pics
[
node
];
return
NULL
;
}
static
int
spider_get_nr
(
unsigned
int
irq
)
{
return
(
irq
%
IIC_NODE_STRIDE
)
-
IIC_EXT_OFFSET
;
}
static
void
__iomem
*
spider_get_irq_config
(
int
irq
)
{
void
__iomem
*
pic
;
pic
=
spider_get_pic
(
irq
);
return
pic
+
TIR_CFGA
+
8
*
spider_get_nr
(
irq
);
}
static
void
spider_enable_irq
(
unsigned
int
irq
)
{
void
__iomem
*
cfg
=
spider_get_irq_config
(
irq
);
irq
=
spider_get_nr
(
irq
);
out_be32
(
cfg
,
in_be32
(
cfg
)
|
0x3107000eu
);
out_be32
(
cfg
+
4
,
in_be32
(
cfg
+
4
)
|
0x00020000u
|
irq
);
}
static
void
spider_disable_irq
(
unsigned
int
irq
)
{
void
__iomem
*
cfg
=
spider_get_irq_config
(
irq
);
irq
=
spider_get_nr
(
irq
);
out_be32
(
cfg
,
in_be32
(
cfg
)
&
~
0x30000000u
);
}
static
unsigned
int
spider_startup_irq
(
unsigned
int
irq
)
{
spider_enable_irq
(
irq
);
return
0
;
}
static
void
spider_shutdown_irq
(
unsigned
int
irq
)
{
spider_disable_irq
(
irq
);
}
static
void
spider_end_irq
(
unsigned
int
irq
)
{
spider_enable_irq
(
irq
);
}
static
void
spider_ack_irq
(
unsigned
int
irq
)
{
spider_disable_irq
(
irq
);
iic_local_enable
();
}
static
struct
hw_interrupt_type
spider_pic
=
{
.
typename
=
" SPIDER "
,
.
startup
=
spider_startup_irq
,
.
shutdown
=
spider_shutdown_irq
,
.
enable
=
spider_enable_irq
,
.
disable
=
spider_disable_irq
,
.
ack
=
spider_ack_irq
,
.
end
=
spider_end_irq
,
};
int
spider_get_irq
(
unsigned
long
int_pending
)
{
void
__iomem
*
regs
=
spider_get_pic
(
int_pending
);
unsigned
long
cs
;
int
irq
;
cs
=
in_be32
(
regs
+
TIR_CS
);
irq
=
cs
>>
24
;
if
(
irq
!=
63
)
return
irq
;
return
-
1
;
}
void
spider_init_IRQ
(
void
)
{
int
node
;
struct
device_node
*
dn
;
unsigned
int
*
property
;
long
spiderpic
;
int
n
;
/* FIXME: detect multiple PICs as soon as the device tree has them */
for
(
node
=
0
;
node
<
1
;
node
++
)
{
dn
=
of_find_node_by_path
(
"/"
);
n
=
prom_n_addr_cells
(
dn
);
property
=
(
unsigned
int
*
)
get_property
(
dn
,
"platform-spider-pic"
,
NULL
);
if
(
!
property
)
continue
;
for
(
spiderpic
=
0
;
n
>
0
;
--
n
)
spiderpic
=
(
spiderpic
<<
32
)
+
*
property
++
;
printk
(
KERN_DEBUG
"SPIDER addr: %lx
\n
"
,
spiderpic
);
spider_pics
[
node
]
=
__ioremap
(
spiderpic
,
0x800
,
_PAGE_NO_CACHE
);
for
(
n
=
0
;
n
<
IIC_NUM_EXT
;
n
++
)
{
int
irq
=
n
+
IIC_EXT_OFFSET
+
node
*
IIC_NODE_STRIDE
;
get_irq_desc
(
irq
)
->
handler
=
&
spider_pic
;
/* do not mask any interrupts because of level */
out_be32
(
spider_pics
[
node
]
+
TIR_MSK
,
0x0
);
/* disable edge detection clear */
/* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
/* enable interrupt packets to be output */
out_be32
(
spider_pics
[
node
]
+
TIR_PIEN
,
in_be32
(
spider_pics
[
node
]
+
TIR_PIEN
)
|
0x1
);
/* Enable the interrupt detection enable bit. Do this last! */
out_be32
(
spider_pics
[
node
]
+
TIR_DEN
,
in_be32
(
spider_pics
[
node
]
+
TIR_DEN
)
|
0x1
);
}
}
}
arch/ppc64/kernel/time.c
View file @
24665cd0
...
...
@@ -107,6 +107,9 @@ void ppc_adjtimex(void);
static
unsigned
adjusting_time
=
0
;
unsigned
long
ppc_proc_freq
;
unsigned
long
ppc_tb_freq
;
static
__inline__
void
timer_check_rtc
(
void
)
{
/*
...
...
@@ -472,6 +475,66 @@ int do_settimeofday(struct timespec *tv)
EXPORT_SYMBOL
(
do_settimeofday
);
#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_MAPLE) || defined(CONFIG_PPC_BPA)
void
__init
generic_calibrate_decr
(
void
)
{
struct
device_node
*
cpu
;
struct
div_result
divres
;
unsigned
int
*
fp
;
int
node_found
;
/*
* The cpu node should have a timebase-frequency property
* to tell us the rate at which the decrementer counts.
*/
cpu
=
of_find_node_by_type
(
NULL
,
"cpu"
);
ppc_tb_freq
=
DEFAULT_TB_FREQ
;
/* hardcoded default */
node_found
=
0
;
if
(
cpu
!=
0
)
{
fp
=
(
unsigned
int
*
)
get_property
(
cpu
,
"timebase-frequency"
,
NULL
);
if
(
fp
!=
0
)
{
node_found
=
1
;
ppc_tb_freq
=
*
fp
;
}
}
if
(
!
node_found
)
printk
(
KERN_ERR
"WARNING: Estimating decrementer frequency "
"(not found)
\n
"
);
ppc_proc_freq
=
DEFAULT_PROC_FREQ
;
node_found
=
0
;
if
(
cpu
!=
0
)
{
fp
=
(
unsigned
int
*
)
get_property
(
cpu
,
"clock-frequency"
,
NULL
);
if
(
fp
!=
0
)
{
node_found
=
1
;
ppc_proc_freq
=
*
fp
;
}
}
if
(
!
node_found
)
printk
(
KERN_ERR
"WARNING: Estimating processor frequency "
"(not found)
\n
"
);
of_node_put
(
cpu
);
printk
(
KERN_INFO
"time_init: decrementer frequency = %lu.%.6lu MHz
\n
"
,
ppc_tb_freq
/
1000000
,
ppc_tb_freq
%
1000000
);
printk
(
KERN_INFO
"time_init: processor frequency = %lu.%.6lu MHz
\n
"
,
ppc_proc_freq
/
1000000
,
ppc_proc_freq
%
1000000
);
tb_ticks_per_jiffy
=
ppc_tb_freq
/
HZ
;
tb_ticks_per_sec
=
tb_ticks_per_jiffy
*
HZ
;
tb_ticks_per_usec
=
ppc_tb_freq
/
1000000
;
tb_to_us
=
mulhwu_scale_factor
(
ppc_tb_freq
,
1000000
);
div128_by_32
(
1024
*
1024
,
0
,
tb_ticks_per_sec
,
&
divres
);
tb_to_xs
=
divres
.
result_low
;
setup_default_decr
();
}
#endif
void
__init
time_init
(
void
)
{
/* This function is only called on the boot processor */
...
...
arch/ppc64/kernel/traps.c
View file @
24665cd0
...
...
@@ -126,6 +126,10 @@ int die(const char *str, struct pt_regs *regs, long err)
printk
(
"POWERMAC "
);
nl
=
1
;
break
;
case
PLATFORM_BPA
:
printk
(
"BPA "
);
nl
=
1
;
break
;
}
if
(
nl
)
printk
(
"
\n
"
);
...
...
drivers/char/watchdog/Kconfig
View file @
24665cd0
...
...
@@ -414,6 +414,16 @@ config WATCHDOG_RIO
machines. The watchdog timeout period is normally one minute but
can be changed with a boot-time parameter.
# ppc64 RTAS watchdog
config WATCHDOG_RTAS
tristate "RTAS watchdog"
depends on WATCHDOG && PPC_RTAS
help
This driver adds watchdog support for the RTAS watchdog.
To compile this driver as a module, choose M here. The module
will be called wdrtas.
#
# ISA-based Watchdog Cards
#
...
...
drivers/char/watchdog/Makefile
View file @
24665cd0
...
...
@@ -33,6 +33,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
obj-$(CONFIG_IXP4XX_WATCHDOG)
+=
ixp4xx_wdt.o
obj-$(CONFIG_IXP2000_WATCHDOG)
+=
ixp2000_wdt.o
obj-$(CONFIG_8xx_WDT)
+=
mpc8xx_wdt.o
obj-$(CONFIG_WATCHDOG_RTAS)
+=
wdrtas.o
# Only one watchdog can succeed. We probe the hardware watchdog
# drivers first, then the softdog driver. This means if your hardware
...
...
drivers/char/watchdog/wdrtas.c
0 → 100644
View file @
24665cd0
/*
* FIXME: add wdrtas_get_status and wdrtas_get_boot_status as soon as
* RTAS calls are available
*/
/*
* RTAS watchdog driver
*
* (C) Copyright IBM Corp. 2005
* device driver to exploit watchdog RTAS functions
*
* Authors : Utz Bacher <utz.bacher@de.ibm.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <asm/rtas.h>
#include <asm/uaccess.h>
#define WDRTAS_MAGIC_CHAR 42
#define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \
WDIOF_MAGICCLOSE)
MODULE_AUTHOR
(
"Utz Bacher <utz.bacher@de.ibm.com>"
);
MODULE_DESCRIPTION
(
"RTAS watchdog driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS_MISCDEV
(
WATCHDOG_MINOR
);
MODULE_ALIAS_MISCDEV
(
TEMP_MINOR
);
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static
int
wdrtas_nowayout
=
1
;
#else
static
int
wdrtas_nowayout
=
0
;
#endif
static
atomic_t
wdrtas_miscdev_open
=
ATOMIC_INIT
(
0
);
static
char
wdrtas_expect_close
=
0
;
static
int
wdrtas_interval
;
#define WDRTAS_THERMAL_SENSOR 3
static
int
wdrtas_token_get_sensor_state
;
#define WDRTAS_SURVEILLANCE_IND 9000
static
int
wdrtas_token_set_indicator
;
#define WDRTAS_SP_SPI 28
static
int
wdrtas_token_get_sp
;
static
int
wdrtas_token_event_scan
;
#define WDRTAS_DEFAULT_INTERVAL 300
#define WDRTAS_LOGBUFFER_LEN 128
static
char
wdrtas_logbuffer
[
WDRTAS_LOGBUFFER_LEN
];
/*** watchdog access functions */
/**
* wdrtas_set_interval - sets the watchdog interval
* @interval: new interval
*
* returns 0 on success, <0 on failures
*
* wdrtas_set_interval sets the watchdog keepalive interval by calling the
* RTAS function set-indicator (surveillance). The unit of interval is
* seconds.
*/
static
int
wdrtas_set_interval
(
int
interval
)
{
long
result
;
static
int
print_msg
=
10
;
/* rtas uses minutes */
interval
=
(
interval
+
59
)
/
60
;
result
=
rtas_call
(
wdrtas_token_set_indicator
,
3
,
1
,
NULL
,
WDRTAS_SURVEILLANCE_IND
,
0
,
interval
);
if
(
(
result
<
0
)
&&
(
print_msg
)
)
{
printk
(
KERN_ERR
"wdrtas: setting the watchdog to %i "
"timeout failed: %li
\n
"
,
interval
,
result
);
print_msg
--
;
}
return
result
;
}
/**
* wdrtas_get_interval - returns the current watchdog interval
* @fallback_value: value (in seconds) to use, if the RTAS call fails
*
* returns the interval
*
* wdrtas_get_interval returns the current watchdog keepalive interval
* as reported by the RTAS function ibm,get-system-parameter. The unit
* of the return value is seconds.
*/
static
int
wdrtas_get_interval
(
int
fallback_value
)
{
long
result
;
char
value
[
4
];
result
=
rtas_call
(
wdrtas_token_get_sp
,
3
,
1
,
NULL
,
WDRTAS_SP_SPI
,
(
void
*
)
__pa
(
&
value
),
4
);
if
(
(
value
[
0
]
!=
0
)
||
(
value
[
1
]
!=
2
)
||
(
value
[
3
]
!=
0
)
||
(
result
<
0
)
)
{
printk
(
KERN_WARNING
"wdrtas: could not get sp_spi watchdog "
"timeout (%li). Continuing
\n
"
,
result
);
return
fallback_value
;
}
/* rtas uses minutes */
return
((
int
)
value
[
2
])
*
60
;
}
/**
* wdrtas_timer_start - starts watchdog
*
* wdrtas_timer_start starts the watchdog by calling the RTAS function
* set-interval (surveillance)
*/
static
void
wdrtas_timer_start
(
void
)
{
wdrtas_set_interval
(
wdrtas_interval
);
}
/**
* wdrtas_timer_stop - stops watchdog
*
* wdrtas_timer_stop stops the watchdog timer by calling the RTAS function
* set-interval (surveillance)
*/
static
void
wdrtas_timer_stop
(
void
)
{
wdrtas_set_interval
(
0
);
}
/**
* wdrtas_log_scanned_event - logs an event we received during keepalive
*
* wdrtas_log_scanned_event prints a message to the log buffer dumping
* the results of the last event-scan call
*/
static
void
wdrtas_log_scanned_event
(
void
)
{
int
i
;
for
(
i
=
0
;
i
<
WDRTAS_LOGBUFFER_LEN
;
i
+=
16
)
printk
(
KERN_INFO
"wdrtas: dumping event (line %i/%i), data = "
"%02x %02x %02x %02x %02x %02x %02x %02x "
"%02x %02x %02x %02x %02x %02x %02x %02x
\n
"
,
(
i
/
16
)
+
1
,
(
WDRTAS_LOGBUFFER_LEN
/
16
),
wdrtas_logbuffer
[
i
+
0
],
wdrtas_logbuffer
[
i
+
1
],
wdrtas_logbuffer
[
i
+
2
],
wdrtas_logbuffer
[
i
+
3
],
wdrtas_logbuffer
[
i
+
4
],
wdrtas_logbuffer
[
i
+
5
],
wdrtas_logbuffer
[
i
+
6
],
wdrtas_logbuffer
[
i
+
7
],
wdrtas_logbuffer
[
i
+
8
],
wdrtas_logbuffer
[
i
+
9
],
wdrtas_logbuffer
[
i
+
10
],
wdrtas_logbuffer
[
i
+
11
],
wdrtas_logbuffer
[
i
+
12
],
wdrtas_logbuffer
[
i
+
13
],
wdrtas_logbuffer
[
i
+
14
],
wdrtas_logbuffer
[
i
+
15
]);
}
/**
* wdrtas_timer_keepalive - resets watchdog timer to keep system alive
*
* wdrtas_timer_keepalive restarts the watchdog timer by calling the
* RTAS function event-scan and repeats these calls as long as there are
* events available. All events will be dumped.
*/
static
void
wdrtas_timer_keepalive
(
void
)
{
long
result
;
do
{
result
=
rtas_call
(
wdrtas_token_event_scan
,
4
,
1
,
NULL
,
RTAS_EVENT_SCAN_ALL_EVENTS
,
0
,
(
void
*
)
__pa
(
wdrtas_logbuffer
),
WDRTAS_LOGBUFFER_LEN
);
if
(
result
<
0
)
printk
(
KERN_ERR
"wdrtas: event-scan failed: %li
\n
"
,
result
);
if
(
result
==
0
)
wdrtas_log_scanned_event
();
}
while
(
result
==
0
);
}
/**
* wdrtas_get_temperature - returns current temperature
*
* returns temperature or <0 on failures
*
* wdrtas_get_temperature returns the current temperature in Fahrenheit. It
* uses the RTAS call get-sensor-state, token 3 to do so
*/
static
int
wdrtas_get_temperature
(
void
)
{
long
result
;
int
temperature
=
0
;
result
=
rtas_call
(
wdrtas_token_get_sensor_state
,
2
,
2
,
(
void
*
)
__pa
(
&
temperature
),
WDRTAS_THERMAL_SENSOR
,
0
);
if
(
result
<
0
)
printk
(
KERN_WARNING
"wdrtas: reading the thermal sensor "
"faild: %li
\n
"
,
result
);
else
temperature
=
((
temperature
*
9
)
/
5
)
+
32
;
/* fahrenheit */
return
temperature
;
}
/**
* wdrtas_get_status - returns the status of the watchdog
*
* returns a bitmask of defines WDIOF_... as defined in
* include/linux/watchdog.h
*/
static
int
wdrtas_get_status
(
void
)
{
return
0
;
/* TODO */
}
/**
* wdrtas_get_boot_status - returns the reason for the last boot
*
* returns a bitmask of defines WDIOF_... as defined in
* include/linux/watchdog.h, indicating why the watchdog rebooted the system
*/
static
int
wdrtas_get_boot_status
(
void
)
{
return
0
;
/* TODO */
}
/*** watchdog API and operations stuff */
/* wdrtas_write - called when watchdog device is written to
* @file: file structure
* @buf: user buffer with data
* @len: amount to data written
* @ppos: position in file
*
* returns the number of successfully processed characters, which is always
* the number of bytes passed to this function
*
* wdrtas_write processes all the data given to it and looks for the magic
* character 'V'. This character allows the watchdog device to be closed
* properly.
*/
static
ssize_t
wdrtas_write
(
struct
file
*
file
,
const
char
__user
*
buf
,
size_t
len
,
loff_t
*
ppos
)
{
int
i
;
char
c
;
if
(
!
len
)
goto
out
;
if
(
!
wdrtas_nowayout
)
{
wdrtas_expect_close
=
0
;
/* look for 'V' */
for
(
i
=
0
;
i
<
len
;
i
++
)
{
if
(
get_user
(
c
,
buf
+
i
))
return
-
EFAULT
;
/* allow to close device */
if
(
c
==
'V'
)
wdrtas_expect_close
=
WDRTAS_MAGIC_CHAR
;
}
}
wdrtas_timer_keepalive
();
out:
return
len
;
}
/**
* wdrtas_ioctl - ioctl function for the watchdog device
* @inode: inode structure
* @file: file structure
* @cmd: command for ioctl
* @arg: argument pointer
*
* returns 0 on success, <0 on failure
*
* wdrtas_ioctl implements the watchdog API ioctls
*/
static
int
wdrtas_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
int
__user
*
argp
=
(
void
*
)
arg
;
int
i
;
static
struct
watchdog_info
wdinfo
=
{
.
options
=
WDRTAS_SUPPORTED_MASK
,
.
firmware_version
=
0
,
.
identity
=
"wdrtas"
};
switch
(
cmd
)
{
case
WDIOC_GETSUPPORT
:
if
(
copy_to_user
(
argp
,
&
wdinfo
,
sizeof
(
wdinfo
)))
return
-
EFAULT
;
return
0
;
case
WDIOC_GETSTATUS
:
i
=
wdrtas_get_status
();
return
put_user
(
i
,
argp
);
case
WDIOC_GETBOOTSTATUS
:
i
=
wdrtas_get_boot_status
();
return
put_user
(
i
,
argp
);
case
WDIOC_GETTEMP
:
if
(
wdrtas_token_get_sensor_state
==
RTAS_UNKNOWN_SERVICE
)
return
-
EOPNOTSUPP
;
i
=
wdrtas_get_temperature
();
return
put_user
(
i
,
argp
);
case
WDIOC_SETOPTIONS
:
if
(
get_user
(
i
,
argp
))
return
-
EFAULT
;
if
(
i
&
WDIOS_DISABLECARD
)
wdrtas_timer_stop
();
if
(
i
&
WDIOS_ENABLECARD
)
{
wdrtas_timer_keepalive
();
wdrtas_timer_start
();
}
if
(
i
&
WDIOS_TEMPPANIC
)
{
/* not implemented. Done by H8 */
}
return
0
;
case
WDIOC_KEEPALIVE
:
wdrtas_timer_keepalive
();
return
0
;
case
WDIOC_SETTIMEOUT
:
if
(
get_user
(
i
,
argp
))
return
-
EFAULT
;
if
(
wdrtas_set_interval
(
i
))
return
-
EINVAL
;
wdrtas_timer_keepalive
();
if
(
wdrtas_token_get_sp
==
RTAS_UNKNOWN_SERVICE
)
wdrtas_interval
=
i
;
else
wdrtas_interval
=
wdrtas_get_interval
(
i
);
/* fallthrough */
case
WDIOC_GETTIMEOUT
:
return
put_user
(
wdrtas_interval
,
argp
);
default:
return
-
ENOIOCTLCMD
;
}
}
/**
* wdrtas_open - open function of watchdog device
* @inode: inode structure
* @file: file structure
*
* returns 0 on success, -EBUSY if the file has been opened already, <0 on
* other failures
*
* function called when watchdog device is opened
*/
static
int
wdrtas_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
/* only open once */
if
(
atomic_inc_return
(
&
wdrtas_miscdev_open
)
>
1
)
{
atomic_dec
(
&
wdrtas_miscdev_open
);
return
-
EBUSY
;
}
wdrtas_timer_start
();
wdrtas_timer_keepalive
();
return
nonseekable_open
(
inode
,
file
);
}
/**
* wdrtas_close - close function of watchdog device
* @inode: inode structure
* @file: file structure
*
* returns 0 on success
*
* close function. Always succeeds
*/
static
int
wdrtas_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
/* only stop watchdog, if this was announced using 'V' before */
if
(
wdrtas_expect_close
==
WDRTAS_MAGIC_CHAR
)
wdrtas_timer_stop
();
else
{
printk
(
KERN_WARNING
"wdrtas: got unexpected close. Watchdog "
"not stopped.
\n
"
);
wdrtas_timer_keepalive
();
}
wdrtas_expect_close
=
0
;
atomic_dec
(
&
wdrtas_miscdev_open
);
return
0
;
}
/**
* wdrtas_temp_read - gives back the temperature in fahrenheit
* @file: file structure
* @buf: user buffer
* @count: number of bytes to be read
* @ppos: position in file
*
* returns always 1 or -EFAULT in case of user space copy failures, <0 on
* other failures
*
* wdrtas_temp_read gives the temperature to the users by copying this
* value as one byte into the user space buffer. The unit is Fahrenheit...
*/
static
ssize_t
wdrtas_temp_read
(
struct
file
*
file
,
char
__user
*
buf
,
size_t
count
,
loff_t
*
ppos
)
{
int
temperature
=
0
;
temperature
=
wdrtas_get_temperature
();
if
(
temperature
<
0
)
return
temperature
;
if
(
copy_to_user
(
buf
,
&
temperature
,
1
))
return
-
EFAULT
;
return
1
;
}
/**
* wdrtas_temp_open - open function of temperature device
* @inode: inode structure
* @file: file structure
*
* returns 0 on success, <0 on failure
*
* function called when temperature device is opened
*/
static
int
wdrtas_temp_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
nonseekable_open
(
inode
,
file
);
}
/**
* wdrtas_temp_close - close function of temperature device
* @inode: inode structure
* @file: file structure
*
* returns 0 on success
*
* close function. Always succeeds
*/
static
int
wdrtas_temp_close
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
0
;
}
/**
* wdrtas_reboot - reboot notifier function
* @nb: notifier block structure
* @code: reboot code
* @ptr: unused
*
* returns NOTIFY_DONE
*
* wdrtas_reboot stops the watchdog in case of a reboot
*/
static
int
wdrtas_reboot
(
struct
notifier_block
*
this
,
unsigned
long
code
,
void
*
ptr
)
{
if
(
(
code
==
SYS_DOWN
)
||
(
code
==
SYS_HALT
)
)
wdrtas_timer_stop
();
return
NOTIFY_DONE
;
}
/*** initialization stuff */
static
struct
file_operations
wdrtas_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
write
=
wdrtas_write
,
.
ioctl
=
wdrtas_ioctl
,
.
open
=
wdrtas_open
,
.
release
=
wdrtas_close
,
};
static
struct
miscdevice
wdrtas_miscdev
=
{
.
minor
=
WATCHDOG_MINOR
,
.
name
=
"watchdog"
,
.
fops
=
&
wdrtas_fops
,
};
static
struct
file_operations
wdrtas_temp_fops
=
{
.
owner
=
THIS_MODULE
,
.
llseek
=
no_llseek
,
.
read
=
wdrtas_temp_read
,
.
open
=
wdrtas_temp_open
,
.
release
=
wdrtas_temp_close
,
};
static
struct
miscdevice
wdrtas_tempdev
=
{
.
minor
=
TEMP_MINOR
,
.
name
=
"temperature"
,
.
fops
=
&
wdrtas_temp_fops
,
};
static
struct
notifier_block
wdrtas_notifier
=
{
.
notifier_call
=
wdrtas_reboot
,
};
/**
* wdrtas_get_tokens - reads in RTAS tokens
*
* returns 0 on succes, <0 on failure
*
* wdrtas_get_tokens reads in the tokens for the RTAS calls used in
* this watchdog driver. It tolerates, if "get-sensor-state" and
* "ibm,get-system-parameter" are not available.
*/
static
int
wdrtas_get_tokens
(
void
)
{
wdrtas_token_get_sensor_state
=
rtas_token
(
"get-sensor-state"
);
if
(
wdrtas_token_get_sensor_state
==
RTAS_UNKNOWN_SERVICE
)
{
printk
(
KERN_WARNING
"wdrtas: couldn't get token for "
"get-sensor-state. Trying to continue without "
"temperature support.
\n
"
);
}
wdrtas_token_get_sp
=
rtas_token
(
"ibm,get-system-parameter"
);
if
(
wdrtas_token_get_sp
==
RTAS_UNKNOWN_SERVICE
)
{
printk
(
KERN_WARNING
"wdrtas: couldn't get token for "
"ibm,get-system-parameter. Trying to continue with "
"a default timeout value of %i seconds.
\n
"
,
WDRTAS_DEFAULT_INTERVAL
);
}
wdrtas_token_set_indicator
=
rtas_token
(
"set-indicator"
);
if
(
wdrtas_token_set_indicator
==
RTAS_UNKNOWN_SERVICE
)
{
printk
(
KERN_ERR
"wdrtas: couldn't get token for "
"set-indicator. Terminating watchdog code.
\n
"
);
return
-
EIO
;
}
wdrtas_token_event_scan
=
rtas_token
(
"event-scan"
);
if
(
wdrtas_token_event_scan
==
RTAS_UNKNOWN_SERVICE
)
{
printk
(
KERN_ERR
"wdrtas: couldn't get token for event-scan. "
"Terminating watchdog code.
\n
"
);
return
-
EIO
;
}
return
0
;
}
/**
* wdrtas_unregister_devs - unregisters the misc dev handlers
*
* wdrtas_register_devs unregisters the watchdog and temperature watchdog
* misc devs
*/
static
void
wdrtas_unregister_devs
(
void
)
{
misc_deregister
(
&
wdrtas_miscdev
);
if
(
wdrtas_token_get_sensor_state
!=
RTAS_UNKNOWN_SERVICE
)
misc_deregister
(
&
wdrtas_tempdev
);
}
/**
* wdrtas_register_devs - registers the misc dev handlers
*
* returns 0 on succes, <0 on failure
*
* wdrtas_register_devs registers the watchdog and temperature watchdog
* misc devs
*/
static
int
wdrtas_register_devs
(
void
)
{
int
result
;
result
=
misc_register
(
&
wdrtas_miscdev
);
if
(
result
)
{
printk
(
KERN_ERR
"wdrtas: couldn't register watchdog misc "
"device. Terminating watchdog code.
\n
"
);
return
result
;
}
if
(
wdrtas_token_get_sensor_state
!=
RTAS_UNKNOWN_SERVICE
)
{
result
=
misc_register
(
&
wdrtas_tempdev
);
if
(
result
)
{
printk
(
KERN_WARNING
"wdrtas: couldn't register "
"watchdog temperature misc device. Continuing "
"without temperature support.
\n
"
);
wdrtas_token_get_sensor_state
=
RTAS_UNKNOWN_SERVICE
;
}
}
return
0
;
}
/**
* wdrtas_init - init function of the watchdog driver
*
* returns 0 on succes, <0 on failure
*
* registers the file handlers and the reboot notifier
*/
static
int
__init
wdrtas_init
(
void
)
{
if
(
wdrtas_get_tokens
())
return
-
ENODEV
;
if
(
wdrtas_register_devs
())
return
-
ENODEV
;
if
(
register_reboot_notifier
(
&
wdrtas_notifier
))
{
printk
(
KERN_ERR
"wdrtas: could not register reboot notifier. "
"Terminating watchdog code.
\n
"
);
wdrtas_unregister_devs
();
return
-
ENODEV
;
}
if
(
wdrtas_token_get_sp
==
RTAS_UNKNOWN_SERVICE
)
wdrtas_interval
=
WDRTAS_DEFAULT_INTERVAL
;
else
wdrtas_interval
=
wdrtas_get_interval
(
WDRTAS_DEFAULT_INTERVAL
);
return
0
;
}
/**
* wdrtas_exit - exit function of the watchdog driver
*
* unregisters the file handlers and the reboot notifier
*/
static
void
__exit
wdrtas_exit
(
void
)
{
if
(
!
wdrtas_nowayout
)
wdrtas_timer_stop
();
wdrtas_unregister_devs
();
unregister_reboot_notifier
(
&
wdrtas_notifier
);
}
module_init
(
wdrtas_init
);
module_exit
(
wdrtas_exit
);
include/asm-ppc64/machdep.h
View file @
24665cd0
...
...
@@ -76,6 +76,7 @@ struct machdep_calls {
void
(
*
tce_flush
)(
struct
iommu_table
*
tbl
);
void
(
*
iommu_dev_setup
)(
struct
pci_dev
*
dev
);
void
(
*
iommu_bus_setup
)(
struct
pci_bus
*
bus
);
void
(
*
irq_bus_setup
)(
struct
pci_bus
*
bus
);
int
(
*
probe
)(
int
platform
);
void
(
*
setup_arch
)(
void
);
...
...
include/asm-ppc64/mmu.h
View file @
24665cd0
...
...
@@ -47,8 +47,9 @@
#define SLB_VSID_KS ASM_CONST(0x0000000000000800)
#define SLB_VSID_KP ASM_CONST(0x0000000000000400)
#define SLB_VSID_N ASM_CONST(0x0000000000000200)
/* no-execute */
#define SLB_VSID_L ASM_CONST(0x0000000000000100)
/* largepage
16M
*/
#define SLB_VSID_L ASM_CONST(0x0000000000000100)
/* largepage */
#define SLB_VSID_C ASM_CONST(0x0000000000000080)
/* class */
#define SLB_VSID_LS ASM_CONST(0x0000000000000070)
/* size of largepage */
#define SLB_VSID_KERNEL (SLB_VSID_KP|SLB_VSID_C)
#define SLB_VSID_USER (SLB_VSID_KP|SLB_VSID_KS)
...
...
include/asm-ppc64/nvram.h
View file @
24665cd0
...
...
@@ -70,6 +70,7 @@ extern struct nvram_partition *nvram_find_partition(int sig, const char *name);
extern
int
pSeries_nvram_init
(
void
);
extern
int
pmac_nvram_init
(
void
);
extern
int
bpa_nvram_init
(
void
);
/* PowerMac specific nvram stuffs */
...
...
include/asm-ppc64/processor.h
View file @
24665cd0
...
...
@@ -138,8 +138,16 @@
#define SPRN_NIADORM 0x3F3
/* Hardware Implementation Register 2 */
#define SPRN_HID4 0x3F4
/* 970 HID4 */
#define SPRN_HID5 0x3F6
/* 970 HID5 */
#define SPRN_TSC 0x3FD
/* Thread switch control */
#define SPRN_TST 0x3FC
/* Thread switch timeout */
#define SPRN_HID6 0x3F9
/* BE HID 6 */
#define HID6_LB (0x0F<<12)
/* Concurrent Large Page Modes */
#define HID6_DLP (1<<20)
/* Disable all large page modes (4K only) */
#define SPRN_TSCR 0x399
/* Thread switch control on BE */
#define SPRN_TTR 0x39A
/* Thread switch timeout on BE */
#define TSCR_DEC_ENABLE 0x200000
/* Decrementer Interrupt */
#define TSCR_EE_ENABLE 0x100000
/* External Interrupt */
#define TSCR_EE_BOOST 0x080000
/* External Interrupt Boost */
#define SPRN_TSC 0x3FD
/* Thread switch control on others */
#define SPRN_TST 0x3FC
/* Thread switch timeout on others */
#define SPRN_L2CR 0x3F9
/* Level 2 Cache Control Regsiter */
#define SPRN_LR 0x008
/* Link Register */
#define SPRN_PIR 0x3FF
/* Processor Identification Register */
...
...
@@ -259,6 +267,7 @@
#define PV_970FX 0x003C
#define PV_630 0x0040
#define PV_630p 0x0041
#define PV_BE 0x0070
/* Platforms supported by PPC64 */
#define PLATFORM_PSERIES 0x0100
...
...
@@ -267,6 +276,7 @@
#define PLATFORM_LPAR 0x0001
#define PLATFORM_POWERMAC 0x0400
#define PLATFORM_MAPLE 0x0500
#define PLATFORM_BPA 0x1000
/* Compatibility with drivers coming from PPC32 world */
#define _machine (systemcfg->platform)
...
...
@@ -278,6 +288,7 @@
#define IC_INVALID 0
#define IC_OPEN_PIC 1
#define IC_PPC_XIC 2
#define IC_BPA_IIC 3
#define XGLUE(a,b) a##b
#define GLUE(a,b) XGLUE(a,b)
...
...
include/asm-ppc64/rtas.h
View file @
24665cd0
...
...
@@ -186,8 +186,14 @@ extern int rtas_get_sensor(int sensor, int index, int *state);
extern
int
rtas_get_power_level
(
int
powerdomain
,
int
*
level
);
extern
int
rtas_set_power_level
(
int
powerdomain
,
int
level
,
int
*
setlevel
);
extern
int
rtas_set_indicator
(
int
indicator
,
int
index
,
int
new_value
);
extern
void
rtas_progress
(
char
*
s
,
unsigned
short
hex
);
extern
void
rtas_initialize
(
void
);
struct
rtc_time
;
extern
void
rtas_get_boot_time
(
struct
rtc_time
*
rtc_time
);
extern
void
rtas_get_rtc_time
(
struct
rtc_time
*
rtc_time
);
extern
int
rtas_set_rtc_time
(
struct
rtc_time
*
rtc_time
);
/* Given an RTAS status code of 9900..9905 compute the hinted delay */
unsigned
int
rtas_extended_busy_delay_time
(
int
status
);
static
inline
int
rtas_is_extended_busy
(
int
status
)
...
...
include/asm-ppc64/smp.h
View file @
24665cd0
...
...
@@ -85,6 +85,14 @@ extern void smp_generic_take_timebase(void);
extern
struct
smp_ops_t
*
smp_ops
;
#ifdef CONFIG_PPC_PSERIES
void
vpa_init
(
int
cpu
);
#else
static
inline
void
vpa_init
(
int
cpu
)
{
}
#endif
/* CONFIG_PPC_PSERIES */
#endif
/* __ASSEMBLY__ */
#endif
/* !(_PPC64_SMP_H) */
...
...
include/asm-ppc64/time.h
View file @
24665cd0
...
...
@@ -34,6 +34,15 @@ struct rtc_time;
extern
void
to_tm
(
int
tim
,
struct
rtc_time
*
tm
);
extern
time_t
last_rtc_update
;
void
generic_calibrate_decr
(
void
);
void
setup_default_decr
(
void
);
/* Some sane defaults: 125 MHz timebase, 1GHz processor */
extern
unsigned
long
ppc_proc_freq
;
#define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8)
extern
unsigned
long
ppc_tb_freq
;
#define DEFAULT_TB_FREQ 125000000UL
/*
* By putting all of this stuff into a single struct we
* reduce the number of cache lines touched by do_gettimeofday.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment