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
Kirill Smelkov
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
Hide 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
...
...
@@ -73,7 +73,21 @@ _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
(
res
->
flags
&&
release_resource
(
res
))
{
printk
(
KERN_ERR
"%s: failed to release IO %d on bus %s
\n
"
,
__FUNCTION__
,
i
,
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
);
}
}
}
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,9 +47,10 @@
#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